xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 33737)
121739Sdist /*
226048Sminshall  * Copyright (c) 1985 Regents of the University of California.
3*33737Sbostic  * All rights reserved.
4*33737Sbostic  *
5*33737Sbostic  * Redistribution and use in source and binary forms are permitted
6*33737Sbostic  * provided that this notice is preserved and that due credit is given
7*33737Sbostic  * to the University of California at Berkeley. The name of the University
8*33737Sbostic  * may not be used to endorse or promote products derived from this
9*33737Sbostic  * software without specific prior written permission. This software
10*33737Sbostic  * is provided ``as is'' without express or implied warranty.
1121739Sdist  */
1221739Sdist 
1310296Ssam #ifndef lint
14*33737Sbostic static char sccsid[] = "@(#)ftp.c	5.17 (Berkeley) 03/14/88";
15*33737Sbostic #endif /* not lint */
1610296Ssam 
1726048Sminshall #include "ftp_var.h"
1826048Sminshall 
1910296Ssam #include <sys/stat.h>
2010296Ssam #include <sys/ioctl.h>
2110296Ssam #include <sys/socket.h>
2213614Ssam #include <sys/time.h>
2328469Skarels #include <sys/param.h>
2410296Ssam 
2510296Ssam #include <netinet/in.h>
2612397Ssam #include <arpa/ftp.h>
2726048Sminshall #include <arpa/telnet.h>
2810296Ssam 
2910296Ssam #include <stdio.h>
3010296Ssam #include <signal.h>
3110296Ssam #include <errno.h>
3210296Ssam #include <netdb.h>
3326048Sminshall #include <fcntl.h>
3426048Sminshall #include <pwd.h>
3510296Ssam 
3610296Ssam struct	sockaddr_in hisctladdr;
3710296Ssam struct	sockaddr_in data_addr;
3810296Ssam int	data = -1;
3926048Sminshall int	abrtflag = 0;
4026048Sminshall int	ptflag = 0;
4110296Ssam int	connected;
4210296Ssam struct	sockaddr_in myctladdr;
4326496Sminshall uid_t	getuid();
4410296Ssam 
4510296Ssam FILE	*cin, *cout;
4610296Ssam FILE	*dataconn();
4710296Ssam 
4825904Skarels char *
4910296Ssam hookup(host, port)
5010296Ssam 	char *host;
5110296Ssam 	int port;
5210296Ssam {
5325904Skarels 	register struct hostent *hp = 0;
5427687Sminshall 	int s,len;
5525904Skarels 	static char hostnamebuf[80];
5610296Ssam 
5710296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5825904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
5925904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6025904Skarels 		hisctladdr.sin_family = AF_INET;
6125904Skarels 		(void) strcpy(hostnamebuf, host);
6226048Sminshall 	}
6326048Sminshall 	else {
6425100Sbloom 		hp = gethostbyname(host);
6525904Skarels 		if (hp == NULL) {
6625904Skarels 			printf("%s: unknown host\n", host);
6726048Sminshall 			code = -1;
6826048Sminshall 			return((char *) 0);
6925904Skarels 		}
7025904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7125904Skarels 		bcopy(hp->h_addr_list[0],
7225904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
7325904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
7410296Ssam 	}
7525904Skarels 	hostname = hostnamebuf;
7625904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7710296Ssam 	if (s < 0) {
7810296Ssam 		perror("ftp: socket");
7926048Sminshall 		code = -1;
8010296Ssam 		return (0);
8110296Ssam 	}
8210296Ssam 	hisctladdr.sin_port = port;
8326496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
8425904Skarels 		if (hp && hp->h_addr_list[1]) {
8525904Skarels 			int oerrno = errno;
8625904Skarels 
8725904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
8825904Skarels 				inet_ntoa(hisctladdr.sin_addr));
8925904Skarels 			errno = oerrno;
9026496Sminshall 			perror((char *) 0);
9125904Skarels 			hp->h_addr_list++;
9225904Skarels 			bcopy(hp->h_addr_list[0],
9326048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
9426496Sminshall 			fprintf(stdout, "Trying %s...\n",
9525904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9626813Skarels 			(void) close(s);
9726813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
9826813Skarels 			if (s < 0) {
9926813Skarels 				perror("ftp: socket");
10026813Skarels 				code = -1;
10126813Skarels 				return (0);
10226813Skarels 			}
10325904Skarels 			continue;
10425904Skarels 		}
10510296Ssam 		perror("ftp: connect");
10626048Sminshall 		code = -1;
10710296Ssam 		goto bad;
10810296Ssam 	}
10911627Ssam 	len = sizeof (myctladdr);
11011627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
11111627Ssam 		perror("ftp: getsockname");
11226048Sminshall 		code = -1;
11310296Ssam 		goto bad;
11410296Ssam 	}
11510296Ssam 	cin = fdopen(s, "r");
11610296Ssam 	cout = fdopen(s, "w");
11711219Ssam 	if (cin == NULL || cout == NULL) {
11810296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
11910296Ssam 		if (cin)
12026496Sminshall 			(void) fclose(cin);
12110296Ssam 		if (cout)
12226496Sminshall 			(void) fclose(cout);
12326048Sminshall 		code = -1;
12410296Ssam 		goto bad;
12510296Ssam 	}
12610296Ssam 	if (verbose)
12726067Sminshall 		printf("Connected to %s.\n", hostname);
12827687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
12926048Sminshall 		if (cin)
13026496Sminshall 			(void) fclose(cin);
13126048Sminshall 		if (cout)
13226496Sminshall 			(void) fclose(cout);
13326048Sminshall 		code = -1;
13426048Sminshall 		goto bad;
13526048Sminshall 	}
13627687Sminshall #ifdef SO_OOBINLINE
13727687Sminshall 	{
13827687Sminshall 	int on = 1;
13926048Sminshall 
14027687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
14127687Sminshall 		< 0 && debug) {
14227687Sminshall 			perror("ftp: setsockopt");
14327687Sminshall 		}
14427687Sminshall 	}
14527687Sminshall #endif SO_OOBINLINE
14626048Sminshall 
14725904Skarels 	return (hostname);
14810296Ssam bad:
14926496Sminshall 	(void) close(s);
15025904Skarels 	return ((char *)0);
15110296Ssam }
15210296Ssam 
15325904Skarels login(host)
15425904Skarels 	char *host;
15510296Ssam {
15626048Sminshall 	char tmp[80];
15726496Sminshall 	char *user, *pass, *acct, *getlogin(), *mygetpass();
15826048Sminshall 	int n, aflag = 0;
15910296Ssam 
16026048Sminshall 	user = pass = acct = 0;
16126048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16226048Sminshall 		disconnect();
16326048Sminshall 		code = -1;
16426048Sminshall 		return(0);
16526048Sminshall 	}
16626048Sminshall 	if (user == NULL) {
16726048Sminshall 		char *myname = getlogin();
16826048Sminshall 
16926048Sminshall 		if (myname == NULL) {
17026048Sminshall 			struct passwd *pp = getpwuid(getuid());
17126048Sminshall 
17226448Slepreau 			if (pp != NULL)
17326048Sminshall 				myname = pp->pw_name;
17426048Sminshall 		}
17526048Sminshall 		printf("Name (%s:%s): ", host, myname);
17626048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
17726048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
17826448Slepreau 		if (*tmp == '\0')
17926048Sminshall 			user = myname;
18026448Slepreau 		else
18126048Sminshall 			user = tmp;
18226048Sminshall 	}
18310296Ssam 	n = command("USER %s", user);
18426048Sminshall 	if (n == CONTINUE) {
18526448Slepreau 		if (pass == NULL)
18626496Sminshall 			pass = mygetpass("Password:");
18710296Ssam 		n = command("PASS %s", pass);
18826048Sminshall 	}
18910296Ssam 	if (n == CONTINUE) {
19026048Sminshall 		aflag++;
19126496Sminshall 		acct = mygetpass("Account:");
19210296Ssam 		n = command("ACCT %s", acct);
19310296Ssam 	}
19410296Ssam 	if (n != COMPLETE) {
19510296Ssam 		fprintf(stderr, "Login failed.\n");
19610296Ssam 		return (0);
19710296Ssam 	}
19826448Slepreau 	if (!aflag && acct != NULL)
19926048Sminshall 		(void) command("ACCT %s", acct);
20026448Slepreau 	if (proxy)
20126048Sminshall 		return(1);
20226048Sminshall 	for (n = 0; n < macnum; ++n) {
20326048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
20426496Sminshall 			(void) strcpy(line, "$init");
20526048Sminshall 			makeargv();
20626048Sminshall 			domacro(margc, margv);
20726048Sminshall 			break;
20826048Sminshall 		}
20926048Sminshall 	}
21010296Ssam 	return (1);
21110296Ssam }
21210296Ssam 
21326048Sminshall cmdabort()
21426048Sminshall {
21526048Sminshall 	extern jmp_buf ptabort;
21626048Sminshall 
21726048Sminshall 	printf("\n");
21826048Sminshall 	(void) fflush(stdout);
21926048Sminshall 	abrtflag++;
22026448Slepreau 	if (ptflag)
22126048Sminshall 		longjmp(ptabort,1);
22226048Sminshall }
22326048Sminshall 
22426496Sminshall /*VARARGS1*/
22510296Ssam command(fmt, args)
22610296Ssam 	char *fmt;
22710296Ssam {
22826048Sminshall 	int r, (*oldintr)(), cmdabort();
22910296Ssam 
23026048Sminshall 	abrtflag = 0;
23110296Ssam 	if (debug) {
23210296Ssam 		printf("---> ");
23310296Ssam 		_doprnt(fmt, &args, stdout);
23410296Ssam 		printf("\n");
23510296Ssam 		(void) fflush(stdout);
23610296Ssam 	}
23711219Ssam 	if (cout == NULL) {
23811219Ssam 		perror ("No control connection for command");
23926048Sminshall 		code = -1;
24011219Ssam 		return (0);
24111219Ssam 	}
24226048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24310296Ssam 	_doprnt(fmt, &args, cout);
24410296Ssam 	fprintf(cout, "\r\n");
24510296Ssam 	(void) fflush(cout);
24626048Sminshall 	cpend = 1;
24726048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
24826448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
24926048Sminshall 		(*oldintr)();
25026048Sminshall 	(void) signal(SIGINT, oldintr);
25126048Sminshall 	return(r);
25210296Ssam }
25310296Ssam 
25410296Ssam #include <ctype.h>
25510296Ssam 
25610296Ssam getreply(expecteof)
25710296Ssam 	int expecteof;
25810296Ssam {
25911219Ssam 	register int c, n;
26026048Sminshall 	register int dig;
26126048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
26226048Sminshall 	int pflag = 0;
26326048Sminshall 	char *pt = pasv;
26410296Ssam 
26526048Sminshall 	oldintr = signal(SIGINT,cmdabort);
26610296Ssam 	for (;;) {
26710296Ssam 		dig = n = code = 0;
26810296Ssam 		while ((c = getc(cin)) != '\n') {
26927687Sminshall 			if (c == IAC) {     /* handle telnet commands */
27027687Sminshall 				switch (c = getc(cin)) {
27127687Sminshall 				case WILL:
27227687Sminshall 				case WONT:
27327687Sminshall 					c = getc(cin);
27427687Sminshall 					fprintf(cout, "%c%c%c",IAC,WONT,c);
27527687Sminshall 					(void) fflush(cout);
27627687Sminshall 					break;
27727687Sminshall 				case DO:
27827687Sminshall 				case DONT:
27927687Sminshall 					c = getc(cin);
28027687Sminshall 					fprintf(cout, "%c%c%c",IAC,DONT,c);
28127687Sminshall 					(void) fflush(cout);
28227687Sminshall 					break;
28327687Sminshall 				default:
28427687Sminshall 					break;
28527687Sminshall 				}
28627687Sminshall 				continue;
28727687Sminshall 			}
28810296Ssam 			dig++;
28910296Ssam 			if (c == EOF) {
29026048Sminshall 				if (expecteof) {
29126048Sminshall 					(void) signal(SIGINT,oldintr);
29226048Sminshall 					code = 221;
29310296Ssam 					return (0);
29426048Sminshall 				}
29510296Ssam 				lostpeer();
29626048Sminshall 				if (verbose) {
29726048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
29826048Sminshall 					(void) fflush(stdout);
29926048Sminshall 					code = 421;
30026048Sminshall 					return(4);
30126048Sminshall 				}
30210296Ssam 			}
30326048Sminshall 			if (c != '\r' && (verbose > 0 ||
30426048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
30526448Slepreau 				if (proxflag &&
30626448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
30726048Sminshall 					printf("%s:",hostname);
30826496Sminshall 				(void) putchar(c);
30926048Sminshall 			}
31010296Ssam 			if (dig < 4 && isdigit(c))
31110296Ssam 				code = code * 10 + (c - '0');
31226448Slepreau 			if (!pflag && code == 227)
31326048Sminshall 				pflag = 1;
31426448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
31526048Sminshall 				pflag = 2;
31626048Sminshall 			if (pflag == 2) {
31726448Slepreau 				if (c != '\r' && c != ')')
31826048Sminshall 					*pt++ = c;
31926048Sminshall 				else {
32026048Sminshall 					*pt = '\0';
32126048Sminshall 					pflag = 3;
32226048Sminshall 				}
32326048Sminshall 			}
32426048Sminshall 			if (dig == 4 && c == '-') {
32526448Slepreau 				if (continuation)
32626048Sminshall 					code = 0;
32710296Ssam 				continuation++;
32826048Sminshall 			}
32910296Ssam 			if (n == 0)
33010296Ssam 				n = c;
33110296Ssam 		}
33226048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
33326496Sminshall 			(void) putchar(c);
33411346Ssam 			(void) fflush (stdout);
33511346Ssam 		}
33610296Ssam 		if (continuation && code != originalcode) {
33710296Ssam 			if (originalcode == 0)
33810296Ssam 				originalcode = code;
33910296Ssam 			continue;
34010296Ssam 		}
34126448Slepreau 		if (n != '1')
34226048Sminshall 			cpend = 0;
34326048Sminshall 		(void) signal(SIGINT,oldintr);
34426448Slepreau 		if (code == 421 || originalcode == 421)
34526048Sminshall 			lostpeer();
34626448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
34726048Sminshall 			(*oldintr)();
34825907Smckusick 		return (n - '0');
34910296Ssam 	}
35010296Ssam }
35110296Ssam 
35226048Sminshall empty(mask, sec)
35327687Sminshall 	struct fd_set *mask;
35426048Sminshall 	int sec;
35526048Sminshall {
35626048Sminshall 	struct timeval t;
35726048Sminshall 
35826048Sminshall 	t.tv_sec = (long) sec;
35926048Sminshall 	t.tv_usec = 0;
36027687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
36126048Sminshall }
36226048Sminshall 
36310296Ssam jmp_buf	sendabort;
36410296Ssam 
36510296Ssam abortsend()
36610296Ssam {
36710296Ssam 
36826048Sminshall 	mflag = 0;
36926048Sminshall 	abrtflag = 0;
37026048Sminshall 	printf("\nsend aborted\n");
37126048Sminshall 	(void) fflush(stdout);
37210296Ssam 	longjmp(sendabort, 1);
37310296Ssam }
37410296Ssam 
37510296Ssam sendrequest(cmd, local, remote)
37610296Ssam 	char *cmd, *local, *remote;
37710296Ssam {
37826496Sminshall 	FILE *fin, *dout = 0, *mypopen();
37926496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
38026048Sminshall 	int abortsend();
38111219Ssam 	char buf[BUFSIZ];
38211651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
38311346Ssam 	register int c, d;
38410296Ssam 	struct stat st;
38510296Ssam 	struct timeval start, stop;
38610296Ssam 
38726048Sminshall 	if (proxy) {
38826048Sminshall 		proxtrans(cmd, local, remote);
38926048Sminshall 		return;
39026048Sminshall 	}
39110296Ssam 	closefunc = NULL;
39226048Sminshall 	oldintr = NULL;
39326048Sminshall 	oldintp = NULL;
39426048Sminshall 	if (setjmp(sendabort)) {
39526048Sminshall 		while (cpend) {
39626048Sminshall 			(void) getreply(0);
39726048Sminshall 		}
39826048Sminshall 		if (data >= 0) {
39926048Sminshall 			(void) close(data);
40026048Sminshall 			data = -1;
40126048Sminshall 		}
40226448Slepreau 		if (oldintr)
40326048Sminshall 			(void) signal(SIGINT,oldintr);
40426448Slepreau 		if (oldintp)
40526048Sminshall 			(void) signal(SIGPIPE,oldintp);
40626048Sminshall 		code = -1;
40726048Sminshall 		return;
40826048Sminshall 	}
40910296Ssam 	oldintr = signal(SIGINT, abortsend);
41010296Ssam 	if (strcmp(local, "-") == 0)
41110296Ssam 		fin = stdin;
41210296Ssam 	else if (*local == '|') {
41326048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
41426496Sminshall 		fin = mypopen(local + 1, "r");
41510296Ssam 		if (fin == NULL) {
41626048Sminshall 			perror(local + 1);
41726048Sminshall 			(void) signal(SIGINT, oldintr);
41826048Sminshall 			(void) signal(SIGPIPE, oldintp);
41926048Sminshall 			code = -1;
42026048Sminshall 			return;
42110296Ssam 		}
42226496Sminshall 		closefunc = mypclose;
42310296Ssam 	} else {
42410296Ssam 		fin = fopen(local, "r");
42510296Ssam 		if (fin == NULL) {
42610296Ssam 			perror(local);
42726048Sminshall 			(void) signal(SIGINT, oldintr);
42826048Sminshall 			code = -1;
42926048Sminshall 			return;
43010296Ssam 		}
43110296Ssam 		closefunc = fclose;
43210296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
43310296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
43426496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
43526048Sminshall 			(void) signal(SIGINT, oldintr);
43626048Sminshall 			code = -1;
43726048Sminshall 			return;
43810296Ssam 		}
43910296Ssam 	}
44026048Sminshall 	if (initconn()) {
44126048Sminshall 		(void) signal(SIGINT, oldintr);
44226448Slepreau 		if (oldintp)
44326048Sminshall 			(void) signal(SIGPIPE, oldintp);
44426048Sminshall 		code = -1;
44526048Sminshall 		return;
44626048Sminshall 	}
44726448Slepreau 	if (setjmp(sendabort))
44826048Sminshall 		goto abort;
44910296Ssam 	if (remote) {
45026048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
45126048Sminshall 			(void) signal(SIGINT, oldintr);
45226448Slepreau 			if (oldintp)
45326048Sminshall 				(void) signal(SIGPIPE, oldintp);
45426048Sminshall 			return;
45526048Sminshall 		}
45610296Ssam 	} else
45726048Sminshall 		if (command("%s", cmd) != PRELIM) {
45826048Sminshall 			(void) signal(SIGINT, oldintr);
45926448Slepreau 			if (oldintp)
46026048Sminshall 				(void) signal(SIGPIPE, oldintp);
46126048Sminshall 			return;
46226048Sminshall 		}
46310296Ssam 	dout = dataconn("w");
46426448Slepreau 	if (dout == NULL)
46526048Sminshall 		goto abort;
46626496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
46711219Ssam 	switch (type) {
46811219Ssam 
46911219Ssam 	case TYPE_I:
47011219Ssam 	case TYPE_L:
47111346Ssam 		errno = d = 0;
47211219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
47311346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
47411219Ssam 				break;
47511219Ssam 			bytes += c;
47611651Ssam 			if (hash) {
47726496Sminshall 				(void) putchar('#');
47826496Sminshall 				(void) fflush(stdout);
47911651Ssam 			}
48011219Ssam 		}
48113213Ssam 		if (hash && bytes > 0) {
48226496Sminshall 			(void) putchar('\n');
48326496Sminshall 			(void) fflush(stdout);
48411651Ssam 		}
48511219Ssam 		if (c < 0)
48611219Ssam 			perror(local);
48711346Ssam 		if (d < 0)
48811219Ssam 			perror("netout");
48911219Ssam 		break;
49011219Ssam 
49111219Ssam 	case TYPE_A:
49211219Ssam 		while ((c = getc(fin)) != EOF) {
49311219Ssam 			if (c == '\n') {
49411651Ssam 				while (hash && (bytes >= hashbytes)) {
49526496Sminshall 					(void) putchar('#');
49626496Sminshall 					(void) fflush(stdout);
49711651Ssam 					hashbytes += sizeof (buf);
49811651Ssam 				}
49911219Ssam 				if (ferror(dout))
50011219Ssam 					break;
50126496Sminshall 				(void) putc('\r', dout);
50211219Ssam 				bytes++;
50311219Ssam 			}
50426496Sminshall 			(void) putc(c, dout);
50511219Ssam 			bytes++;
50626048Sminshall 	/*		if (c == '\r') {			  	*/
50726496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
50826048Sminshall 	/*			bytes++;				*/
50926048Sminshall 	/*		}                          			*/
51011219Ssam 		}
51111651Ssam 		if (hash) {
51213213Ssam 			if (bytes < hashbytes)
51326496Sminshall 				(void) putchar('#');
51426496Sminshall 			(void) putchar('\n');
51526496Sminshall 			(void) fflush(stdout);
51611651Ssam 		}
51711219Ssam 		if (ferror(fin))
51811219Ssam 			perror(local);
51911346Ssam 		if (ferror(dout))
52011219Ssam 			perror("netout");
52111219Ssam 		break;
52210296Ssam 	}
52326496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
52410296Ssam 	if (closefunc != NULL)
52526048Sminshall 		(*closefunc)(fin);
52610296Ssam 	(void) fclose(dout);
52726048Sminshall 	(void) getreply(0);
52826048Sminshall 	(void) signal(SIGINT, oldintr);
52910296Ssam 	if (bytes > 0 && verbose)
53026048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53110296Ssam 	return;
53226048Sminshall abort:
53326496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
53426048Sminshall 	(void) signal(SIGINT, oldintr);
53526448Slepreau 	if (oldintp)
53626048Sminshall 		(void) signal(SIGPIPE, oldintp);
53726048Sminshall 	if (!cpend) {
53826048Sminshall 		code = -1;
53926048Sminshall 		return;
54026048Sminshall 	}
54126048Sminshall 	if (data >= 0) {
54226048Sminshall 		(void) close(data);
54326048Sminshall 		data = -1;
54426048Sminshall 	}
54526448Slepreau 	if (dout)
54626048Sminshall 		(void) fclose(dout);
54726048Sminshall 	(void) getreply(0);
54826048Sminshall 	code = -1;
54910296Ssam 	if (closefunc != NULL && fin != NULL)
55026048Sminshall 		(*closefunc)(fin);
55126048Sminshall 	if (bytes > 0 && verbose)
55226048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
55310296Ssam }
55410296Ssam 
55510296Ssam jmp_buf	recvabort;
55610296Ssam 
55710296Ssam abortrecv()
55810296Ssam {
55910296Ssam 
56026048Sminshall 	mflag = 0;
56126048Sminshall 	abrtflag = 0;
56226048Sminshall 	printf("\n");
56326048Sminshall 	(void) fflush(stdout);
56410296Ssam 	longjmp(recvabort, 1);
56510296Ssam }
56610296Ssam 
56711651Ssam recvrequest(cmd, local, remote, mode)
56811651Ssam 	char *cmd, *local, *remote, *mode;
56910296Ssam {
57026496Sminshall 	FILE *fout, *din = 0, *mypopen();
57126496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
57227687Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag, nfnd;
57327687Sminshall 	char buf[BUFSIZ], *gunique(), msg;
57426496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
57526496Sminshall 	struct fd_set mask;
57611346Ssam 	register int c, d;
57710296Ssam 	struct timeval start, stop;
57810296Ssam 
57926048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
58026048Sminshall 		proxtrans(cmd, local, remote);
58126048Sminshall 		return;
58226048Sminshall 	}
58310296Ssam 	closefunc = NULL;
58426048Sminshall 	oldintr = NULL;
58526048Sminshall 	oldintp = NULL;
58626048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
58726048Sminshall 	if (setjmp(recvabort)) {
58826048Sminshall 		while (cpend) {
58926048Sminshall 			(void) getreply(0);
59026048Sminshall 		}
59126048Sminshall 		if (data >= 0) {
59226048Sminshall 			(void) close(data);
59326048Sminshall 			data = -1;
59426048Sminshall 		}
59526448Slepreau 		if (oldintr)
59626048Sminshall 			(void) signal(SIGINT, oldintr);
59726048Sminshall 		code = -1;
59826048Sminshall 		return;
59926048Sminshall 	}
60010296Ssam 	oldintr = signal(SIGINT, abortrecv);
60126048Sminshall 	if (strcmp(local, "-") && *local != '|') {
60210296Ssam 		if (access(local, 2) < 0) {
60326048Sminshall 			char *dir = rindex(local, '/');
60410296Ssam 
60526048Sminshall 			if (errno != ENOENT && errno != EACCES) {
60610296Ssam 				perror(local);
60726048Sminshall 				(void) signal(SIGINT, oldintr);
60826048Sminshall 				code = -1;
60926048Sminshall 				return;
61010296Ssam 			}
61126048Sminshall 			if (dir != NULL)
61226048Sminshall 				*dir = 0;
61326048Sminshall 			d = access(dir ? local : ".", 2);
61426048Sminshall 			if (dir != NULL)
61526048Sminshall 				*dir = '/';
61626048Sminshall 			if (d < 0) {
61726048Sminshall 				perror(local);
61826048Sminshall 				(void) signal(SIGINT, oldintr);
61926048Sminshall 				code = -1;
62026048Sminshall 				return;
62126048Sminshall 			}
62226048Sminshall 			if (!runique && errno == EACCES &&
62326048Sminshall 			    chmod(local,0600) < 0) {
62426048Sminshall 				perror(local);
62526048Sminshall 				(void) signal(SIGINT, oldintr);
62626048Sminshall 				code = -1;
62726048Sminshall 				return;
62826048Sminshall 			}
62926048Sminshall 			if (runique && errno == EACCES &&
63026048Sminshall 			   (local = gunique(local)) == NULL) {
63126048Sminshall 				(void) signal(SIGINT, oldintr);
63226048Sminshall 				code = -1;
63326048Sminshall 				return;
63426048Sminshall 			}
63510296Ssam 		}
63626048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
63726048Sminshall 			(void) signal(SIGINT, oldintr);
63826048Sminshall 			code = -1;
63926048Sminshall 			return;
64026048Sminshall 		}
64126048Sminshall 	}
64226048Sminshall 	if (initconn()) {
64326048Sminshall 		(void) signal(SIGINT, oldintr);
64426048Sminshall 		code = -1;
64526048Sminshall 		return;
64626048Sminshall 	}
64726448Slepreau 	if (setjmp(recvabort))
64826048Sminshall 		goto abort;
64926048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
65026048Sminshall 		oldtype = type;
65126048Sminshall 		oldverbose = verbose;
65226448Slepreau 		if (!debug)
65326048Sminshall 			verbose = 0;
65426048Sminshall 		setascii();
65526048Sminshall 		verbose = oldverbose;
65626048Sminshall 	}
65710296Ssam 	if (remote) {
65826048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
65926048Sminshall 			(void) signal(SIGINT, oldintr);
66026048Sminshall 			if (oldtype) {
66126448Slepreau 				if (!debug)
66226048Sminshall 					verbose = 0;
66326048Sminshall 				switch (oldtype) {
66426048Sminshall 					case TYPE_I:
66526048Sminshall 						setbinary();
66626048Sminshall 						break;
66726048Sminshall 					case TYPE_E:
66826048Sminshall 						setebcdic();
66926048Sminshall 						break;
67026048Sminshall 					case TYPE_L:
67126048Sminshall 						settenex();
67226048Sminshall 						break;
67326048Sminshall 				}
67426048Sminshall 				verbose = oldverbose;
67526048Sminshall 			}
67626048Sminshall 			return;
67726048Sminshall 		}
67826048Sminshall 	} else {
67926048Sminshall 		if (command("%s", cmd) != PRELIM) {
68026048Sminshall 			(void) signal(SIGINT, oldintr);
68126048Sminshall 			if (oldtype) {
68226448Slepreau 				if (!debug)
68326048Sminshall 					verbose = 0;
68426048Sminshall 				switch (oldtype) {
68526048Sminshall 					case TYPE_I:
68626048Sminshall 						setbinary();
68726048Sminshall 						break;
68826048Sminshall 					case TYPE_E:
68926048Sminshall 						setebcdic();
69026048Sminshall 						break;
69126048Sminshall 					case TYPE_L:
69226048Sminshall 						settenex();
69326048Sminshall 						break;
69426048Sminshall 				}
69526048Sminshall 				verbose = oldverbose;
69626048Sminshall 			}
69726048Sminshall 			return;
69826048Sminshall 		}
69926048Sminshall 	}
70026048Sminshall 	din = dataconn("r");
70126048Sminshall 	if (din == NULL)
70226048Sminshall 		goto abort;
70326448Slepreau 	if (strcmp(local, "-") == 0)
70410296Ssam 		fout = stdout;
70510296Ssam 	else if (*local == '|') {
70626048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
70726496Sminshall 		fout = mypopen(local + 1, "w");
70826048Sminshall 		if (fout == NULL) {
70926048Sminshall 			perror(local+1);
71026048Sminshall 			goto abort;
71126048Sminshall 		}
71226496Sminshall 		closefunc = mypclose;
71326048Sminshall 	}
71426048Sminshall 	else {
71511651Ssam 		fout = fopen(local, mode);
71626048Sminshall 		if (fout == NULL) {
71726048Sminshall 			perror(local);
71826048Sminshall 			goto abort;
71926048Sminshall 		}
72010296Ssam 		closefunc = fclose;
72110296Ssam 	}
72226496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
72311219Ssam 	switch (type) {
72411219Ssam 
72511219Ssam 	case TYPE_I:
72611219Ssam 	case TYPE_L:
72711346Ssam 		errno = d = 0;
72811219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
72911346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
73011219Ssam 				break;
73111219Ssam 			bytes += c;
73211651Ssam 			if (hash) {
73326496Sminshall 				(void) putchar('#');
73426496Sminshall 				(void) fflush(stdout);
73511651Ssam 			}
73611219Ssam 		}
73713213Ssam 		if (hash && bytes > 0) {
73826496Sminshall 			(void) putchar('\n');
73926496Sminshall 			(void) fflush(stdout);
74011651Ssam 		}
74111219Ssam 		if (c < 0)
74211219Ssam 			perror("netin");
74311346Ssam 		if (d < 0)
74410296Ssam 			perror(local);
74511219Ssam 		break;
74611219Ssam 
74711219Ssam 	case TYPE_A:
74811219Ssam 		while ((c = getc(din)) != EOF) {
74927749Sminshall 			while (c == '\r') {
75011651Ssam 				while (hash && (bytes >= hashbytes)) {
75126496Sminshall 					(void) putchar('#');
75226496Sminshall 					(void) fflush(stdout);
75311651Ssam 					hashbytes += sizeof (buf);
75411651Ssam 				}
75510296Ssam 				bytes++;
75626048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
75711219Ssam 					if (ferror (fout))
75811219Ssam 						break;
75926496Sminshall 					(void) putc ('\r', fout);
76011219Ssam 				}
76126048Sminshall 				/*if (c == '\0') {
76211219Ssam 					bytes++;
76311219Ssam 					continue;
76426048Sminshall 				}*/
76511219Ssam 			}
76626496Sminshall 			(void) putc (c, fout);
76711219Ssam 			bytes++;
76810296Ssam 		}
76911651Ssam 		if (hash) {
77013213Ssam 			if (bytes < hashbytes)
77126496Sminshall 				(void) putchar('#');
77226496Sminshall 			(void) putchar('\n');
77326496Sminshall 			(void) fflush(stdout);
77411651Ssam 		}
77511219Ssam 		if (ferror (din))
77611219Ssam 			perror ("netin");
77711219Ssam 		if (ferror (fout))
77811219Ssam 			perror (local);
77911219Ssam 		break;
78010296Ssam 	}
78126448Slepreau 	if (closefunc != NULL)
78226048Sminshall 		(*closefunc)(fout);
78326496Sminshall 	(void) signal(SIGINT, oldintr);
78426448Slepreau 	if (oldintp)
78526048Sminshall 		(void) signal(SIGPIPE, oldintp);
78626496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
78710296Ssam 	(void) fclose(din);
78826048Sminshall 	(void) getreply(0);
78926048Sminshall 	if (bytes > 0 && verbose)
79026048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
79126048Sminshall 	if (oldtype) {
79226448Slepreau 		if (!debug)
79326048Sminshall 			verbose = 0;
79426048Sminshall 		switch (oldtype) {
79526048Sminshall 			case TYPE_I:
79626048Sminshall 				setbinary();
79726048Sminshall 				break;
79826048Sminshall 			case TYPE_E:
79926048Sminshall 				setebcdic();
80026048Sminshall 				break;
80126048Sminshall 			case TYPE_L:
80226048Sminshall 				settenex();
80326048Sminshall 				break;
80426048Sminshall 		}
80526048Sminshall 		verbose = oldverbose;
80626048Sminshall 	}
80726048Sminshall 	return;
80826048Sminshall abort:
80926048Sminshall 
81027687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
81126048Sminshall 
81226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
81326448Slepreau 	if (oldintp)
81426048Sminshall 		(void) signal(SIGPIPE, oldintr);
81526048Sminshall 	(void) signal(SIGINT,SIG_IGN);
81626048Sminshall 	if (oldtype) {
81726448Slepreau 		if (!debug)
81826048Sminshall 			verbose = 0;
81926048Sminshall 		switch (oldtype) {
82026048Sminshall 			case TYPE_I:
82126048Sminshall 				setbinary();
82226048Sminshall 				break;
82326048Sminshall 			case TYPE_E:
82426048Sminshall 				setebcdic();
82526048Sminshall 				break;
82626048Sminshall 			case TYPE_L:
82726048Sminshall 				settenex();
82826048Sminshall 				break;
82926048Sminshall 		}
83026048Sminshall 		verbose = oldverbose;
83126048Sminshall 	}
83226048Sminshall 	if (!cpend) {
83326048Sminshall 		code = -1;
83426048Sminshall 		(void) signal(SIGINT,oldintr);
83526048Sminshall 		return;
83626048Sminshall 	}
83726048Sminshall 
83827687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
83927687Sminshall 	(void) fflush(cout);
84027687Sminshall 	msg = IAC;
84127687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
84227687Sminshall /* after urgent byte rather than before as now is protocol            */
84327687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
84427687Sminshall 		perror("abort");
84526048Sminshall 	}
84627687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
84726048Sminshall 	(void) fflush(cout);
84827687Sminshall 	FD_ZERO(&mask);
84926496Sminshall 	FD_SET(fileno(cin), &mask);
85026496Sminshall 	if (din) {
85126496Sminshall 		FD_SET(fileno(din), &mask);
85226496Sminshall 	}
85327687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
85427687Sminshall 		if (nfnd < 0) {
85527687Sminshall 			perror("abort");
85627687Sminshall 		}
85726048Sminshall 		code = -1;
85826048Sminshall 		lostpeer();
85926048Sminshall 	}
86026496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
86126448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
86226448Slepreau 			;
86326496Sminshall 	}
86427687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
86526048Sminshall 		if (data >= 0) {
86626496Sminshall 			(void) close(data);
86726048Sminshall 			data = -1;
86826048Sminshall 		}
86925907Smckusick 		(void) getreply(0);
87025907Smckusick 	}
87126048Sminshall 	(void) getreply(0);
87226048Sminshall 	code = -1;
87326048Sminshall 	if (data >= 0) {
87426048Sminshall 		(void) close(data);
87526048Sminshall 		data = -1;
87626048Sminshall 	}
87726448Slepreau 	if (closefunc != NULL && fout != NULL)
87826048Sminshall 		(*closefunc)(fout);
87926448Slepreau 	if (din)
88026048Sminshall 		(void) fclose(din);
88110296Ssam 	if (bytes > 0 && verbose)
88226048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
88326048Sminshall 	(void) signal(SIGINT,oldintr);
88410296Ssam }
88510296Ssam 
88610296Ssam /*
88710296Ssam  * Need to start a listen on the data channel
88810296Ssam  * before we send the command, otherwise the
88910296Ssam  * server's connect may fail.
89010296Ssam  */
89133224Sbostic int sendport = -1;
89211651Ssam 
89310296Ssam initconn()
89410296Ssam {
89510296Ssam 	register char *p, *a;
89626048Sminshall 	int result, len, tmpno = 0;
89726993Skarels 	int on = 1;
89810296Ssam 
89911651Ssam noport:
90010296Ssam 	data_addr = myctladdr;
90111651Ssam 	if (sendport)
90211651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
90311651Ssam 	if (data != -1)
90411651Ssam 		(void) close (data);
90518287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
90610296Ssam 	if (data < 0) {
90710296Ssam 		perror("ftp: socket");
90826448Slepreau 		if (tmpno)
90926048Sminshall 			sendport = 1;
91010296Ssam 		return (1);
91110296Ssam 	}
91212397Ssam 	if (!sendport)
91327687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
91433224Sbostic 			perror("ftp: setsockopt (reuse address)");
91512397Ssam 			goto bad;
91612397Ssam 		}
91726496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
91810296Ssam 		perror("ftp: bind");
91910296Ssam 		goto bad;
92010296Ssam 	}
92110296Ssam 	if (options & SO_DEBUG &&
92227687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
92310296Ssam 		perror("ftp: setsockopt (ignored)");
92411627Ssam 	len = sizeof (data_addr);
92511627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
92611627Ssam 		perror("ftp: getsockname");
92710296Ssam 		goto bad;
92810296Ssam 	}
92926448Slepreau 	if (listen(data, 1) < 0)
93010296Ssam 		perror("ftp: listen");
93111651Ssam 	if (sendport) {
93211651Ssam 		a = (char *)&data_addr.sin_addr;
93311651Ssam 		p = (char *)&data_addr.sin_port;
93410296Ssam #define	UC(b)	(((int)b)&0xff)
93511651Ssam 		result =
93611651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
93711651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
93811651Ssam 		      UC(p[0]), UC(p[1]));
93911651Ssam 		if (result == ERROR && sendport == -1) {
94011651Ssam 			sendport = 0;
94126048Sminshall 			tmpno = 1;
94211651Ssam 			goto noport;
94311651Ssam 		}
94411651Ssam 		return (result != COMPLETE);
94511651Ssam 	}
94626448Slepreau 	if (tmpno)
94726048Sminshall 		sendport = 1;
94811651Ssam 	return (0);
94910296Ssam bad:
95010296Ssam 	(void) close(data), data = -1;
95126448Slepreau 	if (tmpno)
95226048Sminshall 		sendport = 1;
95310296Ssam 	return (1);
95410296Ssam }
95510296Ssam 
95610296Ssam FILE *
95710296Ssam dataconn(mode)
95810296Ssam 	char *mode;
95910296Ssam {
96010296Ssam 	struct sockaddr_in from;
96110296Ssam 	int s, fromlen = sizeof (from);
96210296Ssam 
96326496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
96410296Ssam 	if (s < 0) {
96510296Ssam 		perror("ftp: accept");
96610296Ssam 		(void) close(data), data = -1;
96710296Ssam 		return (NULL);
96810296Ssam 	}
96910296Ssam 	(void) close(data);
97010296Ssam 	data = s;
97110296Ssam 	return (fdopen(data, mode));
97210296Ssam }
97310296Ssam 
97426048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
97526048Sminshall 	char *direction, *local, *remote;
97611651Ssam 	long bytes;
97710296Ssam 	struct timeval *t0, *t1;
97810296Ssam {
97910296Ssam 	struct timeval td;
98016437Sleres 	float s, bs;
98110296Ssam 
98210296Ssam 	tvsub(&td, t1, t0);
98316437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
98410296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
98516437Sleres 	bs = bytes / nz(s);
98626448Slepreau 	if (local && *local != '-')
98726048Sminshall 		printf("local: %s ", local);
98826448Slepreau 	if (remote)
98926048Sminshall 		printf("remote: %s\n", remote);
99016437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
99116437Sleres 		bytes, direction, s, bs / 1024.);
99210296Ssam }
99310296Ssam 
99426496Sminshall /*tvadd(tsum, t0)
99510296Ssam 	struct timeval *tsum, *t0;
99610296Ssam {
99710296Ssam 
99810296Ssam 	tsum->tv_sec += t0->tv_sec;
99910296Ssam 	tsum->tv_usec += t0->tv_usec;
100010296Ssam 	if (tsum->tv_usec > 1000000)
100110296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
100226496Sminshall } */
100310296Ssam 
100410296Ssam tvsub(tdiff, t1, t0)
100510296Ssam 	struct timeval *tdiff, *t1, *t0;
100610296Ssam {
100710296Ssam 
100810296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
100910296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
101010296Ssam 	if (tdiff->tv_usec < 0)
101110296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
101210296Ssam }
101326048Sminshall 
101426048Sminshall psabort()
101526048Sminshall {
101626048Sminshall 	extern int abrtflag;
101726048Sminshall 
101826048Sminshall 	abrtflag++;
101926048Sminshall }
102026048Sminshall 
102126048Sminshall pswitch(flag)
102226048Sminshall 	int flag;
102326048Sminshall {
102426048Sminshall 	extern int proxy, abrtflag;
102526048Sminshall 	int (*oldintr)();
102626048Sminshall 	static struct comvars {
102726048Sminshall 		int connect;
102828469Skarels 		char name[MAXHOSTNAMELEN];
102926048Sminshall 		struct sockaddr_in mctl;
103026048Sminshall 		struct sockaddr_in hctl;
103126048Sminshall 		FILE *in;
103226048Sminshall 		FILE *out;
103326048Sminshall 		int tpe;
103426048Sminshall 		int cpnd;
103526048Sminshall 		int sunqe;
103626048Sminshall 		int runqe;
103726048Sminshall 		int mcse;
103826048Sminshall 		int ntflg;
103926048Sminshall 		char nti[17];
104026048Sminshall 		char nto[17];
104126048Sminshall 		int mapflg;
104226048Sminshall 		char mi[MAXPATHLEN];
104326048Sminshall 		char mo[MAXPATHLEN];
104426048Sminshall 		} proxstruct, tmpstruct;
104526048Sminshall 	struct comvars *ip, *op;
104626048Sminshall 
104726048Sminshall 	abrtflag = 0;
104826048Sminshall 	oldintr = signal(SIGINT, psabort);
104926048Sminshall 	if (flag) {
105026448Slepreau 		if (proxy)
105126048Sminshall 			return;
105226048Sminshall 		ip = &tmpstruct;
105326048Sminshall 		op = &proxstruct;
105426048Sminshall 		proxy++;
105526048Sminshall 	}
105626048Sminshall 	else {
105726448Slepreau 		if (!proxy)
105826048Sminshall 			return;
105926048Sminshall 		ip = &proxstruct;
106026048Sminshall 		op = &tmpstruct;
106126048Sminshall 		proxy = 0;
106226048Sminshall 	}
106326048Sminshall 	ip->connect = connected;
106426048Sminshall 	connected = op->connect;
106528469Skarels 	if (hostname) {
106628469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
106728469Skarels 		ip->name[strlen(ip->name)] = '\0';
106828469Skarels 	} else
106928469Skarels 		ip->name[0] = 0;
107026048Sminshall 	hostname = op->name;
107126048Sminshall 	ip->hctl = hisctladdr;
107226048Sminshall 	hisctladdr = op->hctl;
107326048Sminshall 	ip->mctl = myctladdr;
107426048Sminshall 	myctladdr = op->mctl;
107526048Sminshall 	ip->in = cin;
107626048Sminshall 	cin = op->in;
107726048Sminshall 	ip->out = cout;
107826048Sminshall 	cout = op->out;
107926048Sminshall 	ip->tpe = type;
108026048Sminshall 	type = op->tpe;
108126448Slepreau 	if (!type)
108226048Sminshall 		type = 1;
108326048Sminshall 	ip->cpnd = cpend;
108426048Sminshall 	cpend = op->cpnd;
108526048Sminshall 	ip->sunqe = sunique;
108626048Sminshall 	sunique = op->sunqe;
108726048Sminshall 	ip->runqe = runique;
108826048Sminshall 	runique = op->runqe;
108926048Sminshall 	ip->mcse = mcase;
109026048Sminshall 	mcase = op->mcse;
109126048Sminshall 	ip->ntflg = ntflag;
109226048Sminshall 	ntflag = op->ntflg;
109326496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
109426048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
109526496Sminshall 	(void) strcpy(ntin, op->nti);
109626496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
109726048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
109826496Sminshall 	(void) strcpy(ntout, op->nto);
109926048Sminshall 	ip->mapflg = mapflag;
110026048Sminshall 	mapflag = op->mapflg;
110126496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
110226048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
110326496Sminshall 	(void) strcpy(mapin, op->mi);
110426496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
110526048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
110626496Sminshall 	(void) strcpy(mapout, op->mo);
110726048Sminshall 	(void) signal(SIGINT, oldintr);
110826048Sminshall 	if (abrtflag) {
110926048Sminshall 		abrtflag = 0;
111026048Sminshall 		(*oldintr)();
111126448Slepreau 	}
111226048Sminshall }
111326048Sminshall 
111426048Sminshall jmp_buf ptabort;
111526048Sminshall int ptabflg;
111626048Sminshall 
111726048Sminshall abortpt()
111826048Sminshall {
111926048Sminshall 	printf("\n");
112026496Sminshall 	(void) fflush(stdout);
112126048Sminshall 	ptabflg++;
112226048Sminshall 	mflag = 0;
112326048Sminshall 	abrtflag = 0;
112426048Sminshall 	longjmp(ptabort, 1);
112526048Sminshall }
112626048Sminshall 
112726048Sminshall proxtrans(cmd, local, remote)
112826048Sminshall 	char *cmd, *local, *remote;
112926048Sminshall {
113027687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
113126048Sminshall 	extern jmp_buf ptabort;
113226048Sminshall 	char *cmd2;
113326496Sminshall 	struct fd_set mask;
113426048Sminshall 
113526448Slepreau 	if (strcmp(cmd, "RETR"))
113626048Sminshall 		cmd2 = "RETR";
113726448Slepreau 	else
113826048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
113926048Sminshall 	if (command("PASV") != COMPLETE) {
114026048Sminshall 		printf("proxy server does not support third part transfers.\n");
114126048Sminshall 		return;
114226048Sminshall 	}
114326048Sminshall 	tmptype = type;
114426048Sminshall 	pswitch(0);
114526048Sminshall 	if (!connected) {
114626048Sminshall 		printf("No primary connection\n");
114726048Sminshall 		pswitch(1);
114826048Sminshall 		code = -1;
114926048Sminshall 		return;
115026048Sminshall 	}
115126048Sminshall 	if (type != tmptype) {
115226048Sminshall 		oldtype = type;
115326048Sminshall 		switch (tmptype) {
115426048Sminshall 			case TYPE_A:
115526048Sminshall 				setascii();
115626048Sminshall 				break;
115726048Sminshall 			case TYPE_I:
115826048Sminshall 				setbinary();
115926048Sminshall 				break;
116026048Sminshall 			case TYPE_E:
116126048Sminshall 				setebcdic();
116226048Sminshall 				break;
116326048Sminshall 			case TYPE_L:
116426048Sminshall 				settenex();
116526048Sminshall 				break;
116626048Sminshall 		}
116726048Sminshall 	}
116826048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
116926048Sminshall 		switch (oldtype) {
117026048Sminshall 			case 0:
117126048Sminshall 				break;
117226048Sminshall 			case TYPE_A:
117326048Sminshall 				setascii();
117426048Sminshall 				break;
117526048Sminshall 			case TYPE_I:
117626048Sminshall 				setbinary();
117726048Sminshall 				break;
117826048Sminshall 			case TYPE_E:
117926048Sminshall 				setebcdic();
118026048Sminshall 				break;
118126048Sminshall 			case TYPE_L:
118226048Sminshall 				settenex();
118326048Sminshall 				break;
118426048Sminshall 		}
118526048Sminshall 		pswitch(1);
118626048Sminshall 		return;
118726048Sminshall 	}
118826448Slepreau 	if (setjmp(ptabort))
118926048Sminshall 		goto abort;
119026048Sminshall 	oldintr = signal(SIGINT, abortpt);
119126048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
119226048Sminshall 		(void) signal(SIGINT, oldintr);
119326048Sminshall 		switch (oldtype) {
119426048Sminshall 			case 0:
119526048Sminshall 				break;
119626048Sminshall 			case TYPE_A:
119726048Sminshall 				setascii();
119826048Sminshall 				break;
119926048Sminshall 			case TYPE_I:
120026048Sminshall 				setbinary();
120126048Sminshall 				break;
120226048Sminshall 			case TYPE_E:
120326048Sminshall 				setebcdic();
120426048Sminshall 				break;
120526048Sminshall 			case TYPE_L:
120626048Sminshall 				settenex();
120726048Sminshall 				break;
120826048Sminshall 		}
120926048Sminshall 		pswitch(1);
121026048Sminshall 		return;
121126048Sminshall 	}
121226048Sminshall 	sleep(2);
121326048Sminshall 	pswitch(1);
121426048Sminshall 	secndflag++;
121526448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
121626048Sminshall 		goto abort;
121726048Sminshall 	ptflag++;
121826048Sminshall 	(void) getreply(0);
121926048Sminshall 	pswitch(0);
122026048Sminshall 	(void) getreply(0);
122126048Sminshall 	(void) signal(SIGINT, oldintr);
122226048Sminshall 	switch (oldtype) {
122326048Sminshall 		case 0:
122426048Sminshall 			break;
122526048Sminshall 		case TYPE_A:
122626048Sminshall 			setascii();
122726048Sminshall 			break;
122826048Sminshall 		case TYPE_I:
122926048Sminshall 			setbinary();
123026048Sminshall 			break;
123126048Sminshall 		case TYPE_E:
123226048Sminshall 			setebcdic();
123326048Sminshall 			break;
123426048Sminshall 		case TYPE_L:
123526048Sminshall 			settenex();
123626048Sminshall 			break;
123726048Sminshall 	}
123826048Sminshall 	pswitch(1);
123926048Sminshall 	ptflag = 0;
124026048Sminshall 	printf("local: %s remote: %s\n", local, remote);
124126048Sminshall 	return;
124226048Sminshall abort:
124326048Sminshall 	(void) signal(SIGINT, SIG_IGN);
124426048Sminshall 	ptflag = 0;
124526448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
124626048Sminshall 		pswitch(1);
124726448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
124826048Sminshall 		pswitch(0);
124926048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
125026048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
125126048Sminshall 			pswitch(0);
125226048Sminshall 			switch (oldtype) {
125326048Sminshall 				case 0:
125426048Sminshall 					break;
125526048Sminshall 				case TYPE_A:
125626048Sminshall 					setascii();
125726048Sminshall 					break;
125826048Sminshall 				case TYPE_I:
125926048Sminshall 					setbinary();
126026048Sminshall 					break;
126126048Sminshall 				case TYPE_E:
126226048Sminshall 					setebcdic();
126326048Sminshall 					break;
126426048Sminshall 				case TYPE_L:
126526048Sminshall 					settenex();
126626048Sminshall 					break;
126726048Sminshall 			}
126827687Sminshall 			if (cpend) {
126926048Sminshall 				char msg[2];
127026048Sminshall 
127126048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
127226048Sminshall 				(void) fflush(cout);
127326048Sminshall 				*msg = IAC;
127426048Sminshall 				*(msg+1) = DM;
127526448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
127626048Sminshall 					perror("abort");
127726048Sminshall 				fprintf(cout,"ABOR\r\n");
127826048Sminshall 				(void) fflush(cout);
127927687Sminshall 				FD_ZERO(&mask);
128026496Sminshall 				FD_SET(fileno(cin), &mask);
128127687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
128227687Sminshall 					if (nfnd < 0) {
128327687Sminshall 						perror("abort");
128427687Sminshall 					}
128526448Slepreau 					if (ptabflg)
128626048Sminshall 						code = -1;
128726048Sminshall 					lostpeer();
128826048Sminshall 				}
128926048Sminshall 				(void) getreply(0);
129026048Sminshall 				(void) getreply(0);
129126048Sminshall 			}
129226048Sminshall 		}
129326048Sminshall 		pswitch(1);
129426448Slepreau 		if (ptabflg)
129526048Sminshall 			code = -1;
129626048Sminshall 		(void) signal(SIGINT, oldintr);
129726048Sminshall 		return;
129826048Sminshall 	}
129927687Sminshall 	if (cpend) {
130026048Sminshall 		char msg[2];
130126048Sminshall 
130226048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
130326048Sminshall 		(void) fflush(cout);
130426048Sminshall 		*msg = IAC;
130526048Sminshall 		*(msg+1) = DM;
130626448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
130726048Sminshall 			perror("abort");
130826048Sminshall 		fprintf(cout,"ABOR\r\n");
130926048Sminshall 		(void) fflush(cout);
131027687Sminshall 		FD_ZERO(&mask);
131126496Sminshall 		FD_SET(fileno(cin), &mask);
131227687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
131327687Sminshall 			if (nfnd < 0) {
131427687Sminshall 				perror("abort");
131527687Sminshall 			}
131626448Slepreau 			if (ptabflg)
131726048Sminshall 				code = -1;
131826048Sminshall 			lostpeer();
131926048Sminshall 		}
132026048Sminshall 		(void) getreply(0);
132126048Sminshall 		(void) getreply(0);
132226048Sminshall 	}
132326048Sminshall 	pswitch(!proxy);
132426048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
132526048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
132626048Sminshall 			pswitch(0);
132726048Sminshall 			switch (oldtype) {
132826048Sminshall 				case 0:
132926048Sminshall 					break;
133026048Sminshall 				case TYPE_A:
133126048Sminshall 					setascii();
133226048Sminshall 					break;
133326048Sminshall 				case TYPE_I:
133426048Sminshall 					setbinary();
133526048Sminshall 					break;
133626048Sminshall 				case TYPE_E:
133726048Sminshall 					setebcdic();
133826048Sminshall 					break;
133926048Sminshall 				case TYPE_L:
134026048Sminshall 					settenex();
134126048Sminshall 					break;
134226048Sminshall 			}
134327687Sminshall 			if (cpend) {
134426048Sminshall 				char msg[2];
134526048Sminshall 
134626048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
134726048Sminshall 				(void) fflush(cout);
134826048Sminshall 				*msg = IAC;
134926048Sminshall 				*(msg+1) = DM;
135026448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
135126048Sminshall 					perror("abort");
135226048Sminshall 				fprintf(cout,"ABOR\r\n");
135326048Sminshall 				(void) fflush(cout);
135427687Sminshall 				FD_ZERO(&mask);
135526496Sminshall 				FD_SET(fileno(cin), &mask);
135627687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
135727687Sminshall 					if (nfnd < 0) {
135827687Sminshall 						perror("abort");
135927687Sminshall 					}
136026448Slepreau 					if (ptabflg)
136126048Sminshall 						code = -1;
136226048Sminshall 					lostpeer();
136326048Sminshall 				}
136426048Sminshall 				(void) getreply(0);
136526048Sminshall 				(void) getreply(0);
136626048Sminshall 			}
136726048Sminshall 			pswitch(1);
136826448Slepreau 			if (ptabflg)
136926048Sminshall 				code = -1;
137026048Sminshall 			(void) signal(SIGINT, oldintr);
137126048Sminshall 			return;
137226048Sminshall 		}
137326048Sminshall 	}
137427687Sminshall 	if (cpend) {
137526048Sminshall 		char msg[2];
137626048Sminshall 
137726048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
137826048Sminshall 		(void) fflush(cout);
137926048Sminshall 		*msg = IAC;
138026048Sminshall 		*(msg+1) = DM;
138126448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
138226048Sminshall 			perror("abort");
138326048Sminshall 		fprintf(cout,"ABOR\r\n");
138426048Sminshall 		(void) fflush(cout);
138527687Sminshall 		FD_ZERO(&mask);
138626496Sminshall 		FD_SET(fileno(cin), &mask);
138727687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
138827687Sminshall 			if (nfnd < 0) {
138927687Sminshall 				perror("abort");
139027687Sminshall 			}
139126448Slepreau 			if (ptabflg)
139226048Sminshall 				code = -1;
139326048Sminshall 			lostpeer();
139426048Sminshall 		}
139526048Sminshall 		(void) getreply(0);
139626048Sminshall 		(void) getreply(0);
139726048Sminshall 	}
139826048Sminshall 	pswitch(!proxy);
139926048Sminshall 	if (cpend) {
140027687Sminshall 		FD_ZERO(&mask);
140126496Sminshall 		FD_SET(fileno(cin), &mask);
140227687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
140327687Sminshall 			if (nfnd < 0) {
140427687Sminshall 				perror("abort");
140527687Sminshall 			}
140626448Slepreau 			if (ptabflg)
140726048Sminshall 				code = -1;
140826048Sminshall 			lostpeer();
140926048Sminshall 		}
141026048Sminshall 		(void) getreply(0);
141126048Sminshall 		(void) getreply(0);
141226048Sminshall 	}
141326448Slepreau 	if (proxy)
141426048Sminshall 		pswitch(0);
141526048Sminshall 	switch (oldtype) {
141626048Sminshall 		case 0:
141726048Sminshall 			break;
141826048Sminshall 		case TYPE_A:
141926048Sminshall 			setascii();
142026048Sminshall 			break;
142126048Sminshall 		case TYPE_I:
142226048Sminshall 			setbinary();
142326048Sminshall 			break;
142426048Sminshall 		case TYPE_E:
142526048Sminshall 			setebcdic();
142626048Sminshall 			break;
142726048Sminshall 		case TYPE_L:
142826048Sminshall 			settenex();
142926048Sminshall 			break;
143026048Sminshall 	}
143126048Sminshall 	pswitch(1);
143226448Slepreau 	if (ptabflg)
143326048Sminshall 		code = -1;
143426048Sminshall 	(void) signal(SIGINT, oldintr);
143526048Sminshall }
143626048Sminshall 
143726048Sminshall reset()
143826048Sminshall {
143926496Sminshall 	struct fd_set mask;
144026496Sminshall 	int nfnd = 1;
144126048Sminshall 
144227687Sminshall 	FD_ZERO(&mask);
144330946Scsvsj 	while (nfnd > 0) {
144426496Sminshall 		FD_SET(fileno(cin), &mask);
144527687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
144626048Sminshall 			perror("reset");
144726048Sminshall 			code = -1;
144826048Sminshall 			lostpeer();
144926048Sminshall 		}
145027687Sminshall 		else if (nfnd) {
145126048Sminshall 			(void) getreply(0);
145226496Sminshall 		}
145326048Sminshall 	}
145426048Sminshall }
145526048Sminshall 
145626048Sminshall char *
145726048Sminshall gunique(local)
145826048Sminshall 	char *local;
145926048Sminshall {
146026048Sminshall 	static char new[MAXPATHLEN];
146126048Sminshall 	char *cp = rindex(local, '/');
146226048Sminshall 	int d, count=0;
146326048Sminshall 	char ext = '1';
146426048Sminshall 
146526448Slepreau 	if (cp)
146626048Sminshall 		*cp = '\0';
146726048Sminshall 	d = access(cp ? local : ".", 2);
146826448Slepreau 	if (cp)
146926048Sminshall 		*cp = '/';
147026048Sminshall 	if (d < 0) {
147126048Sminshall 		perror(local);
147226048Sminshall 		return((char *) 0);
147326048Sminshall 	}
147426048Sminshall 	(void) strcpy(new, local);
147526048Sminshall 	cp = new + strlen(new);
147626048Sminshall 	*cp++ = '.';
147726048Sminshall 	while (!d) {
147826048Sminshall 		if (++count == 100) {
147926048Sminshall 			printf("runique: can't find unique file name.\n");
148026048Sminshall 			return((char *) 0);
148126048Sminshall 		}
148226048Sminshall 		*cp++ = ext;
148326048Sminshall 		*cp = '\0';
148426448Slepreau 		if (ext == '9')
148526048Sminshall 			ext = '0';
148626448Slepreau 		else
148726048Sminshall 			ext++;
148826448Slepreau 		if ((d = access(new, 0)) < 0)
148926048Sminshall 			break;
149026448Slepreau 		if (ext != '0')
149126048Sminshall 			cp--;
149226448Slepreau 		else if (*(cp - 2) == '.')
149326048Sminshall 			*(cp - 1) = '1';
149426048Sminshall 		else {
149526048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
149626048Sminshall 			cp--;
149726048Sminshall 		}
149826048Sminshall 	}
149926048Sminshall 	return(new);
150026048Sminshall }
1501