]> andersk Git - libfaim.git/blob - src/rxhandlers.c
c0f09562fa81754db721df000271f8f6fa5b436b
[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       /* Try it raw and see if we can get it to happen... */
512       if (!workingPtr->handled) /* XXX this is probably bad. */
513         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
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   return 0;
527 }
528
529 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
530 {
531   rxcallback_t userfunc = NULL;
532   char sn[MAXSNLEN];
533   unsigned short type;
534   int i = 10+8; /* skip SNAC and cookie */
535   int ret = 1;
536   unsigned char snlen;
537
538   type = aimutil_get16(command->data+i);
539   i += 2;
540
541   snlen = aimutil_get8(command->data+i);
542   i++;
543
544   memset(sn, 0, sizeof(sn));
545   strncpy(sn, (char *)command->data+i, snlen);
546
547   if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
548     ret =  userfunc(sess, command, type, sn);
549
550   return ret;
551 }
552
553 /*
554  * The Rate Limiting System, An Abridged Guide to Nonsense.
555  *
556  * OSCAR defines several 'rate classes'.  Each class has seperate
557  * rate limiting properties (limit level, alert level, disconnect
558  * level, etc), and a set of SNAC family/type pairs associated with
559  * it.  The rate classes, their limiting properties, and the definitions
560  * of which SNACs are belong to which class, are defined in the
561  * Rate Response packet at login to each host.  
562  *
563  * Logically, all rate offenses within one class count against further
564  * offenses for other SNACs in the same class (ie, sending messages
565  * too fast will limit the number of user info requests you can send,
566  * since those two SNACs are in the same rate class).
567  *
568  * Since the rate classes are defined dynamically at login, the values
569  * below may change. But they seem to be fairly constant.
570  *
571  * Currently, BOS defines five rate classes, with the commonly used
572  * members as follows...
573  *
574  *  Rate class 0x0001:
575  *      - Everything thats not in any of the other classes
576  *
577  *  Rate class 0x0002:
578  *      - Buddy list add/remove
579  *      - Permit list add/remove
580  *      - Deny list add/remove
581  *
582  *  Rate class 0x0003:
583  *      - User information requests
584  *      - Outgoing ICBMs
585  *
586  *  Rate class 0x0004:
587  *      - A few unknowns: 2/9, 2/b, and f/2
588  *
589  *  Rate class 0x0005:
590  *      - Chat room create
591  *      - Outgoing chat ICBMs
592  *
593  * The only other thing of note is that class 5 (chat) has slightly looser
594  * limiting properties than class 3 (normal messages).  But thats just a 
595  * small bit of trivia for you.
596  *
597  * The last thing that needs to be learned about the rate limiting
598  * system is how the actual numbers relate to the passing of time.  This
599  * seems to be a big mystery.
600  * 
601  */
602 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
603 {
604   rxcallback_t userfunc = NULL;
605   int ret = 1;
606   int i;
607   int code;
608   unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
609   unsigned long currentavg, maxavg;
610
611   i = 10;
612
613   code = aimutil_get16(command->data+i);
614   i += 2;
615
616   rateclass = aimutil_get16(command->data+i);
617   i += 2;
618
619   windowsize = aimutil_get32(command->data+i);
620   i += 4;
621   clear = aimutil_get32(command->data+i);
622   i += 4;
623   alert = aimutil_get32(command->data+i);
624   i += 4;
625   limit = aimutil_get32(command->data+i);
626   i += 4;
627   disconnect = aimutil_get32(command->data+i);
628   i += 4;
629   currentavg = aimutil_get32(command->data+i);
630   i += 4;
631   maxavg = aimutil_get32(command->data+i);
632   i += 4;
633
634   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
635     ret =  userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
636
637   return ret;
638 }
639
640 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
641 {
642   rxcallback_t userfunc = NULL;
643   int ret = 1;
644   int i;
645   unsigned short newevil;
646   struct aim_userinfo_s userinfo;
647
648   i = 10;
649   newevil = aimutil_get16(command->data+10);
650   i += 2;
651
652   memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
653   if (command->commandlen-i)
654     i += aim_extractuserinfo(sess, command->data+i, &userinfo);
655
656   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
657     ret = userfunc(sess, command, newevil, &userinfo);
658   
659   return ret;
660 }
661
662 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
663                                        struct command_rx_struct *command, ...)
664 {
665   rxcallback_t userfunc = NULL;
666   char *msg;
667   int ret=1;
668   struct aim_tlvlist_t *tlvlist;
669   u_short id;
670
671   /*
672    * Code.
673    *
674    * Valid values:
675    *   1 Mandatory upgrade
676    *   2 Advisory upgrade
677    *   3 System bulletin
678    *   4 Nothing's wrong ("top o the world" -- normal)
679    *
680    */
681   id = aimutil_get16(command->data+10);
682
683   /* 
684    * TLVs follow 
685    */
686   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
687     return ret;
688
689   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
690     aim_freetlvchain(&tlvlist);
691     return ret;
692   }
693   
694   userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
695   if (userfunc)
696     ret =  userfunc(sess, command, id, msg);
697
698   aim_freetlvchain(&tlvlist);
699   free(msg);
700
701   return ret;  
702 }
703
704 faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
705                                        struct command_rx_struct *command, ...)
706 {
707   rxcallback_t userfunc = NULL;
708   int ret = 1;
709   unsigned short *families = NULL;
710   int famcount = 0, i;
711
712   famcount = (command->commandlen-10)/2;
713   if (!(families = malloc(command->commandlen-10)))
714     return ret;
715
716   for (i = 0; i < famcount; i++)
717     families[i] = aimutil_get16(command->data+((i*2)+10));
718
719   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
720     ret = userfunc(sess, command, famcount, families);
721
722   free(families);
723
724   return ret;  
725 }
726
727 faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess,
728                                            struct command_rx_struct *command)
729 {
730   rxcallback_t userfunc = NULL;
731   int ret = 1;
732   int status = -1;
733
734   status = aimutil_get16(command->data+10);
735
736   if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007)))
737     ret = userfunc(sess, command, status);
738
739   return ret;  
740 }
741
742 faim_internal int aim_parse_infochange(struct aim_session_t *sess,
743                                        struct command_rx_struct *command)
744 {
745   unsigned short subtype; /* called for both reply and change-reply */
746   int i;
747
748   subtype = aimutil_get16(command->data+2);
749
750   /*
751    * struct {
752    *    unsigned short perms;
753    *    unsigned short tlvcount;
754    *    aim_tlv_t tlvs[tlvcount];
755    *  } admin_info[n];
756    */
757   for (i = 10; i < command->commandlen; ) {
758     int perms, tlvcount;
759
760     perms = aimutil_get16(command->data+i);
761     i += 2;
762
763     tlvcount = aimutil_get16(command->data+i);
764     i += 2;
765
766     while (tlvcount) {
767       rxcallback_t userfunc;
768       struct aim_tlv_t *tlv;
769       int str = 0;
770
771       if ((aimutil_get16(command->data+i) == 0x0011) ||
772           (aimutil_get16(command->data+i) == 0x0004))
773         str = 1;
774
775       if (str)
776         tlv = aim_grabtlvstr(command->data+i);
777       else
778         tlv = aim_grabtlv(command->data+i);
779
780       /* XXX fix so its only called once for the entire packet */
781       if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype)))
782         userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str);
783
784       if (tlv)
785         i += 2+2+tlv->length;
786
787       if (tlv && tlv->value)
788         free(tlv->value);
789       if (tlv)
790         free(tlv);
791
792       tlvcount--;
793     }
794   }
795
796   return 1;
797 }
798
799 faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
800                                          struct command_rx_struct *command, ...)
801 {
802   rxcallback_t userfunc = NULL;
803   int ret = 1;
804   int vercount;
805
806   vercount = (command->commandlen-10)/4;
807   
808   if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
809     ret = userfunc(sess, command, vercount, command->data+10);
810
811   return ret;  
812 }
813
814 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
815                                             struct command_rx_struct *command, ...)
816 {
817   int serviceid = 0;
818   unsigned char *cookie = NULL;
819   char *ip = NULL;
820   rxcallback_t userfunc = NULL;
821   struct aim_tlvlist_t *tlvlist;
822   int ret = 1;
823   
824   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
825
826   if (aim_gettlv(tlvlist, 0x000d, 1))
827     serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
828   if (aim_gettlv(tlvlist, 0x0005, 1))
829     ip = aim_gettlv_str(tlvlist, 0x0005, 1);
830   if (aim_gettlv(tlvlist, 0x0006, 1))
831     cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
832
833   if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
834
835     /*
836      * Chat hack.
837      *
838      */
839     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
840       ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
841       free(sess->pendingjoin);
842       sess->pendingjoin = NULL;
843       sess->pendingjoinexchange = 0;
844   } else if (!serviceid || !ip || !cookie) { /* yeep! */
845     ret = 1;
846   } else {
847     if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
848       ret =  userfunc(sess, command, serviceid, ip, cookie);
849   }
850
851   if (ip)
852     free(ip);
853   if (cookie)
854     free(cookie);
855
856   aim_freetlvchain(&tlvlist);
857
858   return ret;
859 }
860
861 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
862                                           struct command_rx_struct *command, ...)
863 {
864   u_int i = 0;
865
866   if (!sess || !command)
867     return 1;
868
869   faimdprintf(sess, 1, "\nRecieved unknown packet:");
870
871   for (i = 0; i < command->commandlen; i++)
872     {
873       if ((i % 8) == 0)
874         faimdprintf(sess, 1, "\n\t");
875
876       faimdprintf(sess, 1, "0x%2x ", command->data[i]);
877     }
878   
879   faimdprintf(sess, 1, "\n\n");
880
881   return 1;
882 }
883
884
885 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
886                                      struct command_rx_struct *command)
887 {
888   struct aim_tlvlist_t *tlvlist;
889   char *msg = NULL;
890   unsigned short code = 0;
891   rxcallback_t userfunc = NULL;
892   int ret = 1;
893
894   /* Used only by the older login protocol */
895   /* XXX remove this special case? */
896   if (command->conn->type == AIM_CONN_TYPE_AUTH)
897     return aim_authparse(sess, command);
898
899   tlvlist = aim_readtlvchain(command->data, command->commandlen);
900
901   if (aim_gettlv(tlvlist, 0x0009, 1))
902     code = aim_gettlv16(tlvlist, 0x0009, 1);
903
904   if (aim_gettlv(tlvlist, 0x000b, 1))
905     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
906
907   if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
908     ret =  userfunc(sess, command, code, msg);
909
910   aim_freetlvchain(&tlvlist);
911
912   if (msg)
913     free(msg);
914
915   return ret;
916 }
917
918 /*
919  * aim_parse_generalerrs()
920  *
921  * Middle handler for 0x0001 snac of each family.
922  *
923  */
924 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
925                                         struct command_rx_struct *command, ...)
926 {
927   unsigned short family;
928   unsigned short subtype;
929   int ret = 1;
930   int error = 0;
931   rxcallback_t userfunc = NULL;
932   
933   family = aimutil_get16(command->data+0);
934   subtype= aimutil_get16(command->data+2);
935   
936   if (command->commandlen > 10)
937     error = aimutil_get16(command->data+10);
938
939   if ((userfunc = aim_callhandler(sess, command->conn, family, subtype))) 
940     ret = userfunc(sess, command, error);
941
942   return ret;
943 }
944
945
946
This page took 0.106463 seconds and 3 git commands to generate.