home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume40 / ncftp / part02 / ftp.c next >
Encoding:
C/C++ Source or Header  |  1993-11-02  |  39.0 KB  |  1,784 lines

  1. /* ftp.c */
  2.  
  3. /*  $RCSfile: ftp.c,v $
  4.  *  $Revision: 14020.12 $
  5.  *  $Date: 93/07/09 11:30:28 $
  6.  */
  7.  
  8. #include "sys.h"
  9.  
  10. #include <setjmp.h>
  11. #include <sys/stat.h>
  12. #include <sys/file.h>
  13.  
  14. #ifndef AIX /* AIX-2.2.1 declares utimbuf in unistd.h */
  15. #ifdef NO_UTIMEH
  16. struct    utimbuf {time_t actime; time_t modtime;};
  17. #else
  18. #    include <utime.h>
  19. #endif
  20. #endif /*AIX*/
  21.  
  22. #ifdef SYSLOG
  23. #    include <syslog.h>
  24. #endif
  25.  
  26. /* You may need this for declarations of fd_set, etc. */
  27. #ifdef SYSSELECTH
  28. #   include <sys/select.h>
  29. #else
  30. #ifdef STRICT_PROTOS
  31. extern int select (int, void *, void *, void *, struct timeval *);
  32. #endif
  33. #endif
  34.  
  35. #include <netinet/in.h>
  36. #include <arpa/ftp.h>
  37. #include <arpa/inet.h>
  38. #include <arpa/telnet.h>
  39. #include <signal.h>
  40. #include <errno.h>
  41. #ifdef NET_ERRNO_H
  42. #       include <net/errno.h>
  43. #endif
  44. #include <netdb.h>
  45. #include <fcntl.h>
  46. #include <pwd.h>
  47. #include <ctype.h>
  48. #include "util.h"
  49. #include "ftp.h"
  50. #include "cmds.h"
  51. #include "main.h"
  52. #include "ftprc.h"
  53. #include "getpass.h"
  54. #include "defaults.h"
  55. #include "copyright.h"
  56.  
  57. #ifdef TERM_FTP
  58. extern int compress_toggle;
  59. #endif
  60.  
  61. /* ftp.c globals */
  62. struct                sockaddr_in hisctladdr;
  63. struct                sockaddr_in data_addr;
  64. int                    data = -1;
  65. int                    abrtflag = 0;
  66. struct sockaddr_in    myctladdr;
  67. FILE                *cin = NULL, *cout = NULL;
  68. char                *reply_string = NULL;
  69. jmp_buf                sendabort, recvabort;
  70. int                    progress_meter = dPROGRESS;
  71. int                    cur_progress_meter;
  72. int                    sendport = -1;        /* use PORT cmd for each data connection */
  73. int                    code;                /* return/reply code for ftp command */
  74. string                indataline;            
  75. int                 cpend;                /* flag: if != 0, then pending server reply */
  76. char                *xferbuf;            /* buffer for local and remote I/O */
  77. size_t                xferbufsize;        /* size in bytes, of the transfer buffer. */
  78. long                next_report;
  79. long                bytes;
  80. long                now_sec;
  81. long                file_size;
  82. struct timeval        start, stop;
  83. int                    buffer_only = 0;    /* True if reading into redir line
  84.                                          * buffer only (not echoing to
  85.                                          * stdout).
  86.                                          */
  87.  
  88. /* ftp.c externs */
  89. extern FILE                    *logf;
  90. extern string                cwd, anon_password;
  91. extern Hostname                hostname;
  92. extern int                    verbose, debug, macnum, margc;
  93. extern int                    curtype, creating, toatty;
  94. extern int                    options, activemcmd, paging;
  95. extern int                    ansi_escapes, logged_in, macnum;
  96. extern char                    *line, *margv[];
  97. extern char                    *tcap_normal, *tcap_boldface;
  98. extern char                    *tcap_underline, *tcap_reverse;
  99. extern struct userinfo        uinfo;
  100. extern struct macel            macros[];
  101. extern struct lslist        *lshead, *lstail;
  102. extern int                    is_ls;
  103.  
  104. #ifdef GATEWAY
  105. extern string                gateway;
  106. extern string                gate_login;
  107. #endif
  108.  
  109. #ifdef TERM_FTP
  110. #include "client.h"
  111. extern int lcompression, rcompression;
  112. int compress_toggle = 0;
  113. #endif
  114.  
  115.  
  116. #ifdef TERM_FTP
  117.  
  118. int hookup(char *host, unsigned int port)
  119. {
  120.       int s;
  121.  
  122.       lcompression = rcompression = compress_toggle;
  123.  
  124.       if ((s = connect_server(0)) < 0) {
  125.           perror("ftp: connect to term server");
  126.           return -1;
  127.       }
  128.       send_command(s, C_PORT, 0, "%s:%d", host, ntohs(port));
  129.       send_command(s, C_DUMB, 1, 0);
  130.  
  131.       cin = fdopen(s, "r");
  132.       cout = fdopen(s, "w");
  133.       if (cin == NULL || cout == NULL) {
  134.               fprintf(stderr, "ftp: fdopen failed.\n");
  135.               if (cin)
  136.                       fclose(cin);
  137.               if (cout)
  138.                       fclose(cout);
  139.               code = -1;
  140.               goto bad;
  141.       }
  142.       Strncpy(hostname, host);
  143.       if (verbose)
  144.               printf("Connected to %s.\n", hostname);
  145.       if (getreply(0) > 2) {  /* read startup message from server */
  146.               if (cin)
  147.                       fclose(cin);
  148.               if (cout)
  149.                       fclose(cout);
  150.               code = -1;
  151.               goto bad;
  152.       }
  153.       return 0;
  154. bad:
  155.       (void) close(s);
  156.       return code;
  157. }
  158. #else
  159.  
  160. int hookup(char *host, unsigned int port)
  161. {
  162.     register struct hostent *hp = 0;
  163.     int s, len, hErr = -1;
  164.     string errstr;
  165.  
  166.     bzero((char *)&hisctladdr, sizeof (hisctladdr));
  167. #ifdef BAD_INETADDR
  168.     hisctladdr.sin_addr = inet_addr(host);
  169. #else
  170.      hisctladdr.sin_addr.s_addr = inet_addr(host);
  171. #endif
  172.     if (hisctladdr.sin_addr.s_addr != -1) {
  173.         hisctladdr.sin_family = AF_INET;
  174.         (void) Strncpy(hostname, host);
  175.     } else {
  176.         hp = gethostbyname(host);
  177.         if (hp == NULL) {
  178. #ifdef HERROR
  179.             extern int h_errno;
  180.             if (h_errno == HOST_NOT_FOUND)
  181.                 (void) printf("%s: unknown host\n", host);
  182.             else (void) fprintf(stderr, "%s: gethostbyname herror (%d):  ",
  183.                 host, h_errno);
  184.             herror(NULL);
  185. #else
  186.             (void) printf("%s: unknown host\n", host);
  187. #endif
  188.             goto done;
  189.         }
  190.         hisctladdr.sin_family = hp->h_addrtype;
  191.         bcopy(hp->h_addr_list[0],
  192.             (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  193.         (void) Strncpy(hostname, hp->h_name);
  194.     }
  195.     s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  196.     if (s < 0) {
  197.         PERROR("hookup", "socket");
  198.         goto done;
  199.     }
  200.     hisctladdr.sin_port = port;
  201. #ifdef SOCKS
  202.     while (Rconnect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
  203. #else
  204.     while (Connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
  205. #endif
  206.         if (hp && hp->h_addr_list[1]) {
  207.             (void) sprintf(errstr, "connect error to address %s",
  208.                 inet_ntoa(hisctladdr.sin_addr));
  209.             PERROR("hookup", errstr);
  210.             hp->h_addr_list++;
  211.             bcopy(hp->h_addr_list[0],
  212.                  (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  213.             (void) fprintf(stdout, "Trying %s...\n",
  214.                 inet_ntoa(hisctladdr.sin_addr));
  215.             (void) close(s);
  216.             s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  217.             if (s < 0) {
  218.                 PERROR("hookup", "socket");
  219.                 goto done;
  220.             }
  221.             continue;
  222.         }
  223.         PERROR("hookup", "connect");
  224.         switch (errno) {
  225.             case ENETDOWN:
  226.             case ENETUNREACH:
  227.             case ECONNABORTED:
  228.             case ETIMEDOUT:
  229.             case ECONNREFUSED:
  230.             case EHOSTDOWN:
  231.                 hErr = -2;    /* we can re-try later. */
  232.         }
  233.         goto bad;
  234.     }
  235.     len = sizeof (myctladdr);
  236.     if (Getsockname(s, (char *)&myctladdr, &len) < 0) {
  237.         PERROR("hookup", "getsockname");
  238.         goto bad;
  239.     }
  240.     cin = fdopen(s, "r");
  241.     cout = fdopen(s, "w");
  242.     if (cin == NULL || cout == NULL) {
  243.         (void) fprintf(stderr, "ftp: fdopen failed.\n");
  244.         close_streams(0);
  245.         goto bad;
  246.     }
  247.     if (IS_VVERBOSE)
  248.         (void) printf("Connected to %s.\n", hostname);
  249.     if (getreply(0) > 2) {     /* read startup message from server */
  250.         close_streams(0);
  251.         if (code == 421)
  252.             hErr = -2;    /* We can try again later. */
  253.         goto bad;
  254.     }
  255. #ifdef SO_OOBINLINE
  256.     {
  257.     int on = 1;
  258.  
  259.     if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
  260.         < 0 && debug) {
  261.             PERROR("hookup", "setsockopt");
  262.         }
  263.     }
  264. #endif /* SO_OOBINLINE */
  265.  
  266.     hErr = 0;
  267.     goto done;
  268.  
  269. bad:
  270.     (void) close(s);
  271. done:
  272.     return (hErr);
  273. }    /* hookup */
  274. #endif
  275.  
  276.  
  277. /* This registers the user's username, password, and account with the remote
  278.  * host which validates it.  If we get on, we also do some other things, like
  279.  * enter a log entry and execute the startup macro.
  280.  */
  281. int Login(char *userNamePtr, char *passWordPtr, char *accountPtr, int doInit)
  282. {
  283.     string userName;
  284.     string str;
  285.     int n;
  286.     int sentAcct = 0;
  287.     int userWasPrompted = 0;
  288.     int result = CMDERR;
  289.     time_t now;
  290.  
  291.     if (userNamePtr == NULL) {
  292.         /* Prompt for a username. */
  293.         (void) sprintf(str, "Login Name (%s): ", uinfo.username);
  294.         ++userWasPrompted;
  295.         if (Gets(str, userName, sizeof(userName)) == NULL)
  296.             goto done;
  297.         else if (userName[0]) {
  298.             /* User didn't just hit return. */
  299.             userNamePtr = userName;
  300.         } else {
  301.             /*
  302.              * User can hit return if he wants to enter his username
  303.              * automatically.
  304.              */
  305.             if (*uinfo.username != '\0')
  306.                 userNamePtr = uinfo.username;
  307.             else
  308.                 goto done;
  309.         }
  310.     }
  311.  
  312.     if (passWordPtr == NULL) {
  313.         if (((strcmp("anonymous", userName) == 0) ||
  314.              (strcmp("ftp", userName) == 0)) && (*anon_password != '\0'))
  315.             passWordPtr = anon_password;
  316.         else {
  317.             /* Prompt for a password. */
  318.             ++userWasPrompted;
  319.             passWordPtr = Getpass("Password:");
  320.         }
  321.     }
  322.  
  323. #ifdef GATEWAY
  324.     if (*gateway)
  325.         (void) sprintf(str, "USER %s@%s",
  326.                 (*gate_login ? gate_login : dGATEWAY_LOGIN),
  327.                 hostname);
  328.     else
  329. #endif
  330.         (void) sprintf(str, "USER %s", userNamePtr);
  331.  
  332.     /* Send the user name. */
  333.     n = command(str);
  334.     if (n == CONTINUE) {
  335.         /* The remote site is requesting us to send the password now. */
  336.         (void) sprintf(str, "PASS %s", passWordPtr);
  337.         n = command(str);
  338.         if (n == CONTINUE) {
  339.             /* The remote site is requesting us to send the account now. */
  340.             if (accountPtr == NULL) {
  341.                 /* Prompt for a username. */
  342.                 (void) sprintf(str, "ACCT %s", Getpass("Account:"));
  343.                 ++userWasPrompted;
  344.             } else {
  345.                 (void) sprintf(str, "ACCT %s", accountPtr);
  346.             }
  347.             ++sentAcct;    /* Keep track that we've sent the account already. */
  348.             n = command(str);
  349.         }
  350.     }
  351.  
  352.     if (n != COMPLETE) {
  353.         (void) printf("Login failed.\n");
  354.         goto done;
  355.     }
  356.     
  357.     /* If you specified an account, and the remote-host didn't request it
  358.      * (maybe it's optional), we will send the account information.
  359.      */
  360.     if (!sentAcct && accountPtr != NULL) {
  361.         (void) sprintf(str, "ACCT %s", accountPtr);
  362.         (void) command(str);
  363.     }
  364.  
  365.     /* See if remote host dropped connection.  Some sites will let you log
  366.      * in anonymously, only to tell you that they already have too many
  367.      * anon users, then drop you.  We do a no-op here to see if they've
  368.      * ditched us.
  369.      */
  370.     n = quiet_command("NOOP");
  371.     if (n == TRANSIENT)
  372.         goto done;
  373.  
  374. #ifdef SYSLOG
  375.     syslog(LOG_INFO, "%s connected to %s as %s.",
  376.            uinfo.username, hostname, userNamePtr);
  377. #endif
  378.  
  379.     /* Save which sites we opened to the user's logfile. */
  380.     if (logf != NULL) {
  381.         (void) time(&now);
  382.         (void) fprintf(logf, "%s opened at %s",
  383.                        hostname,
  384.                        ctime(&now));
  385.     }
  386.  
  387.     /* Let the user know we are logged in, unless he was prompted for some
  388.      * information already.
  389.      */
  390.     if (!userWasPrompted)
  391.         if (NOT_VQUIET)
  392.             (void) printf("Logged into %s.\n", hostname);
  393.  
  394.     if ((doInit) && (macnum > 0)) {
  395.         /* Run the startup macro, if any. */
  396.         /* If macnum is non-zero, the init macro was defined from
  397.          * ruserpass.  It would be the only macro defined at this
  398.          * point.
  399.          */
  400.         (void) strcpy(line, "$init");
  401.         makeargv();
  402.         (void) domacro(margc, margv);
  403.     }
  404.  
  405.     _cd(NULL);    /* Init cwd variable. */
  406.  
  407.     result = NOERR;
  408.     logged_in = 1;
  409.  
  410. done:
  411.     return (result);
  412. }                                       /* Login */
  413.  
  414.  
  415.  
  416. /*ARGSUSED*/
  417. void cmdabort SIG_PARAMS
  418. {
  419.     (void) printf("\n");
  420.     (void) fflush(stdout);
  421.     abrtflag++;
  422. }    /* cmdabort */
  423.  
  424.  
  425.  
  426.  
  427. int CommandWithFlags(char *cmd, int flags)
  428. {
  429.     int r;
  430.     Sig_t oldintr;
  431.     string str;
  432.  
  433.     abrtflag = 0;
  434.     dbprintf("cmd: \"%s\" (length %d)\n", cmd, (int) strlen(cmd));
  435.     if (cout == NULL) {
  436.         (void) sprintf(str, "%s: No control connection for command", cmd);
  437.         PERROR("command", str);
  438.         return (0);
  439.     }
  440.     oldintr = Signal(SIGINT, /* cmdabort */ SIG_IGN);
  441. #ifndef BROKEN_MEMCPY
  442.     if (cout != NULL)
  443.         (void) fprintf(cout, "%s\r\n", cmd);
  444. #else
  445.     {
  446.         /*
  447.          * The fprintf() above gives me a core-dump in memcpy()...
  448.          * This does the trick though...
  449.          */
  450.  
  451.         char *p = cmd;
  452.         while (*p)
  453.             fputc(*p++, cout);
  454.         fputc('\r', cout);
  455.         fputc('\n', cout);
  456.     }
  457. #endif /* !SCO324 */
  458.     (void) fflush(cout);
  459.     cpend = 1;
  460.     r = (flags == WAIT_FOR_REPLY) ?
  461.             (getreply(strcmp(cmd, "QUIT") == 0)) : PRELIM;
  462.     if (abrtflag && oldintr != SIG_IGN && oldintr != NULL)
  463.         (*oldintr)(0);
  464.     (void) Signal(SIGINT, oldintr);
  465.     return(r);
  466. }    /* CommandWithFlags */
  467.  
  468.  
  469.  
  470. /* This stub runs 'CommandWithFlags' above, telling it to wait for
  471.  * reply after the command is sent.
  472.  */
  473. int command(char *cmd)
  474. {
  475.     return (CommandWithFlags(cmd, WAIT_FOR_REPLY));
  476. }    /* command */
  477.  
  478. /* This stub runs 'CommandWithFlags' above, telling it to NOT wait for
  479.  * reply after the command is sent.
  480.  */
  481. int command_noreply(char *cmd)
  482. {
  483.     return(CommandWithFlags(cmd, DONT_WAIT_FOR_REPLY));
  484. }    /* command */
  485.  
  486.  
  487.  
  488. int quiet_command(char *cmd)
  489. {
  490.     register int oldverbose, result;
  491.     
  492.     oldverbose = verbose;
  493.     verbose = V_QUIET;
  494.     result = command(cmd);
  495.     verbose = oldverbose;
  496.     return (result);
  497. }    /* quiet_command */
  498.  
  499.  
  500.  
  501.  
  502. int verbose_command(char *cmd)
  503. {
  504.     register int oldverbose, result;
  505.     
  506.     oldverbose = verbose;
  507.     verbose = V_VERBOSE;
  508.     result = command(cmd);
  509.     verbose = oldverbose;
  510.     return (result);
  511. }    /* quiet_command */
  512.  
  513.  
  514.  
  515.  
  516. int getreply(int expecteof)
  517. {
  518.     register int c, n = 0;
  519.     int dig;
  520.     char *cp, *end, *dp;
  521.     int thiscode, originalcode = 0, continuation = 0;
  522.     Sig_t oldintr;
  523.  
  524.     if (cin == NULL)
  525.         return (-1);
  526.     /* oldintr = Signal(SIGINT, SIG_IGN); */
  527.     oldintr = Signal(SIGINT, cmdabort);
  528.     end = reply_string + RECEIVEDLINELEN - 2;
  529.     for (;abrtflag==0;) {
  530.         dig = n = thiscode = code = 0;
  531.         cp = reply_string;
  532.         for (;abrtflag==0;) {
  533.             c = fgetc(cin);
  534.             if (c == IAC) {     /* handle telnet commands */
  535.                 switch (c = fgetc(cin)) {
  536.                 case WILL:
  537.                 case WONT:
  538.                     c = fgetc(cin);
  539.                     (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
  540.                     (void) fflush(cout);
  541.                     break;
  542.                 case DO:
  543.                 case DONT:
  544.                     c = fgetc(cin);
  545.                     (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
  546.                     (void) fflush(cout);
  547.                     break;
  548.                 default:
  549.                     break;
  550.                 }
  551.                 continue;
  552.             }
  553.             dig++;
  554.             if (c == EOF) {
  555.                 if (expecteof) {
  556.                     (void) Signal(SIGINT, oldintr);
  557.                     code = 221;
  558.                     return (0);
  559.                 }
  560.                 lostpeer(0);
  561.                 if (NOT_VQUIET) {
  562.                     (void) printf("421 Service not available, remote server has closed connection\n");
  563.                     (void) fflush(stdout);
  564.                 }
  565.                 code = 421;
  566.                 return(4);
  567.             }
  568.             if (cp < end && c != '\r')
  569.                 *cp++ = c;
  570.  
  571.             if (c == '\n')
  572.                 break;
  573.             if (dig < 4 && isdigit(c))
  574.                 code = thiscode = code * 10 + (c - '0');
  575.             else if (dig == 4 && c == '-') {
  576.                 if (continuation)
  577.                     code = 0;
  578.                 continuation++;
  579.             }
  580.             if (n == 0)
  581.                 n = c;
  582.         }    /* end for(;;) #2 */
  583.         
  584.         *cp = '\0';
  585.         switch (verbose) {
  586.             case V_QUIET:
  587.                 /* Don't print anything. */
  588.                 break;
  589.             case V_ERRS:
  590.                 if (n == '5') {
  591.                     dp = reply_string;
  592.                     goto stripCode;
  593.                 }
  594.                 break;    
  595.             case V_IMPLICITCD:
  596.             case V_TERSE:
  597.                 dp = NULL;
  598.                 if (n == '5' && verbose == V_TERSE)
  599.                     dp = reply_string;
  600.                 else {
  601.                     switch (thiscode) {
  602.                         case 230:
  603.                         case 214:
  604.                         case 332:
  605.                         case 421:    /* For ftp.apple.com, etc. */
  606.                             dp = reply_string;
  607.                             break;
  608.                         case 220:
  609.                             /*
  610.                              * Skip the foo FTP server ready line.
  611.                              */
  612.                             if (strstr(reply_string, "ready.") == NULL)
  613.                                 dp = reply_string;
  614.                             break;
  615.                         case 250:
  616.                             /*
  617.                              * Print 250 lines if they aren't
  618.                              * "250 CWD command successful."
  619.                              */
  620.                             if (strncmp(reply_string + 4, "CWD ", (size_t) 4))
  621.                                 dp = reply_string;
  622.                     }
  623.                 }
  624.                 if (dp == NULL) break;            
  625. stripCode:
  626.                 /* Try to strip out the code numbers, etc. */
  627.                 if (isdigit(*dp++) && isdigit(*dp++) && isdigit(*dp++)) {
  628.                     if (*dp == ' ' || *dp == '-') {
  629.                         dp++;
  630.                         if (*dp == ' ') dp++;
  631.                     } else dp = reply_string;            
  632.                 } else {
  633.                     int spaces;
  634.                     dp = reply_string;
  635.                     for (spaces = 0; spaces < 4; ++spaces)
  636.                         if (dp[spaces] != ' ')
  637.                             break;
  638.                     if (spaces == 4)
  639.                         dp += spaces;
  640.                 }                    
  641.                 goto printLine;
  642.             case V_VERBOSE:
  643.                 dp = reply_string;
  644. printLine:        (void) fputs(dp, stdout);
  645.         }    /* end switch */
  646.  
  647.         if (continuation && code != originalcode) {
  648.             if (originalcode == 0)
  649.                 originalcode = code;
  650.             continue;
  651.         }
  652.         if (n != '1')
  653.             cpend = 0;
  654.         (void) Signal(SIGINT,oldintr);
  655.         if (code == 421 || originalcode == 421)
  656.             lostpeer(0);
  657.         if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN && oldintr)
  658.             (*oldintr)(0);
  659.         break;
  660.     }    /* end for(;;) #1 */
  661.     return (n - '0');
  662. }    /* getreply */
  663.  
  664.  
  665.  
  666.  
  667. static int empty(struct fd_set *mask, int sec)
  668. {
  669.     struct timeval t;
  670.  
  671.     t.tv_sec = (long) sec;
  672.     t.tv_usec = 0;
  673.  
  674.     return(Select(32, mask, NULL, NULL, &t));
  675. }    /* empty */
  676.  
  677.  
  678.  
  679.  
  680. static void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
  681. {
  682.     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  683.     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  684.     if (tdiff->tv_usec < 0)
  685.         tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  686. }    /* tvsub */
  687.  
  688.  
  689. /* Variables private to progress_report code. */
  690. static int barlen;
  691. static long last_dot;
  692. static int dots;
  693.  
  694. int start_progress(int sending, char *local)
  695. {
  696.     long s;
  697.     str32 spec;
  698.  
  699.     cur_progress_meter = toatty ? progress_meter : 0;
  700.     if ((cur_progress_meter > pr_last) || (cur_progress_meter < 0))
  701.         cur_progress_meter = dPROGRESS;
  702.     if ((file_size <= 0) && ((cur_progress_meter == pr_percent) || (cur_progress_meter == pr_philbar) || (cur_progress_meter == pr_last)))
  703.         cur_progress_meter = pr_kbytes;
  704.     if (!ansi_escapes && (cur_progress_meter == pr_philbar))
  705.         cur_progress_meter = pr_dots;
  706.  
  707.     (void) Gettimeofday(&start);
  708.     now_sec = start.tv_sec;
  709.  
  710.     switch (cur_progress_meter) {
  711.         case pr_none:
  712.             break;
  713.         case pr_percent:
  714.             (void) printf("%s:     ", local);
  715.             goto zz;
  716.         case pr_kbytes:
  717.             (void) printf("%s:       ", local);
  718.             goto zz;
  719.         case pr_philbar:
  720.             (void) printf("%s%s file: %s %s\n", 
  721.                 tcap_boldface,
  722.                 sending ? "Sending" : "Receiving",
  723.                 local,
  724.                 tcap_normal
  725.             );
  726.             barlen = 63;
  727.             for (s = file_size; s > 0; s /= 10L) barlen--;
  728.             (void) sprintf(spec, "      0 %%%ds %%ld bytes.\r", barlen);
  729.             (void) printf(spec, " ", file_size);
  730.             goto zz;
  731.         case pr_dots:
  732.             last_dot = (file_size / 10) + 1;
  733.             dots = 0;
  734.             (void) printf("%s: ", local);
  735.         zz:
  736.             (void) fflush(stdout);
  737.             echo(stdin, 0);
  738.     }    /* end switch */
  739.     return (cur_progress_meter);
  740. }    /* start_progress */
  741.  
  742.  
  743.  
  744.  
  745. int progress_report(int finish_up)
  746. {
  747.     int size;
  748.     long perc;
  749.     str32 spec;
  750.  
  751.     next_report += xferbufsize;
  752.     (void) Gettimeofday(&stop);
  753.     if ((stop.tv_sec > now_sec) || (finish_up && file_size)) {
  754.         switch (cur_progress_meter) {
  755.             case pr_none:
  756.                 break;
  757.             case pr_percent:
  758.                 perc = 100L * bytes / file_size;
  759.                 if (perc > 100L) perc = 100L;
  760.                 (void) printf("\b\b\b\b%3ld%%", perc);
  761.                 (void) fflush(stdout);
  762.                 break;
  763.             case pr_philbar:
  764.                 size = (int) ((float)barlen * ((float) (bytes > file_size ?
  765.                     file_size : bytes)/file_size));
  766.                 (void) sprintf(spec, "%%3ld%%%%  0 %%s%%%ds%%s\r", size);
  767.                 (void) printf(
  768.                     spec,
  769.                     100L * (bytes > file_size ? file_size : bytes) / file_size,
  770.                     tcap_reverse,
  771.                     " ",
  772.                     tcap_normal
  773.                 );
  774.                 (void) fflush(stdout);
  775.                 break;
  776.             case pr_kbytes:
  777.                 if ((bytes / 1024) > 0) {
  778.                     (void) printf("\b\b\b\b\b\b%5ldK", bytes / 1024);
  779.                     (void) fflush(stdout);
  780.                 }
  781.                 break;
  782.             case pr_dots:
  783.                 if (bytes > last_dot) {
  784.                     (void) fputc('.', stdout);
  785.                     (void) fflush(stdout);
  786.                     last_dot += (file_size / 10) + 1;
  787.                     dots++;
  788.                 }    
  789.         }    /* end switch */
  790.         now_sec = stop.tv_sec;
  791.     }    /* end if we updated */
  792.     return (UserLoggedIn());
  793. }    /* progress_report */
  794.  
  795.  
  796.  
  797.  
  798. void end_progress(char *direction, char *local, char *remote)
  799. {
  800.     struct timeval            td;
  801.     float                    s, bs = 0.0;
  802.     char                    *cp, *bsstr;
  803.     string                    str;
  804.  
  805.     if (bytes <= 0)
  806.         return;
  807.     (void) progress_report(1);        /* tell progress proc to cleanup. */
  808.  
  809.     tvsub(&td, &stop, &start);
  810.     s = td.tv_sec + (td.tv_usec / 1000000.0);
  811.     if (s != 0.0)
  812.         bs = bytes / s;
  813.     if (bs > 1024.0) {
  814.         bs /= 1024.0;
  815.         bsstr = "K/s.\n";
  816.     } else
  817.         bsstr = "Bytes/s.\n";
  818.  
  819.     if (NOT_VQUIET) switch(cur_progress_meter) {
  820.         case pr_none:
  821.         zz:
  822.             (void) printf("%s: %ld bytes %s in %.2f seconds, %.2f %s", local, bytes, direction, s, bs, bsstr);
  823.             break;
  824.         case pr_kbytes:
  825.         case pr_percent:
  826.             (void) printf("%s%ld bytes %s in %.2f seconds, %.2f %s",
  827.             cur_progress_meter == pr_kbytes ? "\b\b\b\b\b\b" : "\b\b\b\b",
  828.             bytes, direction, s, bs, bsstr);
  829.             echo(stdin, 1);
  830.             break;
  831.         case pr_philbar:
  832.             (void) printf("\n");
  833.             echo(stdin, 1);
  834.             goto zz;
  835.         case pr_dots:
  836.             for (; dots < 10; dots++)
  837.                 (void) fputc('.', stdout);
  838.             (void) fputc('\n', stdout);
  839.             echo(stdin, 1);
  840.             goto zz;
  841.     }
  842.     
  843.     /* Save transfers to the logfile. */
  844.     /* if a simple path is given, try to log the full path */
  845.     if (rindex(remote, '/') == NULL && cwd != NULL) {
  846.         (void) sprintf(str, "%s/%s", cwd, remote);
  847.          cp = str;
  848.     } else
  849.         cp = remote;
  850.     if (logf != NULL) {
  851.         (void) fprintf(logf, "\t-> \"%s\" %s, %.2f %s", cp, direction, bs, bsstr);
  852.     } 
  853. #ifdef SYSLOG
  854.     if (direction[0] == 'r')
  855.         syslog (LOG_INFO, "%s received %s as %s from %s (%ld bytes).",
  856.             uinfo.username, cp, local, hostname, bytes);
  857.     else
  858.         syslog (LOG_INFO, "%s sent %s as %s to %s (%ld bytes).",
  859.             uinfo.username, local, cp, hostname, bytes);
  860. #endif
  861. }   /* end_progress */
  862.  
  863.  
  864.  
  865. void close_file(FILE **fin, int filetype)
  866. {
  867.     if (*fin != NULL) {
  868.         if (filetype == IS_FILE) {
  869.             (void) fclose(*fin);
  870.             *fin = NULL;
  871.         } else if (filetype == IS_PIPE) {
  872.             (void) pclose(*fin);
  873.             *fin = NULL;
  874.         }
  875.     }
  876. }    /* close_file */
  877.  
  878.  
  879.  
  880.  
  881. /*ARGSUSED*/
  882. void abortsend SIG_PARAMS
  883. {
  884.     activemcmd = 0;
  885.     abrtflag = 0;
  886.     (void) fprintf(stderr, "\nSend aborted.\n");
  887.     echo(stdin, 1);
  888.     longjmp(sendabort, 1);
  889. }    /* abortsend */
  890.  
  891.  
  892.  
  893. int sendrequest(char *cmd, char *local, char *remote)
  894. {
  895.     FILE                    *fin, *dout = NULL;
  896.     Sig_t                    oldintr, oldintp;
  897.     string                    str;
  898.     register int            c, d;
  899.     struct stat                st;
  900.     int                        filetype, result = NOERR;
  901.     int                        do_reports = 0;
  902.     char                    *mode;
  903.     register char            *bufp;
  904.  
  905.     dbprintf("cmd: %s;  rmt: %s;  loc: %s.\n", cmd, remote, local);
  906.     oldintr = NULL;
  907.     oldintp = NULL;
  908.     mode = "w";
  909.     bytes = file_size = 0L;
  910.     if (setjmp(sendabort)) {
  911.         while (cpend) {
  912.             (void) getreply(0);
  913.         }
  914.         if (data >= 0) {
  915.             (void) close(data);
  916.             data = -1;
  917.         }
  918.         if (oldintr)
  919.             (void) Signal(SIGINT, oldintr);
  920.         if (oldintp)
  921.             (void) Signal(SIGPIPE, oldintp);
  922.         result = -1;
  923.         goto xx;
  924.     }
  925.     oldintr = Signal(SIGINT, abortsend);
  926.     file_size = -1;
  927.     if (strcmp(local, "-") == 0)  {
  928.         fin = stdin;
  929.         filetype = IS_STREAM;
  930.     } else if (*local == '|') {
  931.         filetype = IS_PIPE;
  932.         oldintp = Signal(SIGPIPE,SIG_IGN);
  933.         fin = popen(local + 1, "r");
  934.         if (fin == NULL) {
  935.             PERROR("sendrequest", local + 1);
  936.             (void) Signal(SIGINT, oldintr);
  937.             (void) Signal(SIGPIPE, oldintp);
  938.             result = -1;
  939.             goto xx;
  940.         }
  941.     } else {
  942.         filetype = IS_FILE;
  943.         fin = fopen(local, "r");
  944.         if (fin == NULL) {
  945.             PERROR("sendrequest", local);
  946.             (void) Signal(SIGINT, oldintr);
  947.             result = -1;
  948.             goto xx;
  949.         }
  950.         if (fstat(fileno(fin), &st) < 0 ||
  951.             (st.st_mode&S_IFMT) != S_IFREG) {
  952.             (void) fprintf(stdout, "%s: not a plain file.\n", local);
  953.             (void) Signal(SIGINT, oldintr);
  954.             (void) fclose(fin);
  955.             result = -1;
  956.             goto xx;
  957.         }
  958.         file_size = st.st_size;
  959.     }
  960.     if (initconn()) {
  961.         (void) Signal(SIGINT, oldintr);
  962.         if (oldintp)
  963.             (void) Signal(SIGPIPE, oldintp);
  964.         result = -1;
  965.         close_file(&fin, filetype);
  966.         goto xx;
  967.     }
  968.     if (setjmp(sendabort))
  969.         goto Abort;
  970.  
  971. #ifdef TRY_NOREPLY
  972.     if (remote) {
  973.         (void) sprintf(str, "%s %s", cmd, remote);
  974.         (void) command_noreply(str);
  975.     } else {
  976.         (void) command_noreply(cmd);
  977.     }
  978.  
  979.     dout = dataconn(mode);
  980.     if (dout == NULL)
  981.         goto Abort;
  982.  
  983.     if(getreply(0) != PRELIM) {
  984.         (void) Signal(SIGINT, oldintr);
  985.          if (oldintp)
  986.              (void) Signal(SIGPIPE, oldintp);
  987.          close_file(&fin, filetype);
  988.          return -1;
  989.      }
  990. #else
  991.      if (remote) {
  992.          (void) sprintf(str, "%s %s", cmd, remote);
  993.          if (command(str) != PRELIM) {
  994.              (void) Signal(SIGINT, oldintr);
  995.              if (oldintp)
  996.                  (void) Signal(SIGPIPE, oldintp);
  997.              close_file(&fin, filetype);
  998.              goto xx;
  999.          }
  1000.      } else {
  1001.          if (command(cmd) != PRELIM) {
  1002.              (void) Signal(SIGINT, oldintr);
  1003.              if (oldintp)
  1004.                  (void) Signal(SIGPIPE, oldintp);
  1005.              close_file(&fin, filetype);
  1006.              goto xx;
  1007.          }
  1008.      }
  1009.  
  1010.      dout = dataconn(mode);
  1011.      if (dout == NULL)
  1012.          goto Abort;
  1013. #endif
  1014.  
  1015.     (void) Gettimeofday(&start);
  1016.     oldintp = Signal(SIGPIPE, SIG_IGN);
  1017.     if ((do_reports = (filetype == IS_FILE && NOT_VQUIET)) != 0)
  1018.         do_reports = start_progress(1, local);
  1019.  
  1020.     switch (curtype) {
  1021.  
  1022.     case TYPE_I:
  1023.     case TYPE_L:
  1024.         errno = d = 0;
  1025.         while ((c = read(fileno(fin), xferbuf, (int)xferbufsize)) > 0) {
  1026.             bytes += c;
  1027.             for (bufp = xferbuf; c > 0; c -= d, bufp += d)
  1028.                 if ((d = write(fileno(dout), bufp, c)) <= 0)
  1029.                     break;
  1030.             /* Print progress indicator. */
  1031.             if (do_reports)
  1032.                 do_reports = progress_report(0);
  1033.         }
  1034.         if (c < 0)
  1035.             PERROR("sendrequest", local);
  1036.         if (d <= 0) {
  1037.             if (d == 0 && !creating)
  1038.                 (void) fprintf(stderr, "netout: write returned 0?\n");
  1039.             else if (errno != EPIPE) 
  1040.                 PERROR("sendrequest", "netout");
  1041.             bytes = -1;
  1042.         }
  1043.         break;
  1044.  
  1045.     case TYPE_A:
  1046.         next_report = xferbufsize;
  1047.         while ((c = getc(fin)) != EOF) {
  1048.             if (c == '\n') {
  1049.                 if (ferror(dout))
  1050.                     break;
  1051.                 (void) putc('\r', dout);
  1052.                 bytes++;
  1053.             }
  1054.             (void) putc(c, dout);
  1055.             bytes++;
  1056.  
  1057.             /* Print progress indicator. */
  1058.             if (do_reports && bytes > next_report)
  1059.                 do_reports = progress_report(0);
  1060.         }
  1061.         if (ferror(fin))
  1062.             PERROR("sendrequest", local);
  1063.         if (ferror(dout)) {
  1064.             if (errno != EPIPE)
  1065.                 PERROR("sendrequest", "netout");
  1066.             bytes = -1;
  1067.         }
  1068.         break;
  1069.     }
  1070. Done:
  1071.     close_file(&fin, filetype);
  1072.     if (dout)
  1073.         (void) fclose(dout);
  1074.     (void) getreply(0);
  1075.     (void) Signal(SIGINT, oldintr);
  1076.     if (oldintp)
  1077.         (void) Signal(SIGPIPE, oldintp);
  1078.     if (do_reports)
  1079.         end_progress("sent", local, remote);
  1080. xx:
  1081.     return (result);
  1082. Abort:
  1083.     result = -1;
  1084.     if (!cpend)
  1085.         goto xx;
  1086.     if (data >= 0) {
  1087.         (void) close(data);
  1088.         data = -1;
  1089.     }
  1090.     goto Done;
  1091. }    /* sendrequest */
  1092.  
  1093.  
  1094.  
  1095.  
  1096. /*ARGSUSED*/
  1097. void abortrecv SIG_PARAMS
  1098. {
  1099.     activemcmd = 0;
  1100.     abrtflag = 0;
  1101.     (void) fprintf(stderr, 
  1102. #ifdef TRY_ABOR
  1103.     "(abort)\n");
  1104. #else
  1105.     "\nAborting, please wait...");
  1106. #endif
  1107.     (void) fflush(stderr);
  1108.     echo(stdin, 1);
  1109.     longjmp(recvabort, 1);
  1110. }    /* abortrecv */
  1111.  
  1112.  
  1113.  
  1114.  
  1115. void GetLSRemoteDir(char *remote, char *remote_dir)
  1116. {
  1117.     char *cp;
  1118.  
  1119.     /*
  1120.      * The ls() function can specify a directory to list along with ls flags,
  1121.      * if it sends the flags first followed by the directory name.
  1122.      *
  1123.      * So far, we don't care about the remote directory being listed.  I put
  1124.      * it now so I won't forget in case I need to do something with it later.
  1125.      */
  1126.     remote_dir[0] = 0;
  1127.     if (remote != NULL) {
  1128.         cp = index(remote, LS_FLAGS_AND_FILE);
  1129.         if (cp == NULL)
  1130.             (void) Strncpy(remote_dir, remote);
  1131.         else {
  1132.             *cp++ = ' ';
  1133.             (void) Strncpy(remote_dir, cp);
  1134.         }
  1135.     }
  1136. }    /* GetLSRemoteDir */
  1137.  
  1138.  
  1139.  
  1140.  
  1141. int AdjustLocalFileName(char *local)
  1142. {
  1143.     char *dir;
  1144.  
  1145.     /*
  1146.      * Make sure we are writing to a valid local path.
  1147.      * First check the local directory, and see if we can write to it.
  1148.      */
  1149.     if (access(local, 2) < 0) {
  1150.         dir = rindex(local, '/');
  1151.  
  1152.         if (errno != ENOENT && errno != EACCES) {
  1153.             /* Report an error if it's one we can't handle. */
  1154.             PERROR("AdjustLocalFileName", local);
  1155.             return -1;
  1156.         }
  1157.         /* See if we have write permission on this directory. */
  1158.         if (dir != NULL) {
  1159.             /* Special case: /filename. */
  1160.             if (dir != local)
  1161.                 *dir = 0;
  1162.             if (access(dir == local ? "/" : local, 2) < 0) {
  1163.                 /*
  1164.                  *    We have a big long pathname, like /a/b/c/d,
  1165.                  *    but see if we can write into the current
  1166.                  *    directory and call the file ./d.
  1167.                  */
  1168.                 if (access(".", 2) < 0) {
  1169.                     (void) strcpy(local, " and .");
  1170.                     goto noaccess;
  1171.                 }
  1172.                 (void) strcpy(local, dir + 1);    /* use simple filename. */
  1173.             } else
  1174.                 *dir = '/';
  1175.         } else {
  1176.             /* We have a simple path name (file name only). */
  1177.             if (access(".", 2) < 0) {
  1178. noaccess:        PERROR("AdjustLocalFileName", local);
  1179.                 return -1;
  1180.             }
  1181.         }
  1182.     }
  1183.     return (NOERR);
  1184. }    /* AdjustLocalFileName */
  1185.     
  1186.  
  1187.  
  1188. int SetToAsciiForLS(int is_retr, int currenttype)
  1189. {
  1190.     int oldt = -1, oldv;
  1191.  
  1192.     if (!is_retr) {
  1193.         if (currenttype != TYPE_A) {
  1194.             oldt = currenttype;
  1195.             oldv = verbose;
  1196.             if (!debug)
  1197.                 verbose = V_QUIET;
  1198.             (void) setascii(0, NULL);
  1199.             verbose = oldv;
  1200.         }
  1201.     }
  1202.     return oldt;
  1203. }    /* SetToAsciiForLS */
  1204.  
  1205.  
  1206.  
  1207. int IssueCommand(char *ftpcmd, char *remote)
  1208. {
  1209.     string str;
  1210.     int result = NOERR;
  1211.  
  1212.     if (remote)
  1213.         (void) sprintf(str, "%s %s", ftpcmd, remote);
  1214.     else
  1215.         (void) Strncpy(str, ftpcmd);
  1216.     
  1217. #ifdef TRY_NOREPLY
  1218.     if (command_noreply(str) != PRELIM)
  1219. #else
  1220.     if (command(str) != PRELIM)
  1221. #endif
  1222.         result = -1;
  1223.     return (result);
  1224. }    /* IssueCommand */
  1225.  
  1226.  
  1227.  
  1228. FILE *OpenOutputFile(int filetype, char *local, char *mode, Sig_t *oldintp)
  1229. {
  1230.     FILE *fout;
  1231.  
  1232.     if (filetype == IS_STREAM) {
  1233.         fout = stdout;
  1234.     } else if (filetype == IS_PIPE) {
  1235.         /* If it is a pipe, the pipecmd will have a | as the first char. */
  1236.         ++local;
  1237.         fout = popen(local, "w");
  1238.         *oldintp = Signal(SIGPIPE, abortrecv);
  1239.     } else {
  1240.         fout = fopen(local, mode);
  1241.     }
  1242.     if (fout == NULL)
  1243.         PERROR("OpenOutputFile", local);
  1244.     return (fout);
  1245. }    /* OpenOutputFile */
  1246.  
  1247.  
  1248.  
  1249. void ReceiveBinary(FILE *din, FILE *fout, int *do_reports, char *localfn)
  1250. {
  1251.     int                            c, d, do2;
  1252.  
  1253.     errno = 0;            /* Clear any old error left around. */
  1254.     do2 = *do_reports;    /* A slight optimization :-) */
  1255.     bytes = 0;            /* Init the byte-transfer counter. */
  1256.  
  1257.     for (;;) {
  1258.         /* Read a block from the input stream. */
  1259.         c = read(fileno(din), xferbuf, (int)xferbufsize);
  1260.  
  1261.         /* If c is zero, then we've read the whole file. */
  1262.         if (c == 0)
  1263.             break;
  1264.  
  1265.         /* Check for errors that may have occurred while reading. */
  1266.         if (c < 0) {
  1267.             /* Error occurred while reading. */
  1268.             if (errno != EPIPE)
  1269.                 PERROR("ReceiveBinary", "netin");
  1270.             bytes = -1;
  1271.             break;
  1272.         }
  1273.  
  1274.         /* Write out the same block we just read in. */
  1275.         d = write(fileno(fout), xferbuf, c);
  1276.  
  1277.         /* Check for write errors. */
  1278.         if ((d < 0) || (ferror(fout))) {
  1279.             /* Error occurred while writing. */
  1280.             PERROR("ReceiveBinary", "outfile");
  1281.             break;
  1282.         }
  1283.         if (d < c) {
  1284.             (void) fprintf(stderr, "%s: short write\n", localfn);
  1285.             break;
  1286.         }
  1287.  
  1288.         /* Update the byte counter. */
  1289.         bytes += (long) c;
  1290.  
  1291.         /* Print progress indicator. */
  1292.         if (do2 != 0)
  1293.             do2 = progress_report(0);
  1294.     }
  1295.  
  1296.     *do_reports = do2;    /* Update the real do_reports variable. */
  1297. }    /* ReceiveBinary */
  1298.  
  1299.  
  1300.  
  1301. void AddRedirLine(char *str2)
  1302. {
  1303.     register struct lslist *new;
  1304.  
  1305.     (void) Strncpy(indataline, str2);
  1306.     new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
  1307.     if (new != NULL) {
  1308.         if ((new->string = NewString(str2)) != NULL) {
  1309.                new->next = NULL;
  1310.             if (lshead == NULL)
  1311.                 lshead = lstail = new;
  1312.             else {
  1313.                 lstail->next = new;
  1314.                 lstail = new;
  1315.             }
  1316.         }
  1317.     }
  1318. }    /* AddRedirLine */
  1319.  
  1320.  
  1321.  
  1322. void ReceiveAscii(FILE *din, FILE *fout, int *do_reports, char *localfn, int
  1323. lineMode)
  1324. {
  1325.     string str2;
  1326.     int nchars = 0, c;
  1327.     char *linePtr;
  1328.     int do2 = *do_reports, stripped;
  1329.  
  1330.     next_report = xferbufsize;
  1331.     bytes = errno = 0;
  1332.     if (lineMode) {
  1333.         while ((linePtr = FGets(str2, din)) != NULL) {
  1334.             bytes += (long) RemoveTrailingNewline(linePtr, &stripped);
  1335.             if (is_ls || debug > 0)
  1336.                 AddRedirLine(linePtr);
  1337.  
  1338.             /* Shutup while getting remote size and mod time. */
  1339.             if (!buffer_only) {
  1340.                 c = fputs(linePtr, fout);
  1341.  
  1342.                 if (c != EOF) {
  1343.                     if (stripped > 0)
  1344.                         c = fputc('\n', fout);
  1345.                 }
  1346.                 if ((c == EOF) || (ferror(fout))) {
  1347.                     PERROR("ReceiveAscii", "outfile");
  1348.                     break;
  1349.                 }
  1350.             }
  1351.  
  1352.             /* Print progress indicator. */
  1353.             if (do2 && bytes > next_report)
  1354.                 do2 = progress_report(0);
  1355.         }
  1356.     } else while ((c = getc(din)) != EOF) {
  1357.         linePtr = str2;
  1358.         while (c == '\r') {
  1359.             bytes++;
  1360.             if ((c = getc(din)) != '\n') {
  1361.                 if (ferror(fout))
  1362.                     goto break2;
  1363.                 /* Shutup while getting remote size and mod time. */
  1364.                 if (!buffer_only)
  1365.                     (void) putc('\r', fout);
  1366.                 if (c == '\0') {
  1367.                     bytes++;
  1368.                     goto contin2;
  1369.                 }
  1370.                 if (c == EOF)
  1371.                     goto contin2;
  1372.             }
  1373.         }
  1374.         /* Shutup while getting remote size and mod time. */
  1375.         if (!buffer_only)
  1376.             (void) putc(c, fout);
  1377.         bytes++;
  1378.         
  1379.         /* Print progress indicator. */
  1380.         if (do2 && bytes > next_report)
  1381.             do2 = progress_report(0);
  1382.  
  1383.         /* No seg violations, please */
  1384.         if (nchars < sizeof(str2) - 1) {
  1385.              *linePtr++ = c;  /* build redir string */
  1386.             nchars++;
  1387.         }
  1388.  
  1389.    contin2:
  1390.         /* Save the input line in the buffer for recall later. */
  1391.         if (c == '\n' && is_ls) {
  1392.             *--linePtr = 0;
  1393.             AddRedirLine(str2);
  1394.             nchars = 0;
  1395.         }
  1396.        
  1397.     }    /* while ((c = getc(din)) != EOF) */
  1398. break2:
  1399.     if (ferror(din)) {
  1400.         if (errno != EPIPE)
  1401.             PERROR("ReceiveAscii", "netin");
  1402.         bytes = -1;
  1403.     }
  1404.     if (ferror(fout)) {
  1405.         if (errno != EPIPE)
  1406.             PERROR("ReceiveAscii", localfn);
  1407.     }
  1408.     *do_reports = do2;
  1409. }    /* ReceiveAscii */
  1410.  
  1411.  
  1412.  
  1413. void CloseOutputFile(FILE *f, int filetype, char *name, time_t mt)
  1414. {
  1415.     struct utimbuf                ut;
  1416.  
  1417.     if (f != NULL) {
  1418.         (void) fflush(f);
  1419.         if (filetype == IS_FILE) {
  1420.             (void) fclose(f);
  1421.             if (mt != (time_t)0) {
  1422.                 ut.actime = ut.modtime = mt;
  1423.                 (void) utime(name, &ut);
  1424.             }
  1425.         } else if (filetype == IS_PIPE) {
  1426.             (void)pclose(f);
  1427.         }
  1428.     }
  1429. }    /* close_file */
  1430.  
  1431.  
  1432.  
  1433. void ResetOldType(int oldtype)
  1434. {
  1435.     int oldv;
  1436.  
  1437.     if (oldtype >= 0) {
  1438.         oldv = verbose;
  1439.         if (!debug)
  1440.             verbose = V_QUIET;
  1441.         (void) SetTypeByNumber(oldtype);
  1442.         verbose = oldv;
  1443.     }
  1444. }    /* ResetOldType */
  1445.  
  1446.  
  1447.  
  1448. int FileType(char *fname)
  1449. {
  1450.     int ft = IS_FILE;
  1451.  
  1452.     if (strcmp(fname, "-") == 0)
  1453.         ft = IS_STREAM;
  1454.     else if (*fname == '|')
  1455.         ft = IS_PIPE;
  1456.     return (ft);
  1457. }    /* FileType */
  1458.  
  1459.  
  1460.  
  1461.  
  1462. void CloseData(void) {
  1463.     if (data >= 0) {
  1464.         (void) close(data);
  1465.         data = -1;
  1466.     }
  1467. }    /* CloseData */
  1468.  
  1469.  
  1470.  
  1471.  
  1472. int recvrequest(char *cmd, char *local, char *remote, char *mode)
  1473. {
  1474.     FILE                        *fout = NULL, *din = NULL;
  1475.     Sig_t                        oldintr = NULL, oldintp = NULL;
  1476.     int                            oldtype = 0, is_retr;
  1477.     int                            nfnd;
  1478.     char                        msg;
  1479.     struct fd_set                mask;
  1480.     int                            filetype, do_reports = 0;
  1481.     string                        remote_dir;
  1482.     time_t                        remfTime = 0;
  1483.     int                            result = -1;
  1484.  
  1485.     dbprintf("---> cmd: %s;  rmt: %s;  loc: %s;  mode: %s.\n",
  1486.         cmd, remote, local, mode);
  1487.     is_retr = strcmp(cmd, "RETR") == 0;
  1488.  
  1489.     GetLSRemoteDir(remote, remote_dir);
  1490.     if ((filetype = FileType(local)) == IS_FILE) {
  1491.         if (AdjustLocalFileName(local))
  1492.             goto xx;
  1493.     }
  1494.  
  1495.     file_size = -1;
  1496.     if (filetype == IS_FILE)
  1497.         file_size = GetDateAndSize(remote, (unsigned long *) &remfTime);
  1498.  
  1499.     if (initconn())
  1500.         goto xx;
  1501.  
  1502.     oldtype = SetToAsciiForLS(is_retr, curtype);
  1503.  
  1504.      /* Issue the NLST command but don't wait for the reply.  Some FTP 
  1505.       * servers make the data connection before issuing the 
  1506.       * "150 Opening ASCII mode data connection for /bin/ls" reply.
  1507.       */
  1508.     if (IssueCommand(cmd, remote))
  1509.         goto xx;
  1510.     
  1511.     if ((fout = OpenOutputFile(filetype, local, mode, &oldintp)) == NULL)
  1512.         goto xx;
  1513.  
  1514.     if ((din = dataconn("r")) == NULL)
  1515.         goto Abort;
  1516.  
  1517. #ifdef TRY_NOREPLY
  1518.      /* Now get the reply we skipped above. */
  1519.      (void) getreply(0);
  1520. #endif
  1521.  
  1522.     do_reports = NOT_VQUIET && is_retr && filetype == IS_FILE;
  1523.     if (do_reports)
  1524.         do_reports = start_progress(0, local);
  1525.  
  1526.     if (setjmp(recvabort)) {
  1527. #ifdef TRY_ABOR
  1528.         goto Abort;
  1529. #else
  1530.         /* Just read the rest of the stream without doing anything with
  1531.          * the results.
  1532.          */
  1533.         (void) Signal(SIGINT, SIG_IGN);
  1534.         (void) Signal(SIGPIPE, SIG_IGN);    /* Don't bug us while aborting. */
  1535.         while (read(fileno(din), xferbuf, (int)xferbufsize) > 0)
  1536.             ;
  1537.         (void) fprintf(stderr, "\rAborted.                   \n");
  1538. #endif
  1539.     } else {
  1540.         oldintr = Signal(SIGINT, abortrecv);
  1541.  
  1542.         if (curtype == TYPE_A)
  1543.             ReceiveAscii(din, fout, &do_reports, local, 1);
  1544.         else
  1545.             ReceiveBinary(din, fout, &do_reports, local);
  1546.         result = NOERR;
  1547.         /* Don't interrupt us now, since we finished successfully. */
  1548.         (void) Signal(SIGPIPE, SIG_IGN);
  1549.         (void) Signal(SIGINT, SIG_IGN);
  1550.     }    
  1551.     CloseData();
  1552.     (void) getreply(0);
  1553.  
  1554.     goto xx;
  1555.  
  1556. Abort:
  1557.  
  1558. /* Abort using RFC959 recommended IP,SYNC sequence  */
  1559.  
  1560.     (void) Signal(SIGPIPE, SIG_IGN);    /* Don't bug us while aborting. */
  1561.     (void) Signal(SIGINT, SIG_IGN);
  1562.     if (!cpend || !cout) goto xx;
  1563.     (void) fprintf(cout,"%c%c",IAC,IP);
  1564.     (void) fflush(cout); 
  1565.     msg = IAC;
  1566. /* send IAC in urgent mode instead of DM because UNIX places oob mark */
  1567. /* after urgent byte rather than before as now is protocol            */
  1568.     if (send(fileno(cout),&msg,1,MSG_OOB) != 1)
  1569.         PERROR("recvrequest", "abort");
  1570.     (void) fprintf(cout,"%cABOR\r\n",DM);
  1571.     (void) fflush(cout);
  1572.     FD_ZERO(&mask);
  1573.     FD_SET(fileno(cin), &mask);
  1574.     if (din)
  1575.         FD_SET(fileno(din), &mask);
  1576.     if ((nfnd = empty(&mask,10)) <= 0) {
  1577.         if (nfnd < 0)
  1578.             PERROR("recvrequest", "abort");
  1579.         lostpeer(0);
  1580.     }
  1581.     if (din && FD_ISSET(fileno(din), &mask)) {
  1582.         while ((read(fileno(din), xferbuf, xferbufsize)) > 0)
  1583.             ;
  1584.     }
  1585.     if ((getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
  1586.         CloseData();
  1587.         (void) getreply(0);
  1588.     }
  1589.     (void) getreply(0);
  1590.     result = -1;
  1591.     CloseData();
  1592.  
  1593. xx:
  1594.     CloseOutputFile(fout, filetype, local, remfTime);
  1595.     dbprintf("outfile closed.\n");
  1596.     if (din)
  1597.         (void) fclose(din);
  1598.     if (do_reports)
  1599.         end_progress("received", local, remote);
  1600.     if (oldintr)
  1601.         (void) Signal(SIGINT, oldintr);
  1602.     if (oldintp)
  1603.         (void) Signal(SIGPIPE, oldintp);
  1604.     dbprintf("recvrequest result = %d.\n", result);
  1605.     ResetOldType(oldtype);
  1606.     return (result);
  1607. }    /* recvrequest */
  1608.  
  1609.  
  1610.  
  1611.  
  1612. /*
  1613.  * Need to start a listen on the data channel
  1614.  * before we send the command, otherwise the
  1615.  * server's connect may fail.
  1616.  */
  1617.  
  1618. #ifdef TERM_FTP
  1619.  
  1620. /*
  1621.  * Need to request that the server go into passive mode and
  1622.  * then get the address and port for the term server to connect to.
  1623.  */
  1624. int initconn(void)
  1625. {
  1626.       int result;
  1627.       int n[6];
  1628.       int s;
  1629.  
  1630.       if (data != -1)
  1631.               (void) close(data);
  1632.       result = command("PASV");
  1633.       if (result == COMPLETE) {
  1634.               if (sscanf(reply_string, "%*[^(](%d,%d,%d,%d,%d,%d)",
  1635.                       &n[0], &n[1], &n[2], &n[3], &n[4], &n[5]) != 6) {
  1636.                       fprintf(stderr, "Cannot parse PASV response: %s\n",
  1637.                                reply_string);
  1638.                       return 1;
  1639.               }
  1640.               close(data);
  1641.               lcompression = rcompression = compress_toggle;
  1642.               if ((s = connect_server(0)) < 0) {
  1643.                       perror("ftp: connect to term server");
  1644.                       data = -1;
  1645.                       return 1;
  1646.               }
  1647.               data = s;
  1648.               send_command(s, C_PORT, 0, "%d.%d.%d.%d:%d",
  1649.                       n[0], n[1], n[2], n[3], 256*n[4] + n[5]);
  1650.               send_command(s, C_COMPRESS, 1, "n");
  1651.               send_command(s, C_DUMB, 1, 0);
  1652.               return 0;
  1653.       }
  1654.       return 1;
  1655. }
  1656.  
  1657. FILE *
  1658. dataconn(lmode)
  1659.       char *lmode;
  1660. {
  1661.       return (fdopen(data, lmode));
  1662. }
  1663. #else /* TERM_FTP */
  1664.  
  1665.  
  1666. int initconn(void)
  1667. {
  1668.     register char        *p, *a;
  1669.     int                    result, len, tmpno = 0;
  1670.     int                    on = 1, rval;
  1671.     string                str;
  1672.     Sig_t                oldintr;
  1673.  
  1674.     oldintr = Signal(SIGINT, SIG_IGN);
  1675. noport:
  1676.     data_addr = myctladdr;
  1677.     if (sendport)
  1678.         data_addr.sin_port = 0;    /* let system pick one */ 
  1679.     if (data != -1)
  1680.         (void) close (data);
  1681.     data = socket(AF_INET, SOCK_STREAM, 0);
  1682.     if (data < 0) {
  1683.         PERROR("initconn", "socket");
  1684.         if (tmpno)
  1685.             sendport = 1;
  1686.         rval = 1;  goto Return;
  1687.     }
  1688.     if (!sendport)
  1689.         if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
  1690.             PERROR("initconn", "setsockopt (reuse address)");
  1691.             goto bad;
  1692.         }
  1693. #ifdef SOCKS
  1694.     if (Rbind(data, (struct sockaddr *)&data_addr, sizeof (data_addr), hisctladdr.sin_addr.s_addr) < 0) {
  1695. #else
  1696.     if (Bind(data, &data_addr, sizeof (data_addr)) < 0) {
  1697. #endif
  1698.         PERROR("initconn", "bind");
  1699.         goto bad;
  1700.     }
  1701. #ifdef LINGER    /* If puts don't complete, you could try this. */
  1702.     {
  1703.         struct linger li;
  1704.         li.l_onoff = 1;
  1705.         li.l_linger = 900;
  1706.  
  1707.         if (setsockopt(data, SOL_SOCKET, SO_LINGER,
  1708.             (char *)&li, sizeof(struct linger)) < 0)
  1709.         {
  1710.             PERROR("initconn", "setsockopt(SO_LINGER)");
  1711.         }
  1712.     }
  1713. #endif    /* LINGER */
  1714.     if (options & SO_DEBUG &&
  1715.         setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  1716.         PERROR("initconn", "setsockopt (ignored)");
  1717.     len = sizeof (data_addr);
  1718.     if (Getsockname(data, (char *)&data_addr, &len) < 0) {
  1719.         PERROR("initconn", "getsockname");
  1720.         goto bad;
  1721.     }
  1722. #ifdef SOCKS 
  1723.     if (Rlisten(data, 1) < 0)
  1724. #else
  1725.     if (listen(data, 1) < 0)
  1726. #endif
  1727.         PERROR("initconn", "listen");
  1728.     if (sendport) {
  1729.         a = (char *)&data_addr.sin_addr;
  1730.         p = (char *)&data_addr.sin_port;
  1731. #define UC(x) (int) (((int) x) & 0xff)
  1732.         (void) sprintf(str, "PORT %d,%d,%d,%d,%d,%d",
  1733.             UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1734.         result = command(str);
  1735.         if (result == ERROR && sendport == -1) {
  1736.             sendport = 0;
  1737.             tmpno = 1;
  1738.             goto noport;
  1739.         }
  1740.         rval = (result != COMPLETE);  goto Return;
  1741.     }
  1742.     if (tmpno)
  1743.         sendport = 1;
  1744.     rval = 0;  goto Return;
  1745. bad:
  1746.     (void) close(data), data = -1;
  1747.     if (tmpno)
  1748.         sendport = 1;
  1749.     rval = 1;
  1750. Return:
  1751.     (void) Signal(SIGINT, oldintr);
  1752.     return (rval);
  1753. }    /* initconn */
  1754.  
  1755.  
  1756.  
  1757.  
  1758. FILE *
  1759. dataconn(char *mode)
  1760. {
  1761.     struct sockaddr_in from;
  1762.     FILE *fp;
  1763.     int s, fromlen = sizeof (from);
  1764.  
  1765. #ifdef SOCKS
  1766.     s = Raccept(data, (struct sockaddr *) &from, &fromlen);
  1767. #else
  1768.     s = Accept(data, &from, &fromlen);
  1769. #endif
  1770.     if (s < 0) {
  1771.         PERROR("dataconn", "accept");
  1772.         (void) close(data), data = -1;
  1773.         fp = NULL;
  1774.     } else {
  1775.         (void) close(data);
  1776.         data = s;
  1777.         fp = fdopen(data, mode);
  1778.     }
  1779.     return (fp);
  1780. }    /* dataconn */
  1781. #endif
  1782.  
  1783. /* eof ftp.c */
  1784.