]> andersk Git - libfaim.git/blob - src/rxhandlers.c
2241f711bd38f462d32b73e52431f69b1e7a97d7
[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   static int critical = 0;
312   
313   if (critical)
314     return 0; /* don't call recursively! */
315
316   critical = 1;
317
318   if (sess->queue_incoming == NULL) {
319     faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
320   } else {
321     workingPtr = sess->queue_incoming;
322     for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
323       unsigned short family,subtype;
324
325       /*
326        * XXX: This is still fairly ugly.
327        */
328       if (workingPtr->handled)
329         continue;
330
331       /*
332        * This is a debugging/sanity check only and probably could/should be removed
333        * for stable code.
334        */
335       if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && 
336            (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
337           ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && 
338            (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
339         faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
340         workingPtr->handled = 1;
341         continue;
342       }
343
344       if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
345         /* make sure that we only get OFT frames on these connections */
346         if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
347           faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
348           workingPtr->handled = 1; /* get rid of it */
349         } else {
350           /* XXX: implement this */
351           faimdprintf(sess, 0, "faim: OFT frame!\n");
352           workingPtr->handled = 1; /* get rid of it */
353         }
354         continue;
355       }
356
357       if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
358         /* not possible */
359         faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
360         workingPtr->handled = 1;
361         continue;
362       }
363
364       if ((workingPtr->commandlen == 4) && 
365           (aimutil_get32(workingPtr->data) == 0x00000001)) {
366         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
367         continue;
368       } 
369
370       if (workingPtr->hdr.oscar.type == 0x04) {
371         workingPtr->handled = aim_negchan_middle(sess, workingPtr);
372         continue;
373       }
374           
375       family = aimutil_get16(workingPtr->data);
376       subtype = aimutil_get16(workingPtr->data+2);
377           
378       if (family == 0x0001) {
379
380         if (subtype == 0x0001)
381           workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
382         else if (subtype == 0x0003)
383           workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
384         else if (subtype == 0x0005)
385           workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
386         else if (subtype == 0x0007)
387           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
388         else if (subtype == 0x000a)
389           workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
390         else if (subtype == 0x000f)
391           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
392         else if (subtype == 0x0010)
393           workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
394         else if (subtype == 0x0013)
395           workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
396         else if (subtype == 0x0018)
397           workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
398         else
399           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr);
400
401       } else if (family == 0x0002) {
402
403         if (subtype == 0x0001)
404             workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
405         else if (subtype == 0x0003)
406           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
407         else if (subtype == 0x0006)
408           workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
409         else
410           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
411
412       } else if (family == 0x0003) {
413
414         if (subtype == 0x0001)
415           workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
416         else if (subtype == 0x0003)
417           workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
418         else if (subtype == 0x000b)
419           workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
420         else if (subtype == 0x000c)
421           workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
422         else
423           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
424
425       } else if (family == 0x0004) {
426
427         if (subtype == 0x0001)
428           workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
429         else if (subtype == 0x0005)
430           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
431         else if (subtype == 0x0006)
432           workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
433         else if (subtype == 0x0007)
434           workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
435         else if (subtype == 0x000a)
436           workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
437         else if (subtype == 0x000c)
438           workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
439         else
440           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
441
442       } else if (family == 0x0007) {
443
444         if (subtype == 0x0003)
445           workingPtr->handled = aim_parse_infochange(sess, workingPtr);
446         else if (subtype == 0x0005)
447           workingPtr->handled = aim_parse_infochange(sess, workingPtr);
448         else if (subtype == 0x0007)
449           workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr);
450         break;
451
452       } else if (family == 0x0009) {
453
454         if (subtype == 0x0001)
455           workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
456         else if (subtype == 0x0003)
457           workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
458         else
459           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
460
461       } else if (family == 0x000a) {
462
463         if (subtype == 0x0001)
464           workingPtr->handled = aim_parse_searcherror(sess, workingPtr);
465         else if (subtype == 0x0003)
466           workingPtr->handled = aim_parse_searchreply(sess, workingPtr);
467         else
468           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
469
470       } else if (family == 0x000b) {
471
472         if (subtype == 0x0001)
473           workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
474         else if (subtype == 0x0002)
475           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
476         else
477           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
478
479       } else if (family == 0x000d) {
480
481         if (subtype == 0x0009)
482           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
483
484       } else if (family == 0x000e) {
485
486         if (subtype == 0x0002)
487           workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
488         else if (subtype == 0x0003)
489           workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
490         else if (subtype == 0x0004)
491           workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
492         else if (subtype == 0x0006)
493           workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
494
495       } else if (family == 0x0013) {
496
497         faimdprintf(sess, 0, "lalala: 0x%04x/0x%04x\n", family, subtype);
498
499       } else if (family == 0x0017) {    /* New login protocol */
500
501         if (subtype == 0x0001)
502           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
503         else if (subtype == 0x0003)
504           workingPtr->handled = aim_authparse(sess, workingPtr);
505         else if (subtype == 0x0007)
506           workingPtr->handled = aim_authkeyparse(sess, workingPtr);
507         else
508           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
509
510       } else if (family == AIM_CB_FAM_SPECIAL) {
511
512         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
513
514       }
515     }
516   }
517
518   /* 
519    * This doesn't have to be called here.  It could easily be done
520    * by a seperate thread or something. It's an administrative operation,
521    * and can take a while. Though the less you call it the less memory
522    * you'll have :)
523    */
524   aim_purge_rxqueue(sess);
525
526   critical = 0;
527   
528   return 0;
529 }
530
531 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
532 {
533   rxcallback_t userfunc = NULL;
534   char sn[MAXSNLEN];
535   unsigned short type;
536   int i = 10+8; /* skip SNAC and cookie */
537   int ret = 1;
538   unsigned char snlen;
539
540   type = aimutil_get16(command->data+i);
541   i += 2;
542
543   snlen = aimutil_get8(command->data+i);
544   i++;
545
546   memset(sn, 0, sizeof(sn));
547   strncpy(sn, (char *)command->data+i, snlen);
548
549   if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
550     ret =  userfunc(sess, command, type, sn);
551
552   return ret;
553 }
554
555 /*
556  * The Rate Limiting System, An Abridged Guide to Nonsense.
557  *
558  * OSCAR defines several 'rate classes'.  Each class has seperate
559  * rate limiting properties (limit level, alert level, disconnect
560  * level, etc), and a set of SNAC family/type pairs associated with
561  * it.  The rate classes, their limiting properties, and the definitions
562  * of which SNACs are belong to which class, are defined in the
563  * Rate Response packet at login to each host.  
564  *
565  * Logically, all rate offenses within one class count against further
566  * offenses for other SNACs in the same class (ie, sending messages
567  * too fast will limit the number of user info requests you can send,
568  * since those two SNACs are in the same rate class).
569  *
570  * Since the rate classes are defined dynamically at login, the values
571  * below may change. But they seem to be fairly constant.
572  *
573  * Currently, BOS defines five rate classes, with the commonly used
574  * members as follows...
575  *
576  *  Rate class 0x0001:
577  *      - Everything thats not in any of the other classes
578  *
579  *  Rate class 0x0002:
580  *      - Buddy list add/remove
581  *      - Permit list add/remove
582  *      - Deny list add/remove
583  *
584  *  Rate class 0x0003:
585  *      - User information requests
586  *      - Outgoing ICBMs
587  *
588  *  Rate class 0x0004:
589  *      - A few unknowns: 2/9, 2/b, and f/2
590  *
591  *  Rate class 0x0005:
592  *      - Chat room create
593  *      - Outgoing chat ICBMs
594  *
595  * The only other thing of note is that class 5 (chat) has slightly looser
596  * limiting properties than class 3 (normal messages).  But thats just a 
597  * small bit of trivia for you.
598  *
599  * The last thing that needs to be learned about the rate limiting
600  * system is how the actual numbers relate to the passing of time.  This
601  * seems to be a big mystery.
602  * 
603  */
604 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
605 {
606   rxcallback_t userfunc = NULL;
607   int ret = 1;
608   int i;
609   int code;
610   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
611   unsigned long currentavg, maxavg;
612
613   i = 10;
614
615   code = aimutil_get16(command->data+i);
616   i += 2;
617
618   rateclass = aimutil_get16(command->data+i);
619   i += 2;
620
621   windowsize = aimutil_get32(command->data+i);
622   i += 4;
623   clear = aimutil_get32(command->data+i);
624   i += 4;
625   alert = aimutil_get32(command->data+i);
626   i += 4;
627   limit = aimutil_get32(command->data+i);
628   i += 4;
629   disconnect = aimutil_get32(command->data+i);
630   i += 4;
631   currentavg = aimutil_get32(command->data+i);
632   i += 4;
633   maxavg = aimutil_get32(command->data+i);
634   i += 4;
635
636   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
637     ret =  userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
638
639   return ret;
640 }
641
642 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
643 {
644   rxcallback_t userfunc = NULL;
645   int ret = 1;
646   int i;
647   unsigned short newevil;
648   struct aim_userinfo_s userinfo;
649
650   i = 10;
651   newevil = aimutil_get16(command->data+10);
652   i += 2;
653
654   memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
655   if (command->commandlen-i)
656     i += aim_extractuserinfo(sess, command->data+i, &userinfo);
657
658   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
659     ret = userfunc(sess, command, newevil, &userinfo);
660   
661   return ret;
662 }
663
664 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
665                                        struct command_rx_struct *command, ...)
666 {
667   rxcallback_t userfunc = NULL;
668   char *msg;
669   int ret=1;
670   struct aim_tlvlist_t *tlvlist;
671   u_short id;
672
673   /*
674    * Code.
675    *
676    * Valid values:
677    *   1 Mandatory upgrade
678    *   2 Advisory upgrade
679    *   3 System bulletin
680    *   4 Nothing's wrong ("top o the world" -- normal)
681    *
682    */
683   id = aimutil_get16(command->data+10);
684
685   /* 
686    * TLVs follow 
687    */
688   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
689     return ret;
690
691   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
692     aim_freetlvchain(&tlvlist);
693     return ret;
694   }
695   
696   userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
697   if (userfunc)
698     ret =  userfunc(sess, command, id, msg);
699
700   aim_freetlvchain(&tlvlist);
701   free(msg);
702
703   return ret;  
704 }
705
706 faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
707                                        struct command_rx_struct *command, ...)
708 {
709   rxcallback_t userfunc = NULL;
710   int ret = 1;
711   unsigned short *families = NULL;
712   int famcount = 0, i;
713
714   famcount = (command->commandlen-10)/2;
715   if (!(families = malloc(command->commandlen-10)))
716     return ret;
717
718   for (i = 0; i < famcount; i++)
719     families[i] = aimutil_get16(command->data+((i*2)+10));
720
721   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
722     ret = userfunc(sess, command, famcount, families);
723
724   free(families);
725
726   return ret;  
727 }
728
729 faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess,
730                                            struct command_rx_struct *command)
731 {
732   rxcallback_t userfunc = NULL;
733   int ret = 1;
734   int status = -1;
735
736   status = aimutil_get16(command->data+10);
737
738   if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007)))
739     ret = userfunc(sess, command, status);
740
741   return ret;  
742 }
743
744 faim_internal int aim_parse_infochange(struct aim_session_t *sess,
745                                        struct command_rx_struct *command)
746 {
747   unsigned short subtype; /* called for both reply and change-reply */
748   int i;
749
750   subtype = aimutil_get16(command->data+2);
751
752   /*
753    * struct {
754    *    unsigned short perms;
755    *    unsigned short tlvcount;
756    *    aim_tlv_t tlvs[tlvcount];
757    *  } admin_info[n];
758    */
759   for (i = 10; i < command->commandlen; ) {
760     int perms, tlvcount;
761
762     perms = aimutil_get16(command->data+i);
763     i += 2;
764
765     tlvcount = aimutil_get16(command->data+i);
766     i += 2;
767
768     while (tlvcount) {
769       rxcallback_t userfunc;
770       struct aim_tlv_t *tlv;
771       int str = 0;
772
773       if ((aimutil_get16(command->data+i) == 0x0011) ||
774           (aimutil_get16(command->data+i) == 0x0004))
775         str = 1;
776
777       if (str)
778         tlv = aim_grabtlvstr(command->data+i);
779       else
780         tlv = aim_grabtlv(command->data+i);
781
782       /* XXX fix so its only called once for the entire packet */
783       if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype)))
784         userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str);
785
786       if (tlv)
787         i += 2+2+tlv->length;
788
789       if (tlv && tlv->value)
790         free(tlv->value);
791       if (tlv)
792         free(tlv);
793
794       tlvcount--;
795     }
796   }
797
798   return 1;
799 }
800
801 faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
802                                          struct command_rx_struct *command, ...)
803 {
804   rxcallback_t userfunc = NULL;
805   int ret = 1;
806   int vercount;
807
808   vercount = (command->commandlen-10)/4;
809   
810   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
811     ret = userfunc(sess, command, vercount, command->data+10);
812
813   return ret;  
814 }
815
816 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
817                                             struct command_rx_struct *command, ...)
818 {
819   int serviceid = 0;
820   unsigned char *cookie = NULL;
821   char *ip = NULL;
822   rxcallback_t userfunc = NULL;
823   struct aim_tlvlist_t *tlvlist;
824   int ret = 1;
825   
826   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
827
828   if (aim_gettlv(tlvlist, 0x000d, 1))
829     serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
830   if (aim_gettlv(tlvlist, 0x0005, 1))
831     ip = aim_gettlv_str(tlvlist, 0x0005, 1);
832   if (aim_gettlv(tlvlist, 0x0006, 1))
833     cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
834
835   if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
836
837     /*
838      * Chat hack.
839      *
840      */
841     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
842       ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
843       free(sess->pendingjoin);
844       sess->pendingjoin = NULL;
845       sess->pendingjoinexchange = 0;
846   } else if (!serviceid || !ip || !cookie) { /* yeep! */
847     ret = 1;
848   } else {
849     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
850       ret =  userfunc(sess, command, serviceid, ip, cookie);
851   }
852
853   if (ip)
854     free(ip);
855   if (cookie)
856     free(cookie);
857
858   aim_freetlvchain(&tlvlist);
859
860   return ret;
861 }
862
863 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
864                                           struct command_rx_struct *command, ...)
865 {
866   u_int i = 0;
867
868   if (!sess || !command)
869     return 1;
870
871   faimdprintf(sess, 1, "\nRecieved unknown packet:");
872
873   for (i = 0; i < command->commandlen; i++)
874     {
875       if ((i % 8) == 0)
876         faimdprintf(sess, 1, "\n\t");
877
878       faimdprintf(sess, 1, "0x%2x ", command->data[i]);
879     }
880   
881   faimdprintf(sess, 1, "\n\n");
882
883   return 1;
884 }
885
886
887 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
888                                      struct command_rx_struct *command)
889 {
890   struct aim_tlvlist_t *tlvlist;
891   char *msg = NULL;
892   unsigned short code = 0;
893   rxcallback_t userfunc = NULL;
894   int ret = 1;
895
896   /* Used only by the older login protocol */
897   /* XXX remove this special case? */
898   if (command->conn->type == AIM_CONN_TYPE_AUTH)
899     return aim_authparse(sess, command);
900
901   tlvlist = aim_readtlvchain(command->data, command->commandlen);
902
903   if (aim_gettlv(tlvlist, 0x0009, 1))
904     code = aim_gettlv16(tlvlist, 0x0009, 1);
905
906   if (aim_gettlv(tlvlist, 0x000b, 1))
907     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
908
909   if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
910     ret =  userfunc(sess, command, code, msg);
911
912   aim_freetlvchain(&tlvlist);
913
914   if (msg)
915     free(msg);
916
917   return ret;
918 }
919
920 /*
921  * aim_parse_generalerrs()
922  *
923  * Middle handler for 0x0001 snac of each family.
924  *
925  */
926 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
927                                         struct command_rx_struct *command, ...)
928 {
929   unsigned short family;
930   unsigned short subtype;
931   int ret = 1;
932   int error = 0;
933   rxcallback_t userfunc = NULL;
934   
935   family = aimutil_get16(command->data+0);
936   subtype= aimutil_get16(command->data+2);
937   
938   if (command->commandlen > 10)
939     error = aimutil_get16(command->data+10);
940
941   if ((userfunc = aim_callhandler(sess, command->conn, family, subtype))) 
942     ret = userfunc(sess, command, error);
943
944   return ret;
945 }
946
947
948
This page took 0.126672 seconds and 3 git commands to generate.