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