home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume34 / ncftp / part02 / ftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-08  |  26.3 KB  |  1,240 lines

  1. /* ftp.c */
  2.  
  3. #include "sys.h"
  4. #include <sys/types.h>
  5. #include <sys/param.h>
  6. #include <setjmp.h>
  7. #include <sys/stat.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/socket.h>
  10. #include <sys/time.h>
  11. #include <sys/file.h>
  12.  
  13. /* You may need this for declarations of fd_set, etc. */
  14. #ifdef SYSSELECTH
  15. #   include <sys/select.h>
  16. #endif
  17.  
  18. #include <netinet/in.h>
  19. #include <arpa/ftp.h>
  20. #include <arpa/inet.h>
  21. #include <arpa/telnet.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <signal.h>
  26. #include <errno.h>
  27. #include <netdb.h>
  28. #include <fcntl.h>
  29. #include <pwd.h>
  30. #include <ctype.h>
  31. #include "ftpdefs.h"
  32. #include "defaults.h"
  33. #include "ftp.h"
  34. #include "cmds.h"
  35. #include "main.h"
  36. #include "copyright.h"
  37.  
  38. /* ftp.c globals */
  39. struct                sockaddr_in hisctladdr;
  40. struct                sockaddr_in data_addr;
  41. int                    data = -1;
  42. int                    abrtflag = 0;
  43. int                    connected;            /* connected to server */
  44. struct sockaddr_in    myctladdr;
  45. FILE                *cin = NULL, *cout = NULL;
  46. char                *reply_string = NULL;
  47. jmp_buf                sendabort, recvabort;
  48. int                    want_progress = 1;
  49. int                    sendport = -1;        /* use PORT cmd for each data connection */
  50. int                    code;                /* return/reply code for ftp command */
  51. string                hostname;            /* name of host connected to */
  52. int                 cpend;                /* flag: if != 0, then pending server reply */
  53. char                *xferbuf;            /* buffer for local and remote I/O */
  54. size_t                xferbufsize;        /* size in bytes, of the transfer buffer. */
  55. long                next_report;
  56. long                bytes;
  57. long                now_sec;
  58. long                remote_size;
  59. struct timeval        start, stop;
  60.  
  61.  
  62. /* ftp.c externs */
  63. extern FILE                    *logf;
  64. extern string                hostname, cwd, anon_password;
  65. extern int                    verbose, debug, macnum, margc;
  66. extern int                    curtype, creating;
  67. extern int                    options, activemcmd, paging;
  68. extern char                    *line, *margv[];
  69. extern struct userinfo        uinfo;
  70. extern struct macel            macros[];
  71. #ifdef REDIR
  72. extern struct lslist        *lshead, *lstail;
  73. extern int                    is_ls;
  74. #endif
  75.  
  76.  
  77.  
  78. int hookup(char *host, int port)
  79. {
  80.     register struct hostent *hp = 0;
  81.     int s, len, hErr = -1;
  82.  
  83.     bzero((char *)&hisctladdr, sizeof (hisctladdr));
  84.     hisctladdr.sin_addr.s_addr = inet_addr(host);
  85.     if (hisctladdr.sin_addr.s_addr != -1) {
  86.         hisctladdr.sin_family = AF_INET;
  87.         (void) Strncpy(hostname, host);
  88.     } else {
  89.         hp = gethostbyname(host);
  90.         if (hp == NULL) {
  91. #ifdef HERROR
  92.             extern int h_errno;
  93.             if (h_errno == HOST_NOT_FOUND)
  94.                 (void) printf("%s: unknown host\n", host);
  95.             else (void) fprintf(stderr, "%s: gethostbyname herror (%d):  ",
  96.                 host, h_errno);
  97.             herror(NULL);
  98. #else
  99.             (void) printf("%s: unknown host\n", host);
  100. #endif
  101.             goto done;
  102.         }
  103.         hisctladdr.sin_family = hp->h_addrtype;
  104.         bcopy(hp->h_addr_list[0],
  105.             (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  106.         (void) Strncpy(hostname, hp->h_name);
  107.     }
  108.     s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  109.     if (s < 0) {
  110.         Perror("socket");
  111.         goto done;
  112.     }
  113.     hisctladdr.sin_port = port;
  114.     while (connect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
  115.         if (hp && hp->h_addr_list[1]) {
  116.             int oerrno = errno;
  117.  
  118.             (void) fprintf(stderr, "NcFTP: connect error (%d) to address %s: ",
  119.                 errno, inet_ntoa(hisctladdr.sin_addr));
  120.             errno = oerrno;
  121.             Perror((char *) 0);
  122.             hp->h_addr_list++;
  123.             bcopy(hp->h_addr_list[0],
  124.                  (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  125.             (void) fprintf(stdout, "Trying %s...\n",
  126.                 inet_ntoa(hisctladdr.sin_addr));
  127.             (void) close(s);
  128.             s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  129.             if (s < 0) {
  130.                 Perror("socket");
  131.                 goto done;
  132.             }
  133.             continue;
  134.         }
  135.         Perror("connect");
  136.         switch (errno) {
  137.             case ENETDOWN:
  138.             case ENETUNREACH:
  139.             case ECONNABORTED:
  140.             case ETIMEDOUT:
  141.             case ECONNREFUSED:
  142.             case EHOSTDOWN:
  143.                 hErr = -2;    /* we can re-try later. */
  144.         }
  145.         goto bad;
  146.     }
  147.     len = sizeof (myctladdr);
  148.     if (getsockname(s, (char *)&myctladdr, &len) < 0) {
  149.         Perror("getsockname");
  150.         goto bad;
  151.     }
  152.     cin = fdopen(s, "r");
  153.     cout = fdopen(s, "w");
  154.     if (cin == NULL || cout == NULL) {
  155.         (void) fprintf(stderr, "ftp: fdopen failed.\n");
  156.         close_streams(0);
  157.         goto bad;
  158.     }
  159.     if (IS_VVERBOSE)
  160.         (void) printf("Connected to %s.\n", hostname);
  161.     if (getreply(0) > 2) {     /* read startup message from server */
  162.         close_streams(0);
  163.         goto bad;
  164.     }
  165. #ifdef SO_OOBINLINE
  166.     {
  167.     int on = 1;
  168.  
  169.     if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
  170.         < 0 && debug) {
  171.             Perror("setsockopt");
  172.         }
  173.     }
  174. #endif /* SO_OOBINLINE */
  175.  
  176.     hErr = 0;
  177.     goto done;
  178.  
  179. bad:
  180.     (void) close(s);
  181. done:
  182.     code = hErr;
  183.     return (hErr);
  184. }    /* hookup */
  185.  
  186.  
  187.  
  188.  
  189. int login(char *host, int openmode, int ignore_rc)
  190. {
  191.     string                tmp, str;
  192.     char                *username, *pass, *acct;
  193.     int                    n, aflag = 0, prompted_login;
  194.     int                    user_in_rc, tmpverbose;
  195.  
  196.     username = pass = acct = NULL;
  197.     if (!ignore_rc) {
  198.         if ((ruserpass2(host, &username, &pass, &acct)) < 0) {
  199.             /*NOTREACHED */
  200.             code = -1;
  201.             return(0);
  202.         }
  203.     }
  204.  
  205.     user_in_rc = 1;
  206.     prompted_login = 0;
  207.     if (username == NULL) {
  208.         user_in_rc = 0;
  209.         prompted_login = 1;
  210.     } 
  211.  
  212.     if (!user_in_rc) {
  213.         /* There was no username in the rc. */
  214.         if (openmode == OPEN_A) {
  215.             username = "anonymous";
  216.             prompted_login = 0;
  217.         } else { /* openmode == OPEN_U */
  218.             /* Prompt for a username. */
  219.             (void) printf("Name (%s:%s): ", host, uinfo.username);
  220.             (void) FGets(tmp, stdin);
  221.             tmp[strlen(tmp) - 1] = '\0';
  222.             /*
  223.              *    User can hit return if he wants to enter his username
  224.              *    automatically.
  225.              */
  226.             if (*tmp == '\0')
  227.                 username = uinfo.username;
  228.             else
  229.                 username = tmp;
  230.         }
  231.     }
  232.     (void) sprintf(str, "USER %s", username);
  233.     n = command(str);
  234.     if (n == CONTINUE) {
  235.         if (pass == NULL) {
  236.             if (strcmp("anonymous", username) == 0)
  237.                 pass = anon_password;
  238.             else
  239.                 pass = getpass2("Password:");
  240.         }
  241.         (void) sprintf(str, "PASS %s", pass);
  242.         n = command(str);
  243.     }
  244.     if (n == CONTINUE) {
  245.         aflag++;
  246.         acct = getpass2("Account:");
  247.         (void) sprintf(str, "ACCT %s", acct);
  248.         n = command(str);
  249.     }
  250.     if (n != COMPLETE) {
  251. noLogin:
  252.         (void) fprintf(stderr, "Login failed.\n");
  253.         return (0);
  254.     }
  255.     if (!aflag && acct != NULL) {
  256.         (void) sprintf(str, "ACCT %s", acct);
  257.         (void) command(str);
  258.     }
  259.  
  260.     /* See if remote host dropped connection. */
  261.     tmpverbose = verbose;
  262.     verbose = V_QUIET;
  263.     n = command("NOOP");
  264.     verbose = tmpverbose;
  265.     if (n == 4)
  266.         goto noLogin;
  267.  
  268.     if (NOT_VQUIET && !prompted_login)
  269.         (void) printf("Logged into %s.\n", host);
  270.     if (!ignore_rc)
  271.         for (n = 0; n < macnum; ++n) {
  272.             if (!strcmp("init", macros[n].mac_name)) {
  273.                 (void) strcpy(line, "$init");
  274.                 makeargv();
  275.                 domacro(margc, margv);
  276.                 break;
  277.             }
  278.         }
  279.     return (1);
  280. }    /* login */
  281.  
  282.  
  283.  
  284. /*ARGSUSED*/
  285. void cmdabort(int unused)
  286. {
  287.     (void) printf("\n");
  288.     (void) fflush(stdout);
  289.     abrtflag++;
  290. }    /* cmdabort */
  291.  
  292.  
  293.  
  294.  
  295. command(char *cmd)
  296. {
  297.     int r;
  298.     void (*oldintr)(int);
  299.     string str;
  300.  
  301.     abrtflag = 0;
  302.     if (debug) {
  303.         (void) printf("---> %s\n", cmd);
  304.     }
  305.     if (cout == NULL) {
  306.         (void) sprintf(str, "%s: No control connection for command", cmd);
  307.         Perror(str);
  308.         code = -1;
  309.         return (0);
  310.     }
  311.     oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
  312. #ifndef SCO324
  313.     if (cout != NULL)
  314.         (void) fprintf(cout, "%s\r\n", cmd);
  315. #else
  316.     {
  317.         /*
  318.          * The fprintf() above gives me a core-dump in memcpy()...
  319.          * This does the trick though...
  320.          */
  321.  
  322.         char *p = cmd;
  323.         while (*p)
  324.             fputc(*p++, cout);
  325.         fputc('\r', cout);
  326.         fputc('\n', cout);
  327.     }
  328. #endif /* !SCO324 */
  329.     (void) fflush(cout);
  330.     cpend = 1;
  331.     r = getreply(strcmp(cmd, "QUIT") == 0);
  332.     if (abrtflag && oldintr != SIG_IGN && oldintr != NULL)
  333.         (*oldintr)(0);
  334.     (void) signal(SIGINT, oldintr);
  335.     return(r);
  336. }    /* command */
  337.  
  338.  
  339.  
  340.  
  341. getreply(int expecteof)
  342. {
  343.     register int c, n;
  344.     int dig;
  345.     char *cp, *end, *dp;
  346.     int thiscode, originalcode = 0, continuation = 0;
  347.     void (*oldintr)(int);
  348.  
  349.     if (cin == NULL)
  350.         return (-1);
  351.     oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
  352.     end = reply_string + RECEIVEDLINELEN - 2;
  353.     for (;;) {
  354.         dig = n = code = 0;
  355.         cp = reply_string;
  356.         for (;;) {
  357.             c = getc(cin);
  358.             if (c == IAC) {     /* handle telnet commands */
  359.                 switch (c = getc(cin)) {
  360.                 case WILL:
  361.                 case WONT:
  362.                     c = getc(cin);
  363.                     (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
  364.                     (void) fflush(cout);
  365.                     break;
  366.                 case DO:
  367.                 case DONT:
  368.                     c = getc(cin);
  369.                     (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
  370.                     (void) fflush(cout);
  371.                     break;
  372.                 default:
  373.                     break;
  374.                 }
  375.                 continue;
  376.             }
  377.             dig++;
  378.             if (c == EOF) {
  379.                 if (expecteof) {
  380.                     (void) signal(SIGINT,oldintr);
  381.                     code = 221;
  382.                     return (0);
  383.                 }
  384.                 lostpeer(0);
  385.                 if (NOT_VQUIET) {
  386.                     (void) printf("421 Service not available, remote server has closed connection\n");
  387.                     (void) fflush(stdout);
  388.                 }
  389.                 code = 421;
  390.                 return(4);
  391.             }
  392.             if (cp < end && c != '\r')
  393.                 *cp++ = c;
  394.  
  395.             if (c == '\n')
  396.                 break;
  397.             if (dig < 4 && isdigit(c))
  398.                 code = thiscode = code * 10 + (c - '0');
  399.             else if (dig == 4 && c == '-') {
  400.                 if (continuation)
  401.                     code = 0;
  402.                 continuation++;
  403.             }
  404.             if (n == 0)
  405.                 n = c;
  406.         }    /* end for(;;) #2 */
  407.         
  408.         *cp = '\0';
  409.         switch (verbose) {
  410.             case V_QUIET:
  411.                 /* Don't print anything. */
  412.                 break;
  413.             case V_ERRS:
  414.                 if (n == '5') {
  415.                     dp = reply_string;
  416.                     goto stripCode;
  417.                 }
  418.                 break;    
  419.             case V_TERSE:
  420.                 dp = NULL;
  421.                 if (n == '5')
  422.                     dp = reply_string;
  423.                 else if (n == '2') {
  424.                     switch (thiscode) {
  425.                         case 230:
  426.                         case 214:
  427.                         case 332:
  428.                             dp = reply_string;
  429.                             break;
  430.                         case 220:
  431.                             /*
  432.                              * Skip the foo FTP server ready line.
  433.                              */
  434.                             if (strstr(reply_string, "ready.") == NULL)
  435.                                 dp = reply_string;
  436.                             break;
  437.                         case 250:
  438.                             /*
  439.                              * Print 250 lines if they aren't
  440.                              * "250 CWD command successful."
  441.                              */
  442.                             if (strncmp(reply_string + 4, "CWD ", (size_t) 4))
  443.                                 dp = reply_string;
  444.                     }
  445.                 }
  446.                 if (dp == NULL) break;            
  447. stripCode:
  448.                 /* Try to strip out the code numbers, etc. */
  449.                 if (isdigit(*dp++) && isdigit(*dp++) && isdigit(*dp++)) {
  450.                     if (*dp == ' ' || *dp == '-') {
  451.                         dp++;
  452.                         if (*dp == ' ') dp++;
  453.                     } else dp = reply_string;            
  454.                 } else {
  455.                     int spaces;
  456.                     dp = reply_string;
  457.                     for (spaces = 0; spaces < 4; ++spaces)
  458.                         if (dp[spaces] != ' ')
  459.                             break;
  460.                     if (spaces == 4)
  461.                         dp += spaces;
  462.                 }                    
  463.                 goto printLine;
  464.             case V_VERBOSE:
  465.                 dp = reply_string;
  466. printLine:        (void) fputs(dp, stdout);
  467.         }    /* end switch */
  468.  
  469.         if (continuation && code != originalcode) {
  470.             if (originalcode == 0)
  471.                 originalcode = code;
  472.             continue;
  473.         }
  474.         if (n != '1')
  475.             cpend = 0;
  476.         (void) signal(SIGINT,oldintr);
  477.         if (code == 421 || originalcode == 421)
  478.             lostpeer(0);
  479.         if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN && oldintr)
  480.             (*oldintr)(0);
  481.         return (n - '0');
  482.     }    /* end for(;;) #1 */
  483. }    /* getreply */
  484.  
  485.  
  486.  
  487.  
  488. static int empty(struct fd_set *mask, int sec)
  489. {
  490.     struct timeval t;
  491.  
  492.     t.tv_sec = (long) sec;
  493.     t.tv_usec = 0;
  494.     return(select(32, (int *) mask, (int *) 0, (int *) 0, &t));
  495. }    /* empty */
  496.  
  497.  
  498.  
  499. void progress_report(void)
  500. {
  501.     next_report += xferbufsize;
  502.     (void) gettimeofday(&stop, (struct timezone *)0);
  503.     if (stop.tv_sec > now_sec) {
  504.         (void) printf("\b\b\b\b\b\b%3ld%%  ", 100L * bytes / remote_size);
  505.         (void) fflush(stdout);
  506.         now_sec = stop.tv_sec;
  507.     }
  508. }    /* progress_report */
  509.  
  510.  
  511.  
  512. void close_file(FILE **fin, int filetype)
  513. {
  514.     if (*fin != NULL) {
  515.         if (filetype == IS_FILE) {
  516.             (void) fclose(*fin);
  517.             *fin = NULL;
  518.         } else if (filetype == IS_PIPE) {
  519.             (void) pclose(*fin);
  520.             *fin = NULL;
  521.         }
  522.     }
  523. }    /* close_file */
  524.  
  525.  
  526.  
  527.  
  528. /*ARGSUSED*/
  529. void abortsend(int unused)
  530. {
  531.     activemcmd = 0;
  532.     abrtflag = 0;
  533.     (void) printf("\nSend aborted.\n");
  534.     (void) fflush(stdout);
  535.     longjmp(sendabort, 1);
  536. }    /* abortsend */
  537.  
  538.  
  539.  
  540. void sendrequest(char *cmd, char *local, char *remote)
  541. {
  542.     FILE                    *fin, *dout = NULL;
  543.     void                    (*oldintr)(int), (*oldintp)(int);
  544.     string                    str;
  545.     register int            c, d;
  546.     struct stat                st;
  547.     int                        filetype;
  548.     int                        do_reports = 0;
  549.     char                    *mode;
  550.     register char            *bufp;
  551.  
  552.     oldintr = NULL;
  553.     oldintp = NULL;
  554.     mode = "w";
  555.     bytes = 0;
  556.     if (setjmp(sendabort)) {
  557.         while (cpend) {
  558.             (void) getreply(0);
  559.         }
  560.         if (data >= 0) {
  561.             (void) close(data);
  562.             data = -1;
  563.         }
  564.         if (oldintr)
  565.             (void) signal(SIGINT,oldintr);
  566.         if (oldintp)
  567.             (void) signal(SIGPIPE,oldintp);
  568.         code = -1;
  569.         return;
  570.     }
  571.     oldintr = signal(SIGINT, abortsend);
  572.     if (strcmp(local, "-") == 0)  {
  573.         fin = stdin;
  574.         filetype = IS_STREAM;
  575.     } else if (*local == '|') {
  576.         filetype = IS_PIPE;
  577.         oldintp = signal(SIGPIPE,SIG_IGN);
  578.         fin = popen(local + 1, "r");
  579.         if (fin == NULL) {
  580.             Perror(local + 1);
  581.             (void) signal(SIGINT, oldintr);
  582.             (void) signal(SIGPIPE, oldintp);
  583.             code = -1;
  584.             return;
  585.         }
  586.     } else {
  587.         filetype = IS_FILE;
  588.         fin = fopen(local, "r");
  589.         if (fin == NULL) {
  590.             Perror(local);
  591.             (void) signal(SIGINT, oldintr);
  592.             code = -1;
  593.             return;
  594.         }
  595.         if (fstat(fileno(fin), &st) < 0 ||
  596.             (st.st_mode&S_IFMT) != S_IFREG) {
  597.             (void) fprintf(stdout, "%s: not a plain file.\n", local);
  598.             (void) signal(SIGINT, oldintr);
  599.             (void) fclose(fin);
  600.             code = -1;
  601.             return;
  602.         }
  603.     }
  604.     if (initconn()) {
  605.         (void) signal(SIGINT, oldintr);
  606.         if (oldintp)
  607.             (void) signal(SIGPIPE, oldintp);
  608.         code = -1;
  609.         close_file(&fin, filetype);
  610.         return;
  611.     }
  612.     if (setjmp(sendabort))
  613.         goto Abort;
  614.  
  615.     if (remote) {
  616.         (void) sprintf(str, "%s %s", cmd, remote);
  617.         if (command(str) != PRELIM) {
  618.             (void) signal(SIGINT, oldintr);
  619.             if (oldintp)
  620.                 (void) signal(SIGPIPE, oldintp);
  621.             close_file(&fin, filetype);
  622.             return;
  623.         }
  624.     } else
  625.         if (command(cmd) != PRELIM) {
  626.             (void) signal(SIGINT, oldintr);
  627.             if (oldintp)
  628.                 (void) signal(SIGPIPE, oldintp);
  629.             close_file(&fin, filetype);
  630.             return;
  631.         }
  632.     dout = dataconn(mode);
  633.     if (dout == NULL)
  634.         goto Abort;
  635.     (void) gettimeofday(&start, (struct timezone *)0);
  636.     oldintp = signal(SIGPIPE, SIG_IGN);
  637.     if (filetype == IS_FILE && NOT_VQUIET) {
  638.         now_sec = start.tv_sec;
  639.         do_reports = want_progress;
  640.         (void) printf("%s:       ", local);
  641.         (void) fflush(stdout);
  642.     }
  643.  
  644.     switch (curtype) {
  645.  
  646.     case TYPE_I:
  647.     case TYPE_L:
  648.         errno = d = 0;
  649.         while ((c = read(fileno(fin), xferbuf, (int)xferbufsize)) > 0) {
  650.             bytes += c;
  651.             for (bufp = xferbuf; c > 0; c -= d, bufp += d)
  652.                 if ((d = write(fileno(dout), bufp, c)) <= 0)
  653.                     break;
  654.             /* Print progress indicator. */
  655.             if (do_reports)
  656.                 progress_report();
  657.         }
  658.         if (c < 0)
  659.             Perror(local);
  660.         if (d <= 0) {
  661.             if (d == 0 && !creating)
  662.                 (void) fprintf(stderr, "netout: write returned 0?\n");
  663.             else if (errno != EPIPE) 
  664.                 Perror("netout");
  665.             bytes = -1;
  666.         }
  667.         break;
  668.  
  669.     case TYPE_A:
  670.         next_report = xferbufsize;
  671.         while ((c = getc(fin)) != EOF) {
  672.             if (c == '\n') {
  673.                 if (ferror(dout))
  674.                     break;
  675.                 (void) putc('\r', dout);
  676.                 bytes++;
  677.             }
  678.             (void) putc(c, dout);
  679.             bytes++;
  680.  
  681.             /* Print progress indicator. */
  682.             if (do_reports && bytes > next_report)
  683.                 progress_report();
  684.         }
  685.         if (ferror(fin))
  686.             Perror(local);
  687.         if (ferror(dout)) {
  688.             if (errno != EPIPE)
  689.                 Perror("netout");
  690.             bytes = -1;
  691.         }
  692.         break;
  693.     }
  694. Done:
  695.     (void) gettimeofday(&stop, (struct timezone *)0);
  696.     close_file(&fin, filetype);
  697.     if (dout)
  698.         (void) fclose(dout);
  699.     (void) getreply(0);
  700.     (void) signal(SIGINT, oldintr);
  701.     if (oldintp)
  702.         (void) signal(SIGPIPE, oldintp);
  703.     if (bytes > 0)
  704.         ptransfer("sent", bytes, &start, &stop, local, remote);
  705.     return;
  706. Abort:
  707.     code = -1;
  708.     if (!cpend)
  709.         return;
  710.     if (data >= 0) {
  711.         (void) close(data);
  712.         data = -1;
  713.     }
  714.     goto Done;
  715. }    /* sendrequest */
  716.  
  717.  
  718.  
  719. long get_remote_size(char *remote, int filetype)
  720. {
  721.     int oldverbose;
  722.     long rmt_size;
  723.     string str;
  724.  
  725.     rmt_size = -1;                /*
  726.                                  * Return -1 if we could't get it. 
  727.                                  * Not all sites support SIZE.
  728.                                  */
  729.     
  730.     if (filetype == IS_FILE) {
  731.         /* Won't make sense for a pipe or stream. */
  732.         (void) sprintf(str, "SIZE %s", remote);
  733.         *reply_string = 0;
  734.         oldverbose = verbose;
  735.         verbose = V_QUIET;
  736.         (void) command(str);
  737.         verbose = oldverbose;
  738.         if (*reply_string != 5)        /* 5xx is an error. */
  739.             (void) sscanf(reply_string, "%*d %ld", &rmt_size);    
  740.     }
  741.     return rmt_size;
  742. }    /* get_remote_size */
  743.  
  744.  
  745.  
  746. /*ARGSUSED*/
  747. void abortrecv(int unused)
  748. {
  749.     activemcmd = 0;
  750.     abrtflag = 0;
  751.     (void) printf("(abort)\n");
  752.     (void) fflush(stdout);
  753.     longjmp(recvabort, 1);
  754. }    /* abortrecv */
  755.  
  756.  
  757.  
  758. void recvrequest(char *cmd, char *local, char *remote, char *mode)
  759. {
  760.     FILE                        *fout, *din;
  761.     void                        (*oldintr)(int), (*oldintp)(int); 
  762.     int                            oldverbose, oldtype = 0, is_retr;
  763.     int                            tcrflag, nfnd;
  764.     char                        msg;
  765.     string                        str;
  766.     struct fd_set                mask;
  767.     int                            c, d;
  768.     int                            filetype, do_reports = 0;
  769. #ifdef REDIR
  770.     char                        *linePtr;
  771.     int                            nchars;
  772.     string                        str2;
  773. #endif
  774.  
  775.     bytes = 0;
  776.     is_retr = strcmp(cmd, "RETR") == 0;
  777.     oldintr = NULL;
  778.     oldintp = NULL;
  779.     tcrflag = /* !crflag && */ is_retr;
  780.     if (setjmp(recvabort)) {
  781.         while (cpend) {
  782.             (void) getreply(0);
  783.         }
  784.         if (data >= 0) {
  785.             (void) close(data);
  786.             data = -1;
  787.         }
  788.         if (oldintr)
  789.             (void) signal(SIGINT, oldintr);
  790.         code = -1;
  791.         return;
  792.     }
  793.     oldintr = signal(SIGINT, abortrecv);
  794.  
  795.     if (strcmp(local, "-") == 0)
  796.         filetype = IS_STREAM;
  797.     else if (*local == '|')
  798.         filetype = IS_PIPE;
  799.     else {
  800.         filetype = IS_FILE;  /* is_retr ? IS_FILE : IS_STREAM; */
  801.         if (access(local, 2) < 0) {
  802.             char *dir = rindex(local, '/');
  803.  
  804.             if (errno != ENOENT && errno != EACCES) {
  805.                 Perror(local);
  806.                 (void) signal(SIGINT, oldintr);
  807.                 code = -1;
  808.                 return;
  809.             }
  810.             /* See if we have write permission on this directory. */
  811.             if (dir != NULL) {
  812.                 /* Special case: /filename. */
  813.                 if (dir != local)
  814.                     *dir = 0;
  815.                 if (access(dir == local ? "/" : local, 2) < 0) {
  816.                     /*
  817.                      *    We have a big long pathname, like /a/b/c/d,
  818.                      *    but see if we can write into the current
  819.                      *    directory and call the file ./d.
  820.                      */
  821.                     if (access(".", 2) < 0) {
  822.                         (void) strcpy(local, " and .");
  823.                         goto noaccess;
  824.                     }
  825.                     (void) strcpy(local, dir + 1);    /* use simple filename. */
  826.                 } else
  827.                     *dir = '/';
  828.             } else {
  829.                 /* We have a simple path name (file name only). */
  830.                 if (access(".", 2) < 0) {
  831. noaccess:            Perror(local);
  832.                     (void) signal(SIGINT, oldintr);
  833.                     code = -1;
  834.                     return;
  835.                 }
  836.             }
  837.         }
  838.     }
  839.     if (initconn()) {
  840.         (void) signal(SIGINT, oldintr);
  841.         code = -1;
  842.         return;
  843.     }
  844.     if (!is_retr) {
  845.         if (curtype != TYPE_A) {
  846.             oldtype = curtype;
  847.             oldverbose = verbose;
  848.             if (!debug)
  849.                 verbose = V_QUIET;
  850.             setascii(0, NULL);
  851.             verbose = oldverbose;
  852.         }
  853.     }
  854.  
  855.     remote_size = get_remote_size(remote, filetype);
  856.     if (remote) {
  857.         (void) sprintf(str, "%s %s", cmd, remote);
  858.         if (command(str) != PRELIM) 
  859.             goto nevrmind;
  860.     } else {
  861.         if (command(cmd) != PRELIM) {
  862. nevrmind:    (void) signal(SIGINT, oldintr);
  863.             if (oldtype) {
  864.                 if (!debug)
  865.                     verbose = V_QUIET;
  866.                 if (oldtype == TYPE_I)
  867.                     setbinary(0, NULL);
  868.                 verbose = oldverbose;
  869.             }
  870.             return;
  871.         }
  872.     }
  873.     din = dataconn("r");
  874.     if (din == NULL)
  875.         goto Abort;
  876.     if (filetype == IS_STREAM) {
  877.         fout = stdout;
  878.     } else if (filetype == IS_PIPE) {
  879.         oldintp = signal(SIGPIPE, SIG_IGN);
  880.         fout = popen(local + 1, "w");
  881.         if (fout == NULL) {
  882.             Perror(local+1);
  883.             goto Abort;
  884.         }
  885.     } else {
  886.         fout = fopen(local, mode);
  887.         if (fout == NULL) {
  888.             Perror(local);
  889.             goto Abort;
  890.         }
  891.     }
  892.  
  893.     (void) gettimeofday(&start, (struct timezone *)0);
  894.     do_reports = want_progress && (remote_size > 0) && !paging;
  895.     if (filetype == IS_FILE && NOT_VQUIET && do_reports) {
  896.         now_sec = start.tv_sec;
  897.         (void) printf("%s:       ", local);
  898.         (void) fflush(stdout);
  899.     }
  900.  
  901.     if (setjmp(recvabort))
  902.         goto Abort;
  903.  
  904.     switch (curtype) {
  905.  
  906.     case TYPE_I:
  907.     case TYPE_L:
  908.         errno = d = 0;
  909.         while ((c = read(fileno(din), xferbuf, (int)xferbufsize)) > 0) {
  910.             if ((d = write(fileno(fout), xferbuf, c)) != c)
  911.                 break;
  912.             bytes += c;
  913.  
  914.             /* Print progress indicator. */
  915.             if (do_reports)
  916.                 progress_report();
  917.         }
  918.         if (c < 0) {
  919.             if (errno != EPIPE)
  920.                 Perror("netin");
  921.             bytes = -1;
  922.         }
  923.         if (d < c) {
  924.             if (d < 0) {
  925.                 if (errno != EPIPE)
  926.                     Perror(local);
  927.             } else
  928.                 (void) fprintf(stderr, "%s: short write\n", local);
  929.         }
  930.         break;
  931.  
  932.     case TYPE_A:
  933. #ifdef REDIR
  934.         nchars = 0;
  935.         linePtr = str2;
  936. #endif
  937.         next_report = xferbufsize;
  938.         while ((c = getc(din)) != EOF) {
  939.             while (c == '\r') {
  940.                 bytes++;
  941.                 if ((c = getc(din)) != '\n' || tcrflag) {
  942.                     if (ferror(fout))
  943.                         goto break2;
  944.                     (void) putc('\r', fout);
  945.                     if (c == '\0') {
  946.                         bytes++;
  947.                         goto contin2;
  948.                     }
  949.                     if (c == EOF)
  950.                         goto contin2;
  951.                 }
  952.             }
  953.             (void) putc(c, fout);
  954.             bytes++;
  955.             
  956.             /* Print progress indicator. */
  957.             if (do_reports && bytes > next_report)
  958.                 progress_report();
  959. #ifdef REDIR
  960.             if (nchars < sizeof(str2) - 1) {        /* No seg violations, please */
  961.                  *linePtr++ = c;  /* build redir string */
  962.                  nchars++;
  963.              }
  964. #endif
  965.    contin2:
  966. #ifdef REDIR
  967.             /* Save the input line in the buffer for recall later. */
  968.              if (c=='\n' && is_ls) {
  969.                 register struct lslist *new;
  970.     
  971.                 *--linePtr = '\0';
  972.                 nchars--;
  973.                 new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
  974.                 if (new != NULL) {
  975.                     if (new->string = malloc(strlen(str2) + 1))
  976.                         (void) strcpy(new->string, str2);
  977.                        new->next = NULL;
  978.                        if (lshead == NULL)
  979.                            lshead = lstail = new;
  980.                       else {
  981.                           lstail->next = new;
  982.                           lstail = new;
  983.                       }
  984.                   }
  985.                   /* reset line buffer */
  986.                 linePtr = str2;
  987.                 nchars = 0;
  988.             }    /* ls mode & last char is a newline */
  989. #else
  990.             ;
  991. #endif
  992.         }    /* while ((c = getc(din)) != EOF) */
  993. break2:
  994.         if (ferror(din)) {
  995.             if (errno != EPIPE)
  996.                 Perror("netin");
  997.             bytes = -1;
  998.         }
  999.         if (ferror(fout)) {
  1000.             if (errno != EPIPE)
  1001.                 Perror(local);
  1002.         }
  1003.         break;
  1004.     }    /* end switch (curtype) */
  1005.     
  1006.     close_file(&fout, filetype);
  1007.     (void) signal(SIGINT, oldintr);
  1008.     if (oldintp)
  1009.         (void) signal(SIGPIPE, oldintp);
  1010.     (void) gettimeofday(&stop, (struct timezone *)0);
  1011.     if (din)
  1012.         (void) fclose(din);
  1013.     (void) getreply(0);
  1014.     if (bytes > 0 && is_retr && !paging)
  1015.         ptransfer("received", bytes, &start, &stop, local, remote);
  1016.     if (oldtype) {
  1017.         if (!debug)
  1018.             verbose = V_QUIET;
  1019.             if (oldtype == TYPE_I)
  1020.                 setbinary(0, NULL);
  1021.         verbose = oldverbose;
  1022.     }
  1023.     return;
  1024. Abort:
  1025.  
  1026. /* Abort using RFC959 recommended IP,SYNC sequence  */
  1027.  
  1028.     (void) gettimeofday(&stop, (struct timezone *)0);
  1029.     if (oldintp)
  1030.         (void) signal(SIGPIPE, oldintr);
  1031.     (void) signal(SIGINT,SIG_IGN);
  1032.     if (oldtype) {
  1033.         if (!debug)
  1034.             verbose = V_QUIET;
  1035.             if (oldtype == TYPE_I)
  1036.                 setbinary(0, NULL);
  1037.         verbose = oldverbose;
  1038.     }
  1039.     if (!cpend) {
  1040.         code = -1;
  1041.         (void) signal(SIGINT,oldintr);
  1042.         return;
  1043.     }
  1044.  
  1045.     if (!cout) return;
  1046.     (void) fprintf(cout,"%c%c",IAC,IP);
  1047.     (void) fflush(cout); 
  1048.     msg = IAC;
  1049. /* send IAC in urgent mode instead of DM because UNIX places oob mark */
  1050. /* after urgent byte rather than before as now is protocol            */
  1051.     if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
  1052.         Perror("abort");
  1053.     }
  1054.     (void) fprintf(cout,"%cABOR\r\n",DM);
  1055.     (void) fflush(cout);
  1056.     FD_ZERO(&mask);
  1057.     FD_SET(fileno(cin), &mask);
  1058.     if (din) { 
  1059.         FD_SET(fileno(din), &mask);
  1060.     }
  1061.     if ((nfnd = empty(&mask,10)) <= 0) {
  1062.         if (nfnd < 0) {
  1063.             Perror("abort");
  1064.         }
  1065.         code = -1;
  1066.         lostpeer(0);
  1067.     }
  1068.     if (din && FD_ISSET(fileno(din), &mask)) {
  1069.         while ((c = read(fileno(din), xferbuf, xferbufsize)) > 0)
  1070.             ;
  1071.     }
  1072.     if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
  1073.         if (data >= 0) {
  1074.             (void) close(data);
  1075.             data = -1;
  1076.         }
  1077.         (void) getreply(0);
  1078.     }
  1079.     (void) getreply(0);
  1080.     code = -1;
  1081.     if (data >= 0) {
  1082.         (void) close(data);
  1083.         data = -1;
  1084.     }
  1085.     close_file(&fout, filetype);
  1086.     if (din)
  1087.         (void) fclose(din);
  1088.     if (bytes > 0)
  1089.         ptransfer("received", bytes, &start, &stop, local, remote);
  1090.     (void) signal(SIGINT,oldintr);
  1091. }    /* recvrequest */
  1092.  
  1093.  
  1094.  
  1095.  
  1096. /*
  1097.  * Need to start a listen on the data channel
  1098.  * before we send the command, otherwise the
  1099.  * server's connect may fail.
  1100.  */
  1101.  
  1102. initconn(void)
  1103. {
  1104.     register char        *p, *a;
  1105.     int                    result, len, tmpno = 0;
  1106.     int                    on = 1, rval;
  1107.     string                str;
  1108.     void                (*oldintr)(int);
  1109.  
  1110.     oldintr = signal(SIGINT, SIG_IGN);
  1111. noport:
  1112.     data_addr = myctladdr;
  1113.     if (sendport)
  1114.         data_addr.sin_port = 0;    /* let system pick one */ 
  1115.     if (data != -1)
  1116.         (void) close (data);
  1117.     data = socket(AF_INET, SOCK_STREAM, 0);
  1118.     if (data < 0) {
  1119.         Perror("socket");
  1120.         if (tmpno)
  1121.             sendport = 1;
  1122.         rval = 1;  goto Return;
  1123.     }
  1124.     if (!sendport)
  1125.         if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
  1126.             Perror("setsockopt (reuse address)");
  1127.             goto bad;
  1128.         }
  1129.     if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
  1130.         Perror("bind");
  1131.         goto bad;
  1132.     }
  1133.     if (options & SO_DEBUG &&
  1134.         setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  1135.         Perror("setsockopt (ignored)");
  1136.     len = sizeof (data_addr);
  1137.     if (getsockname(data, (char *)&data_addr, &len) < 0) {
  1138.         Perror("getsockname");
  1139.         goto bad;
  1140.     }
  1141.     if (listen(data, 1) < 0)
  1142.         Perror("listen");
  1143.     if (sendport) {
  1144.         a = (char *)&data_addr.sin_addr;
  1145.         p = (char *)&data_addr.sin_port;
  1146. #define UC(x) (int) (((int) x) & 0xff)
  1147.         (void) sprintf(str, "PORT %d,%d,%d,%d,%d,%d",
  1148.             UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1149.         result = command(str);
  1150.         if (result == ERROR && sendport == -1) {
  1151.             sendport = 0;
  1152.             tmpno = 1;
  1153.             goto noport;
  1154.         }
  1155.         rval = (result != COMPLETE);  goto Return;
  1156.     }
  1157.     if (tmpno)
  1158.         sendport = 1;
  1159.     rval = 0;  goto Return;
  1160. bad:
  1161.     (void) close(data), data = -1;
  1162.     if (tmpno)
  1163.         sendport = 1;
  1164.     rval = 1;
  1165. Return:
  1166.     (void) signal(SIGINT, oldintr);
  1167.     return (rval);
  1168. }    /* initconn */
  1169.  
  1170.  
  1171.  
  1172.  
  1173. FILE *
  1174. dataconn(char *mode)
  1175. {
  1176.     struct sockaddr_in from;
  1177.     FILE *fp;
  1178.     int s, fromlen = sizeof (from);
  1179.  
  1180.     s = accept(data, (struct sockaddr *) &from, &fromlen);
  1181.     if (s < 0) {
  1182.         Perror("accept");
  1183.         (void) close(data), data = -1;
  1184.         fp = NULL;
  1185.     } else {
  1186.         (void) close(data);
  1187.         data = s;
  1188.         fp = fdopen(data, mode);
  1189.     }
  1190.     return (fp);
  1191. }    /* dataconn */
  1192.  
  1193.  
  1194.  
  1195. static void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
  1196. {
  1197.     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  1198.     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  1199.     if (tdiff->tv_usec < 0)
  1200.         tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  1201. }    /* tvsub */
  1202.  
  1203.  
  1204.  
  1205. /*ARGSUSED*/
  1206. void ptransfer(char *direction, long nbytes, struct timeval *t0, struct timeval *t1, char *local, char *remote)
  1207. {
  1208.     struct timeval            td;
  1209.     float                    s, bs;
  1210.     char                    *cp;
  1211.     string                    str;
  1212.  
  1213.     if (NOT_VQUIET || (logf != NULL)) {
  1214.         tvsub(&td, t1, t0);
  1215.         s = td.tv_sec + (td.tv_usec / 1000000.0);
  1216.         if (s != 0.0)
  1217.             bs = nbytes / s;
  1218.         (void) printf("\b\b\b\b\b\b%ld bytes %s in %.2f seconds, ",
  1219.             nbytes, direction, s);
  1220.         if (logf != NULL) {
  1221.             /* if a simple path is given, try to log the full path */
  1222.             if (rindex(remote, '/') == NULL && cwd != NULL) {
  1223.                 (void) sprintf(str, "%s/%s", cwd, remote);
  1224.                 cp = str;
  1225.             } else
  1226.                 cp = remote;
  1227.             (void) fprintf(logf, "\t-> \"%s\" %s, ", cp, direction);
  1228.         }
  1229.         if (bs > 1024.0) {
  1230.             bs /= 1024.0;
  1231.             cp = "%.2f K/s.\n";
  1232.         } else cp = "%.2f Bytes/s.\n";
  1233.         if (NOT_VQUIET) (void) printf(cp, bs);
  1234.         if (logf != NULL)
  1235.             (void) fprintf(logf, cp, bs);
  1236.     } 
  1237. }   /* ptransfer */
  1238.  
  1239. /* eof ftp.c */
  1240.