xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 42665)
121739Sdist /*
236942Skarels  * Copyright (c) 1985, 1989 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
5*42665Sbostic  * %sccs.include.redist.c%
621739Sdist  */
721739Sdist 
810296Ssam #ifndef lint
9*42665Sbostic static char sccsid[] = "@(#)ftp.c	5.34 (Berkeley) 06/01/90";
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>
2012397Ssam #include <arpa/ftp.h>
2126048Sminshall #include <arpa/telnet.h>
2210296Ssam 
2310296Ssam #include <stdio.h>
2410296Ssam #include <signal.h>
2510296Ssam #include <errno.h>
2610296Ssam #include <netdb.h>
2726048Sminshall #include <fcntl.h>
2826048Sminshall #include <pwd.h>
2938133Srick #include <varargs.h>
3010296Ssam 
3136940Skarels #include "ftp_var.h"
3236940Skarels 
3310296Ssam struct	sockaddr_in hisctladdr;
3410296Ssam struct	sockaddr_in data_addr;
3510296Ssam int	data = -1;
3626048Sminshall int	abrtflag = 0;
3726048Sminshall int	ptflag = 0;
3810296Ssam struct	sockaddr_in myctladdr;
3926496Sminshall uid_t	getuid();
4038133Srick sig_t	lostpeer();
4137225Skarels off_t	restart_point = 0;
4210296Ssam 
4338202Srick extern char *strerror();
4440193Sbostic extern int connected, errno;
4538202Srick 
4610296Ssam FILE	*cin, *cout;
4710296Ssam FILE	*dataconn();
4810296Ssam 
4925904Skarels char *
5010296Ssam hookup(host, port)
5110296Ssam 	char *host;
5210296Ssam 	int port;
5310296Ssam {
5425904Skarels 	register struct hostent *hp = 0;
5527687Sminshall 	int s,len;
5625904Skarels 	static char hostnamebuf[80];
5710296Ssam 
5810296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5925904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6025904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6125904Skarels 		hisctladdr.sin_family = AF_INET;
6236940Skarels 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
6336940Skarels 	} else {
6425100Sbloom 		hp = gethostbyname(host);
6525904Skarels 		if (hp == NULL) {
6635792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
6735792Sbostic 			herror((char *)NULL);
6826048Sminshall 			code = -1;
6926048Sminshall 			return((char *) 0);
7025904Skarels 		}
7125904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7225904Skarels 		bcopy(hp->h_addr_list[0],
7325904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
7436940Skarels 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
7510296Ssam 	}
7625904Skarels 	hostname = hostnamebuf;
7725904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7810296Ssam 	if (s < 0) {
7910296Ssam 		perror("ftp: socket");
8026048Sminshall 		code = -1;
8110296Ssam 		return (0);
8210296Ssam 	}
8310296Ssam 	hisctladdr.sin_port = port;
8438133Srick 	while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
8525904Skarels 		if (hp && hp->h_addr_list[1]) {
8625904Skarels 			int oerrno = errno;
8738133Srick 			extern char *inet_ntoa();
8825904Skarels 
8925904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9025904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9125904Skarels 			errno = oerrno;
9226496Sminshall 			perror((char *) 0);
9325904Skarels 			hp->h_addr_list++;
9425904Skarels 			bcopy(hp->h_addr_list[0],
9526048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
9626496Sminshall 			fprintf(stdout, "Trying %s...\n",
9725904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9826813Skarels 			(void) close(s);
9926813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10026813Skarels 			if (s < 0) {
10126813Skarels 				perror("ftp: socket");
10226813Skarels 				code = -1;
10326813Skarels 				return (0);
10426813Skarels 			}
10525904Skarels 			continue;
10625904Skarels 		}
10710296Ssam 		perror("ftp: connect");
10826048Sminshall 		code = -1;
10910296Ssam 		goto bad;
11010296Ssam 	}
11111627Ssam 	len = sizeof (myctladdr);
11238133Srick 	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
11311627Ssam 		perror("ftp: getsockname");
11426048Sminshall 		code = -1;
11510296Ssam 		goto bad;
11610296Ssam 	}
11710296Ssam 	cin = fdopen(s, "r");
11810296Ssam 	cout = fdopen(s, "w");
11911219Ssam 	if (cin == NULL || cout == NULL) {
12010296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12110296Ssam 		if (cin)
12226496Sminshall 			(void) fclose(cin);
12310296Ssam 		if (cout)
12426496Sminshall 			(void) fclose(cout);
12526048Sminshall 		code = -1;
12610296Ssam 		goto bad;
12710296Ssam 	}
12810296Ssam 	if (verbose)
12926067Sminshall 		printf("Connected to %s.\n", hostname);
13027687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13126048Sminshall 		if (cin)
13226496Sminshall 			(void) fclose(cin);
13326048Sminshall 		if (cout)
13426496Sminshall 			(void) fclose(cout);
13526048Sminshall 		code = -1;
13626048Sminshall 		goto bad;
13726048Sminshall 	}
13827687Sminshall #ifdef SO_OOBINLINE
13927687Sminshall 	{
14027687Sminshall 	int on = 1;
14126048Sminshall 
14240193Sbostic 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
14327687Sminshall 		< 0 && debug) {
14427687Sminshall 			perror("ftp: setsockopt");
14527687Sminshall 		}
14627687Sminshall 	}
14738133Srick #endif /* SO_OOBINLINE */
14826048Sminshall 
14925904Skarels 	return (hostname);
15010296Ssam bad:
15126496Sminshall 	(void) close(s);
15225904Skarels 	return ((char *)0);
15310296Ssam }
15410296Ssam 
15525904Skarels login(host)
15625904Skarels 	char *host;
15710296Ssam {
15826048Sminshall 	char tmp[80];
15935659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16026048Sminshall 	int n, aflag = 0;
16110296Ssam 
16226048Sminshall 	user = pass = acct = 0;
16326048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16426048Sminshall 		code = -1;
16526048Sminshall 		return(0);
16626048Sminshall 	}
16737458Skarels 	while (user == NULL) {
16826048Sminshall 		char *myname = getlogin();
16926048Sminshall 
17026048Sminshall 		if (myname == NULL) {
17126048Sminshall 			struct passwd *pp = getpwuid(getuid());
17226048Sminshall 
17326448Slepreau 			if (pp != NULL)
17426048Sminshall 				myname = pp->pw_name;
17526048Sminshall 		}
17637458Skarels 		if (myname)
17737458Skarels 			printf("Name (%s:%s): ", host, myname);
17837458Skarels 		else
17937458Skarels 			printf("Name (%s): ", host);
18026048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18126048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18226448Slepreau 		if (*tmp == '\0')
18326048Sminshall 			user = myname;
18426448Slepreau 		else
18526048Sminshall 			user = tmp;
18626048Sminshall 	}
18710296Ssam 	n = command("USER %s", user);
18826048Sminshall 	if (n == CONTINUE) {
18926448Slepreau 		if (pass == NULL)
19035659Sbostic 			pass = getpass("Password:");
19110296Ssam 		n = command("PASS %s", pass);
19226048Sminshall 	}
19310296Ssam 	if (n == CONTINUE) {
19426048Sminshall 		aflag++;
19535659Sbostic 		acct = getpass("Account:");
19610296Ssam 		n = command("ACCT %s", acct);
19710296Ssam 	}
19810296Ssam 	if (n != COMPLETE) {
19910296Ssam 		fprintf(stderr, "Login failed.\n");
20010296Ssam 		return (0);
20110296Ssam 	}
20226448Slepreau 	if (!aflag && acct != NULL)
20326048Sminshall 		(void) command("ACCT %s", acct);
20426448Slepreau 	if (proxy)
20526048Sminshall 		return(1);
20626048Sminshall 	for (n = 0; n < macnum; ++n) {
20726048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
20826496Sminshall 			(void) strcpy(line, "$init");
20926048Sminshall 			makeargv();
21026048Sminshall 			domacro(margc, margv);
21126048Sminshall 			break;
21226048Sminshall 		}
21326048Sminshall 	}
21410296Ssam 	return (1);
21510296Ssam }
21610296Ssam 
21740193Sbostic void
21826048Sminshall cmdabort()
21926048Sminshall {
22026048Sminshall 	extern jmp_buf ptabort;
22126048Sminshall 
22226048Sminshall 	printf("\n");
22326048Sminshall 	(void) fflush(stdout);
22426048Sminshall 	abrtflag++;
22526448Slepreau 	if (ptflag)
22626048Sminshall 		longjmp(ptabort,1);
22726048Sminshall }
22826048Sminshall 
22938133Srick /*VARARGS*/
23038133Srick command(va_alist)
23138133Srick va_dcl
23238133Srick {
23338133Srick 	va_list ap;
23410296Ssam 	char *fmt;
23538133Srick 	int r;
23640193Sbostic 	sig_t oldintr;
23740193Sbostic 	void cmdabort();
23810296Ssam 
23926048Sminshall 	abrtflag = 0;
24010296Ssam 	if (debug) {
24110296Ssam 		printf("---> ");
24238133Srick 		va_start(ap);
24338133Srick 		fmt = va_arg(ap, char *);
24438133Srick 		if (strncmp("PASS ", fmt, 5) == 0)
24538133Srick 			printf("PASS XXXX");
24638133Srick 		else
24738133Srick 			vfprintf(stdout, fmt, ap);
24838133Srick 		va_end(ap);
24910296Ssam 		printf("\n");
25010296Ssam 		(void) fflush(stdout);
25110296Ssam 	}
25211219Ssam 	if (cout == NULL) {
25311219Ssam 		perror ("No control connection for command");
25426048Sminshall 		code = -1;
25511219Ssam 		return (0);
25611219Ssam 	}
25738133Srick 	oldintr = signal(SIGINT, cmdabort);
25838133Srick 	va_start(ap);
25938133Srick 	fmt = va_arg(ap, char *);
26038133Srick 	vfprintf(cout, fmt, ap);
26138133Srick 	va_end(ap);
26210296Ssam 	fprintf(cout, "\r\n");
26310296Ssam 	(void) fflush(cout);
26426048Sminshall 	cpend = 1;
26526048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
26626448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
26726048Sminshall 		(*oldintr)();
26826048Sminshall 	(void) signal(SIGINT, oldintr);
26926048Sminshall 	return(r);
27010296Ssam }
27110296Ssam 
27237229Skarels char reply_string[BUFSIZ];		/* last line of previous reply */
27336935Skarels 
27410296Ssam #include <ctype.h>
27510296Ssam 
27610296Ssam getreply(expecteof)
27710296Ssam 	int expecteof;
27810296Ssam {
27911219Ssam 	register int c, n;
28026048Sminshall 	register int dig;
28136935Skarels 	register char *cp;
28238133Srick 	int originalcode = 0, continuation = 0;
28340193Sbostic 	sig_t oldintr;
28426048Sminshall 	int pflag = 0;
28526048Sminshall 	char *pt = pasv;
28640193Sbostic 	void cmdabort();
28710296Ssam 
28838133Srick 	oldintr = signal(SIGINT, cmdabort);
28910296Ssam 	for (;;) {
29010296Ssam 		dig = n = code = 0;
29137229Skarels 		cp = reply_string;
29210296Ssam 		while ((c = getc(cin)) != '\n') {
29327687Sminshall 			if (c == IAC) {     /* handle telnet commands */
29427687Sminshall 				switch (c = getc(cin)) {
29527687Sminshall 				case WILL:
29627687Sminshall 				case WONT:
29727687Sminshall 					c = getc(cin);
29838133Srick 					fprintf(cout, "%c%c%c", IAC, DONT, c);
29927687Sminshall 					(void) fflush(cout);
30027687Sminshall 					break;
30127687Sminshall 				case DO:
30227687Sminshall 				case DONT:
30327687Sminshall 					c = getc(cin);
30438133Srick 					fprintf(cout, "%c%c%c", IAC, WONT, c);
30527687Sminshall 					(void) fflush(cout);
30627687Sminshall 					break;
30727687Sminshall 				default:
30827687Sminshall 					break;
30927687Sminshall 				}
31027687Sminshall 				continue;
31127687Sminshall 			}
31210296Ssam 			dig++;
31310296Ssam 			if (c == EOF) {
31426048Sminshall 				if (expecteof) {
31526048Sminshall 					(void) signal(SIGINT,oldintr);
31626048Sminshall 					code = 221;
31710296Ssam 					return (0);
31826048Sminshall 				}
31910296Ssam 				lostpeer();
32026048Sminshall 				if (verbose) {
32126048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
32226048Sminshall 					(void) fflush(stdout);
32326048Sminshall 				}
32433772Scsvsj 				code = 421;
32533772Scsvsj 				return(4);
32610296Ssam 			}
32726048Sminshall 			if (c != '\r' && (verbose > 0 ||
32826048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
32926448Slepreau 				if (proxflag &&
33026448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
33126048Sminshall 					printf("%s:",hostname);
33226496Sminshall 				(void) putchar(c);
33326048Sminshall 			}
33410296Ssam 			if (dig < 4 && isdigit(c))
33510296Ssam 				code = code * 10 + (c - '0');
33626448Slepreau 			if (!pflag && code == 227)
33726048Sminshall 				pflag = 1;
33826448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
33926048Sminshall 				pflag = 2;
34026048Sminshall 			if (pflag == 2) {
34126448Slepreau 				if (c != '\r' && c != ')')
34226048Sminshall 					*pt++ = c;
34326048Sminshall 				else {
34426048Sminshall 					*pt = '\0';
34526048Sminshall 					pflag = 3;
34626048Sminshall 				}
34726048Sminshall 			}
34826048Sminshall 			if (dig == 4 && c == '-') {
34926448Slepreau 				if (continuation)
35026048Sminshall 					code = 0;
35110296Ssam 				continuation++;
35226048Sminshall 			}
35310296Ssam 			if (n == 0)
35410296Ssam 				n = c;
35537229Skarels 			if (cp < &reply_string[sizeof(reply_string) - 1])
35637229Skarels 				*cp++ = c;
35710296Ssam 		}
35826048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
35926496Sminshall 			(void) putchar(c);
36011346Ssam 			(void) fflush (stdout);
36111346Ssam 		}
36210296Ssam 		if (continuation && code != originalcode) {
36310296Ssam 			if (originalcode == 0)
36410296Ssam 				originalcode = code;
36510296Ssam 			continue;
36610296Ssam 		}
36736935Skarels 		*cp = '\0';
36826448Slepreau 		if (n != '1')
36926048Sminshall 			cpend = 0;
37026048Sminshall 		(void) signal(SIGINT,oldintr);
37126448Slepreau 		if (code == 421 || originalcode == 421)
37226048Sminshall 			lostpeer();
37326448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
37426048Sminshall 			(*oldintr)();
37525907Smckusick 		return (n - '0');
37610296Ssam 	}
37710296Ssam }
37810296Ssam 
37926048Sminshall empty(mask, sec)
38027687Sminshall 	struct fd_set *mask;
38126048Sminshall 	int sec;
38226048Sminshall {
38326048Sminshall 	struct timeval t;
38426048Sminshall 
38526048Sminshall 	t.tv_sec = (long) sec;
38626048Sminshall 	t.tv_usec = 0;
38727687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
38826048Sminshall }
38926048Sminshall 
39010296Ssam jmp_buf	sendabort;
39110296Ssam 
39240193Sbostic void
39310296Ssam abortsend()
39410296Ssam {
39510296Ssam 
39626048Sminshall 	mflag = 0;
39726048Sminshall 	abrtflag = 0;
39838133Srick 	printf("\nsend aborted\nwaiting for remote to finish abort\n");
39926048Sminshall 	(void) fflush(stdout);
40010296Ssam 	longjmp(sendabort, 1);
40110296Ssam }
40210296Ssam 
40336940Skarels #define HASHBYTES 1024
40436940Skarels 
40537225Skarels sendrequest(cmd, local, remote, printnames)
40610296Ssam 	char *cmd, *local, *remote;
40737225Skarels 	int printnames;
40810296Ssam {
40940193Sbostic 	struct stat st;
41040193Sbostic 	struct timeval start, stop;
41140193Sbostic 	register int c, d;
41235659Sbostic 	FILE *fin, *dout = 0, *popen();
41338133Srick 	int (*closefunc)(), pclose(), fclose();
41440193Sbostic 	sig_t oldintr, oldintp;
41536940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
41640193Sbostic 	char *lmode, buf[BUFSIZ], *bufp;
41740193Sbostic 	void abortsend();
41810296Ssam 
41937225Skarels 	if (verbose && printnames) {
42037225Skarels 		if (local && *local != '-')
42137225Skarels 			printf("local: %s ", local);
42237225Skarels 		if (remote)
42337225Skarels 			printf("remote: %s\n", remote);
42437225Skarels 	}
42526048Sminshall 	if (proxy) {
42626048Sminshall 		proxtrans(cmd, local, remote);
42726048Sminshall 		return;
42826048Sminshall 	}
42938033Skarels 	if (curtype != type)
43038033Skarels 		changetype(type, 0);
43110296Ssam 	closefunc = NULL;
43226048Sminshall 	oldintr = NULL;
43326048Sminshall 	oldintp = NULL;
43440193Sbostic 	lmode = "w";
43526048Sminshall 	if (setjmp(sendabort)) {
43626048Sminshall 		while (cpend) {
43726048Sminshall 			(void) getreply(0);
43826048Sminshall 		}
43926048Sminshall 		if (data >= 0) {
44026048Sminshall 			(void) close(data);
44126048Sminshall 			data = -1;
44226048Sminshall 		}
44326448Slepreau 		if (oldintr)
44426048Sminshall 			(void) signal(SIGINT,oldintr);
44526448Slepreau 		if (oldintp)
44626048Sminshall 			(void) signal(SIGPIPE,oldintp);
44726048Sminshall 		code = -1;
44826048Sminshall 		return;
44926048Sminshall 	}
45010296Ssam 	oldintr = signal(SIGINT, abortsend);
45110296Ssam 	if (strcmp(local, "-") == 0)
45210296Ssam 		fin = stdin;
45310296Ssam 	else if (*local == '|') {
45426048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
45535659Sbostic 		fin = popen(local + 1, "r");
45610296Ssam 		if (fin == NULL) {
45726048Sminshall 			perror(local + 1);
45826048Sminshall 			(void) signal(SIGINT, oldintr);
45926048Sminshall 			(void) signal(SIGPIPE, oldintp);
46026048Sminshall 			code = -1;
46126048Sminshall 			return;
46210296Ssam 		}
46335659Sbostic 		closefunc = pclose;
46410296Ssam 	} else {
46510296Ssam 		fin = fopen(local, "r");
46610296Ssam 		if (fin == NULL) {
46738202Srick 			fprintf(stderr, "local: %s: %s\n", local,
46838202Srick 				strerror(errno));
46926048Sminshall 			(void) signal(SIGINT, oldintr);
47026048Sminshall 			code = -1;
47126048Sminshall 			return;
47210296Ssam 		}
47310296Ssam 		closefunc = fclose;
47410296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
47510296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
47626496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
47726048Sminshall 			(void) signal(SIGINT, oldintr);
47836935Skarels 			fclose(fin);
47926048Sminshall 			code = -1;
48026048Sminshall 			return;
48110296Ssam 		}
48210296Ssam 	}
48326048Sminshall 	if (initconn()) {
48426048Sminshall 		(void) signal(SIGINT, oldintr);
48526448Slepreau 		if (oldintp)
48626048Sminshall 			(void) signal(SIGPIPE, oldintp);
48726048Sminshall 		code = -1;
48836935Skarels 		if (closefunc != NULL)
48936935Skarels 			(*closefunc)(fin);
49026048Sminshall 		return;
49126048Sminshall 	}
49226448Slepreau 	if (setjmp(sendabort))
49326048Sminshall 		goto abort;
49436935Skarels 
49537225Skarels 	if (restart_point &&
49637225Skarels 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
49737225Skarels 		if (fseek(fin, (long) restart_point, 0) < 0) {
49838202Srick 			fprintf(stderr, "local: %s: %s\n", local,
49938202Srick 				strerror(errno));
50037225Skarels 			restart_point = 0;
50137225Skarels 			if (closefunc != NULL)
50237225Skarels 				(*closefunc)(fin);
50337225Skarels 			return;
50437225Skarels 		}
50537225Skarels 		if (command("REST %ld", (long) restart_point)
50637225Skarels 			!= CONTINUE) {
50737225Skarels 			restart_point = 0;
50837225Skarels 			if (closefunc != NULL)
50937225Skarels 				(*closefunc)(fin);
51037225Skarels 			return;
51137225Skarels 		}
51237225Skarels 		restart_point = 0;
51340193Sbostic 		lmode = "r+w";
51437225Skarels 	}
51510296Ssam 	if (remote) {
51626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
51726048Sminshall 			(void) signal(SIGINT, oldintr);
51826448Slepreau 			if (oldintp)
51926048Sminshall 				(void) signal(SIGPIPE, oldintp);
52036935Skarels 			if (closefunc != NULL)
52136935Skarels 				(*closefunc)(fin);
52226048Sminshall 			return;
52326048Sminshall 		}
52410296Ssam 	} else
52526048Sminshall 		if (command("%s", cmd) != PRELIM) {
52626048Sminshall 			(void) signal(SIGINT, oldintr);
52726448Slepreau 			if (oldintp)
52826048Sminshall 				(void) signal(SIGPIPE, oldintp);
52936935Skarels 			if (closefunc != NULL)
53036935Skarels 				(*closefunc)(fin);
53126048Sminshall 			return;
53226048Sminshall 		}
53340193Sbostic 	dout = dataconn(lmode);
53426448Slepreau 	if (dout == NULL)
53526048Sminshall 		goto abort;
53626496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
53736935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
53842278Skarels 	switch (curtype) {
53911219Ssam 
54011219Ssam 	case TYPE_I:
54111219Ssam 	case TYPE_L:
54211346Ssam 		errno = d = 0;
54336942Skarels 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
54411219Ssam 			bytes += c;
54536942Skarels 			for (bufp = buf; c > 0; c -= d, bufp += d)
54636942Skarels 				if ((d = write(fileno(dout), bufp, c)) <= 0)
54736942Skarels 					break;
54811651Ssam 			if (hash) {
54936940Skarels 				while (bytes >= hashbytes) {
55036940Skarels 					(void) putchar('#');
55136940Skarels 					hashbytes += HASHBYTES;
55236940Skarels 				}
55326496Sminshall 				(void) fflush(stdout);
55411651Ssam 			}
55511219Ssam 		}
55613213Ssam 		if (hash && bytes > 0) {
55736940Skarels 			if (bytes < HASHBYTES)
55836940Skarels 				(void) putchar('#');
55926496Sminshall 			(void) putchar('\n');
56026496Sminshall 			(void) fflush(stdout);
56111651Ssam 		}
56211219Ssam 		if (c < 0)
56338202Srick 			fprintf(stderr, "local: %s: %s\n", local,
56438202Srick 				strerror(errno));
56536942Skarels 		if (d <= 0) {
56636942Skarels 			if (d == 0)
56736942Skarels 				fprintf(stderr, "netout: write returned 0?\n");
56836942Skarels 			else if (errno != EPIPE)
56936935Skarels 				perror("netout");
57036935Skarels 			bytes = -1;
57136935Skarels 		}
57211219Ssam 		break;
57311219Ssam 
57411219Ssam 	case TYPE_A:
57511219Ssam 		while ((c = getc(fin)) != EOF) {
57611219Ssam 			if (c == '\n') {
57711651Ssam 				while (hash && (bytes >= hashbytes)) {
57826496Sminshall 					(void) putchar('#');
57926496Sminshall 					(void) fflush(stdout);
58036940Skarels 					hashbytes += HASHBYTES;
58111651Ssam 				}
58211219Ssam 				if (ferror(dout))
58311219Ssam 					break;
58426496Sminshall 				(void) putc('\r', dout);
58511219Ssam 				bytes++;
58611219Ssam 			}
58726496Sminshall 			(void) putc(c, dout);
58811219Ssam 			bytes++;
58926048Sminshall 	/*		if (c == '\r') {			  	*/
59026496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
59126048Sminshall 	/*			bytes++;				*/
59226048Sminshall 	/*		}                          			*/
59311219Ssam 		}
59411651Ssam 		if (hash) {
59513213Ssam 			if (bytes < hashbytes)
59626496Sminshall 				(void) putchar('#');
59726496Sminshall 			(void) putchar('\n');
59826496Sminshall 			(void) fflush(stdout);
59911651Ssam 		}
60011219Ssam 		if (ferror(fin))
60138202Srick 			fprintf(stderr, "local: %s: %s\n", local,
60238202Srick 				strerror(errno));
60336935Skarels 		if (ferror(dout)) {
60436935Skarels 			if (errno != EPIPE)
60536935Skarels 				perror("netout");
60636935Skarels 			bytes = -1;
60736935Skarels 		}
60811219Ssam 		break;
60910296Ssam 	}
61026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
61110296Ssam 	if (closefunc != NULL)
61226048Sminshall 		(*closefunc)(fin);
61310296Ssam 	(void) fclose(dout);
61426048Sminshall 	(void) getreply(0);
61526048Sminshall 	(void) signal(SIGINT, oldintr);
61636935Skarels 	if (oldintp)
61736935Skarels 		(void) signal(SIGPIPE, oldintp);
61835699Sbostic 	if (bytes > 0)
61937225Skarels 		ptransfer("sent", bytes, &start, &stop);
62010296Ssam 	return;
62126048Sminshall abort:
62226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
62326048Sminshall 	(void) signal(SIGINT, oldintr);
62426448Slepreau 	if (oldintp)
62526048Sminshall 		(void) signal(SIGPIPE, oldintp);
62626048Sminshall 	if (!cpend) {
62726048Sminshall 		code = -1;
62826048Sminshall 		return;
62926048Sminshall 	}
63026048Sminshall 	if (data >= 0) {
63126048Sminshall 		(void) close(data);
63226048Sminshall 		data = -1;
63326048Sminshall 	}
63426448Slepreau 	if (dout)
63526048Sminshall 		(void) fclose(dout);
63626048Sminshall 	(void) getreply(0);
63726048Sminshall 	code = -1;
63810296Ssam 	if (closefunc != NULL && fin != NULL)
63926048Sminshall 		(*closefunc)(fin);
64035699Sbostic 	if (bytes > 0)
64137225Skarels 		ptransfer("sent", bytes, &start, &stop);
64210296Ssam }
64310296Ssam 
64410296Ssam jmp_buf	recvabort;
64510296Ssam 
64640193Sbostic void
64710296Ssam abortrecv()
64810296Ssam {
64910296Ssam 
65026048Sminshall 	mflag = 0;
65126048Sminshall 	abrtflag = 0;
65238133Srick 	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
65326048Sminshall 	(void) fflush(stdout);
65410296Ssam 	longjmp(recvabort, 1);
65510296Ssam }
65610296Ssam 
65740193Sbostic recvrequest(cmd, local, remote, lmode, printnames)
65840193Sbostic 	char *cmd, *local, *remote, *lmode;
65910296Ssam {
66035659Sbostic 	FILE *fout, *din = 0, *popen();
66138133Srick 	int (*closefunc)(), pclose(), fclose();
66240193Sbostic 	sig_t oldintr, oldintp;
66338133Srick 	int is_retr, tcrflag, bare_lfs = 0;
66438133Srick 	char *gunique();
66538133Srick 	static int bufsize;
66636944Skarels 	static char *buf;
66736940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
66811346Ssam 	register int c, d;
66910296Ssam 	struct timeval start, stop;
67036940Skarels 	struct stat st;
67140193Sbostic 	off_t lseek();
67240193Sbostic 	void abortrecv();
67340193Sbostic 	char *malloc();
67410296Ssam 
67536935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
67637225Skarels 	if (is_retr && verbose && printnames) {
67737225Skarels 		if (local && *local != '-')
67837225Skarels 			printf("local: %s ", local);
67937225Skarels 		if (remote)
68037225Skarels 			printf("remote: %s\n", remote);
68137225Skarels 	}
68236935Skarels 	if (proxy && is_retr) {
68326048Sminshall 		proxtrans(cmd, local, remote);
68426048Sminshall 		return;
68526048Sminshall 	}
68610296Ssam 	closefunc = NULL;
68726048Sminshall 	oldintr = NULL;
68826048Sminshall 	oldintp = NULL;
68936935Skarels 	tcrflag = !crflag && is_retr;
69026048Sminshall 	if (setjmp(recvabort)) {
69126048Sminshall 		while (cpend) {
69226048Sminshall 			(void) getreply(0);
69326048Sminshall 		}
69426048Sminshall 		if (data >= 0) {
69526048Sminshall 			(void) close(data);
69626048Sminshall 			data = -1;
69726048Sminshall 		}
69826448Slepreau 		if (oldintr)
69926048Sminshall 			(void) signal(SIGINT, oldintr);
70026048Sminshall 		code = -1;
70126048Sminshall 		return;
70226048Sminshall 	}
70310296Ssam 	oldintr = signal(SIGINT, abortrecv);
70426048Sminshall 	if (strcmp(local, "-") && *local != '|') {
70510296Ssam 		if (access(local, 2) < 0) {
70626048Sminshall 			char *dir = rindex(local, '/');
70710296Ssam 
70826048Sminshall 			if (errno != ENOENT && errno != EACCES) {
70938202Srick 				fprintf(stderr, "local: %s: %s\n", local,
71038202Srick 					strerror(errno));
71126048Sminshall 				(void) signal(SIGINT, oldintr);
71226048Sminshall 				code = -1;
71326048Sminshall 				return;
71410296Ssam 			}
71526048Sminshall 			if (dir != NULL)
71626048Sminshall 				*dir = 0;
71726048Sminshall 			d = access(dir ? local : ".", 2);
71826048Sminshall 			if (dir != NULL)
71926048Sminshall 				*dir = '/';
72026048Sminshall 			if (d < 0) {
72138202Srick 				fprintf(stderr, "local: %s: %s\n", local,
72238202Srick 					strerror(errno));
72326048Sminshall 				(void) signal(SIGINT, oldintr);
72426048Sminshall 				code = -1;
72526048Sminshall 				return;
72626048Sminshall 			}
72726048Sminshall 			if (!runique && errno == EACCES &&
72836935Skarels 			    chmod(local, 0600) < 0) {
72938202Srick 				fprintf(stderr, "local: %s: %s\n", local,
73038202Srick 					strerror(errno));
73126048Sminshall 				(void) signal(SIGINT, oldintr);
73238202Srick 				(void) signal(SIGINT, oldintr);
73326048Sminshall 				code = -1;
73426048Sminshall 				return;
73526048Sminshall 			}
73626048Sminshall 			if (runique && errno == EACCES &&
73726048Sminshall 			   (local = gunique(local)) == NULL) {
73826048Sminshall 				(void) signal(SIGINT, oldintr);
73926048Sminshall 				code = -1;
74026048Sminshall 				return;
74126048Sminshall 			}
74210296Ssam 		}
74326048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
74426048Sminshall 			(void) signal(SIGINT, oldintr);
74526048Sminshall 			code = -1;
74626048Sminshall 			return;
74726048Sminshall 		}
74826048Sminshall 	}
74938033Skarels 	if (!is_retr) {
75038033Skarels 		if (curtype != TYPE_A)
75138033Skarels 			changetype(TYPE_A, 0);
75238033Skarels 	} else if (curtype != type)
75338033Skarels 		changetype(type, 0);
75426048Sminshall 	if (initconn()) {
75526048Sminshall 		(void) signal(SIGINT, oldintr);
75626048Sminshall 		code = -1;
75726048Sminshall 		return;
75826048Sminshall 	}
75926448Slepreau 	if (setjmp(recvabort))
76026048Sminshall 		goto abort;
76138033Skarels 	if (is_retr && restart_point &&
76238033Skarels 	    command("REST %ld", (long) restart_point) != CONTINUE)
76338033Skarels 		return;
76410296Ssam 	if (remote) {
76526048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
76626048Sminshall 			(void) signal(SIGINT, oldintr);
76726048Sminshall 			return;
76826048Sminshall 		}
76926048Sminshall 	} else {
77026048Sminshall 		if (command("%s", cmd) != PRELIM) {
77126048Sminshall 			(void) signal(SIGINT, oldintr);
77226048Sminshall 			return;
77326048Sminshall 		}
77426048Sminshall 	}
77526048Sminshall 	din = dataconn("r");
77626048Sminshall 	if (din == NULL)
77726048Sminshall 		goto abort;
77826448Slepreau 	if (strcmp(local, "-") == 0)
77910296Ssam 		fout = stdout;
78010296Ssam 	else if (*local == '|') {
78126048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
78235659Sbostic 		fout = popen(local + 1, "w");
78326048Sminshall 		if (fout == NULL) {
78426048Sminshall 			perror(local+1);
78526048Sminshall 			goto abort;
78626048Sminshall 		}
78735659Sbostic 		closefunc = pclose;
78836940Skarels 	} else {
78940193Sbostic 		fout = fopen(local, lmode);
79026048Sminshall 		if (fout == NULL) {
79138202Srick 			fprintf(stderr, "local: %s: %s\n", local,
79238202Srick 				strerror(errno));
79326048Sminshall 			goto abort;
79426048Sminshall 		}
79510296Ssam 		closefunc = fclose;
79610296Ssam 	}
79736940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
79836940Skarels 		st.st_blksize = BUFSIZ;
79936940Skarels 	if (st.st_blksize > bufsize) {
80036940Skarels 		if (buf)
80136940Skarels 			(void) free(buf);
80238133Srick 		buf = malloc((unsigned)st.st_blksize);
80336940Skarels 		if (buf == NULL) {
80436940Skarels 			perror("malloc");
80536944Skarels 			bufsize = 0;
80636940Skarels 			goto abort;
80736940Skarels 		}
80836940Skarels 		bufsize = st.st_blksize;
80936940Skarels 	}
81026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
81138033Skarels 	switch (curtype) {
81211219Ssam 
81311219Ssam 	case TYPE_I:
81411219Ssam 	case TYPE_L:
81537225Skarels 		if (restart_point &&
81637225Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
81738202Srick 			fprintf(stderr, "local: %s: %s\n", local,
81838202Srick 				strerror(errno));
81937225Skarels 			if (closefunc != NULL)
82037225Skarels 				(*closefunc)(fout);
82137225Skarels 			return;
82237225Skarels 		}
82311346Ssam 		errno = d = 0;
82436940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
82536944Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
82611219Ssam 				break;
82711219Ssam 			bytes += c;
82811651Ssam 			if (hash) {
82936940Skarels 				while (bytes >= hashbytes) {
83036940Skarels 					(void) putchar('#');
83136940Skarels 					hashbytes += HASHBYTES;
83236940Skarels 				}
83326496Sminshall 				(void) fflush(stdout);
83411651Ssam 			}
83511219Ssam 		}
83613213Ssam 		if (hash && bytes > 0) {
83736940Skarels 			if (bytes < HASHBYTES)
83836940Skarels 				(void) putchar('#');
83926496Sminshall 			(void) putchar('\n');
84026496Sminshall 			(void) fflush(stdout);
84111651Ssam 		}
84236935Skarels 		if (c < 0) {
84336935Skarels 			if (errno != EPIPE)
84436935Skarels 				perror("netin");
84536935Skarels 			bytes = -1;
84636935Skarels 		}
84736942Skarels 		if (d < c) {
84836942Skarels 			if (d < 0)
84938202Srick 				fprintf(stderr, "local: %s: %s\n", local,
85038202Srick 					strerror(errno));
85136942Skarels 			else
85236942Skarels 				fprintf(stderr, "%s: short write\n", local);
85336942Skarels 		}
85411219Ssam 		break;
85511219Ssam 
85611219Ssam 	case TYPE_A:
85737225Skarels 		if (restart_point) {
85840193Sbostic 			register int i, n, ch;
85937225Skarels 
86037225Skarels 			if (fseek(fout, 0L, L_SET) < 0)
86137225Skarels 				goto done;
86237225Skarels 			n = restart_point;
86340193Sbostic 			for (i = 0; i++ < n;) {
86440193Sbostic 				if ((ch = getc(fout)) == EOF)
86537225Skarels 					goto done;
86640193Sbostic 				if (ch == '\n')
86737225Skarels 					i++;
86837225Skarels 			}
86937225Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
87037225Skarels done:
87138202Srick 				fprintf(stderr, "local: %s: %s\n", local,
87238202Srick 					strerror(errno));
87337225Skarels 				if (closefunc != NULL)
87437225Skarels 					(*closefunc)(fout);
87537225Skarels 				return;
87637225Skarels 			}
87737225Skarels 		}
87811219Ssam 		while ((c = getc(din)) != EOF) {
87938133Srick 			if (c == '\n')
88038133Srick 				bare_lfs++;
88127749Sminshall 			while (c == '\r') {
88211651Ssam 				while (hash && (bytes >= hashbytes)) {
88326496Sminshall 					(void) putchar('#');
88426496Sminshall 					(void) fflush(stdout);
88536940Skarels 					hashbytes += HASHBYTES;
88611651Ssam 				}
88710296Ssam 				bytes++;
88826048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
88936940Skarels 					if (ferror(fout))
89036940Skarels 						goto break2;
89136940Skarels 					(void) putc('\r', fout);
89236942Skarels 					if (c == '\0') {
89336942Skarels 						bytes++;
89436940Skarels 						goto contin2;
89536942Skarels 					}
89636942Skarels 					if (c == EOF)
89736942Skarels 						goto contin2;
89811219Ssam 				}
89911219Ssam 			}
90036940Skarels 			(void) putc(c, fout);
90111219Ssam 			bytes++;
90236940Skarels 	contin2:	;
90310296Ssam 		}
90436940Skarels break2:
90538133Srick 		if (bare_lfs) {
90638133Srick 			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
90738133Srick 			printf("File may not have transferred correctly.\n");
90838133Srick 		}
90911651Ssam 		if (hash) {
91013213Ssam 			if (bytes < hashbytes)
91126496Sminshall 				(void) putchar('#');
91226496Sminshall 			(void) putchar('\n');
91326496Sminshall 			(void) fflush(stdout);
91411651Ssam 		}
91536944Skarels 		if (ferror(din)) {
91636935Skarels 			if (errno != EPIPE)
91736944Skarels 				perror("netin");
91836935Skarels 			bytes = -1;
91936935Skarels 		}
92036940Skarels 		if (ferror(fout))
92138202Srick 			fprintf(stderr, "local: %s: %s\n", local,
92238202Srick 				strerror(errno));
92311219Ssam 		break;
92410296Ssam 	}
92526448Slepreau 	if (closefunc != NULL)
92626048Sminshall 		(*closefunc)(fout);
92726496Sminshall 	(void) signal(SIGINT, oldintr);
92826448Slepreau 	if (oldintp)
92926048Sminshall 		(void) signal(SIGPIPE, oldintp);
93026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
93110296Ssam 	(void) fclose(din);
93226048Sminshall 	(void) getreply(0);
93336935Skarels 	if (bytes > 0 && is_retr)
93437225Skarels 		ptransfer("received", bytes, &start, &stop);
93526048Sminshall 	return;
93626048Sminshall abort:
93726048Sminshall 
93827687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
93926048Sminshall 
94026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
94126448Slepreau 	if (oldintp)
94226048Sminshall 		(void) signal(SIGPIPE, oldintr);
94338133Srick 	(void) signal(SIGINT, SIG_IGN);
94426048Sminshall 	if (!cpend) {
94526048Sminshall 		code = -1;
94638133Srick 		(void) signal(SIGINT, oldintr);
94726048Sminshall 		return;
94826048Sminshall 	}
94926048Sminshall 
95038133Srick 	abort_remote(din);
95126048Sminshall 	code = -1;
95226048Sminshall 	if (data >= 0) {
95326048Sminshall 		(void) close(data);
95426048Sminshall 		data = -1;
95526048Sminshall 	}
95626448Slepreau 	if (closefunc != NULL && fout != NULL)
95726048Sminshall 		(*closefunc)(fout);
95826448Slepreau 	if (din)
95926048Sminshall 		(void) fclose(din);
96035699Sbostic 	if (bytes > 0)
96137225Skarels 		ptransfer("received", bytes, &start, &stop);
96238133Srick 	(void) signal(SIGINT, oldintr);
96310296Ssam }
96410296Ssam 
96510296Ssam /*
96640193Sbostic  * Need to start a listen on the data channel before we send the command,
96740193Sbostic  * otherwise the server's connect may fail.
96810296Ssam  */
96910296Ssam initconn()
97010296Ssam {
97110296Ssam 	register char *p, *a;
97226048Sminshall 	int result, len, tmpno = 0;
97326993Skarels 	int on = 1;
97410296Ssam 
97511651Ssam noport:
97610296Ssam 	data_addr = myctladdr;
97711651Ssam 	if (sendport)
97811651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
97911651Ssam 	if (data != -1)
98038133Srick 		(void) close(data);
98118287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
98210296Ssam 	if (data < 0) {
98310296Ssam 		perror("ftp: socket");
98426448Slepreau 		if (tmpno)
98526048Sminshall 			sendport = 1;
98610296Ssam 		return (1);
98710296Ssam 	}
98812397Ssam 	if (!sendport)
98927687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
99033224Sbostic 			perror("ftp: setsockopt (reuse address)");
99112397Ssam 			goto bad;
99212397Ssam 		}
99326496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
99410296Ssam 		perror("ftp: bind");
99510296Ssam 		goto bad;
99610296Ssam 	}
99710296Ssam 	if (options & SO_DEBUG &&
99827687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
99910296Ssam 		perror("ftp: setsockopt (ignored)");
100011627Ssam 	len = sizeof (data_addr);
100138133Srick 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
100211627Ssam 		perror("ftp: getsockname");
100310296Ssam 		goto bad;
100410296Ssam 	}
100526448Slepreau 	if (listen(data, 1) < 0)
100610296Ssam 		perror("ftp: listen");
100711651Ssam 	if (sendport) {
100811651Ssam 		a = (char *)&data_addr.sin_addr;
100911651Ssam 		p = (char *)&data_addr.sin_port;
101010296Ssam #define	UC(b)	(((int)b)&0xff)
101111651Ssam 		result =
101211651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
101311651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
101411651Ssam 		      UC(p[0]), UC(p[1]));
101511651Ssam 		if (result == ERROR && sendport == -1) {
101611651Ssam 			sendport = 0;
101726048Sminshall 			tmpno = 1;
101811651Ssam 			goto noport;
101911651Ssam 		}
102011651Ssam 		return (result != COMPLETE);
102111651Ssam 	}
102226448Slepreau 	if (tmpno)
102326048Sminshall 		sendport = 1;
102411651Ssam 	return (0);
102510296Ssam bad:
102610296Ssam 	(void) close(data), data = -1;
102726448Slepreau 	if (tmpno)
102826048Sminshall 		sendport = 1;
102910296Ssam 	return (1);
103010296Ssam }
103110296Ssam 
103210296Ssam FILE *
103340193Sbostic dataconn(lmode)
103440193Sbostic 	char *lmode;
103510296Ssam {
103610296Ssam 	struct sockaddr_in from;
103710296Ssam 	int s, fromlen = sizeof (from);
103810296Ssam 
103926496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
104010296Ssam 	if (s < 0) {
104110296Ssam 		perror("ftp: accept");
104210296Ssam 		(void) close(data), data = -1;
104310296Ssam 		return (NULL);
104410296Ssam 	}
104510296Ssam 	(void) close(data);
104610296Ssam 	data = s;
104740193Sbostic 	return (fdopen(data, lmode));
104810296Ssam }
104910296Ssam 
105037225Skarels ptransfer(direction, bytes, t0, t1)
105137225Skarels 	char *direction;
105211651Ssam 	long bytes;
105310296Ssam 	struct timeval *t0, *t1;
105410296Ssam {
105510296Ssam 	struct timeval td;
105616437Sleres 	float s, bs;
105710296Ssam 
105835699Sbostic 	if (verbose) {
105935699Sbostic 		tvsub(&td, t1, t0);
106035699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
106110296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
106235699Sbostic 		bs = bytes / nz(s);
106335699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
106435699Sbostic 		    bytes, direction, s, bs / 1024.);
106535699Sbostic 	}
106610296Ssam }
106710296Ssam 
106826496Sminshall /*tvadd(tsum, t0)
106910296Ssam 	struct timeval *tsum, *t0;
107010296Ssam {
107110296Ssam 
107210296Ssam 	tsum->tv_sec += t0->tv_sec;
107310296Ssam 	tsum->tv_usec += t0->tv_usec;
107410296Ssam 	if (tsum->tv_usec > 1000000)
107510296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
107626496Sminshall } */
107710296Ssam 
107810296Ssam tvsub(tdiff, t1, t0)
107910296Ssam 	struct timeval *tdiff, *t1, *t0;
108010296Ssam {
108110296Ssam 
108210296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
108310296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
108410296Ssam 	if (tdiff->tv_usec < 0)
108510296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
108610296Ssam }
108726048Sminshall 
108840193Sbostic void
108926048Sminshall psabort()
109026048Sminshall {
109126048Sminshall 	extern int abrtflag;
109226048Sminshall 
109326048Sminshall 	abrtflag++;
109426048Sminshall }
109526048Sminshall 
109626048Sminshall pswitch(flag)
109726048Sminshall 	int flag;
109826048Sminshall {
109926048Sminshall 	extern int proxy, abrtflag;
110040193Sbostic 	sig_t oldintr;
110126048Sminshall 	static struct comvars {
110226048Sminshall 		int connect;
110328469Skarels 		char name[MAXHOSTNAMELEN];
110426048Sminshall 		struct sockaddr_in mctl;
110526048Sminshall 		struct sockaddr_in hctl;
110626048Sminshall 		FILE *in;
110726048Sminshall 		FILE *out;
110826048Sminshall 		int tpe;
110938033Skarels 		int curtpe;
111026048Sminshall 		int cpnd;
111126048Sminshall 		int sunqe;
111226048Sminshall 		int runqe;
111326048Sminshall 		int mcse;
111426048Sminshall 		int ntflg;
111526048Sminshall 		char nti[17];
111626048Sminshall 		char nto[17];
111726048Sminshall 		int mapflg;
111826048Sminshall 		char mi[MAXPATHLEN];
111926048Sminshall 		char mo[MAXPATHLEN];
112038033Skarels 	} proxstruct, tmpstruct;
112126048Sminshall 	struct comvars *ip, *op;
112226048Sminshall 
112326048Sminshall 	abrtflag = 0;
112426048Sminshall 	oldintr = signal(SIGINT, psabort);
112526048Sminshall 	if (flag) {
112626448Slepreau 		if (proxy)
112726048Sminshall 			return;
112826048Sminshall 		ip = &tmpstruct;
112926048Sminshall 		op = &proxstruct;
113026048Sminshall 		proxy++;
113138033Skarels 	} else {
113226448Slepreau 		if (!proxy)
113326048Sminshall 			return;
113426048Sminshall 		ip = &proxstruct;
113526048Sminshall 		op = &tmpstruct;
113626048Sminshall 		proxy = 0;
113726048Sminshall 	}
113826048Sminshall 	ip->connect = connected;
113926048Sminshall 	connected = op->connect;
114028469Skarels 	if (hostname) {
114128469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
114228469Skarels 		ip->name[strlen(ip->name)] = '\0';
114328469Skarels 	} else
114428469Skarels 		ip->name[0] = 0;
114526048Sminshall 	hostname = op->name;
114626048Sminshall 	ip->hctl = hisctladdr;
114726048Sminshall 	hisctladdr = op->hctl;
114826048Sminshall 	ip->mctl = myctladdr;
114926048Sminshall 	myctladdr = op->mctl;
115026048Sminshall 	ip->in = cin;
115126048Sminshall 	cin = op->in;
115226048Sminshall 	ip->out = cout;
115326048Sminshall 	cout = op->out;
115426048Sminshall 	ip->tpe = type;
115526048Sminshall 	type = op->tpe;
115638033Skarels 	ip->curtpe = curtype;
115738033Skarels 	curtype = op->curtpe;
115826048Sminshall 	ip->cpnd = cpend;
115926048Sminshall 	cpend = op->cpnd;
116026048Sminshall 	ip->sunqe = sunique;
116126048Sminshall 	sunique = op->sunqe;
116226048Sminshall 	ip->runqe = runique;
116326048Sminshall 	runique = op->runqe;
116426048Sminshall 	ip->mcse = mcase;
116526048Sminshall 	mcase = op->mcse;
116626048Sminshall 	ip->ntflg = ntflag;
116726048Sminshall 	ntflag = op->ntflg;
116826496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
116926048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
117026496Sminshall 	(void) strcpy(ntin, op->nti);
117126496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
117226048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
117326496Sminshall 	(void) strcpy(ntout, op->nto);
117426048Sminshall 	ip->mapflg = mapflag;
117526048Sminshall 	mapflag = op->mapflg;
117626496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
117726048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
117826496Sminshall 	(void) strcpy(mapin, op->mi);
117926496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
118026048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
118126496Sminshall 	(void) strcpy(mapout, op->mo);
118226048Sminshall 	(void) signal(SIGINT, oldintr);
118326048Sminshall 	if (abrtflag) {
118426048Sminshall 		abrtflag = 0;
118526048Sminshall 		(*oldintr)();
118626448Slepreau 	}
118726048Sminshall }
118826048Sminshall 
118926048Sminshall jmp_buf ptabort;
119026048Sminshall int ptabflg;
119126048Sminshall 
119240193Sbostic void
119326048Sminshall abortpt()
119426048Sminshall {
119526048Sminshall 	printf("\n");
119626496Sminshall 	(void) fflush(stdout);
119726048Sminshall 	ptabflg++;
119826048Sminshall 	mflag = 0;
119926048Sminshall 	abrtflag = 0;
120026048Sminshall 	longjmp(ptabort, 1);
120126048Sminshall }
120226048Sminshall 
120326048Sminshall proxtrans(cmd, local, remote)
120426048Sminshall 	char *cmd, *local, *remote;
120526048Sminshall {
120640193Sbostic 	sig_t oldintr;
120738133Srick 	int secndflag = 0, prox_type, nfnd;
120826048Sminshall 	extern jmp_buf ptabort;
120926048Sminshall 	char *cmd2;
121026496Sminshall 	struct fd_set mask;
121140193Sbostic 	void abortpt();
121226048Sminshall 
121326448Slepreau 	if (strcmp(cmd, "RETR"))
121426048Sminshall 		cmd2 = "RETR";
121526448Slepreau 	else
121626048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
121738033Skarels 	if ((prox_type = type) == 0) {
121838033Skarels 		if (unix_server && unix_proxy)
121938033Skarels 			prox_type = TYPE_I;
122038033Skarels 		else
122138033Skarels 			prox_type = TYPE_A;
122238033Skarels 	}
122338033Skarels 	if (curtype != prox_type)
122438033Skarels 		changetype(prox_type, 1);
122526048Sminshall 	if (command("PASV") != COMPLETE) {
122638033Skarels 		printf("proxy server does not support third party transfers.\n");
122726048Sminshall 		return;
122826048Sminshall 	}
122926048Sminshall 	pswitch(0);
123026048Sminshall 	if (!connected) {
123126048Sminshall 		printf("No primary connection\n");
123226048Sminshall 		pswitch(1);
123326048Sminshall 		code = -1;
123426048Sminshall 		return;
123526048Sminshall 	}
123638033Skarels 	if (curtype != prox_type)
123738033Skarels 		changetype(prox_type, 1);
123826048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
123926048Sminshall 		pswitch(1);
124026048Sminshall 		return;
124126048Sminshall 	}
124226448Slepreau 	if (setjmp(ptabort))
124326048Sminshall 		goto abort;
124426048Sminshall 	oldintr = signal(SIGINT, abortpt);
124526048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
124626048Sminshall 		(void) signal(SIGINT, oldintr);
124726048Sminshall 		pswitch(1);
124826048Sminshall 		return;
124926048Sminshall 	}
125026048Sminshall 	sleep(2);
125126048Sminshall 	pswitch(1);
125226048Sminshall 	secndflag++;
125326448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
125426048Sminshall 		goto abort;
125526048Sminshall 	ptflag++;
125626048Sminshall 	(void) getreply(0);
125726048Sminshall 	pswitch(0);
125826048Sminshall 	(void) getreply(0);
125926048Sminshall 	(void) signal(SIGINT, oldintr);
126026048Sminshall 	pswitch(1);
126126048Sminshall 	ptflag = 0;
126226048Sminshall 	printf("local: %s remote: %s\n", local, remote);
126326048Sminshall 	return;
126426048Sminshall abort:
126526048Sminshall 	(void) signal(SIGINT, SIG_IGN);
126626048Sminshall 	ptflag = 0;
126726448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
126826048Sminshall 		pswitch(1);
126926448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
127026048Sminshall 		pswitch(0);
127126048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
127226048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
127326048Sminshall 			pswitch(0);
127438133Srick 			if (cpend)
127538133Srick 				abort_remote((FILE *) NULL);
127626048Sminshall 		}
127726048Sminshall 		pswitch(1);
127826448Slepreau 		if (ptabflg)
127926048Sminshall 			code = -1;
128026048Sminshall 		(void) signal(SIGINT, oldintr);
128126048Sminshall 		return;
128226048Sminshall 	}
128338133Srick 	if (cpend)
128438133Srick 		abort_remote((FILE *) NULL);
128526048Sminshall 	pswitch(!proxy);
128626048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
128726048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
128826048Sminshall 			pswitch(0);
128938133Srick 			if (cpend)
129038133Srick 				abort_remote((FILE *) NULL);
129126048Sminshall 			pswitch(1);
129226448Slepreau 			if (ptabflg)
129326048Sminshall 				code = -1;
129426048Sminshall 			(void) signal(SIGINT, oldintr);
129526048Sminshall 			return;
129626048Sminshall 		}
129726048Sminshall 	}
129838133Srick 	if (cpend)
129938133Srick 		abort_remote((FILE *) NULL);
130026048Sminshall 	pswitch(!proxy);
130126048Sminshall 	if (cpend) {
130227687Sminshall 		FD_ZERO(&mask);
130326496Sminshall 		FD_SET(fileno(cin), &mask);
130438133Srick 		if ((nfnd = empty(&mask, 10)) <= 0) {
130527687Sminshall 			if (nfnd < 0) {
130627687Sminshall 				perror("abort");
130727687Sminshall 			}
130826448Slepreau 			if (ptabflg)
130926048Sminshall 				code = -1;
131026048Sminshall 			lostpeer();
131126048Sminshall 		}
131226048Sminshall 		(void) getreply(0);
131326048Sminshall 		(void) getreply(0);
131426048Sminshall 	}
131526448Slepreau 	if (proxy)
131626048Sminshall 		pswitch(0);
131726048Sminshall 	pswitch(1);
131826448Slepreau 	if (ptabflg)
131926048Sminshall 		code = -1;
132026048Sminshall 	(void) signal(SIGINT, oldintr);
132126048Sminshall }
132226048Sminshall 
132326048Sminshall reset()
132426048Sminshall {
132526496Sminshall 	struct fd_set mask;
132626496Sminshall 	int nfnd = 1;
132726048Sminshall 
132827687Sminshall 	FD_ZERO(&mask);
132930946Scsvsj 	while (nfnd > 0) {
133026496Sminshall 		FD_SET(fileno(cin), &mask);
133127687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
133226048Sminshall 			perror("reset");
133326048Sminshall 			code = -1;
133426048Sminshall 			lostpeer();
133526048Sminshall 		}
133627687Sminshall 		else if (nfnd) {
133726048Sminshall 			(void) getreply(0);
133826496Sminshall 		}
133926048Sminshall 	}
134026048Sminshall }
134126048Sminshall 
134226048Sminshall char *
134326048Sminshall gunique(local)
134426048Sminshall 	char *local;
134526048Sminshall {
134626048Sminshall 	static char new[MAXPATHLEN];
134726048Sminshall 	char *cp = rindex(local, '/');
134826048Sminshall 	int d, count=0;
134926048Sminshall 	char ext = '1';
135026048Sminshall 
135126448Slepreau 	if (cp)
135226048Sminshall 		*cp = '\0';
135326048Sminshall 	d = access(cp ? local : ".", 2);
135426448Slepreau 	if (cp)
135526048Sminshall 		*cp = '/';
135626048Sminshall 	if (d < 0) {
135738202Srick 		fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
135826048Sminshall 		return((char *) 0);
135926048Sminshall 	}
136026048Sminshall 	(void) strcpy(new, local);
136126048Sminshall 	cp = new + strlen(new);
136226048Sminshall 	*cp++ = '.';
136326048Sminshall 	while (!d) {
136426048Sminshall 		if (++count == 100) {
136526048Sminshall 			printf("runique: can't find unique file name.\n");
136626048Sminshall 			return((char *) 0);
136726048Sminshall 		}
136826048Sminshall 		*cp++ = ext;
136926048Sminshall 		*cp = '\0';
137026448Slepreau 		if (ext == '9')
137126048Sminshall 			ext = '0';
137226448Slepreau 		else
137326048Sminshall 			ext++;
137426448Slepreau 		if ((d = access(new, 0)) < 0)
137526048Sminshall 			break;
137626448Slepreau 		if (ext != '0')
137726048Sminshall 			cp--;
137826448Slepreau 		else if (*(cp - 2) == '.')
137926048Sminshall 			*(cp - 1) = '1';
138026048Sminshall 		else {
138126048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
138226048Sminshall 			cp--;
138326048Sminshall 		}
138426048Sminshall 	}
138526048Sminshall 	return(new);
138626048Sminshall }
138738133Srick 
138838133Srick abort_remote(din)
138938133Srick FILE *din;
139038133Srick {
139138133Srick 	char buf[BUFSIZ];
139238133Srick 	int nfnd;
139338133Srick 	struct fd_set mask;
139438133Srick 
139538133Srick 	/*
139638133Srick 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
139738133Srick 	 * after urgent byte rather than before as is protocol now
139838133Srick 	 */
139938133Srick 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
140038133Srick 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
140138133Srick 		perror("abort");
140238133Srick 	fprintf(cout,"%cABOR\r\n", DM);
140338133Srick 	(void) fflush(cout);
140438133Srick 	FD_ZERO(&mask);
140538133Srick 	FD_SET(fileno(cin), &mask);
140638133Srick 	if (din) {
140738133Srick 		FD_SET(fileno(din), &mask);
140838133Srick 	}
140938133Srick 	if ((nfnd = empty(&mask, 10)) <= 0) {
141038133Srick 		if (nfnd < 0) {
141138133Srick 			perror("abort");
141238133Srick 		}
141338133Srick 		if (ptabflg)
141438133Srick 			code = -1;
141538133Srick 		lostpeer();
141638133Srick 	}
141738133Srick 	if (din && FD_ISSET(fileno(din), &mask)) {
141838133Srick 		while (read(fileno(din), buf, BUFSIZ) > 0)
141938133Srick 			/* LOOP */;
142038133Srick 	}
142138133Srick 	if (getreply(0) == ERROR && code == 552) {
142238133Srick 		/* 552 needed for nic style abort */
142338133Srick 		(void) getreply(0);
142438133Srick 	}
142538133Srick 	(void) getreply(0);
142638133Srick }
1427