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