home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / TEL23SRC.ZIP / FTP / FTPBIN.C
Encoding:
C/C++ Source or Header  |  1991-08-19  |  69.4 KB  |  2,492 lines

  1. /*
  2. *  User FTP
  3. *  6/8/87
  4. ****************************************************************************
  5. *                                                                          *
  6. *      by Tim Krauskopf and Swami Natarajan                                *
  7. *             Microsoft port by Heeren Pathak                               *
  8. *                                                                          *
  9. *      National Center for Supercomputing Applications                     *
  10. *      152 Computing Applications Building                                 *
  11. *      605 E. Springfield Ave.                                             *
  12. *      Champaign, IL  61820                                                *
  13. *                                                                          *
  14. *                                                                          *
  15. ****************************************************************************
  16. *
  17. */
  18.  
  19. /*
  20.  *Thanks to Jyrki Kuoppala(jkp@hutcs.hut.fi) for the basis of changes for
  21.  * MSC 5.1 
  22. */
  23.  
  24. #define FTPMASTER
  25.  
  26. #ifdef __TURBOC__
  27. #include "turboc.h"
  28. #endif
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <fcntl.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <signal.h>
  36. #include <time.h>
  37. #include <io.h>
  38. #include <errno.h>
  39. #include <string.h>
  40. #include <conio.h>
  41.  
  42. #ifdef    MSC
  43. #define    O_RAW O_BINARY
  44. #include <dos.h>
  45. #ifndef _TURBOC_
  46. #include <direct.h>
  47. #endif
  48. #include <malloc.h>
  49. #endif
  50.  
  51. #ifdef MEMORY_DEBUG
  52. #include "memdebug.h"
  53. #endif
  54. #include "nkeys.h"
  55. #include "hostform.h"
  56. #include "whatami.h"
  57. #include "ftppi.h"                        /* list of commands, help strings */
  58. #include "externs.h"
  59. #include "defines.h"
  60.  
  61. #define VDD_SEG 0x40
  62. #define VDD_ROWS_OFF 0x84    /* This points to a BYTE    */
  63. #define VDD_COLS_OFF 0x4a    /* This points to a WORD (int) */
  64.  
  65. #define FASCII  0
  66. #define FIMAGE  1
  67. #define HFTP   21
  68.  
  69. #define FALSE        0
  70. #define TRUE        1
  71. #define SUCCESS        2
  72. #define ERROR       -1
  73. #define NONE       -2
  74. #define ABORT       -3
  75. #define INCOMPLETE -4
  76. #define AMBIGUOUS  -5
  77. #define HAVEDATA    4
  78.  
  79. int xp=0,                    /* general pointer */
  80.     towrite=0,                /* file transfer pointer */
  81.     len=0,                    /* file transfer length */
  82.     ftpnum,                    /* current command port */
  83.     ftpdata=-1,                /* current data port */
  84.     ftpfh,                    /* file handle for ftp */
  85.     ftpstate=0,                /* state for background process */
  86.     fcnt = 0,                /* counter for ftpd */
  87.     ftpfilemode=0,            /* file open mode for transfer */
  88.     foundbreak=0,            /* cntrl-break pending */
  89.     connected=0,            /* not connected */
  90.     debug=0,                /* debug level */
  91.     bypass_passwd=0,        /* whether to bypass the password check */
  92.     hash=0,                    /* hash mark printing */
  93.     sendport=1,                /* to send ports or not */
  94.     verbose=1,                /* informative messages */
  95.     redirect=1,                /* check for ouput redirection */
  96.     bell=0,                    /* sound bell */
  97.     autologin=1,            /* login on connect */
  98.     prompt=1,                /* check on multiple commands */
  99.     tempprompt=0,            /* temp var for Yes/No/All/Quit convenience */
  100.     glob=1,                    /* expand wildcards */
  101.     slashflip=1,            /* change \ to / */
  102.     capture=0,                /* capture data or not */
  103.     usemore=0,                /* use |more */
  104.     numlines=24,            /* number of lines for |more */
  105.     lineslft=24,            /* number of lines left for |more */
  106.     ttypass=0,                /* use interactive for password */
  107.     fromtty=1,                /* default input from tty */
  108.     f_enter_login=FALSE,    /* noninteractive but ask for user and pass */
  109.     display_init=FALSE,        /* TRUE if title line has been given */
  110.     scrsetup=0,                /* FALSE if need to clear screen */
  111.     dos_color;                /* storage for the DOS color setup */
  112.  
  113. FILE *fromfp=NULL;            /* file pointer for input */
  114. unsigned int curftpprt=0;    /* port to use */
  115. unsigned char destname[50]={0,0},    /* who to connect to */
  116.     s[550],                    /* temporary string */
  117.     path_name[_MAX_DRIVE+_MAX_DIR],        /* character storage for the path name */
  118.     captlist[2001],            /* response string */
  119.     ftpcommand[200];        /* command to execute */
  120. char printline[2001];        /* line to display */
  121.  
  122. struct config def;
  123.  
  124. char *config;
  125.  
  126. #ifdef _TURBOC_
  127. int use_mouse=0;
  128. #endif
  129.  
  130. #ifdef _TURBOC_
  131. #define BUFFERS 10000        /* size of buffer */
  132. #else
  133. #define BUFFERS 20000        /* size of buffer */
  134. #endif
  135. #define READSIZE 256        /* how much to read */
  136.  
  137. static unsigned char xs[BUFFERS+10];    /* buffer space for file transfer */
  138.  
  139. long start=0L,                /* timing var */
  140.     lengthfile=0L;            /* length of current file for transfer */
  141.  
  142. /* function prototypes for local functions */
  143. int main(int argc,char *argv[]);
  144. static char *stpblk(char *ch);
  145. static void breakstop(void );
  146. static unsigned int ftpport(void );
  147. static char *stptok(char *p,char *toword,int len,char *delim);
  148. static void nputs(char *line);
  149. static int printerr(void );
  150. static int ftppi(char *command);
  151. static int putstring(char *string);
  152. static int ftpgets(char *s,int lim,int echo);
  153. static int ftpdo(char *s,char *ofile);
  154. static int checkevent(void );
  155. static void nputchar(char ch);
  156. static int dumpcon(int cnum);
  157. static void telnet(int cnt);
  158. static int getword(char *string,char *word);
  159. static int finduniq(char *name,char *list[],int listsize);
  160. static int checkoredir(char *command,char *filename,int slashflip);
  161. static void flip_slashes(char *command,char *filename);
  162. static void getdir(int drive,char *path);
  163. static int ftpreplies(int cnum,int *rcode);
  164. static int getnname(char *string,char *word);
  165. static int rgetline(int cnum);
  166. static void userftpd(void );
  167. int numrows(void);
  168. void give_args(void);
  169. int domore(void);
  170. static char *check_file_name (char *in_fname, char *out_fname);
  171.  
  172. /************************************************************************/
  173. /* main - main procedure.  Displays opening message, parses arguments,
  174. /*      initializes network, reads user commands and executes them, and
  175. /*      cleans up.
  176. /************************************************************************/
  177.  
  178. main(argc,argv)
  179.     int argc;
  180.     char *argv[]; 
  181. {
  182.     int i,c;
  183.     static char Configfile[50]="config.tel";
  184.     static char fromfile[20]="";
  185.  
  186.     n_window(0,0,(int)*(char far *)MK_FP(VDD_ROWS_OFF,VDD_SEG),
  187.       *(int far *)MK_FP(VDD_COLS_OFF,VDD_SEG));   /* to correctly handle non standard screen sizes */
  188. #ifdef __TURBOC__
  189.     fnsplit(argv[0],path_name,s,captlist,printline);   /* split path up */
  190. #else
  191.     _splitpath(argv[0],path_name,s,captlist,printline); /* split the full path name of telbin.exe into it's components */
  192. #endif
  193.     strcat(path_name,s);    /* append the real path name to the drive specifier */
  194.  
  195. #ifdef    MSC
  196.     signal(SIGINT, breakstop);
  197. #else
  198.     onbreak(&breakstop);    /* break handler */
  199. #endif
  200.  
  201.  
  202.     config=getenv("CONFIG.TEL");
  203.     if (config) strcpy(Configfile,config);
  204.  
  205. /*
  206. *  initialize network
  207. */
  208.     destname[0]='\0';        /* destination unknown */
  209.                             /* parse arguments */
  210.     for(i=1; i<argc; i++) {
  211.         if(argv[i][0]=='-' || argv[i][0] == '/') {
  212.             switch(tolower(argv[i][1])) {
  213.                 case 'r':        /* turn off output redirection */
  214.                     redirect=FALSE;
  215.                     break;
  216.  
  217.                 case 'v':        /* display informative messages */
  218.                     verbose=TRUE;
  219.                     break;
  220.  
  221.                 case 'n':        /* do not login on connect */
  222.                     autologin=FALSE;
  223.                     break;
  224.  
  225.                 case 'i':        /* interactive prompting off */
  226.                     prompt=FALSE;
  227.                     break;
  228.  
  229.                 case 'g':        /* wildcard expansion off */
  230.                     glob=FALSE;
  231.                     break;
  232.  
  233.                 case 'd':        /* debug, optional level */
  234.                     if(sscanf(argv[++i],"%d",&debug)<=0)
  235.                         debug=TRUE;
  236.                     break;
  237.  
  238.                 case 's':        /* do not change \ to / */
  239.                     slashflip=FALSE;
  240.                     break;
  241.  
  242.                 case 'h':        /* host file name */
  243.                     strcpy(Configfile,argv[++i]);
  244.                     break;
  245.  
  246.                 case 'm':        /* use built in |more */
  247.                     printf("\nusing more...");
  248.                     usemore=TRUE;
  249.                     numlines=numrows();
  250.                     lineslft=numlines;
  251.                     printf("\nusing more...");
  252.                     break;
  253.  
  254.                 case 'e':        /* noninteractive commands with interactive login */
  255.                     f_enter_login = TRUE;
  256.  
  257.                 case 'p':        /* noninteractive with interactive password */
  258.                     ttypass=TRUE;
  259.  
  260.                 case 'f':                        /* noninteractive, optional filename */
  261.                     fromtty=FALSE;    /* noninteractive input */
  262.                     strcpy(fromfile,argv[++i]);
  263.                     if(fromfile[0]) {
  264.                            fromfp=fopen(fromfile,"r");
  265.                            if(fromfp==NULL) {
  266.                             sprintf(printline,"Could not open file: %s",fromfile);
  267.                             nputs(printline);
  268.                             return(1);
  269.                              }
  270.                       }
  271.                     break;
  272.  
  273.                 case '?':
  274.                     give_args();
  275.  
  276.                 default:                        /* unknown option */
  277.                     sprintf(printline,"Unrecognized option -%c ignored",argv[i][1]);
  278.                     nputs(printline);
  279.                     break;
  280.               }
  281.           }
  282.         else sscanf(argv[i],"%s",destname);        /* destination host */
  283.       }
  284.  
  285.     *strrchr(argv[0],'\\') == 0;    /* put null at end of pathname string */
  286.     Shostpath(argv[0]);                /* and set the path */
  287.     Shostfile(Configfile);        /* open host file */
  288.  
  289.     if(c=Snetinit()) {                            /* cannot initialize network */
  290.         printerr();                                /* display TCP/IP message */
  291.         nputs("Error initializing network");
  292.         if(c==-3)    /* check for BOOTP server not responding */
  293.             netshut();    /* release network */
  294.         return(1);
  295.       }
  296.  
  297.     Sgetconfig(&def);                /* get information provided in hosts file */
  298.     if(destname[0]) 
  299.         sprintf(ftpcommand,"open %s",destname);    /* if destination specified, connect to it */
  300.     nputs("");                                    /* initializes screen if not done */
  301.     do {
  302.         if(*ftpcommand) {
  303.             ftppi(ftpcommand);            /* if command available, execute it */
  304.             if(debug>4) nputs("after returning from ftppi() ");
  305.         }    /* end if */
  306. /*        if(fromtty)
  307.           n_cur(n_row(),0);                 in case screen messed up */
  308.         putstring("ftp> ");                /* prompt */
  309.         lineslft = numlines;            /* for |more */
  310.         c=ftpgets(ftpcommand,200,1);    /* read cmd from user */
  311.       }while(c!=ABORT);                    /* Alt-F3 aborts */
  312.     netclose(ftpnum);                    /* close command connection */
  313.     netshut();                            /* terminate network stuff */
  314.  
  315.     return(0);
  316. }
  317.  
  318. void give_args(void) {
  319.     nputs("FTP [-dfghimnprsv?]  [hostname]");
  320.     nputs("        d - Debug [level]");
  321.     nputs("        f - input File <filename>");
  322.     nputs("        g - Global wildcard expansion off");
  323.     nputs("        h - Host file <filename>");
  324.     nputs("        i - Interactive prompting off");
  325.     nputs("        m - use built in More");
  326.     nputs("        n - No login on connect");
  327.     nputs("        p - input file with interactive Password <filename>");
  328.     nputs("        r - turn off command line output Redirection");
  329.     nputs("        s - turn off Slash flip (/\\)");
  330.     nputs("        v - Verbose");
  331.     nputs("        ? - This list");
  332.     exit(1);
  333. }
  334.  
  335. /************************************************************************/
  336. /* ftpgets - read a line from the keyboard
  337. /*         returns ABORT if aborted, non-zero on success
  338. /************************************************************************/
  339.  
  340. static int ftpgets(s,lim,echo)
  341.     char *s;            /* where to put the line */
  342.     int lim,echo;        /* max chars to read, echo? */
  343. {
  344.     int c,count,i;
  345.     char *save, *ret;
  346.  
  347.     count=0;        /* none read */
  348.     save=s;            /* beginning of line */
  349.  
  350.     if(foundbreak) {
  351.         foundbreak=0;
  352.         *s='\0';
  353.         nputs("");
  354.         return(ABORT);
  355.       }
  356.     if(!fromtty) {
  357.        if(fromfp==NULL) {
  358.             ret=fgets(s,lim,stdin);
  359.          }
  360.        else {
  361.         ret=fgets(s,lim,fromfp);
  362.          }
  363.        if(ret==NULL) {
  364.         nputs("EOF or error on read from file\n");
  365.         if(connected) {
  366.             ftpdo("QUIT","");
  367.             connected=FALSE;
  368.           }
  369.         netclose(ftpnum);                    /* close command connection */
  370.         netshut();
  371.     if (display_init) {                    /* Restore DOS' color scheme */
  372.         n_color(dos_color);
  373.         n_clear();            /* clear screen */
  374.         n_wrap(1);            /* cursor positioning */
  375.         n_cur(0,0);
  376.     };
  377.         exit(1);
  378.          }
  379.        s[strlen(s)-1]='\0';        /* remove newline */
  380.        if(echo && fromfp)
  381.         nputs(s);
  382.        return(strlen(s));
  383.       }
  384.     while(1) {
  385.         if(foundbreak) {        /* abort */
  386.             s=save;                /* reset line */
  387.             *s='\0';            /* null line */
  388.             nputs("");            /* newline */
  389.             foundbreak=0;        /* break processed */
  390.             return(ABORT);    
  391.           }
  392.         /* SAR 9/13/90 */
  393.         if (!kbhit()) {            /* if no char available */
  394.             checkevent();        /* check event queue */
  395.             c=0;
  396.           }
  397.         else c=getch();            /* else get character */
  398.         switch(c) {                /* allow certain editing chars */
  399.             case BACKSPACE:
  400.             case 8:                /* backspace */
  401.                 if(count) {
  402.                     if(echo) {
  403.                         nputchar((char)8);
  404.                         nputchar(' ');
  405.                         nputchar((char)8);
  406.                       }
  407.                     count--;    /* one less character */
  408.                     s--;        /* move pointer backward */
  409.                   }
  410.                 break;
  411.  
  412.             case EOF:
  413.             case 13:            /* carriage return,=ok */
  414.                 nputs("");        /* newline */
  415.                 *s='\0';        /* terminate the string */
  416.                 return(c);        /* return ok */
  417.                 break;
  418.  
  419.             case 10:            /* line feed */
  420.                 break;            /* ignore */
  421.  
  422.             case 21:            /* kill line */
  423.                 for(i=0; i<s-save; i++) {    /* length of line */
  424.                     if(echo) {                /* erase */
  425.                         nputchar(8);
  426.                         nputchar(' ');
  427.                         nputchar(8);
  428.                       }
  429.                   }
  430.                 s=save;    /* reset line */
  431.                 break;
  432.  
  433.             case 0:                /* do nothing */
  434.                 break;
  435.  
  436.             default:                        /* not special char */
  437.                 if(c>31&&c<127) {            /* printable */
  438.                     if(echo) nputchar((char)c);    /* display */
  439.                     *s++=(char)c;                /* add to string */
  440.                     count++;    /* length of string */
  441.                   }
  442.                 else            /* acts as eol */
  443.                     return(c);    /* value of special char */
  444.                 if(count==lim) {            /* to length limit */
  445.                     *s='\0';    /* terminate */
  446.                     return(c);    
  447.                   }
  448.             break;
  449.  
  450.           }
  451.  
  452.       }
  453. }
  454.  
  455. /************************************************************************/
  456. /* dumpcon
  457. *  take everything from a connection and send it to the screen
  458. *  return -1 on closed connection, else 0, 1 if paused
  459. /************************************************************************/
  460.  
  461. static int dumpcon(cnum)
  462.     int cnum;
  463. {
  464.     int cnt;
  465.     if(fromtty && n_scrlck())
  466.         return(TRUE);                /* if paused, nothing to do */
  467.     do {
  468.         cnt=netread(cnum,s,64);        /* get some from queue */
  469.         telnet(cnt);                /* display on screen, etc.*/
  470.       } while(cnt>0);
  471.     return(cnt);                    /* 0 normally, -1 if connection closed */
  472. }
  473.  
  474.  
  475. /************************************************************************/
  476. /*  telnet
  477. *   filter telnet options on incoming data
  478. /************************************************************************/
  479.  
  480. static void telnet(cnt)
  481.     int cnt;
  482. {
  483.     int i;
  484.  
  485. if(debug>4) {
  486.     sprintf(printline,"telnet(): cnt=%d ",cnt);
  487.     nputs(printline);
  488.   }    /* end if */
  489.     for(i=0; i<cnt; i++) {                    /* put on screen */
  490.         if(s[i] & 128) {                    /* if over ASCII 128 */
  491.             sprintf(printline," %d ",(int)s[i]);    /* show as number */
  492.             nputs(printline);
  493.           }
  494.         else
  495.             nputchar(s[i]);
  496.       }
  497. if(debug>4) {
  498.     nputs("telnet(): leaving ");
  499.   }    /* end if */
  500. }
  501.  
  502. /********************************************************************/
  503. /* FTP PI
  504. *  Protocol interpreter for user interface commands
  505. *  Will permit any command to be abbreviated uniquely.
  506. *  Recognizes commands, translates them to the protocol commands to be
  507. *  sent to the other server, and uses userftpd, the daemon, to do data
  508. *  transfers.
  509. /************************************************************************/
  510.  
  511. static int ftppi(command)
  512. char *command;
  513. {
  514.     int retry;
  515.     int cmdno,i;
  516.     char cmdname[50],word[50],line[100],answer[20],ofilename[50];
  517.     char *p,*firstname(),*nextname();
  518.     struct machinfo *mp,*Sgethost();
  519.  
  520.     if(debug>1) {            /* print command */
  521.         sprintf(printline,"command: %s",command);
  522.         nputs(printline);
  523.           }
  524. /* get command number */
  525.     if(!getword(command,cmdname))
  526.              return(FALSE);    /* get command name */
  527. /* removes first word from command */
  528.     strlwr(cmdname);
  529.     cmdno=finduniq(cmdname,ftp_cmdlist,NCMDS);    /* search cmdlist for prefix */
  530.     if(cmdno==AMBIGUOUS) {        /* not unique abbreviation */
  531.         nputs("?Ambiguous command");
  532.         return(FALSE);
  533.       }
  534.     if(cmdno==NONE) {        /* not a prefix of any command */
  535.         nputs("?Invalid command");
  536.         return(FALSE);
  537.       }
  538. /* change \ to / and check if command output redirected */
  539.     if(cmdno!=BANG) {        /* don't alter shell escape */
  540.         if(redirect) {        /* check for ouput redirection selected */
  541.             if(cmdno!=LLS)        /* do not flip slashes for LLS */
  542.                 checkoredir(command,ofilename,slashflip);    /* check redirection, flip \ */
  543.             else
  544.                 checkoredir(command,ofilename,FALSE);    /* check redirection */
  545.           }    /* end if */
  546.         else {                /* no output redirection */
  547.             if(cmdno!=LLS && slashflip)        /* don't flip slashes for LLS and check for slashflipping here and assume it in routine */
  548.                 flip_slashes(command,ofilename);
  549.           }    /* end else */
  550.       }
  551. /* process commands */
  552.     switch(cmdno) {
  553.         case QMARK:
  554.         case HELP:
  555.             if(!command[0]) {                        /* no argument */
  556.                 nputs("Commands may be abbreviated. Commands are:\n");
  557. /* display command list */
  558.                 printline[0]='\0';
  559.                 for(i=0; i<NCMDS; i++) {
  560.                     sprintf(word,"%-16s",ftp_cmdlist[i]);    /* get word from list */
  561.                     strcat(printline,word);            /* add to line */
  562.                     if(i%5==4) {                    /* display line */
  563.                         printline[79]='\0';
  564.                         nputs(printline);
  565.                         printline[0]='\0';
  566.                       }
  567.                   }
  568.                 if(i%5!=4)
  569.                     nputs(printline);                /* last line */
  570.                 return(TRUE);
  571.               }
  572. /* help for specific commands */
  573.             else {
  574.                 while(getword(command,word)) {        /* loop for all args */
  575.                     i=finduniq(word,ftp_cmdlist,NCMDS);       /* which command? */
  576.                     if(i==AMBIGUOUS)                        /* non-unique command name */
  577.                         sprintf(printline,"?Ambiguous help command %s",word);
  578.                     else 
  579.                         if(i==NONE)                    /* no such command */
  580.                             sprintf(printline,"?Invalid help command %s",word);
  581.                         else                            /* display help string */
  582.                             sprintf(printline,"%s",helpstrings[i-1]);
  583.                     nputs(printline);
  584.                   }
  585.                 return(TRUE);
  586.               }
  587.             break;
  588.  
  589.         case BANG:                            /* shell escape */
  590.             fflush(stdout);
  591.             if(*(stpblk(command))) {        /* command specified */
  592.                 system(command);            /* execute command */
  593.                 return(TRUE);
  594.               }
  595.             dosescape();                    /* subshell */
  596.             return(TRUE);
  597.  
  598.         case BELL:
  599.             if(getword(command,word)) {        /* scan arg */
  600.                 strlwr(word);
  601.                 if(!strcmp(word,"off"))
  602.                      bell=FALSE;
  603.                 else 
  604.                     if(!strcmp(word,"on"))
  605.                         bell=TRUE;
  606.                 else 
  607.                     bell=!bell;
  608.             }
  609.             else
  610.                  bell=!bell;
  611.             if(bell) 
  612.                 nputs("Bell mode on.");
  613.             else 
  614.                 nputs("Bell mode off.");
  615.             return(TRUE);
  616.  
  617.         case BYE:
  618.         case QUIT:
  619.             if(connected) {
  620.                 ftpdo("QUIT",ofilename);
  621.                 connected=FALSE;
  622.               }
  623. /*            if(fromtty)    hack
  624.                 n_cur(24,0);     go to bottom of screen */
  625.             netclose(ftpnum);                    /* close command connection */
  626.             netshut();
  627.     if (display_init) {                    /* Restore DOS' color scheme */
  628.         n_color(dos_color);
  629.         n_clear();            /* clear screen */
  630.         n_wrap(1);            /* cursor positioning */
  631.         n_cur(0,0);
  632.     };
  633.             exit(0);
  634.  
  635.         case DEBUG:                /* turn on/off debugging, optional level */
  636.             if(sscanf(command,"%d",&i)>0)
  637.                 debug=i;                            /* level */
  638.             else
  639.                 if(getword(command,word)) {            /* scan arg */
  640.                     strlwr(word);
  641.                     if(!strcmp(word,"off"))
  642.                         debug=FALSE;
  643.                     else 
  644.                         if(!strcmp(word,"on"))
  645.                             debug=TRUE;
  646.                         else
  647.                             debug=!debug;
  648.                 }
  649.             else
  650.                 debug=!debug;
  651.             if(debug) {
  652.                 sprintf(printline,"Debugging on(debug=%d).",debug);
  653.                 nputs(printline);
  654.               }
  655.             else 
  656.                 nputs("Debugging off.");
  657.             return(TRUE);
  658.  
  659.         case GLOB:        /* wildcard expansion */
  660.             if(getword(command,word)) {
  661.                 strlwr(word);
  662.                 if(!strcmp(word,"off")) 
  663.                     glob=FALSE;
  664.                 else 
  665.                     if(!strcmp(word,"on")) 
  666.                         glob=TRUE;
  667.                     else 
  668.                         glob=!glob;
  669.               }
  670.             else 
  671.                 glob=!glob;
  672.             if(glob) 
  673.                 nputs("Globbing on.");
  674.             else 
  675.                 nputs("Globbing off.");
  676.             return(TRUE);
  677.  
  678.         case HASH:        /* hash mark printing */
  679.             if(getword(command,word)) {
  680.                 strlwr(word);
  681.                 if(!strcmp(word,"off")) 
  682.                     hash=FALSE;
  683.                 else 
  684.                     if(!strcmp(word,"on")) 
  685.                         hash=TRUE;
  686.                     else 
  687.                         hash=!hash;
  688.               }
  689.             else 
  690.                 hash=!hash;
  691.             if(hash) 
  692.                 nputs("Hash mark printing on(1024 bytes/hash mark).");
  693.             else 
  694.                 nputs("Hash printing off.");
  695.             return(TRUE);
  696.  
  697.         case INTERACTIVE:    /* prompting on multiple transfers */
  698.             prompt=TRUE;
  699.             nputs("Interactive mode on.");
  700.             return(TRUE);
  701.  
  702.         case LCD:        /* change local directory */
  703.             if(command[1]==':') {        /* if disk specified */
  704. #ifdef    MSC
  705. #ifdef __TURBOC__
  706.                 setdisk(tolower(command[0])-'a');
  707. #else
  708.                 unsigned int bogus;
  709.                 _dos_setdrive( tolower( command[0])-'a'+1,&bogus);
  710. #endif
  711. #else
  712.                 chgdsk(tolower(command[0])-'a');
  713. #endif
  714.                 strcpy(command,&command[2]);
  715.               }
  716.             if(*(stpblk(command))&&chdir(command)) {    /* CD */
  717.                 nputs("Unable to change directory");
  718.               }
  719.             getdir(0,line);        /* current directory */
  720.             sprintf(printline,"Local directory now %s",line);
  721.             nputs(printline);
  722.             return(TRUE);
  723.  
  724.         case LLS:        /* local DIR */
  725.             sprintf(line,"DIR %s",command);
  726.             fflush(stdout);
  727.             system(line);
  728.             return(TRUE);
  729.  
  730.         case MORE:        /* toggle use of MORE */
  731.             if (getword(command,word)) {
  732.                 strlwr(word);
  733.                 if (!strcmp(word,"off"))
  734.                     usemore=FALSE;
  735.                 else if (!strcmp(word,"on"))
  736.                     usemore=TRUE;
  737.             }
  738.             else usemore=!usemore;
  739.             if (usemore) nputs("Use of built in | more on.");
  740.             else nputs("Use of built in | more off.");
  741.             numlines=numrows();
  742.             lineslft=numlines;
  743.             break;
  744.  
  745.         case NONINTERACTIVE:    /* turn off interactive prompting */
  746.             prompt=FALSE;
  747.             nputs("Interactive mode off.");
  748.             return(TRUE);
  749.  
  750.         case OPEN:        /* open connection to host */
  751.             if(connected) {
  752.                 nputs("Already connected.");
  753.                 return(FALSE);
  754.               }
  755.             while(!(*(stpblk(command)))) {        /* no argument */
  756.                 putstring("To: ");
  757.                 if(ftpgets(command,100,1)==ABORT) 
  758.                     return(FALSE);
  759.               }
  760.             getword(command,destname);        /* host name */
  761.             mp=Sgethost(destname);        /* get host info */
  762.             if(foundbreak) return(FALSE);        /* abort */
  763.             if(mp==NULL) {                /* try domain serving */
  764.                 Sdomain(destname);
  765.                 while(mp==NULL) {
  766.                     switch(checkevent()) {
  767.                         case ABORT:
  768.                             return(FALSE);    /* abort */
  769.  
  770.                         case DOMFAIL:
  771.                             printerr();
  772.                             sprintf(printline,"Unknown host: %s\n",destname);
  773.                             nputs(printline);
  774.                             return(FALSE);
  775.  
  776.                         case DOMOK:
  777.                             mp=Slooknum(ftpnum);    /* get host info */
  778.                             break;
  779.  
  780.                         default:
  781.                             break;
  782.                         }
  783.                 }    /* end while */
  784.               }
  785.             display_init=TRUE;
  786.             def.color[0]=(unsigned char) (mp->nfcolor + (mp->nbcolor<<4));
  787.             scrsetup=FALSE;
  788.             nputs("");
  789.             if(sscanf(command,"%d",&i)>0)    /* port number specified */
  790.                 ftpnum=Snetopen(mp,i);
  791.             else {
  792.                 ftpnum=Snetopen(mp,HFTP);        /* default port */
  793.               }
  794.             if(foundbreak) return(FALSE);         /* abort */
  795.             if(ftpnum<0) {                /* error on open */
  796.                 printerr();
  797.                 sprintf(printline,"Unable to connect to %s",destname);
  798.                 nputs(printline);
  799.                 return(FALSE);
  800.               }
  801.             ftpreplies(ftpnum,&i);        /* response from other end */
  802.             if(foundbreak) return(FALSE);
  803.             connected=TRUE;
  804.             if(autologin) {        /* execute login command */
  805.                 strcpy(command,"user");
  806.                 ftppi(command);
  807.               }
  808.             return(TRUE);
  809.  
  810.         case PROMPT:            /* interactive prompting */
  811.             if(getword(command,word)) {
  812.                 strlwr(word);
  813.                 if(!strcmp(word,"off")) 
  814.                     prompt=FALSE;
  815.                 else 
  816.                     if(!strcmp(word,"on")) 
  817.                         prompt=TRUE;
  818.                     else prompt=!prompt;
  819.               }
  820.             else 
  821.                 prompt=!prompt;
  822.             if(prompt) 
  823.                 nputs("Interactive mode on.");
  824.             else 
  825.                 nputs("Interactive mode off.");
  826.             return(TRUE);
  827.  
  828.         case SENDPORT:            /* send PORT commands for each transfer */
  829.             if(getword(command,word)) {
  830.                 strlwr(word);
  831.                 if(!strcmp(word,"off")) 
  832.                     sendport=FALSE;
  833.                 else 
  834.                     if(!strcmp(word,"on")) 
  835.                         sendport=TRUE;
  836.                     else 
  837.                         sendport=!sendport;
  838.               }
  839.             else 
  840.                 sendport=!sendport;
  841.             if(sendport) 
  842.                 nputs("Use of PORT cmds on.");
  843.             else 
  844.                 nputs("Use of PORT cmds off.");
  845.             return(TRUE);
  846.  
  847.         case SLASHFLIP:            /* change \ to / */
  848.             if(getword(command,word)) {
  849.                 strlwr(word);
  850.                 if(!strcmp(word,"off")) 
  851.                     slashflip=FALSE;
  852.                 else 
  853.                     if(!strcmp(word,"on")) 
  854.                         slashflip=TRUE;
  855.                     else 
  856.                         slashflip=!slashflip;
  857.               }
  858.             else 
  859.                 slashflip=!slashflip;
  860.             if(slashflip) 
  861.                 nputs("Slash translation on.");
  862.             else 
  863.                 nputs("Slash translation off.");
  864.             return(TRUE);
  865.  
  866.         case STATUS:        /* display status info */
  867.             if(connected) {
  868.                 sprintf(printline,"Connected to %s",destname);
  869.                 nputs(printline);
  870.               }
  871.             if(ftpfilemode==FASCII) 
  872.                 nputs("Transfer mode is ascii.");
  873.             else 
  874.                 nputs("Transfer mode is binary.");
  875.             if(bell) 
  876.                 nputs("Bell on."); else nputs("Bell off.");
  877.             if(debug) {
  878.                 sprintf(printline,"Debugging on.(Debug=%d)",debug);
  879.                 nputs(printline);
  880.               }
  881.             else 
  882.                 nputs("Debugging off.");
  883.             if(glob) 
  884.                 nputs("Filename globbing on."); 
  885.             else 
  886.                 nputs("Filename globbing off.");
  887.             if(hash) 
  888.                 nputs("Hash-mark printing on.");
  889.             else 
  890.                 nputs("Hash-mark printing off.");
  891.             if(prompt)
  892.                 nputs("Interactive prompting on."); 
  893.             else 
  894.                 nputs("Interactive prompting off.");
  895.             if(sendport) 
  896.                 nputs("Sending of port commands on.");
  897.             else 
  898.                 nputs("Sending of PORT cmds off.");
  899.             if(slashflip) 
  900.                 nputs("Flipping \\ to / on.");
  901.             else
  902.                 nputs("Flipping \\ to / off.");
  903.             if(verbose) 
  904.                 nputs("Verbose mode on."); 
  905.             else 
  906.                 nputs("Verbose mode off.");
  907.             if (usemore)
  908.                 nputs("Use of built in | more on.");
  909.             else
  910.                 nputs("Use of built in | more off.");
  911.             if(connected) {        /* send STAT command */
  912.                 nputs("\nRemote status:");
  913.                 ftpdo("STAT",ofilename);
  914.               }
  915.             return(TRUE);
  916.  
  917.         case VERBOSE:        /* display informative messages */
  918.             if(getword(command,word)) {
  919.                 strlwr(word);
  920.                 if(!strcmp(word,"off")) 
  921.                     verbose=FALSE;
  922.                 else 
  923.                     if(!strcmp(word,"on")) 
  924.                         verbose=TRUE;
  925.                     else 
  926.                         verbose=!verbose;
  927.               }
  928.             else 
  929.                 verbose=!verbose;
  930.             if(verbose) 
  931.                 nputs("Verbose mode on.");
  932.             else 
  933.                 nputs("Verbose mode off.");
  934.             return(TRUE);
  935.  
  936.         default:        /* The other commands valid only if connected */
  937.             if(!connected) {
  938.                 nputs("Not connected.");
  939.                 return(FALSE);
  940.               }
  941.  
  942.         switch(cmdno) {
  943.             case ASCII:            /* transfer mode */
  944.                 ftpdo("TYPE A",ofilename);
  945.                 return(TRUE);
  946.  
  947.             case BGET:            /* get file in binary mode */
  948.                 i=ftpfilemode;    /* save current mode */
  949.                 if(i==FASCII) 
  950.                     ftpdo("TYPE I",ofilename);
  951.                 while(!(*(stpblk(command)))) {
  952.                     putstring("File: ");
  953.                     if(ftpgets(command,100,1)==ABORT) 
  954.                         return(FALSE);
  955.                   }
  956.                 sprintf(line,"RETR %s",command);
  957.                 ftpdo(line,ofilename);        /* get file */
  958.                 if(i==FASCII) 
  959.                     ftpdo("TYPE A",ofilename);    /* restore mode */
  960.                 return(TRUE);
  961.  
  962.             case BINARY:        /* binary mode */
  963.                 ftpdo("TYPE I",ofilename);
  964.                 return(TRUE);
  965.  
  966.             case BPUT:            /* put file in binary mode */
  967.                 i=ftpfilemode;
  968.                 if(i==FASCII) 
  969.                     ftpdo("TYPE I",ofilename);
  970.                 while(!(*(stpblk(command)))) {        /* if no arg */
  971.                     putstring("File: ");    /* get from user */
  972.                     if(ftpgets(command,100,1)==ABORT) 
  973.                         return(FALSE);
  974.                   }
  975.                 sprintf(line,"STOR %s",command);
  976.                 for (retry = 0; retry < 5; retry++) {
  977.                     if ((i = ftpdo(line,ofilename)) == TRUE) {
  978.                         if(i==FASCII) ftpdo("TYPE A",ofilename);
  979.                         return(TRUE);
  980.                     }
  981.                     else if (i != FALSE) {
  982.                         if(i==FASCII) ftpdo("TYPE A",ofilename);
  983.                         return(ERROR);
  984.                     }
  985.                     printf("\nRetrying...");
  986.                 }
  987.                 printf("Maximum retry count reached.  Aborting this file transfer...");
  988.                 return(FALSE);
  989.  
  990.             case CD:        /* change remote directory */
  991.                 while(!(*(stpblk(command)))) {        /* if no arg, get from user */
  992.                     putstring("To: ");
  993.                     if(ftpgets(command,100,1)==ABORT) 
  994.                         return(FALSE);    /* abort */
  995.                   }
  996.                 getword(command,word);
  997.                 if(!strcmp(word,"..")) {    /* special case */
  998.                     i=ftpdo("CDUP",ofilename);
  999.                     if(i!=ERROR) 
  1000.                         return(TRUE);        /* if CDUP understood */
  1001.                     nputs("Trying again...");
  1002.                     i=ftpdo("XCUP",ofilename);    /* try alternative */
  1003.                     if(i!=ERROR) 
  1004.                         return(TRUE);
  1005.                     nputs("Trying again...");        /* else try usual CD */
  1006.                   }
  1007.                 sprintf(line,"CWD %s",word);        /* try CWD */
  1008.                 i=ftpdo(line,ofilename);
  1009.                 if(i!=ERROR) 
  1010.                     return(TRUE);
  1011.                 nputs("Trying again...");
  1012.                 sprintf(line,"XCWD %s",word);        /* try XCWD */
  1013.                 ftpdo(line,ofilename);
  1014.                 return(TRUE);
  1015.  
  1016.             case CLOSE:                /* drop connection */
  1017.                 ftpdo("QUIT",ofilename);
  1018.                 connected=FALSE;
  1019.                 return(TRUE);
  1020.  
  1021.             case DEL:
  1022.             case RM:
  1023.                 getword(command,word);
  1024.                 while(!word[0]) {    /* get arg from user */
  1025.                     putstring("File: ");
  1026.                     if(ftpgets(word,100,1)==ABORT) 
  1027.                         return(FALSE);    /* abort */
  1028.                   }
  1029.                 if(prompt) {        /* check interactively */
  1030.                     sprintf(printline,"Delete %s? ",word);
  1031.                     putstring(printline);
  1032.                     ftpgets(answer,20,1);
  1033.                     if(tolower(*(stpblk(answer)))!='y') 
  1034.                         return(TRUE);
  1035.                   }
  1036.                 sprintf(line,"DELE %s",word);
  1037.                 ftpdo(line,ofilename);
  1038.                 return(TRUE);            
  1039.         
  1040.             case DIR:        /* get list of remote files */
  1041.                 i=ftpfilemode;    /* save mode */
  1042.                 if(i==FIMAGE) 
  1043.                     ftpdo("TYPE A",ofilename);
  1044.                 if(getword(command,word)) {    /* do DIR */
  1045.                     sprintf(line,"LIST %s",word);
  1046.                     ftpdo(line,ofilename);
  1047.                   }
  1048.                 else 
  1049.                     ftpdo("LIST",ofilename);
  1050.                 if(i==FIMAGE) 
  1051.                     ftpdo("TYPE I",ofilename);
  1052.                 return(TRUE);
  1053.  
  1054.             case GET:
  1055.             case RECV:        /* get remote file */
  1056.                 while(!(*(stpblk(command)))) {        /* if no arg */
  1057.                     putstring("File: ");
  1058.                     if(ftpgets(command,100,1)==ABORT) 
  1059.                         return(FALSE);    /* abort */
  1060.                   }
  1061.                 sprintf(line,"RETR %s",command);
  1062.                 ftpdo(line,ofilename);
  1063.                 return(TRUE);        
  1064.  
  1065.             case LS:        /* get remote file list - short */
  1066.                 i=ftpfilemode;
  1067.                 if(i==FIMAGE) 
  1068.                     ftpdo("TYPE A",ofilename);
  1069.                 if(getword(command,word)) {
  1070.                     sprintf(line,"NLST %s",word);
  1071.                     ftpdo(line,ofilename);
  1072.                   }
  1073.                 else 
  1074.                     ftpdo("NLST",ofilename);
  1075.                 if(i==FIMAGE) 
  1076.                     ftpdo("TYPE I",ofilename);
  1077.                 return(TRUE);    
  1078.  
  1079.             case MDELETE:
  1080.                 while(!(*(stpblk(command)))) {        /* no arg */
  1081.                     putstring("Files: ");
  1082.                     if(ftpgets(command,100,1)==ABORT) 
  1083.                         return(FALSE);    /* abort */
  1084.                   }
  1085.                 while(getword(command,word)) {        /* for each arg */
  1086.                     if(glob) {        /* wildcard expansion */
  1087.                         sprintf(line,"NLST %s",word);
  1088.                         capture=TRUE;
  1089.                         ftpdo(line,ofilename);    /* put exapnsion in captlist */
  1090.                         capture=FALSE;
  1091.                       }
  1092.                     else 
  1093.                         strcpy(captlist,word);    /* captlist has name(s) now */
  1094.                     while(getnname(captlist,word)) {    /* for each name */
  1095.                         if(prompt) {    /* check */
  1096.                             sprintf(printline,"mdelete %s? ",word);
  1097.                             putstring(printline);
  1098.                             if(ftpgets(answer,20,1)==ABORT) {    /* abort */
  1099.                                 command[0]='\0';    /* no more processing */
  1100.                                 break;            /* quit immediately */
  1101.                               }
  1102.                             if(tolower(*(stpblk(answer)))!='y') 
  1103.                                 continue;
  1104.                           }
  1105.                         sprintf(line,"DELE %s",word);    /* delete */
  1106.                         ftpdo(line,ofilename);
  1107.                       }
  1108.                   }
  1109.                 return(TRUE);                
  1110.  
  1111.             case MDIR:        /* remote multiple DIR */
  1112.                 i=ftpfilemode;    /* save mode */
  1113.                 if(i==FIMAGE) 
  1114.                     ftpdo("TYPE A",ofilename);
  1115.                 while(!(*(stpblk(command)))) {        /* no arg */
  1116.                     putstring("Directories: ");
  1117.                     if(ftpgets(command,100,1)==ABORT) return(FALSE);    /* abort */
  1118.                   }
  1119.                 while(getword(command,word)) {        /* for each arg */
  1120.                     if(glob) {        /* expand wildcards */
  1121.                         sprintf(line,"NLST %s",word);
  1122.                         capture=TRUE;
  1123.                         ftpdo(line,ofilename);
  1124.                         capture=FALSE;
  1125.                       }
  1126.                     else 
  1127.                         strcpy(captlist,word);
  1128.                     while(getnname(captlist,word)) {    /* for each name */
  1129.                         if(prompt) {    /* check */
  1130.                             sprintf(printline,"mdir %s? ",word);
  1131.                             putstring(printline);
  1132.                             if(ftpgets(answer,20,1)==ABORT) {    /* abort */
  1133.                                 command[0]='\0';    /* no more processing */
  1134.                                 break;            /* quit immediately */
  1135.                               }
  1136.                             if(tolower(*(stpblk(answer)))!='y') 
  1137.                                 continue;
  1138.                           }
  1139.                         sprintf(line,"LIST %s",word);    /* DIR */
  1140.                         ftpdo(line,ofilename);
  1141.                       }
  1142.                   }
  1143.                 if(i==FIMAGE) 
  1144.                     ftpdo("TYPE I",ofilename);
  1145.                 return(TRUE);
  1146.  
  1147.             case MGET:        /* get multiple files */
  1148.                 getword(command,line);
  1149.                 while(!line[0]) {    /* no arg */
  1150.                     putstring("Files: ");
  1151.                     if(ftpgets(line,100,1)==ABORT) 
  1152.                         return(FALSE);    /* abort */
  1153.                 }
  1154.                 while(getword(line,word)) {    /* for each arg */
  1155.                     if(glob) {        /* expand wildcards */
  1156.                         sprintf(command,"NLST %s",word);
  1157.                         capture=TRUE;
  1158.                         ftpdo(command,ofilename);
  1159.                         capture=FALSE;
  1160.                     }
  1161.                     else 
  1162.                         strcpy(captlist,word);
  1163.                     while(getnname(captlist,word)) {    /* for each name */
  1164.                         if(prompt) {    /* check */
  1165.                             sprintf(printline,"mget %s? (Yes/No/All/Quit) ",word);
  1166.                             putstring(printline);
  1167.                             if((ftpgets(answer,20,1)==ABORT)||(tolower(*(stpblk(answer)))=='q')) {    /* abort */
  1168.                                 command[0]='\0';    /* no more processing */
  1169.                                 break;            /* quit immediately */
  1170.                             }
  1171.                             if(tolower(*(stpblk(answer)))=='a') {   /* All */
  1172.                                 prompt=FALSE;
  1173.                                 tempprompt=TRUE;
  1174.                             }
  1175.                             if((tolower(*(stpblk(answer)))!='y')&&(tolower(*(stpblk(answer)))!='a')) continue;
  1176.                         }
  1177.                         sprintf(command,"RETR \"%s\"",word);
  1178.                         ftpdo(command,ofilename);
  1179.                     }
  1180.                     if (tempprompt==TRUE) {
  1181.                         prompt=TRUE;
  1182.                         tempprompt=FALSE;
  1183.                     }
  1184.                 }
  1185.                 return(TRUE);
  1186.  
  1187.             case MKDIR:        /* create directory */
  1188.                 while(!(*(stpblk(command)))) {        /* no arg */
  1189.                     putstring("Directory: ");
  1190.                     if(ftpgets(command,100,1)==ABORT) 
  1191.                         return(FALSE);    /* abort */
  1192.                   }
  1193.                 sprintf(line,"XMKD %s",command);    /* try XMKD */
  1194.                 i=ftpdo(line,ofilename);
  1195.                 if(i!=ERROR) 
  1196.                     return(TRUE);
  1197.                 nputs("Trying again...");
  1198.                 sprintf(line,"MKD %s",command);        /* else try MKD */
  1199.                 ftpdo(line,ofilename);
  1200.                 return(TRUE);
  1201.  
  1202.             case MLS:
  1203.                 i=ftpfilemode;
  1204.                 if(i==FIMAGE) 
  1205.                     ftpdo("TYPE A",ofilename);
  1206.                 while(!(*(stpblk(command)))) {        /* no arg */
  1207.                     putstring("Directories: ");
  1208.                     if(ftpgets(command,100,1)==ABORT) 
  1209.                         return(FALSE);    /* abort */
  1210.                   }
  1211.                 while(getword(command,word)) {        /* for each arg */
  1212.                     if(glob) {        /* exapnd wildcards */
  1213.                         sprintf(line,"NLST %s",word);
  1214.                         capture=TRUE;
  1215.                         ftpdo(line,ofilename);
  1216.                         capture=FALSE;
  1217.                       }
  1218.                     else 
  1219.                         strcpy(captlist,word);
  1220.                     while(getnname(captlist,word)) {    /* for each name */
  1221.                         if(prompt) {        /* check */
  1222.                             sprintf(printline,"mls %s? ",word);
  1223.                             putstring(printline);
  1224.                             if(ftpgets(answer,20,1)==ABORT) {  /* abort */
  1225.                                 command[0]='\0';    /* no more processing */
  1226.                                 break;            /* quit immediately */
  1227.                               }
  1228.                             if(tolower(*(stpblk(answer)))!='y') 
  1229.                                 continue;
  1230.                           }
  1231.                         sprintf(line,"NLST %s",word);    /* DIR */
  1232.                         ftpdo(line,ofilename);
  1233.                       }
  1234.                   }
  1235.                 if(i==FIMAGE) 
  1236.                     ftpdo("TYPE I",ofilename);
  1237.                 return(TRUE);
  1238.  
  1239.             case MODE:        /* set stream mode */
  1240.                 getword(command,word);
  1241.                 strlwr(word);
  1242.                 if(strncmp(word,"stream",strlen(word)))
  1243.                     nputs("We only support stream mode, sorry.");
  1244.                 else 
  1245.                     nputs("Mode is stream.");
  1246.                 return(TRUE);
  1247.     
  1248.             case MPUT:        /* put multiple files */
  1249.                 getword(command,line);
  1250.                 while(!line[0]) {    /* no arg */
  1251.                     putstring("Files: ");
  1252.                     if(ftpgets(line,100,1)==ABORT) 
  1253.                         return(FALSE);    /* abort */
  1254.                   }
  1255.                 p=NULL;    /* no names expanded yet */
  1256.                 while(getword(line,word)) {    /* for each arg */
  1257.                       do {        /* for each name */
  1258.                         if(glob) {        /* local wildcard expansion */
  1259.                             if(p==NULL) {    /* if no expansions yet */
  1260.                                 p=firstname(word,0);    /* get first name, with no file information attached */
  1261.                                 if(p==NULL) {    /* if no expansions */
  1262.                                     sprintf(printline,"No match for %s",word);
  1263.                                     nputs(printline);
  1264.                                     continue;
  1265.                                   }
  1266.                               }
  1267.                             else {        /* not first name */
  1268.                                 p=nextname(0);        /* get next name, with no file information attached */
  1269.                                 if(p==NULL) 
  1270.                                     continue;    /* if no names, next arg */
  1271.                               }
  1272.                           }
  1273.                         else 
  1274.                             p=word;        /* no expansion */
  1275.                         if(prompt) {    /* check */
  1276.                             sprintf(printline,"mput %s? (Yes/No/All/Quit) ",p);
  1277.                             putstring(printline);
  1278.                             if((ftpgets(answer,20,1)==ABORT)||(tolower(*(stpblk(answer)))=='q')) {    /* abort */
  1279.                                 command[0]='\0';    /* no more processing */
  1280.                                 break;            /* quit immediately */
  1281.                             }
  1282.                             if(tolower(*(stpblk(answer)))=='a') {
  1283.                                 prompt=FALSE;
  1284.                                 tempprompt=TRUE;
  1285.                             }
  1286.                             if((tolower(*(stpblk(answer)))!='y')&&(tolower(*(stpblk(answer)))!='a'))
  1287.                                 continue;
  1288.                             }
  1289.                         sprintf(command,"STOR \"%s\"",p);    /* name may have spl chars */
  1290.                         ftpdo(command,ofilename);
  1291.                       } while(glob && p!=NULL);        /* Not last expansion */
  1292.                     if (tempprompt) {
  1293.                         prompt=TRUE;
  1294.                         tempprompt=FALSE;
  1295.                     }
  1296.                   }
  1297.                 return(TRUE);
  1298.  
  1299.             case PUT:            
  1300.             case SEND:        /* put file */
  1301.                 while(!(*(stpblk(command)))) {        /* no args */
  1302.                     putstring("File: ");
  1303.                     if(ftpgets(command,100,1)==ABORT) return(FALSE);
  1304.                   }
  1305.                 sprintf(line,"STOR %s",command);    /* put file */
  1306.                 for (retry = 0; retry < 5; retry++) {
  1307.                     if ((i = ftpdo(line,ofilename)) == TRUE)
  1308.                         return(TRUE);
  1309.                     else if (i !=FALSE)
  1310.                         return(ERROR);
  1311.                     printf("\nRetrying...");
  1312.                 }
  1313.                 printf("\nMaximum retry count reached.  Aborting file transfer...");
  1314.                 return(ERROR);
  1315.     
  1316.             case PWD:
  1317.                 i=ftpdo("XPWD",ofilename);        /* try XPWD */
  1318.                 if(i!=ERROR) 
  1319.                     return(TRUE);
  1320.                 nputs("Trying again...");
  1321.                 ftpdo("PWD",ofilename);            /* else try PWD */
  1322.                 return(TRUE);
  1323.     
  1324.             case QUOTE:
  1325.                 while(!(*(stpblk(command)))) {        /* no arg */
  1326.                     putstring("Command: ");
  1327.                     if(ftpgets(command,100,1)==ABORT) 
  1328.                         return(FALSE);
  1329.                   }
  1330.                 ftpdo(command,ofilename);        /* send command */
  1331.                 return(TRUE);
  1332.     
  1333.             case REMOTEHELP:                /* get help */
  1334.                 if(*(stpblk(command))) {        /* for specific command */
  1335.                     sprintf(line,"HELP %s",command);
  1336.                     ftpdo(line,ofilename);
  1337.                   }
  1338.                 else 
  1339.                     ftpdo("HELP",ofilename);        /* generic help */
  1340.                 return(TRUE);
  1341.     
  1342.             case RENAME:        /* rename remote file */
  1343.                 while(!(*(stpblk(command)))) {        /* no arg */
  1344.                     putstring("From: ");
  1345.                     if(ftpgets(command,100,1)==ABORT) 
  1346.                         return(FALSE);
  1347.                   }
  1348.                 getword(command,word);
  1349.                 sprintf(line,"RNFR %s",word);
  1350.                 ftpdo(line,ofilename);        /* send rename from name */
  1351.                 while(!(*(stpblk(command)))) {        /* no second arg */
  1352.                     putstring("To: ");
  1353.                     if(ftpgets(command,100,1)==ABORT) {
  1354.                         ftpdo("ABOR",ofilename);
  1355.                         return(FALSE);
  1356.                       }
  1357.                   }
  1358.                 sprintf(line,"RNTO %s",command); /* send rename to name */
  1359.                 ftpdo(line,ofilename);
  1360.                 return(TRUE);
  1361.     
  1362.             case RMDIR:            /* remove remote dir */
  1363.                 while(!(*(stpblk(command)))) {        /* no arg */
  1364.                     putstring("Directory: ");
  1365.                     if(ftpgets(command,100,1)==ABORT) 
  1366.                         return(FALSE);
  1367.                   }
  1368.                 sprintf(line,"XRMD %s",command);    /* try XRMD */
  1369.                 i=ftpdo(line,ofilename);
  1370.                 if(i!=ERROR) 
  1371.                     return(TRUE);
  1372.                 nputs("Trying again...");
  1373.                 sprintf(line,"RMD %s",command);        /* try RMD */
  1374.                 ftpdo(line,ofilename);
  1375.                 return(TRUE);
  1376.     
  1377.             case STRUCT:        /* set structure type - only file */
  1378.                 getword(command,word);
  1379.                 strlwr(word);
  1380.                 if(strncmp(word,"file",strlen(word)))
  1381.                     nputs("We only support file structure, sorry.");
  1382.                 else 
  1383.                     nputs("Structure is file.");
  1384.                 return(TRUE);
  1385.     
  1386.             case TYPE:        /* set transfer type */
  1387.                 if(!getword(command,word)) {    /* no arg, just show */
  1388.                        if(ftpfilemode==FASCII) 
  1389.                         nputs("Transfer type is ascii.");
  1390.                        else 
  1391.                         nputs("Transfer type is binary.");
  1392.                   }
  1393.                 strlwr(word);
  1394.                 if(!strncmp(word,"ascii",strlen(word)))
  1395.                     ftpdo("TYPE A",ofilename);
  1396.                 else 
  1397.                     if(!strncmp(word,"binary",strlen(word))||!strncmp(word,"image",strlen(word)))
  1398.                         ftpdo("TYPE I",ofilename);
  1399.                     else {
  1400.                         sprintf(printline,"Unrecognized type: %s",word);
  1401.                         nputs(printline);
  1402.                       }
  1403.                 return(TRUE);
  1404.         
  1405.             case USER:            /* login to remote machine */
  1406.                 if (!fromtty && ttypass)
  1407.                     fromtty = TRUE;    /* go interactive */
  1408.                 if (f_enter_login) {
  1409.                     fromtty = 1;        /* fake interactive mode */
  1410.                     n_cur(n_row(), 0);    /* in case screen is messed up */
  1411.                   }
  1412.                 if(!(*(stpblk(command)))) {    /* null response to prompt ok */
  1413.                     putstring("Username: ");
  1414.                     if(ftpgets(command,100,1)==ABORT) 
  1415.                         return(FALSE);
  1416.                   }
  1417.                 sprintf(line,"USER %s",command);    /* username */
  1418.                 switch(ftpdo(line,ofilename)) {
  1419.                     case TRUE:  return (TRUE);
  1420.                     case FALSE:
  1421.                     case ERROR: return(FALSE);
  1422.                     case ABORT: return(ABORT);
  1423.                     default:    break;
  1424.                 }
  1425.                 putstring("Password: ");
  1426.                 if(ftpgets(word,40,0)==ABORT) 
  1427.                     return(FALSE);        /* no echoing */
  1428.                 if (f_enter_login)        /* restore to non-interactive mode */
  1429.                     fromtty = 0;
  1430.                 sprintf(line,"PASS %s",word);        /* password */
  1431.                 if(ftpdo(line,ofilename)==INCOMPLETE) {    /* if account needed */
  1432.                     do {
  1433.                         putstring("Account: ");
  1434.                         if(ftpgets(command,100,1)==ABORT) 
  1435.                             return(FALSE);
  1436.                       } while(!(*(stpblk(command))));
  1437.                     sprintf(line,"ACCT %s",command);
  1438.                     ftpdo(line,ofilename);
  1439.                 }
  1440.                 if (ttypass) fromtty=FALSE;        /* back to batch */
  1441.                 return(TRUE);
  1442.  
  1443.             case ACCOUNT:
  1444.                 if (!(*(stpblk(command)))) {   /* null response to prompt OK */
  1445.                     putstring("Account: ");
  1446.                     if (ftpgets(command,100,0)==ABORT) return(FALSE); /* no echo */
  1447.                     while (!(*(stpblk(command))));
  1448.                     sprintf(line,"ACCT %s",command);
  1449.                     ftpdo(line,ofilename);
  1450.                 }
  1451.                 return(TRUE);
  1452.  
  1453.             case SITE:        /* site commands */
  1454.                 while(!(*(stpblk(command)))) {        /* if no arg */
  1455.                     putstring("Site: ");
  1456.                     if(ftpgets(command,100,1)==ABORT)
  1457.                         return(FALSE);    /* abort */
  1458.                   }
  1459.                 sprintf(line,"SITE %s",command);
  1460.                 ftpdo(line,ofilename);
  1461.                 return(TRUE);
  1462.  
  1463.  
  1464.             default:    /* unknown command */
  1465.                 sprintf(printline,"***Program error: Unknown command no: %d",cmdno);
  1466.                 nputs(printline);
  1467.                 break;
  1468.           }
  1469.     }
  1470. }
  1471.  
  1472. /************************************************************************/
  1473. /* ftpdo
  1474. *  Do whatever command is sent from the user interface using
  1475. *  userftpd, the background file handler
  1476. *  Returns code from ftpreplies
  1477. /************************************************************************/
  1478.  
  1479. static int ftpdo(s,ofile)
  1480.     char *s,*ofile;
  1481. {
  1482.     int i,rcode;
  1483.     char name[50],name2[50];
  1484.  
  1485.     for(i=0; i<4; i++) {
  1486.         s[i]=(char) toupper(s[i]);    /* command to upper case */
  1487.       }
  1488.     if(!strncmp(s,"STOR",4)) {    /* put file */
  1489.         getword(&s[5],name);    /* first arg - local file */
  1490.         if(!s[5]) 
  1491.             strcpy(&s[5],name);        /* if only one argument */
  1492.         else {
  1493.             getword(&s[5],name2);    /* second arg - removes quotes etc. */
  1494.             strcpy(&s[5],name2);    /* copy back into command */
  1495.           }
  1496. #ifdef    MSC
  1497.         if(0>(ftpfh=open(name,O_RDONLY | O_BINARY))) {    /* open local file */
  1498. #else
  1499.         if(0 >(ftpfh=open(name,O_RAW))) {    /* open local file */
  1500. #endif    
  1501.             nputs(" Cannot open file to transfer.");
  1502.             return(-1);
  1503.           }
  1504.         ftpdata=netlisten(ftpport());        /* open data connection */
  1505.         ftpstate=20;
  1506.       }
  1507.     else 
  1508.         if(!strncmp(s,"RETR",4)) {    /* get file */
  1509.             getword(&s[5],name);            /* remote file */
  1510.             if(s[5])         /* two args present */
  1511.                 getword(&s[5],name2);   /* local file */
  1512.              else
  1513.                 check_file_name (name, name2);
  1514. #ifdef  MSC
  1515.             ftpfh=open(name2,O_BINARY|O_CREAT|O_TRUNC+O_WRONLY,S_IREAD|S_IWRITE);
  1516. #else
  1517.              ftpfh=creat(name2,O_RAW);              /* open local file */
  1518. #endif
  1519.             if(ftpfh<0) {
  1520.                 sprintf(printline,"Cannot open file to receive: %s",name);
  1521.                 nputs(printline);
  1522.                 return(-1);
  1523.               }
  1524.             strcpy(&s[5],name);    /* put remote name back into command */
  1525.             ftpdata=netlisten(ftpport());        /* open data connection */
  1526.             ftpstate=30;
  1527.           }
  1528.         else 
  1529.             if(!strncmp(s,"LIST",4)||!strncmp(s,"NLST",4)) {
  1530.                 if(capture) 
  1531.                     captlist[0]='\0';    /* where to put incoming data */
  1532. if(debug>4) {
  1533.     nputs("ftpdo(): before calling ftpport() ");
  1534.   }    /* end if */
  1535.                 ftpdata=netlisten(ftpport());        /* data connection */
  1536. if(debug>4) {
  1537.     nputs("ftpdo(): after calling ftpport() ");
  1538.   }    /* end if */
  1539.                 ftpstate=40;
  1540.                 }
  1541.             else 
  1542.                 if(!strncmp(s,"TYPE",4)) {
  1543.                     if(toupper(s[5])=='I')
  1544.                         ftpfilemode=FIMAGE;    /* remember mode */
  1545.                     else 
  1546.                         if(toupper(s[5])=='A')
  1547.                             ftpfilemode=FASCII;
  1548.                   }
  1549.  
  1550.     dumpcon(ftpnum);            /* clear command connection */
  1551.     netpush(ftpnum);
  1552.     netwrite(ftpnum,s,strlen(s));        /* send command */
  1553.     netwrite(ftpnum,"\r\n",2);        /* <CRLF> terminates command */
  1554.     if(!capture && ofile[0]) {        /* command redirected */
  1555.         if((ftpstate!=20) &&(ftpstate!=30)) {    /* not get or put */
  1556. #ifdef    MSC
  1557.              if(0>(ftpfh=open(ofile,O_CREAT|O_APPEND|O_WRONLY,S_IWRITE|S_IREAD)))
  1558. #else
  1559.              if(0>(ftpfh=open(ofile,O_CREAT|O_APPEND|O_WRONLY,S_IWRITE)))
  1560. #endif
  1561.                 nputs(" Cannot open output file.");
  1562.             else
  1563.                 if(ftpdata > -1)
  1564.                     ftpstate=30;    /* act as get, since data goes into file */
  1565.                 else {
  1566.                     close(ftpfh);
  1567.                     ftpfh=0;
  1568.                   }
  1569.           }
  1570.       }
  1571.     if(debug) {
  1572.         sprintf(printline,"---> %s",s);    /* show command sent */
  1573.         nputs(printline);
  1574.         if(debug>=7) {
  1575.             for(i=0; i < (int)strlen(s); i++)
  1576.                 sprintf(&printline[4*i],"%3d ",s[i]);
  1577.             nputs(printline);
  1578.           }
  1579.       }
  1580.     i=ftpreplies(ftpnum,&rcode);        /* get remote response */
  1581. if(debug) {
  1582.     nputs("after ftpreplies() call, in ftpdo ");
  1583.   }    /* end if */
  1584.     if((i==NONE) && strncmp(s,"QUIT",4)) {    /* unexpected connection drop */
  1585.         nputs("lost connection");
  1586.         connected=FALSE;
  1587.       }
  1588.     if(i==ABORT||i==NONE||i==ERROR||i==FALSE)  {
  1589.         ftpstate=0;        /* if error, no transfer */
  1590.         if(ftpdata>-1)
  1591.             netclose(ftpdata);
  1592.         if(ftpfh!=0)
  1593.             close(ftpfh);
  1594.         ftpdata=-1;
  1595.         ftpfh=0;
  1596.       }
  1597.     return(i);
  1598. }
  1599.  
  1600. /************************************************************************/
  1601. /*   ftpport
  1602. *   return a new port number so that we don't try to re-use ports
  1603. *   before the mandatory TCP timeout period. (lifetime of a packet)
  1604. *   use a time-based initial port selection scheme.
  1605. /************************************************************************/
  1606.  
  1607. long int time();            /* global */
  1608.  
  1609. static unsigned int ftpport()
  1610. {
  1611.     unsigned int i,rcode;
  1612.     unsigned char hostnum[5];
  1613.     char sendline[60];        /* for port command */
  1614.  
  1615.     if(!sendport)            /* default port */
  1616.         return(HFTP-1);
  1617.     if(curftpprt<0x4000) {     /* restart cycle */
  1618.         i=(unsigned int)time(NULL);
  1619.         curftpprt=(unsigned int) (0x4000+(i&0x3fff));
  1620.       }
  1621.     i=curftpprt--;            /* get port, update for next time */
  1622.     netgetip(hostnum);        /* get my ip number */
  1623.     sprintf(sendline,"PORT %d,%d,%d,%d,%d,%d\r\n",hostnum[0],hostnum[1],hostnum[2],hostnum[3],i/256,i&255);    /* full port number */
  1624.     if(debug>1)
  1625.         nputs(sendline);
  1626.     netpush(ftpnum);        /* empty command connection */
  1627.     netwrite(ftpnum,sendline,strlen(sendline));    /* send PORT command */
  1628. if(debug>1) {
  1629.     nputs("ftpport(): before dumpcon() call ");
  1630.   }    /* end if */
  1631. /* check result of command, make sure port was okay */
  1632. /* return 0 on error */        /* ????? */
  1633.     dumpcon(ftpnum);
  1634. if(debug>1) {
  1635.     nputs("ftpport(): before ftpreplies() call ");
  1636.   }    /* end if */
  1637.     ftpreplies(ftpnum,&rcode);    /* get response */
  1638. if(debug>1) {
  1639.     sprintf(printline,"ftpport(): after ftpreplies() call, i=%d ",i);
  1640.     nputs(printline);
  1641.   }    /* end if */
  1642.     return(i);        /* port number */
  1643. }
  1644.  
  1645. /************************************************************************/
  1646. /* ftpreplies
  1647. * get responses to commands to server
  1648. * return TRUE on successful completion, FALSE on transient negative
  1649. * completion, INCOMPLETE if more commands needed for operation,
  1650. * NONE on lost connection, ABORT on user abort and ERROR on failure
  1651. *
  1652. /************************************************************************/
  1653.  
  1654. static int ftpreplies(cnum,rcode)
  1655. int cnum,*rcode;
  1656. {
  1657.     int cnt,ev,j=0;
  1658.  
  1659.     while(1) {
  1660. if(debug>4) {
  1661.     nputs("ftpreplies(): before rgetline() call ");
  1662.   }    /* end if */
  1663.         cnt=rgetline(cnum);        /* get line form remote host */
  1664. if(debug>4) {
  1665.     sprintf(printline,"s=%s cnt=%d ",s,cnt);
  1666.     nputs(printline);
  1667.   }    /* end if */
  1668.         if(cnt==NONE)
  1669.             return(NONE);        /* lost connection */
  1670.         if(cnt==ABORT) {        /* user abort */
  1671.             netpush(cnum);
  1672.             netwrite(cnum,"ABOR\r\n",6);        /* send abort */
  1673.             return(ABORT);
  1674.           }
  1675.         if(!sscanf(s,"%d",rcode))
  1676.             *rcode=-1;                    /* continuation line */
  1677.         if((*rcode/100)==2) {            /* positive completion */
  1678.         dumpcon(ftpnum);            /* clear command connection */
  1679.             while(ftpdata>=0) {            /* wait till transfers complete */
  1680.                 ev=checkevent();
  1681. if(debug>4) {
  1682.     sprintf(printline,"ev=%d ",ev);
  1683.     nputs(printline);
  1684.   }    /* end if */
  1685.                 if(ev==NONE)
  1686.                     return(NONE);        /* lost connection */
  1687.                 if(ev==ABORT)
  1688.                     return(ABORT);                /* user abort */
  1689.  
  1690.                 if(ev==HAVEDATA)
  1691.                     dumpcon(ftpnum);    /* msg on command connection */
  1692.               }
  1693.           }
  1694.         if(verbose || (*rcode==-1) || (*rcode>500))
  1695.             telnet(cnt);                /* informative/error msg or display on */
  1696.         if(j)
  1697.             if(*rcode==j)
  1698.                 j=0;                    /* end of continuation */
  1699.             else 
  1700.                 continue;
  1701.         else 
  1702.             if(s[3]=='-') {                /* line with continuations */
  1703.                 j=*rcode;                            /* remember end code */
  1704.                 continue;
  1705.               }
  1706. if(debug>4) {
  1707.     sprintf(printline,"*rcode=%d ",*rcode);
  1708.     nputs(printline);
  1709.   }    /* end if */
  1710.         switch((int)(*rcode/100)) {        /* first digit */
  1711.             case 1:                        /* preliminary */
  1712.                 continue;
  1713.     
  1714.             case 2:                        /* positive completion */
  1715.                 return(TRUE);
  1716.                 break;
  1717.  
  1718.             case 3:                        /* intermediate */
  1719.                 return(INCOMPLETE);
  1720.                 break;
  1721.         
  1722.             case 4:                        /* transient negative completion */
  1723.                 return(FALSE);
  1724.                 break;
  1725.  
  1726.             case 5:                        /* Permanent negative completion */
  1727.                 return(ERROR);
  1728.                 break;
  1729.  
  1730.             default:
  1731.                 nputs("Server response not understood. Terminating command\n");
  1732.                 return(ERROR);
  1733.           }    /* end switch */
  1734.       }    /* end while */
  1735. }
  1736.  
  1737. /************************************************************************/
  1738. /* rgetline - get a line from remote server
  1739. * return ABORT on user ABORT, NONE on lost connection,
  1740. * length of received line on success
  1741. *
  1742. /************************************************************************/
  1743.  
  1744. static int rgetline(cnum)
  1745. int cnum;
  1746. {
  1747.     int cnt,i=0,ev;
  1748.  
  1749.     while(1) {
  1750.         if(debug>4) 
  1751.             nputs("rgetline(): before checkevent() ");
  1752.         ev=checkevent();
  1753.         if(debug>4) {
  1754.             printf("\nevent: %d\n",ev);
  1755.             nputs("rgetline(): after checkevent() ");
  1756.           }    /* end if */
  1757.  
  1758.         switch(ev) {
  1759.             case ABORT:                /* user abort */
  1760.             case NONE:                /* lost connection */
  1761.                 return(ev);
  1762.  
  1763.             case HAVEDATA:
  1764.                 if(fromtty && n_scrlck())
  1765.                     cnt=0;                    /* if paused, nothing to do */
  1766.                 else 
  1767.                     while(1) {
  1768.                         cnt=netread(cnum,&s[i],1);    /* get some from queue */
  1769.                         if(!cnt) 
  1770.                             break;            /* nothing available */
  1771.                         if(s[i++]=='\n') {    /* end of line */
  1772.                             s[i]='\0';
  1773. if(debug>3) {
  1774.     sprintf(printline,"rgetline(): s=%s, i=%d ",s,i);
  1775.     nputs(printline);
  1776.   }    /* end if */
  1777.                             return(i);        /* return line length */
  1778.                           }
  1779.                       }
  1780.                 break;
  1781.  
  1782.             default:        /* ignore other events */
  1783.                 break;
  1784.           }
  1785.       }
  1786. }
  1787.  
  1788. /************************************************************************/
  1789. /* breakstop
  1790. * handle cntrl-break
  1791. /************************************************************************/
  1792.  
  1793. static void breakstop()
  1794. {
  1795. #ifdef MSC
  1796.     signal(SIGINT,SIG_IGN);        /* ignore interrupts while processing this routine */
  1797. #endif
  1798.     foundbreak=1;
  1799. #ifdef MSC
  1800.     signal(SIGINT,breakstop);    /* reset Microsoft interception of break */
  1801. #endif
  1802. }
  1803.  
  1804. /************************************************************************/
  1805. /* userftpd
  1806. *  FTP receive and send file functions
  1807. /************************************************************************/
  1808.  
  1809. static void userftpd(void )
  1810. {
  1811.     int i,r1,r2;
  1812.     char lastchar;
  1813.     double rate;
  1814.     static int stopcapture=FALSE;    /* bytes xferred % 1024 */
  1815.     static long tbytes;
  1816.  
  1817.     switch(ftpstate) {
  1818.         default:                    /* unknown */
  1819.             break;
  1820.  
  1821.         case 40:                /* start LIST */
  1822.             if(!netest(ftpdata)) {
  1823.                 start=time(NULL);    /* current time */
  1824.                 tbytes=0;        /* received so far */
  1825.                 ftpstate=41;
  1826.               }
  1827.             break;
  1828.  
  1829.         case 41:        /* get started */
  1830.             do {
  1831.                 if(capture && !stopcapture) {    /* into captlist */
  1832.                     fcnt=netread(ftpdata,xs,READSIZE);
  1833.                     if(fcnt>0) {        /* make certain a negative length string is not appended */
  1834.                         if(strlen(captlist)+fcnt>=2000) { /* full */
  1835.                             if(!fromtty || !n_scrlck())
  1836.                                 nputs(&xs[2001-strlen(captlist)]);    /* display excess chars */
  1837.                             strncat(captlist,xs,2000-strlen(captlist));
  1838.                             nputs("Error: capture list too long");
  1839.                             stopcapture=TRUE;
  1840.                           }
  1841.                         else 
  1842.                             strncat(captlist,xs,fcnt);         /* append */
  1843.                       }    /* end if */
  1844.                     if(debug>2) {
  1845.                         sprintf(printline,"xs %s fcnt %d ",xs,fcnt);
  1846.                         nputs(printline);
  1847.                         sprintf(printline,"tbytes %ld strlen(captlist) %d ",tbytes,strlen(captlist));
  1848.                         nputs(printline);
  1849.                       }
  1850.                   }
  1851.                 else {
  1852.                     if(fromtty && n_scrlck())
  1853.                         break;    /* paused */
  1854.                     fcnt=netread(ftpdata,xs,READSIZE);
  1855.                     for(i=0; i<fcnt; i++) {
  1856.                         nputchar(xs[i]);                    /* display */
  1857.                         if (xs[i] == 10) domore();            /* |more */
  1858.                     }
  1859.                   }
  1860.                 if(fcnt>0) 
  1861.                     tbytes += fcnt;                        /* how much */
  1862.               } while(fcnt>0);                            /* till no more input */
  1863.             if(debug>1) {
  1864.                 sprintf(printline,"tbytes %ld ",tbytes);
  1865.                 nputs(printline);
  1866.                 sprintf(printline,"captlist %s ",captlist);
  1867.                 nputs(printline);
  1868.               }
  1869.             break;
  1870.  
  1871.         case 30:        /* receive */
  1872.             if(!netest(ftpdata)) {        /* connection made */
  1873.                 start=time(NULL);
  1874.             ftpstate=31;
  1875.                 len=xp=0;
  1876.                 tbytes=0;
  1877.               }
  1878.             break;
  1879.  
  1880.         case 31:
  1881. /*
  1882. * file has already been opened, take everything from the connection
  1883. * and place into the open file: ftpfh
  1884. */
  1885.             do {        /* wait until xs is full before writing to disk */
  1886.                 if(len <= 0) {
  1887.                     if(xp) {
  1888.                         if ((write(ftpfh,xs,xp) == -1)&&(errno==ENOSPC)) {
  1889.                             netwrite(ftpdata,"ABOR\r\n",6);    /* send abort */
  1890.                             netwrite(ftpdata,"452 Disk full error.\r\n",22);
  1891.                             printf("Local disk full error.\n");
  1892.                         }
  1893.                         else xp=0;
  1894.                       }
  1895.                     len=BUFFERS;        /* expected or desired len to go */
  1896.                   }
  1897. /* how much to read */
  1898.                 if(len < READSIZE)
  1899.                     i=len;
  1900.                 else
  1901.                     i=READSIZE;
  1902.                 fcnt=netread(ftpdata,&xs[xp],i);
  1903.                 if(fcnt>0) {    /* adjust counts */
  1904.                     len -= fcnt;
  1905.                     xp += fcnt;
  1906.                     tbytes += fcnt;
  1907.                   }
  1908.                 if(debug>1) {
  1909.                     sprintf(printline,"len %d xp %d fcnt %d",len,xp,fcnt);
  1910.                     nputs(printline);
  1911.                   }
  1912.                 if(fcnt<0) {                    /* connection closed */
  1913.                     write(ftpfh,xs,xp);            /* write last block */
  1914.                     if(ftpfilemode==FASCII) 
  1915.                         write(ftpfh,"\032",1);    /* EOF char */
  1916.                     close(ftpfh);
  1917.                     ftpfh=0;
  1918.                   }
  1919.                 if(hash) {                        /* hash mark printing */
  1920.                     for(i=(int)(((tbytes-(long)fcnt)%1024L+(long)fcnt)/1024L); i; i--)
  1921.                     nputchar('#');
  1922.                   }
  1923.               } while(fcnt>0);
  1924.             break;
  1925.  
  1926.         case 20:    /* send */
  1927.             if(!netest(ftpdata)) {                /* connection made */
  1928.                 start=time(NULL);
  1929.                 ftpstate=21;
  1930.                 lengthfile=lseek(ftpfh,0L,SEEK_END);   /* how long is file? */
  1931.                 lseek(ftpfh, -1L,SEEK_CUR);            /* position at last character*/
  1932.                 if (read(ftpfh, &lastchar, 1)==0) {
  1933.                     if (debug>4) printf("LC Test failed.\n");
  1934.                     lastchar='\0';
  1935.                 }
  1936.                   else {
  1937.                     if (debug>4) printf("Last character test returned %d.\n",(int) lastchar);
  1938.                 };
  1939.                 lseek(ftpfh,0L,SEEK_SET);               /* back to beginning */
  1940.                 if ((ftpfilemode==FASCII)&&(lastchar=='\26'))        /* drop cntr-Z for ascii transfer */
  1941.                     lengthfile--;                /* leave off ctrl-Z */
  1942.                 towrite=0;
  1943.                 xp=0;
  1944.                 tbytes=0;
  1945.               }
  1946.             break;
  1947.  
  1948.         case 21:
  1949. /*
  1950. *  transfer file(s) to the other host via ftp request
  1951. *  file is already open=ftpfh
  1952. */
  1953. if (debug > 4) printf("lengthfile=%d  towrite=%d  xp=%d  i=%d\n",lengthfile,towrite,xp,i);
  1954.  
  1955.             if(towrite<=xp) {            /* need to read again */
  1956. if (debug > 4) printf("towrite<=xp\n");
  1957.                 if(lengthfile <(long)BUFFERS)
  1958.                     i=(int)lengthfile;
  1959.                 else
  1960.                     i=BUFFERS;
  1961. if (debug > 4) printf("i=%d\n",i);
  1962.                 towrite=read(ftpfh,xs,i);
  1963. if (debug > 4) printf("towrite=%d\n",towrite);
  1964.                 xp=0;
  1965.               }
  1966.             if (towrite>=xp) 
  1967.                 i=netwrite(ftpdata,&xs[xp],towrite-xp);
  1968.             else 
  1969.                 i=netwrite(ftpdata,&xs[xp],0);
  1970.             if(i>0) {                    /* send successful, adjust counts */
  1971.                 xp+=i;
  1972.                 lengthfile -=i;
  1973.                 tbytes+=i;
  1974.               }
  1975.             if(debug>1) {
  1976.                 sprintf(printline,"i %d xp %d towrite %d",i,xp,towrite);
  1977.                 nputs(printline);
  1978.               }
  1979.             if(hash) {                    /* hash printing */
  1980.                 for(r1=(int)(((tbytes-(long)i)%1024L+(long)i)/1024L); r1; r1--)
  1981.                 nputchar('#');
  1982.               }
  1983. /*
  1984. *  done if:  the file is all read from disk and all sent
  1985. *  or other side has ruined connection
  1986. */
  1987.             if((lengthfile<=0L&&xp>=towrite)||netest(ftpdata)) 
  1988.                 ftpstate=22;
  1989.             break;
  1990.  
  1991.         case 22:            /* send done */
  1992. /* wait for other side to accept everything and then close */
  1993.             if(0>=(r1=netpush(ftpdata)))
  1994.                 fcnt=-1;
  1995.             if(debug>1) {
  1996.                 sprintf(printline,"fcnt %d r1 %d\n",fcnt,r1);
  1997.                 nputs(printline);
  1998.                 if (kbhit()) { netclose(ftpdata); exit(0);};
  1999.             };
  2000.             break;
  2001.  
  2002.       }                 /* end of switch */
  2003. /*
  2004. *  after reading from connection, if the connection is closed,
  2005. *  reset up shop.
  2006. */
  2007.     if(fcnt<0) {        /* connection lost */
  2008.         if(ftpfh>0) {    /* close file */
  2009.             close(ftpfh);
  2010.             ftpfh=0;
  2011.           }
  2012.         ftpstate=0;    /* done */
  2013.         fcnt=0;
  2014.         i=(int)(time(NULL)-start);    /* how long to transfer */
  2015.         if(!i) 
  2016.             rate=((double) tbytes) / 1024.0;
  2017.         else 
  2018.             rate=((double) tbytes) /(i * 1024.0);
  2019.         r1=(int) rate;                /* integer part of rate */
  2020.         r2=(int)((rate -(double) r1) * 1000);
  2021.         sprintf(printline,"Transferred %ld bytes in %d seconds(%d.%03d Kbytes/sec)",tbytes,i,r1,r2);
  2022.         if(hash) 
  2023.             nputs("");
  2024.         if(verbose) 
  2025.             nputs(printline);
  2026.         netclose(ftpdata);            /* close connection */
  2027.         ftpdata=-1;
  2028.         if(bell) 
  2029.             nputchar(7);
  2030.       }
  2031. }
  2032.  
  2033. /************************************************************************/
  2034. /* getword: remove a word from a string.  Things within quotes are
  2035. * assumed to be one word.
  2036. * return TRUE on success, FALSE on end of string
  2037. /************************************************************************/
  2038.  
  2039. static int getword(string,word)
  2040. char *string,*word;
  2041. {
  2042.     char *p,*q;
  2043.     int i=0;
  2044.  
  2045.     if(debug>4) {
  2046.         sprintf(printline,"getword: string is %s",string);
  2047.         nputs(printline);
  2048.       }
  2049.     p=stpblk(string);            /* skip leading blanks */
  2050.     if(!(*p)) {                /* no words in string */
  2051.         word[0]='\0';
  2052.         return(FALSE);
  2053.       }
  2054.     if(*p=='!') {                /*! is a word */
  2055.         word[0]=*p;
  2056.         word[1]='\0';
  2057.         strcpy(string,++p);
  2058.         return(TRUE);
  2059.       }
  2060.     if(*p=='\"') {                /* word delimited by quotes */
  2061.         while(p[++i] && p[i]!='\"') word[i-1]=p[i];
  2062.         word[i-1]='\0';
  2063.         if(!p[i]) 
  2064.             nputs("Missing \". Assumed at end of string.");
  2065.         else 
  2066.             i++;
  2067.         q=p+i;
  2068.       }
  2069.     else 
  2070.         q=stptok(p, word, 50, " \t\r\n");    /* get word, max len 50 */
  2071.     p=stpblk(q);                         /* remove trailing blanks */
  2072.     strcpy(string,p);                    /* remove extracted stuff */
  2073.     return(TRUE);
  2074. }
  2075.  
  2076. /************************************************************************/
  2077. /* flip_slashes: change \ to /                                            */
  2078. /************************************************************************/
  2079. static void flip_slashes(command,filename)
  2080. char *command;
  2081. char *filename;
  2082. {
  2083.     register int i;                    /* local counting variable */
  2084.  
  2085.     filename[0]='\0';                /* don't do anything with the filename */
  2086.     for(i=0; !command[i]; i++) {        /* loop over entire string */
  2087.         if(command[i]=='\\')         /* found a \ ? */
  2088.             command[i]='/';            /* flip the \ to a / */
  2089.       }
  2090. }    /* end flip_slashes() */
  2091.  
  2092. /************************************************************************/
  2093. /* checkoredir: check for output redirection.  If the command contains a
  2094. * >, assume a filename follows and extract it.  Remove the redirection
  2095. * from the original command.
  2096. * Also change \ to /
  2097. * return TRUE if redirection specified, FALSE otherwise 
  2098. /************************************************************************/
  2099.  
  2100. static int checkoredir(command,filename,slashflip)
  2101. char *command,*filename;
  2102. int slashflip;
  2103. {
  2104.     int i;
  2105.  
  2106.     filename[0]='\0';
  2107.     for(i=0;(command[i]!='>'); i++) {    /* process command part */
  2108.         if(slashflip && command[i]=='\\') 
  2109.             command[i]='/';
  2110.         if(!command[i]) 
  2111.             return(FALSE);                /* no redirection */
  2112.       }
  2113.     getword(&command[i+1],filename);    /* get redirected filename */
  2114.     command[i]='\0';
  2115.     return(TRUE);
  2116. }
  2117.  
  2118. /************************************************************************/
  2119. /* getdir: get current directory.  Finds current drive and current path
  2120. * on drive, returns a string.
  2121. *
  2122. /************************************************************************/
  2123.  
  2124. static void getdir(drive,path)
  2125. int drive;
  2126. char *path;
  2127. {
  2128. #ifdef    MSC
  2129.     getcwd(path,100);
  2130.     drive=drive;            /* To get rid of annoying "Unreferenced formal parameter" warning. */
  2131. #else
  2132.     char partpath[64];
  2133.     if(!drive) drive=getdsk();                /* current disk */
  2134.         getcd(drive+1,partpath);            /* current dir */
  2135.     sprintf(path,"%c:\\%s",'A'+drive,partpath);
  2136. #endif
  2137. }
  2138.  
  2139. /************************************************************************/
  2140. /* finduniq: find name that is a unique prefix of one of the entries in
  2141. * a list.  Return position of the entry, NONE if none, AMBIGUOUS if more
  2142. * than one.
  2143. *
  2144. /************************************************************************/
  2145.  
  2146. static int finduniq(name,list,listsize)
  2147. char *name, *list[];
  2148. int listsize;
  2149. {
  2150.     int i,j=NONE,len;
  2151.     len=strlen(name);
  2152.     for(i=0; i<listsize; i++) {
  2153.         if(!strncmp(name,list[i],len)) {        /* prefix */
  2154.             if(len==(int)strlen(list[i]))
  2155.                 return(i+1);                    /* exact match */
  2156.             if(j!=NONE) 
  2157.                 j=AMBIGUOUS;                    /* more than one match */
  2158.         else 
  2159.             j=i+1;                                /* note prefix found */
  2160.             }
  2161.       }
  2162.     return(j);                                    /* prefix */
  2163. }
  2164.  
  2165. /************************************************************************/
  2166. /* checkevent
  2167. * get and process network events
  2168. * returns ABORT on user abort, HAVEDATA if data available on command
  2169. * connection, NONE if connection lost, DOMOK if domain search succeeds,
  2170. * DOMFAIL if domain search fails, TRUE if no relevant event.
  2171. /************************************************************************/
  2172.  
  2173. static int checkevent(void)
  2174. {
  2175.     int ev,class=0,data;
  2176.  
  2177.     kbhit();            /* check for cntrl-break */
  2178.     if(foundbreak) return(ABORT);
  2179.     userftpd();         /* do ftp stuff */
  2180.     Stask();            /* keep connections alive */
  2181.     ev=Sgetevent(CONCLASS|ERRCLASS|USERCLASS, &class,&data);
  2182.     if(class==CONCLASS) {
  2183.         if(data==ftpnum) {        /* command connection */
  2184.             if(ev==CONCLOSE) {    /* connection lost */
  2185.                 netclose(ftpnum);
  2186.                 if(!netest(ftpdata)) 
  2187.                     netclose(ftpdata);    /* close data connection */
  2188.                 connected=FALSE;
  2189.                 return(NONE);
  2190.               }
  2191.             if(ev==CONDATA)
  2192.                 return(HAVEDATA);    /* data received */
  2193.           }
  2194.       }
  2195.     else 
  2196.         if(class==USERCLASS) {        
  2197.             if(ev==DOMOK) {        /* domain search succeeded */
  2198.                 ftpnum=data;
  2199.                 return(DOMOK);
  2200.               }
  2201.             else 
  2202.                 if(ev==DOMFAIL) 
  2203.                     return(DOMFAIL);    /* domain search failed */
  2204.           }
  2205.  
  2206. /* else if(class==ERRCLASS&&ev==ERR1) nputs(neterrstring(data)); */
  2207.     return(TRUE);
  2208. }
  2209.  
  2210. /************************************************************************/
  2211. /* putstring: display string using vt100 emulation routines
  2212. /************************************************************************/
  2213.  
  2214. static int putstring(string)
  2215. char *string;
  2216. {
  2217.     for(; *string; string++) nputchar(*string);
  2218.     return(TRUE);
  2219. }
  2220.  
  2221. /************************************************************************/
  2222. /* printerr: display TCP error messages - disabled
  2223. /************************************************************************/
  2224.  
  2225. static int printerr(void )
  2226. {
  2227. /*    int data,class;    while(ERR1==Sgetevent(ERRCLASS,&class,&data))nputs(neterrstring(data));*/
  2228. return(TRUE);
  2229. }
  2230.  
  2231. /************************************************************************/
  2232. /* getnname: get next name from captured list
  2233. * names delimited by newlines - <CR> or <LF>
  2234. /************************************************************************/
  2235.  
  2236. static int getnname(string,word)
  2237. char *string,*word;
  2238. {
  2239.     char *s;
  2240.  
  2241.     s=string;
  2242.     while((*string=='\n')||(*string=='\r')) 
  2243.         string++;                        /* skip initial newlines */
  2244.     if(!(*string)) 
  2245.         return(FALSE);        /* end of captlist */
  2246.     while((*string!='\n') &&(*string!='\r') &&(*string)) *(word++)=*(string++);
  2247.     while((*string=='\n')||(*string=='\r')) 
  2248.         string++;    /* skip trailing newline */
  2249.     *word='\0';
  2250.     strcpy(s,string);
  2251.     return(TRUE);
  2252. }
  2253.  
  2254. /***************************************************************************/
  2255. /*  dosescape
  2256. *  escape to dos for processing
  2257. *  put the connections to automated sleep while in DOS
  2258. /************************************************************************/
  2259.  
  2260. void dosescape(void)
  2261. {
  2262.     int i;
  2263.     char *command_shell;
  2264.  
  2265.     nputs("Warning, some programs will interfere with network communication and can");
  2266.     nputs("cause lost connections.  Do not run any network programs from this DOS shell.");
  2267.     nputs("Type 'EXIT' to return to FTP");
  2268. /*
  2269. *  invoke a put-to-sleep routine which calls netsleep every 8/18ths of a sec
  2270. */
  2271.     tinst();
  2272.     command_shell=getenv("COMSPEC");
  2273.     if (command_shell !=NULL)
  2274.         i=system(command_shell);        /* call DOS */
  2275.      else
  2276.         i= -1;
  2277.     tdeinst();
  2278.  
  2279.     if(i<0) {
  2280.         nputs("\n\nError loading COMMAND.COM");
  2281.         nputs("Make sure COMMAND.COM is specified under COMSPEC.");
  2282.         nputs("It must also be in a directory which is in your PATH statement.");
  2283.       }
  2284.     if(fromtty) 
  2285.         n_row();
  2286. }
  2287.  
  2288.  
  2289. static void nputs(line)
  2290. char *line;
  2291. {
  2292.     if(!scrsetup) {
  2293.         scrsetup = 1;
  2294.         if(fromtty) {            /* don't do anything now */
  2295.             if (!display_init) {
  2296.                 Sgetconfig(&def);        /* get information provided in hosts file */
  2297.                 display_init=TRUE;
  2298.                 dos_color=n_color((int) def.color[0]);    /* set color to that set in config file */
  2299.             };
  2300.             n_color((int) def.color[0]);    /* set color to that set in config file */
  2301.             n_clear();            /* clear screen */
  2302.             n_wrap(1);            /* cursor positioning */
  2303.             n_cur(0,0);
  2304.           }
  2305.         puts("National Center for Supercomputing Applications");
  2306.         puts("        FTP version 2.3.03  7/23/91");
  2307. #ifdef FINAL_RELEASE
  2308.         puts("Copyright Board of Trustees University of Illinois");
  2309. #endif
  2310.     }
  2311.  
  2312.     if(*line) 
  2313.         puts(line);
  2314.     else 
  2315.         puts("");
  2316. }
  2317.  
  2318. static void nputchar(ch)
  2319. char ch;
  2320. {
  2321.     if(fromtty & ttypass) 
  2322.         putc(ch,stderr);
  2323.     else 
  2324.         putchar(ch);
  2325. }
  2326. /*
  2327.     unsigned char convtable []={
  2328.         '{', 0x84,
  2329.         '|',0x94,
  2330.         '}',0x86,
  2331.          '[',0x8e,
  2332.          '\\',0x99,
  2333.          ']',0x8f,
  2334.          0,0
  2335.         };
  2336.  
  2337. n_chkchar()
  2338. {
  2339.     int    x;
  2340.     unsigned char *i=convtable;
  2341.  
  2342.     x=x_chkchar();
  2343.      for( ; *i!=0; i+=2)
  2344.          if(x==(int)*(i+1))
  2345.              x=(int) *i;
  2346.      return( x);
  2347.  }
  2348. */
  2349.  
  2350. #ifdef    MSC
  2351.  
  2352. static char *stptok( p, toword, len, delim)
  2353.  
  2354.  char *p;
  2355.  char *toword;
  2356.  int len;
  2357.  char *delim;
  2358.  
  2359.  {
  2360.      char *adv=toword;
  2361.      int i;
  2362.      int end=0;
  2363.  
  2364.      do { 
  2365.          for(i=0; i< (int) strlen(delim); i++)
  2366.              if(*p==delim[i]||(!*p))
  2367.             end++;
  2368.          if(! end) {
  2369.              if(adv>=(toword+len-1)) 
  2370.                 end++;
  2371.              *adv++=*p++;
  2372.            }
  2373.        } while(! end);
  2374.      *adv='\0';
  2375.      return( p);
  2376.  }
  2377.  
  2378. static char *stpblk( ch)
  2379.  char    *ch;
  2380.  
  2381.  {
  2382.      while(*ch==' '||*ch=='\t') ch++;
  2383.      return( ch);
  2384.  }
  2385. #endif
  2386.  
  2387. int numrows()        /* detect number of rows */
  2388. {
  2389.     int rows=24;    /* default number of rows */
  2390.  
  2391. #ifdef INT_FIXED
  2392.     union REGS regs;
  2393.  
  2394.     regs.x.ax = 0x1130;    /* get font information (includes # of rows) */
  2395.     int86(0x10,®s,®s);
  2396.     rows = regs.h.dl;    /* number of rows */
  2397. #endif
  2398.  
  2399.     return (rows);
  2400. }
  2401.  
  2402. int domore(void)
  2403. {
  2404.     int ch = 0;
  2405.  
  2406.     if (usemore) {
  2407.         if (lineslft-- <=1) {
  2408.             printf("-- more --");
  2409.             ch=0;
  2410.             while (!ch) {
  2411.                 if (!kbhit())        /* if no char available */
  2412.                     Stask();        /* keep the connection alive */
  2413.                 else
  2414.                     ch = getch();    /* else get a character */
  2415.                 if (foundbreak) {
  2416.                     foundbreak=0;
  2417.                     ch=32;
  2418.                 }
  2419.             }
  2420.             printf("\r          \r");
  2421.             if (ch == 13)
  2422.                 lineslft++;
  2423.             else lineslft=numlines;
  2424.         }
  2425.     }
  2426.     return(ch);
  2427. }
  2428.  
  2429. /************************************************************************/
  2430. /*                             check_file_name                          */
  2431. /*                                                                      */
  2432. /*  A function to check for and enforce MS-DOS file name compatibility  */
  2433. /*  and uniqueness.  All non-MS-DOS filename characters from 'in_fname' */
  2434. /*  are deleted.  If the filename exists in the current directory, a    */
  2435. /*  unique name is created to avoid file name collision.                */
  2436. /*  'out_fname' must be large enough for the full filename (13 bytes).  */
  2437. /*                                                                      */
  2438. /*       Returns:    pointer to 'out_fname'                             */
  2439. /*                                                                      */
  2440. /*       Allen W. Todd                        Dec 24, 1990              */
  2441. /*                                                                      */
  2442. /************************************************************************/
  2443.  
  2444. char  *check_file_name (char  *in_fname,
  2445.                         char  *out_fname)
  2446.  
  2447. {
  2448.    char  buf[80];
  2449.    char  *s;
  2450.    char  *fname;
  2451.    char  *fextn;
  2452.    char  num_buf[20];
  2453.    long  count    = 0L;
  2454.  
  2455.    strcpy (buf, in_fname);    /* make local copy */
  2456.    strlwr (buf);              /* convert to lower case */
  2457.    while ((s = strpbrk (buf, "\"*+,/:;<=>?[\]^|")) != NULL)
  2458.       strcpy (s, s+1);        /* delete non-DOS chars */
  2459.    fname = &buf[0];           /* separate filename from file extension */
  2460.    if ((fextn = strchr (buf, '.')) != NULL)
  2461.       *fextn++ = '\0';
  2462.    if (strlen (fname) > 8) *(fname+8) = '\0';   /* fix filename @ 8 char */
  2463.    if (strlen (fextn) > 3) *(fextn+3) = '\0';   /* fix file extension @ 3 char */
  2464.    strcpy (out_fname, fname);     /* build complete filename */
  2465.    if (fextn)
  2466.       {
  2467.       strcat (out_fname, ".");
  2468.       strcat (out_fname, fextn);
  2469.       }
  2470.    while (access (out_fname, 0) == 0)   /* if file already exists */
  2471.       {
  2472.       ltoa (count++, num_buf, 10);
  2473.       strcpy (out_fname, fname);     /* build complete filename */
  2474.       if ( (strlen (fextn) < 3) && (strlen (num_buf) + strlen (fextn) <= 3) )
  2475.          strcat (fextn, num_buf);
  2476.       else
  2477.          {
  2478.          if (strlen(fname) > strlen(num_buf))
  2479.             strcpy (out_fname+(strlen(fname)-strlen(num_buf)), num_buf);
  2480.          else
  2481.             strcat (out_fname, num_buf);
  2482.          }
  2483.       if (fextn)
  2484.          {
  2485.          strcat (out_fname, ".");
  2486.          strcat (out_fname, fextn);
  2487.          }
  2488.       }
  2489.    return (out_fname);
  2490. }
  2491.  
  2492.