home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / tcpip / amitcp-support / ncftp-1.5.6 / src / rcs / ftp.c,v < prev    next >
Encoding:
Text File  |  1994-06-29  |  38.2 KB  |  1,820 lines

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