]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
220394f2abf907ce6a8aa264b42caf83449a0555
[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 faim_internal 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 faim_export 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 *newcb;
192
193   if (!conn)
194     return -1;
195
196   faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
197
198   if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
199     return -1;
200   newcb->family = family;
201   newcb->type = type;
202   newcb->flags = flags;
203   if (!newhandler)
204     newcb->handler = &bleck;
205   else
206     newcb->handler = newhandler;
207   newcb->next = NULL;
208   
209   if (!conn->handlerlist)
210     conn->handlerlist = newcb;
211   else {
212     struct aim_rxcblist_t *cur;
213
214     cur = conn->handlerlist;
215
216     while (cur->next)
217       cur = cur->next;
218     cur->next = newcb;
219   }
220
221   return 0;
222 }
223
224 faim_export int aim_clearhandlers(struct aim_conn_t *conn)
225 {
226  struct aim_rxcblist_t *cur;
227
228  if (!conn)
229    return -1;
230
231  cur = conn->handlerlist;
232  while(cur) {
233    struct aim_rxcblist_t *tmp;
234
235    tmp = cur->next;
236    free(cur);
237    cur = tmp;
238  }
239
240  return 0;
241 }
242
243 faim_internal rxcallback_t aim_callhandler(struct aim_conn_t *conn,
244                                          u_short family,
245                                          u_short type)
246 {
247   struct aim_rxcblist_t *cur;
248
249   if (!conn)
250     return NULL;
251
252   faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
253   
254   cur = conn->handlerlist;
255   while(cur)
256     {
257       if ( (cur->family == family) && (cur->type == type) )
258         return cur->handler;
259       cur = cur->next;
260     }
261
262   if (type==0xffff)
263     return NULL;
264
265   return aim_callhandler(conn, family, 0xffff);
266 }
267
268 faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
269                                           struct aim_conn_t *conn,
270                                           u_short family,
271                                           u_short type,
272                                           struct command_rx_struct *ptr)
273 {
274   rxcallback_t userfunc = NULL;
275   userfunc = aim_callhandler(conn, family, type);
276   if (userfunc)
277     return userfunc(sess, ptr);
278   return 1; /* XXX */
279 }
280
281 /*
282   aim_rxdispatch()
283
284   Basically, heres what this should do:
285     1) Determine correct packet handler for this packet
286     2) Mark the packet handled (so it can be dequeued in purge_queue())
287     3) Send the packet to the packet handler
288     4) Go to next packet in the queue and start over
289     5) When done, run purge_queue() to purge handled commands
290
291   Note that any unhandlable packets should probably be left in the
292   queue.  This is the best way to prevent data loss.  This means
293   that a single packet may get looked at by this function multiple
294   times.  This is more good than bad!  This behavior may change.
295
296   Aren't queue's fun? 
297
298   TODO: Get rid of all the ugly if's.
299   TODO: Clean up.
300   TODO: More support for mid-level handlers.
301   TODO: Allow for NULL handlers.
302   
303  */
304 faim_export int aim_rxdispatch(struct aim_session_t *sess)
305 {
306   int i = 0;
307   struct command_rx_struct *workingPtr = NULL;
308   
309   if (sess->queue_incoming == NULL) {
310     faimdprintf(1, "parse_generic: incoming packet queue empty.\n");
311     return 0;
312   } else {
313     workingPtr = sess->queue_incoming;
314     for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
315       /*
316        * XXX: This is still fairly ugly.
317        */
318       if (workingPtr->handled)
319         continue;
320
321       /*
322        * This is a debugging/sanity check only and probably could/should be removed
323        * for stable code.
324        */
325       if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && 
326            (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
327           ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && 
328            (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
329         printf("faim: rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
330         workingPtr->handled = 1;
331         continue;
332       }
333
334       switch(workingPtr->conn->type) {
335       case -1:
336         /*
337          * This can happen if we have a queued command
338          * that was recieved after a connection has 
339          * been terminated.  In which case, the handler
340          * list has been cleared, and there's nothing we
341          * can do for it.  We can only cancel it.
342          */
343         workingPtr->handled = 1;
344         break;
345       case AIM_CONN_TYPE_AUTH: {
346         unsigned long head;
347         
348         head = aimutil_get32(workingPtr->data);
349         if ((head == 0x00000001) && (workingPtr->commandlen == 4)) {
350           faimdprintf(1, "got connection ack on auth line\n");
351           workingPtr->handled = 1;
352         } else if (workingPtr->hdr.oscar.type == 0x04) {
353           /* Used only by the older login protocol */
354           workingPtr->handled = aim_authparse(sess, workingPtr);
355         } else {
356           unsigned short family,subtype;
357           
358           family = aimutil_get16(workingPtr->data);
359           subtype = aimutil_get16(workingPtr->data+2);
360           
361           switch (family) {
362             /* New login protocol */
363           case 0x0017:
364             if (subtype == 0x0001)
365               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
366             else if (subtype == 0x0003)
367               workingPtr->handled = aim_authparse(sess, workingPtr);
368             else if (subtype == 0x0007)
369               workingPtr->handled = aim_authkeyparse(sess, workingPtr);
370             else
371               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
372             break;
373          case 0x0007:
374            if (subtype == 0x0005)
375              workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
376            break;
377          case AIM_CB_FAM_SPECIAL:
378            if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
379              workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
380              break;
381            } /* others fall through */
382          default:
383 #if 0
384            /* Old login protocol */
385            /* any user callbacks will be called from here */
386            workingPtr->handled = aim_authparse(sess, workingPtr);
387 #endif
388             break;
389           }
390         }
391         break;
392       }
393       case AIM_CONN_TYPE_BOS: {
394         u_short family;
395         u_short subtype;
396
397         if (workingPtr->hdr.oscar.type == 0x04) {
398           workingPtr->handled = aim_negchan_middle(sess, workingPtr);
399           break;
400         }
401
402         family = aimutil_get16(workingPtr->data);
403         subtype = aimutil_get16(workingPtr->data+2);
404         
405         switch (family) {
406         case 0x0000: /* not really a family, but it works */
407           if (subtype == 0x0001)
408             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
409           else
410             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
411           break;
412         case 0x0001: /* Family: General */
413           switch (subtype) {
414           case 0x0001:
415             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
416             break;
417           case 0x0003:
418             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
419             break;
420           case 0x0005:
421             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
422             break;
423           case 0x0007:
424             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
425             break;
426           case 0x000a:
427             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
428             break;
429           case 0x000f:
430             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
431             break;
432           case 0x0010:
433             workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
434             break;
435           case 0x0013:
436             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
437             break;
438           default:
439             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
440             break;
441           }
442           break;
443         case 0x0002: /* Family: Location */
444           switch (subtype) {
445           case 0x0001:
446             workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
447             break;
448           case 0x0003:
449             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
450             break;
451           case 0x0006:
452             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
453             break;
454           default:
455             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
456             break;
457           }
458           break;
459         case 0x0003: /* Family: Buddy List */
460           switch (subtype) {
461           case 0x0001:
462             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
463             break;
464           case 0x0003:
465             workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
466             break;
467           case 0x000b: /* oncoming buddy */
468             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
469             break;
470           case 0x000c: /* offgoing buddy */
471             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
472             break;
473           default:
474             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
475           }
476           break;
477         case 0x0004: /* Family: Messeging */
478           switch (subtype) {
479           case 0x0001:
480             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
481             break;
482           case 0x0005:
483             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
484             break;
485           case 0x0006:
486             workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
487             break;
488           case 0x0007:
489             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
490             break;
491           case 0x000a:
492             workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
493             break;
494           case 0x000c:
495             workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
496             break;
497           default:
498             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
499           }
500           break;
501         case 0x0009:
502           if (subtype == 0x0001)
503             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
504           else if (subtype == 0x0003)
505             workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
506           else
507             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
508           break;
509         case 0x000a:  /* Family: User lookup */
510           switch (subtype) {
511           case 0x0001:
512             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
513             break;
514           case 0x0003:
515             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
516             break;
517           default:
518             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
519           }
520           break;
521         case 0x000b: {
522           if (subtype == 0x0001)
523             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
524           else if (subtype == 0x0002)
525             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
526           else
527             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
528           break;
529         }
530         case AIM_CB_FAM_SPECIAL: 
531           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
532           break;
533         default:
534           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
535           break;
536         } /* switch(family) */
537         break;
538       } /* AIM_CONN_TYPE_BOS */
539       case AIM_CONN_TYPE_CHATNAV: {
540         u_short family;
541         u_short subtype;
542         family = aimutil_get16(workingPtr->data);
543         subtype= aimutil_get16(workingPtr->data+2);
544         
545         if ((family == 0x0002) && (subtype == 0x0006)) {
546           workingPtr->handled = 1;
547           aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
548         } else if ((family == 0x000d) && (subtype == 0x0009)) {
549           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
550         } else {
551           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
552         }
553         break;
554       }
555       case AIM_CONN_TYPE_CHAT: {
556         u_short family, subtype;
557         
558         family = aimutil_get16(workingPtr->data);
559         subtype= aimutil_get16(workingPtr->data+2);
560         
561         if ((family == 0x0000) && (subtype == 0x00001))
562           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
563         else if (family == 0x0001) {
564           if (subtype == 0x0001)
565             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
566           else if (subtype == 0x0003)
567             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
568           else if (subtype == 0x0007)
569             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
570           else
571             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
572         } else if (family == 0x000e) {
573           if (subtype == 0x0002)
574             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
575           else if (subtype == 0x0003)
576             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
577           else if (subtype == 0x0004)
578             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
579           else if (subtype == 0x0006)
580             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
581           else  
582             printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
583         } else {
584           printf("Chat: unknown snac %04x/%04x\n", family, subtype);
585           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
586         }
587         break;
588       }
589       case AIM_CONN_TYPE_RENDEZVOUS: {
590         /* make sure that we only get OFT frames on these connections */
591         if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
592           printf("faim: internal error: non-OFT frames on OFT connection\n");
593           workingPtr->handled = 1; /* get rid of it */
594           break;
595         }
596         
597         /* XXX: implement this */
598         printf("faim: OFT frame!\n");
599         
600         break;
601       }
602       case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
603         /* not possible */
604         break;
605       }
606       default:
607         printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
608         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
609         break;
610       } 
611     }
612   }
613
614   /* 
615    * This doesn't have to be called here.  It could easily be done
616    * by a seperate thread or something. It's an administrative operation,
617    * and can take a while. Though the less you call it the less memory
618    * you'll have :)
619    */
620   aim_purge_rxqueue(sess);
621   
622   return 0;
623 }
624
625 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
626 {
627   rxcallback_t userfunc = NULL;
628   char sn[MAXSNLEN];
629   unsigned short type;
630   int i = 10+8; /* skip SNAC and cookie */
631   int ret = 1;
632   unsigned char snlen;
633
634   type = aimutil_get16(command->data+i);
635   i += 2;
636
637   snlen = aimutil_get8(command->data+i);
638   i++;
639
640   memset(sn, 0, sizeof(sn));
641   strncpy(sn, (char *)command->data+i, snlen);
642
643   if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x000c)))
644     ret =  userfunc(sess, command, type, sn);
645
646   return ret;
647 }
648
649 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
650 {
651   rxcallback_t userfunc = NULL;
652   int ret = 1;
653   unsigned long newrate;
654
655   if (command->commandlen != 0x2f) {
656     printf("faim: unknown rate change length 0x%04x\n", command->commandlen);
657     return 1;
658   }
659   
660   newrate = aimutil_get32(command->data+34);
661
662   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a)))
663     ret =  userfunc(sess, command, newrate);
664
665   return ret;
666 }
667
668 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
669 {
670   rxcallback_t userfunc = NULL;
671   int ret = 1, pos;
672   char *sn = NULL;
673
674   if(command->commandlen < 12) /* a warning level dec sends this */
675     return 1;
676
677   if ((pos = aimutil_get8(command->data+ 12)) > MAXSNLEN)
678     return 1;
679
680   if(!(sn = (char *)calloc(1, pos+1)))
681     return 1;
682
683   memcpy(sn, command->data+13, pos);
684
685   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010)))
686     ret = userfunc(sess, command, sn);
687   
688   free(sn);
689
690   return ret;
691 }
692
693 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
694                                        struct command_rx_struct *command, ...)
695 {
696   rxcallback_t userfunc = NULL;
697   char *msg;
698   int ret=1;
699   struct aim_tlvlist_t *tlvlist;
700   u_short id;
701
702   /*
703    * Code.
704    *
705    * Valid values:
706    *   1 Mandatory upgrade
707    *   2 Advisory upgrade
708    *   3 System bulletin
709    *   4 Nothing's wrong ("top o the world" -- normal)
710    *
711    */
712   id = aimutil_get16(command->data+10);
713
714   /* 
715    * TLVs follow 
716    */
717   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
718     return ret;
719
720   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
721     aim_freetlvchain(&tlvlist);
722     return ret;
723   }
724   
725   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
726   if (userfunc)
727     ret =  userfunc(sess, command, id, msg);
728
729   aim_freetlvchain(&tlvlist);
730   free(msg);
731
732   return ret;  
733 }
734
735 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
736                               struct command_rx_struct *command, ...)
737 {
738   struct aim_tlv_t *tmptlv = NULL;
739   int serviceid = 0x00;
740   unsigned char cookie[AIM_COOKIELEN];
741   char *ip = NULL;
742   rxcallback_t userfunc = NULL;
743   struct aim_tlvlist_t *tlvlist;
744   int ret = 1;
745   
746   if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
747     {
748       printf("libfaim: major bug: unable to read tlvchain from redirect\n");
749       return ret;
750     }
751   
752   if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) 
753     {
754       printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
755       aim_freetlvchain(&tlvlist);
756       return ret;
757     }
758   serviceid = aimutil_get16(tmptlv->value);
759
760   if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) 
761     {
762       printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
763       free(ip);
764       aim_freetlvchain(&tlvlist);
765       return ret;
766     }
767   
768   if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
769     {
770       printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
771       free(ip);
772       aim_freetlvchain(&tlvlist);
773       return ret;
774     }
775   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
776
777   if (serviceid == AIM_CONN_TYPE_CHAT)
778     {
779       /*
780        * Chat hack.
781        *
782        */
783       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
784       if (userfunc)
785         ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
786       free(sess->pendingjoin);
787       sess->pendingjoin = NULL;
788     }
789   else
790     {
791       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
792       if (userfunc)
793         ret =  userfunc(sess, command, serviceid, ip, cookie);
794     }
795
796   free(ip);
797   aim_freetlvchain(&tlvlist);
798
799   return ret;
800 }
801
802 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
803                                           struct command_rx_struct *command, ...)
804 {
805   u_int i = 0;
806
807   faimdprintf(1, "\nRecieved unknown packet:");
808
809   for (i = 0; i < command->commandlen; i++)
810     {
811       if ((i % 8) == 0)
812         faimdprintf(1, "\n\t");
813
814       faimdprintf(1, "0x%2x ", command->data[i]);
815     }
816   
817   faimdprintf(1, "\n\n");
818
819   return 1;
820 }
821
822
823 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
824                                      struct command_rx_struct *command)
825 {
826   struct aim_tlvlist_t *tlvlist;
827   char *msg = NULL;
828   unsigned short code = 0;
829   struct aim_tlv_t *tmptlv;
830   rxcallback_t userfunc = NULL;
831   int ret = 1;
832
833   tlvlist = aim_readtlvchain(command->data, command->commandlen);
834
835   if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
836     code = aimutil_get16(tmptlv->value);
837
838   if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
839     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
840
841   userfunc = aim_callhandler(command->conn, 
842                              AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
843   if (userfunc)
844     ret =  userfunc(sess, command, code, msg);
845
846   aim_freetlvchain(&tlvlist);
847   free(msg);
848
849   return ret;
850 }
851
852 /*
853  * aim_parse_generalerrs()
854  *
855  * Middle handler for 0x0001 snac of each family.
856  *
857  */
858 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
859                                         struct command_rx_struct *command, ...)
860 {
861   u_short family;
862   u_short subtype;
863   
864   family = aimutil_get16(command->data+0);
865   subtype= aimutil_get16(command->data+2);
866   
867   switch(family)
868     {
869     default:
870       /* Unknown family */
871       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
872     }
873
874   return 1;
875 }
876
877
878
This page took 0.091724 seconds and 3 git commands to generate.