home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / FTPCLI.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  47KB  |  1,667 lines

  1. /* Internet FTP client (interactive user)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by G1EMM and PA0GRI */
  5. /* modifications for encrypted password by ik1che 900419 */
  6. /* added "resume" and "rput" commands for interrupted file transfers
  7.  * by iw0cnb 15 Feb 92 */
  8.   
  9.  /* VIEW command added by Simon G1FHY. Mod by Paul@wolf.demon.co.uk */
  10. #ifdef MSDOS
  11. #include <dir.h>
  12. #endif
  13. #ifdef LINUX
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #endif
  17. #include "global.h"
  18. #include "mbuf.h"
  19. #include "session.h"
  20. #include "cmdparse.h"
  21. #include "proc.h"
  22. #include "tty.h"
  23. #include "socket.h"
  24. #include "mailbox.h"
  25. #include "ftp.h"
  26. #include "ftpcli.h"
  27. #include "commands.h"
  28. #include "netuser.h"
  29. #include "dirutil.h"
  30. #include "files.h"
  31. #include "config.h"
  32.   
  33. #define DIRBUF  256
  34.   
  35. #ifdef FTPSESSION
  36.   
  37. #ifdef  LZW
  38. #include "lzw.h"
  39.   
  40. int Ftpslzw;
  41. int Ftpclzw;
  42. int doftpslzw __ARGS((int argc,char *argv[],void *p));
  43. int doftpclzw __ARGS((int argc,char *argv[],void *p));
  44. static int dolocftpclzw __ARGS((int argc,char *argv[],void *p));
  45. #endif
  46.   
  47. extern char System[];
  48. static int doascii __ARGS((int argc,char *argv[],void *p));
  49. static int dobatch __ARGS((int argc,char *argv[],void *p));
  50. static int dobinary __ARGS((int argc,char *argv[],void *p));
  51. static int doftpcd __ARGS((int argc,char *argv[],void *p));
  52. static int doftphelp __ARGS((int argc,char *argv[],void *p));
  53. static int doget __ARGS((int argc,char *argv[],void *p));
  54. static int dohash __ARGS((int argc,char *argv[],void *p));
  55. static int doverbose __ARGS((int argc,char *argv[],void *p));
  56. static int dolist __ARGS((int argc,char *argv[],void *p));
  57. static int dols __ARGS((int argc,char *argv[],void *p));
  58. static int doldir  __ARGS((int argc,char *argv[],void *p));
  59. static int dolcd  __ARGS((int argc,char *argv[],void *p));
  60. static int dolmkdir __ARGS((int argc,char *argv[],void *p));
  61. static int domkdir __ARGS((int argc,char *argv[],void *p));
  62. static int domget __ARGS((int argc,char *argv[],void *p));
  63. static int domput __ARGS((int argc,char *argv[],void *p));
  64. static int doput __ARGS((int argc,char *argv[],void *p));
  65. static int doquit __ARGS((int argc,char *argv[],void *p));
  66. static int dormdir __ARGS((int argc,char *argv[],void *p));
  67. static int doresume __ARGS((int argc,char *argv[],void *p));
  68. static int dorput __ARGS((int argc,char *argv[],void *p));
  69. static int dotype __ARGS((int argc,char *argv[],void *p));
  70. static int doview __ARGS((int argc,char *argv[],void *p));
  71. static int getline __ARGS((struct session *sp,char *prompt,char *buf,int n));
  72. static int getresp __ARGS((struct ftpcli *ftp,int mincode));
  73. static long getsub __ARGS((struct ftpcli *ftp,char *command,char *remotename,
  74. char *localname));
  75. static long putsub __ARGS((struct ftpcli *ftp,char *remotename,char *localname,int putr));
  76. static void sendport __ARGS((int s,struct sockaddr_in *socket));
  77. static char *ftpcli_login __ARGS((struct ftpcli *ftp,char *host));
  78.   
  79. static char Notsess[] = "Not an FTP session!\n";
  80.   
  81. static int Ftp_type = ASCII_TYPE;
  82. static int Ftp_logbsize = 8;
  83.   
  84. static struct cmds Ftpcmds[] = {
  85.     "",             donothing,      0, 0, NULLCHAR,
  86.     "?",            doftphelp,      0, 0, NULLCHAR,
  87.     "ascii",        doascii,        0, 0, NULLCHAR,
  88.     "batch",        dobatch,        0, 0, NULLCHAR,
  89.     "binary",       dobinary,       0, 0, NULLCHAR,
  90.     "cd",           doftpcd,        0, 2, "cd <directory>",
  91.     "dir",          dolist,         0, 0, NULLCHAR,
  92.     "list",         dolist,         0, 0, NULLCHAR,
  93.     "get",          doget,          0, 2, "get <remotefile> <localfile>",
  94.     "hash",         dohash,         0, 0, NULLCHAR,
  95.     "help",         doftphelp,      0, 0, NULLCHAR,
  96.     "ls",           dols,           0, 0, NULLCHAR,
  97.     "lcd",          dolcd,          0, 1, NULLCHAR,
  98.     "ldir",         doldir,         0, 1, NULLCHAR,
  99.     "lmkdir",       dolmkdir,       0, 2, "lmkdir <local Directory>",
  100. #ifdef LZW
  101.     "reclzw",       dolocftpclzw,   0, 0, NULLCHAR,
  102.     "sendlzw",      doftpslzw,      0, 0, NULLCHAR,
  103. #endif
  104.     "mget",         domget,         0, 2, "mget <file> [<file> ...]",
  105.     "mkdir",        domkdir,        0, 2, "mkdir <directory>",
  106.     "mput",         domput,         0, 2, "mput <file> [<file> ...]",
  107.     "nlst",         dols,           0, 0, NULLCHAR,
  108.     "put",          doput,          0, 2, "put <localfile> <remotefile>",
  109.     "quit",         doquit,         0, 0, NULLCHAR,
  110.     "resume",       doresume,       0, 2, "resume <remotefile> <localfile>",
  111.     "rmdir",        dormdir,        0, 2, "rmdir <directory>",
  112.     "rput",         dorput,         0, 2, "rput <localfile> <remotefile>",
  113.     "type",         dotype,         0, 0, NULLCHAR,
  114.     "verbose",      doverbose,      0, 0, NULLCHAR,
  115.     "view",         doview,         0, 2,"view <remotefile>",
  116.     NULLCHAR,       NULLFP,         0, 0, NULLCHAR,
  117. };
  118.   
  119. int
  120. doftphelp(argc,argv,p)
  121. int argc;
  122. char *argv[];
  123. void *p;
  124. {
  125.     register struct cmds *cmdp;
  126.     int i;
  127.     char buf[77];
  128.   
  129.     tputs("\nFTP commands:\n");
  130.     memset(buf,' ',sizeof(buf));
  131.     buf[75] = '\n';
  132.     buf[76] = '\0';
  133.     for(i=0,cmdp = Ftpcmds;cmdp->name != NULL;cmdp++,i = (i+1)%7){
  134.         strncpy(&buf[i*10],cmdp->name,strlen(cmdp->name));
  135.         if(i == 6){
  136.             tputs(buf);
  137.             memset(buf,' ',sizeof(buf));
  138.             buf[75] = '\n';
  139.             buf[76] = '\0';
  140.         }
  141.     }
  142.     if(i != 0)
  143.         tputs(buf);
  144.     tputc('\n');
  145.     return 0;
  146. }
  147.   
  148. /* Handle top-level FTP command */
  149. int
  150. doftp(argc,argv,p)
  151. int argc;
  152. char *argv[];
  153. void *p;
  154. {
  155.     struct session *sp;
  156.     struct ftpcli ftp;
  157.     struct sockaddr_in fsocket;
  158.     int resp,vsave;
  159.     char *buf,*bufsav,*cp,*un;
  160.     char prmt[40];
  161.     char l[17];
  162.     int control;
  163. #ifdef __GNUC__
  164.     static
  165. #endif
  166.     char *ftpcli_login __ARGS((struct ftpcli *, char *));
  167.     char *ftpcli_login();
  168.     FILE *fp1 = NULLFILE;
  169.     struct  cur_dirs dirs;
  170.   
  171.     /* Only from console - WG7J */
  172.     if(Curproc->input != Command->input)
  173.         return 0;
  174.   
  175.     /* Allocate a session control block */
  176.     if((sp = newsession(argv[1],FTP,0)) == NULLSESSION){
  177.         tputs(TooManySessions);
  178.         return 1;
  179.     }
  180.     memset((char *)&ftp,0,sizeof(ftp));
  181.     ftp.control = ftp.data = -1;
  182.     ftp.verbose = V_BYTE;           /* Default changed by IW0CNB */
  183.     ftp.type = Ftp_type;
  184.     ftp.logbsize = Ftp_logbsize;
  185. #ifdef LZW
  186.     ftp.uselzw = Ftpclzw;
  187. #endif
  188.   
  189.     sp->cb.ftp = &ftp;      /* Downward link */
  190.     ftp.session = sp;       /* Upward link */
  191.   
  192.     sp->curdirs = ftp.curdirs = &dirs;
  193.   
  194.     fsocket.sin_family = AF_INET;
  195.     fsocket.sin_port = IPPORT_FTP;
  196.   
  197.     tprintf("Resolving %s... ",sp->name);
  198.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  199.         tprintf(Badhost,sp->name);
  200.         keywait(NULLCHAR,1);
  201.         freesession(sp);
  202.         return 1;
  203.     }
  204.   
  205.     /* Open the control connection */
  206.     if((control = sp->s = ftp.control = socket(AF_INET,SOCK_STREAM,0)) == -1){
  207.         tputs("Can't create socket\n");
  208.         keywait(NULLCHAR,1);
  209.         freesession(sp);
  210.         return 1;
  211.     }
  212.   
  213.     sockmode(sp->s,SOCK_ASCII);
  214.     setflush(sp->s,-1);     /* Flush output only when we call getresp() */
  215.     tprintf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  216.     tprintf("Local Directory - %s\n",init_dirs(&dirs));
  217.     if(connect(control,(char *)&fsocket,sizeof(fsocket)) == -1)
  218.         goto quit;
  219.     tprintf("FTP session %u connected to %s\n",(unsigned)(sp-Sessions),
  220.     sp->name);
  221.   
  222.     /* Wait for greeting from server */
  223.     resp = getresp(&ftp,200);
  224.   
  225.     if(resp >= 400)
  226.         goto quit;
  227.     un = getenv("USER");
  228.     if(un != NULLCHAR)
  229.         sprintf(prmt,"Enter user name (%s): ",un);
  230.     else
  231.         sprintf(prmt,"Enter user name: ");
  232.   
  233.     /* Now process responses and commands */
  234.     buf = mallocw(LINELEN);
  235.   
  236.     if(argc > 2){
  237.         if((fp1 = fopen(argv[2],READ_TEXT)) == NULLFILE) goto quit;
  238.     }
  239.     while(resp != -1){
  240.         if(resp == 220){
  241.             /* Sign-on banner; prompt for and send USER command */
  242.             if((cp = ftpcli_login(&ftp, sp->name)) == NULLCHAR){
  243. #ifndef notdef
  244.                 getline(sp,prmt,buf,LINELEN);
  245. #else
  246.                 getline(sp,"Enter user name: ",buf,LINELEN);
  247. #endif
  248.                 /* Send the command only if the user response
  249.                  * was non-null
  250.                  */
  251.                 if(buf[0] != '\n'){
  252.                     usprintf(control,"USER %s",buf);
  253.                     resp = getresp(&ftp,200);
  254.                 } else {
  255.                     if(un != NULLCHAR){
  256.                         usprintf(control,"USER %s\n",un);
  257.                         resp = getresp(&ftp,200);
  258.                     } else {
  259.                         tputs("No username sent\n");
  260.                         resp = 200;     /* dummy */
  261.                     }
  262.                 }
  263.             } else {
  264.                 usprintf(control,"USER %s\n",cp);
  265.                 free(cp);
  266.                 resp = getresp(&ftp,200);
  267.             }
  268.         } else if(resp == 331){
  269.             if(ftp.password == NULLCHAR){
  270.                 /* turn off echo */
  271.                 sp->ttystate.echo = 0;
  272.                 getline(sp,"Password: ",buf,LINELEN);
  273.                 tputc('\n');
  274.                 /* Turn echo back on */
  275.                 sp->ttystate.echo = 1;
  276.                 /* Send the command only if the user response
  277.                  * was non-null
  278.                  */
  279.                 if(buf[0] != '\n'){
  280.                     usprintf(control,"PASS %s",buf);
  281.                     resp = getresp(&ftp,200);
  282.                 } else {
  283.                     tputs("Password must be provided.\nLogin failed.\n");
  284.                     resp = 200;     /* dummy */
  285.                 }
  286.             } else {
  287.                 usprintf(control,"PASS %s\n",ftp.password);
  288.                 resp = getresp(&ftp,200);
  289.                 free(ftp.password);
  290.                 ftp.password = NULLCHAR;        /* clean up */
  291.             }
  292.         } else if(resp == 230) {    /* Successful login */
  293.             /* Find out what type of system we're talking to */
  294.             tprintf("ftp> syst\n");
  295.             usprintf(control,"SYST\n");
  296.             resp = getresp(&ftp,200);
  297.         } else if(resp == 215) {    /* Response to SYST command */
  298.             cp = strchr(ftp.line,' ');
  299.             if(cp != NULLCHAR && strnicmp(cp+1,System,strlen(System)) == 0){
  300.                 ftp.type = IMAGE_TYPE;
  301.                 tputs("Defaulting to binary mode transfers\n");
  302.             }
  303.             resp = 200; /* dummy */
  304.         } else if(resp == 399) {        /* Encrypted password login */
  305.             if(ftp.password == NULLCHAR){
  306.                 getline(sp,"Key ? --> ",buf,LINELEN);
  307.                 /* Send the command only if the user response
  308.                  * was non-null
  309.                  */
  310.                 if(buf[0] != '\n'){
  311.                     cp = strchr(ftp.line,':');
  312.                     cp += 2;
  313.                       /*
  314.                     epass(htol(cp),buf,l);
  315.                       */
  316.                     l[16] = '\0';
  317.                     free(ftp.line);
  318.                     ftp.line = NULLCHAR;
  319.                     usprintf(control,"PASS %s\n",l);
  320.                     resp = getresp(&ftp,200);
  321.                 } else {
  322.                     tputs("Password must be provided.\nLogin failed.\n");
  323.                     resp = 200;     /* dummy */
  324.                 }
  325.             } else {
  326.                 cp = strchr(ftp.line,':');
  327.                 cp += 2;
  328.                 /*
  329.                 epass(htol(cp),ftp.password,l);
  330.                 */
  331.                 l[16] = '\0';
  332.                 free(ftp.line);
  333.                 ftp.line = NULLCHAR;
  334.                 usprintf(control,"PASS %s\n",l);
  335.                 resp = getresp(&ftp,200);
  336.                 free(ftp.password);
  337.                 ftp.password = NULLCHAR;        /* clean up */
  338.             }
  339.         } else {
  340.             /* Test the control channel first */
  341.             if(sockstate(control) == NULLCHAR)
  342.                 break;
  343.             if(argc > 2){
  344.                 if(fgets(buf,LINELEN,fp1) == NULLCHAR)
  345.                     goto quit;
  346.             } else
  347.                 getline(sp,"ftp> ",buf,LINELEN);
  348.   
  349.             /* Copy because cmdparse modifies the original */
  350.             bufsav = strdup(buf);
  351.             if((resp = cmdparse(Ftpcmds,buf,&ftp)) != -1){
  352.                 /* Valid command, free buffer and get another */
  353.                 free(bufsav);
  354.             } else {
  355.                 /* Not a local cmd, send to remote server */
  356.                 usputs(control,bufsav);
  357.                 free(bufsav);
  358.   
  359.                 /* Enable display of server response */
  360.                 vsave = ftp.verbose;
  361.                 ftp.verbose = V_NORMAL;
  362.                 resp = getresp(&ftp,200);
  363.                 ftp.verbose = vsave;
  364.             }
  365.         }
  366.     }
  367.     free(buf);
  368.     quit:   cp = sockerr(control);
  369.     tprintf("FTP session %u closed: %s\n",(unsigned)(sp - Sessions),
  370.     cp != NULLCHAR ? cp : "EOF");
  371.   
  372.     if(ftp.fp != NULLFILE && ftp.fp != stdout)
  373.         fclose(ftp.fp);
  374.     if(ftp.data != -1)
  375.         close_s(ftp.data);
  376.     if(ftp.control != -1)
  377.         close_s(ftp.control);
  378.     if(argc < 3)
  379.         keywait(NULLCHAR,1);
  380.     else
  381.         fclose(fp1);
  382.     if(ftp.session != NULLSESSION)
  383.         freesession(ftp.session);
  384.     free_dirs(&dirs);
  385.     return 0;
  386. }
  387.   
  388. #ifdef LZW
  389. int
  390. doftpslzw(argc,argv,p)
  391. int argc;
  392. char *argv[];
  393. void *p;
  394. {
  395.     return setbool(&Ftpslzw,"FTP server lzw",argc,argv);
  396. }
  397.   
  398. int
  399. doftpclzw(argc,argv,p)
  400. int argc;
  401. char *argv[];
  402. void *p;
  403. {
  404.     return setbool(&Ftpclzw,"FTP client lzw",argc,argv);
  405. }
  406.   
  407. static int
  408. dolocftpclzw(argc,argv,p)
  409. int argc;
  410. char *argv[];
  411. void *p;
  412. {
  413.     register struct ftpcli *ftp;
  414.     int result;
  415.  
  416. /* We'd like to keep ftp.uselzw in sync with Ftpclzw (just so we can turn
  417.    lzw on and off within an ftp session ... is it really worth it?).
  418.    We need a separate proc since the ftpclzw cmd exists. --N5KNX */
  419.  
  420.     result = setbool(&Ftpclzw,"FTP client lzw",argc,argv);
  421.     if((ftp = (struct ftpcli *)p) != NULLFTP &&
  422.        (result == 0)) ftp->uselzw = Ftpclzw;  /* keep in sync with changes */
  423.     return result;
  424. }
  425. #endif
  426.   
  427. /* Control verbosity level */
  428. static int
  429. doverbose(argc,argv,p)
  430. int argc;
  431. char *argv[];
  432. void *p;
  433. {
  434.     register struct ftpcli *ftp;
  435.   
  436.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  437.         return -1;
  438.     return setshort(&ftp->verbose,"Verbose",argc,argv);
  439. }
  440. /* Enable/disable command batching */
  441. static int
  442. dobatch(argc,argv,p)
  443. int argc;
  444. char *argv[];
  445. void *p;
  446. {
  447.     register struct ftpcli *ftp;
  448.   
  449.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  450.         return -1;
  451.     return setbool(&ftp->batch,"Command batching",argc,argv);
  452. }
  453. /* Set verbosity to high (convenience command) */
  454. static int
  455. dohash(argc,argv,p)
  456. int argc;
  457. char *argv[];
  458. void *p;
  459. {
  460.     register struct ftpcli *ftp;
  461.   
  462.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  463.         return -1;
  464.     tputs("Hash Printing ");
  465.     if (ftp->verbose==V_HASH){
  466.         ftp->verbose = V_HASH+1;
  467.         tputs("Off\n");
  468.     } else {
  469.         tputs("On\n");
  470.         ftp->verbose = V_HASH;
  471.     }
  472.     return 0;
  473. }
  474.   
  475. /* Close session */
  476. static int
  477. doquit(argc,argv,p)
  478. int argc;
  479. char *argv[];
  480. void *p;
  481. {
  482.     register struct ftpcli *ftp;
  483.   
  484.     ftp = (struct ftpcli *)p;
  485.     if(ftp == NULLFTP)
  486.         return -1;
  487.     usputs(ftp->control,"QUIT\n");
  488.   
  489.     getresp(ftp,200);       /* Get the closing message */
  490.     getresp(ftp,200);       /* Wait for the server to close */
  491.     return -1;
  492. }
  493.   
  494. /* Translate 'cd' to 'cwd' for convenience */
  495. static int
  496. doftpcd(argc,argv,p)
  497. int argc;
  498. char *argv[];
  499. void *p;
  500. {
  501.     register struct ftpcli *ftp;
  502.   
  503.     ftp = (struct ftpcli *)p;
  504.     if(ftp == NULLFTP)
  505.         return -1;
  506.     usprintf(ftp->control,"CWD %s\n",argv[1]);
  507.     return getresp(ftp,200);
  508. }
  509. /* Translate 'mkdir' to 'xmkd' for convenience */
  510. static int
  511. domkdir(argc,argv,p)
  512. int argc;
  513. char *argv[];
  514. void *p;
  515. {
  516.     register struct ftpcli *ftp;
  517.   
  518.     ftp = (struct ftpcli *)p;
  519.     if(ftp == NULLFTP)
  520.         return -1;
  521.     usprintf(ftp->control,"XMKD %s\n",argv[1]);
  522.     return getresp(ftp,200);
  523. }
  524. /* Translate 'rmdir' to 'xrmd' for convenience */
  525. static int
  526. dormdir(argc,argv,p)
  527. int argc;
  528. char *argv[];
  529. void *p;
  530. {
  531.     register struct ftpcli *ftp;
  532.   
  533.     ftp = (struct ftpcli *)p;
  534.     if(ftp == NULLFTP)
  535.         return -1;
  536.     usprintf(ftp->control,"XRMD %s\n",argv[1]);
  537.     return getresp(ftp,200);
  538. }
  539. static int
  540. dobinary(argc,argv,p)
  541. int argc;
  542. char *argv[];
  543. void *p;
  544. {
  545.     char *args[2];
  546.   
  547.     args[1] = "I";
  548.     return dotype(2,args,p);
  549. }
  550. static int
  551. doascii(argc,argv,p)
  552. int argc;
  553. char *argv[];
  554. void *p;
  555. {
  556.     char *args[2];
  557.   
  558.     args[1] = "A";
  559.     return dotype(2,args,p);
  560. }
  561.   
  562. /* Handle "type" command from user */
  563. static int
  564. dotype(argc,argv,p)
  565. int argc;
  566. char *argv[];
  567. void *p;
  568. {
  569.     register struct ftpcli *ftp;
  570.   
  571.     ftp = (struct ftpcli *)p;
  572.     if(ftp == NULLFTP)
  573.         return -1;
  574.     if(argc < 2){
  575.         switch(ftp->type){
  576.             case IMAGE_TYPE:
  577.                 tputs("Image\n");
  578.                 break;
  579.             case ASCII_TYPE:
  580.                 tputs("Ascii\n");
  581.                 break;
  582.             case LOGICAL_TYPE:
  583.                 tprintf("Logical bytesize %u\n",ftp->logbsize);
  584.                 break;
  585.         }
  586.         return 0;
  587.     }
  588.     switch(*argv[1]){
  589.         case 'i':
  590.         case 'I':
  591.         case 'b':
  592.         case 'B':
  593.             ftp->type = IMAGE_TYPE;
  594.             break;
  595.         case 'a':
  596.         case 'A':
  597.             ftp->type = ASCII_TYPE;
  598.             break;
  599.         case 'L':
  600.         case 'l':
  601.             ftp->type = LOGICAL_TYPE;
  602.             ftp->logbsize = atoi(argv[2]);
  603.             break;
  604.         default:
  605.             tprintf("Invalid type %s\n",argv[1]);
  606.             return 1;
  607.     }
  608.     return 0;
  609. }
  610.   
  611. /* Handle "ftype" command */
  612. int
  613. doftype(argc,argv,p)
  614. int argc;
  615. char *argv[];
  616. void *p;
  617. {
  618.     if(argc < 2){
  619.         tputs("Ftp initial TYPE is ");
  620.         switch(Ftp_type){
  621.             case IMAGE_TYPE:
  622.                 tputs("Image\n");
  623.                 break;
  624.             case ASCII_TYPE:
  625.                 tputs("Ascii\n");
  626.                 break;
  627.             case LOGICAL_TYPE:
  628.                 tprintf("Logical bytesize %u\n",Ftp_logbsize);
  629.                 break;
  630.         }
  631.         return 0;
  632.     }
  633.     switch(*argv[1]){
  634.         case 'i':
  635.         case 'I':
  636.         case 'b':
  637.         case 'B':
  638.             Ftp_type = IMAGE_TYPE;
  639.             break;
  640.         case 'a':
  641.         case 'A':
  642.             Ftp_type = ASCII_TYPE;
  643.             break;
  644.         case 'L':
  645.         case 'l':
  646.             Ftp_type = LOGICAL_TYPE;
  647.             Ftp_logbsize = atoi(argv[2]);
  648.             break;
  649.         default:
  650.             tprintf("Invalid type %s\n",argv[1]);
  651.             return 1;
  652.     }
  653.     return 0;
  654. }
  655.   
  656. /* View added to jnos1.08 by Simon G1FHY _ mod by Paul@wolf.demon.co.uk */
  657. /* Start view transfer. Syntax: view <remote name> */
  658. static int
  659. doview(argc,argv,p)
  660. int argc;
  661. char *argv[];
  662. void *p;
  663. {
  664.     char *remotename;
  665.     register struct ftpcli  *ftp;
  666.   
  667.     ftp = (struct ftpcli *)p;
  668.     if(ftp == NULLFTP){
  669.         tputs(Notsess);
  670.         return 1;
  671.     }
  672.     remotename = argv[1];
  673.   
  674.     getsub(ftp,"RETR",remotename,NULLCHAR);
  675.     return 0;
  676. }
  677. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  678. static int
  679. doget(argc,argv,p)
  680. int argc;
  681. char *argv[];
  682. void *p;
  683. {
  684.     char *remotename,*localname;
  685.     register struct ftpcli *ftp;
  686.   
  687.     ftp = (struct ftpcli *)p;
  688.     if(ftp == NULLFTP){
  689.         tputs(Notsess);
  690.         return 1;
  691.     }
  692.     remotename = argv[1];
  693.     if(argc < 3)
  694.         localname = remotename;
  695.     else
  696.         localname = argv[2];
  697.   
  698.     getsub(ftp,"RETR",remotename,localname);
  699.     return 0;
  700. }
  701. /* Get a collection of files */
  702. static int
  703. domget(argc,argv,p)
  704. int argc;
  705. char *argv[];
  706. void *p;
  707. {
  708.     register struct ftpcli *ftp;
  709.     FILE *files, *filel;
  710.     char tmpname[80];
  711.     char *buf, *local;
  712.     int i, inlist;
  713.     long r;
  714. #ifdef MSDOS
  715.     char *c;
  716. #endif
  717.   
  718.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  719.         tputs(Notsess);
  720.         return 1;
  721.     }
  722.     tmpnam(tmpname);
  723.     buf = mallocw(DIRBUF);
  724.     ftp->state = RECEIVING_STATE;
  725.     for(i=1;i<argc;i++){
  726.         if(argv[i][0] == '@'){
  727.             inlist = 1;
  728.             if((filel = fopen(make_fname(ftp->curdirs->dir,&argv[i][1]), "r")) == NULLFILE){
  729.                 tprintf("Can't open listfile: %s\n", &argv[i][1]);
  730.                 continue;
  731.             }
  732.             if((files = fopen(tmpname, "w")) == NULLFILE){
  733.                 tprintf("Can't open tempfile: %s\n", tmpname);
  734.                 continue;
  735.             }
  736.             while(fgets(buf,DIRBUF,filel) != NULLCHAR){
  737.                 fputs(buf,files);
  738.             }
  739.             fclose(files);
  740.             fclose(filel);
  741.             if((files = fopen(tmpname, "r")) == NULLFILE){
  742.                 tprintf("Can't open tempfile: %s\n", tmpname);
  743.                 continue;
  744.             }
  745.         } else {
  746.             inlist = 0;
  747.             r = getsub(ftp,"NLST",argv[i],tmpname);
  748.             if(ftp->abort)
  749.                 break;  /* Aborted */
  750.             if(r == -1 || (files = fopen(tmpname,"r")) == NULLFILE){
  751.                 tprintf("Can't NLST %s\n",argv[i]);
  752.                 unlink(tmpname);
  753.                 continue;
  754.             }
  755.         }
  756.         /* The tmp file now contains a list of the remote files, so
  757.          * go get 'em. Break out if the user signals an abort.
  758.          */
  759.         while(fgets(buf,DIRBUF,files) != NULLCHAR){
  760.             rip(buf);
  761.             local = strdup(buf);
  762. #ifdef  MSDOS
  763.             if(inlist){
  764.                 strrev(local);
  765.                 strtok(local, "\\/[]<>,?#~()&%");
  766.                 strrev(local);
  767.             }
  768.             if((c = strstr(local, ".")) != NULLCHAR) {
  769.                 c++;
  770.                 c = strtok(c, ".");     /* remove 2nd period if any*/
  771.             }
  772. #endif
  773.             getsub(ftp,"RETR",buf,local);
  774.             free(local);
  775.             if(ftp->abort){
  776.                 /* User abort */
  777.                 ftp->abort = 0;
  778.                 fclose(files);
  779.                 unlink(tmpname);
  780.                 free(buf);
  781.                 ftp->state = COMMAND_STATE;
  782.                 return 1;
  783.             }
  784.         }
  785.         fclose(files);
  786.         unlink(tmpname);
  787.     }
  788.     free(buf);
  789.     ftp->state = COMMAND_STATE;
  790.     ftp->abort = 0;
  791.     return 0;
  792. }
  793. /* Resume interrupted file transfer. Syntax: resume <remote name> [<local name>] */
  794. static int
  795. doresume(argc,argv,p)
  796. int argc;
  797. char *argv[];
  798. void *p;
  799. {
  800.     char *remotename,*localname;
  801.     register struct ftpcli *ftp;
  802.   
  803.     ftp = (struct ftpcli *)p;
  804.     if(ftp == NULLFTP){
  805.         tputs(Notsess);
  806.         return 1;
  807.     }
  808.     remotename = argv[1];
  809.     if(argc < 3)
  810.         localname = remotename;
  811.     else
  812.         localname = argv[2];
  813.   
  814.     getsub(ftp,"RSME",remotename,localname);
  815.     return 0;
  816. }
  817. /* List remote directory. Syntax: dir <remote files> [<local name>] */
  818. static int
  819. dolist(argc,argv,p)
  820. int argc;
  821. char *argv[];
  822. void *p;
  823. {
  824.     char *remotename,*localname;
  825.     register struct ftpcli *ftp;
  826.   
  827.     ftp = (struct ftpcli *)p;
  828.     if(ftp == NULLFTP){
  829.         tputs(Notsess);
  830.         return 1;
  831.     }
  832.     remotename = argv[1];
  833.     if(argc > 2)
  834.         localname = argv[2];
  835.     else
  836.         localname = NULLCHAR;
  837.   
  838.     getsub(ftp,"LIST",remotename,localname);
  839.     return 0;
  840. }
  841. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  842. static int
  843. dols(argc,argv,p)
  844. int argc;
  845. char *argv[];
  846. void *p;
  847. {
  848.     char *remotename,*localname;
  849.     register struct ftpcli *ftp;
  850.   
  851.     ftp = (struct ftpcli *)p;
  852.     if(ftp == NULLFTP){
  853.         tputs(Notsess);
  854.         return 1;
  855.     }
  856.     remotename = argv[1];
  857.     if(argc > 2)
  858.         localname = argv[2];
  859.     else
  860.         localname = NULLCHAR;
  861.   
  862.     getsub(ftp,"NLST",remotename,localname);
  863.     return 0;
  864. }
  865. /* Common code to LIST/NLST/RETR/RSME and mget
  866.  * Returns number of bytes received if successful
  867.  * Returns -1 on error
  868.  */
  869. static long
  870. getsub(ftp,command,remotename,localname)
  871. register struct ftpcli *ftp;
  872. char *command,*remotename,*localname;
  873. {
  874.     long total;
  875.     FILE *fp;
  876.     int cnt,resp,i,control,savmode;
  877.     char *mode;
  878.     struct sockaddr_in lsocket;
  879.     struct sockaddr_in lcsocket;
  880.     int32 startclk,rate;
  881.     int vsave;
  882.     int typewait = 0, portwait = 0;
  883.     int prevstate;
  884.     long starting;
  885. #ifdef  LZW
  886.     int lzwmode, lzwbits;
  887.     int rcode;
  888.     extern int16 Lzwbits;
  889.     extern int Lzwmode;
  890. #endif
  891.   
  892.     if(ftp == NULLFTP)
  893.         return -1;
  894.     control = ftp->control;
  895.     savmode = ftp->type;
  896.   
  897.     switch(ftp->type){
  898.         case IMAGE_TYPE:
  899.         case LOGICAL_TYPE:
  900.             if(strcmp(command,"RSME") == 0)
  901.                 mode = APPEND_BINARY;
  902.             else
  903.                 mode = WRITE_BINARY;
  904.             break;
  905.         case ASCII_TYPE:
  906.             if(strcmp(command,"RSME") == 0)
  907.                 mode = APPEND_TEXT;
  908.             else
  909.                 mode = WRITE_TEXT;
  910.             break;
  911.     }
  912.     /* Open the file */
  913.     if(localname == NULLCHAR){
  914.         fp = NULLFILE;
  915.     } else if((fp = fopen(make_fname(ftp->curdirs->dir,localname),mode)) == NULLFILE){
  916.         tprintf("Can't write %s: %s\n",localname,sys_errlist[errno]);
  917.         return -1;
  918.     }
  919.     /* Open the data connection */
  920.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  921.     listen(ftp->data,0);    /* Accept only one connection */
  922.     prevstate = ftp->state;
  923.     ftp->state = RECEIVING_STATE;
  924.   
  925.     /* Send TYPE message, if necessary */
  926.     if(strcmp(command,"LIST") == 0 || strcmp(command,"NLST") == 0){
  927.         /* Directory listings are always in ASCII */
  928.         ftp->type = ASCII_TYPE;
  929.     }
  930.     if(ftp->typesent != ftp->type){
  931.         switch(ftp->type){
  932.             case ASCII_TYPE:
  933.                 usputs(control,"TYPE A\n");
  934.                 break;
  935.             case IMAGE_TYPE:
  936.                 usputs(control,"TYPE I\n");
  937.                 break;
  938.             case LOGICAL_TYPE:
  939.                 usprintf(control,"TYPE L %d\n",ftp->logbsize);
  940.                 break;
  941.         }
  942.         ftp->typesent = ftp->type;
  943.         if(!ftp->batch){
  944.             resp = getresp(ftp,200);
  945.             if(resp == -1 || resp > 299)
  946.                 goto failure;
  947.         } else
  948.             typewait = 1;
  949.     }
  950.     /* Send the PORT message. Use the IP address
  951.      * on the local end of our control connection.
  952.      */
  953.     i = SOCKSIZE;
  954.     getsockname(ftp->data,(char *)&lsocket,&i); /* Get port number */
  955.     i = SOCKSIZE;
  956.     getsockname(ftp->control,(char *)&lcsocket,&i);
  957.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  958.     sendport(control,&lsocket);
  959.     if(!ftp->batch){
  960.         /* Get response to PORT command */
  961.         resp = getresp(ftp,200);
  962.         if(resp == -1 || resp > 299)
  963.             goto failure;
  964.     }
  965.     else portwait=1;
  966. #ifdef LZW
  967.     if(ftp->uselzw && ftp->type == ASCII_TYPE) {
  968.         /* Send XLZW string */
  969.         usprintf(control, "XLZW %d %d\n", Lzwbits, Lzwmode);
  970.         if(ftp->batch){
  971.             /* Get response to TYPE command, if sent */
  972.             if(typewait){
  973.                 resp = getresp(ftp,200);
  974.                 if(resp == -1 || resp > 299){
  975.                     goto failure;
  976.                 }
  977.                 typewait=0;
  978.             }
  979.             /* Get response to PORT command, if needed */
  980.             if(portwait){
  981.                 resp = getresp(ftp,200);
  982.                 if(resp == -1 || resp > 299){
  983.                     goto failure;
  984.                 }
  985.                 portwait=0;
  986.             }
  987.         }
  988.         resp = getresp(ftp, 200);
  989.         if (resp == -1 || resp > 299)
  990.             ftp->uselzw=0;    /* Command not supported. */
  991.         else {
  992.             /* strip off any garbage. */
  993.             rip(ftp->line);
  994.             rcode = lzwmode = lzwbits = 0;
  995.             /* Get bits from the XLZW response. */
  996.             sscanf(ftp->line, "%d %d %d", &rcode, &lzwbits, &lzwmode);
  997.             if ((rcode >= 200) && (rcode < 300)) {
  998.                 if (lzwmode != Lzwmode || lzwbits != Lzwbits) {
  999.                     lzwmode = LZWCOMPACT;
  1000.                     lzwbits = LZWBITS;
  1001.                 }
  1002.             }
  1003.             /* Turn on the LZW stuff. */
  1004.             lzwinit(ftp->data,lzwbits,lzwmode);
  1005.         }
  1006.     }
  1007. #endif
  1008.     /* Generate the command to start the transfer */
  1009.     if(remotename != NULLCHAR)
  1010.         usprintf(control,"%s %s\n",command,remotename);
  1011.     else
  1012.         usprintf(control,"%s\n",command);
  1013.   
  1014.     if(ftp->batch){
  1015.         /* Get response to TYPE command, if sent */
  1016.         if(typewait){
  1017.             resp = getresp(ftp,200);
  1018.             if(resp == -1 || resp > 299)
  1019.                 goto failure;
  1020.         }
  1021.         /* Get response to PORT command, if needed */
  1022.         if(portwait){
  1023.             resp = getresp(ftp,200);
  1024.             if(resp == -1 || resp > 299)
  1025.                 goto failure;
  1026.         }
  1027.     }
  1028.     /* Get the intermediate "150" response */
  1029.     resp = getresp(ftp,100);
  1030.     if(resp == -1 || resp >= 400)
  1031.         goto failure;
  1032.   
  1033.     /* Wait for the server to open the data connection */
  1034.     cnt = 0;
  1035.     accept(ftp->data,NULLCHAR,(int *)NULL);
  1036.     startclk = msclock();
  1037.   
  1038.     /* If output is to the screen, temporarily disable hash marking */
  1039.     vsave = ftp->verbose;
  1040.     if(vsave >= V_HASH && fp == NULLFILE)
  1041.         ftp->verbose = V_NORMAL;
  1042.   
  1043.     if(strcmp(command,"RSME") == 0){
  1044.         if((starting = getsize(fp)) == -1)
  1045.             starting = 0L;
  1046.         usprintf(control,"%ld %lu\n",starting,checksum(fp,starting));
  1047.         usflush(control);
  1048.         fseek(fp,starting,SEEK_SET);
  1049.     }
  1050.     total = recvfile(fp,ftp->data,ftp->type,(ftp->verbose >= V_HASH) ? ftp->verbose : 0);
  1051.     /* Immediately close the data connection; some servers (e.g., TOPS-10)
  1052.      * wait for the data connection to close completely before returning
  1053.      * the completion message on the control channel
  1054.      */
  1055.     close_s(ftp->data);
  1056.     ftp->data = -1;
  1057.   
  1058.     if(fp != NULLFILE && fp != stdout)
  1059.         fclose(fp);
  1060.     if(remotename == NULLCHAR)
  1061.         remotename = "";
  1062.     if(total == -1){
  1063.         tprintf("%s %s: Error/abort during data transfer\n",command,remotename);
  1064.     } else if(ftp->verbose >= V_SHORT){
  1065.         startclk = msclock() - startclk;
  1066.         rate = 0;
  1067.         if(startclk != 0){      /* Avoid divide-by-zero */
  1068.             if(total < 4294967L){
  1069.                 rate = (total*1000)/startclk;
  1070.             } else {        /* Avoid overflow */
  1071.                 rate = total/(startclk/1000);
  1072.             }
  1073.         }
  1074.         tprintf("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
  1075.         command,remotename, total,startclk/1000,rate);
  1076.     }
  1077.     /* Get the "Sent" message */
  1078.     getresp(ftp,200);
  1079.   
  1080.     ftp->state = prevstate;
  1081.     ftp->verbose = vsave;
  1082.     ftp->type = savmode;
  1083.     return total;
  1084.   
  1085.     failure:
  1086.     /* Error, quit */
  1087.     if(fp != NULLFILE && fp != stdout)
  1088.         fclose(fp);
  1089.     close_s(ftp->data);
  1090.     ftp->data = -1;
  1091.     ftp->state = prevstate;
  1092.     ftp->type = savmode;
  1093.     return -1;
  1094. }
  1095. /* Send a file. Syntax: put <local name> [<remote name>] */
  1096. static int
  1097. doput(argc,argv,p)
  1098. int argc;
  1099. char *argv[];
  1100. void *p;
  1101. {
  1102.     register struct ftpcli *ftp;
  1103.     char *remotename,*localname;
  1104.   
  1105.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1106.         tputs(Notsess);
  1107.         return 1;
  1108.     }
  1109.     localname = argv[1];
  1110.     if(argc < 3)
  1111.         remotename = localname;
  1112.     else
  1113.         remotename = argv[2];
  1114.   
  1115.     putsub(ftp,remotename,localname,0);
  1116.     return 0;
  1117. }
  1118. /* Put a collection of files */
  1119. static int
  1120. domput(argc,argv,p)
  1121. int argc;
  1122. char *argv[];
  1123. void *p;
  1124. {
  1125.     register struct ftpcli *ftp;
  1126.     FILE *files;
  1127.     int i,j;
  1128.     char tmpname[80];
  1129.     char *buf,*file;
  1130.   
  1131.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1132.         tputs(Notsess);
  1133.         return 1;
  1134.     }
  1135.     tmpnam(tmpname);
  1136.     if((files = fopen(tmpname,"w+")) == NULLFILE){
  1137.         tputs("Can't list local files\n");
  1138.         unlink(tmpname);
  1139.         return 1;
  1140.     }
  1141.   
  1142.     for(i=1;i<argc;i++) {
  1143.     /* Use the path in the ftp client struct, since user may have done
  1144.      * a lcd command to change dir !
  1145.      */
  1146.         file = pathname(ftp->curdirs->dir,argv[i]);
  1147.     /* Shift everything back one byte, pathname returns with a leading '/'! */
  1148.     /*
  1149.     for(j=1;j<=strlen(file);j++)
  1150.         file[j-1] = file[j];
  1151.     */
  1152.         getdir(file,0,files);
  1153.         free(file);
  1154.     }
  1155.     rewind(files);
  1156.     buf = mallocw(DIRBUF);
  1157.     ftp->state = SENDING_STATE;
  1158.     while(fgets(buf,DIRBUF,files) != NULLCHAR){
  1159.         rip(buf);
  1160.         putsub(ftp,buf,buf,0);
  1161.         if(ftp->abort)
  1162.             break;          /* User abort */
  1163.     }
  1164.     fclose(files);
  1165.     unlink(tmpname);
  1166.     free(buf);
  1167.     ftp->state = COMMAND_STATE;
  1168.     ftp->abort = 0;
  1169.     return 0;
  1170. }
  1171. /* Put a file, appending data to it - iw0cnb */
  1172. static int
  1173. dorput(argc,argv,p)
  1174. int argc;
  1175. char *argv[];
  1176. void *p;
  1177. {
  1178.     register struct ftpcli *ftp;
  1179.     char *remotename,*localname;
  1180.   
  1181.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1182.         tputs(Notsess);
  1183.         return 1;
  1184.     }
  1185.     localname = argv[1];
  1186.     if(argc < 3)
  1187.         remotename = localname;
  1188.     else
  1189.         remotename = argv[2];
  1190.   
  1191.     putsub(ftp,remotename,localname,1);
  1192.     return 0;
  1193. }
  1194. /* Common code to put, mput, rput.
  1195.  * Returns number of bytes sent if successful
  1196.  * Returns -1 on error
  1197.  */
  1198. static long
  1199. putsub(ftp,remotename,localname,putr)
  1200. register struct ftpcli *ftp;
  1201. char *remotename,*localname;
  1202. int putr;       /* Flag: 0 if standard put, 1 if put with resume */
  1203. {
  1204.     char *mode;
  1205.     int i,resp,control;
  1206.     long total;
  1207.     FILE *fp;
  1208.     struct sockaddr_in lsocket,lcsocket;
  1209.     int32 startclk,rate;
  1210.     int typewait = 0, portwait = 0;
  1211.     int prevstate;
  1212.     char *line;
  1213.     long starting;
  1214.     unsigned long check, local_check;
  1215. #ifdef  LZW
  1216.     int lzwmode, lzwbits;
  1217.     int rcode;
  1218.     extern int16 Lzwbits;
  1219.     extern int Lzwmode;
  1220. #endif
  1221.   
  1222.     control = ftp->control;
  1223.     if(ftp->type == IMAGE_TYPE)
  1224.         mode = READ_BINARY;
  1225.     else
  1226.         mode = READ_TEXT;
  1227.   
  1228.     /* Open the file */
  1229.     if((fp = fopen(make_fname(ftp->curdirs->dir,localname),mode)) == NULLFILE){
  1230.         tprintf("Can't read %s: %s\n",localname,sys_errlist[errno]);
  1231.         return -1;
  1232.     }
  1233.     if(ftp->type == ASCII_TYPE && isbinary(fp)){
  1234.         tprintf("Warning: type is ASCII and %s appears to be binary\n",localname);
  1235.     }
  1236.     /* Open the data connection */
  1237.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  1238.     listen(ftp->data,0);
  1239.     prevstate = ftp->state;
  1240.     ftp->state = SENDING_STATE;
  1241.   
  1242.     /* Send TYPE message, if necessary */
  1243.     if(ftp->typesent != ftp->type){
  1244.         switch(ftp->type){
  1245.             case ASCII_TYPE:
  1246.                 usputs(control,"TYPE A\n");
  1247.                 break;
  1248.             case IMAGE_TYPE:
  1249.                 usputs(control,"TYPE I\n");
  1250.                 break;
  1251.             case LOGICAL_TYPE:
  1252.                 usprintf(control,"TYPE L %d\n",ftp->logbsize);
  1253.                 break;
  1254.         }
  1255.         ftp->typesent = ftp->type;
  1256.   
  1257.         /* Get response to TYPE command */
  1258.         if(!ftp->batch){
  1259.             resp = getresp(ftp,200);
  1260.             if(resp == -1 || resp > 299){
  1261.                 goto failure;
  1262.             }
  1263.         } else
  1264.             typewait = 1;
  1265.     }
  1266.     /* Send the PORT message. Use the IP address
  1267.      * on the local end of our control connection.
  1268.      */
  1269.     i = SOCKSIZE;
  1270.     getsockname(ftp->data,(char *)&lsocket,&i);
  1271.     i = SOCKSIZE;
  1272.     getsockname(ftp->control,(char *)&lcsocket,&i);
  1273.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  1274.     sendport(control,&lsocket);
  1275.     if(!ftp->batch){
  1276.         /* Get response to PORT command */
  1277.         resp = getresp(ftp,200);
  1278.         if(resp == -1 || resp > 299){
  1279.             goto failure;
  1280.         }
  1281.     }
  1282.     else portwait=1;
  1283. #ifdef LZW
  1284.     if(ftp->uselzw && ftp->type == ASCII_TYPE) {
  1285.         /* Send XLZW string */
  1286.         usprintf(control, "XLZW %d %d\n", Lzwbits, Lzwmode);
  1287.         if(ftp->batch){
  1288.             /* Get response to TYPE command, if sent */
  1289.             if(typewait){
  1290.                 resp = getresp(ftp,200);
  1291.                 if(resp == -1 || resp > 299){
  1292.                     goto failure;
  1293.                 }
  1294.                 typewait=0;
  1295.             }
  1296.             /* Get response to PORT command, if needed */
  1297.             if(portwait){
  1298.                 resp = getresp(ftp,200);
  1299.                 if(resp == -1 || resp > 299){
  1300.                     goto failure;
  1301.                 }
  1302.                 portwait=0;
  1303.             }
  1304.         }
  1305.         resp = getresp(ftp, 200);
  1306.         if (resp == -1 || resp > 299)
  1307.             ftp->uselzw=0;    /* Command not supported. */
  1308.         else {
  1309.             /* strip off any garbage. */
  1310.             rip(ftp->line);
  1311.             rcode = lzwmode = lzwbits = 0;
  1312.             /* Get bits from the XLZW response. */
  1313.             sscanf(ftp->line, "%d %d %d", &rcode, &lzwbits, &lzwmode);
  1314.             if ((rcode >= 200) && (rcode < 300)) {
  1315.                 if (lzwmode != Lzwmode || lzwbits != Lzwbits) {
  1316.                     lzwmode = LZWCOMPACT;
  1317.                     lzwbits = LZWBITS;
  1318.                 }
  1319.             }
  1320.             /* Turn on the LZW stuff. */
  1321.             lzwinit(ftp->data,lzwbits,lzwmode);
  1322.         }
  1323.     }
  1324. #endif
  1325.     /* Generate the command to start the transfer */
  1326.     if(putr == 1)
  1327.         usprintf(control,"RPUT %s\n",remotename);
  1328.     else
  1329.         usprintf(control,"STOR %s\n",remotename);
  1330.   
  1331.     if(ftp->batch){
  1332.         /* Get response to TYPE command, if sent */
  1333.         if(typewait){
  1334.             resp = getresp(ftp,200);
  1335.             if(resp == -1 || resp > 299){
  1336.                 goto failure;
  1337.             }
  1338.         }
  1339.         /* Get response to PORT command, if needed */
  1340.         if(portwait){
  1341.             resp = getresp(ftp,200);
  1342.             if(resp == -1 || resp > 299){
  1343.                 goto failure;
  1344.             }
  1345.         }
  1346.     }
  1347.     /* Get the intermediate "150" response */
  1348.     resp = getresp(ftp,100);
  1349.     if(resp == -1 || resp >= 400){
  1350.         goto failure;
  1351.     }
  1352.   
  1353.     /* Wait for the data connection to open. Otherwise the first
  1354.      * block of data would go out with the SYN, and this may confuse
  1355.      * some other TCPs
  1356.      */
  1357.     accept(ftp->data,NULLCHAR,(int *)NULL);
  1358.   
  1359.     startclk = msclock();
  1360.     if(putr == 1){          /* Wait for file offset and checksum */
  1361.         line=mallocw(40);
  1362.         recvline(control,line,40);
  1363.         starting=atol(line);
  1364.         check = (unsigned long)atol(strchr(line,' '));
  1365.         free(line);
  1366.         local_check = checksum(fp,starting);
  1367.         if(ftp->verbose >= V_HASH)
  1368.             tprintf("Remote checksum: %lu Local checksum: %lu Offset: %ld\n",check,local_check,starting);
  1369.         check -= local_check;
  1370.         if(check != 0){
  1371.             tprintf("Can't send %s: files are different\n",localname);
  1372.             shutdown(ftp->data,1);
  1373.             getresp(ftp,200);
  1374.             goto failure;
  1375.         }
  1376.     }
  1377.   
  1378.     total = sendfile(fp,ftp->data,ftp->type,(ftp->verbose >= V_HASH) ? ftp->verbose : 0,NULL);
  1379.     close_s(ftp->data);
  1380.     ftp->data = -1;
  1381.     fclose(fp);
  1382.   
  1383.     /* Wait for control channel ack before calculating transfer time;
  1384.      * this accounts for transmitted data in the pipe.
  1385.      */
  1386.     getresp(ftp,200);
  1387.   
  1388.     if(total == -1){
  1389.         tprintf("STOR %s: Error/abort during data transfer\n",remotename);
  1390.     } else if(ftp->verbose >= V_SHORT){
  1391.         startclk = msclock() - startclk;
  1392.         rate = 0;
  1393.         if(startclk != 0){      /* Avoid divide-by-zero */
  1394.             if(total < 4294967L){
  1395.                 rate = (total*1000)/startclk;
  1396.             } else {        /* Avoid overflow */
  1397.                 rate = total/(startclk/1000);
  1398.             }
  1399.         }
  1400.         tprintf("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
  1401.         remotename,total,startclk/1000,rate);
  1402.     }
  1403.     ftp->state = prevstate;
  1404.     return total;
  1405.   
  1406.     failure:
  1407.     /* Error, quit */
  1408.     fclose(fp);
  1409.     close_s(ftp->data);
  1410.     ftp->data = -1;
  1411.     ftp->state = prevstate;
  1412.     return -1;
  1413. }
  1414. /* Abort a GET or PUT operation in progress. Note: this will leave
  1415.  * the partial file on the local or remote system
  1416.  */
  1417. int
  1418. doabort(argc,argv,p)
  1419. int argc;
  1420. char *argv[];
  1421. void *p;
  1422. {
  1423.     register struct session *sp;
  1424.     register struct ftpcli *ftp;
  1425.   
  1426.     sp = (struct session *)p;
  1427.     if(sp == NULLSESSION)
  1428.         return -1;
  1429.   
  1430.     /* Default is the current session, but it can be overridden with
  1431.      * an argument.
  1432.      */
  1433.     if(argc > 1)
  1434.         sp = sessptr(argv[1]);
  1435.   
  1436.     if(sp == NULLSESSION || sp->type != FTP){
  1437.         tputs("Not an active FTP session\n");
  1438.         return 1;
  1439.     }
  1440.     ftp = sp->cb.ftp;
  1441.     switch(ftp->state){
  1442.         case COMMAND_STATE:
  1443.             tputs("No active transfer\n");
  1444.             return 1;
  1445.         case SENDING_STATE:
  1446.         /* Send a premature EOF.
  1447.          * Unfortunately we can't just reset the connection
  1448.          * since the remote side might end up waiting forever
  1449.          * for us to send something.
  1450.          */
  1451.             shutdown(ftp->data,1);  /* Note fall-thru */
  1452.             ftp->abort = 1;
  1453.             break;
  1454.         case RECEIVING_STATE:
  1455.         /* Just blow away the receive socket */
  1456.             shutdown(ftp->data,2);  /* Note fall-thru */
  1457.             ftp->abort = 1;
  1458.             break;
  1459.     }
  1460.     return 0;
  1461. }
  1462. /* send PORT message */
  1463. static void
  1464. sendport(s,socket)
  1465. int s;
  1466. struct sockaddr_in *socket;
  1467. {
  1468.     /* Send PORT a,a,a,a,p,p message */
  1469.     usprintf(s,"PORT %u,%u,%u,%u,%u,%u\n",
  1470.     hibyte(hiword(socket->sin_addr.s_addr)),
  1471.     lobyte(hiword(socket->sin_addr.s_addr)),
  1472.     hibyte(loword(socket->sin_addr.s_addr)),
  1473.     lobyte(loword(socket->sin_addr.s_addr)),
  1474.     hibyte(socket->sin_port),
  1475.     lobyte(socket->sin_port));
  1476. }
  1477.   
  1478. /* Wait for, read and display response from FTP server. Return the result code.
  1479.  */
  1480. static int
  1481. getresp(ftp,mincode)
  1482. struct ftpcli *ftp;
  1483. int mincode;    /* Keep reading until at least this code comes back */
  1484. {
  1485.     register char *line;
  1486.     int rval;
  1487.   
  1488.     usflush(ftp->control);
  1489.     line = mallocw(LINELEN);
  1490.     for(;;){
  1491.         /* Get line */
  1492.         if(recvline(ftp->control,line,LINELEN) == -1){
  1493.             rval = -1;
  1494.             break;
  1495.         }
  1496.         rip(line);              /* Remove cr/lf */
  1497.         rval = atoi(line);
  1498.         if(rval >= 400 || ftp->verbose >= V_NORMAL)
  1499.             tprintf("%s\n",line);   /* Display to user */
  1500.   
  1501.         /* Messages with dashes are continued */
  1502.         if(line[3] != '-' && rval >= mincode)
  1503.             break;
  1504.     }
  1505. #ifdef LZW
  1506.     if((rval == 215) || (rval == 299) || (rval == 399)) {  /* Return encrypted password */
  1507.         ftp->line = mallocw(LINELEN);
  1508.         strcpy(ftp->line, line);
  1509.     }
  1510. #else
  1511.     if((rval == 215) || (rval == 399)) {          /* Return encrypted password */
  1512.         ftp->line = mallocw(LINELEN);
  1513.         strcpy(ftp->line, line);
  1514.     }
  1515. #endif
  1516.     free(line);
  1517.     return rval;
  1518. }
  1519.   
  1520. /* Issue a prompt and read a line from the user */
  1521. static int
  1522. getline(sp,prompt,buf,n)
  1523. struct session *sp;
  1524. char *prompt;
  1525. char *buf;
  1526. int n;
  1527. {
  1528.     /* If there's something already there, don't issue prompt */
  1529.     if(socklen(sp->input,0) == 0)
  1530.         tputs(prompt);
  1531.   
  1532.     usflush(sp->output);
  1533.     return recvline(sp->input,buf,n);
  1534. }
  1535.   
  1536. /* Attempt to log in the user whose name is in ftp->username and password
  1537.  * in pass
  1538.  */
  1539. static char *
  1540. ftpcli_login(ftp,host)
  1541. struct ftpcli *ftp;
  1542. char *host; {
  1543.   
  1544.     char buf[80],*cp,*cp1;
  1545.     FILE *fp;
  1546.   
  1547.     extern char *Hostfile;  /* List of user names and permissions */
  1548.   
  1549.     if((fp = fopen(Hostfile,"r")) == NULLFILE){
  1550.         return NULLCHAR;
  1551.     }
  1552.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  1553.         buf[strlen(buf)-1] = '\0';      /* Nuke the newline */
  1554.         if(buf[0] == '#')
  1555.             continue;       /* Comment */
  1556.         if((cp = strpbrk(buf," \t")) == NULLCHAR)
  1557.             /* Bogus entry */
  1558.             continue;
  1559.         *cp++ = '\0';           /* Now points to user name */
  1560.         if(strcmp(host,buf) == 0)
  1561.             break;          /* Found host name */
  1562.     }
  1563.     if(feof(fp)){
  1564.         /* User name not found in file */
  1565.         fclose(fp);
  1566.         return NULLCHAR;
  1567.     }
  1568.     fclose(fp);
  1569.     /* Look for space after user field in file */
  1570.     cp = skipwhite(cp);
  1571.     if((cp1 = strpbrk(cp," \t")) == NULLCHAR)
  1572.         /* if not there then we'll prompt */
  1573.         ftp->password = NULLCHAR;
  1574.     else
  1575.         *cp1++ = '\0';          /* Now points to password */
  1576.     cp1 = skipwhite(cp1);
  1577.     if(strcmp(cp,"*") == 0)
  1578.         cp1 = "anonymous";
  1579.     ftp->password = strdup(cp1);
  1580.     return strdup(cp);
  1581. }
  1582.   
  1583. int
  1584. dolcd(argc,argv,p)
  1585. int argc;
  1586. char *argv[];
  1587. void *p;
  1588. {
  1589.     register struct ftpcli *ftp;
  1590.   
  1591.     ftp = (struct ftpcli *)p;
  1592.     if(ftp == NULLFTP){
  1593.         tputs(Notsess);
  1594.         return 1;
  1595.     }
  1596.   
  1597.     if(argc > 1){
  1598.         if (!dir_ok(argv[1],ftp->curdirs)) {
  1599.   
  1600.             tprintf("Invalid Drive/Directory - %s\n",argv[1]);
  1601.             return 1;
  1602.         }
  1603.   
  1604.     }
  1605.     tprintf("Local Directory - %s\n",ftp->curdirs->dir);
  1606.   
  1607.     return 0;
  1608. }
  1609.   
  1610.   
  1611. int
  1612. doldir(argc,argv,p)
  1613. int argc;
  1614. char *argv[];
  1615. void *p;
  1616. {
  1617.     register struct ftpcli *ftp;
  1618.     char ** margv;
  1619.   
  1620.     margv=(char **)callocw(2,sizeof(char*));
  1621.   
  1622.     ftp = (struct ftpcli *)p;
  1623.     if(ftp == NULLFTP){
  1624.         tputs(Notsess);
  1625.         return 1;
  1626.     }
  1627.   
  1628.     tputc('\n');
  1629.     margv[1]=strdup(make_dir_path(argc,argv[1],ftp->curdirs->dir));
  1630.     dircmd(2,margv,p);
  1631.     free(margv[1]);
  1632.     free(margv);
  1633.     tputc('\n');
  1634.     return 0;
  1635. }
  1636.   
  1637. int
  1638. dolmkdir(argc,argv,p)
  1639. int argc;
  1640. char *argv[];
  1641. void *p;
  1642. {
  1643.     register struct ftpcli *ftp;
  1644.     char *buf;
  1645.   
  1646.     ftp = (struct ftpcli *)p;
  1647.     if(ftp == NULLFTP){
  1648.         tputs(Notsess);
  1649.         return 1;
  1650.     }
  1651.     undosify(argv[1]);
  1652.     buf=strdup(make_fname(ftp->curdirs->dir,argv[1]));
  1653. #ifdef UNIX
  1654.     if (mkdir(buf, 0777) == -1)
  1655. #else
  1656.         if (mkdir(buf) == -1)
  1657. #endif
  1658.             tprintf("Can't make %s: %s\n",buf,sys_errlist[errno]);
  1659.         else
  1660.             tprintf("Directory %s Created\n",buf);
  1661.     free(buf);
  1662.     return 0;
  1663. }
  1664.   
  1665. #endif /* FTPSESSION */
  1666.   
  1667.