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