home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / TEL23SRC.ZIP / ENGINE / BKGR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-21  |  30.7 KB  |  1,220 lines

  1. /*      BKGR.C
  2. *
  3. *    Background routines( FTP and RCP )
  4. *
  5. ***************************************************************************
  6. *                                                                          *
  7. *      part of:                                                            *
  8. *      TCP/IP kernel for NCSA Telnet                                       *
  9. *      by Tim Krauskopf                                                    *
  10. *                                                                          *
  11. *      National Center for Supercomputing Applications                     *
  12. *      152 Computing Applications Building                                 *
  13. *      605 E. Springfield Ave.                                             *
  14. *      Champaign, IL  61820                                                *
  15. *                                                                          *
  16. ***************************************************************************
  17. *
  18. *    Revision history:
  19. *
  20. *    11/86    Started by Timk
  21. *    xx/88    Rewritten by everyone
  22. *    5/89    clean up for 2.3 release, JKM    
  23. *    10/89    fixed ftp bugs                QAK
  24. *
  25. */
  26.  
  27. /*
  28. *    Includes
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <fcntl.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #ifdef MSC
  36. #ifdef __TURBOC__
  37. #include <alloc.h>
  38. #else
  39. #include <malloc.h>
  40. #endif
  41. #endif
  42. #ifdef MEMORY_DEBUG
  43. #include "memdebug.h"
  44. #endif
  45. #include "whatami.h"
  46. #include "hostform.h"
  47.  
  48. /*
  49. *    Defines
  50. */
  51.  
  52. #define HTELNET 23
  53. #define HRSHD 514
  54. #define HFTP 21
  55. #define BUFFERS 8000
  56. #define PATHLEN 256
  57.  
  58. #define RCPSEGSIZE 1024
  59. #define EOLCHAR 10
  60.  
  61. #ifdef MSC
  62. #define O_RAW    O_BINARY
  63. #ifdef __TURBOC__
  64. #include <dir.h>
  65. #else
  66. #include <direct.h>
  67. #endif
  68.  
  69. #include <sys/types.h>
  70. #include <sys/stat.h>
  71. #include <io.h>
  72. #endif    /* msc */
  73.  
  74. #include "externs.h"
  75.  
  76.  
  77. /*
  78. *    Global Variables
  79. */
  80.  
  81. static int ftpenable=0,            /* is file transfer enabled? */
  82.     ftpDir=0,
  83.     rcpenable=0,                /* is rcp enabled? */
  84.     ftpdata=-1,                    /* port for ftp data connection */
  85.     fnum=-1,                    /* port number for incoming ftp */
  86.     rsnum=-1,                    /* port number for incoming rshell */
  87.     rserr=-1,                    /* port number for rshd()stderr */
  88.     lstype;                        /* what type of ftp list to do */
  89. static unsigned char xs[BUFFERS+10],    /* buffer space for file transfer */
  90.         pathname[PATHLEN],            /* space to keep path names */
  91.         newfile[PATHLEN],            /* current file being received */
  92.         myuser[17],                    /* user name on my machine */
  93.         hisuser[17],                /* user name on his machine */
  94.         waitchar;                    /* character waiting for from net */
  95.  
  96. static int 
  97.     curstate=-1,            /* state machine for background processes */
  98.     retstate=200,            /* to emulate a subroutine call */
  99.     ftpstate=0,                /* state of the ftp data transfer */
  100.     isdir=0,                /* flag for rcp target pathname */
  101.     waitpos=0,                /* marker for gathering strings from net */
  102.     cnt=0,                    /* number of characters from last netread()*/
  103.     fh=0,                    /* file handle when transfer file is open */
  104.     ftpfh=0,                /* file handle for ftp data */
  105.     rc=0,                    /* telnet flag */
  106.     xp=0,                    /* general pointer */
  107.     towrite=0,                /* file transfer pointer */
  108.     len=0;                    /* file transfer length */
  109.  
  110. static long int
  111.     filelen=0L;                /* length of current file for transfer */
  112.  
  113. static char bkgr_path[PATHLEN];
  114. static unsigned int curr_drive;
  115. static char mungbuf[1024],crfound=0;
  116. static char *nextfile;        /* pointer to the next filename returned by DOS */
  117.  
  118. extern char Sptypes[NPORTS];/* flags for port #'s */
  119. #define PFTP 1
  120. #define PRCP 2
  121. #define PDATA 3
  122.  
  123. #ifdef PC
  124.  
  125. #define ga() while(!netwrite(rsnum,"",1))netsleep(0)
  126.  
  127. /************************************************************************/
  128. /*  unsetrshd
  129. *   remove the acceptance of rshd calls(rcp)
  130. */
  131. void unsetrshd()
  132. {
  133.     netclose(rsnum);
  134.     rsnum=-1;
  135.     rcpenable=0;
  136. }
  137.  
  138. /************************************************************************/
  139. void setrshd(void )
  140. {
  141.     int i;
  142. /*
  143. *  set up to receive a rsh call connection 
  144. */
  145.     if(rsnum>=0)
  146.         return;
  147.     curstate=199;                    /* waiting for connection */
  148.     i=netsegsize(RCPSEGSIZE);
  149.     rsnum=netlisten(HRSHD);
  150.     netsegsize(i);
  151.     if(rsnum>=0)
  152.         Sptypes[rsnum]=PRCP;
  153.     rcpenable=1;
  154. }
  155.  
  156. /************************************************************************/
  157. /*  rshell
  158. *   take an incoming rshell request and service it.  Designed to handle
  159. *   rcp primarily.
  160. */
  161. void rshd(code)
  162. int code;
  163. {
  164.     int i,j;
  165.  
  166.     if(!rcpenable)
  167.         return;
  168.     switch(curstate) {
  169.         case 199:                    /* wait to get started */
  170.             if(code!=CONOPEN)
  171.                 break;
  172.  
  173.             curstate=0;
  174.             netputuev(SCLASS,RCPACT,rsnum);        /* keep us alive */
  175.             break;
  176. /*
  177. * in effect, this is a subroutine that captures network traffic while
  178. * waiting for a specific character to be received
  179. */
  180.         case 50:
  181.             while(0<(cnt=netread(rsnum,&xs[waitpos],1))){
  182.                 if(xs[waitpos]==waitchar){
  183.                     curstate=retstate;
  184.                     netputuev(SCLASS,RCPACT,rsnum);        /* keep us alive */
  185.                     break;
  186.                   }
  187.                 else 
  188.                     waitpos+=cnt;
  189.              }
  190.             netpush(rsnum);
  191.             break;
  192.  
  193.         case 51:                /* for recursion, passes straight through */
  194.             break;
  195.  
  196.         case 0:                    /* waiting for first string */
  197.             retstate=1;
  198.             curstate=50;
  199.             waitchar=0;
  200.             waitpos=0;
  201.             netputuev(SCLASS,RCPACT,rsnum);        /* keep us alive */
  202.             break;
  203.  
  204.         case 1:                    /* we have received stderr port number */
  205.             i=atoi(xs);            /* port number */
  206.             curstate=51;
  207.             if(i) {
  208.                 cnt=-1;                /* abort it all, we don't take rsh */
  209.                 break;
  210.               }
  211.             else
  212.                 rserr=-1;
  213.             retstate=2; 
  214.             curstate=50;
  215.             waitpos=0; 
  216.             waitchar=0;
  217.             break;
  218.  
  219.         case 2:                        /* get user name, my machine */
  220.             strncpy(myuser,xs,16);
  221.             retstate=3; 
  222.             curstate=50;
  223.             waitpos=0; 
  224.             waitchar=0;
  225.             break;
  226.  
  227.         case 3:                         /* get user name, his machine */
  228.             strncpy(hisuser,xs,16);
  229.                                     /*ftransinfo(hisuser); */
  230.             retstate=4; 
  231.             curstate=50;
  232.             waitchar=0; 
  233.             waitpos=0;
  234.             break;
  235.  
  236.         case 4:
  237.                                     /*ftransinfo(xs);*/
  238. /*
  239. * ACK receipt of command line
  240. */
  241.             if(rserr>=0)
  242.                 netwrite(rserr,(char *)&xp,1);        /* send null byte */
  243.             else
  244.                 ga();                        /* send NULL on main connection */
  245.             if(!strncmp(xs,"rcp ",4)){
  246. /*
  247. *  rcp will be using wildcards, target must be a directory
  248. */
  249.                 if(!strncmp(&xs[4],"-d -t",5)){
  250.                     strncpy(pathname,&xs[10],PATHLEN);
  251.                     if(direxist(pathname)){
  252.                                             /*ftransinfo("no directory by that name ");*/
  253.                         netwrite(rsnum,"\001 No dir found ",16);
  254.                         netpush(rsnum);
  255.                         cnt=-1;
  256.                         break;
  257.                       }
  258.                     isdir=1;
  259.                     retstate=20; curstate=50;
  260.                     waitchar='\012'; waitpos=0;
  261.                     ga();                    /* ready for them to start */
  262.                     break;
  263.                   }
  264. /*
  265. * target could be a directory or a complete file spec
  266. */
  267.                 if(!strncmp(&xs[4],"-t",2)){
  268.                     strncpy(pathname,&xs[7],PATHLEN);
  269.                     if(!direxist(pathname))
  270.                         isdir=1;
  271.                     else
  272.                         isdir=0;
  273.                     retstate=20; 
  274.                     curstate=50;
  275.                     waitchar='\012'; 
  276.                     waitpos=0;
  277.                     ga();            /* ready for rcp to start */
  278.                     break;
  279.                   }
  280. /*
  281. *  rcp is requesting me to transfer file(s)(or giving directory name)
  282. */
  283.                 if(!strncmp(&xs[4],"-f",2)){
  284.                     strncpy(pathname,&xs[7],PATHLEN);
  285. /*
  286. *  direxist returns whether the path spec refers to a directory, and if
  287. *  it does, prepares it as a prefix.  Therefore, if it is a dir, we append
  288. *  a '*' to it to wildcard all members of the directory.
  289. *  Firstname()takes a file spec(with wildcards)and returns a pointer
  290. *  to a prepared ACTUAL file name.  nextname()returns successive ACTUAL
  291. *  filenames based on firstname().
  292. */
  293.                     if(!direxist(pathname)){
  294.                         i=strlen(pathname);
  295.                         pathname[i]='*';        /* all members of directory*/
  296.                         pathname[++i]='\0';
  297.                       }
  298.                     nextfile=(char *)firstname(pathname,0);
  299.                     if(nextfile==NULL){
  300.                         /*ftransinfo(" file or directory not found ");*/
  301.                         netwrite(rsnum,"\001 File not found ",18);
  302.                         netpush(rsnum);
  303.                         cnt=-1;
  304.                       }
  305.                     else {
  306.                                                 /* wait for other side to be ready */
  307.                         retstate=30;    
  308.                         curstate=50;
  309.                         waitchar=0; 
  310.                         waitpos=0;
  311.                       }
  312.                     break;
  313.                   }
  314.               }
  315.             break;
  316.  
  317.         case 20:
  318.             xs[waitpos]='\0';        /* add terminator */
  319.  
  320. /*
  321. *  get working values from command line just received
  322. *  open file for receive
  323. */
  324.             if(xs[0]!='C'||xs[5]!=' '){
  325.                                     /*ftransinfo(" Cannot parse filename line "); */
  326.                 netwrite(rsnum,"\001 Problem with file name ",26);
  327.                 cnt=-1;
  328.                 break;
  329.               }
  330.  
  331.             filelen=atol(&xs[6]);
  332.             for(i=6; xs[i]!=' '; i++)
  333.                 if(!xs[i]){
  334.                                     /*ftransinfo(" premature EOL ");*/
  335.                     netwrite(rsnum,"\001 Problem with file name ",26);
  336.                     cnt=-1;
  337.                     break;
  338.                   }
  339.             strcpy(newfile,pathname);        /* path spec for file */
  340.             if(isdir)                        /* add file name for wildcards */
  341.                 strcat(newfile,&xs[++i]);
  342. #ifdef MSC
  343.             if(0>(fh=open(newfile,O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, S_IREAD|S_IWRITE))){
  344. #else                    
  345.             if(0>(fh=creat(newfile,O_RAW))){
  346. #endif    
  347.                 netwrite(rsnum,"\001 Cannot open file for write ",29);
  348.                 cnt=-1;
  349.                 break;
  350.              }
  351.             netputevent(USERCLASS,RCPBEGIN,-1);
  352.             ga();                            /* start sending the file to me */
  353.             xp=len=0;
  354.             curstate=21;                    /* receive file, fall through */
  355.             break;
  356.  
  357.         case 21:
  358.             do {                /* wait until xs is full before writing to disk */
  359.                 if(len<=0) {
  360.                     if(xp) {
  361.                         write(fh,xs,xp);
  362.                         xp=0;
  363.                       }
  364.                     if(filelen>(long)BUFFERS)
  365.                         len=BUFFERS;
  366.                     else
  367.                         len=(int)filelen;
  368.                   }
  369.                 cnt=netread(rsnum,&xs[xp],len);
  370.                 filelen-=(long)cnt;
  371.                 len-=cnt;
  372.                 xp+=cnt;
  373.                             /*printf(" %ld %d %d %d ",filelen,len,xp,cnt);n_row(); n_puts(""); */
  374.                 if(filelen<=0L || cnt<0) {
  375.                     write(fh,xs,xp);        /* write last block */
  376.                     close(fh);
  377.                     fh=0;                    /* wait for NULL byte at end after closing file */
  378.                     curstate=50;  
  379.                     retstate=22;
  380.                     waitchar=0;   
  381.                     waitpos=0;
  382.                     break;
  383.                   }
  384.               } while(cnt>0);
  385.             break;
  386.  
  387.         case 22:
  388.     /* cause next sequence of bytes to be saved as next filename to transfer     */
  389.             ga();                    /* tell other side, I am ready */
  390.             waitchar='\012'; 
  391.             waitpos=0;
  392.             curstate=50; 
  393.             retstate=20;
  394.             break;
  395. /*
  396. *  transfer file(s)to the sun via rcp
  397. */
  398.         case 30:
  399. #ifdef MSC
  400.             if(0>(fh=open(nextfile,O_BINARY|O_RDONLY))) {
  401. #else
  402.             if(0>(fh=open(nextfile,O_RAW))){
  403. #endif
  404.                 netwrite(rsnum,"\001 File not found ",19);
  405.                 /*ftransinfo("Cannot open file to transfer: ");ftransinfo(nextfile); */
  406.                 cnt=-1;
  407.                 break;
  408.               }
  409.             netputevent(USERCLASS,RCPBEGIN,-1);
  410.             filelen=lseek(fh,0L,2);        /* how long is file? */
  411.             lseek(fh,0L,0);                /* back to beginning */
  412.             for(i=0,j=-1; nextfile[i]; i++)
  413.                 if(nextfile[i]=='\\')
  414.                     j=i;
  415.             sprintf(xs,"C0755 %lu %s\012",filelen,&nextfile[j+1]);
  416.             netwrite(rsnum,xs,strlen(xs));    /* send info to other side */
  417.                                             /*ftransinfo(xs);check it */
  418.             retstate=31; 
  419.             curstate=50;
  420.             waitchar=0;  
  421.             waitpos=0;
  422.             towrite=xp=0;
  423.             break;
  424.  
  425.         case 31:
  426. /*
  427. *   we are in the process of sending the file 
  428. */
  429.             netputuev(SCLASS,RCPACT,rsnum);        /* keep us alive */
  430.             if(towrite<=xp){
  431.                 towrite=read(fh,xs,BUFFERS);
  432.                 xp=0;
  433.                 filelen -=(long)towrite;
  434.               }
  435.             i=netwrite(rsnum,&xs[xp],towrite-xp);
  436.             if(i>0)
  437.                 xp+=i;
  438.                                                 /*printf(" %d %d %d %ld\012",i,xp,towrite,filelen);n_row();*/
  439. /*
  440. *  done if:  the file is all read from disk and all sent
  441. *  or other side has ruined connection
  442. */
  443.             if((filelen<=0L && xp>=towrite) || netest(rsnum)){
  444.                 close(fh);
  445.                 fh=0;
  446.                 nextfile=(char *)nextname(0);            /* case of wildcards */
  447.                 ga(); 
  448.                 netputuev(SCLASS,RCPACT,rsnum);
  449.                 if(nextfile==NULL)
  450.                     retstate=32;
  451.                 else
  452.                     retstate=30;
  453.                 curstate=50;
  454.                 waitchar=0;    waitpos=0;
  455.               }
  456.             break;
  457.  
  458.         case 32:
  459.             cnt=-1;
  460.             break;
  461.  
  462.         case 5:
  463.             break;
  464.  
  465.         default:
  466.             break;
  467.  
  468.       }
  469. /*
  470. *  after reading from connection, if the connection is closed,
  471. *  reset up shop.
  472. */
  473.     if(cnt<0){
  474.         if(fh>0){
  475.             close(fh);
  476.             fh=0;
  477.         }
  478.         curstate=5;
  479.         cnt=0;
  480.         netclose(rsnum);
  481.         rsnum=-1;
  482.         netputevent(USERCLASS,RCPEND,-1);
  483.         setrshd();                    /* reset for next transfer */
  484.       }
  485. }
  486. #endif
  487.  
  488. /***********************************************************************/
  489. /***********************************************************************/
  490. /***********************************************************************/
  491. /************************************************************************/
  492. /*  ftp section
  493. *   This should be extracted from rcp so that it compiles cleanly
  494. */
  495.  
  496. #define CRESP(A) netwrite(fnum, messs[(A)], strlen(messs[(A)]))
  497. #define FCRESP3(A,B,C) {char msg[80];sprintf(msg,messs[(A)],B,C),netwrite(fnum, msg, strlen(msg));}
  498.  
  499. #ifdef MSC
  500. #ifdef __TURBOC__
  501. #define FASCII O_RAW
  502. #else
  503. #define FASCII O_TEXT
  504. #endif
  505. #else
  506. #define FASCII    0
  507. #endif
  508. #define FIMAGE O_RAW
  509. #define FAMODE 0
  510. #define FIMODE 1
  511. #define FMMODE 2                /* Mac Binary, when ready */
  512.  
  513. extern int bypass_passwd;        /* flag to indicate whether or not to bypass the password check */
  514.  
  515. static int rfstate,
  516.     portnum[8],
  517.     ftpfilemode=FASCII,            /* how to open the file */
  518.     ftptmode=FAMODE;            /* how to transfer the file on net */
  519.  
  520. /*
  521. *  set up to receive a telnet connection for ftp commands
  522. */
  523. static uint16 fdport;
  524. void setftp()
  525. {
  526.     rfstate=0;
  527.     ftpstate=0;
  528.     fnum=netlisten(HFTP);
  529.     ftpenable=1;
  530.  
  531.     if(fnum>=0)                    /* signal that events should be caught */
  532.         Sptypes[fnum]=PFTP;
  533.     strcpy(myuser,"unknown");    /* set unknown user name */
  534. }
  535.  
  536. void unsetftp(void )
  537. {
  538.     rfstate=0;
  539.     ftpstate=0;
  540.     netclose(fnum);
  541.     fnum=-1;
  542.     ftpenable=0;
  543. }
  544.  
  545. /***********************************************************************/
  546. /*
  547. *  resident ftp server -- enables initiation of ftp without a username
  548. *  and password, as long as this telnet is active at the same time
  549. *  Now checks for the need of passwords.
  550. */
  551.  
  552. static char *messs[]={
  553.     "220 PC Resident FTP server, ready \015\012",
  554.     "451 Error in processing list command \015\012",
  555.     "221 Goodbye \015\012",                        /*2*/
  556.     "200 This space intentionally left blank<>\015\012",
  557.     "150 Opening %s mode connection for file %s\015\012",
  558.     "226 Transfer complete \015\012",            /*5*/
  559.     "200 Type set to A, ASCII transfer mode \015\012",
  560.     "200 Type set to I, binary transfer mode \015\012",
  561.     "500 Command not understood \015\012",        /*8*/
  562.     "200 Okay \015\012",
  563.     "230 User logged in \015\012",
  564.     "550 File not found \015\012",                /*11*/
  565.     "501 Directory not present or syntax error\015\012",
  566.     "250 Chdir okay\015\012",
  567.     "257 \"",
  568.     "\" is the current directory \015\012",        /*15*/
  569.     "501 File not found \015\012",
  570.     "504 Parameter not accepted, not implemented\015\012",
  571.     "200 Stru F, file structure\015\012",
  572.     "200 Mode S, stream mode\015\012",        /*19*/
  573.     "202 Allocate and Account not required for this server\015\012",
  574.     "501 Cannot open file to write, check for valid name\015\012",
  575.     "530 USER and PASS required to activate me\015\012",
  576.     "331 Password required\015\012",      /*23 */
  577.     "530 Login failed\015\012",
  578.     "200 MacBinary Mode enabled\015\012",
  579.     "200 MacBinary Mode disabled\015\012",  /*26 */
  580.     "552 Disk write error, probably disk full\015\012",
  581.     "214-NCSA Telnet FTP server, supported commands:\015\012",
  582.     "    USER  PORT  RETR  ALLO  PASS  STOR  CWD  XCWD  XPWD  LIST  NLST\015\012",
  583.     "    HELP  QUIT  MODE  TYPE  STRU  ACCT  CDUP  DELE  MKD  RMD  NOOP\015\012", /*30*/
  584.     "    A Macintosh version of NCSA Telnet is also available.\015\012",
  585.     "214 Direct comments and bugs to pctelbug@ncsa.uiuc.edu\015\012",
  586.     "200 Type set to I, binary transfer mode [MACBINARY ENABLED]\015\012",                /* 33 */
  587.     "200 Type set to I, binary transfer mode [macbinary disabled]\015\012",
  588.     "\" created\015\012",        /*35*/
  589.     "553 File name not allowed\015\012",
  590.     "502 Command not implemented\015\012",
  591.     ""
  592. };
  593.  
  594. void rftpd(code)
  595. int code;
  596. {
  597.     int i;
  598.  
  599.     if(!ftpenable)
  600.         return;
  601.  
  602.     netpush(fnum);
  603.  
  604.     switch(rfstate) {
  605.         case 0:
  606.             if(code!=CONOPEN)
  607.                 break;
  608.             ftpfilemode=FASCII;
  609.             ftptmode=FAMODE;
  610.             netputevent(USERCLASS,FTPCOPEN,-1);
  611.             rfstate=1;                    /* drop through */
  612.  
  613.         case 1:
  614.             dopwd(bkgr_path,256);
  615.             getdrive(&curr_drive);
  616.             CRESP(0);
  617.             netgetftp(portnum,fnum);    /* get default ftp information */
  618.             for(i=0; i<4; i++)            /* copy IP number */
  619.                 hisuser[i]=(char)portnum[i];
  620.             fdport=portnum[6]*256+portnum[7];
  621.             waitpos=0; 
  622.             waitchar='\012';
  623.             rfstate=50;                   /* note skips over */
  624.             if(Sneedpass())
  625.                 retstate=3;                /* check pass */
  626.             else
  627.                 retstate=5;                /* who needs one ? */
  628.             break;
  629.  
  630.         case 3:                            /* check for passwords */
  631.         case 4:
  632.             waitpos=0;  
  633.             waitchar='\012';
  634.             rfstate=50;  
  635.             if(!strncmp("USER",xs,4)){
  636.                 strncpy(myuser,&xs[5],16);        /* keep user name */
  637.                 netputevent(USERCLASS,FTPUSER,-1);
  638.                 CRESP(23);
  639.                 retstate=4;                        /* wait for password */
  640.                 break;
  641.               }
  642.             if(!strncmp("PASS",xs,4)) {
  643.                 if(Scheckpass(myuser,&xs[5]) || (bypass_passwd)) {    /* chcek for correct passwd, or check whether we bypassed the passwd from the keyboard */
  644.                     if(bypass_passwd)        /* reset the bypassing flag */
  645.                         bypass_passwd=0;
  646.                     netputevent(USERCLASS,FTPPWOK,-1);
  647.                     CRESP(10);
  648.                     retstate=5;
  649.                   }
  650.                 else {
  651.                     netputevent(USERCLASS,FTPPWNO,-1);
  652.                     CRESP(24);
  653.                     retstate=3;
  654.                   }
  655.                 break;
  656.               }
  657.             if(!strncmp("QUIT",xs,4)) {
  658.                 CRESP(2);
  659.                 cnt=-1;
  660.               }
  661.             else
  662.                 CRESP(22);
  663.             retstate=3;            /* must have password first */
  664.             break;                
  665.                 
  666. /*
  667. *  interpret commands that are received from the other side
  668. */
  669.         case 5:
  670.             for(i=4; (unsigned int)i < strlen(xs); i++)
  671.                 if(xs[i]=='/')        /* flip slashes */
  672.                     xs[i]='\\';
  673. /*
  674. *  set to a safe state to handle recursion
  675. *  wait for another command line from client
  676. *  
  677. */
  678.             rfstate=50; 
  679.             retstate=5;
  680.             waitchar='\012';  
  681.             waitpos=0;
  682.             if(!strncmp(xs,"LIST",4) || !strncmp(xs,"NLST",4)) {
  683.                 if(!strncmp(xs,"LIST",4)) {
  684.                     if((strlen(xs)<6) || (xs[5]=='.'))
  685.                         strcpy(xs,"LIST *");
  686.                     lstype=1;
  687.                   }    /* end if */
  688.                 else {
  689.                     if((strlen(xs)<6) || (xs[5]=='.'))
  690.                         strcpy(xs,"NLST *");
  691.                     lstype=0;
  692.                   } /* end else */
  693.                 nextfile=(char *)firstname(&xs[5],lstype);    /* find first name */
  694.                 if(nextfile==NULL)
  695.                     CRESP(16);
  696.                 else {
  697.                     ftpgo();                            /* open the connection */
  698.                     fdport=portnum[6]*256+portnum[7];     /* reset to def */
  699.                     if(ftpdata>=0)
  700.                         Sptypes[ftpdata]=PDATA;
  701.                     ftpstate=40;                        /* ready to transmit */
  702.                     FCRESP3(4,"ASCII","list");
  703.                     netputevent(USERCLASS,FTPLIST,-1);
  704.                   }    /* end else */
  705.               }    /* end if */
  706.             else if(!strncmp(xs,"CWD",3)) {
  707.                 if(chgdir(fixdirnm(&xs[4])))                    /* failed */
  708.                     CRESP(12);
  709.                 else                                /* success */
  710.                     CRESP(13);
  711.                 }    /* end if */
  712.             else if(!strncmp(xs,"CDUP",4)) {
  713.                 if(chgdir(".."))                    /* failed */
  714.                     CRESP(12);
  715.                 else                                /* success */
  716.                     CRESP(13);
  717.                 }    /* end if */
  718.             else if(!strncmp(xs,"MKD",3)) {
  719.                 if(mkdir(&xs[4]))                    /* failed */
  720.                     CRESP(36);
  721.                 else {                                /* success */
  722.                     CRESP(14);                        /* start reply */
  723.                     netwrite(fnum,&xs[4],strlen(&xs[4]));    /* write dir name */
  724.                     CRESP(35);                        /* finish reply */
  725.                   }    /* end else */
  726.                 }    /* end if */
  727.             else if(!strncmp(xs,"RMD",3)) {
  728.                 if(rmdir(&xs[4]))                    /* failed */
  729.                     CRESP(11);
  730.                 else                                /* success */
  731.                     CRESP(9);
  732.                 }    /* end if */
  733.             else if(!strncmp(xs,"DELE",4)) {
  734.                 if(remove(&xs[5]))                    /* failed */
  735.                     CRESP(11);
  736.                 else                                /* success */
  737.                     CRESP(9);
  738.                 }    /* end if */
  739.             else if(!strncmp(xs,"STOR",4)) {
  740.                    ftpDir=1;
  741. #ifdef MSC
  742.                 if(0>(ftpfh=open(&xs[5], ftpfilemode|O_CREAT|O_TRUNC|O_WRONLY, S_IREAD|S_IWRITE))) {
  743. #else                    
  744.                 if(0>(ftpfh=creat(&xs[5],ftpfilemode))) {
  745. #endif                
  746.                     CRESP(21);
  747.                     break;
  748.                   }
  749.                 ftpstate=0;
  750.                 strncpy(newfile,&xs[5],PATHLEN-1);
  751.                 ftpgo();                        /* open connection */
  752.                 fdport=portnum[6]*256+portnum[7]; /* reset to def */
  753.                 if(ftpdata>=0)
  754.                     Sptypes[ftpdata]=PDATA;
  755.                 FCRESP3(4,(ftpfilemode==FASCII)?"ASCII":"BINARY",&xs[5]);
  756.                 ftpstate=30;                /* ready for data */
  757.               }    /* end if */
  758.             else if(!strncmp(xs,"RETR",4)) {
  759.                 ftpDir=0;
  760. #ifdef MSC
  761.                 if(0>(ftpfh=open(&xs[5], ftpfilemode|O_RDONLY))) {
  762. #else                    
  763.                 if(0>(ftpfh=creat(&xs[5],ftpfilemode))) {
  764. #endif
  765.                     CRESP(11);
  766.                     break;
  767.                   }
  768.                 strncpy(newfile,&xs[5],PATHLEN-1);
  769.                 ftpgo();                /* open connection */
  770.                 fdport=portnum[6]*256+portnum[7]; /* reset to def */
  771.                 ftpstate=20;        /* ready for data */
  772.                 if(ftpdata>=0)
  773.                     Sptypes[ftpdata]=PDATA;
  774.                 FCRESP3(4,(ftpfilemode==FASCII)?"ASCII":"BINARY",&xs[5]);
  775.               }    /* end if */
  776.             else if(!strncmp(xs,"TYPE",4)) {
  777.                 if(toupper(xs[5])=='I') {
  778.                     ftpfilemode=FIMAGE;
  779.                     ftptmode=FIMODE;
  780.                     CRESP(7);
  781.                   }
  782.                 else 
  783.                     if(toupper(xs[5])=='A') {
  784.                         ftpfilemode=FASCII;
  785.                         ftptmode=FAMODE;
  786.                         CRESP(6);
  787.                       }
  788.                     else
  789.                         CRESP(17);
  790.               }    /* end if */
  791.             else if(!strncmp(xs,"PORT",4)) {
  792. /*
  793. * get the requested port number from the command given
  794. */
  795.                 sscanf(&xs[5],"%d,%d,%d,%d,%d,%d",&portnum[0],&portnum[1],&portnum[2],&portnum[3],&portnum[4],&portnum[5]);
  796.                 fdport=portnum[4]*256+portnum[5];
  797.                 CRESP(3);
  798.               }    /* end if */
  799.             else if(!strncmp(xs,"QUIT",4)) {
  800.                 chgdir(bkgr_path);
  801.                 setdrive(curr_drive);
  802.                 CRESP(2);
  803.                 rfstate=60;
  804.                 netputuev(CONCLASS,CONDATA,fnum);    /* post back to me */
  805.               }    /* end if */
  806.             else if(!strncmp(xs,"XPWD",4) || !strncmp(xs,"PWD",3)) {
  807.                 CRESP(14);                        /* start reply */
  808.                 dopwd(xs,1000);                    /* get directory */
  809.                 netwrite(fnum,xs,strlen(xs));    /* write dir name */
  810.                 CRESP(15);                        /* finish reply */
  811.                 }    /* end if */
  812.             else if(!strncmp(xs,"USER",4)) {
  813.                 strncpy(myuser,&xs[5],16);        /* keep user name */
  814.                 netputevent(USERCLASS,FTPUSER,-1);    /* confirm log in without password */
  815.                 CRESP(10);
  816.               }    /* end if */
  817.             else if(!strncmp(xs,"STRU",4)) {    /* only one stru allowed */
  818.                 if(xs[5]=='F')
  819.                     CRESP(18);
  820.                 else
  821.                     CRESP(17);
  822.               }    /* end if */
  823.             else if(!strncmp(xs,"MODE",4)) {    /* only one mode allowed */
  824.                 if(xs[5]=='S')
  825.                     CRESP(19);
  826.                 else
  827.                     CRESP(17);
  828.               }    /* end if */
  829.             else if(!strncmp(xs,"ALLO",4) || !strncmp(xs,"ACCT",4))
  830.                 CRESP(20);
  831.             else if(!strncmp(xs,"HELP",4)) {
  832.                 for(i=28; i<33; i++)
  833.                     CRESP(i);
  834.               }    /* end if */
  835.             else if(!strncmp(xs,"NOOP",4))
  836.                 CRESP(9);
  837.             else if(!strncmp(xs,"REIN",4) || !strncmp(xs,"PASV",4) || 
  838.                         !strncmp(xs,"APPE",4) || !strncmp(xs,"REST",4) || 
  839.                         !strncmp(xs,"RNFR",4) || !strncmp(xs,"RNTO",4) || 
  840.                         !strncmp(xs,"ABOR",4) || !strncmp(xs,"SITE",4) || 
  841.                         !strncmp(xs,"STAT",4) || !strncmp(xs,"SMNT",4) || 
  842.                         !strncmp(xs,"SMNT",4) || !strncmp(xs,"SYST",4) || 
  843.                         !strncmp(xs,"STOU",4))        /* unimplemented commands */
  844.                 CRESP(37);
  845.             else            /* command not understood */
  846.                 CRESP(8);
  847.             break;
  848. /*
  849. *  subroutine to wait for a particular character
  850. */
  851.         case 50:
  852.             while(0<(cnt=netread(fnum,&xs[waitpos],1))) {
  853.                 if(xs[waitpos]==waitchar) {
  854.                     rfstate=retstate;
  855.                     while(xs[waitpos]<33)        /* find end of string */
  856.                         waitpos--;
  857.                     xs[++waitpos]='\0';            /* put in terminator */
  858.                     for(i=0; i<4; i++)                /* want upper case */
  859.                         xs[i]=(unsigned char)toupper((int)xs[i]);
  860.                     break;
  861.                   }    /* end if */
  862.                 else
  863.                     waitpos+=cnt;
  864.               }    /* end while */
  865.             break;
  866.  
  867.         case 60:                    /* wait for message to get through */
  868.                                     /* or connection is broken */
  869.                                     /*printf("%d,%d",netpush(fnum),netest(fnum));*/
  870.             if(!netpush(fnum)||netest(fnum))
  871.                 cnt=-1;
  872.             else
  873.                 netputuev(CONCLASS,CONDATA,fnum);    /* post back to me */
  874.             break;
  875.  
  876.         default:
  877.             break;
  878.       }
  879.     if(cnt<0) {
  880.         if(ftpfh>0) {
  881.             close(ftpfh);
  882.             ftpfh=0;
  883.           }
  884.         if(ftpdata>0) {
  885.             netclose(ftpdata);
  886.             netputevent(USERCLASS,FTPEND,-1);
  887.           }
  888.         rfstate=100;
  889.         ftpstate=0;
  890.         cnt=0;
  891.         netclose(fnum);
  892.         netputevent(USERCLASS,FTPCLOSE,-1);
  893.         fnum=-1;
  894.         ftpdata=-1;
  895.         setftp();                /* reset it */
  896.       }
  897. }
  898.  
  899. /***********************************************************************/
  900. /* ftpgo
  901. *  open the FTP data connection to the remote host
  902. */
  903. void ftpgo(void )
  904. {
  905.     int savest;
  906.     struct machinfo *m;
  907.  
  908.     xs[0]=(unsigned char)portnum[0];
  909.     xs[1]=(unsigned char)portnum[1];
  910.     xs[2]=(unsigned char)portnum[2];
  911.     xs[3]=(unsigned char)portnum[3];
  912.  
  913.     netfromport(20);     /* ftp data port */
  914.  
  915.     if(NULL==(m=Slookip(xs))){        /* use default entry */
  916.         if(NULL==(m=Shostlook("default")))
  917.             return;
  918.         savest=m->mstat;
  919.         m->mstat=HAVEIP;
  920.         movebytes(m->hostip,xs,4);
  921.         ftpdata=Snetopen(m,fdport);
  922.         m->mstat=savest;
  923.         movebytes(m->hostip,"\0\0\0\0",4);
  924.         return;
  925.       }
  926.     ftpdata=Snetopen(m,fdport);
  927. }
  928.  
  929. /*********************************************************************/
  930. /*
  931. *  FTP receive and send file functions
  932. */
  933. static int fcnt=0;
  934.  
  935. void ftpd(code,curcon)
  936. int code,curcon;
  937. {
  938.     int i;
  939.  
  940.     if(curcon!=ftpdata)        /* wrong event, was for someone else */
  941.         return;
  942.     switch(ftpstate){
  943.         default:
  944.             break;
  945.  
  946.         case 40:                /* list file names in current dir */
  947.             if(code==CONFAIL)    /* something went wrong */
  948.                 fcnt=-1;
  949.             if(code!=CONOPEN)    /* waiting for connection to open */
  950.                 break;
  951.             ftpstate=41;
  952. /*
  953. *  send the "nextfile" string and then see if there is another file
  954. *  name to send
  955. */
  956.         case 41:
  957.             netputuev(SCLASS,FTPACT,ftpdata);
  958.             netpush(ftpdata);
  959.             i=strlen(nextfile);
  960.             if(i!=netwrite(ftpdata,nextfile,i)){
  961.                 CRESP(1);
  962.                 fcnt=-1;
  963.                 break;
  964.               }
  965.             netwrite(ftpdata,"\015\012",2);
  966.             if(NULL==(nextfile=nextname(lstype)))    /* normal end */
  967.                 ftpstate=22;                           /* push data through */
  968.             break;
  969.             
  970.         case 30:
  971.             if(code==CONFAIL)    /* something went wrong */
  972.                 fcnt=-1;
  973.             if(code!=CONOPEN)    /* waiting for connection to open */
  974.                 break;
  975.             ftpstate=31;
  976.             crfound=0;
  977.             len=xp=0;
  978.             filelen=0L;
  979.             netputevent(USERCLASS,FTPBEGIN,-2);
  980.             break;
  981.  
  982.         case 31:
  983. /*
  984. * file has already been opened, take everything from the connection
  985. * and place into the open file: ftpfh
  986. */
  987.             do {                /* wait until xs is full before writing to disk */
  988.                 if(len<=2000){
  989.                     if(xp){
  990.                         if(0>write(ftpfh,xs,xp)){     /* disk full err */
  991.                             netclose(ftpdata);
  992.                             fcnt=-1;
  993.                             CRESP(27);
  994.                             break;
  995.                           }
  996.                         xp=0;
  997.                       }
  998.                     len=BUFFERS;        /* expected or desired len to go */
  999.                   }
  1000.                 if(ftptmode==FAMODE)
  1001.                     fcnt=Sfread(ftpdata,&xs[xp],len);
  1002.                 else
  1003.                     fcnt=netread(ftpdata,&xs[xp],len);
  1004.                 if(fcnt >=0){
  1005.                     len -=fcnt;
  1006.                     xp+=fcnt;
  1007.                     filelen+=fcnt;
  1008.                   }
  1009. /*                printf(" %d %d %d \012",len,xp,fcnt);
  1010.                 n_row();  
  1011. */
  1012.                 if(fcnt<0){
  1013.                     if(0>write(ftpfh,xs,xp)){     /* disk full check */
  1014.                         CRESP(27);
  1015.                         break;
  1016.                       }
  1017.                     close(ftpfh);
  1018.                     ftpfh=0;
  1019.                     CRESP(5);
  1020.                   }
  1021.               } while(fcnt>0);
  1022.             break;
  1023.  
  1024.         case 20:
  1025.             if(code==CONFAIL)                    /* something went wrong */
  1026.                 fcnt=-1;
  1027.             if(code!=CONOPEN)                    /* waiting for connection to open */
  1028.                 break;
  1029.             ftpstate=21;
  1030.             filelen=lseek(ftpfh,0L,2);            /* how long is file? */
  1031.             lseek(ftpfh,0L,0);                    /* back to beginning */
  1032.             towrite=0;
  1033.             xp=0;
  1034.             netputevent(USERCLASS,FTPBEGIN,-1);
  1035.  
  1036.         case 21:
  1037. /*
  1038. *  transfer file(s)to the other host via ftp request
  1039. *  file is already open=ftpfh
  1040. */
  1041.             netputuev(SCLASS,FTPACT,ftpdata);
  1042.             if(towrite<=xp) {
  1043.                 i=BUFFERS;
  1044.                 towrite=read(ftpfh,xs,i);
  1045.                 xp=0;
  1046.               }
  1047.             if(towrite<=0 || netest(ftpdata)) {
  1048.                 ftpstate=22;
  1049.                 break;
  1050.               }
  1051.             if(ftptmode==FAMODE)
  1052.                 i=Sfwrite(ftpdata,&xs[xp],towrite-xp);
  1053.             else
  1054.                 i=netwrite(ftpdata,&xs[xp],towrite-xp);
  1055.             if(i>0) {
  1056.                 xp+=i;
  1057.                 filelen-=i;
  1058.                 if(filelen<0L)
  1059.                     filelen=0L;
  1060.               }
  1061.             break;
  1062.  
  1063.         case 22:                        /* wait for data to be accepted */
  1064.             netputuev(SCLASS,FTPACT,ftpdata);
  1065.             fcnt=netpush(ftpdata);        /* will go negative on err */
  1066.             if(!fcnt || netest(ftpdata))
  1067.                 fcnt=-1;
  1068.             if(fcnt<0)
  1069.                 CRESP(5);
  1070.             break;
  1071.  
  1072.         case 0:
  1073.             break;
  1074.       }  /* end of switch */
  1075.  
  1076. /*
  1077. *  after reading from connection, if the connection is closed,
  1078. *  reset up shop.
  1079. */
  1080.     if(fcnt<0){
  1081.         if(ftpfh>0){
  1082.             close(ftpfh);
  1083.             ftpfh=0;
  1084.           }
  1085.         ftpstate=0;
  1086.         fcnt=0;
  1087.         if(ftpdata >=0){
  1088.             netclose(ftpdata);
  1089.             netputevent(USERCLASS,FTPEND,-1);
  1090.             ftpdata=-1;
  1091.           }
  1092.       }
  1093. }
  1094.  
  1095. /***************************************************************************/
  1096. /*  Sfwrite
  1097. *   Write an EOL translated buffer into netwrite.
  1098. *   Returns the number of bytes which were processed from the incoming
  1099. *   buffer.  Uses its own 1024 byte buffer for the translation(with Sfread).
  1100. */
  1101. int Sfwrite(pnum,buf,nsrc)
  1102. int pnum,nsrc;
  1103. char *buf;
  1104. {
  1105.     int i,ndone,nout,lim;
  1106.     char *p,*q;
  1107.  
  1108.     ndone=0;
  1109.  
  1110.     while(ndone<nsrc){
  1111.         if(0>(i=netroom(pnum)))
  1112.             return(-1);
  1113.         if(i<1024)                    /* not enough room to work with */
  1114.             return(ndone);
  1115. /*
  1116. *  process up to 512 source bytes for output(could produce 1K bytes out)
  1117. */
  1118.         if(nsrc-ndone>512)
  1119.             lim=512;
  1120.         else
  1121.             lim=nsrc-ndone;
  1122.         p=buf+ndone;                /* where to start this block */
  1123.         q=mungbuf;                    /* where munged stuff goes */
  1124.         for(i=0; i<lim; i++) {
  1125.             if(*p==EOLCHAR) {
  1126.                 *q++=13;
  1127.                 *q++=10;
  1128.                 p++;
  1129.               }
  1130.             else
  1131.                 *q++=*p++;
  1132.           }
  1133.         ndone+=lim;                    /* # of chars processed */
  1134.         nout=q-mungbuf;                /* # of chars new */
  1135.         netwrite(pnum,mungbuf,nout);    /* send them on their way */
  1136.       }
  1137.     return(ndone);
  1138. }
  1139.  
  1140. /*
  1141. *  important note:  for Sfread, nwant must be 256 bytes LARGER than the amount
  1142. *  which will probably be read from the connection.
  1143. *  Sfread will stop anywhere from 0 to 256 bytes short of filling nwant
  1144. *  number of bytes.
  1145. */
  1146. int Sfread(pnum,buf,nwant)
  1147. int pnum,nwant;
  1148. char *buf;
  1149. {
  1150.     int i,ndone,lim;
  1151.     char *p,*q;
  1152.  
  1153.     if(nwant<1024)
  1154.         return(-1);
  1155.     ndone=0;
  1156.     while(ndone<nwant - 1024){        /* bugfix 6/88 - TK(added -1024)*/
  1157.         if(0>=(lim=netread(pnum,mungbuf,1024))) {
  1158.             if(ndone || !lim)            /* if this read is valid, but no data */
  1159.                 return(ndone);
  1160.             else
  1161.                 return(-1);                /* if connection is closed for good */
  1162.           }
  1163.         p=mungbuf;
  1164.         q=buf+ndone;
  1165.         for(i=0; i<lim; i++) {
  1166.             if(crfound) {
  1167.                 if(*p==10)
  1168.                     *q++=EOLCHAR;
  1169.                 else 
  1170.                     if(*p==0)
  1171.                         *q++=13;            /* CR-NUL means CR */
  1172.                 crfound=0;
  1173.               }
  1174.             else 
  1175.                 if(*p==13)
  1176.                     crfound=1;
  1177.                 else 
  1178.                     *q++=*p;                /* copy the char */
  1179.             p++;
  1180.           }
  1181.         ndone=q-buf;                    /* count chars ready */
  1182.       }
  1183.     return(ndone);
  1184. }
  1185.  
  1186. /***********************************************************************/
  1187. /* Sftpname and Sftpuser and Sftphost
  1188. *  record the name of the file being transferred, to use in the status
  1189. *  line updates
  1190. */
  1191. void Sftpname(s)
  1192. char *s;
  1193. {
  1194.     strcpy(s,newfile);
  1195. }
  1196.  
  1197. void Sftpuser(user)
  1198. char *user;
  1199. {
  1200.     strcpy(user,myuser);            /* user name entered to log in */
  1201. }
  1202.  
  1203. int SftpDirection(void)
  1204. {
  1205.     return ftpDir;
  1206. }
  1207.  
  1208. void Sftphost(host)
  1209. char *host;
  1210. {
  1211.     movebytes(host,hisuser,4);        /* IP address of remote host */
  1212. }
  1213.  
  1214. void Sftpstat(byt)
  1215. long *byt;
  1216. {
  1217.     *byt=filelen;
  1218. }
  1219.  
  1220.