xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 46828)
121739Sdist /*
236942Skarels  * Copyright (c) 1985, 1989 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
542665Sbostic  * %sccs.include.redist.c%
621739Sdist  */
721739Sdist 
810296Ssam #ifndef lint
9*46828Sbostic static char sccsid[] = "@(#)ftp.c	5.37 (Berkeley) 03/01/91";
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>
2212397Ssam #include <arpa/ftp.h>
2326048Sminshall #include <arpa/telnet.h>
2410296Ssam 
2510296Ssam #include <stdio.h>
2610296Ssam #include <signal.h>
2710296Ssam #include <errno.h>
2810296Ssam #include <netdb.h>
2926048Sminshall #include <fcntl.h>
3026048Sminshall #include <pwd.h>
3138133Srick #include <varargs.h>
3210296Ssam 
3336940Skarels #include "ftp_var.h"
3436940Skarels 
3510296Ssam struct	sockaddr_in hisctladdr;
3610296Ssam struct	sockaddr_in data_addr;
3710296Ssam int	data = -1;
3826048Sminshall int	abrtflag = 0;
3926048Sminshall int	ptflag = 0;
4010296Ssam struct	sockaddr_in myctladdr;
4126496Sminshall uid_t	getuid();
4238133Srick sig_t	lostpeer();
4337225Skarels off_t	restart_point = 0;
4410296Ssam 
4538202Srick extern char *strerror();
4640193Sbostic extern int connected, errno;
4738202Srick 
4810296Ssam FILE	*cin, *cout;
4910296Ssam FILE	*dataconn();
5010296Ssam 
5125904Skarels char *
5210296Ssam hookup(host, port)
5310296Ssam 	char *host;
5410296Ssam 	int port;
5510296Ssam {
5625904Skarels 	register struct hostent *hp = 0;
5744340Skarels 	int s, len, tos;
5825904Skarels 	static char hostnamebuf[80];
5910296Ssam 
6010296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
6125904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6225904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6325904Skarels 		hisctladdr.sin_family = AF_INET;
6436940Skarels 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
6536940Skarels 	} else {
6625100Sbloom 		hp = gethostbyname(host);
6725904Skarels 		if (hp == NULL) {
6835792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
6935792Sbostic 			herror((char *)NULL);
7026048Sminshall 			code = -1;
7126048Sminshall 			return((char *) 0);
7225904Skarels 		}
7325904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7425904Skarels 		bcopy(hp->h_addr_list[0],
7525904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
7636940Skarels 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
7710296Ssam 	}
7825904Skarels 	hostname = hostnamebuf;
7925904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8010296Ssam 	if (s < 0) {
8110296Ssam 		perror("ftp: socket");
8226048Sminshall 		code = -1;
8310296Ssam 		return (0);
8410296Ssam 	}
8510296Ssam 	hisctladdr.sin_port = port;
8638133Srick 	while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
8725904Skarels 		if (hp && hp->h_addr_list[1]) {
8825904Skarels 			int oerrno = errno;
8938133Srick 			extern char *inet_ntoa();
9025904Skarels 
9125904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9325904Skarels 			errno = oerrno;
9426496Sminshall 			perror((char *) 0);
9525904Skarels 			hp->h_addr_list++;
9625904Skarels 			bcopy(hp->h_addr_list[0],
9726048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
9826496Sminshall 			fprintf(stdout, "Trying %s...\n",
9925904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10026813Skarels 			(void) close(s);
10126813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10226813Skarels 			if (s < 0) {
10326813Skarels 				perror("ftp: socket");
10426813Skarels 				code = -1;
10526813Skarels 				return (0);
10626813Skarels 			}
10725904Skarels 			continue;
10825904Skarels 		}
10910296Ssam 		perror("ftp: connect");
11026048Sminshall 		code = -1;
11110296Ssam 		goto bad;
11210296Ssam 	}
11311627Ssam 	len = sizeof (myctladdr);
11438133Srick 	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
11511627Ssam 		perror("ftp: getsockname");
11626048Sminshall 		code = -1;
11710296Ssam 		goto bad;
11810296Ssam 	}
11944340Skarels #ifdef IP_TOS
12044340Skarels 	tos = IPTOS_LOWDELAY;
12144340Skarels 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
12244661Skarels 		perror("ftp: setsockopt TOS (ignored)");
12344340Skarels #endif
12410296Ssam 	cin = fdopen(s, "r");
12510296Ssam 	cout = fdopen(s, "w");
12611219Ssam 	if (cin == NULL || cout == NULL) {
12710296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12810296Ssam 		if (cin)
12926496Sminshall 			(void) fclose(cin);
13010296Ssam 		if (cout)
13126496Sminshall 			(void) fclose(cout);
13226048Sminshall 		code = -1;
13310296Ssam 		goto bad;
13410296Ssam 	}
13510296Ssam 	if (verbose)
13626067Sminshall 		printf("Connected to %s.\n", hostname);
13727687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13826048Sminshall 		if (cin)
13926496Sminshall 			(void) fclose(cin);
14026048Sminshall 		if (cout)
14126496Sminshall 			(void) fclose(cout);
14226048Sminshall 		code = -1;
14326048Sminshall 		goto bad;
14426048Sminshall 	}
14527687Sminshall #ifdef SO_OOBINLINE
14627687Sminshall 	{
14727687Sminshall 	int on = 1;
14826048Sminshall 
14940193Sbostic 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
15027687Sminshall 		< 0 && debug) {
15127687Sminshall 			perror("ftp: setsockopt");
15227687Sminshall 		}
15327687Sminshall 	}
15438133Srick #endif /* SO_OOBINLINE */
15526048Sminshall 
15625904Skarels 	return (hostname);
15710296Ssam bad:
15826496Sminshall 	(void) close(s);
15925904Skarels 	return ((char *)0);
16010296Ssam }
16110296Ssam 
16225904Skarels login(host)
16325904Skarels 	char *host;
16410296Ssam {
16526048Sminshall 	char tmp[80];
16635659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16726048Sminshall 	int n, aflag = 0;
16810296Ssam 
16926048Sminshall 	user = pass = acct = 0;
17026048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
17126048Sminshall 		code = -1;
17226048Sminshall 		return(0);
17326048Sminshall 	}
17437458Skarels 	while (user == NULL) {
17526048Sminshall 		char *myname = getlogin();
17626048Sminshall 
17726048Sminshall 		if (myname == NULL) {
17826048Sminshall 			struct passwd *pp = getpwuid(getuid());
17926048Sminshall 
18026448Slepreau 			if (pp != NULL)
18126048Sminshall 				myname = pp->pw_name;
18226048Sminshall 		}
18337458Skarels 		if (myname)
18437458Skarels 			printf("Name (%s:%s): ", host, myname);
18537458Skarels 		else
18637458Skarels 			printf("Name (%s): ", host);
18726048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18826048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18926448Slepreau 		if (*tmp == '\0')
19026048Sminshall 			user = myname;
19126448Slepreau 		else
19226048Sminshall 			user = tmp;
19326048Sminshall 	}
19410296Ssam 	n = command("USER %s", user);
19526048Sminshall 	if (n == CONTINUE) {
19626448Slepreau 		if (pass == NULL)
19735659Sbostic 			pass = getpass("Password:");
19810296Ssam 		n = command("PASS %s", pass);
19926048Sminshall 	}
20010296Ssam 	if (n == CONTINUE) {
20126048Sminshall 		aflag++;
20235659Sbostic 		acct = getpass("Account:");
20310296Ssam 		n = command("ACCT %s", acct);
20410296Ssam 	}
20510296Ssam 	if (n != COMPLETE) {
20610296Ssam 		fprintf(stderr, "Login failed.\n");
20710296Ssam 		return (0);
20810296Ssam 	}
20926448Slepreau 	if (!aflag && acct != NULL)
21026048Sminshall 		(void) command("ACCT %s", acct);
21126448Slepreau 	if (proxy)
21226048Sminshall 		return(1);
21326048Sminshall 	for (n = 0; n < macnum; ++n) {
21426048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21526496Sminshall 			(void) strcpy(line, "$init");
21626048Sminshall 			makeargv();
21726048Sminshall 			domacro(margc, margv);
21826048Sminshall 			break;
21926048Sminshall 		}
22026048Sminshall 	}
22110296Ssam 	return (1);
22210296Ssam }
22310296Ssam 
22440193Sbostic void
22526048Sminshall cmdabort()
22626048Sminshall {
22726048Sminshall 	extern jmp_buf ptabort;
22826048Sminshall 
22926048Sminshall 	printf("\n");
23026048Sminshall 	(void) fflush(stdout);
23126048Sminshall 	abrtflag++;
23226448Slepreau 	if (ptflag)
23326048Sminshall 		longjmp(ptabort,1);
23426048Sminshall }
23526048Sminshall 
23638133Srick /*VARARGS*/
23738133Srick command(va_alist)
23838133Srick va_dcl
23938133Srick {
24038133Srick 	va_list ap;
24110296Ssam 	char *fmt;
24238133Srick 	int r;
24340193Sbostic 	sig_t oldintr;
24440193Sbostic 	void cmdabort();
24510296Ssam 
24626048Sminshall 	abrtflag = 0;
24710296Ssam 	if (debug) {
24810296Ssam 		printf("---> ");
24938133Srick 		va_start(ap);
25038133Srick 		fmt = va_arg(ap, char *);
25138133Srick 		if (strncmp("PASS ", fmt, 5) == 0)
25238133Srick 			printf("PASS XXXX");
25338133Srick 		else
25438133Srick 			vfprintf(stdout, fmt, ap);
25538133Srick 		va_end(ap);
25610296Ssam 		printf("\n");
25710296Ssam 		(void) fflush(stdout);
25810296Ssam 	}
25911219Ssam 	if (cout == NULL) {
26011219Ssam 		perror ("No control connection for command");
26126048Sminshall 		code = -1;
26211219Ssam 		return (0);
26311219Ssam 	}
26438133Srick 	oldintr = signal(SIGINT, cmdabort);
26538133Srick 	va_start(ap);
26638133Srick 	fmt = va_arg(ap, char *);
26738133Srick 	vfprintf(cout, fmt, ap);
26838133Srick 	va_end(ap);
26910296Ssam 	fprintf(cout, "\r\n");
27010296Ssam 	(void) fflush(cout);
27126048Sminshall 	cpend = 1;
27226048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
27326448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
274*46828Sbostic 		(*oldintr)(SIGINT);
27526048Sminshall 	(void) signal(SIGINT, oldintr);
27626048Sminshall 	return(r);
27710296Ssam }
27810296Ssam 
27937229Skarels char reply_string[BUFSIZ];		/* last line of previous reply */
28036935Skarels 
28110296Ssam #include <ctype.h>
28210296Ssam 
28310296Ssam getreply(expecteof)
28410296Ssam 	int expecteof;
28510296Ssam {
28611219Ssam 	register int c, n;
28726048Sminshall 	register int dig;
28836935Skarels 	register char *cp;
28938133Srick 	int originalcode = 0, continuation = 0;
29040193Sbostic 	sig_t oldintr;
29126048Sminshall 	int pflag = 0;
29226048Sminshall 	char *pt = pasv;
29340193Sbostic 	void cmdabort();
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;
33233772Scsvsj 				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)
381*46828Sbostic 			(*oldintr)(SIGINT);
38225907Smckusick 		return (n - '0');
38310296Ssam 	}
38410296Ssam }
38510296Ssam 
38626048Sminshall empty(mask, sec)
38727687Sminshall 	struct fd_set *mask;
38826048Sminshall 	int sec;
38926048Sminshall {
39026048Sminshall 	struct timeval t;
39126048Sminshall 
39226048Sminshall 	t.tv_sec = (long) sec;
39326048Sminshall 	t.tv_usec = 0;
39427687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
39526048Sminshall }
39626048Sminshall 
39710296Ssam jmp_buf	sendabort;
39810296Ssam 
39940193Sbostic void
40010296Ssam abortsend()
40110296Ssam {
40210296Ssam 
40326048Sminshall 	mflag = 0;
40426048Sminshall 	abrtflag = 0;
40538133Srick 	printf("\nsend aborted\nwaiting for remote to finish abort\n");
40626048Sminshall 	(void) fflush(stdout);
40710296Ssam 	longjmp(sendabort, 1);
40810296Ssam }
40910296Ssam 
41036940Skarels #define HASHBYTES 1024
41136940Skarels 
41237225Skarels sendrequest(cmd, local, remote, printnames)
41310296Ssam 	char *cmd, *local, *remote;
41437225Skarels 	int printnames;
41510296Ssam {
41640193Sbostic 	struct stat st;
41740193Sbostic 	struct timeval start, stop;
41840193Sbostic 	register int c, d;
41935659Sbostic 	FILE *fin, *dout = 0, *popen();
42038133Srick 	int (*closefunc)(), pclose(), fclose();
42140193Sbostic 	sig_t oldintr, oldintp;
42236940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
42340193Sbostic 	char *lmode, buf[BUFSIZ], *bufp;
42440193Sbostic 	void abortsend();
42510296Ssam 
42637225Skarels 	if (verbose && printnames) {
42737225Skarels 		if (local && *local != '-')
42837225Skarels 			printf("local: %s ", local);
42937225Skarels 		if (remote)
43037225Skarels 			printf("remote: %s\n", remote);
43137225Skarels 	}
43226048Sminshall 	if (proxy) {
43326048Sminshall 		proxtrans(cmd, local, remote);
43426048Sminshall 		return;
43526048Sminshall 	}
43638033Skarels 	if (curtype != type)
43738033Skarels 		changetype(type, 0);
43810296Ssam 	closefunc = NULL;
43926048Sminshall 	oldintr = NULL;
44026048Sminshall 	oldintp = NULL;
44140193Sbostic 	lmode = "w";
44226048Sminshall 	if (setjmp(sendabort)) {
44326048Sminshall 		while (cpend) {
44426048Sminshall 			(void) getreply(0);
44526048Sminshall 		}
44626048Sminshall 		if (data >= 0) {
44726048Sminshall 			(void) close(data);
44826048Sminshall 			data = -1;
44926048Sminshall 		}
45026448Slepreau 		if (oldintr)
45126048Sminshall 			(void) signal(SIGINT,oldintr);
45226448Slepreau 		if (oldintp)
45326048Sminshall 			(void) signal(SIGPIPE,oldintp);
45426048Sminshall 		code = -1;
45526048Sminshall 		return;
45626048Sminshall 	}
45710296Ssam 	oldintr = signal(SIGINT, abortsend);
45810296Ssam 	if (strcmp(local, "-") == 0)
45910296Ssam 		fin = stdin;
46010296Ssam 	else if (*local == '|') {
46126048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
46235659Sbostic 		fin = popen(local + 1, "r");
46310296Ssam 		if (fin == NULL) {
46426048Sminshall 			perror(local + 1);
46526048Sminshall 			(void) signal(SIGINT, oldintr);
46626048Sminshall 			(void) signal(SIGPIPE, oldintp);
46726048Sminshall 			code = -1;
46826048Sminshall 			return;
46910296Ssam 		}
47035659Sbostic 		closefunc = pclose;
47110296Ssam 	} else {
47210296Ssam 		fin = fopen(local, "r");
47310296Ssam 		if (fin == NULL) {
47438202Srick 			fprintf(stderr, "local: %s: %s\n", local,
47538202Srick 				strerror(errno));
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)) {
50437225Skarels 		if (fseek(fin, (long) restart_point, 0) < 0) {
50538202Srick 			fprintf(stderr, "local: %s: %s\n", local,
50638202Srick 				strerror(errno));
50737225Skarels 			restart_point = 0;
50837225Skarels 			if (closefunc != NULL)
50937225Skarels 				(*closefunc)(fin);
51037225Skarels 			return;
51137225Skarels 		}
51237225Skarels 		if (command("REST %ld", (long) restart_point)
51337225Skarels 			!= CONTINUE) {
51437225Skarels 			restart_point = 0;
51537225Skarels 			if (closefunc != NULL)
51637225Skarels 				(*closefunc)(fin);
51737225Skarels 			return;
51837225Skarels 		}
51937225Skarels 		restart_point = 0;
52040193Sbostic 		lmode = "r+w";
52137225Skarels 	}
52210296Ssam 	if (remote) {
52326048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
52426048Sminshall 			(void) signal(SIGINT, oldintr);
52526448Slepreau 			if (oldintp)
52626048Sminshall 				(void) signal(SIGPIPE, oldintp);
52736935Skarels 			if (closefunc != NULL)
52836935Skarels 				(*closefunc)(fin);
52926048Sminshall 			return;
53026048Sminshall 		}
53110296Ssam 	} else
53226048Sminshall 		if (command("%s", cmd) != PRELIM) {
53326048Sminshall 			(void) signal(SIGINT, oldintr);
53426448Slepreau 			if (oldintp)
53526048Sminshall 				(void) signal(SIGPIPE, oldintp);
53636935Skarels 			if (closefunc != NULL)
53736935Skarels 				(*closefunc)(fin);
53826048Sminshall 			return;
53926048Sminshall 		}
54040193Sbostic 	dout = dataconn(lmode);
54126448Slepreau 	if (dout == NULL)
54226048Sminshall 		goto abort;
54326496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
54436935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
54542278Skarels 	switch (curtype) {
54611219Ssam 
54711219Ssam 	case TYPE_I:
54811219Ssam 	case TYPE_L:
54911346Ssam 		errno = d = 0;
55036942Skarels 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
55111219Ssam 			bytes += c;
55236942Skarels 			for (bufp = buf; c > 0; c -= d, bufp += d)
55336942Skarels 				if ((d = write(fileno(dout), bufp, c)) <= 0)
55436942Skarels 					break;
55511651Ssam 			if (hash) {
55636940Skarels 				while (bytes >= hashbytes) {
55736940Skarels 					(void) putchar('#');
55836940Skarels 					hashbytes += HASHBYTES;
55936940Skarels 				}
56026496Sminshall 				(void) fflush(stdout);
56111651Ssam 			}
56211219Ssam 		}
56313213Ssam 		if (hash && bytes > 0) {
56436940Skarels 			if (bytes < HASHBYTES)
56536940Skarels 				(void) putchar('#');
56626496Sminshall 			(void) putchar('\n');
56726496Sminshall 			(void) fflush(stdout);
56811651Ssam 		}
56911219Ssam 		if (c < 0)
57038202Srick 			fprintf(stderr, "local: %s: %s\n", local,
57138202Srick 				strerror(errno));
57236942Skarels 		if (d <= 0) {
57336942Skarels 			if (d == 0)
57436942Skarels 				fprintf(stderr, "netout: write returned 0?\n");
57536942Skarels 			else if (errno != EPIPE)
57636935Skarels 				perror("netout");
57736935Skarels 			bytes = -1;
57836935Skarels 		}
57911219Ssam 		break;
58011219Ssam 
58111219Ssam 	case TYPE_A:
58211219Ssam 		while ((c = getc(fin)) != EOF) {
58311219Ssam 			if (c == '\n') {
58411651Ssam 				while (hash && (bytes >= hashbytes)) {
58526496Sminshall 					(void) putchar('#');
58626496Sminshall 					(void) fflush(stdout);
58736940Skarels 					hashbytes += HASHBYTES;
58811651Ssam 				}
58911219Ssam 				if (ferror(dout))
59011219Ssam 					break;
59126496Sminshall 				(void) putc('\r', dout);
59211219Ssam 				bytes++;
59311219Ssam 			}
59426496Sminshall 			(void) putc(c, dout);
59511219Ssam 			bytes++;
59626048Sminshall 	/*		if (c == '\r') {			  	*/
59726496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
59826048Sminshall 	/*			bytes++;				*/
59926048Sminshall 	/*		}                          			*/
60011219Ssam 		}
60111651Ssam 		if (hash) {
60213213Ssam 			if (bytes < hashbytes)
60326496Sminshall 				(void) putchar('#');
60426496Sminshall 			(void) putchar('\n');
60526496Sminshall 			(void) fflush(stdout);
60611651Ssam 		}
60711219Ssam 		if (ferror(fin))
60838202Srick 			fprintf(stderr, "local: %s: %s\n", local,
60938202Srick 				strerror(errno));
61036935Skarels 		if (ferror(dout)) {
61136935Skarels 			if (errno != EPIPE)
61236935Skarels 				perror("netout");
61336935Skarels 			bytes = -1;
61436935Skarels 		}
61511219Ssam 		break;
61610296Ssam 	}
61726496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
61810296Ssam 	if (closefunc != NULL)
61926048Sminshall 		(*closefunc)(fin);
62010296Ssam 	(void) fclose(dout);
62126048Sminshall 	(void) getreply(0);
62226048Sminshall 	(void) signal(SIGINT, oldintr);
62336935Skarels 	if (oldintp)
62436935Skarels 		(void) signal(SIGPIPE, oldintp);
62535699Sbostic 	if (bytes > 0)
62637225Skarels 		ptransfer("sent", bytes, &start, &stop);
62710296Ssam 	return;
62826048Sminshall abort:
62926496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
63026048Sminshall 	(void) signal(SIGINT, oldintr);
63126448Slepreau 	if (oldintp)
63226048Sminshall 		(void) signal(SIGPIPE, oldintp);
63326048Sminshall 	if (!cpend) {
63426048Sminshall 		code = -1;
63526048Sminshall 		return;
63626048Sminshall 	}
63726048Sminshall 	if (data >= 0) {
63826048Sminshall 		(void) close(data);
63926048Sminshall 		data = -1;
64026048Sminshall 	}
64126448Slepreau 	if (dout)
64226048Sminshall 		(void) fclose(dout);
64326048Sminshall 	(void) getreply(0);
64426048Sminshall 	code = -1;
64510296Ssam 	if (closefunc != NULL && fin != NULL)
64626048Sminshall 		(*closefunc)(fin);
64735699Sbostic 	if (bytes > 0)
64837225Skarels 		ptransfer("sent", bytes, &start, &stop);
64910296Ssam }
65010296Ssam 
65110296Ssam jmp_buf	recvabort;
65210296Ssam 
65340193Sbostic void
65410296Ssam abortrecv()
65510296Ssam {
65610296Ssam 
65726048Sminshall 	mflag = 0;
65826048Sminshall 	abrtflag = 0;
65938133Srick 	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
66026048Sminshall 	(void) fflush(stdout);
66110296Ssam 	longjmp(recvabort, 1);
66210296Ssam }
66310296Ssam 
66440193Sbostic recvrequest(cmd, local, remote, lmode, printnames)
66540193Sbostic 	char *cmd, *local, *remote, *lmode;
66610296Ssam {
66735659Sbostic 	FILE *fout, *din = 0, *popen();
66838133Srick 	int (*closefunc)(), pclose(), fclose();
66940193Sbostic 	sig_t oldintr, oldintp;
67038133Srick 	int is_retr, tcrflag, bare_lfs = 0;
67138133Srick 	char *gunique();
67238133Srick 	static int bufsize;
67336944Skarels 	static char *buf;
67436940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
67511346Ssam 	register int c, d;
67610296Ssam 	struct timeval start, stop;
67736940Skarels 	struct stat st;
67840193Sbostic 	off_t lseek();
67940193Sbostic 	void abortrecv();
68040193Sbostic 	char *malloc();
68110296Ssam 
68236935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
68337225Skarels 	if (is_retr && verbose && printnames) {
68437225Skarels 		if (local && *local != '-')
68537225Skarels 			printf("local: %s ", local);
68637225Skarels 		if (remote)
68737225Skarels 			printf("remote: %s\n", remote);
68837225Skarels 	}
68936935Skarels 	if (proxy && is_retr) {
69026048Sminshall 		proxtrans(cmd, local, remote);
69126048Sminshall 		return;
69226048Sminshall 	}
69310296Ssam 	closefunc = NULL;
69426048Sminshall 	oldintr = NULL;
69526048Sminshall 	oldintp = NULL;
69636935Skarels 	tcrflag = !crflag && is_retr;
69726048Sminshall 	if (setjmp(recvabort)) {
69826048Sminshall 		while (cpend) {
69926048Sminshall 			(void) getreply(0);
70026048Sminshall 		}
70126048Sminshall 		if (data >= 0) {
70226048Sminshall 			(void) close(data);
70326048Sminshall 			data = -1;
70426048Sminshall 		}
70526448Slepreau 		if (oldintr)
70626048Sminshall 			(void) signal(SIGINT, oldintr);
70726048Sminshall 		code = -1;
70826048Sminshall 		return;
70926048Sminshall 	}
71010296Ssam 	oldintr = signal(SIGINT, abortrecv);
71126048Sminshall 	if (strcmp(local, "-") && *local != '|') {
71210296Ssam 		if (access(local, 2) < 0) {
71326048Sminshall 			char *dir = rindex(local, '/');
71410296Ssam 
71526048Sminshall 			if (errno != ENOENT && errno != EACCES) {
71638202Srick 				fprintf(stderr, "local: %s: %s\n", local,
71738202Srick 					strerror(errno));
71826048Sminshall 				(void) signal(SIGINT, oldintr);
71926048Sminshall 				code = -1;
72026048Sminshall 				return;
72110296Ssam 			}
72226048Sminshall 			if (dir != NULL)
72326048Sminshall 				*dir = 0;
72426048Sminshall 			d = access(dir ? local : ".", 2);
72526048Sminshall 			if (dir != NULL)
72626048Sminshall 				*dir = '/';
72726048Sminshall 			if (d < 0) {
72838202Srick 				fprintf(stderr, "local: %s: %s\n", local,
72938202Srick 					strerror(errno));
73026048Sminshall 				(void) signal(SIGINT, oldintr);
73126048Sminshall 				code = -1;
73226048Sminshall 				return;
73326048Sminshall 			}
73426048Sminshall 			if (!runique && errno == EACCES &&
73536935Skarels 			    chmod(local, 0600) < 0) {
73638202Srick 				fprintf(stderr, "local: %s: %s\n", local,
73738202Srick 					strerror(errno));
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) {
79126048Sminshall 			perror(local+1);
79226048Sminshall 			goto abort;
79326048Sminshall 		}
79435659Sbostic 		closefunc = pclose;
79536940Skarels 	} else {
79640193Sbostic 		fout = fopen(local, lmode);
79726048Sminshall 		if (fout == NULL) {
79838202Srick 			fprintf(stderr, "local: %s: %s\n", local,
79938202Srick 				strerror(errno));
80026048Sminshall 			goto abort;
80126048Sminshall 		}
80210296Ssam 		closefunc = fclose;
80310296Ssam 	}
80436940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
80536940Skarels 		st.st_blksize = BUFSIZ;
80636940Skarels 	if (st.st_blksize > bufsize) {
80736940Skarels 		if (buf)
80836940Skarels 			(void) free(buf);
80938133Srick 		buf = malloc((unsigned)st.st_blksize);
81036940Skarels 		if (buf == NULL) {
81136940Skarels 			perror("malloc");
81236944Skarels 			bufsize = 0;
81336940Skarels 			goto abort;
81436940Skarels 		}
81536940Skarels 		bufsize = st.st_blksize;
81636940Skarels 	}
81726496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
81838033Skarels 	switch (curtype) {
81911219Ssam 
82011219Ssam 	case TYPE_I:
82111219Ssam 	case TYPE_L:
82237225Skarels 		if (restart_point &&
82337225Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
82438202Srick 			fprintf(stderr, "local: %s: %s\n", local,
82538202Srick 				strerror(errno));
82637225Skarels 			if (closefunc != NULL)
82737225Skarels 				(*closefunc)(fout);
82837225Skarels 			return;
82937225Skarels 		}
83011346Ssam 		errno = d = 0;
83136940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
83236944Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
83311219Ssam 				break;
83411219Ssam 			bytes += c;
83511651Ssam 			if (hash) {
83636940Skarels 				while (bytes >= hashbytes) {
83736940Skarels 					(void) putchar('#');
83836940Skarels 					hashbytes += HASHBYTES;
83936940Skarels 				}
84026496Sminshall 				(void) fflush(stdout);
84111651Ssam 			}
84211219Ssam 		}
84313213Ssam 		if (hash && bytes > 0) {
84436940Skarels 			if (bytes < HASHBYTES)
84536940Skarels 				(void) putchar('#');
84626496Sminshall 			(void) putchar('\n');
84726496Sminshall 			(void) fflush(stdout);
84811651Ssam 		}
84936935Skarels 		if (c < 0) {
85036935Skarels 			if (errno != EPIPE)
85136935Skarels 				perror("netin");
85236935Skarels 			bytes = -1;
85336935Skarels 		}
85436942Skarels 		if (d < c) {
85536942Skarels 			if (d < 0)
85638202Srick 				fprintf(stderr, "local: %s: %s\n", local,
85738202Srick 					strerror(errno));
85836942Skarels 			else
85936942Skarels 				fprintf(stderr, "%s: short write\n", local);
86036942Skarels 		}
86111219Ssam 		break;
86211219Ssam 
86311219Ssam 	case TYPE_A:
86437225Skarels 		if (restart_point) {
86540193Sbostic 			register int i, n, ch;
86637225Skarels 
86737225Skarels 			if (fseek(fout, 0L, L_SET) < 0)
86837225Skarels 				goto done;
86937225Skarels 			n = restart_point;
87040193Sbostic 			for (i = 0; i++ < n;) {
87140193Sbostic 				if ((ch = getc(fout)) == EOF)
87237225Skarels 					goto done;
87340193Sbostic 				if (ch == '\n')
87437225Skarels 					i++;
87537225Skarels 			}
87637225Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
87737225Skarels done:
87838202Srick 				fprintf(stderr, "local: %s: %s\n", local,
87938202Srick 					strerror(errno));
88037225Skarels 				if (closefunc != NULL)
88137225Skarels 					(*closefunc)(fout);
88237225Skarels 				return;
88337225Skarels 			}
88437225Skarels 		}
88511219Ssam 		while ((c = getc(din)) != EOF) {
88638133Srick 			if (c == '\n')
88738133Srick 				bare_lfs++;
88827749Sminshall 			while (c == '\r') {
88911651Ssam 				while (hash && (bytes >= hashbytes)) {
89026496Sminshall 					(void) putchar('#');
89126496Sminshall 					(void) fflush(stdout);
89236940Skarels 					hashbytes += HASHBYTES;
89311651Ssam 				}
89410296Ssam 				bytes++;
89526048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
89636940Skarels 					if (ferror(fout))
89736940Skarels 						goto break2;
89836940Skarels 					(void) putc('\r', fout);
89936942Skarels 					if (c == '\0') {
90036942Skarels 						bytes++;
90136940Skarels 						goto contin2;
90236942Skarels 					}
90336942Skarels 					if (c == EOF)
90436942Skarels 						goto contin2;
90511219Ssam 				}
90611219Ssam 			}
90736940Skarels 			(void) putc(c, fout);
90811219Ssam 			bytes++;
90936940Skarels 	contin2:	;
91010296Ssam 		}
91136940Skarels break2:
91238133Srick 		if (bare_lfs) {
91338133Srick 			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
91438133Srick 			printf("File may not have transferred correctly.\n");
91538133Srick 		}
91611651Ssam 		if (hash) {
91713213Ssam 			if (bytes < hashbytes)
91826496Sminshall 				(void) putchar('#');
91926496Sminshall 			(void) putchar('\n');
92026496Sminshall 			(void) fflush(stdout);
92111651Ssam 		}
92236944Skarels 		if (ferror(din)) {
92336935Skarels 			if (errno != EPIPE)
92436944Skarels 				perror("netin");
92536935Skarels 			bytes = -1;
92636935Skarels 		}
92736940Skarels 		if (ferror(fout))
92838202Srick 			fprintf(stderr, "local: %s: %s\n", local,
92938202Srick 				strerror(errno));
93011219Ssam 		break;
93110296Ssam 	}
93226448Slepreau 	if (closefunc != NULL)
93326048Sminshall 		(*closefunc)(fout);
93426496Sminshall 	(void) signal(SIGINT, oldintr);
93526448Slepreau 	if (oldintp)
93626048Sminshall 		(void) signal(SIGPIPE, oldintp);
93726496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
93810296Ssam 	(void) fclose(din);
93926048Sminshall 	(void) getreply(0);
94036935Skarels 	if (bytes > 0 && is_retr)
94137225Skarels 		ptransfer("received", bytes, &start, &stop);
94226048Sminshall 	return;
94326048Sminshall abort:
94426048Sminshall 
94527687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
94626048Sminshall 
94726496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
94826448Slepreau 	if (oldintp)
94926048Sminshall 		(void) signal(SIGPIPE, oldintr);
95038133Srick 	(void) signal(SIGINT, SIG_IGN);
95126048Sminshall 	if (!cpend) {
95226048Sminshall 		code = -1;
95338133Srick 		(void) signal(SIGINT, oldintr);
95426048Sminshall 		return;
95526048Sminshall 	}
95626048Sminshall 
95738133Srick 	abort_remote(din);
95826048Sminshall 	code = -1;
95926048Sminshall 	if (data >= 0) {
96026048Sminshall 		(void) close(data);
96126048Sminshall 		data = -1;
96226048Sminshall 	}
96326448Slepreau 	if (closefunc != NULL && fout != NULL)
96426048Sminshall 		(*closefunc)(fout);
96526448Slepreau 	if (din)
96626048Sminshall 		(void) fclose(din);
96735699Sbostic 	if (bytes > 0)
96837225Skarels 		ptransfer("received", bytes, &start, &stop);
96938133Srick 	(void) signal(SIGINT, oldintr);
97010296Ssam }
97110296Ssam 
97210296Ssam /*
97340193Sbostic  * Need to start a listen on the data channel before we send the command,
97440193Sbostic  * otherwise the server's connect may fail.
97510296Ssam  */
97610296Ssam initconn()
97710296Ssam {
97810296Ssam 	register char *p, *a;
97926048Sminshall 	int result, len, tmpno = 0;
98026993Skarels 	int on = 1;
98110296Ssam 
98211651Ssam noport:
98310296Ssam 	data_addr = myctladdr;
98411651Ssam 	if (sendport)
98511651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
98611651Ssam 	if (data != -1)
98738133Srick 		(void) close(data);
98818287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
98910296Ssam 	if (data < 0) {
99010296Ssam 		perror("ftp: socket");
99126448Slepreau 		if (tmpno)
99226048Sminshall 			sendport = 1;
99310296Ssam 		return (1);
99410296Ssam 	}
99512397Ssam 	if (!sendport)
99627687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
99733224Sbostic 			perror("ftp: setsockopt (reuse address)");
99812397Ssam 			goto bad;
99912397Ssam 		}
100026496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
100110296Ssam 		perror("ftp: bind");
100210296Ssam 		goto bad;
100310296Ssam 	}
100410296Ssam 	if (options & SO_DEBUG &&
100527687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
100610296Ssam 		perror("ftp: setsockopt (ignored)");
100711627Ssam 	len = sizeof (data_addr);
100838133Srick 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
100911627Ssam 		perror("ftp: getsockname");
101010296Ssam 		goto bad;
101110296Ssam 	}
101226448Slepreau 	if (listen(data, 1) < 0)
101310296Ssam 		perror("ftp: listen");
101411651Ssam 	if (sendport) {
101511651Ssam 		a = (char *)&data_addr.sin_addr;
101611651Ssam 		p = (char *)&data_addr.sin_port;
101710296Ssam #define	UC(b)	(((int)b)&0xff)
101811651Ssam 		result =
101911651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
102011651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
102111651Ssam 		      UC(p[0]), UC(p[1]));
102211651Ssam 		if (result == ERROR && sendport == -1) {
102311651Ssam 			sendport = 0;
102426048Sminshall 			tmpno = 1;
102511651Ssam 			goto noport;
102611651Ssam 		}
102711651Ssam 		return (result != COMPLETE);
102811651Ssam 	}
102926448Slepreau 	if (tmpno)
103026048Sminshall 		sendport = 1;
103144340Skarels #ifdef IP_TOS
103244340Skarels 	on = IPTOS_THROUGHPUT;
103344340Skarels 	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
103444661Skarels 		perror("ftp: setsockopt TOS (ignored)");
103544340Skarels #endif
103611651Ssam 	return (0);
103710296Ssam bad:
103810296Ssam 	(void) close(data), data = -1;
103926448Slepreau 	if (tmpno)
104026048Sminshall 		sendport = 1;
104110296Ssam 	return (1);
104210296Ssam }
104310296Ssam 
104410296Ssam FILE *
104540193Sbostic dataconn(lmode)
104640193Sbostic 	char *lmode;
104710296Ssam {
104810296Ssam 	struct sockaddr_in from;
104944340Skarels 	int s, fromlen = sizeof (from), tos;
105010296Ssam 
105126496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
105210296Ssam 	if (s < 0) {
105310296Ssam 		perror("ftp: accept");
105410296Ssam 		(void) close(data), data = -1;
105510296Ssam 		return (NULL);
105610296Ssam 	}
105710296Ssam 	(void) close(data);
105810296Ssam 	data = s;
105944340Skarels #ifdef IP_TOS
106044340Skarels 	tos = IPTOS_THROUGHPUT;
106144340Skarels 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
106244661Skarels 		perror("ftp: setsockopt TOS (ignored)");
106344340Skarels #endif
106440193Sbostic 	return (fdopen(data, lmode));
106510296Ssam }
106610296Ssam 
106737225Skarels ptransfer(direction, bytes, t0, t1)
106837225Skarels 	char *direction;
106911651Ssam 	long bytes;
107010296Ssam 	struct timeval *t0, *t1;
107110296Ssam {
107210296Ssam 	struct timeval td;
107316437Sleres 	float s, bs;
107410296Ssam 
107535699Sbostic 	if (verbose) {
107635699Sbostic 		tvsub(&td, t1, t0);
107735699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
107810296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
107935699Sbostic 		bs = bytes / nz(s);
108035699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
108135699Sbostic 		    bytes, direction, s, bs / 1024.);
108235699Sbostic 	}
108310296Ssam }
108410296Ssam 
108526496Sminshall /*tvadd(tsum, t0)
108610296Ssam 	struct timeval *tsum, *t0;
108710296Ssam {
108810296Ssam 
108910296Ssam 	tsum->tv_sec += t0->tv_sec;
109010296Ssam 	tsum->tv_usec += t0->tv_usec;
109110296Ssam 	if (tsum->tv_usec > 1000000)
109210296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
109326496Sminshall } */
109410296Ssam 
109510296Ssam tvsub(tdiff, t1, t0)
109610296Ssam 	struct timeval *tdiff, *t1, *t0;
109710296Ssam {
109810296Ssam 
109910296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
110010296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
110110296Ssam 	if (tdiff->tv_usec < 0)
110210296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
110310296Ssam }
110426048Sminshall 
110540193Sbostic void
110626048Sminshall psabort()
110726048Sminshall {
110826048Sminshall 	extern int abrtflag;
110926048Sminshall 
111026048Sminshall 	abrtflag++;
111126048Sminshall }
111226048Sminshall 
111326048Sminshall pswitch(flag)
111426048Sminshall 	int flag;
111526048Sminshall {
111626048Sminshall 	extern int proxy, abrtflag;
111740193Sbostic 	sig_t oldintr;
111826048Sminshall 	static struct comvars {
111926048Sminshall 		int connect;
112028469Skarels 		char name[MAXHOSTNAMELEN];
112126048Sminshall 		struct sockaddr_in mctl;
112226048Sminshall 		struct sockaddr_in hctl;
112326048Sminshall 		FILE *in;
112426048Sminshall 		FILE *out;
112526048Sminshall 		int tpe;
112638033Skarels 		int curtpe;
112726048Sminshall 		int cpnd;
112826048Sminshall 		int sunqe;
112926048Sminshall 		int runqe;
113026048Sminshall 		int mcse;
113126048Sminshall 		int ntflg;
113226048Sminshall 		char nti[17];
113326048Sminshall 		char nto[17];
113426048Sminshall 		int mapflg;
113526048Sminshall 		char mi[MAXPATHLEN];
113626048Sminshall 		char mo[MAXPATHLEN];
113738033Skarels 	} proxstruct, tmpstruct;
113826048Sminshall 	struct comvars *ip, *op;
113926048Sminshall 
114026048Sminshall 	abrtflag = 0;
114126048Sminshall 	oldintr = signal(SIGINT, psabort);
114226048Sminshall 	if (flag) {
114326448Slepreau 		if (proxy)
114426048Sminshall 			return;
114526048Sminshall 		ip = &tmpstruct;
114626048Sminshall 		op = &proxstruct;
114726048Sminshall 		proxy++;
114838033Skarels 	} else {
114926448Slepreau 		if (!proxy)
115026048Sminshall 			return;
115126048Sminshall 		ip = &proxstruct;
115226048Sminshall 		op = &tmpstruct;
115326048Sminshall 		proxy = 0;
115426048Sminshall 	}
115526048Sminshall 	ip->connect = connected;
115626048Sminshall 	connected = op->connect;
115728469Skarels 	if (hostname) {
115828469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
115928469Skarels 		ip->name[strlen(ip->name)] = '\0';
116028469Skarels 	} else
116128469Skarels 		ip->name[0] = 0;
116226048Sminshall 	hostname = op->name;
116326048Sminshall 	ip->hctl = hisctladdr;
116426048Sminshall 	hisctladdr = op->hctl;
116526048Sminshall 	ip->mctl = myctladdr;
116626048Sminshall 	myctladdr = op->mctl;
116726048Sminshall 	ip->in = cin;
116826048Sminshall 	cin = op->in;
116926048Sminshall 	ip->out = cout;
117026048Sminshall 	cout = op->out;
117126048Sminshall 	ip->tpe = type;
117226048Sminshall 	type = op->tpe;
117338033Skarels 	ip->curtpe = curtype;
117438033Skarels 	curtype = op->curtpe;
117526048Sminshall 	ip->cpnd = cpend;
117626048Sminshall 	cpend = op->cpnd;
117726048Sminshall 	ip->sunqe = sunique;
117826048Sminshall 	sunique = op->sunqe;
117926048Sminshall 	ip->runqe = runique;
118026048Sminshall 	runique = op->runqe;
118126048Sminshall 	ip->mcse = mcase;
118226048Sminshall 	mcase = op->mcse;
118326048Sminshall 	ip->ntflg = ntflag;
118426048Sminshall 	ntflag = op->ntflg;
118526496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
118626048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
118726496Sminshall 	(void) strcpy(ntin, op->nti);
118826496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
118926048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
119026496Sminshall 	(void) strcpy(ntout, op->nto);
119126048Sminshall 	ip->mapflg = mapflag;
119226048Sminshall 	mapflag = op->mapflg;
119326496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
119426048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
119526496Sminshall 	(void) strcpy(mapin, op->mi);
119626496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
119726048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
119826496Sminshall 	(void) strcpy(mapout, op->mo);
119926048Sminshall 	(void) signal(SIGINT, oldintr);
120026048Sminshall 	if (abrtflag) {
120126048Sminshall 		abrtflag = 0;
1202*46828Sbostic 		(*oldintr)(SIGINT);
120326448Slepreau 	}
120426048Sminshall }
120526048Sminshall 
120626048Sminshall jmp_buf ptabort;
120726048Sminshall int ptabflg;
120826048Sminshall 
120940193Sbostic void
121026048Sminshall abortpt()
121126048Sminshall {
121226048Sminshall 	printf("\n");
121326496Sminshall 	(void) fflush(stdout);
121426048Sminshall 	ptabflg++;
121526048Sminshall 	mflag = 0;
121626048Sminshall 	abrtflag = 0;
121726048Sminshall 	longjmp(ptabort, 1);
121826048Sminshall }
121926048Sminshall 
122026048Sminshall proxtrans(cmd, local, remote)
122126048Sminshall 	char *cmd, *local, *remote;
122226048Sminshall {
122340193Sbostic 	sig_t oldintr;
122438133Srick 	int secndflag = 0, prox_type, nfnd;
122526048Sminshall 	extern jmp_buf ptabort;
122626048Sminshall 	char *cmd2;
122726496Sminshall 	struct fd_set mask;
122840193Sbostic 	void abortpt();
122926048Sminshall 
123026448Slepreau 	if (strcmp(cmd, "RETR"))
123126048Sminshall 		cmd2 = "RETR";
123226448Slepreau 	else
123326048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
123438033Skarels 	if ((prox_type = type) == 0) {
123538033Skarels 		if (unix_server && unix_proxy)
123638033Skarels 			prox_type = TYPE_I;
123738033Skarels 		else
123838033Skarels 			prox_type = TYPE_A;
123938033Skarels 	}
124038033Skarels 	if (curtype != prox_type)
124138033Skarels 		changetype(prox_type, 1);
124226048Sminshall 	if (command("PASV") != COMPLETE) {
124338033Skarels 		printf("proxy server does not support third party transfers.\n");
124426048Sminshall 		return;
124526048Sminshall 	}
124626048Sminshall 	pswitch(0);
124726048Sminshall 	if (!connected) {
124826048Sminshall 		printf("No primary connection\n");
124926048Sminshall 		pswitch(1);
125026048Sminshall 		code = -1;
125126048Sminshall 		return;
125226048Sminshall 	}
125338033Skarels 	if (curtype != prox_type)
125438033Skarels 		changetype(prox_type, 1);
125526048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
125626048Sminshall 		pswitch(1);
125726048Sminshall 		return;
125826048Sminshall 	}
125926448Slepreau 	if (setjmp(ptabort))
126026048Sminshall 		goto abort;
126126048Sminshall 	oldintr = signal(SIGINT, abortpt);
126226048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
126326048Sminshall 		(void) signal(SIGINT, oldintr);
126426048Sminshall 		pswitch(1);
126526048Sminshall 		return;
126626048Sminshall 	}
126726048Sminshall 	sleep(2);
126826048Sminshall 	pswitch(1);
126926048Sminshall 	secndflag++;
127026448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
127126048Sminshall 		goto abort;
127226048Sminshall 	ptflag++;
127326048Sminshall 	(void) getreply(0);
127426048Sminshall 	pswitch(0);
127526048Sminshall 	(void) getreply(0);
127626048Sminshall 	(void) signal(SIGINT, oldintr);
127726048Sminshall 	pswitch(1);
127826048Sminshall 	ptflag = 0;
127926048Sminshall 	printf("local: %s remote: %s\n", local, remote);
128026048Sminshall 	return;
128126048Sminshall abort:
128226048Sminshall 	(void) signal(SIGINT, SIG_IGN);
128326048Sminshall 	ptflag = 0;
128426448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
128526048Sminshall 		pswitch(1);
128626448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
128726048Sminshall 		pswitch(0);
128826048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
128926048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
129026048Sminshall 			pswitch(0);
129138133Srick 			if (cpend)
129238133Srick 				abort_remote((FILE *) NULL);
129326048Sminshall 		}
129426048Sminshall 		pswitch(1);
129526448Slepreau 		if (ptabflg)
129626048Sminshall 			code = -1;
129726048Sminshall 		(void) signal(SIGINT, oldintr);
129826048Sminshall 		return;
129926048Sminshall 	}
130038133Srick 	if (cpend)
130138133Srick 		abort_remote((FILE *) NULL);
130226048Sminshall 	pswitch(!proxy);
130326048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
130426048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
130526048Sminshall 			pswitch(0);
130638133Srick 			if (cpend)
130738133Srick 				abort_remote((FILE *) NULL);
130826048Sminshall 			pswitch(1);
130926448Slepreau 			if (ptabflg)
131026048Sminshall 				code = -1;
131126048Sminshall 			(void) signal(SIGINT, oldintr);
131226048Sminshall 			return;
131326048Sminshall 		}
131426048Sminshall 	}
131538133Srick 	if (cpend)
131638133Srick 		abort_remote((FILE *) NULL);
131726048Sminshall 	pswitch(!proxy);
131826048Sminshall 	if (cpend) {
131927687Sminshall 		FD_ZERO(&mask);
132026496Sminshall 		FD_SET(fileno(cin), &mask);
132138133Srick 		if ((nfnd = empty(&mask, 10)) <= 0) {
132227687Sminshall 			if (nfnd < 0) {
132327687Sminshall 				perror("abort");
132427687Sminshall 			}
132526448Slepreau 			if (ptabflg)
132626048Sminshall 				code = -1;
132726048Sminshall 			lostpeer();
132826048Sminshall 		}
132926048Sminshall 		(void) getreply(0);
133026048Sminshall 		(void) getreply(0);
133126048Sminshall 	}
133226448Slepreau 	if (proxy)
133326048Sminshall 		pswitch(0);
133426048Sminshall 	pswitch(1);
133526448Slepreau 	if (ptabflg)
133626048Sminshall 		code = -1;
133726048Sminshall 	(void) signal(SIGINT, oldintr);
133826048Sminshall }
133926048Sminshall 
134026048Sminshall reset()
134126048Sminshall {
134226496Sminshall 	struct fd_set mask;
134326496Sminshall 	int nfnd = 1;
134426048Sminshall 
134527687Sminshall 	FD_ZERO(&mask);
134630946Scsvsj 	while (nfnd > 0) {
134726496Sminshall 		FD_SET(fileno(cin), &mask);
134827687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
134926048Sminshall 			perror("reset");
135026048Sminshall 			code = -1;
135126048Sminshall 			lostpeer();
135226048Sminshall 		}
135327687Sminshall 		else if (nfnd) {
135426048Sminshall 			(void) getreply(0);
135526496Sminshall 		}
135626048Sminshall 	}
135726048Sminshall }
135826048Sminshall 
135926048Sminshall char *
136026048Sminshall gunique(local)
136126048Sminshall 	char *local;
136226048Sminshall {
136326048Sminshall 	static char new[MAXPATHLEN];
136426048Sminshall 	char *cp = rindex(local, '/');
136526048Sminshall 	int d, count=0;
136626048Sminshall 	char ext = '1';
136726048Sminshall 
136826448Slepreau 	if (cp)
136926048Sminshall 		*cp = '\0';
137026048Sminshall 	d = access(cp ? local : ".", 2);
137126448Slepreau 	if (cp)
137226048Sminshall 		*cp = '/';
137326048Sminshall 	if (d < 0) {
137438202Srick 		fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
137526048Sminshall 		return((char *) 0);
137626048Sminshall 	}
137726048Sminshall 	(void) strcpy(new, local);
137826048Sminshall 	cp = new + strlen(new);
137926048Sminshall 	*cp++ = '.';
138026048Sminshall 	while (!d) {
138126048Sminshall 		if (++count == 100) {
138226048Sminshall 			printf("runique: can't find unique file name.\n");
138326048Sminshall 			return((char *) 0);
138426048Sminshall 		}
138526048Sminshall 		*cp++ = ext;
138626048Sminshall 		*cp = '\0';
138726448Slepreau 		if (ext == '9')
138826048Sminshall 			ext = '0';
138926448Slepreau 		else
139026048Sminshall 			ext++;
139126448Slepreau 		if ((d = access(new, 0)) < 0)
139226048Sminshall 			break;
139326448Slepreau 		if (ext != '0')
139426048Sminshall 			cp--;
139526448Slepreau 		else if (*(cp - 2) == '.')
139626048Sminshall 			*(cp - 1) = '1';
139726048Sminshall 		else {
139826048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
139926048Sminshall 			cp--;
140026048Sminshall 		}
140126048Sminshall 	}
140226048Sminshall 	return(new);
140326048Sminshall }
140438133Srick 
140538133Srick abort_remote(din)
140638133Srick FILE *din;
140738133Srick {
140838133Srick 	char buf[BUFSIZ];
140938133Srick 	int nfnd;
141038133Srick 	struct fd_set mask;
141138133Srick 
141238133Srick 	/*
141338133Srick 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
141438133Srick 	 * after urgent byte rather than before as is protocol now
141538133Srick 	 */
141638133Srick 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
141738133Srick 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
141838133Srick 		perror("abort");
141938133Srick 	fprintf(cout,"%cABOR\r\n", DM);
142038133Srick 	(void) fflush(cout);
142138133Srick 	FD_ZERO(&mask);
142238133Srick 	FD_SET(fileno(cin), &mask);
142338133Srick 	if (din) {
142438133Srick 		FD_SET(fileno(din), &mask);
142538133Srick 	}
142638133Srick 	if ((nfnd = empty(&mask, 10)) <= 0) {
142738133Srick 		if (nfnd < 0) {
142838133Srick 			perror("abort");
142938133Srick 		}
143038133Srick 		if (ptabflg)
143138133Srick 			code = -1;
143238133Srick 		lostpeer();
143338133Srick 	}
143438133Srick 	if (din && FD_ISSET(fileno(din), &mask)) {
143538133Srick 		while (read(fileno(din), buf, BUFSIZ) > 0)
143638133Srick 			/* LOOP */;
143738133Srick 	}
143838133Srick 	if (getreply(0) == ERROR && code == 552) {
143938133Srick 		/* 552 needed for nic style abort */
144038133Srick 		(void) getreply(0);
144138133Srick 	}
144238133Srick 	(void) getreply(0);
144338133Srick }
1444