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