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