home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / ncsa_tel / contribu / byu_tel2.hqx / tcpip / bkgr.c < prev    next >
Text File  |  1989-11-09  |  31KB  |  1,361 lines

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