xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 38133)
121739Sdist /*
236942Skarels  * Copyright (c) 1985, 1989 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1536935Skarels  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621739Sdist  */
1721739Sdist 
1810296Ssam #ifndef lint
19*38133Srick static char sccsid[] = "@(#)ftp.c	5.30 (Berkeley) 05/26/89";
2033737Sbostic #endif /* not lint */
2110296Ssam 
2236940Skarels #include <sys/param.h>
2310296Ssam #include <sys/stat.h>
2410296Ssam #include <sys/ioctl.h>
2510296Ssam #include <sys/socket.h>
2613614Ssam #include <sys/time.h>
2736935Skarels #include <sys/file.h>
2810296Ssam 
2910296Ssam #include <netinet/in.h>
3012397Ssam #include <arpa/ftp.h>
3126048Sminshall #include <arpa/telnet.h>
3210296Ssam 
3310296Ssam #include <stdio.h>
3410296Ssam #include <signal.h>
3510296Ssam #include <errno.h>
3610296Ssam #include <netdb.h>
3726048Sminshall #include <fcntl.h>
3826048Sminshall #include <pwd.h>
39*38133Srick #include <varargs.h>
4010296Ssam 
4136940Skarels #include "ftp_var.h"
4236940Skarels 
4310296Ssam struct	sockaddr_in hisctladdr;
4410296Ssam struct	sockaddr_in data_addr;
4510296Ssam int	data = -1;
4626048Sminshall int	abrtflag = 0;
4726048Sminshall int	ptflag = 0;
4810296Ssam int	connected;
4910296Ssam struct	sockaddr_in myctladdr;
5026496Sminshall uid_t	getuid();
51*38133Srick sig_t	lostpeer();
5237225Skarels off_t	restart_point = 0;
5310296Ssam 
5410296Ssam FILE	*cin, *cout;
5510296Ssam FILE	*dataconn();
5610296Ssam 
5725904Skarels char *
5810296Ssam hookup(host, port)
5910296Ssam 	char *host;
6010296Ssam 	int port;
6110296Ssam {
6225904Skarels 	register struct hostent *hp = 0;
6327687Sminshall 	int s,len;
6425904Skarels 	static char hostnamebuf[80];
6510296Ssam 
6610296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
6725904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6825904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6925904Skarels 		hisctladdr.sin_family = AF_INET;
7036940Skarels 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
7136940Skarels 	} else {
7225100Sbloom 		hp = gethostbyname(host);
7325904Skarels 		if (hp == NULL) {
7435792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
7535792Sbostic 			herror((char *)NULL);
7626048Sminshall 			code = -1;
7726048Sminshall 			return((char *) 0);
7825904Skarels 		}
7925904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
8025904Skarels 		bcopy(hp->h_addr_list[0],
8125904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8236940Skarels 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
8310296Ssam 	}
8425904Skarels 	hostname = hostnamebuf;
8525904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8610296Ssam 	if (s < 0) {
8710296Ssam 		perror("ftp: socket");
8826048Sminshall 		code = -1;
8910296Ssam 		return (0);
9010296Ssam 	}
9110296Ssam 	hisctladdr.sin_port = port;
92*38133Srick 	while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
9325904Skarels 		if (hp && hp->h_addr_list[1]) {
9425904Skarels 			int oerrno = errno;
95*38133Srick 			extern char *inet_ntoa();
9625904Skarels 
9725904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9825904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9925904Skarels 			errno = oerrno;
10026496Sminshall 			perror((char *) 0);
10125904Skarels 			hp->h_addr_list++;
10225904Skarels 			bcopy(hp->h_addr_list[0],
10326048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
10426496Sminshall 			fprintf(stdout, "Trying %s...\n",
10525904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10626813Skarels 			(void) close(s);
10726813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10826813Skarels 			if (s < 0) {
10926813Skarels 				perror("ftp: socket");
11026813Skarels 				code = -1;
11126813Skarels 				return (0);
11226813Skarels 			}
11325904Skarels 			continue;
11425904Skarels 		}
11510296Ssam 		perror("ftp: connect");
11626048Sminshall 		code = -1;
11710296Ssam 		goto bad;
11810296Ssam 	}
11911627Ssam 	len = sizeof (myctladdr);
120*38133Srick 	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
12111627Ssam 		perror("ftp: getsockname");
12226048Sminshall 		code = -1;
12310296Ssam 		goto bad;
12410296Ssam 	}
12510296Ssam 	cin = fdopen(s, "r");
12610296Ssam 	cout = fdopen(s, "w");
12711219Ssam 	if (cin == NULL || cout == NULL) {
12810296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12910296Ssam 		if (cin)
13026496Sminshall 			(void) fclose(cin);
13110296Ssam 		if (cout)
13226496Sminshall 			(void) fclose(cout);
13326048Sminshall 		code = -1;
13410296Ssam 		goto bad;
13510296Ssam 	}
13610296Ssam 	if (verbose)
13726067Sminshall 		printf("Connected to %s.\n", hostname);
13827687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13926048Sminshall 		if (cin)
14026496Sminshall 			(void) fclose(cin);
14126048Sminshall 		if (cout)
14226496Sminshall 			(void) fclose(cout);
14326048Sminshall 		code = -1;
14426048Sminshall 		goto bad;
14526048Sminshall 	}
14627687Sminshall #ifdef SO_OOBINLINE
14727687Sminshall 	{
14827687Sminshall 	int on = 1;
14926048Sminshall 
15027687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
15127687Sminshall 		< 0 && debug) {
15227687Sminshall 			perror("ftp: setsockopt");
15327687Sminshall 		}
15427687Sminshall 	}
155*38133Srick #endif /* SO_OOBINLINE */
15626048Sminshall 
15725904Skarels 	return (hostname);
15810296Ssam bad:
15926496Sminshall 	(void) close(s);
16025904Skarels 	return ((char *)0);
16110296Ssam }
16210296Ssam 
16325904Skarels login(host)
16425904Skarels 	char *host;
16510296Ssam {
16626048Sminshall 	char tmp[80];
16735659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16826048Sminshall 	int n, aflag = 0;
16910296Ssam 
17026048Sminshall 	user = pass = acct = 0;
17126048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
17226048Sminshall 		code = -1;
17326048Sminshall 		return(0);
17426048Sminshall 	}
17537458Skarels 	while (user == NULL) {
17626048Sminshall 		char *myname = getlogin();
17726048Sminshall 
17826048Sminshall 		if (myname == NULL) {
17926048Sminshall 			struct passwd *pp = getpwuid(getuid());
18026048Sminshall 
18126448Slepreau 			if (pp != NULL)
18226048Sminshall 				myname = pp->pw_name;
18326048Sminshall 		}
18437458Skarels 		if (myname)
18537458Skarels 			printf("Name (%s:%s): ", host, myname);
18637458Skarels 		else
18737458Skarels 			printf("Name (%s): ", host);
18826048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18926048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
19026448Slepreau 		if (*tmp == '\0')
19126048Sminshall 			user = myname;
19226448Slepreau 		else
19326048Sminshall 			user = tmp;
19426048Sminshall 	}
19510296Ssam 	n = command("USER %s", user);
19626048Sminshall 	if (n == CONTINUE) {
19726448Slepreau 		if (pass == NULL)
19835659Sbostic 			pass = getpass("Password:");
19910296Ssam 		n = command("PASS %s", pass);
20026048Sminshall 	}
20110296Ssam 	if (n == CONTINUE) {
20226048Sminshall 		aflag++;
20335659Sbostic 		acct = getpass("Account:");
20410296Ssam 		n = command("ACCT %s", acct);
20510296Ssam 	}
20610296Ssam 	if (n != COMPLETE) {
20710296Ssam 		fprintf(stderr, "Login failed.\n");
20810296Ssam 		return (0);
20910296Ssam 	}
21026448Slepreau 	if (!aflag && acct != NULL)
21126048Sminshall 		(void) command("ACCT %s", acct);
21226448Slepreau 	if (proxy)
21326048Sminshall 		return(1);
21426048Sminshall 	for (n = 0; n < macnum; ++n) {
21526048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21626496Sminshall 			(void) strcpy(line, "$init");
21726048Sminshall 			makeargv();
21826048Sminshall 			domacro(margc, margv);
21926048Sminshall 			break;
22026048Sminshall 		}
22126048Sminshall 	}
22210296Ssam 	return (1);
22310296Ssam }
22410296Ssam 
225*38133Srick sig_t
22626048Sminshall cmdabort()
22726048Sminshall {
22826048Sminshall 	extern jmp_buf ptabort;
22926048Sminshall 
23026048Sminshall 	printf("\n");
23126048Sminshall 	(void) fflush(stdout);
23226048Sminshall 	abrtflag++;
23326448Slepreau 	if (ptflag)
23426048Sminshall 		longjmp(ptabort,1);
23526048Sminshall }
23626048Sminshall 
237*38133Srick /*VARARGS*/
238*38133Srick command(va_alist)
239*38133Srick va_dcl
240*38133Srick {
241*38133Srick 	va_list ap;
24210296Ssam 	char *fmt;
243*38133Srick 	int r;
244*38133Srick 	sig_t (*oldintr)(), cmdabort();
24510296Ssam 
24626048Sminshall 	abrtflag = 0;
24710296Ssam 	if (debug) {
24810296Ssam 		printf("---> ");
249*38133Srick 		va_start(ap);
250*38133Srick 		fmt = va_arg(ap, char *);
251*38133Srick 		if (strncmp("PASS ", fmt, 5) == 0)
252*38133Srick 			printf("PASS XXXX");
253*38133Srick 		else
254*38133Srick 			vfprintf(stdout, fmt, ap);
255*38133Srick 		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 	}
264*38133Srick 	oldintr = signal(SIGINT, cmdabort);
265*38133Srick 	va_start(ap);
266*38133Srick 	fmt = va_arg(ap, char *);
267*38133Srick 	vfprintf(cout, fmt, ap);
268*38133Srick 	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)
27426048Sminshall 		(*oldintr)();
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;
289*38133Srick 	int originalcode = 0, continuation = 0;
290*38133Srick 	sig_t (*oldintr)(), cmdabort();
29126048Sminshall 	int pflag = 0;
29226048Sminshall 	char *pt = pasv;
29310296Ssam 
294*38133Srick 	oldintr = signal(SIGINT, cmdabort);
29510296Ssam 	for (;;) {
29610296Ssam 		dig = n = code = 0;
29737229Skarels 		cp = reply_string;
29810296Ssam 		while ((c = getc(cin)) != '\n') {
29927687Sminshall 			if (c == IAC) {     /* handle telnet commands */
30027687Sminshall 				switch (c = getc(cin)) {
30127687Sminshall 				case WILL:
30227687Sminshall 				case WONT:
30327687Sminshall 					c = getc(cin);
304*38133Srick 					fprintf(cout, "%c%c%c", IAC, DONT, c);
30527687Sminshall 					(void) fflush(cout);
30627687Sminshall 					break;
30727687Sminshall 				case DO:
30827687Sminshall 				case DONT:
30927687Sminshall 					c = getc(cin);
310*38133Srick 					fprintf(cout, "%c%c%c", IAC, WONT, c);
31127687Sminshall 					(void) fflush(cout);
31227687Sminshall 					break;
31327687Sminshall 				default:
31427687Sminshall 					break;
31527687Sminshall 				}
31627687Sminshall 				continue;
31727687Sminshall 			}
31810296Ssam 			dig++;
31910296Ssam 			if (c == EOF) {
32026048Sminshall 				if (expecteof) {
32126048Sminshall 					(void) signal(SIGINT,oldintr);
32226048Sminshall 					code = 221;
32310296Ssam 					return (0);
32426048Sminshall 				}
32510296Ssam 				lostpeer();
32626048Sminshall 				if (verbose) {
32726048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
32826048Sminshall 					(void) fflush(stdout);
32926048Sminshall 				}
33033772Scsvsj 				code = 421;
33133772Scsvsj 				return(4);
33210296Ssam 			}
33326048Sminshall 			if (c != '\r' && (verbose > 0 ||
33426048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
33526448Slepreau 				if (proxflag &&
33626448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
33726048Sminshall 					printf("%s:",hostname);
33826496Sminshall 				(void) putchar(c);
33926048Sminshall 			}
34010296Ssam 			if (dig < 4 && isdigit(c))
34110296Ssam 				code = code * 10 + (c - '0');
34226448Slepreau 			if (!pflag && code == 227)
34326048Sminshall 				pflag = 1;
34426448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
34526048Sminshall 				pflag = 2;
34626048Sminshall 			if (pflag == 2) {
34726448Slepreau 				if (c != '\r' && c != ')')
34826048Sminshall 					*pt++ = c;
34926048Sminshall 				else {
35026048Sminshall 					*pt = '\0';
35126048Sminshall 					pflag = 3;
35226048Sminshall 				}
35326048Sminshall 			}
35426048Sminshall 			if (dig == 4 && c == '-') {
35526448Slepreau 				if (continuation)
35626048Sminshall 					code = 0;
35710296Ssam 				continuation++;
35826048Sminshall 			}
35910296Ssam 			if (n == 0)
36010296Ssam 				n = c;
36137229Skarels 			if (cp < &reply_string[sizeof(reply_string) - 1])
36237229Skarels 				*cp++ = c;
36310296Ssam 		}
36426048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
36526496Sminshall 			(void) putchar(c);
36611346Ssam 			(void) fflush (stdout);
36711346Ssam 		}
36810296Ssam 		if (continuation && code != originalcode) {
36910296Ssam 			if (originalcode == 0)
37010296Ssam 				originalcode = code;
37110296Ssam 			continue;
37210296Ssam 		}
37336935Skarels 		*cp = '\0';
37426448Slepreau 		if (n != '1')
37526048Sminshall 			cpend = 0;
37626048Sminshall 		(void) signal(SIGINT,oldintr);
37726448Slepreau 		if (code == 421 || originalcode == 421)
37826048Sminshall 			lostpeer();
37926448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
38026048Sminshall 			(*oldintr)();
38125907Smckusick 		return (n - '0');
38210296Ssam 	}
38310296Ssam }
38410296Ssam 
38526048Sminshall empty(mask, sec)
38627687Sminshall 	struct fd_set *mask;
38726048Sminshall 	int sec;
38826048Sminshall {
38926048Sminshall 	struct timeval t;
39026048Sminshall 
39126048Sminshall 	t.tv_sec = (long) sec;
39226048Sminshall 	t.tv_usec = 0;
39327687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
39426048Sminshall }
39526048Sminshall 
39610296Ssam jmp_buf	sendabort;
39710296Ssam 
39810296Ssam abortsend()
39910296Ssam {
40010296Ssam 
40126048Sminshall 	mflag = 0;
40226048Sminshall 	abrtflag = 0;
403*38133Srick 	printf("\nsend aborted\nwaiting for remote to finish abort\n");
40426048Sminshall 	(void) fflush(stdout);
40510296Ssam 	longjmp(sendabort, 1);
40610296Ssam }
40710296Ssam 
40836940Skarels #define HASHBYTES 1024
40936940Skarels 
41037225Skarels sendrequest(cmd, local, remote, printnames)
41110296Ssam 	char *cmd, *local, *remote;
41237225Skarels 	int printnames;
41310296Ssam {
41435659Sbostic 	FILE *fin, *dout = 0, *popen();
415*38133Srick 	int (*closefunc)(), pclose(), fclose();
416*38133Srick 	sig_t (*oldintr)(), (*oldintp)();
41726048Sminshall 	int abortsend();
41836942Skarels 	char buf[BUFSIZ], *bufp;
41936940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
42011346Ssam 	register int c, d;
42110296Ssam 	struct stat st;
42210296Ssam 	struct timeval start, stop;
42336935Skarels 	char *mode;
42410296Ssam 
42537225Skarels 	if (verbose && printnames) {
42637225Skarels 		if (local && *local != '-')
42737225Skarels 			printf("local: %s ", local);
42837225Skarels 		if (remote)
42937225Skarels 			printf("remote: %s\n", remote);
43037225Skarels 	}
43126048Sminshall 	if (proxy) {
43226048Sminshall 		proxtrans(cmd, local, remote);
43326048Sminshall 		return;
43426048Sminshall 	}
43538033Skarels 	if (curtype != type)
43638033Skarels 		changetype(type, 0);
43710296Ssam 	closefunc = NULL;
43826048Sminshall 	oldintr = NULL;
43926048Sminshall 	oldintp = NULL;
44036935Skarels 	mode = "w";
44126048Sminshall 	if (setjmp(sendabort)) {
44226048Sminshall 		while (cpend) {
44326048Sminshall 			(void) getreply(0);
44426048Sminshall 		}
44526048Sminshall 		if (data >= 0) {
44626048Sminshall 			(void) close(data);
44726048Sminshall 			data = -1;
44826048Sminshall 		}
44926448Slepreau 		if (oldintr)
45026048Sminshall 			(void) signal(SIGINT,oldintr);
45126448Slepreau 		if (oldintp)
45226048Sminshall 			(void) signal(SIGPIPE,oldintp);
45326048Sminshall 		code = -1;
45426048Sminshall 		return;
45526048Sminshall 	}
45610296Ssam 	oldintr = signal(SIGINT, abortsend);
45710296Ssam 	if (strcmp(local, "-") == 0)
45810296Ssam 		fin = stdin;
45910296Ssam 	else if (*local == '|') {
46026048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
46135659Sbostic 		fin = popen(local + 1, "r");
46210296Ssam 		if (fin == NULL) {
46326048Sminshall 			perror(local + 1);
46426048Sminshall 			(void) signal(SIGINT, oldintr);
46526048Sminshall 			(void) signal(SIGPIPE, oldintp);
46626048Sminshall 			code = -1;
46726048Sminshall 			return;
46810296Ssam 		}
46935659Sbostic 		closefunc = pclose;
47010296Ssam 	} else {
47110296Ssam 		fin = fopen(local, "r");
47210296Ssam 		if (fin == NULL) {
47310296Ssam 			perror(local);
47426048Sminshall 			(void) signal(SIGINT, oldintr);
47526048Sminshall 			code = -1;
47626048Sminshall 			return;
47710296Ssam 		}
47810296Ssam 		closefunc = fclose;
47910296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
48010296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
48126496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
48226048Sminshall 			(void) signal(SIGINT, oldintr);
48336935Skarels 			fclose(fin);
48426048Sminshall 			code = -1;
48526048Sminshall 			return;
48610296Ssam 		}
48710296Ssam 	}
48826048Sminshall 	if (initconn()) {
48926048Sminshall 		(void) signal(SIGINT, oldintr);
49026448Slepreau 		if (oldintp)
49126048Sminshall 			(void) signal(SIGPIPE, oldintp);
49226048Sminshall 		code = -1;
49336935Skarels 		if (closefunc != NULL)
49436935Skarels 			(*closefunc)(fin);
49526048Sminshall 		return;
49626048Sminshall 	}
49726448Slepreau 	if (setjmp(sendabort))
49826048Sminshall 		goto abort;
49936935Skarels 
50037225Skarels 	if (restart_point &&
50137225Skarels 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
50237225Skarels 		if (fseek(fin, (long) restart_point, 0) < 0) {
50337225Skarels 			perror(local);
50437225Skarels 			restart_point = 0;
50537225Skarels 			if (closefunc != NULL)
50637225Skarels 				(*closefunc)(fin);
50737225Skarels 			return;
50837225Skarels 		}
50937225Skarels 		if (command("REST %ld", (long) restart_point)
51037225Skarels 			!= CONTINUE) {
51137225Skarels 			restart_point = 0;
51237225Skarels 			if (closefunc != NULL)
51337225Skarels 				(*closefunc)(fin);
51437225Skarels 			return;
51537225Skarels 		}
51637225Skarels 		restart_point = 0;
51737225Skarels 		mode = "r+w";
51837225Skarels 	}
51910296Ssam 	if (remote) {
52026048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
52126048Sminshall 			(void) signal(SIGINT, oldintr);
52226448Slepreau 			if (oldintp)
52326048Sminshall 				(void) signal(SIGPIPE, oldintp);
52436935Skarels 			if (closefunc != NULL)
52536935Skarels 				(*closefunc)(fin);
52626048Sminshall 			return;
52726048Sminshall 		}
52810296Ssam 	} else
52926048Sminshall 		if (command("%s", cmd) != PRELIM) {
53026048Sminshall 			(void) signal(SIGINT, oldintr);
53126448Slepreau 			if (oldintp)
53226048Sminshall 				(void) signal(SIGPIPE, oldintp);
53336935Skarels 			if (closefunc != NULL)
53436935Skarels 				(*closefunc)(fin);
53526048Sminshall 			return;
53626048Sminshall 		}
53736935Skarels 	dout = dataconn(mode);
53826448Slepreau 	if (dout == NULL)
53926048Sminshall 		goto abort;
54026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
54136935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
54211219Ssam 	switch (type) {
54311219Ssam 
54411219Ssam 	case TYPE_I:
54511219Ssam 	case TYPE_L:
54611346Ssam 		errno = d = 0;
54736942Skarels 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
54811219Ssam 			bytes += c;
54936942Skarels 			for (bufp = buf; c > 0; c -= d, bufp += d)
55036942Skarels 				if ((d = write(fileno(dout), bufp, c)) <= 0)
55136942Skarels 					break;
55211651Ssam 			if (hash) {
55336940Skarels 				while (bytes >= hashbytes) {
55436940Skarels 					(void) putchar('#');
55536940Skarels 					hashbytes += HASHBYTES;
55636940Skarels 				}
55726496Sminshall 				(void) fflush(stdout);
55811651Ssam 			}
55911219Ssam 		}
56013213Ssam 		if (hash && bytes > 0) {
56136940Skarels 			if (bytes < HASHBYTES)
56236940Skarels 				(void) putchar('#');
56326496Sminshall 			(void) putchar('\n');
56426496Sminshall 			(void) fflush(stdout);
56511651Ssam 		}
56611219Ssam 		if (c < 0)
56711219Ssam 			perror(local);
56836942Skarels 		if (d <= 0) {
56936942Skarels 			if (d == 0)
57036942Skarels 				fprintf(stderr, "netout: write returned 0?\n");
57136942Skarels 			else if (errno != EPIPE)
57236935Skarels 				perror("netout");
57336935Skarels 			bytes = -1;
57436935Skarels 		}
57511219Ssam 		break;
57611219Ssam 
57711219Ssam 	case TYPE_A:
57811219Ssam 		while ((c = getc(fin)) != EOF) {
57911219Ssam 			if (c == '\n') {
58011651Ssam 				while (hash && (bytes >= hashbytes)) {
58126496Sminshall 					(void) putchar('#');
58226496Sminshall 					(void) fflush(stdout);
58336940Skarels 					hashbytes += HASHBYTES;
58411651Ssam 				}
58511219Ssam 				if (ferror(dout))
58611219Ssam 					break;
58726496Sminshall 				(void) putc('\r', dout);
58811219Ssam 				bytes++;
58911219Ssam 			}
59026496Sminshall 			(void) putc(c, dout);
59111219Ssam 			bytes++;
59226048Sminshall 	/*		if (c == '\r') {			  	*/
59326496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
59426048Sminshall 	/*			bytes++;				*/
59526048Sminshall 	/*		}                          			*/
59611219Ssam 		}
59711651Ssam 		if (hash) {
59813213Ssam 			if (bytes < hashbytes)
59926496Sminshall 				(void) putchar('#');
60026496Sminshall 			(void) putchar('\n');
60126496Sminshall 			(void) fflush(stdout);
60211651Ssam 		}
60311219Ssam 		if (ferror(fin))
60411219Ssam 			perror(local);
60536935Skarels 		if (ferror(dout)) {
60636935Skarels 			if (errno != EPIPE)
60736935Skarels 				perror("netout");
60836935Skarels 			bytes = -1;
60936935Skarels 		}
61011219Ssam 		break;
61110296Ssam 	}
61226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
61310296Ssam 	if (closefunc != NULL)
61426048Sminshall 		(*closefunc)(fin);
61510296Ssam 	(void) fclose(dout);
61626048Sminshall 	(void) getreply(0);
61726048Sminshall 	(void) signal(SIGINT, oldintr);
61836935Skarels 	if (oldintp)
61936935Skarels 		(void) signal(SIGPIPE, oldintp);
62035699Sbostic 	if (bytes > 0)
62137225Skarels 		ptransfer("sent", bytes, &start, &stop);
62210296Ssam 	return;
62326048Sminshall abort:
62426496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
62526048Sminshall 	(void) signal(SIGINT, oldintr);
62626448Slepreau 	if (oldintp)
62726048Sminshall 		(void) signal(SIGPIPE, oldintp);
62826048Sminshall 	if (!cpend) {
62926048Sminshall 		code = -1;
63026048Sminshall 		return;
63126048Sminshall 	}
63226048Sminshall 	if (data >= 0) {
63326048Sminshall 		(void) close(data);
63426048Sminshall 		data = -1;
63526048Sminshall 	}
63626448Slepreau 	if (dout)
63726048Sminshall 		(void) fclose(dout);
63826048Sminshall 	(void) getreply(0);
63926048Sminshall 	code = -1;
64010296Ssam 	if (closefunc != NULL && fin != NULL)
64126048Sminshall 		(*closefunc)(fin);
64235699Sbostic 	if (bytes > 0)
64337225Skarels 		ptransfer("sent", bytes, &start, &stop);
64410296Ssam }
64510296Ssam 
64610296Ssam jmp_buf	recvabort;
64710296Ssam 
648*38133Srick sig_t
64910296Ssam abortrecv()
65010296Ssam {
65110296Ssam 
65226048Sminshall 	mflag = 0;
65326048Sminshall 	abrtflag = 0;
654*38133Srick 	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
65526048Sminshall 	(void) fflush(stdout);
65610296Ssam 	longjmp(recvabort, 1);
65710296Ssam }
65810296Ssam 
65937225Skarels recvrequest(cmd, local, remote, mode, printnames)
66011651Ssam 	char *cmd, *local, *remote, *mode;
66110296Ssam {
66235659Sbostic 	FILE *fout, *din = 0, *popen();
663*38133Srick 	int (*closefunc)(), pclose(), fclose();
664*38133Srick 	sig_t (*oldintr)(), (*oldintp)(), abortrecv();
665*38133Srick 	int is_retr, tcrflag, bare_lfs = 0;
666*38133Srick 	char *gunique();
667*38133Srick 	static int bufsize;
66836944Skarels 	static char *buf;
66936940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
67011346Ssam 	register int c, d;
67110296Ssam 	struct timeval start, stop;
67236940Skarels 	struct stat st;
67336940Skarels 	extern 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) {
70910296Ssam 				perror(local);
71026048Sminshall 				(void) signal(SIGINT, oldintr);
71126048Sminshall 				code = -1;
71226048Sminshall 				return;
71310296Ssam 			}
71426048Sminshall 			if (dir != NULL)
71526048Sminshall 				*dir = 0;
71626048Sminshall 			d = access(dir ? local : ".", 2);
71726048Sminshall 			if (dir != NULL)
71826048Sminshall 				*dir = '/';
71926048Sminshall 			if (d < 0) {
72026048Sminshall 				perror(local);
72126048Sminshall 				(void) signal(SIGINT, oldintr);
72226048Sminshall 				code = -1;
72326048Sminshall 				return;
72426048Sminshall 			}
72526048Sminshall 			if (!runique && errno == EACCES &&
72636935Skarels 			    chmod(local, 0600) < 0) {
72726048Sminshall 				perror(local);
72826048Sminshall 				(void) signal(SIGINT, oldintr);
72926048Sminshall 				code = -1;
73026048Sminshall 				return;
73126048Sminshall 			}
73226048Sminshall 			if (runique && errno == EACCES &&
73326048Sminshall 			   (local = gunique(local)) == NULL) {
73426048Sminshall 				(void) signal(SIGINT, oldintr);
73526048Sminshall 				code = -1;
73626048Sminshall 				return;
73726048Sminshall 			}
73810296Ssam 		}
73926048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
74026048Sminshall 			(void) signal(SIGINT, oldintr);
74126048Sminshall 			code = -1;
74226048Sminshall 			return;
74326048Sminshall 		}
74426048Sminshall 	}
74538033Skarels 	if (!is_retr) {
74638033Skarels 		if (curtype != TYPE_A)
74738033Skarels 			changetype(TYPE_A, 0);
74838033Skarels 	} else if (curtype != type)
74938033Skarels 		changetype(type, 0);
75026048Sminshall 	if (initconn()) {
75126048Sminshall 		(void) signal(SIGINT, oldintr);
75226048Sminshall 		code = -1;
75326048Sminshall 		return;
75426048Sminshall 	}
75526448Slepreau 	if (setjmp(recvabort))
75626048Sminshall 		goto abort;
75738033Skarels 	if (is_retr && restart_point &&
75838033Skarels 	    command("REST %ld", (long) restart_point) != CONTINUE)
75938033Skarels 		return;
76010296Ssam 	if (remote) {
76126048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
76226048Sminshall 			(void) signal(SIGINT, oldintr);
76326048Sminshall 			return;
76426048Sminshall 		}
76526048Sminshall 	} else {
76626048Sminshall 		if (command("%s", cmd) != PRELIM) {
76726048Sminshall 			(void) signal(SIGINT, oldintr);
76826048Sminshall 			return;
76926048Sminshall 		}
77026048Sminshall 	}
77126048Sminshall 	din = dataconn("r");
77226048Sminshall 	if (din == NULL)
77326048Sminshall 		goto abort;
77426448Slepreau 	if (strcmp(local, "-") == 0)
77510296Ssam 		fout = stdout;
77610296Ssam 	else if (*local == '|') {
77726048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
77835659Sbostic 		fout = popen(local + 1, "w");
77926048Sminshall 		if (fout == NULL) {
78026048Sminshall 			perror(local+1);
78126048Sminshall 			goto abort;
78226048Sminshall 		}
78335659Sbostic 		closefunc = pclose;
78436940Skarels 	} else {
78511651Ssam 		fout = fopen(local, mode);
78626048Sminshall 		if (fout == NULL) {
78726048Sminshall 			perror(local);
78826048Sminshall 			goto abort;
78926048Sminshall 		}
79010296Ssam 		closefunc = fclose;
79110296Ssam 	}
79236940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
79336940Skarels 		st.st_blksize = BUFSIZ;
79436940Skarels 	if (st.st_blksize > bufsize) {
79536940Skarels 		if (buf)
79636940Skarels 			(void) free(buf);
797*38133Srick 		buf = malloc((unsigned)st.st_blksize);
79836940Skarels 		if (buf == NULL) {
79936940Skarels 			perror("malloc");
80036944Skarels 			bufsize = 0;
80136940Skarels 			goto abort;
80236940Skarels 		}
80336940Skarels 		bufsize = st.st_blksize;
80436940Skarels 	}
80526496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
80638033Skarels 	switch (curtype) {
80711219Ssam 
80811219Ssam 	case TYPE_I:
80911219Ssam 	case TYPE_L:
81037225Skarels 		if (restart_point &&
81137225Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
81237225Skarels 			perror(local);
81337225Skarels 			if (closefunc != NULL)
81437225Skarels 				(*closefunc)(fout);
81537225Skarels 			return;
81637225Skarels 		}
81711346Ssam 		errno = d = 0;
81836940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
81936944Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
82011219Ssam 				break;
82111219Ssam 			bytes += c;
82211651Ssam 			if (hash) {
82336940Skarels 				while (bytes >= hashbytes) {
82436940Skarels 					(void) putchar('#');
82536940Skarels 					hashbytes += HASHBYTES;
82636940Skarels 				}
82726496Sminshall 				(void) fflush(stdout);
82811651Ssam 			}
82911219Ssam 		}
83013213Ssam 		if (hash && bytes > 0) {
83136940Skarels 			if (bytes < HASHBYTES)
83236940Skarels 				(void) putchar('#');
83326496Sminshall 			(void) putchar('\n');
83426496Sminshall 			(void) fflush(stdout);
83511651Ssam 		}
83636935Skarels 		if (c < 0) {
83736935Skarels 			if (errno != EPIPE)
83836935Skarels 				perror("netin");
83936935Skarels 			bytes = -1;
84036935Skarels 		}
84136942Skarels 		if (d < c) {
84236942Skarels 			if (d < 0)
84336942Skarels 				perror(local);
84436942Skarels 			else
84536942Skarels 				fprintf(stderr, "%s: short write\n", local);
84636942Skarels 		}
84711219Ssam 		break;
84811219Ssam 
84911219Ssam 	case TYPE_A:
85037225Skarels 		if (restart_point) {
85137225Skarels 			register int i, n, c;
85237225Skarels 
85337225Skarels 			if (fseek(fout, 0L, L_SET) < 0)
85437225Skarels 				goto done;
85537225Skarels 			n = restart_point;
85637225Skarels 			i = 0;
85737225Skarels 			while (i++ < n) {
85837225Skarels 				if ((c=getc(fout)) == EOF)
85937225Skarels 					goto done;
86037225Skarels 				if (c == '\n')
86137225Skarels 					i++;
86237225Skarels 			}
86337225Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
86437225Skarels done:
86537225Skarels 				perror(local);
86637225Skarels 				if (closefunc != NULL)
86737225Skarels 					(*closefunc)(fout);
86837225Skarels 				return;
86937225Skarels 			}
87037225Skarels 		}
87111219Ssam 		while ((c = getc(din)) != EOF) {
872*38133Srick 			if (c == '\n')
873*38133Srick 				bare_lfs++;
87427749Sminshall 			while (c == '\r') {
87511651Ssam 				while (hash && (bytes >= hashbytes)) {
87626496Sminshall 					(void) putchar('#');
87726496Sminshall 					(void) fflush(stdout);
87836940Skarels 					hashbytes += HASHBYTES;
87911651Ssam 				}
88010296Ssam 				bytes++;
88126048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
88236940Skarels 					if (ferror(fout))
88336940Skarels 						goto break2;
88436940Skarels 					(void) putc('\r', fout);
88536942Skarels 					if (c == '\0') {
88636942Skarels 						bytes++;
88736940Skarels 						goto contin2;
88836942Skarels 					}
88936942Skarels 					if (c == EOF)
89036942Skarels 						goto contin2;
89111219Ssam 				}
89211219Ssam 			}
89336940Skarels 			(void) putc(c, fout);
89411219Ssam 			bytes++;
89536940Skarels 	contin2:	;
89610296Ssam 		}
89736940Skarels break2:
898*38133Srick 		if (bare_lfs) {
899*38133Srick 			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
900*38133Srick 			printf("File may not have transferred correctly.\n");
901*38133Srick 		}
90211651Ssam 		if (hash) {
90313213Ssam 			if (bytes < hashbytes)
90426496Sminshall 				(void) putchar('#');
90526496Sminshall 			(void) putchar('\n');
90626496Sminshall 			(void) fflush(stdout);
90711651Ssam 		}
90836944Skarels 		if (ferror(din)) {
90936935Skarels 			if (errno != EPIPE)
91036944Skarels 				perror("netin");
91136935Skarels 			bytes = -1;
91236935Skarels 		}
91336940Skarels 		if (ferror(fout))
91436944Skarels 			perror(local);
91511219Ssam 		break;
91610296Ssam 	}
91726448Slepreau 	if (closefunc != NULL)
91826048Sminshall 		(*closefunc)(fout);
91926496Sminshall 	(void) signal(SIGINT, oldintr);
92026448Slepreau 	if (oldintp)
92126048Sminshall 		(void) signal(SIGPIPE, oldintp);
92226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
92310296Ssam 	(void) fclose(din);
92426048Sminshall 	(void) getreply(0);
92536935Skarels 	if (bytes > 0 && is_retr)
92637225Skarels 		ptransfer("received", bytes, &start, &stop);
92726048Sminshall 	return;
92826048Sminshall abort:
92926048Sminshall 
93027687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
93126048Sminshall 
93226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
93326448Slepreau 	if (oldintp)
93426048Sminshall 		(void) signal(SIGPIPE, oldintr);
935*38133Srick 	(void) signal(SIGINT, SIG_IGN);
93626048Sminshall 	if (!cpend) {
93726048Sminshall 		code = -1;
938*38133Srick 		(void) signal(SIGINT, oldintr);
93926048Sminshall 		return;
94026048Sminshall 	}
94126048Sminshall 
942*38133Srick 	abort_remote(din);
94326048Sminshall 	code = -1;
94426048Sminshall 	if (data >= 0) {
94526048Sminshall 		(void) close(data);
94626048Sminshall 		data = -1;
94726048Sminshall 	}
94826448Slepreau 	if (closefunc != NULL && fout != NULL)
94926048Sminshall 		(*closefunc)(fout);
95026448Slepreau 	if (din)
95126048Sminshall 		(void) fclose(din);
95235699Sbostic 	if (bytes > 0)
95337225Skarels 		ptransfer("received", bytes, &start, &stop);
954*38133Srick 	(void) signal(SIGINT, oldintr);
95510296Ssam }
95610296Ssam 
95710296Ssam /*
95810296Ssam  * Need to start a listen on the data channel
95910296Ssam  * before we send the command, otherwise the
96010296Ssam  * server's connect may fail.
96110296Ssam  */
962*38133Srick int sendport;
96311651Ssam 
96410296Ssam initconn()
96510296Ssam {
96610296Ssam 	register char *p, *a;
96726048Sminshall 	int result, len, tmpno = 0;
96826993Skarels 	int on = 1;
96910296Ssam 
97011651Ssam noport:
97110296Ssam 	data_addr = myctladdr;
97211651Ssam 	if (sendport)
97311651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
97411651Ssam 	if (data != -1)
975*38133Srick 		(void) close(data);
97618287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
97710296Ssam 	if (data < 0) {
97810296Ssam 		perror("ftp: socket");
97926448Slepreau 		if (tmpno)
98026048Sminshall 			sendport = 1;
98110296Ssam 		return (1);
98210296Ssam 	}
98312397Ssam 	if (!sendport)
98427687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
98533224Sbostic 			perror("ftp: setsockopt (reuse address)");
98612397Ssam 			goto bad;
98712397Ssam 		}
98826496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
98910296Ssam 		perror("ftp: bind");
99010296Ssam 		goto bad;
99110296Ssam 	}
99210296Ssam 	if (options & SO_DEBUG &&
99327687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
99410296Ssam 		perror("ftp: setsockopt (ignored)");
99511627Ssam 	len = sizeof (data_addr);
996*38133Srick 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
99711627Ssam 		perror("ftp: getsockname");
99810296Ssam 		goto bad;
99910296Ssam 	}
100026448Slepreau 	if (listen(data, 1) < 0)
100110296Ssam 		perror("ftp: listen");
100211651Ssam 	if (sendport) {
100311651Ssam 		a = (char *)&data_addr.sin_addr;
100411651Ssam 		p = (char *)&data_addr.sin_port;
100510296Ssam #define	UC(b)	(((int)b)&0xff)
100611651Ssam 		result =
100711651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
100811651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
100911651Ssam 		      UC(p[0]), UC(p[1]));
101011651Ssam 		if (result == ERROR && sendport == -1) {
101111651Ssam 			sendport = 0;
101226048Sminshall 			tmpno = 1;
101311651Ssam 			goto noport;
101411651Ssam 		}
101511651Ssam 		return (result != COMPLETE);
101611651Ssam 	}
101726448Slepreau 	if (tmpno)
101826048Sminshall 		sendport = 1;
101911651Ssam 	return (0);
102010296Ssam bad:
102110296Ssam 	(void) close(data), data = -1;
102226448Slepreau 	if (tmpno)
102326048Sminshall 		sendport = 1;
102410296Ssam 	return (1);
102510296Ssam }
102610296Ssam 
102710296Ssam FILE *
102810296Ssam dataconn(mode)
102910296Ssam 	char *mode;
103010296Ssam {
103110296Ssam 	struct sockaddr_in from;
103210296Ssam 	int s, fromlen = sizeof (from);
103310296Ssam 
103426496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
103510296Ssam 	if (s < 0) {
103610296Ssam 		perror("ftp: accept");
103710296Ssam 		(void) close(data), data = -1;
103810296Ssam 		return (NULL);
103910296Ssam 	}
104010296Ssam 	(void) close(data);
104110296Ssam 	data = s;
104210296Ssam 	return (fdopen(data, mode));
104310296Ssam }
104410296Ssam 
104537225Skarels ptransfer(direction, bytes, t0, t1)
104637225Skarels 	char *direction;
104711651Ssam 	long bytes;
104810296Ssam 	struct timeval *t0, *t1;
104910296Ssam {
105010296Ssam 	struct timeval td;
105116437Sleres 	float s, bs;
105210296Ssam 
105335699Sbostic 	if (verbose) {
105435699Sbostic 		tvsub(&td, t1, t0);
105535699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
105610296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
105735699Sbostic 		bs = bytes / nz(s);
105835699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
105935699Sbostic 		    bytes, direction, s, bs / 1024.);
106035699Sbostic 	}
106110296Ssam }
106210296Ssam 
106326496Sminshall /*tvadd(tsum, t0)
106410296Ssam 	struct timeval *tsum, *t0;
106510296Ssam {
106610296Ssam 
106710296Ssam 	tsum->tv_sec += t0->tv_sec;
106810296Ssam 	tsum->tv_usec += t0->tv_usec;
106910296Ssam 	if (tsum->tv_usec > 1000000)
107010296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
107126496Sminshall } */
107210296Ssam 
107310296Ssam tvsub(tdiff, t1, t0)
107410296Ssam 	struct timeval *tdiff, *t1, *t0;
107510296Ssam {
107610296Ssam 
107710296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
107810296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
107910296Ssam 	if (tdiff->tv_usec < 0)
108010296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
108110296Ssam }
108226048Sminshall 
1083*38133Srick sig_t
108426048Sminshall psabort()
108526048Sminshall {
108626048Sminshall 	extern int abrtflag;
108726048Sminshall 
108826048Sminshall 	abrtflag++;
108926048Sminshall }
109026048Sminshall 
109126048Sminshall pswitch(flag)
109226048Sminshall 	int flag;
109326048Sminshall {
109426048Sminshall 	extern int proxy, abrtflag;
1095*38133Srick 	sig_t (*oldintr)();
109626048Sminshall 	static struct comvars {
109726048Sminshall 		int connect;
109828469Skarels 		char name[MAXHOSTNAMELEN];
109926048Sminshall 		struct sockaddr_in mctl;
110026048Sminshall 		struct sockaddr_in hctl;
110126048Sminshall 		FILE *in;
110226048Sminshall 		FILE *out;
110326048Sminshall 		int tpe;
110438033Skarels 		int curtpe;
110526048Sminshall 		int cpnd;
110626048Sminshall 		int sunqe;
110726048Sminshall 		int runqe;
110826048Sminshall 		int mcse;
110926048Sminshall 		int ntflg;
111026048Sminshall 		char nti[17];
111126048Sminshall 		char nto[17];
111226048Sminshall 		int mapflg;
111326048Sminshall 		char mi[MAXPATHLEN];
111426048Sminshall 		char mo[MAXPATHLEN];
111538033Skarels 	} proxstruct, tmpstruct;
111626048Sminshall 	struct comvars *ip, *op;
111726048Sminshall 
111826048Sminshall 	abrtflag = 0;
111926048Sminshall 	oldintr = signal(SIGINT, psabort);
112026048Sminshall 	if (flag) {
112126448Slepreau 		if (proxy)
112226048Sminshall 			return;
112326048Sminshall 		ip = &tmpstruct;
112426048Sminshall 		op = &proxstruct;
112526048Sminshall 		proxy++;
112638033Skarels 	} else {
112726448Slepreau 		if (!proxy)
112826048Sminshall 			return;
112926048Sminshall 		ip = &proxstruct;
113026048Sminshall 		op = &tmpstruct;
113126048Sminshall 		proxy = 0;
113226048Sminshall 	}
113326048Sminshall 	ip->connect = connected;
113426048Sminshall 	connected = op->connect;
113528469Skarels 	if (hostname) {
113628469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
113728469Skarels 		ip->name[strlen(ip->name)] = '\0';
113828469Skarels 	} else
113928469Skarels 		ip->name[0] = 0;
114026048Sminshall 	hostname = op->name;
114126048Sminshall 	ip->hctl = hisctladdr;
114226048Sminshall 	hisctladdr = op->hctl;
114326048Sminshall 	ip->mctl = myctladdr;
114426048Sminshall 	myctladdr = op->mctl;
114526048Sminshall 	ip->in = cin;
114626048Sminshall 	cin = op->in;
114726048Sminshall 	ip->out = cout;
114826048Sminshall 	cout = op->out;
114926048Sminshall 	ip->tpe = type;
115026048Sminshall 	type = op->tpe;
115138033Skarels 	ip->curtpe = curtype;
115238033Skarels 	curtype = op->curtpe;
115326048Sminshall 	ip->cpnd = cpend;
115426048Sminshall 	cpend = op->cpnd;
115526048Sminshall 	ip->sunqe = sunique;
115626048Sminshall 	sunique = op->sunqe;
115726048Sminshall 	ip->runqe = runique;
115826048Sminshall 	runique = op->runqe;
115926048Sminshall 	ip->mcse = mcase;
116026048Sminshall 	mcase = op->mcse;
116126048Sminshall 	ip->ntflg = ntflag;
116226048Sminshall 	ntflag = op->ntflg;
116326496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
116426048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
116526496Sminshall 	(void) strcpy(ntin, op->nti);
116626496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
116726048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
116826496Sminshall 	(void) strcpy(ntout, op->nto);
116926048Sminshall 	ip->mapflg = mapflag;
117026048Sminshall 	mapflag = op->mapflg;
117126496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
117226048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
117326496Sminshall 	(void) strcpy(mapin, op->mi);
117426496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
117526048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
117626496Sminshall 	(void) strcpy(mapout, op->mo);
117726048Sminshall 	(void) signal(SIGINT, oldintr);
117826048Sminshall 	if (abrtflag) {
117926048Sminshall 		abrtflag = 0;
118026048Sminshall 		(*oldintr)();
118126448Slepreau 	}
118226048Sminshall }
118326048Sminshall 
118426048Sminshall jmp_buf ptabort;
118526048Sminshall int ptabflg;
118626048Sminshall 
1187*38133Srick sig_t
118826048Sminshall abortpt()
118926048Sminshall {
119026048Sminshall 	printf("\n");
119126496Sminshall 	(void) fflush(stdout);
119226048Sminshall 	ptabflg++;
119326048Sminshall 	mflag = 0;
119426048Sminshall 	abrtflag = 0;
119526048Sminshall 	longjmp(ptabort, 1);
119626048Sminshall }
119726048Sminshall 
119826048Sminshall proxtrans(cmd, local, remote)
119926048Sminshall 	char *cmd, *local, *remote;
120026048Sminshall {
1201*38133Srick 	sig_t (*oldintr)(), abortpt();
1202*38133Srick 	int secndflag = 0, prox_type, nfnd;
120326048Sminshall 	extern jmp_buf ptabort;
120426048Sminshall 	char *cmd2;
120526496Sminshall 	struct fd_set mask;
120626048Sminshall 
120726448Slepreau 	if (strcmp(cmd, "RETR"))
120826048Sminshall 		cmd2 = "RETR";
120926448Slepreau 	else
121026048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
121138033Skarels 	if ((prox_type = type) == 0) {
121238033Skarels 		if (unix_server && unix_proxy)
121338033Skarels 			prox_type = TYPE_I;
121438033Skarels 		else
121538033Skarels 			prox_type = TYPE_A;
121638033Skarels 	}
121738033Skarels 	if (curtype != prox_type)
121838033Skarels 		changetype(prox_type, 1);
121926048Sminshall 	if (command("PASV") != COMPLETE) {
122038033Skarels 		printf("proxy server does not support third party transfers.\n");
122126048Sminshall 		return;
122226048Sminshall 	}
122326048Sminshall 	pswitch(0);
122426048Sminshall 	if (!connected) {
122526048Sminshall 		printf("No primary connection\n");
122626048Sminshall 		pswitch(1);
122726048Sminshall 		code = -1;
122826048Sminshall 		return;
122926048Sminshall 	}
123038033Skarels 	if (curtype != prox_type)
123138033Skarels 		changetype(prox_type, 1);
123226048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
123326048Sminshall 		pswitch(1);
123426048Sminshall 		return;
123526048Sminshall 	}
123626448Slepreau 	if (setjmp(ptabort))
123726048Sminshall 		goto abort;
123826048Sminshall 	oldintr = signal(SIGINT, abortpt);
123926048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
124026048Sminshall 		(void) signal(SIGINT, oldintr);
124126048Sminshall 		pswitch(1);
124226048Sminshall 		return;
124326048Sminshall 	}
124426048Sminshall 	sleep(2);
124526048Sminshall 	pswitch(1);
124626048Sminshall 	secndflag++;
124726448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
124826048Sminshall 		goto abort;
124926048Sminshall 	ptflag++;
125026048Sminshall 	(void) getreply(0);
125126048Sminshall 	pswitch(0);
125226048Sminshall 	(void) getreply(0);
125326048Sminshall 	(void) signal(SIGINT, oldintr);
125426048Sminshall 	pswitch(1);
125526048Sminshall 	ptflag = 0;
125626048Sminshall 	printf("local: %s remote: %s\n", local, remote);
125726048Sminshall 	return;
125826048Sminshall abort:
125926048Sminshall 	(void) signal(SIGINT, SIG_IGN);
126026048Sminshall 	ptflag = 0;
126126448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
126226048Sminshall 		pswitch(1);
126326448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
126426048Sminshall 		pswitch(0);
126526048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
126626048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
126726048Sminshall 			pswitch(0);
1268*38133Srick 			if (cpend)
1269*38133Srick 				abort_remote((FILE *) NULL);
127026048Sminshall 		}
127126048Sminshall 		pswitch(1);
127226448Slepreau 		if (ptabflg)
127326048Sminshall 			code = -1;
127426048Sminshall 		(void) signal(SIGINT, oldintr);
127526048Sminshall 		return;
127626048Sminshall 	}
1277*38133Srick 	if (cpend)
1278*38133Srick 		abort_remote((FILE *) NULL);
127926048Sminshall 	pswitch(!proxy);
128026048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
128126048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
128226048Sminshall 			pswitch(0);
1283*38133Srick 			if (cpend)
1284*38133Srick 				abort_remote((FILE *) NULL);
128526048Sminshall 			pswitch(1);
128626448Slepreau 			if (ptabflg)
128726048Sminshall 				code = -1;
128826048Sminshall 			(void) signal(SIGINT, oldintr);
128926048Sminshall 			return;
129026048Sminshall 		}
129126048Sminshall 	}
1292*38133Srick 	if (cpend)
1293*38133Srick 		abort_remote((FILE *) NULL);
129426048Sminshall 	pswitch(!proxy);
129526048Sminshall 	if (cpend) {
129627687Sminshall 		FD_ZERO(&mask);
129726496Sminshall 		FD_SET(fileno(cin), &mask);
1298*38133Srick 		if ((nfnd = empty(&mask, 10)) <= 0) {
129927687Sminshall 			if (nfnd < 0) {
130027687Sminshall 				perror("abort");
130127687Sminshall 			}
130226448Slepreau 			if (ptabflg)
130326048Sminshall 				code = -1;
130426048Sminshall 			lostpeer();
130526048Sminshall 		}
130626048Sminshall 		(void) getreply(0);
130726048Sminshall 		(void) getreply(0);
130826048Sminshall 	}
130926448Slepreau 	if (proxy)
131026048Sminshall 		pswitch(0);
131126048Sminshall 	pswitch(1);
131226448Slepreau 	if (ptabflg)
131326048Sminshall 		code = -1;
131426048Sminshall 	(void) signal(SIGINT, oldintr);
131526048Sminshall }
131626048Sminshall 
131726048Sminshall reset()
131826048Sminshall {
131926496Sminshall 	struct fd_set mask;
132026496Sminshall 	int nfnd = 1;
132126048Sminshall 
132227687Sminshall 	FD_ZERO(&mask);
132330946Scsvsj 	while (nfnd > 0) {
132426496Sminshall 		FD_SET(fileno(cin), &mask);
132527687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
132626048Sminshall 			perror("reset");
132726048Sminshall 			code = -1;
132826048Sminshall 			lostpeer();
132926048Sminshall 		}
133027687Sminshall 		else if (nfnd) {
133126048Sminshall 			(void) getreply(0);
133226496Sminshall 		}
133326048Sminshall 	}
133426048Sminshall }
133526048Sminshall 
133626048Sminshall char *
133726048Sminshall gunique(local)
133826048Sminshall 	char *local;
133926048Sminshall {
134026048Sminshall 	static char new[MAXPATHLEN];
134126048Sminshall 	char *cp = rindex(local, '/');
134226048Sminshall 	int d, count=0;
134326048Sminshall 	char ext = '1';
134426048Sminshall 
134526448Slepreau 	if (cp)
134626048Sminshall 		*cp = '\0';
134726048Sminshall 	d = access(cp ? local : ".", 2);
134826448Slepreau 	if (cp)
134926048Sminshall 		*cp = '/';
135026048Sminshall 	if (d < 0) {
135126048Sminshall 		perror(local);
135226048Sminshall 		return((char *) 0);
135326048Sminshall 	}
135426048Sminshall 	(void) strcpy(new, local);
135526048Sminshall 	cp = new + strlen(new);
135626048Sminshall 	*cp++ = '.';
135726048Sminshall 	while (!d) {
135826048Sminshall 		if (++count == 100) {
135926048Sminshall 			printf("runique: can't find unique file name.\n");
136026048Sminshall 			return((char *) 0);
136126048Sminshall 		}
136226048Sminshall 		*cp++ = ext;
136326048Sminshall 		*cp = '\0';
136426448Slepreau 		if (ext == '9')
136526048Sminshall 			ext = '0';
136626448Slepreau 		else
136726048Sminshall 			ext++;
136826448Slepreau 		if ((d = access(new, 0)) < 0)
136926048Sminshall 			break;
137026448Slepreau 		if (ext != '0')
137126048Sminshall 			cp--;
137226448Slepreau 		else if (*(cp - 2) == '.')
137326048Sminshall 			*(cp - 1) = '1';
137426048Sminshall 		else {
137526048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
137626048Sminshall 			cp--;
137726048Sminshall 		}
137826048Sminshall 	}
137926048Sminshall 	return(new);
138026048Sminshall }
1381*38133Srick 
1382*38133Srick abort_remote(din)
1383*38133Srick FILE *din;
1384*38133Srick {
1385*38133Srick 	char buf[BUFSIZ];
1386*38133Srick 	int nfnd;
1387*38133Srick 	struct fd_set mask;
1388*38133Srick 
1389*38133Srick 	/*
1390*38133Srick 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1391*38133Srick 	 * after urgent byte rather than before as is protocol now
1392*38133Srick 	 */
1393*38133Srick 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
1394*38133Srick 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1395*38133Srick 		perror("abort");
1396*38133Srick 	fprintf(cout,"%cABOR\r\n", DM);
1397*38133Srick 	(void) fflush(cout);
1398*38133Srick 	FD_ZERO(&mask);
1399*38133Srick 	FD_SET(fileno(cin), &mask);
1400*38133Srick 	if (din) {
1401*38133Srick 		FD_SET(fileno(din), &mask);
1402*38133Srick 	}
1403*38133Srick 	if ((nfnd = empty(&mask, 10)) <= 0) {
1404*38133Srick 		if (nfnd < 0) {
1405*38133Srick 			perror("abort");
1406*38133Srick 		}
1407*38133Srick 		if (ptabflg)
1408*38133Srick 			code = -1;
1409*38133Srick 		lostpeer();
1410*38133Srick 	}
1411*38133Srick 	if (din && FD_ISSET(fileno(din), &mask)) {
1412*38133Srick 		while (read(fileno(din), buf, BUFSIZ) > 0)
1413*38133Srick 			/* LOOP */;
1414*38133Srick 	}
1415*38133Srick 	if (getreply(0) == ERROR && code == 552) {
1416*38133Srick 		/* 552 needed for nic style abort */
1417*38133Srick 		(void) getreply(0);
1418*38133Srick 	}
1419*38133Srick 	(void) getreply(0);
1420*38133Srick }
1421