]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
- Sun Mar 19 06:07:52 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; i++) {
308       /*
309        * XXX: This is still fairly ugly.
310        */
311       switch(workingPtr->conn->type) {
312       case -1:
313         /*
314          * This can happen if we have a queued command
315          * that was recieved after a connection has 
316          * been terminated.  In which case, the handler
317          * list has been cleared, and there's nothing we
318          * can do for it.  We can only cancel it.
319          */
320         workingPtr->handled = 1;
321         break;
322       case AIM_CONN_TYPE_AUTH: {
323         u_long head;
324         
325         head = aimutil_get32(workingPtr->data);
326         if (head == 0x00000001) {
327           faimdprintf(1, "got connection ack on auth line\n");
328           workingPtr->handled = 1;
329         } else {
330           u_short family,subtype;
331           
332           family = aimutil_get16(workingPtr->data);
333           subtype = aimutil_get16(workingPtr->data+2);
334           
335           switch (family) {
336             /* New login protocol */
337 #ifdef SNACLOGIN
338           case 0x0017:
339             if (subtype == 0x0001)
340               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
341             else if (subtype == 0x0003)
342               workingPtr->handled = aim_authparse(sess, workingPtr);
343             else if (subtype == 0x0007)
344               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
345             else
346               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
347             break;
348 #else   
349             /* XXX: this isnt foolproof */
350           case 0x0001:
351             if (subtype == 0x0003)
352               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
353             else
354               workingPtr->handled = aim_authparse(sess, workingPtr);
355             break;
356           case 0x0007:
357             if (subtype == 0x0005)
358               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
359             break;
360           default:
361             /* Old login protocol */
362             /* any user callbacks will be called from here */
363             workingPtr->handled = aim_authparse(sess, workingPtr);
364 #endif
365           }
366         }
367         break;
368       }
369       case AIM_CONN_TYPE_BOS: {
370         u_short family;
371         u_short subtype;
372         
373         family = aimutil_get16(workingPtr->data);
374         subtype = aimutil_get16(workingPtr->data+2);
375         
376         switch (family) {
377         case 0x0000: /* not really a family, but it works */
378           if (subtype == 0x0001)
379             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
380           else
381             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
382           break;
383         case 0x0001: /* Family: General */
384           switch (subtype) {
385           case 0x0001:
386             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
387             break;
388           case 0x0003:
389             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
390             break;
391           case 0x0005:
392             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
393             break;
394           case 0x0007:
395             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
396             break;
397           case 0x000a:
398             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
399             break;
400           case 0x000f:
401             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
402             break;
403           case 0x0013:
404             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
405             break;
406           default:
407             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
408             break;
409           }
410         case 0x0002: /* Family: Location */
411           switch (subtype) {
412           case 0x0001:
413             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
414             break;
415           case 0x0003:
416             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
417             break;
418           case 0x0006:
419             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
420             break;
421           default:
422             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
423             break;
424           }
425         case 0x0003: /* Family: Buddy List */
426           switch (subtype) {
427           case 0x0001:
428             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
429             break;
430           case 0x0003:
431             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
432             break;
433           case 0x000b: /* oncoming buddy */
434             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
435             break;
436           case 0x000c: /* offgoing buddy */
437             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
438             break;
439           default:
440             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
441           }
442           break;
443         case 0x0004: /* Family: Messeging */
444           switch (subtype) {
445           case 0x0001:
446             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
447             break;
448           case 0x0005:
449             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
450             break;
451           case 0x0007:
452             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
453             break;
454           case 0x000a:
455             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
456             break;
457           default:
458             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
459           }
460           break;
461         case 0x0009:
462           if (subtype == 0x0001)
463             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
464           else if (subtype == 0x0003)
465             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
466           else
467             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
468           break;
469         case 0x000a:  /* Family: User lookup */
470           switch (subtype) {
471           case 0x0001:
472             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
473             break;
474           case 0x0003:
475             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
476             break;
477           default:
478             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
479           }
480           break;
481         case 0x000b:
482           if (subtype == 0x0001)
483             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
484           else if (subtype == 0x0002)
485             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
486           else
487             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
488           break;
489         default:
490           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
491           break;
492         }
493         break;
494       }
495       case AIM_CONN_TYPE_CHATNAV: {
496         u_short family;
497         u_short subtype;
498         family = aimutil_get16(workingPtr->data);
499         subtype= aimutil_get16(workingPtr->data+2);
500         
501         if ((family == 0x0002) && (subtype == 0x0006)) {
502           workingPtr->handled = 1;
503           aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
504         } else if ((family == 0x000d) && (subtype == 0x0009)) {
505           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
506         } else {
507           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
508         }
509         break;
510       }
511       case AIM_CONN_TYPE_CHAT: {
512         u_short family, subtype;
513         
514         family = aimutil_get16(workingPtr->data);
515         subtype= aimutil_get16(workingPtr->data+2);
516         
517         if ((family == 0x0000) && (subtype == 0x00001))
518           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
519         else if (family == 0x0001) {
520           if (subtype == 0x0001)
521             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
522           else if (subtype == 0x0003)
523             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
524           else if (subtype == 0x0007)
525             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
526           else
527             printf("Chat: unknown snac %04x/%04x\n", family, subtype);
528         } else if (family == 0x000e) {
529           if (subtype == 0x0002)
530             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
531           else if (subtype == 0x0003)
532             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
533           else if (subtype == 0x0004)
534             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
535           else if (subtype == 0x0006)
536             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
537           else  
538             printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
539         } else {
540           printf("Chat: unknown snac %04x/%04x\n", family, subtype);
541           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
542         }
543         break;
544       }
545       default:
546         printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
547         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
548         break;
549       } 
550       /* move to next command */
551       workingPtr = workingPtr->next;
552     }
553   }
554
555   /* 
556    * This doesn't have to be called here.  It could easily be done
557    * by a seperate thread or something. It's an administrative operation,
558    * and can take a while. Though the less you call it the less memory
559    * you'll have :)
560    */
561   aim_purge_rxqueue(sess);
562   
563   return 0;
564 }
565
566 int aim_parsemotd_middle(struct aim_session_t *sess,
567                               struct command_rx_struct *command, ...)
568 {
569   rxcallback_t userfunc = NULL;
570   char *msg;
571   int ret=1;
572   struct aim_tlvlist_t *tlvlist;
573   u_short id;
574
575   /*
576    * Dunno.
577    */
578   id = aimutil_get16(command->data+10);
579
580   /* 
581    * TLVs follow 
582    */
583   tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
584   
585   msg = aim_gettlv_str(tlvlist, 0x000b, 1);
586   
587   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
588   if (userfunc)
589     ret =  userfunc(sess, command, id, msg);
590
591   aim_freetlvchain(&tlvlist);
592
593   return ret;
594   
595 }
596
597 int aim_handleredirect_middle(struct aim_session_t *sess,
598                               struct command_rx_struct *command, ...)
599 {
600   struct aim_tlv_t *tmptlv = NULL;
601   int serviceid = 0x00;
602   char cookie[AIM_COOKIELEN];
603   char *ip = NULL;
604   rxcallback_t userfunc = NULL;
605   struct aim_tlvlist_t *tlvlist;
606   int ret = 1;
607   
608   if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
609     {
610       printf("libfaim: major bug: unable to read tlvchain from redirect\n");
611       return ret;
612     }
613   
614   if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) 
615     {
616       printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
617       aim_freetlvchain(&tlvlist);
618       return ret;
619     }
620   serviceid = aimutil_get16(tmptlv->value);
621
622   if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) 
623     {
624       printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
625       aim_freetlvchain(&tlvlist);
626       return ret;
627     }
628   
629   if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
630     {
631       printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
632       aim_freetlvchain(&tlvlist);
633       return ret;
634     }
635   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
636
637   if (serviceid == AIM_CONN_TYPE_CHAT)
638     {
639       /*
640        * Chat hack.
641        *
642        */
643       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
644       if (userfunc)
645         ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
646       free(sess->pendingjoin);
647       sess->pendingjoin = NULL;
648     }
649   else
650     {
651       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
652       if (userfunc)
653         ret =  userfunc(sess, command, serviceid, ip, cookie);
654     }
655
656   /*
657    * XXX: Is there a leak here?  Where does IP get freed?
658    */
659   aim_freetlvchain(&tlvlist);
660
661   return ret;
662 }
663
664 int aim_parse_unknown(struct aim_session_t *sess,
665                       struct command_rx_struct *command, ...)
666 {
667   u_int i = 0;
668
669   faimdprintf(1, "\nRecieved unknown packet:");
670
671   for (i = 0; i < command->commandlen; i++)
672     {
673       if ((i % 8) == 0)
674         printf("\n\t");
675
676       printf("0x%2x ", command->data[i]);
677     }
678   
679   printf("\n\n");
680
681   return 1;
682 }
683
684
685 /*
686  * aim_parse_generalerrs()
687  *
688  * Middle handler for 0x0001 snac of each family.
689  *
690  */
691 int aim_parse_generalerrs(struct aim_session_t *sess,
692                           struct command_rx_struct *command, ...)
693 {
694   u_short family;
695   u_short subtype;
696   
697   family = aimutil_get16(command->data+0);
698   subtype= aimutil_get16(command->data+2);
699   
700   switch(family)
701     {
702     default:
703       /* Unknown family */
704       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
705     }
706
707   return 1;
708 }
709
710
711
This page took 0.094963 seconds and 5 git commands to generate.