xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 27687)
121739Sdist /*
226048Sminshall  * Copyright (c) 1985 Regents of the University of California.
321739Sdist  * All rights reserved.  The Berkeley software License Agreement
421739Sdist  * specifies the terms and conditions for redistribution.
521739Sdist  */
621739Sdist 
710296Ssam #ifndef lint
8*27687Sminshall static char sccsid[] = "@(#)ftp.c	5.12 (Berkeley) 05/02/86";
921739Sdist #endif not lint
1010296Ssam 
1126048Sminshall #include "ftp_var.h"
1226048Sminshall 
1310296Ssam #include <sys/stat.h>
1410296Ssam #include <sys/ioctl.h>
1510296Ssam #include <sys/socket.h>
1613614Ssam #include <sys/time.h>
1726496Sminshall #include <sys/types.h>
1810296Ssam 
1910296Ssam #include <netinet/in.h>
2012397Ssam #include <arpa/ftp.h>
2126048Sminshall #include <arpa/telnet.h>
2210296Ssam 
2310296Ssam #include <stdio.h>
2410296Ssam #include <signal.h>
2510296Ssam #include <errno.h>
2610296Ssam #include <netdb.h>
2726048Sminshall #include <fcntl.h>
2826048Sminshall #include <pwd.h>
2910296Ssam 
3010296Ssam struct	sockaddr_in hisctladdr;
3110296Ssam struct	sockaddr_in data_addr;
3210296Ssam int	data = -1;
3326048Sminshall int	abrtflag = 0;
3426048Sminshall int	ptflag = 0;
3510296Ssam int	connected;
3610296Ssam struct	sockaddr_in myctladdr;
3726496Sminshall uid_t	getuid();
3810296Ssam 
3910296Ssam FILE	*cin, *cout;
4010296Ssam FILE	*dataconn();
4110296Ssam 
4225904Skarels char *
4310296Ssam hookup(host, port)
4410296Ssam 	char *host;
4510296Ssam 	int port;
4610296Ssam {
4725904Skarels 	register struct hostent *hp = 0;
48*27687Sminshall 	int s,len;
4925904Skarels 	static char hostnamebuf[80];
5010296Ssam 
5110296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5225904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
5325904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
5425904Skarels 		hisctladdr.sin_family = AF_INET;
5525904Skarels 		(void) strcpy(hostnamebuf, host);
5626048Sminshall 	}
5726048Sminshall 	else {
5825100Sbloom 		hp = gethostbyname(host);
5925904Skarels 		if (hp == NULL) {
6025904Skarels 			printf("%s: unknown host\n", host);
6126048Sminshall 			code = -1;
6226048Sminshall 			return((char *) 0);
6325904Skarels 		}
6425904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
6525904Skarels 		bcopy(hp->h_addr_list[0],
6625904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
6725904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
6810296Ssam 	}
6925904Skarels 	hostname = hostnamebuf;
7025904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7110296Ssam 	if (s < 0) {
7210296Ssam 		perror("ftp: socket");
7326048Sminshall 		code = -1;
7410296Ssam 		return (0);
7510296Ssam 	}
7610296Ssam 	hisctladdr.sin_port = port;
7726496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
7825904Skarels 		if (hp && hp->h_addr_list[1]) {
7925904Skarels 			int oerrno = errno;
8025904Skarels 
8125904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
8225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
8325904Skarels 			errno = oerrno;
8426496Sminshall 			perror((char *) 0);
8525904Skarels 			hp->h_addr_list++;
8625904Skarels 			bcopy(hp->h_addr_list[0],
8726048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8826496Sminshall 			fprintf(stdout, "Trying %s...\n",
8925904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9026813Skarels 			(void) close(s);
9126813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
9226813Skarels 			if (s < 0) {
9326813Skarels 				perror("ftp: socket");
9426813Skarels 				code = -1;
9526813Skarels 				return (0);
9626813Skarels 			}
9725904Skarels 			continue;
9825904Skarels 		}
9910296Ssam 		perror("ftp: connect");
10026048Sminshall 		code = -1;
10110296Ssam 		goto bad;
10210296Ssam 	}
10311627Ssam 	len = sizeof (myctladdr);
10411627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
10511627Ssam 		perror("ftp: getsockname");
10626048Sminshall 		code = -1;
10710296Ssam 		goto bad;
10810296Ssam 	}
10910296Ssam 	cin = fdopen(s, "r");
11010296Ssam 	cout = fdopen(s, "w");
11111219Ssam 	if (cin == NULL || cout == NULL) {
11210296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
11310296Ssam 		if (cin)
11426496Sminshall 			(void) fclose(cin);
11510296Ssam 		if (cout)
11626496Sminshall 			(void) fclose(cout);
11726048Sminshall 		code = -1;
11810296Ssam 		goto bad;
11910296Ssam 	}
12010296Ssam 	if (verbose)
12126067Sminshall 		printf("Connected to %s.\n", hostname);
122*27687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
12326048Sminshall 		if (cin)
12426496Sminshall 			(void) fclose(cin);
12526048Sminshall 		if (cout)
12626496Sminshall 			(void) fclose(cout);
12726048Sminshall 		code = -1;
12826048Sminshall 		goto bad;
12926048Sminshall 	}
130*27687Sminshall #ifdef SO_OOBINLINE
131*27687Sminshall 	{
132*27687Sminshall 	int on = 1;
13326048Sminshall 
134*27687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
135*27687Sminshall 		< 0 && debug) {
136*27687Sminshall 			perror("ftp: setsockopt");
137*27687Sminshall 		}
138*27687Sminshall 	}
139*27687Sminshall #endif SO_OOBINLINE
14026048Sminshall 
14125904Skarels 	return (hostname);
14210296Ssam bad:
14326496Sminshall 	(void) close(s);
14425904Skarels 	return ((char *)0);
14510296Ssam }
14610296Ssam 
14725904Skarels login(host)
14825904Skarels 	char *host;
14910296Ssam {
15026048Sminshall 	char tmp[80];
15126496Sminshall 	char *user, *pass, *acct, *getlogin(), *mygetpass();
15226048Sminshall 	int n, aflag = 0;
15310296Ssam 
15426048Sminshall 	user = pass = acct = 0;
15526048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
15626048Sminshall 		disconnect();
15726048Sminshall 		code = -1;
15826048Sminshall 		return(0);
15926048Sminshall 	}
16026048Sminshall 	if (user == NULL) {
16126048Sminshall 		char *myname = getlogin();
16226048Sminshall 
16326048Sminshall 		if (myname == NULL) {
16426048Sminshall 			struct passwd *pp = getpwuid(getuid());
16526048Sminshall 
16626448Slepreau 			if (pp != NULL)
16726048Sminshall 				myname = pp->pw_name;
16826048Sminshall 		}
16926048Sminshall 		printf("Name (%s:%s): ", host, myname);
17026048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
17126048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
17226448Slepreau 		if (*tmp == '\0')
17326048Sminshall 			user = myname;
17426448Slepreau 		else
17526048Sminshall 			user = tmp;
17626048Sminshall 	}
17710296Ssam 	n = command("USER %s", user);
17826048Sminshall 	if (n == CONTINUE) {
17926448Slepreau 		if (pass == NULL)
18026496Sminshall 			pass = mygetpass("Password:");
18110296Ssam 		n = command("PASS %s", pass);
18226048Sminshall 	}
18310296Ssam 	if (n == CONTINUE) {
18426048Sminshall 		aflag++;
18526496Sminshall 		acct = mygetpass("Account:");
18610296Ssam 		n = command("ACCT %s", acct);
18710296Ssam 	}
18810296Ssam 	if (n != COMPLETE) {
18910296Ssam 		fprintf(stderr, "Login failed.\n");
19010296Ssam 		return (0);
19110296Ssam 	}
19226448Slepreau 	if (!aflag && acct != NULL)
19326048Sminshall 		(void) command("ACCT %s", acct);
19426448Slepreau 	if (proxy)
19526048Sminshall 		return(1);
19626048Sminshall 	for (n = 0; n < macnum; ++n) {
19726048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
19826496Sminshall 			(void) strcpy(line, "$init");
19926048Sminshall 			makeargv();
20026048Sminshall 			domacro(margc, margv);
20126048Sminshall 			break;
20226048Sminshall 		}
20326048Sminshall 	}
20410296Ssam 	return (1);
20510296Ssam }
20610296Ssam 
20726048Sminshall cmdabort()
20826048Sminshall {
20926048Sminshall 	extern jmp_buf ptabort;
21026048Sminshall 
21126048Sminshall 	printf("\n");
21226048Sminshall 	(void) fflush(stdout);
21326048Sminshall 	abrtflag++;
21426448Slepreau 	if (ptflag)
21526048Sminshall 		longjmp(ptabort,1);
21626048Sminshall }
21726048Sminshall 
21826496Sminshall /*VARARGS1*/
21910296Ssam command(fmt, args)
22010296Ssam 	char *fmt;
22110296Ssam {
22226048Sminshall 	int r, (*oldintr)(), cmdabort();
22310296Ssam 
22426048Sminshall 	abrtflag = 0;
22510296Ssam 	if (debug) {
22610296Ssam 		printf("---> ");
22710296Ssam 		_doprnt(fmt, &args, stdout);
22810296Ssam 		printf("\n");
22910296Ssam 		(void) fflush(stdout);
23010296Ssam 	}
23111219Ssam 	if (cout == NULL) {
23211219Ssam 		perror ("No control connection for command");
23326048Sminshall 		code = -1;
23411219Ssam 		return (0);
23511219Ssam 	}
23626048Sminshall 	oldintr = signal(SIGINT,cmdabort);
23710296Ssam 	_doprnt(fmt, &args, cout);
23810296Ssam 	fprintf(cout, "\r\n");
23910296Ssam 	(void) fflush(cout);
24026048Sminshall 	cpend = 1;
24126048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
24226448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
24326048Sminshall 		(*oldintr)();
24426048Sminshall 	(void) signal(SIGINT, oldintr);
24526048Sminshall 	return(r);
24610296Ssam }
24710296Ssam 
24810296Ssam #include <ctype.h>
24910296Ssam 
25010296Ssam getreply(expecteof)
25110296Ssam 	int expecteof;
25210296Ssam {
25311219Ssam 	register int c, n;
25426048Sminshall 	register int dig;
25526048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
25626048Sminshall 	int pflag = 0;
25726048Sminshall 	char *pt = pasv;
25810296Ssam 
25926048Sminshall 	oldintr = signal(SIGINT,cmdabort);
26010296Ssam 	for (;;) {
26110296Ssam 		dig = n = code = 0;
26210296Ssam 		while ((c = getc(cin)) != '\n') {
263*27687Sminshall 			if (c == IAC) {     /* handle telnet commands */
264*27687Sminshall 				switch (c = getc(cin)) {
265*27687Sminshall 				case WILL:
266*27687Sminshall 				case WONT:
267*27687Sminshall 					c = getc(cin);
268*27687Sminshall 					fprintf(cout, "%c%c%c",IAC,WONT,c);
269*27687Sminshall 					(void) fflush(cout);
270*27687Sminshall 					break;
271*27687Sminshall 				case DO:
272*27687Sminshall 				case DONT:
273*27687Sminshall 					c = getc(cin);
274*27687Sminshall 					fprintf(cout, "%c%c%c",IAC,DONT,c);
275*27687Sminshall 					(void) fflush(cout);
276*27687Sminshall 					break;
277*27687Sminshall 				default:
278*27687Sminshall 					break;
279*27687Sminshall 				}
280*27687Sminshall 				continue;
281*27687Sminshall 			}
28210296Ssam 			dig++;
28310296Ssam 			if (c == EOF) {
28426048Sminshall 				if (expecteof) {
28526048Sminshall 					(void) signal(SIGINT,oldintr);
28626048Sminshall 					code = 221;
28710296Ssam 					return (0);
28826048Sminshall 				}
28910296Ssam 				lostpeer();
29026048Sminshall 				if (verbose) {
29126048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
29226048Sminshall 					(void) fflush(stdout);
29326048Sminshall 					code = 421;
29426048Sminshall 					return(4);
29526048Sminshall 				}
29610296Ssam 			}
29726048Sminshall 			if (c != '\r' && (verbose > 0 ||
29826048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
29926448Slepreau 				if (proxflag &&
30026448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
30126048Sminshall 					printf("%s:",hostname);
30226496Sminshall 				(void) putchar(c);
30326048Sminshall 			}
30410296Ssam 			if (dig < 4 && isdigit(c))
30510296Ssam 				code = code * 10 + (c - '0');
30626448Slepreau 			if (!pflag && code == 227)
30726048Sminshall 				pflag = 1;
30826448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
30926048Sminshall 				pflag = 2;
31026048Sminshall 			if (pflag == 2) {
31126448Slepreau 				if (c != '\r' && c != ')')
31226048Sminshall 					*pt++ = c;
31326048Sminshall 				else {
31426048Sminshall 					*pt = '\0';
31526048Sminshall 					pflag = 3;
31626048Sminshall 				}
31726048Sminshall 			}
31826048Sminshall 			if (dig == 4 && c == '-') {
31926448Slepreau 				if (continuation)
32026048Sminshall 					code = 0;
32110296Ssam 				continuation++;
32226048Sminshall 			}
32310296Ssam 			if (n == 0)
32410296Ssam 				n = c;
32510296Ssam 		}
32626048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
32726496Sminshall 			(void) putchar(c);
32811346Ssam 			(void) fflush (stdout);
32911346Ssam 		}
33010296Ssam 		if (continuation && code != originalcode) {
33110296Ssam 			if (originalcode == 0)
33210296Ssam 				originalcode = code;
33310296Ssam 			continue;
33410296Ssam 		}
33526448Slepreau 		if (n != '1')
33626048Sminshall 			cpend = 0;
33726048Sminshall 		(void) signal(SIGINT,oldintr);
33826448Slepreau 		if (code == 421 || originalcode == 421)
33926048Sminshall 			lostpeer();
34026448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
34126048Sminshall 			(*oldintr)();
34225907Smckusick 		return (n - '0');
34310296Ssam 	}
34410296Ssam }
34510296Ssam 
34626048Sminshall empty(mask, sec)
347*27687Sminshall 	struct fd_set *mask;
34826048Sminshall 	int sec;
34926048Sminshall {
35026048Sminshall 	struct timeval t;
35126048Sminshall 
35226048Sminshall 	t.tv_sec = (long) sec;
35326048Sminshall 	t.tv_usec = 0;
354*27687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
35526048Sminshall }
35626048Sminshall 
35710296Ssam jmp_buf	sendabort;
35810296Ssam 
35910296Ssam abortsend()
36010296Ssam {
36110296Ssam 
36226048Sminshall 	mflag = 0;
36326048Sminshall 	abrtflag = 0;
36426048Sminshall 	printf("\nsend aborted\n");
36526048Sminshall 	(void) fflush(stdout);
36610296Ssam 	longjmp(sendabort, 1);
36710296Ssam }
36810296Ssam 
36910296Ssam sendrequest(cmd, local, remote)
37010296Ssam 	char *cmd, *local, *remote;
37110296Ssam {
37226496Sminshall 	FILE *fin, *dout = 0, *mypopen();
37326496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
37426048Sminshall 	int abortsend();
37511219Ssam 	char buf[BUFSIZ];
37611651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
37711346Ssam 	register int c, d;
37810296Ssam 	struct stat st;
37910296Ssam 	struct timeval start, stop;
38010296Ssam 
38126048Sminshall 	if (proxy) {
38226048Sminshall 		proxtrans(cmd, local, remote);
38326048Sminshall 		return;
38426048Sminshall 	}
38510296Ssam 	closefunc = NULL;
38626048Sminshall 	oldintr = NULL;
38726048Sminshall 	oldintp = NULL;
38826048Sminshall 	if (setjmp(sendabort)) {
38926048Sminshall 		while (cpend) {
39026048Sminshall 			(void) getreply(0);
39126048Sminshall 		}
39226048Sminshall 		if (data >= 0) {
39326048Sminshall 			(void) close(data);
39426048Sminshall 			data = -1;
39526048Sminshall 		}
39626448Slepreau 		if (oldintr)
39726048Sminshall 			(void) signal(SIGINT,oldintr);
39826448Slepreau 		if (oldintp)
39926048Sminshall 			(void) signal(SIGPIPE,oldintp);
40026048Sminshall 		code = -1;
40126048Sminshall 		return;
40226048Sminshall 	}
40310296Ssam 	oldintr = signal(SIGINT, abortsend);
40410296Ssam 	if (strcmp(local, "-") == 0)
40510296Ssam 		fin = stdin;
40610296Ssam 	else if (*local == '|') {
40726048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
40826496Sminshall 		fin = mypopen(local + 1, "r");
40910296Ssam 		if (fin == NULL) {
41026048Sminshall 			perror(local + 1);
41126048Sminshall 			(void) signal(SIGINT, oldintr);
41226048Sminshall 			(void) signal(SIGPIPE, oldintp);
41326048Sminshall 			code = -1;
41426048Sminshall 			return;
41510296Ssam 		}
41626496Sminshall 		closefunc = mypclose;
41710296Ssam 	} else {
41810296Ssam 		fin = fopen(local, "r");
41910296Ssam 		if (fin == NULL) {
42010296Ssam 			perror(local);
42126048Sminshall 			(void) signal(SIGINT, oldintr);
42226048Sminshall 			code = -1;
42326048Sminshall 			return;
42410296Ssam 		}
42510296Ssam 		closefunc = fclose;
42610296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
42710296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
42826496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
42926048Sminshall 			(void) signal(SIGINT, oldintr);
43026048Sminshall 			code = -1;
43126048Sminshall 			return;
43210296Ssam 		}
43310296Ssam 	}
43426048Sminshall 	if (initconn()) {
43526048Sminshall 		(void) signal(SIGINT, oldintr);
43626448Slepreau 		if (oldintp)
43726048Sminshall 			(void) signal(SIGPIPE, oldintp);
43826048Sminshall 		code = -1;
43926048Sminshall 		return;
44026048Sminshall 	}
44126448Slepreau 	if (setjmp(sendabort))
44226048Sminshall 		goto abort;
44310296Ssam 	if (remote) {
44426048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
44526048Sminshall 			(void) signal(SIGINT, oldintr);
44626448Slepreau 			if (oldintp)
44726048Sminshall 				(void) signal(SIGPIPE, oldintp);
44826048Sminshall 			return;
44926048Sminshall 		}
45010296Ssam 	} else
45126048Sminshall 		if (command("%s", cmd) != PRELIM) {
45226048Sminshall 			(void) signal(SIGINT, oldintr);
45326448Slepreau 			if (oldintp)
45426048Sminshall 				(void) signal(SIGPIPE, oldintp);
45526048Sminshall 			return;
45626048Sminshall 		}
45710296Ssam 	dout = dataconn("w");
45826448Slepreau 	if (dout == NULL)
45926048Sminshall 		goto abort;
46026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
46111219Ssam 	switch (type) {
46211219Ssam 
46311219Ssam 	case TYPE_I:
46411219Ssam 	case TYPE_L:
46511346Ssam 		errno = d = 0;
46611219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
46711346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
46811219Ssam 				break;
46911219Ssam 			bytes += c;
47011651Ssam 			if (hash) {
47126496Sminshall 				(void) putchar('#');
47226496Sminshall 				(void) fflush(stdout);
47311651Ssam 			}
47411219Ssam 		}
47513213Ssam 		if (hash && bytes > 0) {
47626496Sminshall 			(void) putchar('\n');
47726496Sminshall 			(void) fflush(stdout);
47811651Ssam 		}
47911219Ssam 		if (c < 0)
48011219Ssam 			perror(local);
48111346Ssam 		if (d < 0)
48211219Ssam 			perror("netout");
48311219Ssam 		break;
48411219Ssam 
48511219Ssam 	case TYPE_A:
48611219Ssam 		while ((c = getc(fin)) != EOF) {
48711219Ssam 			if (c == '\n') {
48811651Ssam 				while (hash && (bytes >= hashbytes)) {
48926496Sminshall 					(void) putchar('#');
49026496Sminshall 					(void) fflush(stdout);
49111651Ssam 					hashbytes += sizeof (buf);
49211651Ssam 				}
49311219Ssam 				if (ferror(dout))
49411219Ssam 					break;
49526496Sminshall 				(void) putc('\r', dout);
49611219Ssam 				bytes++;
49711219Ssam 			}
49826496Sminshall 			(void) putc(c, dout);
49911219Ssam 			bytes++;
50026048Sminshall 	/*		if (c == '\r') {			  	*/
50126496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
50226048Sminshall 	/*			bytes++;				*/
50326048Sminshall 	/*		}                          			*/
50411219Ssam 		}
50511651Ssam 		if (hash) {
50613213Ssam 			if (bytes < hashbytes)
50726496Sminshall 				(void) putchar('#');
50826496Sminshall 			(void) putchar('\n');
50926496Sminshall 			(void) fflush(stdout);
51011651Ssam 		}
51111219Ssam 		if (ferror(fin))
51211219Ssam 			perror(local);
51311346Ssam 		if (ferror(dout))
51411219Ssam 			perror("netout");
51511219Ssam 		break;
51610296Ssam 	}
51726496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
51810296Ssam 	if (closefunc != NULL)
51926048Sminshall 		(*closefunc)(fin);
52010296Ssam 	(void) fclose(dout);
52126048Sminshall 	(void) getreply(0);
52226048Sminshall 	(void) signal(SIGINT, oldintr);
52310296Ssam 	if (bytes > 0 && verbose)
52426048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
52510296Ssam 	return;
52626048Sminshall abort:
52726496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
52826048Sminshall 	(void) signal(SIGINT, oldintr);
52926448Slepreau 	if (oldintp)
53026048Sminshall 		(void) signal(SIGPIPE, oldintp);
53126048Sminshall 	if (!cpend) {
53226048Sminshall 		code = -1;
53326048Sminshall 		return;
53426048Sminshall 	}
53526048Sminshall 	if (data >= 0) {
53626048Sminshall 		(void) close(data);
53726048Sminshall 		data = -1;
53826048Sminshall 	}
53926448Slepreau 	if (dout)
54026048Sminshall 		(void) fclose(dout);
54126048Sminshall 	(void) getreply(0);
54226048Sminshall 	code = -1;
54310296Ssam 	if (closefunc != NULL && fin != NULL)
54426048Sminshall 		(*closefunc)(fin);
54526048Sminshall 	if (bytes > 0 && verbose)
54626048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
54710296Ssam }
54810296Ssam 
54910296Ssam jmp_buf	recvabort;
55010296Ssam 
55110296Ssam abortrecv()
55210296Ssam {
55310296Ssam 
55426048Sminshall 	mflag = 0;
55526048Sminshall 	abrtflag = 0;
55626048Sminshall 	printf("\n");
55726048Sminshall 	(void) fflush(stdout);
55810296Ssam 	longjmp(recvabort, 1);
55910296Ssam }
56010296Ssam 
56111651Ssam recvrequest(cmd, local, remote, mode)
56211651Ssam 	char *cmd, *local, *remote, *mode;
56310296Ssam {
56426496Sminshall 	FILE *fout, *din = 0, *mypopen();
56526496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
566*27687Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag, nfnd;
567*27687Sminshall 	char buf[BUFSIZ], *gunique(), msg;
56826496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
56926496Sminshall 	struct fd_set mask;
57011346Ssam 	register int c, d;
57110296Ssam 	struct timeval start, stop;
57210296Ssam 
57326048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
57426048Sminshall 		proxtrans(cmd, local, remote);
57526048Sminshall 		return;
57626048Sminshall 	}
57710296Ssam 	closefunc = NULL;
57826048Sminshall 	oldintr = NULL;
57926048Sminshall 	oldintp = NULL;
58026048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
58126048Sminshall 	if (setjmp(recvabort)) {
58226048Sminshall 		while (cpend) {
58326048Sminshall 			(void) getreply(0);
58426048Sminshall 		}
58526048Sminshall 		if (data >= 0) {
58626048Sminshall 			(void) close(data);
58726048Sminshall 			data = -1;
58826048Sminshall 		}
58926448Slepreau 		if (oldintr)
59026048Sminshall 			(void) signal(SIGINT, oldintr);
59126048Sminshall 		code = -1;
59226048Sminshall 		return;
59326048Sminshall 	}
59410296Ssam 	oldintr = signal(SIGINT, abortrecv);
59526048Sminshall 	if (strcmp(local, "-") && *local != '|') {
59610296Ssam 		if (access(local, 2) < 0) {
59726048Sminshall 			char *dir = rindex(local, '/');
59810296Ssam 
59926048Sminshall 			if (errno != ENOENT && errno != EACCES) {
60010296Ssam 				perror(local);
60126048Sminshall 				(void) signal(SIGINT, oldintr);
60226048Sminshall 				code = -1;
60326048Sminshall 				return;
60410296Ssam 			}
60526048Sminshall 			if (dir != NULL)
60626048Sminshall 				*dir = 0;
60726048Sminshall 			d = access(dir ? local : ".", 2);
60826048Sminshall 			if (dir != NULL)
60926048Sminshall 				*dir = '/';
61026048Sminshall 			if (d < 0) {
61126048Sminshall 				perror(local);
61226048Sminshall 				(void) signal(SIGINT, oldintr);
61326048Sminshall 				code = -1;
61426048Sminshall 				return;
61526048Sminshall 			}
61626048Sminshall 			if (!runique && errno == EACCES &&
61726048Sminshall 			    chmod(local,0600) < 0) {
61826048Sminshall 				perror(local);
61926048Sminshall 				(void) signal(SIGINT, oldintr);
62026048Sminshall 				code = -1;
62126048Sminshall 				return;
62226048Sminshall 			}
62326048Sminshall 			if (runique && errno == EACCES &&
62426048Sminshall 			   (local = gunique(local)) == NULL) {
62526048Sminshall 				(void) signal(SIGINT, oldintr);
62626048Sminshall 				code = -1;
62726048Sminshall 				return;
62826048Sminshall 			}
62910296Ssam 		}
63026048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
63126048Sminshall 			(void) signal(SIGINT, oldintr);
63226048Sminshall 			code = -1;
63326048Sminshall 			return;
63426048Sminshall 		}
63526048Sminshall 	}
63626048Sminshall 	if (initconn()) {
63726048Sminshall 		(void) signal(SIGINT, oldintr);
63826048Sminshall 		code = -1;
63926048Sminshall 		return;
64026048Sminshall 	}
64126448Slepreau 	if (setjmp(recvabort))
64226048Sminshall 		goto abort;
64326048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
64426048Sminshall 		oldtype = type;
64526048Sminshall 		oldverbose = verbose;
64626448Slepreau 		if (!debug)
64726048Sminshall 			verbose = 0;
64826048Sminshall 		setascii();
64926048Sminshall 		verbose = oldverbose;
65026048Sminshall 	}
65110296Ssam 	if (remote) {
65226048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
65326048Sminshall 			(void) signal(SIGINT, oldintr);
65426048Sminshall 			if (oldtype) {
65526448Slepreau 				if (!debug)
65626048Sminshall 					verbose = 0;
65726048Sminshall 				switch (oldtype) {
65826048Sminshall 					case TYPE_I:
65926048Sminshall 						setbinary();
66026048Sminshall 						break;
66126048Sminshall 					case TYPE_E:
66226048Sminshall 						setebcdic();
66326048Sminshall 						break;
66426048Sminshall 					case TYPE_L:
66526048Sminshall 						settenex();
66626048Sminshall 						break;
66726048Sminshall 				}
66826048Sminshall 				verbose = oldverbose;
66926048Sminshall 			}
67026048Sminshall 			return;
67126048Sminshall 		}
67226048Sminshall 	} else {
67326048Sminshall 		if (command("%s", cmd) != PRELIM) {
67426048Sminshall 			(void) signal(SIGINT, oldintr);
67526048Sminshall 			if (oldtype) {
67626448Slepreau 				if (!debug)
67726048Sminshall 					verbose = 0;
67826048Sminshall 				switch (oldtype) {
67926048Sminshall 					case TYPE_I:
68026048Sminshall 						setbinary();
68126048Sminshall 						break;
68226048Sminshall 					case TYPE_E:
68326048Sminshall 						setebcdic();
68426048Sminshall 						break;
68526048Sminshall 					case TYPE_L:
68626048Sminshall 						settenex();
68726048Sminshall 						break;
68826048Sminshall 				}
68926048Sminshall 				verbose = oldverbose;
69026048Sminshall 			}
69126048Sminshall 			return;
69226048Sminshall 		}
69326048Sminshall 	}
69426048Sminshall 	din = dataconn("r");
69526048Sminshall 	if (din == NULL)
69626048Sminshall 		goto abort;
69726448Slepreau 	if (strcmp(local, "-") == 0)
69810296Ssam 		fout = stdout;
69910296Ssam 	else if (*local == '|') {
70026048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
70126496Sminshall 		fout = mypopen(local + 1, "w");
70226048Sminshall 		if (fout == NULL) {
70326048Sminshall 			perror(local+1);
70426048Sminshall 			goto abort;
70526048Sminshall 		}
70626496Sminshall 		closefunc = mypclose;
70726048Sminshall 	}
70826048Sminshall 	else {
70911651Ssam 		fout = fopen(local, mode);
71026048Sminshall 		if (fout == NULL) {
71126048Sminshall 			perror(local);
71226048Sminshall 			goto abort;
71326048Sminshall 		}
71410296Ssam 		closefunc = fclose;
71510296Ssam 	}
71626496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
71711219Ssam 	switch (type) {
71811219Ssam 
71911219Ssam 	case TYPE_I:
72011219Ssam 	case TYPE_L:
72111346Ssam 		errno = d = 0;
72211219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
72311346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
72411219Ssam 				break;
72511219Ssam 			bytes += c;
72611651Ssam 			if (hash) {
72726496Sminshall 				(void) putchar('#');
72826496Sminshall 				(void) fflush(stdout);
72911651Ssam 			}
73011219Ssam 		}
73113213Ssam 		if (hash && bytes > 0) {
73226496Sminshall 			(void) putchar('\n');
73326496Sminshall 			(void) fflush(stdout);
73411651Ssam 		}
73511219Ssam 		if (c < 0)
73611219Ssam 			perror("netin");
73711346Ssam 		if (d < 0)
73810296Ssam 			perror(local);
73911219Ssam 		break;
74011219Ssam 
74111219Ssam 	case TYPE_A:
74211219Ssam 		while ((c = getc(din)) != EOF) {
74311219Ssam 			if (c == '\r') {
74411651Ssam 				while (hash && (bytes >= hashbytes)) {
74526496Sminshall 					(void) putchar('#');
74626496Sminshall 					(void) fflush(stdout);
74711651Ssam 					hashbytes += sizeof (buf);
74811651Ssam 				}
74910296Ssam 				bytes++;
75026048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
75111219Ssam 					if (ferror (fout))
75211219Ssam 						break;
75326496Sminshall 					(void) putc ('\r', fout);
75411219Ssam 				}
75526048Sminshall 				/*if (c == '\0') {
75611219Ssam 					bytes++;
75711219Ssam 					continue;
75826048Sminshall 				}*/
75911219Ssam 			}
76026496Sminshall 			(void) putc (c, fout);
76111219Ssam 			bytes++;
76210296Ssam 		}
76311651Ssam 		if (hash) {
76413213Ssam 			if (bytes < hashbytes)
76526496Sminshall 				(void) putchar('#');
76626496Sminshall 			(void) putchar('\n');
76726496Sminshall 			(void) fflush(stdout);
76811651Ssam 		}
76911219Ssam 		if (ferror (din))
77011219Ssam 			perror ("netin");
77111219Ssam 		if (ferror (fout))
77211219Ssam 			perror (local);
77311219Ssam 		break;
77410296Ssam 	}
77526448Slepreau 	if (closefunc != NULL)
77626048Sminshall 		(*closefunc)(fout);
77726496Sminshall 	(void) signal(SIGINT, oldintr);
77826448Slepreau 	if (oldintp)
77926048Sminshall 		(void) signal(SIGPIPE, oldintp);
78026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
78110296Ssam 	(void) fclose(din);
78226048Sminshall 	(void) getreply(0);
78326048Sminshall 	if (bytes > 0 && verbose)
78426048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
78526048Sminshall 	if (oldtype) {
78626448Slepreau 		if (!debug)
78726048Sminshall 			verbose = 0;
78826048Sminshall 		switch (oldtype) {
78926048Sminshall 			case TYPE_I:
79026048Sminshall 				setbinary();
79126048Sminshall 				break;
79226048Sminshall 			case TYPE_E:
79326048Sminshall 				setebcdic();
79426048Sminshall 				break;
79526048Sminshall 			case TYPE_L:
79626048Sminshall 				settenex();
79726048Sminshall 				break;
79826048Sminshall 		}
79926048Sminshall 		verbose = oldverbose;
80026048Sminshall 	}
80126048Sminshall 	return;
80226048Sminshall abort:
80326048Sminshall 
804*27687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
80526048Sminshall 
80626496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
80726448Slepreau 	if (oldintp)
80826048Sminshall 		(void) signal(SIGPIPE, oldintr);
80926048Sminshall 	(void) signal(SIGINT,SIG_IGN);
81026048Sminshall 	if (oldtype) {
81126448Slepreau 		if (!debug)
81226048Sminshall 			verbose = 0;
81326048Sminshall 		switch (oldtype) {
81426048Sminshall 			case TYPE_I:
81526048Sminshall 				setbinary();
81626048Sminshall 				break;
81726048Sminshall 			case TYPE_E:
81826048Sminshall 				setebcdic();
81926048Sminshall 				break;
82026048Sminshall 			case TYPE_L:
82126048Sminshall 				settenex();
82226048Sminshall 				break;
82326048Sminshall 		}
82426048Sminshall 		verbose = oldverbose;
82526048Sminshall 	}
82626048Sminshall 	if (!cpend) {
82726048Sminshall 		code = -1;
82826048Sminshall 		(void) signal(SIGINT,oldintr);
82926048Sminshall 		return;
83026048Sminshall 	}
83126048Sminshall 
832*27687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
833*27687Sminshall 	(void) fflush(cout);
834*27687Sminshall 	msg = IAC;
835*27687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
836*27687Sminshall /* after urgent byte rather than before as now is protocol            */
837*27687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
838*27687Sminshall 		perror("abort");
83926048Sminshall 	}
840*27687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
84126048Sminshall 	(void) fflush(cout);
842*27687Sminshall 	FD_ZERO(&mask);
84326496Sminshall 	FD_SET(fileno(cin), &mask);
84426496Sminshall 	if (din) {
84526496Sminshall 		FD_SET(fileno(din), &mask);
84626496Sminshall 	}
847*27687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
848*27687Sminshall 		if (nfnd < 0) {
849*27687Sminshall 			perror("abort");
850*27687Sminshall 		}
85126048Sminshall 		code = -1;
85226048Sminshall 		lostpeer();
85326048Sminshall 	}
85426496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
85526448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
85626448Slepreau 			;
85726496Sminshall 	}
858*27687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
85926048Sminshall 		if (data >= 0) {
86026496Sminshall 			(void) close(data);
86126048Sminshall 			data = -1;
86226048Sminshall 		}
86325907Smckusick 		(void) getreply(0);
86425907Smckusick 	}
86526048Sminshall 	(void) getreply(0);
86626048Sminshall 	code = -1;
86726048Sminshall 	if (data >= 0) {
86826048Sminshall 		(void) close(data);
86926048Sminshall 		data = -1;
87026048Sminshall 	}
87126448Slepreau 	if (closefunc != NULL && fout != NULL)
87226048Sminshall 		(*closefunc)(fout);
87326448Slepreau 	if (din)
87426048Sminshall 		(void) fclose(din);
87510296Ssam 	if (bytes > 0 && verbose)
87626048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
87726048Sminshall 	(void) signal(SIGINT,oldintr);
87810296Ssam }
87910296Ssam 
88010296Ssam /*
88110296Ssam  * Need to start a listen on the data channel
88210296Ssam  * before we send the command, otherwise the
88310296Ssam  * server's connect may fail.
88410296Ssam  */
88511651Ssam static int sendport = -1;
88611651Ssam 
88710296Ssam initconn()
88810296Ssam {
88910296Ssam 	register char *p, *a;
89026048Sminshall 	int result, len, tmpno = 0;
89126993Skarels 	int on = 1;
89210296Ssam 
89311651Ssam noport:
89410296Ssam 	data_addr = myctladdr;
89511651Ssam 	if (sendport)
89611651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
89711651Ssam 	if (data != -1)
89811651Ssam 		(void) close (data);
89918287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
90010296Ssam 	if (data < 0) {
90110296Ssam 		perror("ftp: socket");
90226448Slepreau 		if (tmpno)
90326048Sminshall 			sendport = 1;
90410296Ssam 		return (1);
90510296Ssam 	}
90612397Ssam 	if (!sendport)
907*27687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
90826048Sminshall 			perror("ftp: setsockopt (resuse address)");
90912397Ssam 			goto bad;
91012397Ssam 		}
91126496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
91210296Ssam 		perror("ftp: bind");
91310296Ssam 		goto bad;
91410296Ssam 	}
91510296Ssam 	if (options & SO_DEBUG &&
916*27687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
91710296Ssam 		perror("ftp: setsockopt (ignored)");
91811627Ssam 	len = sizeof (data_addr);
91911627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
92011627Ssam 		perror("ftp: getsockname");
92110296Ssam 		goto bad;
92210296Ssam 	}
92326448Slepreau 	if (listen(data, 1) < 0)
92410296Ssam 		perror("ftp: listen");
92511651Ssam 	if (sendport) {
92611651Ssam 		a = (char *)&data_addr.sin_addr;
92711651Ssam 		p = (char *)&data_addr.sin_port;
92810296Ssam #define	UC(b)	(((int)b)&0xff)
92911651Ssam 		result =
93011651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
93111651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
93211651Ssam 		      UC(p[0]), UC(p[1]));
93311651Ssam 		if (result == ERROR && sendport == -1) {
93411651Ssam 			sendport = 0;
93526048Sminshall 			tmpno = 1;
93611651Ssam 			goto noport;
93711651Ssam 		}
93811651Ssam 		return (result != COMPLETE);
93911651Ssam 	}
94026448Slepreau 	if (tmpno)
94126048Sminshall 		sendport = 1;
94211651Ssam 	return (0);
94310296Ssam bad:
94410296Ssam 	(void) close(data), data = -1;
94526448Slepreau 	if (tmpno)
94626048Sminshall 		sendport = 1;
94710296Ssam 	return (1);
94810296Ssam }
94910296Ssam 
95010296Ssam FILE *
95110296Ssam dataconn(mode)
95210296Ssam 	char *mode;
95310296Ssam {
95410296Ssam 	struct sockaddr_in from;
95510296Ssam 	int s, fromlen = sizeof (from);
95610296Ssam 
95726496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
95810296Ssam 	if (s < 0) {
95910296Ssam 		perror("ftp: accept");
96010296Ssam 		(void) close(data), data = -1;
96110296Ssam 		return (NULL);
96210296Ssam 	}
96310296Ssam 	(void) close(data);
96410296Ssam 	data = s;
96510296Ssam 	return (fdopen(data, mode));
96610296Ssam }
96710296Ssam 
96826048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
96926048Sminshall 	char *direction, *local, *remote;
97011651Ssam 	long bytes;
97110296Ssam 	struct timeval *t0, *t1;
97210296Ssam {
97310296Ssam 	struct timeval td;
97416437Sleres 	float s, bs;
97510296Ssam 
97610296Ssam 	tvsub(&td, t1, t0);
97716437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
97810296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
97916437Sleres 	bs = bytes / nz(s);
98026448Slepreau 	if (local && *local != '-')
98126048Sminshall 		printf("local: %s ", local);
98226448Slepreau 	if (remote)
98326048Sminshall 		printf("remote: %s\n", remote);
98416437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
98516437Sleres 		bytes, direction, s, bs / 1024.);
98610296Ssam }
98710296Ssam 
98826496Sminshall /*tvadd(tsum, t0)
98910296Ssam 	struct timeval *tsum, *t0;
99010296Ssam {
99110296Ssam 
99210296Ssam 	tsum->tv_sec += t0->tv_sec;
99310296Ssam 	tsum->tv_usec += t0->tv_usec;
99410296Ssam 	if (tsum->tv_usec > 1000000)
99510296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
99626496Sminshall } */
99710296Ssam 
99810296Ssam tvsub(tdiff, t1, t0)
99910296Ssam 	struct timeval *tdiff, *t1, *t0;
100010296Ssam {
100110296Ssam 
100210296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
100310296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
100410296Ssam 	if (tdiff->tv_usec < 0)
100510296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
100610296Ssam }
100726048Sminshall 
100826048Sminshall psabort()
100926048Sminshall {
101026048Sminshall 	extern int abrtflag;
101126048Sminshall 
101226048Sminshall 	abrtflag++;
101326048Sminshall }
101426048Sminshall 
101526048Sminshall pswitch(flag)
101626048Sminshall 	int flag;
101726048Sminshall {
101826048Sminshall 	extern int proxy, abrtflag;
101926048Sminshall 	int (*oldintr)();
102026048Sminshall 	static struct comvars {
102126048Sminshall 		int connect;
102226048Sminshall 		char name[32];
102326048Sminshall 		struct sockaddr_in mctl;
102426048Sminshall 		struct sockaddr_in hctl;
102526048Sminshall 		FILE *in;
102626048Sminshall 		FILE *out;
102726048Sminshall 		int tpe;
102826048Sminshall 		int cpnd;
102926048Sminshall 		int sunqe;
103026048Sminshall 		int runqe;
103126048Sminshall 		int mcse;
103226048Sminshall 		int ntflg;
103326048Sminshall 		char nti[17];
103426048Sminshall 		char nto[17];
103526048Sminshall 		int mapflg;
103626048Sminshall 		char mi[MAXPATHLEN];
103726048Sminshall 		char mo[MAXPATHLEN];
103826048Sminshall 		} proxstruct, tmpstruct;
103926048Sminshall 	struct comvars *ip, *op;
104026048Sminshall 
104126048Sminshall 	abrtflag = 0;
104226048Sminshall 	oldintr = signal(SIGINT, psabort);
104326048Sminshall 	if (flag) {
104426448Slepreau 		if (proxy)
104526048Sminshall 			return;
104626048Sminshall 		ip = &tmpstruct;
104726048Sminshall 		op = &proxstruct;
104826048Sminshall 		proxy++;
104926048Sminshall 	}
105026048Sminshall 	else {
105126448Slepreau 		if (!proxy)
105226048Sminshall 			return;
105326048Sminshall 		ip = &proxstruct;
105426048Sminshall 		op = &tmpstruct;
105526048Sminshall 		proxy = 0;
105626048Sminshall 	}
105726048Sminshall 	ip->connect = connected;
105826048Sminshall 	connected = op->connect;
105926496Sminshall 	(void) strncpy(ip->name, hostname, 31);
106026048Sminshall 	(ip->name)[strlen(ip->name)] = '\0';
106126048Sminshall 	hostname = op->name;
106226048Sminshall 	ip->hctl = hisctladdr;
106326048Sminshall 	hisctladdr = op->hctl;
106426048Sminshall 	ip->mctl = myctladdr;
106526048Sminshall 	myctladdr = op->mctl;
106626048Sminshall 	ip->in = cin;
106726048Sminshall 	cin = op->in;
106826048Sminshall 	ip->out = cout;
106926048Sminshall 	cout = op->out;
107026048Sminshall 	ip->tpe = type;
107126048Sminshall 	type = op->tpe;
107226448Slepreau 	if (!type)
107326048Sminshall 		type = 1;
107426048Sminshall 	ip->cpnd = cpend;
107526048Sminshall 	cpend = op->cpnd;
107626048Sminshall 	ip->sunqe = sunique;
107726048Sminshall 	sunique = op->sunqe;
107826048Sminshall 	ip->runqe = runique;
107926048Sminshall 	runique = op->runqe;
108026048Sminshall 	ip->mcse = mcase;
108126048Sminshall 	mcase = op->mcse;
108226048Sminshall 	ip->ntflg = ntflag;
108326048Sminshall 	ntflag = op->ntflg;
108426496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
108526048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
108626496Sminshall 	(void) strcpy(ntin, op->nti);
108726496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
108826048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
108926496Sminshall 	(void) strcpy(ntout, op->nto);
109026048Sminshall 	ip->mapflg = mapflag;
109126048Sminshall 	mapflag = op->mapflg;
109226496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
109326048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
109426496Sminshall 	(void) strcpy(mapin, op->mi);
109526496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
109626048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
109726496Sminshall 	(void) strcpy(mapout, op->mo);
109826048Sminshall 	(void) signal(SIGINT, oldintr);
109926048Sminshall 	if (abrtflag) {
110026048Sminshall 		abrtflag = 0;
110126048Sminshall 		(*oldintr)();
110226448Slepreau 	}
110326048Sminshall }
110426048Sminshall 
110526048Sminshall jmp_buf ptabort;
110626048Sminshall int ptabflg;
110726048Sminshall 
110826048Sminshall abortpt()
110926048Sminshall {
111026048Sminshall 	printf("\n");
111126496Sminshall 	(void) fflush(stdout);
111226048Sminshall 	ptabflg++;
111326048Sminshall 	mflag = 0;
111426048Sminshall 	abrtflag = 0;
111526048Sminshall 	longjmp(ptabort, 1);
111626048Sminshall }
111726048Sminshall 
111826048Sminshall proxtrans(cmd, local, remote)
111926048Sminshall 	char *cmd, *local, *remote;
112026048Sminshall {
1121*27687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
112226048Sminshall 	extern jmp_buf ptabort;
112326048Sminshall 	char *cmd2;
112426496Sminshall 	struct fd_set mask;
112526048Sminshall 
112626448Slepreau 	if (strcmp(cmd, "RETR"))
112726048Sminshall 		cmd2 = "RETR";
112826448Slepreau 	else
112926048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
113026048Sminshall 	if (command("PASV") != COMPLETE) {
113126048Sminshall 		printf("proxy server does not support third part transfers.\n");
113226048Sminshall 		return;
113326048Sminshall 	}
113426048Sminshall 	tmptype = type;
113526048Sminshall 	pswitch(0);
113626048Sminshall 	if (!connected) {
113726048Sminshall 		printf("No primary connection\n");
113826048Sminshall 		pswitch(1);
113926048Sminshall 		code = -1;
114026048Sminshall 		return;
114126048Sminshall 	}
114226048Sminshall 	if (type != tmptype) {
114326048Sminshall 		oldtype = type;
114426048Sminshall 		switch (tmptype) {
114526048Sminshall 			case TYPE_A:
114626048Sminshall 				setascii();
114726048Sminshall 				break;
114826048Sminshall 			case TYPE_I:
114926048Sminshall 				setbinary();
115026048Sminshall 				break;
115126048Sminshall 			case TYPE_E:
115226048Sminshall 				setebcdic();
115326048Sminshall 				break;
115426048Sminshall 			case TYPE_L:
115526048Sminshall 				settenex();
115626048Sminshall 				break;
115726048Sminshall 		}
115826048Sminshall 	}
115926048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
116026048Sminshall 		switch (oldtype) {
116126048Sminshall 			case 0:
116226048Sminshall 				break;
116326048Sminshall 			case TYPE_A:
116426048Sminshall 				setascii();
116526048Sminshall 				break;
116626048Sminshall 			case TYPE_I:
116726048Sminshall 				setbinary();
116826048Sminshall 				break;
116926048Sminshall 			case TYPE_E:
117026048Sminshall 				setebcdic();
117126048Sminshall 				break;
117226048Sminshall 			case TYPE_L:
117326048Sminshall 				settenex();
117426048Sminshall 				break;
117526048Sminshall 		}
117626048Sminshall 		pswitch(1);
117726048Sminshall 		return;
117826048Sminshall 	}
117926448Slepreau 	if (setjmp(ptabort))
118026048Sminshall 		goto abort;
118126048Sminshall 	oldintr = signal(SIGINT, abortpt);
118226048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
118326048Sminshall 		(void) signal(SIGINT, oldintr);
118426048Sminshall 		switch (oldtype) {
118526048Sminshall 			case 0:
118626048Sminshall 				break;
118726048Sminshall 			case TYPE_A:
118826048Sminshall 				setascii();
118926048Sminshall 				break;
119026048Sminshall 			case TYPE_I:
119126048Sminshall 				setbinary();
119226048Sminshall 				break;
119326048Sminshall 			case TYPE_E:
119426048Sminshall 				setebcdic();
119526048Sminshall 				break;
119626048Sminshall 			case TYPE_L:
119726048Sminshall 				settenex();
119826048Sminshall 				break;
119926048Sminshall 		}
120026048Sminshall 		pswitch(1);
120126048Sminshall 		return;
120226048Sminshall 	}
120326048Sminshall 	sleep(2);
120426048Sminshall 	pswitch(1);
120526048Sminshall 	secndflag++;
120626448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
120726048Sminshall 		goto abort;
120826048Sminshall 	ptflag++;
120926048Sminshall 	(void) getreply(0);
121026048Sminshall 	pswitch(0);
121126048Sminshall 	(void) getreply(0);
121226048Sminshall 	(void) signal(SIGINT, oldintr);
121326048Sminshall 	switch (oldtype) {
121426048Sminshall 		case 0:
121526048Sminshall 			break;
121626048Sminshall 		case TYPE_A:
121726048Sminshall 			setascii();
121826048Sminshall 			break;
121926048Sminshall 		case TYPE_I:
122026048Sminshall 			setbinary();
122126048Sminshall 			break;
122226048Sminshall 		case TYPE_E:
122326048Sminshall 			setebcdic();
122426048Sminshall 			break;
122526048Sminshall 		case TYPE_L:
122626048Sminshall 			settenex();
122726048Sminshall 			break;
122826048Sminshall 	}
122926048Sminshall 	pswitch(1);
123026048Sminshall 	ptflag = 0;
123126048Sminshall 	printf("local: %s remote: %s\n", local, remote);
123226048Sminshall 	return;
123326048Sminshall abort:
123426048Sminshall 	(void) signal(SIGINT, SIG_IGN);
123526048Sminshall 	ptflag = 0;
123626448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
123726048Sminshall 		pswitch(1);
123826448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
123926048Sminshall 		pswitch(0);
124026048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
124126048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
124226048Sminshall 			pswitch(0);
124326048Sminshall 			switch (oldtype) {
124426048Sminshall 				case 0:
124526048Sminshall 					break;
124626048Sminshall 				case TYPE_A:
124726048Sminshall 					setascii();
124826048Sminshall 					break;
124926048Sminshall 				case TYPE_I:
125026048Sminshall 					setbinary();
125126048Sminshall 					break;
125226048Sminshall 				case TYPE_E:
125326048Sminshall 					setebcdic();
125426048Sminshall 					break;
125526048Sminshall 				case TYPE_L:
125626048Sminshall 					settenex();
125726048Sminshall 					break;
125826048Sminshall 			}
1259*27687Sminshall 			if (cpend) {
126026048Sminshall 				char msg[2];
126126048Sminshall 
126226048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
126326048Sminshall 				(void) fflush(cout);
126426048Sminshall 				*msg = IAC;
126526048Sminshall 				*(msg+1) = DM;
126626448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
126726048Sminshall 					perror("abort");
126826048Sminshall 				fprintf(cout,"ABOR\r\n");
126926048Sminshall 				(void) fflush(cout);
1270*27687Sminshall 				FD_ZERO(&mask);
127126496Sminshall 				FD_SET(fileno(cin), &mask);
1272*27687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
1273*27687Sminshall 					if (nfnd < 0) {
1274*27687Sminshall 						perror("abort");
1275*27687Sminshall 					}
127626448Slepreau 					if (ptabflg)
127726048Sminshall 						code = -1;
127826048Sminshall 					lostpeer();
127926048Sminshall 				}
128026048Sminshall 				(void) getreply(0);
128126048Sminshall 				(void) getreply(0);
128226048Sminshall 			}
128326048Sminshall 		}
128426048Sminshall 		pswitch(1);
128526448Slepreau 		if (ptabflg)
128626048Sminshall 			code = -1;
128726048Sminshall 		(void) signal(SIGINT, oldintr);
128826048Sminshall 		return;
128926048Sminshall 	}
1290*27687Sminshall 	if (cpend) {
129126048Sminshall 		char msg[2];
129226048Sminshall 
129326048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
129426048Sminshall 		(void) fflush(cout);
129526048Sminshall 		*msg = IAC;
129626048Sminshall 		*(msg+1) = DM;
129726448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
129826048Sminshall 			perror("abort");
129926048Sminshall 		fprintf(cout,"ABOR\r\n");
130026048Sminshall 		(void) fflush(cout);
1301*27687Sminshall 		FD_ZERO(&mask);
130226496Sminshall 		FD_SET(fileno(cin), &mask);
1303*27687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
1304*27687Sminshall 			if (nfnd < 0) {
1305*27687Sminshall 				perror("abort");
1306*27687Sminshall 			}
130726448Slepreau 			if (ptabflg)
130826048Sminshall 				code = -1;
130926048Sminshall 			lostpeer();
131026048Sminshall 		}
131126048Sminshall 		(void) getreply(0);
131226048Sminshall 		(void) getreply(0);
131326048Sminshall 	}
131426048Sminshall 	pswitch(!proxy);
131526048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
131626048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
131726048Sminshall 			pswitch(0);
131826048Sminshall 			switch (oldtype) {
131926048Sminshall 				case 0:
132026048Sminshall 					break;
132126048Sminshall 				case TYPE_A:
132226048Sminshall 					setascii();
132326048Sminshall 					break;
132426048Sminshall 				case TYPE_I:
132526048Sminshall 					setbinary();
132626048Sminshall 					break;
132726048Sminshall 				case TYPE_E:
132826048Sminshall 					setebcdic();
132926048Sminshall 					break;
133026048Sminshall 				case TYPE_L:
133126048Sminshall 					settenex();
133226048Sminshall 					break;
133326048Sminshall 			}
1334*27687Sminshall 			if (cpend) {
133526048Sminshall 				char msg[2];
133626048Sminshall 
133726048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
133826048Sminshall 				(void) fflush(cout);
133926048Sminshall 				*msg = IAC;
134026048Sminshall 				*(msg+1) = DM;
134126448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
134226048Sminshall 					perror("abort");
134326048Sminshall 				fprintf(cout,"ABOR\r\n");
134426048Sminshall 				(void) fflush(cout);
1345*27687Sminshall 				FD_ZERO(&mask);
134626496Sminshall 				FD_SET(fileno(cin), &mask);
1347*27687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
1348*27687Sminshall 					if (nfnd < 0) {
1349*27687Sminshall 						perror("abort");
1350*27687Sminshall 					}
135126448Slepreau 					if (ptabflg)
135226048Sminshall 						code = -1;
135326048Sminshall 					lostpeer();
135426048Sminshall 				}
135526048Sminshall 				(void) getreply(0);
135626048Sminshall 				(void) getreply(0);
135726048Sminshall 			}
135826048Sminshall 			pswitch(1);
135926448Slepreau 			if (ptabflg)
136026048Sminshall 				code = -1;
136126048Sminshall 			(void) signal(SIGINT, oldintr);
136226048Sminshall 			return;
136326048Sminshall 		}
136426048Sminshall 	}
1365*27687Sminshall 	if (cpend) {
136626048Sminshall 		char msg[2];
136726048Sminshall 
136826048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
136926048Sminshall 		(void) fflush(cout);
137026048Sminshall 		*msg = IAC;
137126048Sminshall 		*(msg+1) = DM;
137226448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
137326048Sminshall 			perror("abort");
137426048Sminshall 		fprintf(cout,"ABOR\r\n");
137526048Sminshall 		(void) fflush(cout);
1376*27687Sminshall 		FD_ZERO(&mask);
137726496Sminshall 		FD_SET(fileno(cin), &mask);
1378*27687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
1379*27687Sminshall 			if (nfnd < 0) {
1380*27687Sminshall 				perror("abort");
1381*27687Sminshall 			}
138226448Slepreau 			if (ptabflg)
138326048Sminshall 				code = -1;
138426048Sminshall 			lostpeer();
138526048Sminshall 		}
138626048Sminshall 		(void) getreply(0);
138726048Sminshall 		(void) getreply(0);
138826048Sminshall 	}
138926048Sminshall 	pswitch(!proxy);
139026048Sminshall 	if (cpend) {
1391*27687Sminshall 		FD_ZERO(&mask);
139226496Sminshall 		FD_SET(fileno(cin), &mask);
1393*27687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
1394*27687Sminshall 			if (nfnd < 0) {
1395*27687Sminshall 				perror("abort");
1396*27687Sminshall 			}
139726448Slepreau 			if (ptabflg)
139826048Sminshall 				code = -1;
139926048Sminshall 			lostpeer();
140026048Sminshall 		}
140126048Sminshall 		(void) getreply(0);
140226048Sminshall 		(void) getreply(0);
140326048Sminshall 	}
140426448Slepreau 	if (proxy)
140526048Sminshall 		pswitch(0);
140626048Sminshall 	switch (oldtype) {
140726048Sminshall 		case 0:
140826048Sminshall 			break;
140926048Sminshall 		case TYPE_A:
141026048Sminshall 			setascii();
141126048Sminshall 			break;
141226048Sminshall 		case TYPE_I:
141326048Sminshall 			setbinary();
141426048Sminshall 			break;
141526048Sminshall 		case TYPE_E:
141626048Sminshall 			setebcdic();
141726048Sminshall 			break;
141826048Sminshall 		case TYPE_L:
141926048Sminshall 			settenex();
142026048Sminshall 			break;
142126048Sminshall 	}
142226048Sminshall 	pswitch(1);
142326448Slepreau 	if (ptabflg)
142426048Sminshall 		code = -1;
142526048Sminshall 	(void) signal(SIGINT, oldintr);
142626048Sminshall }
142726048Sminshall 
142826048Sminshall reset()
142926048Sminshall {
143026496Sminshall 	struct fd_set mask;
143126496Sminshall 	int nfnd = 1;
143226048Sminshall 
1433*27687Sminshall 	FD_ZERO(&mask);
143426496Sminshall 	while (nfnd) {
143526496Sminshall 		FD_SET(fileno(cin), &mask);
1436*27687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
143726048Sminshall 			perror("reset");
143826048Sminshall 			code = -1;
143926048Sminshall 			lostpeer();
144026048Sminshall 		}
1441*27687Sminshall 		else if (nfnd) {
144226048Sminshall 			(void) getreply(0);
144326496Sminshall 		}
144426048Sminshall 	}
144526048Sminshall }
144626048Sminshall 
144726048Sminshall char *
144826048Sminshall gunique(local)
144926048Sminshall 	char *local;
145026048Sminshall {
145126048Sminshall 	static char new[MAXPATHLEN];
145226048Sminshall 	char *cp = rindex(local, '/');
145326048Sminshall 	int d, count=0;
145426048Sminshall 	char ext = '1';
145526048Sminshall 
145626448Slepreau 	if (cp)
145726048Sminshall 		*cp = '\0';
145826048Sminshall 	d = access(cp ? local : ".", 2);
145926448Slepreau 	if (cp)
146026048Sminshall 		*cp = '/';
146126048Sminshall 	if (d < 0) {
146226048Sminshall 		perror(local);
146326048Sminshall 		return((char *) 0);
146426048Sminshall 	}
146526048Sminshall 	(void) strcpy(new, local);
146626048Sminshall 	cp = new + strlen(new);
146726048Sminshall 	*cp++ = '.';
146826048Sminshall 	while (!d) {
146926048Sminshall 		if (++count == 100) {
147026048Sminshall 			printf("runique: can't find unique file name.\n");
147126048Sminshall 			return((char *) 0);
147226048Sminshall 		}
147326048Sminshall 		*cp++ = ext;
147426048Sminshall 		*cp = '\0';
147526448Slepreau 		if (ext == '9')
147626048Sminshall 			ext = '0';
147726448Slepreau 		else
147826048Sminshall 			ext++;
147926448Slepreau 		if ((d = access(new, 0)) < 0)
148026048Sminshall 			break;
148126448Slepreau 		if (ext != '0')
148226048Sminshall 			cp--;
148326448Slepreau 		else if (*(cp - 2) == '.')
148426048Sminshall 			*(cp - 1) = '1';
148526048Sminshall 		else {
148626048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
148726048Sminshall 			cp--;
148826048Sminshall 		}
148926048Sminshall 	}
149026048Sminshall 	return(new);
149126048Sminshall }
1492