121739Sdist /*
266672Spendry * Copyright (c) 1985, 1989, 1993, 1994
362010Sbostic * The Regents of the University of California. All rights reserved.
433737Sbostic *
542665Sbostic * %sccs.include.redist.c%
621739Sdist */
721739Sdist
810296Ssam #ifndef lint
9*67865Smckusick static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
1033737Sbostic #endif /* not lint */
1110296Ssam
1236940Skarels #include <sys/param.h>
1310296Ssam #include <sys/stat.h>
1410296Ssam #include <sys/ioctl.h>
1510296Ssam #include <sys/socket.h>
1613614Ssam #include <sys/time.h>
1736935Skarels #include <sys/file.h>
1810296Ssam
1910296Ssam #include <netinet/in.h>
2044340Skarels #include <netinet/in_systm.h>
2144340Skarels #include <netinet/ip.h>
2266670Spendry #include <arpa/inet.h>
2312397Ssam #include <arpa/ftp.h>
2426048Sminshall #include <arpa/telnet.h>
2510296Ssam
2666670Spendry #include <ctype.h>
2766670Spendry #include <err.h>
2866670Spendry #include <errno.h>
2966670Spendry #include <fcntl.h>
3010296Ssam #include <netdb.h>
3126048Sminshall #include <pwd.h>
3266670Spendry #include <signal.h>
3366670Spendry #include <stdio.h>
3454192Sbostic #include <stdlib.h>
3554192Sbostic #include <string.h>
3666670Spendry #include <unistd.h>
3766670Spendry #include <varargs.h>
3810296Ssam
3936940Skarels #include "ftp_var.h"
4036940Skarels
4166670Spendry extern int h_errno;
4266670Spendry
4310296Ssam struct sockaddr_in hisctladdr;
4410296Ssam struct sockaddr_in data_addr;
4510296Ssam int data = -1;
4626048Sminshall int abrtflag = 0;
4766670Spendry jmp_buf ptabort;
4866670Spendry int ptabflg;
4926048Sminshall int ptflag = 0;
5010296Ssam struct sockaddr_in myctladdr;
5137225Skarels off_t restart_point = 0;
5210296Ssam
5338202Srick
5410296Ssam FILE *cin, *cout;
5510296Ssam
5625904Skarels char *
hookup(host,port)5710296Ssam hookup(host, port)
5810296Ssam char *host;
5910296Ssam int port;
6010296Ssam {
6166670Spendry struct hostent *hp = 0;
6244340Skarels int s, len, tos;
6325904Skarels static char hostnamebuf[80];
6410296Ssam
6566670Spendry memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
6625904Skarels hisctladdr.sin_addr.s_addr = inet_addr(host);
6725904Skarels if (hisctladdr.sin_addr.s_addr != -1) {
6825904Skarels hisctladdr.sin_family = AF_INET;
6936940Skarels (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
7036940Skarels } else {
7125100Sbloom hp = gethostbyname(host);
7225904Skarels if (hp == NULL) {
7366670Spendry warnx("%s: %s", host, hstrerror(h_errno));
7426048Sminshall code = -1;
7566670Spendry return ((char *) 0);
7625904Skarels }
7725904Skarels hisctladdr.sin_family = hp->h_addrtype;
7866670Spendry memmove((caddr_t)&hisctladdr.sin_addr,
7966670Spendry hp->h_addr_list[0], hp->h_length);
8036940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
8110296Ssam }
8225904Skarels hostname = hostnamebuf;
8325904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8410296Ssam if (s < 0) {
8566670Spendry warn("socket");
8626048Sminshall code = -1;
8710296Ssam return (0);
8810296Ssam }
8910296Ssam hisctladdr.sin_port = port;
9038133Srick while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
9125904Skarels if (hp && hp->h_addr_list[1]) {
9225904Skarels int oerrno = errno;
9366670Spendry char *ia;
9425904Skarels
9566670Spendry ia = inet_ntoa(hisctladdr.sin_addr);
9625904Skarels errno = oerrno;
9766670Spendry warn("connect to address %s", ia);
9825904Skarels hp->h_addr_list++;
9966670Spendry memmove((caddr_t)&hisctladdr.sin_addr,
10066670Spendry hp->h_addr_list[0], hp->h_length);
10126496Sminshall fprintf(stdout, "Trying %s...\n",
10225904Skarels inet_ntoa(hisctladdr.sin_addr));
10326813Skarels (void) close(s);
10426813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10526813Skarels if (s < 0) {
10666670Spendry warn("socket");
10726813Skarels code = -1;
10826813Skarels return (0);
10926813Skarels }
11025904Skarels continue;
11125904Skarels }
11266670Spendry warn("connect");
11326048Sminshall code = -1;
11410296Ssam goto bad;
11510296Ssam }
11611627Ssam len = sizeof (myctladdr);
11738133Srick if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
11866670Spendry warn("getsockname");
11926048Sminshall code = -1;
12010296Ssam goto bad;
12110296Ssam }
12244340Skarels #ifdef IP_TOS
12344340Skarels tos = IPTOS_LOWDELAY;
12444340Skarels if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
12566670Spendry warn("setsockopt TOS (ignored)");
12644340Skarels #endif
12710296Ssam cin = fdopen(s, "r");
12810296Ssam cout = fdopen(s, "w");
12911219Ssam if (cin == NULL || cout == NULL) {
13066670Spendry warnx("fdopen failed.");
13110296Ssam if (cin)
13226496Sminshall (void) fclose(cin);
13310296Ssam if (cout)
13426496Sminshall (void) fclose(cout);
13526048Sminshall code = -1;
13610296Ssam goto bad;
13710296Ssam }
13810296Ssam if (verbose)
13926067Sminshall printf("Connected to %s.\n", hostname);
14027687Sminshall if (getreply(0) > 2) { /* read startup message from server */
14126048Sminshall if (cin)
14226496Sminshall (void) fclose(cin);
14326048Sminshall if (cout)
14426496Sminshall (void) fclose(cout);
14526048Sminshall code = -1;
14626048Sminshall goto bad;
14726048Sminshall }
14827687Sminshall #ifdef SO_OOBINLINE
14927687Sminshall {
15027687Sminshall int on = 1;
15126048Sminshall
15240193Sbostic if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
15327687Sminshall < 0 && debug) {
15466670Spendry warn("setsockopt");
15527687Sminshall }
15627687Sminshall }
15738133Srick #endif /* SO_OOBINLINE */
15826048Sminshall
15925904Skarels return (hostname);
16010296Ssam bad:
16126496Sminshall (void) close(s);
16225904Skarels return ((char *)0);
16310296Ssam }
16410296Ssam
16566670Spendry int
login(host)16625904Skarels login(host)
16725904Skarels char *host;
16810296Ssam {
16926048Sminshall char tmp[80];
17066670Spendry char *user, *pass, *acct;
17126048Sminshall int n, aflag = 0;
17210296Ssam
17326048Sminshall user = pass = acct = 0;
17426048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) {
17526048Sminshall code = -1;
17666670Spendry return (0);
17726048Sminshall }
17837458Skarels while (user == NULL) {
17926048Sminshall char *myname = getlogin();
18026048Sminshall
18126048Sminshall if (myname == NULL) {
18226048Sminshall struct passwd *pp = getpwuid(getuid());
18326048Sminshall
18426448Slepreau if (pp != NULL)
18526048Sminshall myname = pp->pw_name;
18626048Sminshall }
18737458Skarels if (myname)
18837458Skarels printf("Name (%s:%s): ", host, myname);
18937458Skarels else
19037458Skarels printf("Name (%s): ", host);
19126048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin);
19226048Sminshall tmp[strlen(tmp) - 1] = '\0';
19326448Slepreau if (*tmp == '\0')
19426048Sminshall user = myname;
19526448Slepreau else
19626048Sminshall user = tmp;
19726048Sminshall }
19810296Ssam n = command("USER %s", user);
19926048Sminshall if (n == CONTINUE) {
20026448Slepreau if (pass == NULL)
20135659Sbostic pass = getpass("Password:");
20210296Ssam n = command("PASS %s", pass);
20326048Sminshall }
20410296Ssam if (n == CONTINUE) {
20526048Sminshall aflag++;
20635659Sbostic acct = getpass("Account:");
20710296Ssam n = command("ACCT %s", acct);
20810296Ssam }
20910296Ssam if (n != COMPLETE) {
21066670Spendry warnx("Login failed.");
21110296Ssam return (0);
21210296Ssam }
21326448Slepreau if (!aflag && acct != NULL)
21426048Sminshall (void) command("ACCT %s", acct);
21526448Slepreau if (proxy)
21666670Spendry return (1);
21726048Sminshall for (n = 0; n < macnum; ++n) {
21826048Sminshall if (!strcmp("init", macros[n].mac_name)) {
21926496Sminshall (void) strcpy(line, "$init");
22026048Sminshall makeargv();
22126048Sminshall domacro(margc, margv);
22226048Sminshall break;
22326048Sminshall }
22426048Sminshall }
22510296Ssam return (1);
22610296Ssam }
22710296Ssam
22840193Sbostic void
cmdabort()22926048Sminshall cmdabort()
23026048Sminshall {
23126048Sminshall
23226048Sminshall printf("\n");
23326048Sminshall (void) fflush(stdout);
23426048Sminshall abrtflag++;
23526448Slepreau if (ptflag)
23626048Sminshall longjmp(ptabort,1);
23726048Sminshall }
23826048Sminshall
23938133Srick /*VARARGS*/
24066670Spendry int
command(va_alist)24138133Srick command(va_alist)
24238133Srick va_dcl
24338133Srick {
24438133Srick va_list ap;
24510296Ssam char *fmt;
24638133Srick int r;
24740193Sbostic sig_t oldintr;
24810296Ssam
24926048Sminshall abrtflag = 0;
25010296Ssam if (debug) {
25110296Ssam printf("---> ");
25238133Srick va_start(ap);
25338133Srick fmt = va_arg(ap, char *);
25438133Srick if (strncmp("PASS ", fmt, 5) == 0)
25538133Srick printf("PASS XXXX");
25638133Srick else
25738133Srick vfprintf(stdout, fmt, ap);
25838133Srick va_end(ap);
25910296Ssam printf("\n");
26010296Ssam (void) fflush(stdout);
26110296Ssam }
26211219Ssam if (cout == NULL) {
26366670Spendry warn("No control connection for command");
26426048Sminshall code = -1;
26511219Ssam return (0);
26611219Ssam }
26738133Srick oldintr = signal(SIGINT, cmdabort);
26838133Srick va_start(ap);
26938133Srick fmt = va_arg(ap, char *);
27038133Srick vfprintf(cout, fmt, ap);
27138133Srick va_end(ap);
27210296Ssam fprintf(cout, "\r\n");
27310296Ssam (void) fflush(cout);
27426048Sminshall cpend = 1;
27526048Sminshall r = getreply(!strcmp(fmt, "QUIT"));
27626448Slepreau if (abrtflag && oldintr != SIG_IGN)
27746828Sbostic (*oldintr)(SIGINT);
27826048Sminshall (void) signal(SIGINT, oldintr);
27966670Spendry return (r);
28010296Ssam }
28110296Ssam
28237229Skarels char reply_string[BUFSIZ]; /* last line of previous reply */
28336935Skarels
28466670Spendry int
getreply(expecteof)28510296Ssam getreply(expecteof)
28610296Ssam int expecteof;
28710296Ssam {
28866670Spendry int c, n;
28966670Spendry int dig;
29038133Srick int originalcode = 0, continuation = 0;
29140193Sbostic sig_t oldintr;
29226048Sminshall int pflag = 0;
29366670Spendry char *cp, *pt = pasv;
29410296Ssam
29538133Srick oldintr = signal(SIGINT, cmdabort);
29610296Ssam for (;;) {
29710296Ssam dig = n = code = 0;
29837229Skarels cp = reply_string;
29910296Ssam while ((c = getc(cin)) != '\n') {
30027687Sminshall if (c == IAC) { /* handle telnet commands */
30127687Sminshall switch (c = getc(cin)) {
30227687Sminshall case WILL:
30327687Sminshall case WONT:
30427687Sminshall c = getc(cin);
30538133Srick fprintf(cout, "%c%c%c", IAC, DONT, c);
30627687Sminshall (void) fflush(cout);
30727687Sminshall break;
30827687Sminshall case DO:
30927687Sminshall case DONT:
31027687Sminshall c = getc(cin);
31138133Srick fprintf(cout, "%c%c%c", IAC, WONT, c);
31227687Sminshall (void) fflush(cout);
31327687Sminshall break;
31427687Sminshall default:
31527687Sminshall break;
31627687Sminshall }
31727687Sminshall continue;
31827687Sminshall }
31910296Ssam dig++;
32010296Ssam if (c == EOF) {
32126048Sminshall if (expecteof) {
32226048Sminshall (void) signal(SIGINT,oldintr);
32326048Sminshall code = 221;
32410296Ssam return (0);
32526048Sminshall }
32610296Ssam lostpeer();
32726048Sminshall if (verbose) {
32826048Sminshall printf("421 Service not available, remote server has closed connection\n");
32926048Sminshall (void) fflush(stdout);
33026048Sminshall }
33133772Scsvsj code = 421;
33266670Spendry return (4);
33310296Ssam }
33426048Sminshall if (c != '\r' && (verbose > 0 ||
33526048Sminshall (verbose > -1 && n == '5' && dig > 4))) {
33626448Slepreau if (proxflag &&
33726448Slepreau (dig == 1 || dig == 5 && verbose == 0))
33826048Sminshall printf("%s:",hostname);
33926496Sminshall (void) putchar(c);
34026048Sminshall }
34110296Ssam if (dig < 4 && isdigit(c))
34210296Ssam code = code * 10 + (c - '0');
34326448Slepreau if (!pflag && code == 227)
34426048Sminshall pflag = 1;
34526448Slepreau if (dig > 4 && pflag == 1 && isdigit(c))
34626048Sminshall pflag = 2;
34726048Sminshall if (pflag == 2) {
34826448Slepreau if (c != '\r' && c != ')')
34926048Sminshall *pt++ = c;
35026048Sminshall else {
35126048Sminshall *pt = '\0';
35226048Sminshall pflag = 3;
35326048Sminshall }
35426048Sminshall }
35526048Sminshall if (dig == 4 && c == '-') {
35626448Slepreau if (continuation)
35726048Sminshall code = 0;
35810296Ssam continuation++;
35926048Sminshall }
36010296Ssam if (n == 0)
36110296Ssam n = c;
36237229Skarels if (cp < &reply_string[sizeof(reply_string) - 1])
36337229Skarels *cp++ = c;
36410296Ssam }
36526048Sminshall if (verbose > 0 || verbose > -1 && n == '5') {
36626496Sminshall (void) putchar(c);
36711346Ssam (void) fflush (stdout);
36811346Ssam }
36910296Ssam if (continuation && code != originalcode) {
37010296Ssam if (originalcode == 0)
37110296Ssam originalcode = code;
37210296Ssam continue;
37310296Ssam }
37436935Skarels *cp = '\0';
37526448Slepreau if (n != '1')
37626048Sminshall cpend = 0;
37726048Sminshall (void) signal(SIGINT,oldintr);
37826448Slepreau if (code == 421 || originalcode == 421)
37926048Sminshall lostpeer();
38026448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
38146828Sbostic (*oldintr)(SIGINT);
38225907Smckusick return (n - '0');
38310296Ssam }
38410296Ssam }
38510296Ssam
38666670Spendry int
empty(mask,sec)38726048Sminshall empty(mask, sec)
38827687Sminshall struct fd_set *mask;
38926048Sminshall int sec;
39026048Sminshall {
39126048Sminshall struct timeval t;
39226048Sminshall
39326048Sminshall t.tv_sec = (long) sec;
39426048Sminshall t.tv_usec = 0;
39566670Spendry return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
39626048Sminshall }
39726048Sminshall
39810296Ssam jmp_buf sendabort;
39910296Ssam
40040193Sbostic void
abortsend()40110296Ssam abortsend()
40210296Ssam {
40310296Ssam
40426048Sminshall mflag = 0;
40526048Sminshall abrtflag = 0;
40638133Srick printf("\nsend aborted\nwaiting for remote to finish abort\n");
40726048Sminshall (void) fflush(stdout);
40810296Ssam longjmp(sendabort, 1);
40910296Ssam }
41010296Ssam
41136940Skarels #define HASHBYTES 1024
41236940Skarels
41366670Spendry void
sendrequest(cmd,local,remote,printnames)41437225Skarels sendrequest(cmd, local, remote, printnames)
41510296Ssam char *cmd, *local, *remote;
41637225Skarels int printnames;
41710296Ssam {
41840193Sbostic struct stat st;
41940193Sbostic struct timeval start, stop;
42066670Spendry int c, d;
42135659Sbostic FILE *fin, *dout = 0, *popen();
42266670Spendry int (*closefunc) __P((FILE *));
42340193Sbostic sig_t oldintr, oldintp;
42436940Skarels long bytes = 0, hashbytes = HASHBYTES;
42540193Sbostic char *lmode, buf[BUFSIZ], *bufp;
42610296Ssam
42737225Skarels if (verbose && printnames) {
42837225Skarels if (local && *local != '-')
42937225Skarels printf("local: %s ", local);
43037225Skarels if (remote)
43137225Skarels printf("remote: %s\n", remote);
43237225Skarels }
43326048Sminshall if (proxy) {
43426048Sminshall proxtrans(cmd, local, remote);
43526048Sminshall return;
43626048Sminshall }
43738033Skarels if (curtype != type)
43838033Skarels changetype(type, 0);
43910296Ssam closefunc = NULL;
44026048Sminshall oldintr = NULL;
44126048Sminshall oldintp = NULL;
44240193Sbostic lmode = "w";
44326048Sminshall if (setjmp(sendabort)) {
44426048Sminshall while (cpend) {
44526048Sminshall (void) getreply(0);
44626048Sminshall }
44726048Sminshall if (data >= 0) {
44826048Sminshall (void) close(data);
44926048Sminshall data = -1;
45026048Sminshall }
45126448Slepreau if (oldintr)
45226048Sminshall (void) signal(SIGINT,oldintr);
45326448Slepreau if (oldintp)
45426048Sminshall (void) signal(SIGPIPE,oldintp);
45526048Sminshall code = -1;
45626048Sminshall return;
45726048Sminshall }
45810296Ssam oldintr = signal(SIGINT, abortsend);
45910296Ssam if (strcmp(local, "-") == 0)
46010296Ssam fin = stdin;
46110296Ssam else if (*local == '|') {
46226048Sminshall oldintp = signal(SIGPIPE,SIG_IGN);
46335659Sbostic fin = popen(local + 1, "r");
46410296Ssam if (fin == NULL) {
46566670Spendry warn("%s", local + 1);
46626048Sminshall (void) signal(SIGINT, oldintr);
46726048Sminshall (void) signal(SIGPIPE, oldintp);
46826048Sminshall code = -1;
46926048Sminshall return;
47010296Ssam }
47135659Sbostic closefunc = pclose;
47210296Ssam } else {
47310296Ssam fin = fopen(local, "r");
47410296Ssam if (fin == NULL) {
47566670Spendry warn("local: %s", local);
47626048Sminshall (void) signal(SIGINT, oldintr);
47726048Sminshall code = -1;
47826048Sminshall return;
47910296Ssam }
48010296Ssam closefunc = fclose;
48110296Ssam if (fstat(fileno(fin), &st) < 0 ||
48210296Ssam (st.st_mode&S_IFMT) != S_IFREG) {
48326496Sminshall fprintf(stdout, "%s: not a plain file.\n", local);
48426048Sminshall (void) signal(SIGINT, oldintr);
48536935Skarels fclose(fin);
48626048Sminshall code = -1;
48726048Sminshall return;
48810296Ssam }
48910296Ssam }
49026048Sminshall if (initconn()) {
49126048Sminshall (void) signal(SIGINT, oldintr);
49226448Slepreau if (oldintp)
49326048Sminshall (void) signal(SIGPIPE, oldintp);
49426048Sminshall code = -1;
49536935Skarels if (closefunc != NULL)
49636935Skarels (*closefunc)(fin);
49726048Sminshall return;
49826048Sminshall }
49926448Slepreau if (setjmp(sendabort))
50026048Sminshall goto abort;
50136935Skarels
50237225Skarels if (restart_point &&
50337225Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
50466724Spendry int rc;
50566724Spendry
50666724Spendry switch (curtype) {
50766724Spendry case TYPE_A:
50866724Spendry rc = fseek(fin, (long) restart_point, SEEK_SET);
50966724Spendry break;
51066724Spendry case TYPE_I:
51166724Spendry case TYPE_L:
51266724Spendry rc = lseek(fileno(fin), restart_point, SEEK_SET);
51366724Spendry break;
51466724Spendry }
51566724Spendry if (rc < 0) {
51666670Spendry warn("local: %s", local);
51737225Skarels restart_point = 0;
51837225Skarels if (closefunc != NULL)
51937225Skarels (*closefunc)(fin);
52037225Skarels return;
52137225Skarels }
52237225Skarels if (command("REST %ld", (long) restart_point)
52337225Skarels != CONTINUE) {
52437225Skarels restart_point = 0;
52537225Skarels if (closefunc != NULL)
52637225Skarels (*closefunc)(fin);
52737225Skarels return;
52837225Skarels }
52937225Skarels restart_point = 0;
53040193Sbostic lmode = "r+w";
53137225Skarels }
53210296Ssam if (remote) {
53326048Sminshall if (command("%s %s", cmd, remote) != PRELIM) {
53426048Sminshall (void) signal(SIGINT, oldintr);
53526448Slepreau if (oldintp)
53626048Sminshall (void) signal(SIGPIPE, oldintp);
53736935Skarels if (closefunc != NULL)
53836935Skarels (*closefunc)(fin);
53926048Sminshall return;
54026048Sminshall }
54110296Ssam } else
54226048Sminshall if (command("%s", cmd) != PRELIM) {
54326048Sminshall (void) signal(SIGINT, oldintr);
54426448Slepreau if (oldintp)
54526048Sminshall (void) signal(SIGPIPE, oldintp);
54636935Skarels if (closefunc != NULL)
54736935Skarels (*closefunc)(fin);
54826048Sminshall return;
54926048Sminshall }
55040193Sbostic dout = dataconn(lmode);
55126448Slepreau if (dout == NULL)
55226048Sminshall goto abort;
55326496Sminshall (void) gettimeofday(&start, (struct timezone *)0);
55436935Skarels oldintp = signal(SIGPIPE, SIG_IGN);
55542278Skarels switch (curtype) {
55611219Ssam
55711219Ssam case TYPE_I:
55811219Ssam case TYPE_L:
55911346Ssam errno = d = 0;
56036942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
56111219Ssam bytes += c;
56236942Skarels for (bufp = buf; c > 0; c -= d, bufp += d)
56336942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0)
56436942Skarels break;
56511651Ssam if (hash) {
56636940Skarels while (bytes >= hashbytes) {
56736940Skarels (void) putchar('#');
56836940Skarels hashbytes += HASHBYTES;
56936940Skarels }
57026496Sminshall (void) fflush(stdout);
57111651Ssam }
57211219Ssam }
57313213Ssam if (hash && bytes > 0) {
57436940Skarels if (bytes < HASHBYTES)
57536940Skarels (void) putchar('#');
57626496Sminshall (void) putchar('\n');
57726496Sminshall (void) fflush(stdout);
57811651Ssam }
57911219Ssam if (c < 0)
58066670Spendry warn("local: %s", local);
58148507Srick if (d < 0) {
58248507Srick if (errno != EPIPE)
58366670Spendry warn("netout");
58436935Skarels bytes = -1;
58536935Skarels }
58611219Ssam break;
58711219Ssam
58811219Ssam case TYPE_A:
58911219Ssam while ((c = getc(fin)) != EOF) {
59011219Ssam if (c == '\n') {
59111651Ssam while (hash && (bytes >= hashbytes)) {
59226496Sminshall (void) putchar('#');
59326496Sminshall (void) fflush(stdout);
59436940Skarels hashbytes += HASHBYTES;
59511651Ssam }
59611219Ssam if (ferror(dout))
59711219Ssam break;
59826496Sminshall (void) putc('\r', dout);
59911219Ssam bytes++;
60011219Ssam }
60126496Sminshall (void) putc(c, dout);
60211219Ssam bytes++;
60326048Sminshall /* if (c == '\r') { */
60466670Spendry /* (void) putc('\0', dout); // this violates rfc */
60526048Sminshall /* bytes++; */
60626048Sminshall /* } */
60711219Ssam }
60811651Ssam if (hash) {
60913213Ssam if (bytes < hashbytes)
61026496Sminshall (void) putchar('#');
61126496Sminshall (void) putchar('\n');
61226496Sminshall (void) fflush(stdout);
61311651Ssam }
61411219Ssam if (ferror(fin))
61566670Spendry warn("local: %s", local);
61636935Skarels if (ferror(dout)) {
61736935Skarels if (errno != EPIPE)
61866670Spendry warn("netout");
61936935Skarels bytes = -1;
62036935Skarels }
62111219Ssam break;
62210296Ssam }
62310296Ssam if (closefunc != NULL)
62426048Sminshall (*closefunc)(fin);
62510296Ssam (void) fclose(dout);
626*67865Smckusick (void) gettimeofday(&stop, (struct timezone *)0);
62726048Sminshall (void) getreply(0);
62826048Sminshall (void) signal(SIGINT, oldintr);
62936935Skarels if (oldintp)
63036935Skarels (void) signal(SIGPIPE, oldintp);
63135699Sbostic if (bytes > 0)
63237225Skarels ptransfer("sent", bytes, &start, &stop);
63310296Ssam return;
63426048Sminshall abort:
63526048Sminshall (void) signal(SIGINT, oldintr);
63626448Slepreau if (oldintp)
63726048Sminshall (void) signal(SIGPIPE, oldintp);
63826048Sminshall if (!cpend) {
63926048Sminshall code = -1;
64026048Sminshall return;
64126048Sminshall }
64226048Sminshall if (data >= 0) {
64326048Sminshall (void) close(data);
64426048Sminshall data = -1;
64526048Sminshall }
64626448Slepreau if (dout)
64726048Sminshall (void) fclose(dout);
64826048Sminshall (void) getreply(0);
64926048Sminshall code = -1;
65010296Ssam if (closefunc != NULL && fin != NULL)
65126048Sminshall (*closefunc)(fin);
652*67865Smckusick (void) gettimeofday(&stop, (struct timezone *)0);
65335699Sbostic if (bytes > 0)
65437225Skarels ptransfer("sent", bytes, &start, &stop);
65510296Ssam }
65610296Ssam
65710296Ssam jmp_buf recvabort;
65810296Ssam
65940193Sbostic void
abortrecv()66010296Ssam abortrecv()
66110296Ssam {
66210296Ssam
66326048Sminshall mflag = 0;
66426048Sminshall abrtflag = 0;
66538133Srick printf("\nreceive aborted\nwaiting for remote to finish abort\n");
66626048Sminshall (void) fflush(stdout);
66710296Ssam longjmp(recvabort, 1);
66810296Ssam }
66910296Ssam
67066670Spendry void
recvrequest(cmd,local,remote,lmode,printnames)67140193Sbostic recvrequest(cmd, local, remote, lmode, printnames)
67240193Sbostic char *cmd, *local, *remote, *lmode;
67366670Spendry int printnames;
67410296Ssam {
67566670Spendry FILE *fout, *din = 0;
67666670Spendry int (*closefunc) __P((FILE *));
67740193Sbostic sig_t oldintr, oldintp;
67866670Spendry int c, d, is_retr, tcrflag, bare_lfs = 0;
67938133Srick static int bufsize;
68036944Skarels static char *buf;
68136940Skarels long bytes = 0, hashbytes = HASHBYTES;
68210296Ssam struct timeval start, stop;
68336940Skarels struct stat st;
68410296Ssam
68536935Skarels is_retr = strcmp(cmd, "RETR") == 0;
68637225Skarels if (is_retr && verbose && printnames) {
68737225Skarels if (local && *local != '-')
68837225Skarels printf("local: %s ", local);
68937225Skarels if (remote)
69037225Skarels printf("remote: %s\n", remote);
69137225Skarels }
69236935Skarels if (proxy && is_retr) {
69326048Sminshall proxtrans(cmd, local, remote);
69426048Sminshall return;
69526048Sminshall }
69610296Ssam closefunc = NULL;
69726048Sminshall oldintr = NULL;
69826048Sminshall oldintp = NULL;
69936935Skarels tcrflag = !crflag && is_retr;
70026048Sminshall if (setjmp(recvabort)) {
70126048Sminshall while (cpend) {
70226048Sminshall (void) getreply(0);
70326048Sminshall }
70426048Sminshall if (data >= 0) {
70526048Sminshall (void) close(data);
70626048Sminshall data = -1;
70726048Sminshall }
70826448Slepreau if (oldintr)
70926048Sminshall (void) signal(SIGINT, oldintr);
71026048Sminshall code = -1;
71126048Sminshall return;
71226048Sminshall }
71310296Ssam oldintr = signal(SIGINT, abortrecv);
71426048Sminshall if (strcmp(local, "-") && *local != '|') {
71510296Ssam if (access(local, 2) < 0) {
71666670Spendry char *dir = strrchr(local, '/');
71710296Ssam
71826048Sminshall if (errno != ENOENT && errno != EACCES) {
71966670Spendry warn("local: %s", local);
72026048Sminshall (void) signal(SIGINT, oldintr);
72126048Sminshall code = -1;
72226048Sminshall return;
72310296Ssam }
72426048Sminshall if (dir != NULL)
72526048Sminshall *dir = 0;
72626048Sminshall d = access(dir ? local : ".", 2);
72726048Sminshall if (dir != NULL)
72826048Sminshall *dir = '/';
72926048Sminshall if (d < 0) {
73066670Spendry warn("local: %s", local);
73126048Sminshall (void) signal(SIGINT, oldintr);
73226048Sminshall code = -1;
73326048Sminshall return;
73426048Sminshall }
73526048Sminshall if (!runique && errno == EACCES &&
73636935Skarels chmod(local, 0600) < 0) {
73766670Spendry warn("local: %s", local);
73826048Sminshall (void) signal(SIGINT, oldintr);
73938202Srick (void) signal(SIGINT, oldintr);
74026048Sminshall code = -1;
74126048Sminshall return;
74226048Sminshall }
74326048Sminshall if (runique && errno == EACCES &&
74426048Sminshall (local = gunique(local)) == NULL) {
74526048Sminshall (void) signal(SIGINT, oldintr);
74626048Sminshall code = -1;
74726048Sminshall return;
74826048Sminshall }
74910296Ssam }
75026048Sminshall else if (runique && (local = gunique(local)) == NULL) {
75126048Sminshall (void) signal(SIGINT, oldintr);
75226048Sminshall code = -1;
75326048Sminshall return;
75426048Sminshall }
75526048Sminshall }
75638033Skarels if (!is_retr) {
75738033Skarels if (curtype != TYPE_A)
75838033Skarels changetype(TYPE_A, 0);
75938033Skarels } else if (curtype != type)
76038033Skarels changetype(type, 0);
76126048Sminshall if (initconn()) {
76226048Sminshall (void) signal(SIGINT, oldintr);
76326048Sminshall code = -1;
76426048Sminshall return;
76526048Sminshall }
76626448Slepreau if (setjmp(recvabort))
76726048Sminshall goto abort;
76838033Skarels if (is_retr && restart_point &&
76938033Skarels command("REST %ld", (long) restart_point) != CONTINUE)
77038033Skarels return;
77110296Ssam if (remote) {
77226048Sminshall if (command("%s %s", cmd, remote) != PRELIM) {
77326048Sminshall (void) signal(SIGINT, oldintr);
77426048Sminshall return;
77526048Sminshall }
77626048Sminshall } else {
77726048Sminshall if (command("%s", cmd) != PRELIM) {
77826048Sminshall (void) signal(SIGINT, oldintr);
77926048Sminshall return;
78026048Sminshall }
78126048Sminshall }
78226048Sminshall din = dataconn("r");
78326048Sminshall if (din == NULL)
78426048Sminshall goto abort;
78526448Slepreau if (strcmp(local, "-") == 0)
78610296Ssam fout = stdout;
78710296Ssam else if (*local == '|') {
78826048Sminshall oldintp = signal(SIGPIPE, SIG_IGN);
78935659Sbostic fout = popen(local + 1, "w");
79026048Sminshall if (fout == NULL) {
79166670Spendry warn("%s", local+1);
79226048Sminshall goto abort;
79326048Sminshall }
79435659Sbostic closefunc = pclose;
79536940Skarels } else {
79640193Sbostic fout = fopen(local, lmode);
79726048Sminshall if (fout == NULL) {
79866670Spendry warn("local: %s", local);
79926048Sminshall goto abort;
80026048Sminshall }
80110296Ssam closefunc = fclose;
80210296Ssam }
80336940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
80436940Skarels st.st_blksize = BUFSIZ;
80536940Skarels if (st.st_blksize > bufsize) {
80636940Skarels if (buf)
80736940Skarels (void) free(buf);
80838133Srick buf = malloc((unsigned)st.st_blksize);
80936940Skarels if (buf == NULL) {
81066670Spendry warn("malloc");
81136944Skarels bufsize = 0;
81236940Skarels goto abort;
81336940Skarels }
81436940Skarels bufsize = st.st_blksize;
81536940Skarels }
81626496Sminshall (void) gettimeofday(&start, (struct timezone *)0);
81738033Skarels switch (curtype) {
81811219Ssam
81911219Ssam case TYPE_I:
82011219Ssam case TYPE_L:
82137225Skarels if (restart_point &&
82266724Spendry lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
82366670Spendry warn("local: %s", local);
82437225Skarels if (closefunc != NULL)
82537225Skarels (*closefunc)(fout);
82637225Skarels return;
82737225Skarels }
82811346Ssam errno = d = 0;
82936940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) {
83036944Skarels if ((d = write(fileno(fout), buf, c)) != c)
83111219Ssam break;
83211219Ssam bytes += c;
83311651Ssam if (hash) {
83436940Skarels while (bytes >= hashbytes) {
83536940Skarels (void) putchar('#');
83636940Skarels hashbytes += HASHBYTES;
83736940Skarels }
83826496Sminshall (void) fflush(stdout);
83911651Ssam }
84011219Ssam }
84113213Ssam if (hash && bytes > 0) {
84236940Skarels if (bytes < HASHBYTES)
84336940Skarels (void) putchar('#');
84426496Sminshall (void) putchar('\n');
84526496Sminshall (void) fflush(stdout);
84611651Ssam }
84736935Skarels if (c < 0) {
84836935Skarels if (errno != EPIPE)
84966670Spendry warn("netin");
85036935Skarels bytes = -1;
85136935Skarels }
85236942Skarels if (d < c) {
85336942Skarels if (d < 0)
85466670Spendry warn("local: %s", local);
85536942Skarels else
85666670Spendry warnx("%s: short write", local);
85736942Skarels }
85811219Ssam break;
85911219Ssam
86011219Ssam case TYPE_A:
86137225Skarels if (restart_point) {
86266670Spendry int i, n, ch;
86337225Skarels
86466724Spendry if (fseek(fout, 0L, SEEK_SET) < 0)
86537225Skarels goto done;
86637225Skarels n = restart_point;
86740193Sbostic for (i = 0; i++ < n;) {
86840193Sbostic if ((ch = getc(fout)) == EOF)
86937225Skarels goto done;
87040193Sbostic if (ch == '\n')
87137225Skarels i++;
87237225Skarels }
87366724Spendry if (fseek(fout, 0L, SEEK_CUR) < 0) {
87437225Skarels done:
87566670Spendry warn("local: %s", local);
87637225Skarels if (closefunc != NULL)
87737225Skarels (*closefunc)(fout);
87837225Skarels return;
87937225Skarels }
88037225Skarels }
88111219Ssam while ((c = getc(din)) != EOF) {
88238133Srick if (c == '\n')
88338133Srick bare_lfs++;
88427749Sminshall while (c == '\r') {
88511651Ssam while (hash && (bytes >= hashbytes)) {
88626496Sminshall (void) putchar('#');
88726496Sminshall (void) fflush(stdout);
88836940Skarels hashbytes += HASHBYTES;
88911651Ssam }
89010296Ssam bytes++;
89126048Sminshall if ((c = getc(din)) != '\n' || tcrflag) {
89236940Skarels if (ferror(fout))
89336940Skarels goto break2;
89436940Skarels (void) putc('\r', fout);
89536942Skarels if (c == '\0') {
89636942Skarels bytes++;
89736940Skarels goto contin2;
89836942Skarels }
89936942Skarels if (c == EOF)
90036942Skarels goto contin2;
90111219Ssam }
90211219Ssam }
90336940Skarels (void) putc(c, fout);
90411219Ssam bytes++;
90536940Skarels contin2: ;
90610296Ssam }
90736940Skarels break2:
90838133Srick if (bare_lfs) {
90938133Srick printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
91038133Srick printf("File may not have transferred correctly.\n");
91138133Srick }
91211651Ssam if (hash) {
91313213Ssam if (bytes < hashbytes)
91426496Sminshall (void) putchar('#');
91526496Sminshall (void) putchar('\n');
91626496Sminshall (void) fflush(stdout);
91711651Ssam }
91836944Skarels if (ferror(din)) {
91936935Skarels if (errno != EPIPE)
92066670Spendry warn("netin");
92136935Skarels bytes = -1;
92236935Skarels }
92336940Skarels if (ferror(fout))
92466670Spendry warn("local: %s", local);
92511219Ssam break;
92610296Ssam }
92726448Slepreau if (closefunc != NULL)
92826048Sminshall (*closefunc)(fout);
92926496Sminshall (void) signal(SIGINT, oldintr);
93026448Slepreau if (oldintp)
93126048Sminshall (void) signal(SIGPIPE, oldintp);
932*67865Smckusick (void) fclose(din);
93326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0);
93426048Sminshall (void) getreply(0);
93536935Skarels if (bytes > 0 && is_retr)
93637225Skarels ptransfer("received", bytes, &start, &stop);
93726048Sminshall return;
93826048Sminshall abort:
93926048Sminshall
94027687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */
94126048Sminshall
94226448Slepreau if (oldintp)
94326048Sminshall (void) signal(SIGPIPE, oldintr);
94438133Srick (void) signal(SIGINT, SIG_IGN);
94526048Sminshall if (!cpend) {
94626048Sminshall code = -1;
94738133Srick (void) signal(SIGINT, oldintr);
94826048Sminshall return;
94926048Sminshall }
95026048Sminshall
95138133Srick abort_remote(din);
95226048Sminshall code = -1;
95326048Sminshall if (data >= 0) {
95426048Sminshall (void) close(data);
95526048Sminshall data = -1;
95626048Sminshall }
95726448Slepreau if (closefunc != NULL && fout != NULL)
95826048Sminshall (*closefunc)(fout);
95926448Slepreau if (din)
96026048Sminshall (void) fclose(din);
961*67865Smckusick (void) gettimeofday(&stop, (struct timezone *)0);
96235699Sbostic if (bytes > 0)
96337225Skarels ptransfer("received", bytes, &start, &stop);
96438133Srick (void) signal(SIGINT, oldintr);
96510296Ssam }
96610296Ssam
96710296Ssam /*
96840193Sbostic * Need to start a listen on the data channel before we send the command,
96940193Sbostic * otherwise the server's connect may fail.
97010296Ssam */
97166670Spendry int
initconn()97210296Ssam initconn()
97310296Ssam {
97466670Spendry char *p, *a;
97526048Sminshall int result, len, tmpno = 0;
97626993Skarels int on = 1;
97767794Smckusick int a0, a1, a2, a3, p0, p1;
97810296Ssam
97967794Smckusick if (passivemode) {
98067794Smckusick data = socket(AF_INET, SOCK_STREAM, 0);
98167794Smckusick if (data < 0) {
98267794Smckusick perror("ftp: socket");
98367794Smckusick return(1);
98467794Smckusick }
98567794Smckusick if ((options & SO_DEBUG) &&
98667794Smckusick setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
98767794Smckusick sizeof (on)) < 0)
98867794Smckusick perror("ftp: setsockopt (ignored)");
98967794Smckusick if (command("PASV") != COMPLETE) {
99067794Smckusick printf("Passive mode refused.\n");
99167794Smckusick goto bad;
99267794Smckusick }
99367794Smckusick
99467794Smckusick /*
99567794Smckusick * What we've got at this point is a string of comma
99667794Smckusick * separated one-byte unsigned integer values.
99767794Smckusick * The first four are the an IP address. The fifth is
99867794Smckusick * the MSB of the port number, the sixth is the LSB.
99967794Smckusick * From that we'll prepare a sockaddr_in.
100067794Smckusick */
100167794Smckusick
100267794Smckusick if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",
100367794Smckusick &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
100467794Smckusick printf("Passive mode address scan failure. "
100567794Smckusick "Shouldn't happen!\n");
100667794Smckusick goto bad;
100767794Smckusick }
100867794Smckusick
100967794Smckusick bzero(&data_addr, sizeof(data_addr));
101067794Smckusick data_addr.sin_family = AF_INET;
101167794Smckusick a = (char *)&data_addr.sin_addr.s_addr;
101267794Smckusick a[0] = a0 & 0xff;
101367794Smckusick a[1] = a1 & 0xff;
101467794Smckusick a[2] = a2 & 0xff;
101567794Smckusick a[3] = a3 & 0xff;
101667794Smckusick p = (char *)&data_addr.sin_port;
101767794Smckusick p[0] = p0 & 0xff;
101867794Smckusick p[1] = p1 & 0xff;
101967794Smckusick
102067794Smckusick if (connect(data, (struct sockaddr *)&data_addr,
102167794Smckusick sizeof(data_addr)) < 0) {
102267794Smckusick perror("ftp: connect");
102367794Smckusick goto bad;
102467794Smckusick }
102567794Smckusick #ifdef IP_TOS
102667794Smckusick on = IPTOS_THROUGHPUT;
102767794Smckusick if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
102867794Smckusick sizeof(int)) < 0)
102967794Smckusick perror("ftp: setsockopt TOS (ignored)");
103067794Smckusick #endif
103167794Smckusick return(0);
103267794Smckusick }
103367794Smckusick
103411651Ssam noport:
103510296Ssam data_addr = myctladdr;
103611651Ssam if (sendport)
103711651Ssam data_addr.sin_port = 0; /* let system pick one */
103811651Ssam if (data != -1)
103938133Srick (void) close(data);
104018287Sralph data = socket(AF_INET, SOCK_STREAM, 0);
104110296Ssam if (data < 0) {
104266670Spendry warn("socket");
104326448Slepreau if (tmpno)
104426048Sminshall sendport = 1;
104510296Ssam return (1);
104610296Ssam }
104712397Ssam if (!sendport)
104827687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
104966670Spendry warn("setsockopt (reuse address)");
105012397Ssam goto bad;
105112397Ssam }
105226496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
105366670Spendry warn("bind");
105410296Ssam goto bad;
105510296Ssam }
105610296Ssam if (options & SO_DEBUG &&
105727687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
105866670Spendry warn("setsockopt (ignored)");
105911627Ssam len = sizeof (data_addr);
106038133Srick if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
106166670Spendry warn("getsockname");
106210296Ssam goto bad;
106310296Ssam }
106426448Slepreau if (listen(data, 1) < 0)
106566670Spendry warn("listen");
106611651Ssam if (sendport) {
106711651Ssam a = (char *)&data_addr.sin_addr;
106811651Ssam p = (char *)&data_addr.sin_port;
106910296Ssam #define UC(b) (((int)b)&0xff)
107011651Ssam result =
107111651Ssam command("PORT %d,%d,%d,%d,%d,%d",
107211651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
107311651Ssam UC(p[0]), UC(p[1]));
107411651Ssam if (result == ERROR && sendport == -1) {
107511651Ssam sendport = 0;
107626048Sminshall tmpno = 1;
107711651Ssam goto noport;
107811651Ssam }
107911651Ssam return (result != COMPLETE);
108011651Ssam }
108126448Slepreau if (tmpno)
108226048Sminshall sendport = 1;
108344340Skarels #ifdef IP_TOS
108444340Skarels on = IPTOS_THROUGHPUT;
108544340Skarels if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
108666670Spendry warn("setsockopt TOS (ignored)");
108744340Skarels #endif
108811651Ssam return (0);
108910296Ssam bad:
109010296Ssam (void) close(data), data = -1;
109126448Slepreau if (tmpno)
109226048Sminshall sendport = 1;
109310296Ssam return (1);
109410296Ssam }
109510296Ssam
109610296Ssam FILE *
dataconn(lmode)109740193Sbostic dataconn(lmode)
109840193Sbostic char *lmode;
109910296Ssam {
110010296Ssam struct sockaddr_in from;
110144340Skarels int s, fromlen = sizeof (from), tos;
110210296Ssam
110367794Smckusick if (passivemode)
110467794Smckusick return (fdopen(data, lmode));
110567794Smckusick
110626496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen);
110710296Ssam if (s < 0) {
110866670Spendry warn("accept");
110910296Ssam (void) close(data), data = -1;
111010296Ssam return (NULL);
111110296Ssam }
111210296Ssam (void) close(data);
111310296Ssam data = s;
111444340Skarels #ifdef IP_TOS
111544340Skarels tos = IPTOS_THROUGHPUT;
111644340Skarels if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
111766670Spendry warn("setsockopt TOS (ignored)");
111844340Skarels #endif
111940193Sbostic return (fdopen(data, lmode));
112010296Ssam }
112110296Ssam
112266670Spendry void
ptransfer(direction,bytes,t0,t1)112337225Skarels ptransfer(direction, bytes, t0, t1)
112437225Skarels char *direction;
112511651Ssam long bytes;
112610296Ssam struct timeval *t0, *t1;
112710296Ssam {
112810296Ssam struct timeval td;
112967794Smckusick float s;
113067794Smckusick long bs;
113110296Ssam
113235699Sbostic if (verbose) {
113335699Sbostic tvsub(&td, t1, t0);
113435699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.);
113510296Ssam #define nz(x) ((x) == 0 ? 1 : (x))
113635699Sbostic bs = bytes / nz(s);
113767794Smckusick printf("%ld bytes %s in %.3g seconds (%ld bytes/s)\n",
113867794Smckusick bytes, direction, s, bs);
113935699Sbostic }
114010296Ssam }
114110296Ssam
114266670Spendry /*
114366670Spendry void
114466670Spendry tvadd(tsum, t0)
114510296Ssam struct timeval *tsum, *t0;
114610296Ssam {
114710296Ssam
114810296Ssam tsum->tv_sec += t0->tv_sec;
114910296Ssam tsum->tv_usec += t0->tv_usec;
115010296Ssam if (tsum->tv_usec > 1000000)
115110296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000;
115266670Spendry }
115366670Spendry */
115410296Ssam
115566670Spendry void
tvsub(tdiff,t1,t0)115610296Ssam tvsub(tdiff, t1, t0)
115710296Ssam struct timeval *tdiff, *t1, *t0;
115810296Ssam {
115910296Ssam
116010296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
116110296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
116210296Ssam if (tdiff->tv_usec < 0)
116310296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000;
116410296Ssam }
116526048Sminshall
116640193Sbostic void
psabort()116726048Sminshall psabort()
116826048Sminshall {
116926048Sminshall
117026048Sminshall abrtflag++;
117126048Sminshall }
117226048Sminshall
117366670Spendry void
pswitch(flag)117426048Sminshall pswitch(flag)
117526048Sminshall int flag;
117626048Sminshall {
117740193Sbostic sig_t oldintr;
117826048Sminshall static struct comvars {
117926048Sminshall int connect;
118028469Skarels char name[MAXHOSTNAMELEN];
118126048Sminshall struct sockaddr_in mctl;
118226048Sminshall struct sockaddr_in hctl;
118326048Sminshall FILE *in;
118426048Sminshall FILE *out;
118526048Sminshall int tpe;
118638033Skarels int curtpe;
118726048Sminshall int cpnd;
118826048Sminshall int sunqe;
118926048Sminshall int runqe;
119026048Sminshall int mcse;
119126048Sminshall int ntflg;
119226048Sminshall char nti[17];
119326048Sminshall char nto[17];
119426048Sminshall int mapflg;
119526048Sminshall char mi[MAXPATHLEN];
119626048Sminshall char mo[MAXPATHLEN];
119738033Skarels } proxstruct, tmpstruct;
119826048Sminshall struct comvars *ip, *op;
119926048Sminshall
120026048Sminshall abrtflag = 0;
120126048Sminshall oldintr = signal(SIGINT, psabort);
120226048Sminshall if (flag) {
120326448Slepreau if (proxy)
120426048Sminshall return;
120526048Sminshall ip = &tmpstruct;
120626048Sminshall op = &proxstruct;
120726048Sminshall proxy++;
120838033Skarels } else {
120926448Slepreau if (!proxy)
121026048Sminshall return;
121126048Sminshall ip = &proxstruct;
121226048Sminshall op = &tmpstruct;
121326048Sminshall proxy = 0;
121426048Sminshall }
121526048Sminshall ip->connect = connected;
121626048Sminshall connected = op->connect;
121728469Skarels if (hostname) {
121828469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
121928469Skarels ip->name[strlen(ip->name)] = '\0';
122028469Skarels } else
122128469Skarels ip->name[0] = 0;
122226048Sminshall hostname = op->name;
122326048Sminshall ip->hctl = hisctladdr;
122426048Sminshall hisctladdr = op->hctl;
122526048Sminshall ip->mctl = myctladdr;
122626048Sminshall myctladdr = op->mctl;
122726048Sminshall ip->in = cin;
122826048Sminshall cin = op->in;
122926048Sminshall ip->out = cout;
123026048Sminshall cout = op->out;
123126048Sminshall ip->tpe = type;
123226048Sminshall type = op->tpe;
123338033Skarels ip->curtpe = curtype;
123438033Skarels curtype = op->curtpe;
123526048Sminshall ip->cpnd = cpend;
123626048Sminshall cpend = op->cpnd;
123726048Sminshall ip->sunqe = sunique;
123826048Sminshall sunique = op->sunqe;
123926048Sminshall ip->runqe = runique;
124026048Sminshall runique = op->runqe;
124126048Sminshall ip->mcse = mcase;
124226048Sminshall mcase = op->mcse;
124326048Sminshall ip->ntflg = ntflag;
124426048Sminshall ntflag = op->ntflg;
124526496Sminshall (void) strncpy(ip->nti, ntin, 16);
124626048Sminshall (ip->nti)[strlen(ip->nti)] = '\0';
124726496Sminshall (void) strcpy(ntin, op->nti);
124826496Sminshall (void) strncpy(ip->nto, ntout, 16);
124926048Sminshall (ip->nto)[strlen(ip->nto)] = '\0';
125026496Sminshall (void) strcpy(ntout, op->nto);
125126048Sminshall ip->mapflg = mapflag;
125226048Sminshall mapflag = op->mapflg;
125326496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
125426048Sminshall (ip->mi)[strlen(ip->mi)] = '\0';
125526496Sminshall (void) strcpy(mapin, op->mi);
125626496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
125726048Sminshall (ip->mo)[strlen(ip->mo)] = '\0';
125826496Sminshall (void) strcpy(mapout, op->mo);
125926048Sminshall (void) signal(SIGINT, oldintr);
126026048Sminshall if (abrtflag) {
126126048Sminshall abrtflag = 0;
126246828Sbostic (*oldintr)(SIGINT);
126326448Slepreau }
126426048Sminshall }
126526048Sminshall
126640193Sbostic void
abortpt()126726048Sminshall abortpt()
126826048Sminshall {
126966670Spendry
127026048Sminshall printf("\n");
127126496Sminshall (void) fflush(stdout);
127226048Sminshall ptabflg++;
127326048Sminshall mflag = 0;
127426048Sminshall abrtflag = 0;
127526048Sminshall longjmp(ptabort, 1);
127626048Sminshall }
127726048Sminshall
127866670Spendry void
proxtrans(cmd,local,remote)127926048Sminshall proxtrans(cmd, local, remote)
128026048Sminshall char *cmd, *local, *remote;
128126048Sminshall {
128240193Sbostic sig_t oldintr;
128338133Srick int secndflag = 0, prox_type, nfnd;
128426048Sminshall char *cmd2;
128526496Sminshall struct fd_set mask;
128626048Sminshall
128726448Slepreau if (strcmp(cmd, "RETR"))
128826048Sminshall cmd2 = "RETR";
128926448Slepreau else
129026048Sminshall cmd2 = runique ? "STOU" : "STOR";
129138033Skarels if ((prox_type = type) == 0) {
129238033Skarels if (unix_server && unix_proxy)
129338033Skarels prox_type = TYPE_I;
129438033Skarels else
129538033Skarels prox_type = TYPE_A;
129638033Skarels }
129738033Skarels if (curtype != prox_type)
129838033Skarels changetype(prox_type, 1);
129926048Sminshall if (command("PASV") != COMPLETE) {
130038033Skarels printf("proxy server does not support third party transfers.\n");
130126048Sminshall return;
130226048Sminshall }
130326048Sminshall pswitch(0);
130426048Sminshall if (!connected) {
130526048Sminshall printf("No primary connection\n");
130626048Sminshall pswitch(1);
130726048Sminshall code = -1;
130826048Sminshall return;
130926048Sminshall }
131038033Skarels if (curtype != prox_type)
131138033Skarels changetype(prox_type, 1);
131226048Sminshall if (command("PORT %s", pasv) != COMPLETE) {
131326048Sminshall pswitch(1);
131426048Sminshall return;
131526048Sminshall }
131626448Slepreau if (setjmp(ptabort))
131726048Sminshall goto abort;
131826048Sminshall oldintr = signal(SIGINT, abortpt);
131926048Sminshall if (command("%s %s", cmd, remote) != PRELIM) {
132026048Sminshall (void) signal(SIGINT, oldintr);
132126048Sminshall pswitch(1);
132226048Sminshall return;
132326048Sminshall }
132426048Sminshall sleep(2);
132526048Sminshall pswitch(1);
132626048Sminshall secndflag++;
132726448Slepreau if (command("%s %s", cmd2, local) != PRELIM)
132826048Sminshall goto abort;
132926048Sminshall ptflag++;
133026048Sminshall (void) getreply(0);
133126048Sminshall pswitch(0);
133226048Sminshall (void) getreply(0);
133326048Sminshall (void) signal(SIGINT, oldintr);
133426048Sminshall pswitch(1);
133526048Sminshall ptflag = 0;
133626048Sminshall printf("local: %s remote: %s\n", local, remote);
133726048Sminshall return;
133826048Sminshall abort:
133926048Sminshall (void) signal(SIGINT, SIG_IGN);
134026048Sminshall ptflag = 0;
134126448Slepreau if (strcmp(cmd, "RETR") && !proxy)
134226048Sminshall pswitch(1);
134326448Slepreau else if (!strcmp(cmd, "RETR") && proxy)
134426048Sminshall pswitch(0);
134526048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
134626048Sminshall if (command("%s %s", cmd2, local) != PRELIM) {
134726048Sminshall pswitch(0);
134838133Srick if (cpend)
134938133Srick abort_remote((FILE *) NULL);
135026048Sminshall }
135126048Sminshall pswitch(1);
135226448Slepreau if (ptabflg)
135326048Sminshall code = -1;
135426048Sminshall (void) signal(SIGINT, oldintr);
135526048Sminshall return;
135626048Sminshall }
135738133Srick if (cpend)
135838133Srick abort_remote((FILE *) NULL);
135926048Sminshall pswitch(!proxy);
136026048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
136126048Sminshall if (command("%s %s", cmd2, local) != PRELIM) {
136226048Sminshall pswitch(0);
136338133Srick if (cpend)
136438133Srick abort_remote((FILE *) NULL);
136526048Sminshall pswitch(1);
136626448Slepreau if (ptabflg)
136726048Sminshall code = -1;
136826048Sminshall (void) signal(SIGINT, oldintr);
136926048Sminshall return;
137026048Sminshall }
137126048Sminshall }
137238133Srick if (cpend)
137338133Srick abort_remote((FILE *) NULL);
137426048Sminshall pswitch(!proxy);
137526048Sminshall if (cpend) {
137627687Sminshall FD_ZERO(&mask);
137726496Sminshall FD_SET(fileno(cin), &mask);
137838133Srick if ((nfnd = empty(&mask, 10)) <= 0) {
137927687Sminshall if (nfnd < 0) {
138066670Spendry warn("abort");
138127687Sminshall }
138226448Slepreau if (ptabflg)
138326048Sminshall code = -1;
138426048Sminshall lostpeer();
138526048Sminshall }
138626048Sminshall (void) getreply(0);
138726048Sminshall (void) getreply(0);
138826048Sminshall }
138926448Slepreau if (proxy)
139026048Sminshall pswitch(0);
139126048Sminshall pswitch(1);
139226448Slepreau if (ptabflg)
139326048Sminshall code = -1;
139426048Sminshall (void) signal(SIGINT, oldintr);
139526048Sminshall }
139626048Sminshall
139766670Spendry void
reset(argc,argv)139866670Spendry reset(argc, argv)
139966670Spendry int argc;
140066670Spendry char *argv[];
140126048Sminshall {
140226496Sminshall struct fd_set mask;
140326496Sminshall int nfnd = 1;
140426048Sminshall
140527687Sminshall FD_ZERO(&mask);
140630946Scsvsj while (nfnd > 0) {
140726496Sminshall FD_SET(fileno(cin), &mask);
140827687Sminshall if ((nfnd = empty(&mask,0)) < 0) {
140966670Spendry warn("reset");
141026048Sminshall code = -1;
141126048Sminshall lostpeer();
141226048Sminshall }
141327687Sminshall else if (nfnd) {
141426048Sminshall (void) getreply(0);
141526496Sminshall }
141626048Sminshall }
141726048Sminshall }
141826048Sminshall
141926048Sminshall char *
gunique(local)142026048Sminshall gunique(local)
142126048Sminshall char *local;
142226048Sminshall {
142326048Sminshall static char new[MAXPATHLEN];
142466670Spendry char *cp = strrchr(local, '/');
142526048Sminshall int d, count=0;
142626048Sminshall char ext = '1';
142726048Sminshall
142826448Slepreau if (cp)
142926048Sminshall *cp = '\0';
143026048Sminshall d = access(cp ? local : ".", 2);
143126448Slepreau if (cp)
143226048Sminshall *cp = '/';
143326048Sminshall if (d < 0) {
143466670Spendry warn("local: %s", local);
143566670Spendry return ((char *) 0);
143626048Sminshall }
143726048Sminshall (void) strcpy(new, local);
143826048Sminshall cp = new + strlen(new);
143926048Sminshall *cp++ = '.';
144026048Sminshall while (!d) {
144126048Sminshall if (++count == 100) {
144226048Sminshall printf("runique: can't find unique file name.\n");
144366670Spendry return ((char *) 0);
144426048Sminshall }
144526048Sminshall *cp++ = ext;
144626048Sminshall *cp = '\0';
144726448Slepreau if (ext == '9')
144826048Sminshall ext = '0';
144926448Slepreau else
145026048Sminshall ext++;
145126448Slepreau if ((d = access(new, 0)) < 0)
145226048Sminshall break;
145326448Slepreau if (ext != '0')
145426048Sminshall cp--;
145526448Slepreau else if (*(cp - 2) == '.')
145626048Sminshall *(cp - 1) = '1';
145726048Sminshall else {
145826048Sminshall *(cp - 2) = *(cp - 2) + 1;
145926048Sminshall cp--;
146026048Sminshall }
146126048Sminshall }
146266670Spendry return (new);
146326048Sminshall }
146438133Srick
146566670Spendry void
abort_remote(din)146638133Srick abort_remote(din)
146766670Spendry FILE *din;
146838133Srick {
146938133Srick char buf[BUFSIZ];
147038133Srick int nfnd;
147138133Srick struct fd_set mask;
147238133Srick
147338133Srick /*
147438133Srick * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
147538133Srick * after urgent byte rather than before as is protocol now
147638133Srick */
147738133Srick sprintf(buf, "%c%c%c", IAC, IP, IAC);
147838133Srick if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
147966670Spendry warn("abort");
148038133Srick fprintf(cout,"%cABOR\r\n", DM);
148138133Srick (void) fflush(cout);
148238133Srick FD_ZERO(&mask);
148338133Srick FD_SET(fileno(cin), &mask);
148438133Srick if (din) {
148538133Srick FD_SET(fileno(din), &mask);
148638133Srick }
148738133Srick if ((nfnd = empty(&mask, 10)) <= 0) {
148838133Srick if (nfnd < 0) {
148966670Spendry warn("abort");
149038133Srick }
149138133Srick if (ptabflg)
149238133Srick code = -1;
149338133Srick lostpeer();
149438133Srick }
149538133Srick if (din && FD_ISSET(fileno(din), &mask)) {
149638133Srick while (read(fileno(din), buf, BUFSIZ) > 0)
149738133Srick /* LOOP */;
149838133Srick }
149938133Srick if (getreply(0) == ERROR && code == 552) {
150038133Srick /* 552 needed for nic style abort */
150138133Srick (void) getreply(0);
150238133Srick }
150338133Srick (void) getreply(0);
150438133Srick }
1505