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