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