]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
- Wed Nov 8 02:23:25 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 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         u_long head;
347         
348         head = aimutil_get32(workingPtr->data);
349         if (head == 0x00000001) {
350           faimdprintf(1, "got connection ack on auth line\n");
351           workingPtr->handled = 1;
352         } else if (workingPtr->hdr.oscar.type == 0x0004) {
353           workingPtr->handled = aim_authparse(sess, workingPtr);
354         } else {
355           u_short family,subtype;
356           
357           family = aimutil_get16(workingPtr->data);
358           subtype = aimutil_get16(workingPtr->data+2);
359           
360           switch (family) {
361             /* New login protocol */
362           case 0x0017:
363             if (subtype == 0x0001)
364               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
365             else if (subtype == 0x0003)
366               workingPtr->handled = aim_authparse(sess, workingPtr);
367             else if (subtype == 0x0007)
368               workingPtr->handled = aim_authkeyparse(sess, workingPtr);
369             else
370               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
371             break;
372          case 0x0007:
373            if (subtype == 0x0005)
374              workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
375            break;
376          case AIM_CB_FAM_SPECIAL:
377            if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
378              workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
379              break;
380            } /* others fall through */
381          default:
382 #if 0
383            /* Old login protocol */
384            /* any user callbacks will be called from here */
385            workingPtr->handled = aim_authparse(sess, workingPtr);
386 #endif
387             break;
388           }
389         }
390         break;
391       }
392       case AIM_CONN_TYPE_BOS: {
393         u_short family;
394         u_short subtype;
395
396         if (workingPtr->hdr.oscar.type == 0x04) {
397           workingPtr->handled = aim_negchan_middle(sess, workingPtr);
398           break;
399         }
400
401         family = aimutil_get16(workingPtr->data);
402         subtype = aimutil_get16(workingPtr->data+2);
403         
404         switch (family) {
405         case 0x0000: /* not really a family, but it works */
406           if (subtype == 0x0001)
407             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
408           else
409             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
410           break;
411         case 0x0001: /* Family: General */
412           switch (subtype) {
413           case 0x0001:
414             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
415             break;
416           case 0x0003:
417             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
418             break;
419           case 0x0005:
420             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
421             break;
422           case 0x0007:
423             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
424             break;
425           case 0x000a:
426             workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
427             break;
428           case 0x000f:
429             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
430             break;
431           case 0x0010:
432             workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
433             break;
434           case 0x0013:
435             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
436             break;
437           default:
438             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
439             break;
440           }
441           break;
442         case 0x0002: /* Family: Location */
443           switch (subtype) {
444           case 0x0001:
445             workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
446             break;
447           case 0x0003:
448             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
449             break;
450           case 0x0006:
451             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
452             break;
453           default:
454             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
455             break;
456           }
457           break;
458         case 0x0003: /* Family: Buddy List */
459           switch (subtype) {
460           case 0x0001:
461             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
462             break;
463           case 0x0003:
464             workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
465             break;
466           case 0x000b: /* oncoming buddy */
467             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
468             break;
469           case 0x000c: /* offgoing buddy */
470             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
471             break;
472           default:
473             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
474           }
475           break;
476         case 0x0004: /* Family: Messeging */
477           switch (subtype) {
478           case 0x0001:
479             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
480             break;
481           case 0x0005:
482             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
483             break;
484           case 0x0006:
485             workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
486             break;
487           case 0x0007:
488             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
489             break;
490           case 0x000a:
491             workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
492             break;
493           case 0x000c:
494             workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
495             break;
496           default:
497             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
498           }
499           break;
500         case 0x0009:
501           if (subtype == 0x0001)
502             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
503           else if (subtype == 0x0003)
504             workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
505           else
506             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
507           break;
508         case 0x000a:  /* Family: User lookup */
509           switch (subtype) {
510           case 0x0001:
511             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
512             break;
513           case 0x0003:
514             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
515             break;
516           default:
517             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
518           }
519           break;
520         case 0x000b: {
521           if (subtype == 0x0001)
522             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
523           else if (subtype == 0x0002)
524             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
525           else
526             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
527           break;
528         }
529         case AIM_CB_FAM_SPECIAL: 
530           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
531           break;
532         default:
533           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
534           break;
535         } /* switch(family) */
536         break;
537       } /* AIM_CONN_TYPE_BOS */
538       case AIM_CONN_TYPE_CHATNAV: {
539         u_short family;
540         u_short subtype;
541         family = aimutil_get16(workingPtr->data);
542         subtype= aimutil_get16(workingPtr->data+2);
543         
544         if ((family == 0x0002) && (subtype == 0x0006)) {
545           workingPtr->handled = 1;
546           aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
547         } else if ((family == 0x000d) && (subtype == 0x0009)) {
548           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
549         } else {
550           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
551         }
552         break;
553       }
554       case AIM_CONN_TYPE_CHAT: {
555         u_short family, subtype;
556         
557         family = aimutil_get16(workingPtr->data);
558         subtype= aimutil_get16(workingPtr->data+2);
559         
560         if ((family == 0x0000) && (subtype == 0x00001))
561           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
562         else if (family == 0x0001) {
563           if (subtype == 0x0001)
564             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
565           else if (subtype == 0x0003)
566             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
567           else if (subtype == 0x0007)
568             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
569           else
570             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
571         } else if (family == 0x000e) {
572           if (subtype == 0x0002)
573             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
574           else if (subtype == 0x0003)
575             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
576           else if (subtype == 0x0004)
577             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
578           else if (subtype == 0x0006)
579             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
580           else  
581             printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
582         } else {
583           printf("Chat: unknown snac %04x/%04x\n", family, subtype);
584           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
585         }
586         break;
587       }
588       case AIM_CONN_TYPE_RENDEZVOUS: {
589         /* make sure that we only get OFT frames on these connections */
590         if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
591           printf("faim: internal error: non-OFT frames on OFT connection\n");
592           workingPtr->handled = 1; /* get rid of it */
593           break;
594         }
595         
596         /* XXX: implement this */
597         printf("faim: OFT frame!\n");
598         
599         break;
600       }
601       case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
602         /* not possible */
603         break;
604       }
605       default:
606         printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
607         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
608         break;
609       } 
610     }
611   }
612
613   /* 
614    * This doesn't have to be called here.  It could easily be done
615    * by a seperate thread or something. It's an administrative operation,
616    * and can take a while. Though the less you call it the less memory
617    * you'll have :)
618    */
619   aim_purge_rxqueue(sess);
620   
621   return 0;
622 }
623
624 faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
625 {
626   rxcallback_t userfunc = NULL;
627   char sn[MAXSNLEN];
628   unsigned short type;
629   int i = 10+8; /* skip SNAC and cookie */
630   int ret = 1;
631   unsigned char snlen;
632
633   type = aimutil_get16(command->data+i);
634   i += 2;
635
636   snlen = aimutil_get8(command->data+i);
637   i++;
638
639   memset(sn, 0, sizeof(sn));
640   strncpy(sn, (char *)command->data+i, snlen);
641
642   if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x000c)))
643     ret =  userfunc(sess, command, type, sn);
644
645   return ret;
646 }
647
648 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
649 {
650   rxcallback_t userfunc = NULL;
651   int ret = 1;
652   unsigned long newrate;
653
654   if (command->commandlen != 0x2f) {
655     printf("faim: unknown rate change length 0x%04x\n", command->commandlen);
656     return 1;
657   }
658   
659   newrate = aimutil_get32(command->data+34);
660
661   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a)))
662     ret =  userfunc(sess, command, newrate);
663
664   return ret;
665 }
666
667 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
668 {
669   rxcallback_t userfunc = NULL;
670   int ret = 1, pos;
671   char *sn = NULL;
672
673   if(command->commandlen < 12) /* a warning level dec sends this */
674     return 1;
675
676   if ((pos = aimutil_get8(command->data+ 12)) > MAXSNLEN)
677     return 1;
678
679   if(!(sn = (char *)calloc(1, pos+1)))
680     return 1;
681
682   memcpy(sn, command->data+13, pos);
683
684   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010)))
685     ret = userfunc(sess, command, sn);
686   
687   free(sn);
688
689   return ret;
690 }
691
692 faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
693                                        struct command_rx_struct *command, ...)
694 {
695   rxcallback_t userfunc = NULL;
696   char *msg;
697   int ret=1;
698   struct aim_tlvlist_t *tlvlist;
699   u_short id;
700
701   /*
702    * Code.
703    *
704    * Valid values:
705    *   1 Mandatory upgrade
706    *   2 Advisory upgrade
707    *   3 System bulletin
708    *   4 Nothing's wrong ("top o the world" -- normal)
709    *
710    */
711   id = aimutil_get16(command->data+10);
712
713   /* 
714    * TLVs follow 
715    */
716   if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
717     return ret;
718
719   if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
720     aim_freetlvchain(&tlvlist);
721     return ret;
722   }
723   
724   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
725   if (userfunc)
726     ret =  userfunc(sess, command, id, msg);
727
728   aim_freetlvchain(&tlvlist);
729   free(msg);
730
731   return ret;  
732 }
733
734 faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
735                               struct command_rx_struct *command, ...)
736 {
737   struct aim_tlv_t *tmptlv = NULL;
738   int serviceid = 0x00;
739   unsigned char cookie[AIM_COOKIELEN];
740   char *ip = NULL;
741   rxcallback_t userfunc = NULL;
742   struct aim_tlvlist_t *tlvlist;
743   int ret = 1;
744   
745   if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
746     {
747       printf("libfaim: major bug: unable to read tlvchain from redirect\n");
748       return ret;
749     }
750   
751   if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) 
752     {
753       printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
754       aim_freetlvchain(&tlvlist);
755       return ret;
756     }
757   serviceid = aimutil_get16(tmptlv->value);
758
759   if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) 
760     {
761       printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
762       free(ip);
763       aim_freetlvchain(&tlvlist);
764       return ret;
765     }
766   
767   if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
768     {
769       printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
770       free(ip);
771       aim_freetlvchain(&tlvlist);
772       return ret;
773     }
774   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
775
776   if (serviceid == AIM_CONN_TYPE_CHAT)
777     {
778       /*
779        * Chat hack.
780        *
781        */
782       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
783       if (userfunc)
784         ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
785       free(sess->pendingjoin);
786       sess->pendingjoin = NULL;
787     }
788   else
789     {
790       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
791       if (userfunc)
792         ret =  userfunc(sess, command, serviceid, ip, cookie);
793     }
794
795   free(ip);
796   aim_freetlvchain(&tlvlist);
797
798   return ret;
799 }
800
801 faim_internal int aim_parse_unknown(struct aim_session_t *sess,
802                                           struct command_rx_struct *command, ...)
803 {
804   u_int i = 0;
805
806   faimdprintf(1, "\nRecieved unknown packet:");
807
808   for (i = 0; i < command->commandlen; i++)
809     {
810       if ((i % 8) == 0)
811         faimdprintf(1, "\n\t");
812
813       faimdprintf(1, "0x%2x ", command->data[i]);
814     }
815   
816   faimdprintf(1, "\n\n");
817
818   return 1;
819 }
820
821
822 faim_internal int aim_negchan_middle(struct aim_session_t *sess,
823                                      struct command_rx_struct *command)
824 {
825   struct aim_tlvlist_t *tlvlist;
826   char *msg = NULL;
827   unsigned short code = 0;
828   struct aim_tlv_t *tmptlv;
829   rxcallback_t userfunc = NULL;
830   int ret = 1;
831
832   tlvlist = aim_readtlvchain(command->data, command->commandlen);
833
834   if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
835     code = aimutil_get16(tmptlv->value);
836
837   if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
838     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
839
840   userfunc = aim_callhandler(command->conn, 
841                              AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
842   if (userfunc)
843     ret =  userfunc(sess, command, code, msg);
844
845   aim_freetlvchain(&tlvlist);
846   free(msg);
847
848   return ret;
849 }
850
851 /*
852  * aim_parse_generalerrs()
853  *
854  * Middle handler for 0x0001 snac of each family.
855  *
856  */
857 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
858                                         struct command_rx_struct *command, ...)
859 {
860   u_short family;
861   u_short subtype;
862   
863   family = aimutil_get16(command->data+0);
864   subtype= aimutil_get16(command->data+2);
865   
866   switch(family)
867     {
868     default:
869       /* Unknown family */
870       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
871     }
872
873   return 1;
874 }
875
876
877
This page took 1.23732 seconds and 5 git commands to generate.