FTPD.D
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:22k
源码类别:

操作系统开发

开发平台:

DOS

  1. /*
  2.  * Copyright (c) 1990, 1999 Erick Engelke
  3.  */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <time.h>
  10. #include <ctype.h>
  11. #include <io.h>
  12. #include <mem.h>
  13. #include <rtos.h>
  14. #include <net.h>
  15. #include <dir.h>
  16. #include <dos.h>
  17. #include <share.h>
  18. #define S_INIT  0
  19. #define S_WAIT  1
  20. #define S_CONN  2   /* connected and talking */
  21. #define S_DATA  4
  22. #define S_CLOS  5
  23. #define S_HALT  6   /* halt service */
  24. char *cmds[] = {
  25.     "ABOR", "QUIT", "PASS", "HELP", "NOOP", "USER", 
  26.     "MKD",  "XMKD", "RMD",  "XRMD", "CWD",  "XCWD", "PWD",  "XPWD",
  27.     "SITE", "DEL" , "TYPE", "SIZE", "PORT", "LIST", "NLST", "STOR", "RETR"
  28.     };
  29. enum {
  30.      ABOR,   QUIT,   PASS,   HELP,   NOOP,   USER,
  31.      MKD,    XMKD,   RMD,    XRMD,   CWD,    XCWD,   PWD,    XPWD,
  32.      SITE,   DEL,    TYPE,   SIZE,   PORT,   LIST,   NLST,   STOR,   RETR,
  33.      ENDLIST };
  34. #define FTPDPASS   "FTPD.PASSWORD"
  35. #define FTPDBUFSIZ "FTPD.BUFSIZ"
  36. #define FTPDPORT    21
  37. #define FTP_OP_DIR  0
  38. #define FTP_OP_GET  1
  39. #define FTP_OP_PUT  2
  40. #define FTP_OP_DON  3
  41. #define FTP_OP_NOP  4
  42. #define FTPDIRLEN  65
  43. #define FTPPATHLEN 81
  44. typedef struct {
  45.     int         status;
  46.     tcp_Socket socket;
  47.     int         dstatus;
  48.     int         doperation;
  49.     int         dcmd;
  50.     tcp_Socket  dsocket;
  51.     struct ffblk ffblk;
  52.     int         dhandle;        /* for file transfer */
  53.     int         gotpass;
  54.     int         ascii;         /* 1 is ascii */
  55.     longword    biglen;         /* for file transfer completion stats */
  56.     word        bufhead;
  57.     word        buftail;
  58.     longword    hisip;          /* used for data connections */
  59.     word        hisport;
  60.     char       *errmsg;
  61.     char        dirpath[ FTPDIRLEN ];
  62.     char        filepath[ FTPPATHLEN ];
  63. } ftpdses;
  64. static char *ftpdbuffer;
  65. int   ftpdbufferlen = 0;
  66. static ftpdses *ftpd;
  67. char ftpdpassword[ 128 ];
  68. char ftpdwelcome[ 128 ];
  69. extern void *getvalue( char * p );
  70. extern int cmdcompare( char *p, char *command );
  71. typedef struct dostimedate {
  72.     unsigned xxx  : 5;
  73.     unsigned min  : 6;
  74.     unsigned hour : 5;
  75.     unsigned date : 5;
  76.     unsigned mon  : 4;
  77.     unsigned year : 7;
  78. };
  79. /*
  80.  * handlerrs - install an error handler which simply returns as though fail
  81.  *             was sellected by the user
  82.  */
  83. static void interrupt (*olderrhandler)();
  84. #pragma warn -par
  85. /*
  86.  * handlerrs - it prevents abort,retry,ignore,...
  87.  *      - coded Borland specific
  88.  *      - start = nonzero installs handler, zero resets it
  89.  */
  90. static void handlerrs( int start )
  91. {
  92.     if ( start ) {
  93. olderrhandler = getvect( 0x24 );
  94. harderr( (int (*)()) hardretn );
  95.     } else
  96. setvect( 0x24, olderrhandler );
  97. }
  98. /*
  99.  * strins - copy little_string into big_string
  100.  *
  101.  * eg. strins( "0123456", "abcd", 2 ) creates "ab23456"
  102.  */
  103. static void strins( char *big, char *little, int len )
  104. {
  105.     int movlen;
  106.     movlen = min( strlen( little ), ((len > 0) ? len : -len));
  107.     if ( len > 0 ) movmem( little, big, movlen );
  108.     else movmem( little, big - (len + movlen), movlen );
  109. }
  110. /*
  111.  * dirformblock - create a unix "ls -l" style of output for this dir entry
  112.  */
  113. static
  114. void
  115. dirformblock( struct ffblk* ff, char* formatted)
  116. {
  117.   struct dostimedate* pdos_time = (struct dostimedate*) &ff->ff_ftime;
  118.   struct tm unix_time;
  119.   time_t timer = time( NULL );
  120.   int current_year = localtime( &timer )->tm_year + 1900; /* UNIX year bias */
  121.   char buf[16];
  122.   int i;
  123.   memset(&unix_time, 0, sizeof(unix_time));
  124.   unix_time.tm_min  = pdos_time->min;
  125.   unix_time.tm_hour = pdos_time->hour;
  126.   unix_time.tm_mday = pdos_time->date;
  127.   unix_time.tm_mon  = pdos_time->mon - 1; /* DOS months 1-12, UNIX months 0-11 */
  128.   unix_time.tm_year = pdos_time->year + 1980 /* DOS year bias */ - 1900 /* UNIX year bias */;
  129.   
  130.   sprintf( formatted, "%c", ff->ff_attrib & FA_DIREC ? 'd' : '-' );
  131.   sprintf( buf, "r%cx", !(ff->ff_attrib & FA_RDONLY) ? 'w' : '-' );
  132.   for(i = 0; i<3; i++)
  133.     strcat( formatted, buf );
  134.   sprintf( strchr(formatted, 0), " 1 user users %10s ", ltoa( ff->ff_fsize, buf, 10 ) );
  135.   strftime( strchr(formatted, 0), -1,
  136.     pdos_time->year + 1980 == current_year ? "%b %d %H:%M " : "%b %d  %Y ", &unix_time
  137.   );
  138.   strcat(formatted, ff->ff_name);
  139.   strcat(formatted, "rn");
  140. }
  141. /*
  142.  * functions to handle paths
  143.  */
  144. static char *pathfile( ftpdses *f, char *fname )
  145. {
  146.     /* better return bad name than overwrite buffers */
  147.     if ( (strlen( f->dirpath ) + strlen( fname ) - 2) >= FTPPATHLEN )
  148.         return( fname );
  149.     strcpy( f->filepath, ".\");
  150.     if ( *f->dirpath ) {
  151.         strcat( f->filepath, f->dirpath );
  152.         strcat( f->filepath, "\");
  153.     }
  154.     strcat( f->filepath, fname );
  155.     return( f->filepath );
  156. }
  157. static int changedir( ftpdses *f, char *path)
  158. {
  159.     struct stat st;
  160.     char *p;
  161.     /* fix unix styled slashes */
  162.     while ( (p = strchr( path, '/' )) != NULL ) *p = '\';
  163.     /* handle up one dir */
  164.     if ( (path[0] == '.') && (path[1] == '.' )) {
  165.         /* go up a subdir */
  166.         if ( (p = strrchr( f->dirpath, '\'))!= NULL) {
  167.             *p = 0;
  168.         } else
  169.             f->dirpath[0] = 0;
  170.         return( 0 );    /* say it was successful */
  171.     }
  172.     /*  root is . */
  173.     if ( (path[0] == '\' ) && ( path[1] == 0 )) {
  174.         *f->dirpath = 0;
  175.         return( 0 );
  176.     }
  177.     /* if they didn't specify  then assume we are adding to path */
  178.     if ( *path == '\' )
  179.         path++;     /* skip leading  for relative directory */
  180.     else {
  181.         strcpy( f->filepath, f->dirpath );
  182.         if ( *f->dirpath )
  183.             strcat( f->filepath, "\");
  184.         strcat( f->filepath, path );
  185.         path = f->filepath;
  186.     }
  187.     if ( stat( path, &st ) != 0 )      /* no such file or directory */
  188.         return( 1 );
  189.     if ((st.st_mode & S_IFDIR ) == 0 )
  190.         return( 1 ); /* not a directory */
  191.     /* use new directory path */
  192.     strncpy( f->dirpath, path, FTPDIRLEN - 1 );
  193.     f->dirpath[ FTPDIRLEN - 1] = 0;
  194.     return( 0 );
  195. }
  196. /*
  197.  * data_op_... operations on data socket
  198.  */
  199. /*
  200.  * data_op_get - does a "GET"
  201.  *             - could be optimized for speed by allocing a second
  202.  *               buffer and performing the DOS read while waiting for
  203.  *               the remote host to ack the data
  204.  */
  205. static void data_op_get( ftpdses *f, tcp_Socket *t )
  206. {
  207.     int len;
  208.     unsigned diff;
  209.     if ( sock_tbused( t ) == 0 ){
  210. //      if ((diff = _dos_read( f->dhandle, ftpdbuffer, ftpdbufferlen )) <= 0 ) {
  211.         diff = 0;
  212.         if( _dos_read( f->dhandle, ftpdbuffer, ftpdbufferlen, &diff ) != 0 )
  213.     f->errmsg = "550 Error while trying to read filern";        
  214.         else if ( diff == 0 ) /* eof or possibly error condition */
  215.     f->doperation = FTP_OP_DON;
  216.         else
  217.             sock_write( t, ftpdbuffer, diff );
  218.     }
  219. }
  220. static void data_op_init( ftpdses *f, word operation )
  221. {
  222.     f->doperation = operation;
  223.     f->dstatus = S_INIT;
  224.     f->status = S_DATA;
  225.     f->biglen = 0;
  226.     f->bufhead = f->buftail = 0;
  227.     f->errmsg = "250 Donern";
  228.     sock_puts( &f->socket, "150 Openning data connectionrn");
  229. }
  230. static void c_op_dir( ftpdses *f, char *path )
  231. {
  232.     char buffer[ 81 ], p;
  233.     int status;
  234.     f->dhandle = 0;
  235.     /* support pseudo-standard -L */
  236.     if ( !strnicmp( path, "-L", 2 )) {
  237.         path += 2;
  238.         if ( !*path ) path = NULL;
  239.     }
  240.     /* new for directories */
  241.     if ( path != NULL ) strcpy( buffer, pathfile( f, path ));
  242.     else strcpy( buffer, pathfile( f, "*.*" ));
  243. //    if (path != NULL ) movmem( path, buffer, sizeof(buffer) - 1 );
  244. //    else strcpy( buffer, "*.*" );
  245.     buffer[ sizeof( buffer ) - 1 ] = 0;
  246.     status = findfirst( buffer, &f->ffblk, FA_DIREC);
  247.     if ( !strchr( buffer, '*' ) &&
  248.          !strchr( buffer, '?' ) &&
  249.          !status                &&
  250.          (ftpd->ffblk.ff_attrib & FA_DIREC ) &&
  251.  *ftpd->ffblk.ff_name != '.') {
  252. strcat( buffer, "\*.*");
  253. status = findfirst( buffer, &f->ffblk, FA_DIREC);
  254.     }
  255.     if (!status) data_op_init( f, FTP_OP_DIR );
  256.     else sock_puts(&f->socket, "550 File or directory not foundrn");
  257. }
  258. static void (*oldinit)(char *, char *);
  259. static void newinit( char *directive, char *value )
  260. {
  261.     if (!strcmp( directive, FTPDPASS )) {
  262.         strncpy( ftpdpassword, value, sizeof(ftpdpassword)-1);
  263.         ftpdpassword[ sizeof(ftpdpassword) - 1] = 0;
  264.     } else if (!strcmp( directive, FTPDBUFSIZ ))
  265.         ftpdbufferlen = atoi( value );
  266.     else
  267.         if (oldinit) (*oldinit)( directive, value );
  268. }
  269. /*
  270.  * getport - reads the FTP port negotiation stuff
  271.  *         - return nonzero on success
  272.  *
  273.  */
  274. static int getport( ftpdses *f, char *text )
  275. {
  276.     byte a[6], *p;
  277.     int i;
  278.     for ( i = 0 ; (i < 6) && text ; ++i ) {
  279.         if (( p = strchr( text , ',' )) != NULL) *p++ = 0;
  280.         a[i] = atoi( text );
  281.         text = p;
  282.     }
  283.     if ( i == 6 ) {
  284.         f->hisip = intel( *(longword*)a );
  285.         f->hisport = intel16( *(word*)&a[4] );
  286.     } else {
  287.         f->hisip = 0L;          /* should be gained from his structure */
  288.         f->hisport = 0;
  289.     }
  290.     return( i == 6 );
  291. }
  292. /*
  293.  * parseftpline - called with a particular session and some data
  294.  *              - note, this baby supports multiple FTP sessions
  295.  *                by calling with different ftpdses values
  296.  */
  297. static void parseftpline( ftpdses *f, tcp_Socket *s, char *line )
  298. {
  299.     char *p, *q, cmdnum;
  300.     FILE* file;
  301.     /* remove blanks from line - p points to parameters */
  302.     p = strchr( line, ' ');
  303.     while ( *p == ' ') *p++ = 0;
  304.     if ((q = strchr( p, ' '))!=NULL)
  305.         while ( *q == ' ' ) *q++ = 0;
  306.     if (!*line) return;     /* nothing there */
  307.     for ( cmdnum = 0 ; cmdnum < ENDLIST ; ++cmdnum )
  308.         if ( !strnicmp( line, cmds[ cmdnum ], strlen( cmds[ cmdnum ] )))
  309.             break;
  310.     if ( cmdnum == ENDLIST ) {
  311.         sock_puts( s, "500 Command not understood '");
  312.         sock_puts( s, line );
  313.         sock_puts( s, "'rn");
  314.         /* check for unprivileged access */
  315.     } else if ( cmdnum > USER && f->gotpass == 0 )
  316.         sock_puts( s, "530 You're not logged in yetrn");
  317.         /* file commands need a port number */
  318.     else if ( cmdnum > PORT && ( f->hisport == 0 || f->hisip ==0L ))
  319.         sock_puts( s, "425 Sorry, need PORT command firstrn");
  320.         /* do the normal thing */
  321.     else switch( f->dcmd = cmdnum ) {
  322.         case ABOR   :
  323.             if (f->status == S_DATA ) {
  324.                 sock_abort( &f->dsocket );
  325.                 sock_puts( s, "426 Aborting at user's requestrn");
  326.             } else
  327.                 sock_puts( s, "550 Abort what?rn");
  328.             break;
  329.         case QUIT   :
  330.             sock_puts( s, "221 Goodbyern");
  331.             sock_close( s );
  332.             sock_close( &f->dsocket );    /* if necessary */
  333.             f->status = S_CLOS;
  334.             break;
  335.         case USER   :
  336.             sock_puts( s, "331 Password requiredrn");
  337.             break;
  338.         case PASS   :
  339.             if ( (*ftpdpassword && *line && !strcmp( p, ftpdpassword )) || !*ftpdpassword ) {
  340.                 f->gotpass = 1;
  341.                 sock_puts( s, "230 User logged inrn");
  342.             } else {
  343.                 sock_puts( s, "530 Not quitern");
  344.                 f->gotpass = 0;
  345.             }
  346.             break;
  347.         case HELP   :
  348.             sock_puts( s, "214-HELP - list of command accepted by WATTCP FTP daemonrn");
  349.             sock_puts( s, "    ABOR  QUIT  USER  PASS  HELP  NOOP  DEL   TYPE  PORTrn");
  350.             sock_puts( s, "    LIST  NLST  SIZE  STOR  RETR  SITErn");
  351.             sock_puts( s, "    RMD   XRMD  MKD   XMKD  CWD   XCWD  PWD   XPWDrn");
  352.             sock_puts( s, "214 OKrn");
  353.             break;
  354.         case RMD    :
  355.         case XRMD   :
  356.             if ( rmdir( pathfile(f,p) ) == 0 )
  357.               sock_puts( s, "250 RMD workedrn");
  358.             else
  359.               sock_puts( s, "550 RMD failedrn");
  360.             break;
  361.         case MKD    :
  362.         case XMKD   :
  363.             if ( mkdir( pathfile(f,p)) == 0 )
  364.               sock_puts( s, "250 MKD workedrn");
  365.             else
  366.               sock_puts( s, "550 MKD failedrn");
  367.             break;
  368.         case PWD    :
  369.         case XPWD   :
  370.             sock_puts( s, "257 "");
  371.             sock_puts( s, f->dirpath );
  372.             sock_puts( s, "" is current directory.rn");
  373.             break;
  374.         case CWD    :
  375.         case XCWD   :
  376.             if ( !changedir( f, p )) {
  377.                 sock_puts( s, "250 changed directory to ");
  378.                 sock_puts( s, f->dirpath );
  379.                 sock_puts( s, "rn");
  380.             } else
  381.                 sock_puts( s, "550 CWD failedrn");
  382.             break;
  383.         case DEL    :
  384.             sock_puts( s, (!unlink(pathfile(f,p))) ?
  385.                 "250 File deleted - "" : "550 Not Deleted - "" );
  386.             sock_puts( s, p );
  387.             sock_puts( s, ""rn");
  388.             break;
  389.         case PORT   :
  390.             if ( getport( f, p ))
  391.                 sock_puts( s, "200 Port command successfulrn");
  392.             else
  393.                 sock_puts( s, "501 Bad port commandrn");
  394.             break;
  395.         case NLST :
  396.         case LIST   :
  397.             c_op_dir( f, p );       /* start directory */
  398.             break;
  399.         case STOR   :               /* start a put */
  400.             unlink( pathfile(f, p) );
  401.             if ( (f->dhandle =  open( pathfile(f,p), O_RDWR | O_CREAT |
  402.                 ((f->ascii) ? O_TEXT : O_BINARY) | O_DENYNONE, S_IWRITE)) == -1) {
  403. //                                creat( pathfile(f,p), S_IWRITE )) == -1 ) {
  404.                 sock_puts( &f->socket, "550 Could not create file '");
  405.                 sock_puts( &f->socket, p );
  406.                 sock_puts( &f->socket, "'.rn");
  407.             } else
  408.                 data_op_init( f, FTP_OP_PUT );
  409.             break;
  410.         case RETR   :               /* start a get */
  411.             if ( (f->dhandle = open( p, O_RDONLY ||
  412.                 ( /* (f->ascii) ? O_TEXT : */ O_BINARY))) == -1) {
  413.                 sock_puts( &f->socket, "550 Could not open file '");
  414.                 sock_puts( &f->socket, p );
  415.                 sock_puts( &f->socket, "' for readingrn");
  416.             } else
  417.                 data_op_init( f, FTP_OP_GET );
  418.             break;
  419.         case SIZE   :
  420.             file = fopen( p, "rb" );
  421.             if ( file == 0 || fseek( file, 0, SEEK_END ) != 0 ) {
  422.                 sock_puts( &f->socket, "550 Could not open file '");
  423.                 sock_puts( &f->socket, p );
  424.                 sock_puts( &f->socket, "' for readingrn");
  425.             } else {
  426.                 long int fsize = ftell(file);
  427.                 sock_puts( &f->socket, "213 " );
  428.                 ltoa( fsize, ftpdbuffer, 10 );
  429.                 sock_puts( &f->socket, ftpdbuffer );
  430.                 sock_puts( &f->socket, "n" );
  431.                 fclose( file );                
  432.             }
  433.             break;
  434.             
  435.         case TYPE   :
  436.             *p = toupper( *p );
  437.             if ( *p == 'B' || *p == 'I' ) f->ascii = 0;
  438.             else if ( *p == 'A' ) f->ascii = 1;
  439.             else if ( *p == 'L' && *q == '8' ) f->ascii = 0;
  440.             else {
  441.                 sock_puts( s, "550 Type not understoodrn");
  442.                 p = NULL;
  443.             }
  444.             if (p)
  445.                 sock_puts( s, (f->ascii)? "200 ASCII modern":"200 Binary modern");
  446.             break;
  447.         case NOOP  :
  448.             sock_puts( s, "200 NOOPrn");
  449.             break;
  450.         case SITE :
  451.             if ( !strnicmp( p, "HALT", 4 )) {
  452.                 sock_puts( s, "221 Goodbye! Halting servicern");
  453.                 sock_close( s );
  454.                 sock_close( &f->dsocket );  /* if necessary */
  455.                 f->status = S_HALT;
  456.             } else {
  457.                 sock_puts( s, "500 command not understood 'SITE ");
  458.                 sock_puts( s, p );
  459.                 sock_puts( s, "'rn");
  460.             }
  461.             break;
  462.     }
  463. }
  464. /*
  465.  * ftpd_alt_tick - processes data when we are doing something and not
  466.  *                 awaiting user input
  467.  */
  468. static void ftpd_alt_tick( ftpdses *f)
  469. {
  470.     tcp_Socket *t;
  471.     int len, wlen;
  472.     t = &f->dsocket;
  473.     switch ( ftpd->dstatus ) {
  474.         case S_INIT :
  475.                 tcp_open( t, FTPDPORT-1, f->hisip, f->hisport, NULL );
  476.                 f->dstatus = S_WAIT;
  477.         case S_WAIT :
  478.                 if ( sock_established( t )) ftpd->dstatus = S_CONN;
  479.                 break;
  480.         case S_CONN :
  481.                 switch ( ftpd->doperation ) {
  482.                     case FTP_OP_DIR :   /* directory operation */
  483.                             while ( sock_tbleft( t ) > 80 ) {
  484.                                 if( f->dcmd == NLST ) {
  485.                                     sock_puts( t, f->ffblk.ff_name );
  486.                                     sock_puts( t, "n" );
  487.                                 } else {
  488.                                     dirformblock( &f->ffblk, ftpdbuffer );
  489.                                     sock_puts( t, ftpdbuffer );
  490.                                 }
  491.                                 if ( findnext( &f->ffblk ))
  492.                                     f->doperation = FTP_OP_DON;
  493.                                 break;
  494.                             }
  495.                             break;
  496.                     case FTP_OP_PUT :   /* part of put */
  497.                             if ((len = sock_fastread( t, ftpdbuffer, ftpdbufferlen)) > 0 ) {
  498.                                 wlen = write( f->dhandle, ftpdbuffer, len );
  499.                                 if (wlen < len || wlen == -1 ) {
  500.                                     f->doperation = FTP_OP_DON;
  501.                                     f->errmsg = "550 Error incurred while writing filern";
  502.                                 }
  503.                             }
  504.                             break;
  505.                     case FTP_OP_GET : data_op_get(f,t); break;
  506.                     case FTP_OP_DON : /* close socket .... */
  507.                             sock_close( t );
  508.                             if (f->dhandle) close( f->dhandle );
  509.                             f->dhandle = 0;
  510.                             sock_puts( &f->socket, f->errmsg );
  511.                             f->doperation = FTP_OP_NOP;
  512.                             break;
  513.                     case FTP_OP_NOP : break;
  514.                 }
  515.                 if (!tcp_tick( t )) {
  516.                     if ( ftpd->doperation < FTP_OP_DON )
  517.                         ftpd->doperation = FTP_OP_DON;
  518.                     else {
  519.                         sock_close( t );
  520.                         ftpd->status = S_CONN;
  521.                         ftpd->dstatus = S_INIT;
  522.                     }
  523.                 }
  524.                 break;
  525.     }
  526. }
  527. /*
  528.  * ftpd_tick - call this whenever you have a free moment
  529.  *           - modify this routine to use several ftpdses
  530.  *             structures if you wish
  531.  */
  532. void ftpd_tick( void )
  533. {
  534.     tcp_Socket *t;
  535.     t = &ftpd->socket;
  536.     switch ( ftpd->status ) {
  537.         case S_INIT :   sock_abort( t );
  538.                         memset( ftpd, 0, sizeof( ftpdses ));
  539.                         ftpd->ascii = 0;
  540.                         tcp_listen( t, FTPDPORT, 0L, 0, NULL, 0 );
  541.                         ftpd->status = S_WAIT;
  542.                         break;
  543.         case S_WAIT :   if ( sock_established( t )) {
  544.                             sock_puts(t,"220-FTP Serverrn");
  545.                             if (*ftpdwelcome) {
  546.                                 sock_puts(t,ftpdwelcome);
  547. sock_puts(t,"rn");
  548.                             }
  549.                             sock_puts(t,"220 Loginrn");
  550.                             ftpd->status = S_CONN;
  551.                             sock_mode( t, TCP_MODE_ASCII );
  552.                         }
  553.                         if ( !tcp_tick( t ))
  554.                             ftpd->status = S_CONN;
  555.                         break;
  556.         case S_DATA :   sock_mode( t, TCP_MODE_BINARY );
  557.                         ftpd_alt_tick( ftpd );
  558.                         sock_mode( t, TCP_MODE_ASCII );
  559.                         /* fall through */
  560.                         if ( !tcp_tick( t )) {
  561.                             sock_abort( t );
  562.                             sock_abort( &ftpd->dsocket );
  563.                             ftpd->status = S_CLOS;
  564.                         }
  565. case S_CONN :   if ( sock_dataready( t )) {
  566.                             sock_gets( t, ftpdbuffer, ftpdbufferlen);
  567.                             sock_mode( t, TCP_MODE_BINARY );
  568.                             parseftpline( ftpd, t, ftpdbuffer );
  569.                             sock_mode( t, TCP_MODE_ASCII );
  570.                         }
  571. if (!tcp_tick( t )) {
  572.                             sock_close( t );
  573.                             ftpd->status = S_CLOS;
  574.                         }
  575.                         break;
  576.         case S_CLOS :   if ( !tcp_tick( t ) ) {
  577.                             ftpd->status = S_INIT;
  578.                             sock_close( t );
  579.                         }
  580.                         break;
  581.         case S_HALT :   break;
  582.     }
  583. }
  584. static void ftpd_init()
  585. {
  586.     *ftpdpassword = 0;
  587.     *ftpdwelcome = 0;
  588.     oldinit = usr_init;
  589.     usr_init = newinit;
  590.     ftpd = calloc( sizeof( ftpdses ), 1 );  /* before kernel init */
  591.     ftpd->status = S_INIT;
  592. }
  593. #pragma startup ftpd_init 100
  594. void ftpdthread( DWORD x )
  595. {
  596.     if (!ftpdbufferlen) ftpdbufferlen = 512;
  597.     ftpdbuffer = kcalloc( 1, ftpdbufferlen);
  598.     handlerrs( 1 );
  599.     if ( *ftpdpassword == 0 )
  600.         cprintf("WARNING: ftpd.password is not set in config file, any password will matchrn");
  601.     while (1) {
  602. ftpd_tick();
  603.         /* improve response only while doing real stuff */
  604.         if ( ftpd->status == S_HALT ) break;
  605.         else if ( ftpd->status == S_DATA ) rt_sleep(0);
  606.         else rt_sleep( 100 );
  607.     }
  608.     /* if SITE was used to halt us */
  609.     while ( tcp_tick( &ftpd->socket )) rt_sleep( 100 );
  610.     kfree( ftpdbuffer );
  611.     handlerrs( 0 );
  612. }