xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 26993)
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*26993Skarels static char sccsid[] = "@(#)ftp.c	5.11 (Berkeley) 04/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     telflag = 0;
3426048Sminshall int	abrtflag = 0;
3526048Sminshall int	ptflag = 0;
3610296Ssam int	connected;
3710296Ssam struct	sockaddr_in myctladdr;
3826496Sminshall uid_t	getuid();
3910296Ssam 
4010296Ssam FILE	*cin, *cout;
4110296Ssam FILE	*dataconn();
4210296Ssam 
4325904Skarels char *
4410296Ssam hookup(host, port)
4510296Ssam 	char *host;
4610296Ssam 	int port;
4710296Ssam {
4825904Skarels 	register struct hostent *hp = 0;
4926048Sminshall 	int s,len,oldverbose;
5025904Skarels 	static char hostnamebuf[80];
5126048Sminshall 	char msg[2];
5210296Ssam 
5310296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5425904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
5525904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
5625904Skarels 		hisctladdr.sin_family = AF_INET;
5725904Skarels 		(void) strcpy(hostnamebuf, host);
5826048Sminshall 	}
5926048Sminshall 	else {
6025100Sbloom 		hp = gethostbyname(host);
6125904Skarels 		if (hp == NULL) {
6225904Skarels 			printf("%s: unknown host\n", host);
6326048Sminshall 			code = -1;
6426048Sminshall 			return((char *) 0);
6525904Skarels 		}
6625904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
6725904Skarels 		bcopy(hp->h_addr_list[0],
6825904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
6925904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
7010296Ssam 	}
7125904Skarels 	hostname = hostnamebuf;
7225904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7310296Ssam 	if (s < 0) {
7410296Ssam 		perror("ftp: socket");
7526048Sminshall 		code = -1;
7610296Ssam 		return (0);
7710296Ssam 	}
7810296Ssam 	hisctladdr.sin_port = port;
7926496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
8025904Skarels 		if (hp && hp->h_addr_list[1]) {
8125904Skarels 			int oerrno = errno;
8225904Skarels 
8325904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
8425904Skarels 				inet_ntoa(hisctladdr.sin_addr));
8525904Skarels 			errno = oerrno;
8626496Sminshall 			perror((char *) 0);
8725904Skarels 			hp->h_addr_list++;
8825904Skarels 			bcopy(hp->h_addr_list[0],
8926048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
9026496Sminshall 			fprintf(stdout, "Trying %s...\n",
9125904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9226813Skarels 			(void) close(s);
9326813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
9426813Skarels 			if (s < 0) {
9526813Skarels 				perror("ftp: socket");
9626813Skarels 				code = -1;
9726813Skarels 				return (0);
9826813Skarels 			}
9925904Skarels 			continue;
10025904Skarels 		}
10110296Ssam 		perror("ftp: connect");
10226048Sminshall 		code = -1;
10310296Ssam 		goto bad;
10410296Ssam 	}
10511627Ssam 	len = sizeof (myctladdr);
10611627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
10711627Ssam 		perror("ftp: getsockname");
10826048Sminshall 		code = -1;
10910296Ssam 		goto bad;
11010296Ssam 	}
11110296Ssam 	cin = fdopen(s, "r");
11210296Ssam 	cout = fdopen(s, "w");
11311219Ssam 	if (cin == NULL || cout == NULL) {
11410296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
11510296Ssam 		if (cin)
11626496Sminshall 			(void) fclose(cin);
11710296Ssam 		if (cout)
11826496Sminshall 			(void) fclose(cout);
11926048Sminshall 		code = -1;
12010296Ssam 		goto bad;
12110296Ssam 	}
12210296Ssam 	if (verbose)
12326067Sminshall 		printf("Connected to %s.\n", hostname);
12426048Sminshall 	if (getreply(0) != 2) { 	/* read startup message from server */
12526048Sminshall 		if (cin)
12626496Sminshall 			(void) fclose(cin);
12726048Sminshall 		if (cout)
12826496Sminshall 			(void) fclose(cout);
12926048Sminshall 		code = -1;
13026048Sminshall 		goto bad;
13126048Sminshall 	}
13226048Sminshall 
13326048Sminshall /* test to see if server command parser understands TELNET SYNC command */
13426048Sminshall 
13526048Sminshall 	fprintf(cout,"%c%c",IAC,NOP);
13626048Sminshall 	(void) fflush(cout);
13726048Sminshall 	*msg = IAC;
13826048Sminshall 	*(msg+1) = DM;
13926448Slepreau 	if (send(s,msg,2,MSG_OOB) != 2)
14026048Sminshall 		perror("sync");
14126048Sminshall 	oldverbose = verbose;
14226448Slepreau 	if (!debug)
14326048Sminshall 		verbose = -1;
14426448Slepreau 	if (command("NOOP") == COMPLETE)
14526048Sminshall 		telflag = 1;
14626448Slepreau 	else
14726048Sminshall 		telflag = 0;
14826048Sminshall 	verbose = oldverbose;
14925904Skarels 	return (hostname);
15010296Ssam bad:
15126496Sminshall 	(void) close(s);
15225904Skarels 	return ((char *)0);
15310296Ssam }
15410296Ssam 
15525904Skarels login(host)
15625904Skarels 	char *host;
15710296Ssam {
15826048Sminshall 	char tmp[80];
15926496Sminshall 	char *user, *pass, *acct, *getlogin(), *mygetpass();
16026048Sminshall 	int n, aflag = 0;
16110296Ssam 
16226048Sminshall 	user = pass = acct = 0;
16326048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16426048Sminshall 		disconnect();
16526048Sminshall 		code = -1;
16626048Sminshall 		return(0);
16726048Sminshall 	}
16826048Sminshall 	if (user == NULL) {
16926048Sminshall 		char *myname = getlogin();
17026048Sminshall 
17126048Sminshall 		if (myname == NULL) {
17226048Sminshall 			struct passwd *pp = getpwuid(getuid());
17326048Sminshall 
17426448Slepreau 			if (pp != NULL)
17526048Sminshall 				myname = pp->pw_name;
17626048Sminshall 		}
17726048Sminshall 		printf("Name (%s:%s): ", host, myname);
17826048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
17926048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18026448Slepreau 		if (*tmp == '\0')
18126048Sminshall 			user = myname;
18226448Slepreau 		else
18326048Sminshall 			user = tmp;
18426048Sminshall 	}
18510296Ssam 	n = command("USER %s", user);
18626048Sminshall 	if (n == CONTINUE) {
18726448Slepreau 		if (pass == NULL)
18826496Sminshall 			pass = mygetpass("Password:");
18910296Ssam 		n = command("PASS %s", pass);
19026048Sminshall 	}
19110296Ssam 	if (n == CONTINUE) {
19226048Sminshall 		aflag++;
19326496Sminshall 		acct = mygetpass("Account:");
19410296Ssam 		n = command("ACCT %s", acct);
19510296Ssam 	}
19610296Ssam 	if (n != COMPLETE) {
19710296Ssam 		fprintf(stderr, "Login failed.\n");
19810296Ssam 		return (0);
19910296Ssam 	}
20026448Slepreau 	if (!aflag && acct != NULL)
20126048Sminshall 		(void) command("ACCT %s", acct);
20226448Slepreau 	if (proxy)
20326048Sminshall 		return(1);
20426048Sminshall 	for (n = 0; n < macnum; ++n) {
20526048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
20626496Sminshall 			(void) strcpy(line, "$init");
20726048Sminshall 			makeargv();
20826048Sminshall 			domacro(margc, margv);
20926048Sminshall 			break;
21026048Sminshall 		}
21126048Sminshall 	}
21210296Ssam 	return (1);
21310296Ssam }
21410296Ssam 
21526048Sminshall cmdabort()
21626048Sminshall {
21726048Sminshall 	extern jmp_buf ptabort;
21826048Sminshall 
21926048Sminshall 	printf("\n");
22026048Sminshall 	(void) fflush(stdout);
22126048Sminshall 	abrtflag++;
22226448Slepreau 	if (ptflag)
22326048Sminshall 		longjmp(ptabort,1);
22426048Sminshall }
22526048Sminshall 
22626496Sminshall /*VARARGS1*/
22710296Ssam command(fmt, args)
22810296Ssam 	char *fmt;
22910296Ssam {
23026048Sminshall 	int r, (*oldintr)(), cmdabort();
23110296Ssam 
23226048Sminshall 	abrtflag = 0;
23310296Ssam 	if (debug) {
23410296Ssam 		printf("---> ");
23510296Ssam 		_doprnt(fmt, &args, stdout);
23610296Ssam 		printf("\n");
23710296Ssam 		(void) fflush(stdout);
23810296Ssam 	}
23911219Ssam 	if (cout == NULL) {
24011219Ssam 		perror ("No control connection for command");
24126048Sminshall 		code = -1;
24211219Ssam 		return (0);
24311219Ssam 	}
24426048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24510296Ssam 	_doprnt(fmt, &args, cout);
24610296Ssam 	fprintf(cout, "\r\n");
24710296Ssam 	(void) fflush(cout);
24826048Sminshall 	cpend = 1;
24926048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25026448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
25126048Sminshall 		(*oldintr)();
25226048Sminshall 	(void) signal(SIGINT, oldintr);
25326048Sminshall 	return(r);
25410296Ssam }
25510296Ssam 
25610296Ssam #include <ctype.h>
25710296Ssam 
25810296Ssam getreply(expecteof)
25910296Ssam 	int expecteof;
26010296Ssam {
26111219Ssam 	register int c, n;
26226048Sminshall 	register int dig;
26326048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
26426048Sminshall 	int pflag = 0;
26526048Sminshall 	char *pt = pasv;
26610296Ssam 
26726048Sminshall 	oldintr = signal(SIGINT,cmdabort);
26810296Ssam 	for (;;) {
26910296Ssam 		dig = n = code = 0;
27010296Ssam 		while ((c = getc(cin)) != '\n') {
27110296Ssam 			dig++;
27210296Ssam 			if (c == EOF) {
27326048Sminshall 				if (expecteof) {
27426048Sminshall 					(void) signal(SIGINT,oldintr);
27526048Sminshall 					code = 221;
27610296Ssam 					return (0);
27726048Sminshall 				}
27810296Ssam 				lostpeer();
27926048Sminshall 				if (verbose) {
28026048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
28126048Sminshall 					(void) fflush(stdout);
28226048Sminshall 					code = 421;
28326048Sminshall 					return(4);
28426048Sminshall 				}
28510296Ssam 			}
28626048Sminshall 			if (c != '\r' && (verbose > 0 ||
28726048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
28826448Slepreau 				if (proxflag &&
28926448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
29026048Sminshall 					printf("%s:",hostname);
29126496Sminshall 				(void) putchar(c);
29226048Sminshall 			}
29310296Ssam 			if (dig < 4 && isdigit(c))
29410296Ssam 				code = code * 10 + (c - '0');
29526448Slepreau 			if (!pflag && code == 227)
29626048Sminshall 				pflag = 1;
29726448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
29826048Sminshall 				pflag = 2;
29926048Sminshall 			if (pflag == 2) {
30026448Slepreau 				if (c != '\r' && c != ')')
30126048Sminshall 					*pt++ = c;
30226048Sminshall 				else {
30326048Sminshall 					*pt = '\0';
30426048Sminshall 					pflag = 3;
30526048Sminshall 				}
30626048Sminshall 			}
30726048Sminshall 			if (dig == 4 && c == '-') {
30826448Slepreau 				if (continuation)
30926048Sminshall 					code = 0;
31010296Ssam 				continuation++;
31126048Sminshall 			}
31210296Ssam 			if (n == 0)
31310296Ssam 				n = c;
31410296Ssam 		}
31526048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
31626496Sminshall 			(void) putchar(c);
31711346Ssam 			(void) fflush (stdout);
31811346Ssam 		}
31910296Ssam 		if (continuation && code != originalcode) {
32010296Ssam 			if (originalcode == 0)
32110296Ssam 				originalcode = code;
32210296Ssam 			continue;
32310296Ssam 		}
32426448Slepreau 		if (n != '1')
32526048Sminshall 			cpend = 0;
32626048Sminshall 		(void) signal(SIGINT,oldintr);
32726448Slepreau 		if (code == 421 || originalcode == 421)
32826048Sminshall 			lostpeer();
32926448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
33026048Sminshall 			(*oldintr)();
33125907Smckusick 		return (n - '0');
33210296Ssam 	}
33310296Ssam }
33410296Ssam 
33526048Sminshall empty(mask, sec)
33626496Sminshall 	struct fd_set mask;
33726048Sminshall 	int sec;
33826048Sminshall {
33926048Sminshall 	struct timeval t;
34026048Sminshall 
34126048Sminshall 	t.tv_sec = (long) sec;
34226048Sminshall 	t.tv_usec = 0;
34326496Sminshall 	if (select(20, &mask, (struct fd_set *) 0, (struct fd_set *) 0, &t) < 0)
34426048Sminshall 		return(-1);
34526496Sminshall 	return (1);
34626048Sminshall }
34726048Sminshall 
34810296Ssam jmp_buf	sendabort;
34910296Ssam 
35010296Ssam abortsend()
35110296Ssam {
35210296Ssam 
35326048Sminshall 	mflag = 0;
35426048Sminshall 	abrtflag = 0;
35526048Sminshall 	printf("\nsend aborted\n");
35626048Sminshall 	(void) fflush(stdout);
35710296Ssam 	longjmp(sendabort, 1);
35810296Ssam }
35910296Ssam 
36010296Ssam sendrequest(cmd, local, remote)
36110296Ssam 	char *cmd, *local, *remote;
36210296Ssam {
36326496Sminshall 	FILE *fin, *dout = 0, *mypopen();
36426496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
36526048Sminshall 	int abortsend();
36611219Ssam 	char buf[BUFSIZ];
36711651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
36811346Ssam 	register int c, d;
36910296Ssam 	struct stat st;
37010296Ssam 	struct timeval start, stop;
37110296Ssam 
37226048Sminshall 	if (proxy) {
37326048Sminshall 		proxtrans(cmd, local, remote);
37426048Sminshall 		return;
37526048Sminshall 	}
37610296Ssam 	closefunc = NULL;
37726048Sminshall 	oldintr = NULL;
37826048Sminshall 	oldintp = NULL;
37926048Sminshall 	if (setjmp(sendabort)) {
38026048Sminshall 		while (cpend) {
38126048Sminshall 			(void) getreply(0);
38226048Sminshall 		}
38326048Sminshall 		if (data >= 0) {
38426048Sminshall 			(void) close(data);
38526048Sminshall 			data = -1;
38626048Sminshall 		}
38726448Slepreau 		if (oldintr)
38826048Sminshall 			(void) signal(SIGINT,oldintr);
38926448Slepreau 		if (oldintp)
39026048Sminshall 			(void) signal(SIGPIPE,oldintp);
39126048Sminshall 		code = -1;
39226048Sminshall 		return;
39326048Sminshall 	}
39410296Ssam 	oldintr = signal(SIGINT, abortsend);
39510296Ssam 	if (strcmp(local, "-") == 0)
39610296Ssam 		fin = stdin;
39710296Ssam 	else if (*local == '|') {
39826048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
39926496Sminshall 		fin = mypopen(local + 1, "r");
40010296Ssam 		if (fin == NULL) {
40126048Sminshall 			perror(local + 1);
40226048Sminshall 			(void) signal(SIGINT, oldintr);
40326048Sminshall 			(void) signal(SIGPIPE, oldintp);
40426048Sminshall 			code = -1;
40526048Sminshall 			return;
40610296Ssam 		}
40726496Sminshall 		closefunc = mypclose;
40810296Ssam 	} else {
40910296Ssam 		fin = fopen(local, "r");
41010296Ssam 		if (fin == NULL) {
41110296Ssam 			perror(local);
41226048Sminshall 			(void) signal(SIGINT, oldintr);
41326048Sminshall 			code = -1;
41426048Sminshall 			return;
41510296Ssam 		}
41610296Ssam 		closefunc = fclose;
41710296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
41810296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
41926496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
42026048Sminshall 			(void) signal(SIGINT, oldintr);
42126048Sminshall 			code = -1;
42226048Sminshall 			return;
42310296Ssam 		}
42410296Ssam 	}
42526048Sminshall 	if (initconn()) {
42626048Sminshall 		(void) signal(SIGINT, oldintr);
42726448Slepreau 		if (oldintp)
42826048Sminshall 			(void) signal(SIGPIPE, oldintp);
42926048Sminshall 		code = -1;
43026048Sminshall 		return;
43126048Sminshall 	}
43226448Slepreau 	if (setjmp(sendabort))
43326048Sminshall 		goto abort;
43410296Ssam 	if (remote) {
43526048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
43626048Sminshall 			(void) signal(SIGINT, oldintr);
43726448Slepreau 			if (oldintp)
43826048Sminshall 				(void) signal(SIGPIPE, oldintp);
43926048Sminshall 			return;
44026048Sminshall 		}
44110296Ssam 	} else
44226048Sminshall 		if (command("%s", cmd) != PRELIM) {
44326048Sminshall 			(void) signal(SIGINT, oldintr);
44426448Slepreau 			if (oldintp)
44526048Sminshall 				(void) signal(SIGPIPE, oldintp);
44626048Sminshall 			return;
44726048Sminshall 		}
44810296Ssam 	dout = dataconn("w");
44926448Slepreau 	if (dout == NULL)
45026048Sminshall 		goto abort;
45126496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
45211219Ssam 	switch (type) {
45311219Ssam 
45411219Ssam 	case TYPE_I:
45511219Ssam 	case TYPE_L:
45611346Ssam 		errno = d = 0;
45711219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
45811346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
45911219Ssam 				break;
46011219Ssam 			bytes += c;
46111651Ssam 			if (hash) {
46226496Sminshall 				(void) putchar('#');
46326496Sminshall 				(void) fflush(stdout);
46411651Ssam 			}
46511219Ssam 		}
46613213Ssam 		if (hash && bytes > 0) {
46726496Sminshall 			(void) putchar('\n');
46826496Sminshall 			(void) fflush(stdout);
46911651Ssam 		}
47011219Ssam 		if (c < 0)
47111219Ssam 			perror(local);
47211346Ssam 		if (d < 0)
47311219Ssam 			perror("netout");
47411219Ssam 		break;
47511219Ssam 
47611219Ssam 	case TYPE_A:
47711219Ssam 		while ((c = getc(fin)) != EOF) {
47811219Ssam 			if (c == '\n') {
47911651Ssam 				while (hash && (bytes >= hashbytes)) {
48026496Sminshall 					(void) putchar('#');
48126496Sminshall 					(void) fflush(stdout);
48211651Ssam 					hashbytes += sizeof (buf);
48311651Ssam 				}
48411219Ssam 				if (ferror(dout))
48511219Ssam 					break;
48626496Sminshall 				(void) putc('\r', dout);
48711219Ssam 				bytes++;
48811219Ssam 			}
48926496Sminshall 			(void) putc(c, dout);
49011219Ssam 			bytes++;
49126048Sminshall 	/*		if (c == '\r') {			  	*/
49226496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
49326048Sminshall 	/*			bytes++;				*/
49426048Sminshall 	/*		}                          			*/
49511219Ssam 		}
49611651Ssam 		if (hash) {
49713213Ssam 			if (bytes < hashbytes)
49826496Sminshall 				(void) putchar('#');
49926496Sminshall 			(void) putchar('\n');
50026496Sminshall 			(void) fflush(stdout);
50111651Ssam 		}
50211219Ssam 		if (ferror(fin))
50311219Ssam 			perror(local);
50411346Ssam 		if (ferror(dout))
50511219Ssam 			perror("netout");
50611219Ssam 		break;
50710296Ssam 	}
50826496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
50910296Ssam 	if (closefunc != NULL)
51026048Sminshall 		(*closefunc)(fin);
51110296Ssam 	(void) fclose(dout);
51226048Sminshall 	(void) getreply(0);
51326048Sminshall 	(void) signal(SIGINT, oldintr);
51410296Ssam 	if (bytes > 0 && verbose)
51526048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
51610296Ssam 	return;
51726048Sminshall abort:
51826496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
51926048Sminshall 	(void) signal(SIGINT, oldintr);
52026448Slepreau 	if (oldintp)
52126048Sminshall 		(void) signal(SIGPIPE, oldintp);
52226048Sminshall 	if (!cpend) {
52326048Sminshall 		code = -1;
52426048Sminshall 		return;
52526048Sminshall 	}
52626048Sminshall 	if (data >= 0) {
52726048Sminshall 		(void) close(data);
52826048Sminshall 		data = -1;
52926048Sminshall 	}
53026448Slepreau 	if (dout)
53126048Sminshall 		(void) fclose(dout);
53226048Sminshall 	(void) getreply(0);
53326048Sminshall 	code = -1;
53410296Ssam 	if (closefunc != NULL && fin != NULL)
53526048Sminshall 		(*closefunc)(fin);
53626048Sminshall 	if (bytes > 0 && verbose)
53726048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53810296Ssam }
53910296Ssam 
54010296Ssam jmp_buf	recvabort;
54110296Ssam 
54210296Ssam abortrecv()
54310296Ssam {
54410296Ssam 
54526048Sminshall 	mflag = 0;
54626048Sminshall 	abrtflag = 0;
54726048Sminshall 	printf("\n");
54826048Sminshall 	(void) fflush(stdout);
54910296Ssam 	longjmp(recvabort, 1);
55010296Ssam }
55110296Ssam 
55211651Ssam recvrequest(cmd, local, remote, mode)
55311651Ssam 	char *cmd, *local, *remote, *mode;
55410296Ssam {
55526496Sminshall 	FILE *fout, *din = 0, *mypopen();
55626496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
55726048Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag;
55826048Sminshall 	char buf[BUFSIZ], *gunique();
55926496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
56026496Sminshall 	struct fd_set mask;
56111346Ssam 	register int c, d;
56210296Ssam 	struct timeval start, stop;
56310296Ssam 
56426048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
56526048Sminshall 		proxtrans(cmd, local, remote);
56626048Sminshall 		return;
56726048Sminshall 	}
56810296Ssam 	closefunc = NULL;
56926048Sminshall 	oldintr = NULL;
57026048Sminshall 	oldintp = NULL;
57126048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
57226048Sminshall 	if (setjmp(recvabort)) {
57326048Sminshall 		while (cpend) {
57426048Sminshall 			(void) getreply(0);
57526048Sminshall 		}
57626048Sminshall 		if (data >= 0) {
57726048Sminshall 			(void) close(data);
57826048Sminshall 			data = -1;
57926048Sminshall 		}
58026448Slepreau 		if (oldintr)
58126048Sminshall 			(void) signal(SIGINT, oldintr);
58226048Sminshall 		code = -1;
58326048Sminshall 		return;
58426048Sminshall 	}
58510296Ssam 	oldintr = signal(SIGINT, abortrecv);
58626048Sminshall 	if (strcmp(local, "-") && *local != '|') {
58710296Ssam 		if (access(local, 2) < 0) {
58826048Sminshall 			char *dir = rindex(local, '/');
58910296Ssam 
59026048Sminshall 			if (errno != ENOENT && errno != EACCES) {
59110296Ssam 				perror(local);
59226048Sminshall 				(void) signal(SIGINT, oldintr);
59326048Sminshall 				code = -1;
59426048Sminshall 				return;
59510296Ssam 			}
59626048Sminshall 			if (dir != NULL)
59726048Sminshall 				*dir = 0;
59826048Sminshall 			d = access(dir ? local : ".", 2);
59926048Sminshall 			if (dir != NULL)
60026048Sminshall 				*dir = '/';
60126048Sminshall 			if (d < 0) {
60226048Sminshall 				perror(local);
60326048Sminshall 				(void) signal(SIGINT, oldintr);
60426048Sminshall 				code = -1;
60526048Sminshall 				return;
60626048Sminshall 			}
60726048Sminshall 			if (!runique && errno == EACCES &&
60826048Sminshall 			    chmod(local,0600) < 0) {
60926048Sminshall 				perror(local);
61026048Sminshall 				(void) signal(SIGINT, oldintr);
61126048Sminshall 				code = -1;
61226048Sminshall 				return;
61326048Sminshall 			}
61426048Sminshall 			if (runique && errno == EACCES &&
61526048Sminshall 			   (local = gunique(local)) == NULL) {
61626048Sminshall 				(void) signal(SIGINT, oldintr);
61726048Sminshall 				code = -1;
61826048Sminshall 				return;
61926048Sminshall 			}
62010296Ssam 		}
62126048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
62226048Sminshall 			(void) signal(SIGINT, oldintr);
62326048Sminshall 			code = -1;
62426048Sminshall 			return;
62526048Sminshall 		}
62626048Sminshall 	}
62726048Sminshall 	if (initconn()) {
62826048Sminshall 		(void) signal(SIGINT, oldintr);
62926048Sminshall 		code = -1;
63026048Sminshall 		return;
63126048Sminshall 	}
63226448Slepreau 	if (setjmp(recvabort))
63326048Sminshall 		goto abort;
63426048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
63526048Sminshall 		oldtype = type;
63626048Sminshall 		oldverbose = verbose;
63726448Slepreau 		if (!debug)
63826048Sminshall 			verbose = 0;
63926048Sminshall 		setascii();
64026048Sminshall 		verbose = oldverbose;
64126048Sminshall 	}
64210296Ssam 	if (remote) {
64326048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
64426048Sminshall 			(void) signal(SIGINT, oldintr);
64526048Sminshall 			if (oldtype) {
64626448Slepreau 				if (!debug)
64726048Sminshall 					verbose = 0;
64826048Sminshall 				switch (oldtype) {
64926048Sminshall 					case TYPE_I:
65026048Sminshall 						setbinary();
65126048Sminshall 						break;
65226048Sminshall 					case TYPE_E:
65326048Sminshall 						setebcdic();
65426048Sminshall 						break;
65526048Sminshall 					case TYPE_L:
65626048Sminshall 						settenex();
65726048Sminshall 						break;
65826048Sminshall 				}
65926048Sminshall 				verbose = oldverbose;
66026048Sminshall 			}
66126048Sminshall 			return;
66226048Sminshall 		}
66326048Sminshall 	} else {
66426048Sminshall 		if (command("%s", cmd) != PRELIM) {
66526048Sminshall 			(void) signal(SIGINT, oldintr);
66626048Sminshall 			if (oldtype) {
66726448Slepreau 				if (!debug)
66826048Sminshall 					verbose = 0;
66926048Sminshall 				switch (oldtype) {
67026048Sminshall 					case TYPE_I:
67126048Sminshall 						setbinary();
67226048Sminshall 						break;
67326048Sminshall 					case TYPE_E:
67426048Sminshall 						setebcdic();
67526048Sminshall 						break;
67626048Sminshall 					case TYPE_L:
67726048Sminshall 						settenex();
67826048Sminshall 						break;
67926048Sminshall 				}
68026048Sminshall 				verbose = oldverbose;
68126048Sminshall 			}
68226048Sminshall 			return;
68326048Sminshall 		}
68426048Sminshall 	}
68526048Sminshall 	din = dataconn("r");
68626048Sminshall 	if (din == NULL)
68726048Sminshall 		goto abort;
68826448Slepreau 	if (strcmp(local, "-") == 0)
68910296Ssam 		fout = stdout;
69010296Ssam 	else if (*local == '|') {
69126048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
69226496Sminshall 		fout = mypopen(local + 1, "w");
69326048Sminshall 		if (fout == NULL) {
69426048Sminshall 			perror(local+1);
69526048Sminshall 			goto abort;
69626048Sminshall 		}
69726496Sminshall 		closefunc = mypclose;
69826048Sminshall 	}
69926048Sminshall 	else {
70011651Ssam 		fout = fopen(local, mode);
70126048Sminshall 		if (fout == NULL) {
70226048Sminshall 			perror(local);
70326048Sminshall 			goto abort;
70426048Sminshall 		}
70510296Ssam 		closefunc = fclose;
70610296Ssam 	}
70726496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
70811219Ssam 	switch (type) {
70911219Ssam 
71011219Ssam 	case TYPE_I:
71111219Ssam 	case TYPE_L:
71211346Ssam 		errno = d = 0;
71311219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
71411346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
71511219Ssam 				break;
71611219Ssam 			bytes += c;
71711651Ssam 			if (hash) {
71826496Sminshall 				(void) putchar('#');
71926496Sminshall 				(void) fflush(stdout);
72011651Ssam 			}
72111219Ssam 		}
72213213Ssam 		if (hash && bytes > 0) {
72326496Sminshall 			(void) putchar('\n');
72426496Sminshall 			(void) fflush(stdout);
72511651Ssam 		}
72611219Ssam 		if (c < 0)
72711219Ssam 			perror("netin");
72811346Ssam 		if (d < 0)
72910296Ssam 			perror(local);
73011219Ssam 		break;
73111219Ssam 
73211219Ssam 	case TYPE_A:
73311219Ssam 		while ((c = getc(din)) != EOF) {
73411219Ssam 			if (c == '\r') {
73511651Ssam 				while (hash && (bytes >= hashbytes)) {
73626496Sminshall 					(void) putchar('#');
73726496Sminshall 					(void) fflush(stdout);
73811651Ssam 					hashbytes += sizeof (buf);
73911651Ssam 				}
74010296Ssam 				bytes++;
74126048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
74211219Ssam 					if (ferror (fout))
74311219Ssam 						break;
74426496Sminshall 					(void) putc ('\r', fout);
74511219Ssam 				}
74626048Sminshall 				/*if (c == '\0') {
74711219Ssam 					bytes++;
74811219Ssam 					continue;
74926048Sminshall 				}*/
75011219Ssam 			}
75126496Sminshall 			(void) putc (c, fout);
75211219Ssam 			bytes++;
75310296Ssam 		}
75411651Ssam 		if (hash) {
75513213Ssam 			if (bytes < hashbytes)
75626496Sminshall 				(void) putchar('#');
75726496Sminshall 			(void) putchar('\n');
75826496Sminshall 			(void) fflush(stdout);
75911651Ssam 		}
76011219Ssam 		if (ferror (din))
76111219Ssam 			perror ("netin");
76211219Ssam 		if (ferror (fout))
76311219Ssam 			perror (local);
76411219Ssam 		break;
76510296Ssam 	}
76626448Slepreau 	if (closefunc != NULL)
76726048Sminshall 		(*closefunc)(fout);
76826496Sminshall 	(void) signal(SIGINT, oldintr);
76926448Slepreau 	if (oldintp)
77026048Sminshall 		(void) signal(SIGPIPE, oldintp);
77126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
77210296Ssam 	(void) fclose(din);
77326048Sminshall 	(void) getreply(0);
77426048Sminshall 	if (bytes > 0 && verbose)
77526048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
77626048Sminshall 	if (oldtype) {
77726448Slepreau 		if (!debug)
77826048Sminshall 			verbose = 0;
77926048Sminshall 		switch (oldtype) {
78026048Sminshall 			case TYPE_I:
78126048Sminshall 				setbinary();
78226048Sminshall 				break;
78326048Sminshall 			case TYPE_E:
78426048Sminshall 				setebcdic();
78526048Sminshall 				break;
78626048Sminshall 			case TYPE_L:
78726048Sminshall 				settenex();
78826048Sminshall 				break;
78926048Sminshall 		}
79026048Sminshall 		verbose = oldverbose;
79126048Sminshall 	}
79226048Sminshall 	return;
79326048Sminshall abort:
79426048Sminshall 
79526048Sminshall /* if server command parser understands TELNET commands, abort using */
79626048Sminshall /* recommended IP,SYNC sequence                                      */
79726048Sminshall 
79826496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
79926448Slepreau 	if (oldintp)
80026048Sminshall 		(void) signal(SIGPIPE, oldintr);
80126048Sminshall 	(void) signal(SIGINT,SIG_IGN);
80226048Sminshall 	if (oldtype) {
80326448Slepreau 		if (!debug)
80426048Sminshall 			verbose = 0;
80526048Sminshall 		switch (oldtype) {
80626048Sminshall 			case TYPE_I:
80726048Sminshall 				setbinary();
80826048Sminshall 				break;
80926048Sminshall 			case TYPE_E:
81026048Sminshall 				setebcdic();
81126048Sminshall 				break;
81226048Sminshall 			case TYPE_L:
81326048Sminshall 				settenex();
81426048Sminshall 				break;
81526048Sminshall 		}
81626048Sminshall 		verbose = oldverbose;
81726048Sminshall 	}
81826048Sminshall 	if (!cpend) {
81926048Sminshall 		code = -1;
82026048Sminshall 		(void) signal(SIGINT,oldintr);
82126048Sminshall 		return;
82226048Sminshall 	}
82326048Sminshall 	if (telflag) {
82426048Sminshall 		char msg[2];
82526048Sminshall 
82626048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
82726048Sminshall 		(void) fflush(cout);
82826048Sminshall 		*msg = IAC;
82926048Sminshall 		*(msg+1) = DM;
83026448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
83126048Sminshall 			perror("abort");
83226048Sminshall 	}
83326048Sminshall 	fprintf(cout,"ABOR\r\n");
83426048Sminshall 	(void) fflush(cout);
83526496Sminshall 	FD_ZERO((char *) &mask);
83626496Sminshall 	FD_SET(fileno(cin), &mask);
83726496Sminshall 	if (din) {
83826496Sminshall 		FD_SET(fileno(din), &mask);
83926496Sminshall 	}
84026496Sminshall 	if (empty(mask,10) < 0) {
84126048Sminshall 		perror("abort");
84226048Sminshall 		code = -1;
84326048Sminshall 		lostpeer();
84426048Sminshall 	}
84526496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
84626448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
84726448Slepreau 			;
84826496Sminshall 	}
84926048Sminshall 	if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */
85026048Sminshall 		if (data >= 0) {
85126496Sminshall 			(void) close(data);
85226048Sminshall 			data = -1;
85326048Sminshall 		}
85425907Smckusick 		(void) getreply(0);
85525907Smckusick 	}
85626048Sminshall 	(void) getreply(0);
85726048Sminshall 	code = -1;
85826048Sminshall 	if (data >= 0) {
85926048Sminshall 		(void) close(data);
86026048Sminshall 		data = -1;
86126048Sminshall 	}
86226448Slepreau 	if (closefunc != NULL && fout != NULL)
86326048Sminshall 		(*closefunc)(fout);
86426448Slepreau 	if (din)
86526048Sminshall 		(void) fclose(din);
86610296Ssam 	if (bytes > 0 && verbose)
86726048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
86826048Sminshall 	(void) signal(SIGINT,oldintr);
86910296Ssam }
87010296Ssam 
87110296Ssam /*
87210296Ssam  * Need to start a listen on the data channel
87310296Ssam  * before we send the command, otherwise the
87410296Ssam  * server's connect may fail.
87510296Ssam  */
87611651Ssam static int sendport = -1;
87711651Ssam 
87810296Ssam initconn()
87910296Ssam {
88010296Ssam 	register char *p, *a;
88126048Sminshall 	int result, len, tmpno = 0;
882*26993Skarels 	int on = 1;
88310296Ssam 
88411651Ssam noport:
88510296Ssam 	data_addr = myctladdr;
88611651Ssam 	if (sendport)
88711651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
88811651Ssam 	if (data != -1)
88911651Ssam 		(void) close (data);
89018287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
89110296Ssam 	if (data < 0) {
89210296Ssam 		perror("ftp: socket");
89326448Slepreau 		if (tmpno)
89426048Sminshall 			sendport = 1;
89510296Ssam 		return (1);
89610296Ssam 	}
89712397Ssam 	if (!sendport)
89817450Slepreau 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
89926048Sminshall 			perror("ftp: setsockopt (resuse address)");
90012397Ssam 			goto bad;
90112397Ssam 		}
90226496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
90310296Ssam 		perror("ftp: bind");
90410296Ssam 		goto bad;
90510296Ssam 	}
90610296Ssam 	if (options & SO_DEBUG &&
90717450Slepreau 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
90810296Ssam 		perror("ftp: setsockopt (ignored)");
90911627Ssam 	len = sizeof (data_addr);
91011627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
91111627Ssam 		perror("ftp: getsockname");
91210296Ssam 		goto bad;
91310296Ssam 	}
91426448Slepreau 	if (listen(data, 1) < 0)
91510296Ssam 		perror("ftp: listen");
91611651Ssam 	if (sendport) {
91711651Ssam 		a = (char *)&data_addr.sin_addr;
91811651Ssam 		p = (char *)&data_addr.sin_port;
91910296Ssam #define	UC(b)	(((int)b)&0xff)
92011651Ssam 		result =
92111651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
92211651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
92311651Ssam 		      UC(p[0]), UC(p[1]));
92411651Ssam 		if (result == ERROR && sendport == -1) {
92511651Ssam 			sendport = 0;
92626048Sminshall 			tmpno = 1;
92711651Ssam 			goto noport;
92811651Ssam 		}
92911651Ssam 		return (result != COMPLETE);
93011651Ssam 	}
93126448Slepreau 	if (tmpno)
93226048Sminshall 		sendport = 1;
93311651Ssam 	return (0);
93410296Ssam bad:
93510296Ssam 	(void) close(data), data = -1;
93626448Slepreau 	if (tmpno)
93726048Sminshall 		sendport = 1;
93810296Ssam 	return (1);
93910296Ssam }
94010296Ssam 
94110296Ssam FILE *
94210296Ssam dataconn(mode)
94310296Ssam 	char *mode;
94410296Ssam {
94510296Ssam 	struct sockaddr_in from;
94610296Ssam 	int s, fromlen = sizeof (from);
94710296Ssam 
94826496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
94910296Ssam 	if (s < 0) {
95010296Ssam 		perror("ftp: accept");
95110296Ssam 		(void) close(data), data = -1;
95210296Ssam 		return (NULL);
95310296Ssam 	}
95410296Ssam 	(void) close(data);
95510296Ssam 	data = s;
95610296Ssam 	return (fdopen(data, mode));
95710296Ssam }
95810296Ssam 
95926048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
96026048Sminshall 	char *direction, *local, *remote;
96111651Ssam 	long bytes;
96210296Ssam 	struct timeval *t0, *t1;
96310296Ssam {
96410296Ssam 	struct timeval td;
96516437Sleres 	float s, bs;
96610296Ssam 
96710296Ssam 	tvsub(&td, t1, t0);
96816437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
96910296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
97016437Sleres 	bs = bytes / nz(s);
97126448Slepreau 	if (local && *local != '-')
97226048Sminshall 		printf("local: %s ", local);
97326448Slepreau 	if (remote)
97426048Sminshall 		printf("remote: %s\n", remote);
97516437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
97616437Sleres 		bytes, direction, s, bs / 1024.);
97710296Ssam }
97810296Ssam 
97926496Sminshall /*tvadd(tsum, t0)
98010296Ssam 	struct timeval *tsum, *t0;
98110296Ssam {
98210296Ssam 
98310296Ssam 	tsum->tv_sec += t0->tv_sec;
98410296Ssam 	tsum->tv_usec += t0->tv_usec;
98510296Ssam 	if (tsum->tv_usec > 1000000)
98610296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
98726496Sminshall } */
98810296Ssam 
98910296Ssam tvsub(tdiff, t1, t0)
99010296Ssam 	struct timeval *tdiff, *t1, *t0;
99110296Ssam {
99210296Ssam 
99310296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
99410296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
99510296Ssam 	if (tdiff->tv_usec < 0)
99610296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
99710296Ssam }
99826048Sminshall 
99926048Sminshall psabort()
100026048Sminshall {
100126048Sminshall 	extern int abrtflag;
100226048Sminshall 
100326048Sminshall 	abrtflag++;
100426048Sminshall }
100526048Sminshall 
100626048Sminshall pswitch(flag)
100726048Sminshall 	int flag;
100826048Sminshall {
100926048Sminshall 	extern int proxy, abrtflag;
101026048Sminshall 	int (*oldintr)();
101126048Sminshall 	static struct comvars {
101226048Sminshall 		int connect;
101326048Sminshall 		char name[32];
101426048Sminshall 		struct sockaddr_in mctl;
101526048Sminshall 		struct sockaddr_in hctl;
101626048Sminshall 		FILE *in;
101726048Sminshall 		FILE *out;
101826048Sminshall 		int tflag;
101926048Sminshall 		int tpe;
102026048Sminshall 		int cpnd;
102126048Sminshall 		int sunqe;
102226048Sminshall 		int runqe;
102326048Sminshall 		int mcse;
102426048Sminshall 		int ntflg;
102526048Sminshall 		char nti[17];
102626048Sminshall 		char nto[17];
102726048Sminshall 		int mapflg;
102826048Sminshall 		char mi[MAXPATHLEN];
102926048Sminshall 		char mo[MAXPATHLEN];
103026048Sminshall 		} proxstruct, tmpstruct;
103126048Sminshall 	struct comvars *ip, *op;
103226048Sminshall 
103326048Sminshall 	abrtflag = 0;
103426048Sminshall 	oldintr = signal(SIGINT, psabort);
103526048Sminshall 	if (flag) {
103626448Slepreau 		if (proxy)
103726048Sminshall 			return;
103826048Sminshall 		ip = &tmpstruct;
103926048Sminshall 		op = &proxstruct;
104026048Sminshall 		proxy++;
104126048Sminshall 	}
104226048Sminshall 	else {
104326448Slepreau 		if (!proxy)
104426048Sminshall 			return;
104526048Sminshall 		ip = &proxstruct;
104626048Sminshall 		op = &tmpstruct;
104726048Sminshall 		proxy = 0;
104826048Sminshall 	}
104926048Sminshall 	ip->connect = connected;
105026048Sminshall 	connected = op->connect;
105126496Sminshall 	(void) strncpy(ip->name, hostname, 31);
105226048Sminshall 	(ip->name)[strlen(ip->name)] = '\0';
105326048Sminshall 	hostname = op->name;
105426048Sminshall 	ip->hctl = hisctladdr;
105526048Sminshall 	hisctladdr = op->hctl;
105626048Sminshall 	ip->mctl = myctladdr;
105726048Sminshall 	myctladdr = op->mctl;
105826048Sminshall 	ip->in = cin;
105926048Sminshall 	cin = op->in;
106026048Sminshall 	ip->out = cout;
106126048Sminshall 	cout = op->out;
106226048Sminshall 	ip->tflag = telflag;
106326048Sminshall 	telflag = op->tflag;
106426048Sminshall 	ip->tpe = type;
106526048Sminshall 	type = op->tpe;
106626448Slepreau 	if (!type)
106726048Sminshall 		type = 1;
106826048Sminshall 	ip->cpnd = cpend;
106926048Sminshall 	cpend = op->cpnd;
107026048Sminshall 	ip->sunqe = sunique;
107126048Sminshall 	sunique = op->sunqe;
107226048Sminshall 	ip->runqe = runique;
107326048Sminshall 	runique = op->runqe;
107426048Sminshall 	ip->mcse = mcase;
107526048Sminshall 	mcase = op->mcse;
107626048Sminshall 	ip->ntflg = ntflag;
107726048Sminshall 	ntflag = op->ntflg;
107826496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
107926048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
108026496Sminshall 	(void) strcpy(ntin, op->nti);
108126496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
108226048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
108326496Sminshall 	(void) strcpy(ntout, op->nto);
108426048Sminshall 	ip->mapflg = mapflag;
108526048Sminshall 	mapflag = op->mapflg;
108626496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
108726048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
108826496Sminshall 	(void) strcpy(mapin, op->mi);
108926496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
109026048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
109126496Sminshall 	(void) strcpy(mapout, op->mo);
109226048Sminshall 	(void) signal(SIGINT, oldintr);
109326048Sminshall 	if (abrtflag) {
109426048Sminshall 		abrtflag = 0;
109526048Sminshall 		(*oldintr)();
109626448Slepreau 	}
109726048Sminshall }
109826048Sminshall 
109926048Sminshall jmp_buf ptabort;
110026048Sminshall int ptabflg;
110126048Sminshall 
110226048Sminshall abortpt()
110326048Sminshall {
110426048Sminshall 	printf("\n");
110526496Sminshall 	(void) fflush(stdout);
110626048Sminshall 	ptabflg++;
110726048Sminshall 	mflag = 0;
110826048Sminshall 	abrtflag = 0;
110926048Sminshall 	longjmp(ptabort, 1);
111026048Sminshall }
111126048Sminshall 
111226048Sminshall proxtrans(cmd, local, remote)
111326048Sminshall 	char *cmd, *local, *remote;
111426048Sminshall {
111526048Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0;
111626048Sminshall 	extern jmp_buf ptabort;
111726048Sminshall 	char *cmd2;
111826496Sminshall 	struct fd_set mask;
111926048Sminshall 
112026448Slepreau 	if (strcmp(cmd, "RETR"))
112126048Sminshall 		cmd2 = "RETR";
112226448Slepreau 	else
112326048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
112426048Sminshall 	if (command("PASV") != COMPLETE) {
112526048Sminshall 		printf("proxy server does not support third part transfers.\n");
112626048Sminshall 		return;
112726048Sminshall 	}
112826048Sminshall 	tmptype = type;
112926048Sminshall 	pswitch(0);
113026048Sminshall 	if (!connected) {
113126048Sminshall 		printf("No primary connection\n");
113226048Sminshall 		pswitch(1);
113326048Sminshall 		code = -1;
113426048Sminshall 		return;
113526048Sminshall 	}
113626048Sminshall 	if (type != tmptype) {
113726048Sminshall 		oldtype = type;
113826048Sminshall 		switch (tmptype) {
113926048Sminshall 			case TYPE_A:
114026048Sminshall 				setascii();
114126048Sminshall 				break;
114226048Sminshall 			case TYPE_I:
114326048Sminshall 				setbinary();
114426048Sminshall 				break;
114526048Sminshall 			case TYPE_E:
114626048Sminshall 				setebcdic();
114726048Sminshall 				break;
114826048Sminshall 			case TYPE_L:
114926048Sminshall 				settenex();
115026048Sminshall 				break;
115126048Sminshall 		}
115226048Sminshall 	}
115326048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
115426048Sminshall 		switch (oldtype) {
115526048Sminshall 			case 0:
115626048Sminshall 				break;
115726048Sminshall 			case TYPE_A:
115826048Sminshall 				setascii();
115926048Sminshall 				break;
116026048Sminshall 			case TYPE_I:
116126048Sminshall 				setbinary();
116226048Sminshall 				break;
116326048Sminshall 			case TYPE_E:
116426048Sminshall 				setebcdic();
116526048Sminshall 				break;
116626048Sminshall 			case TYPE_L:
116726048Sminshall 				settenex();
116826048Sminshall 				break;
116926048Sminshall 		}
117026048Sminshall 		pswitch(1);
117126048Sminshall 		return;
117226048Sminshall 	}
117326448Slepreau 	if (setjmp(ptabort))
117426048Sminshall 		goto abort;
117526048Sminshall 	oldintr = signal(SIGINT, abortpt);
117626048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
117726048Sminshall 		(void) signal(SIGINT, oldintr);
117826048Sminshall 		switch (oldtype) {
117926048Sminshall 			case 0:
118026048Sminshall 				break;
118126048Sminshall 			case TYPE_A:
118226048Sminshall 				setascii();
118326048Sminshall 				break;
118426048Sminshall 			case TYPE_I:
118526048Sminshall 				setbinary();
118626048Sminshall 				break;
118726048Sminshall 			case TYPE_E:
118826048Sminshall 				setebcdic();
118926048Sminshall 				break;
119026048Sminshall 			case TYPE_L:
119126048Sminshall 				settenex();
119226048Sminshall 				break;
119326048Sminshall 		}
119426048Sminshall 		pswitch(1);
119526048Sminshall 		return;
119626048Sminshall 	}
119726048Sminshall 	sleep(2);
119826048Sminshall 	pswitch(1);
119926048Sminshall 	secndflag++;
120026448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
120126048Sminshall 		goto abort;
120226048Sminshall 	ptflag++;
120326048Sminshall 	(void) getreply(0);
120426048Sminshall 	pswitch(0);
120526048Sminshall 	(void) getreply(0);
120626048Sminshall 	(void) signal(SIGINT, oldintr);
120726048Sminshall 	switch (oldtype) {
120826048Sminshall 		case 0:
120926048Sminshall 			break;
121026048Sminshall 		case TYPE_A:
121126048Sminshall 			setascii();
121226048Sminshall 			break;
121326048Sminshall 		case TYPE_I:
121426048Sminshall 			setbinary();
121526048Sminshall 			break;
121626048Sminshall 		case TYPE_E:
121726048Sminshall 			setebcdic();
121826048Sminshall 			break;
121926048Sminshall 		case TYPE_L:
122026048Sminshall 			settenex();
122126048Sminshall 			break;
122226048Sminshall 	}
122326048Sminshall 	pswitch(1);
122426048Sminshall 	ptflag = 0;
122526048Sminshall 	printf("local: %s remote: %s\n", local, remote);
122626048Sminshall 	return;
122726048Sminshall abort:
122826048Sminshall 	(void) signal(SIGINT, SIG_IGN);
122926048Sminshall 	ptflag = 0;
123026448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
123126048Sminshall 		pswitch(1);
123226448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
123326048Sminshall 		pswitch(0);
123426048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
123526048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
123626048Sminshall 			pswitch(0);
123726048Sminshall 			switch (oldtype) {
123826048Sminshall 				case 0:
123926048Sminshall 					break;
124026048Sminshall 				case TYPE_A:
124126048Sminshall 					setascii();
124226048Sminshall 					break;
124326048Sminshall 				case TYPE_I:
124426048Sminshall 					setbinary();
124526048Sminshall 					break;
124626048Sminshall 				case TYPE_E:
124726048Sminshall 					setebcdic();
124826048Sminshall 					break;
124926048Sminshall 				case TYPE_L:
125026048Sminshall 					settenex();
125126048Sminshall 					break;
125226048Sminshall 			}
125326048Sminshall 			if (cpend && telflag) {
125426048Sminshall 				char msg[2];
125526048Sminshall 
125626048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
125726048Sminshall 				(void) fflush(cout);
125826048Sminshall 				*msg = IAC;
125926048Sminshall 				*(msg+1) = DM;
126026448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
126126048Sminshall 					perror("abort");
126226048Sminshall 			}
126326048Sminshall 			if (cpend) {
126426048Sminshall 				fprintf(cout,"ABOR\r\n");
126526048Sminshall 				(void) fflush(cout);
126626496Sminshall 				FD_ZERO((char *) &mask);
126726496Sminshall 				FD_SET(fileno(cin), &mask);
126826496Sminshall 				if (empty(mask,10) < 0) {
126926048Sminshall 					perror("abort");
127026448Slepreau 					if (ptabflg)
127126048Sminshall 						code = -1;
127226048Sminshall 					lostpeer();
127326048Sminshall 				}
127426048Sminshall 				(void) getreply(0);
127526048Sminshall 				(void) getreply(0);
127626048Sminshall 			}
127726048Sminshall 		}
127826048Sminshall 		pswitch(1);
127926448Slepreau 		if (ptabflg)
128026048Sminshall 			code = -1;
128126048Sminshall 		(void) signal(SIGINT, oldintr);
128226048Sminshall 		return;
128326048Sminshall 	}
128426048Sminshall 	if (cpend && telflag) {
128526048Sminshall 		char msg[2];
128626048Sminshall 
128726048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
128826048Sminshall 		(void) fflush(cout);
128926048Sminshall 		*msg = IAC;
129026048Sminshall 		*(msg+1) = DM;
129126448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
129226048Sminshall 			perror("abort");
129326048Sminshall 	}
129426048Sminshall 	if (cpend) {
129526048Sminshall 		fprintf(cout,"ABOR\r\n");
129626048Sminshall 		(void) fflush(cout);
129726496Sminshall 		FD_ZERO((char *) &mask);
129826496Sminshall 		FD_SET(fileno(cin), &mask);
129926496Sminshall 		if ((empty(mask,10)) < 0) {
130026048Sminshall 			perror("abort");
130126448Slepreau 			if (ptabflg)
130226048Sminshall 				code = -1;
130326048Sminshall 			lostpeer();
130426048Sminshall 		}
130526048Sminshall 		(void) getreply(0);
130626048Sminshall 		(void) getreply(0);
130726048Sminshall 	}
130826048Sminshall 	pswitch(!proxy);
130926048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
131026048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
131126048Sminshall 			pswitch(0);
131226048Sminshall 			switch (oldtype) {
131326048Sminshall 				case 0:
131426048Sminshall 					break;
131526048Sminshall 				case TYPE_A:
131626048Sminshall 					setascii();
131726048Sminshall 					break;
131826048Sminshall 				case TYPE_I:
131926048Sminshall 					setbinary();
132026048Sminshall 					break;
132126048Sminshall 				case TYPE_E:
132226048Sminshall 					setebcdic();
132326048Sminshall 					break;
132426048Sminshall 				case TYPE_L:
132526048Sminshall 					settenex();
132626048Sminshall 					break;
132726048Sminshall 			}
132826048Sminshall 			if (cpend && telflag) {
132926048Sminshall 				char msg[2];
133026048Sminshall 
133126048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
133226048Sminshall 				(void) fflush(cout);
133326048Sminshall 				*msg = IAC;
133426048Sminshall 				*(msg+1) = DM;
133526448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
133626048Sminshall 					perror("abort");
133726048Sminshall 			}
133826048Sminshall 			if (cpend) {
133926048Sminshall 				fprintf(cout,"ABOR\r\n");
134026048Sminshall 				(void) fflush(cout);
134126496Sminshall 				FD_ZERO((char *) &mask);
134226496Sminshall 				FD_SET(fileno(cin), &mask);
134326496Sminshall 				if (empty(mask,10) < 0) {
134426048Sminshall 					perror("abort");
134526448Slepreau 					if (ptabflg)
134626048Sminshall 						code = -1;
134726048Sminshall 					lostpeer();
134826048Sminshall 				}
134926048Sminshall 				(void) getreply(0);
135026048Sminshall 				(void) getreply(0);
135126048Sminshall 			}
135226048Sminshall 			pswitch(1);
135326448Slepreau 			if (ptabflg)
135426048Sminshall 				code = -1;
135526048Sminshall 			(void) signal(SIGINT, oldintr);
135626048Sminshall 			return;
135726048Sminshall 		}
135826048Sminshall 	}
135926048Sminshall 	if (cpend && telflag) {
136026048Sminshall 		char msg[2];
136126048Sminshall 
136226048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
136326048Sminshall 		(void) fflush(cout);
136426048Sminshall 		*msg = IAC;
136526048Sminshall 		*(msg+1) = DM;
136626448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
136726048Sminshall 			perror("abort");
136826048Sminshall 	}
136926048Sminshall 	if (cpend) {
137026048Sminshall 		fprintf(cout,"ABOR\r\n");
137126048Sminshall 		(void) fflush(cout);
137226496Sminshall 		FD_ZERO((char *) &mask);
137326496Sminshall 		FD_SET(fileno(cin), &mask);
137426496Sminshall 		if (empty(mask,10) < 0) {
137526048Sminshall 			perror("abort");
137626448Slepreau 			if (ptabflg)
137726048Sminshall 				code = -1;
137826048Sminshall 			lostpeer();
137926048Sminshall 		}
138026048Sminshall 		(void) getreply(0);
138126048Sminshall 		(void) getreply(0);
138226048Sminshall 	}
138326048Sminshall 	pswitch(!proxy);
138426048Sminshall 	if (cpend) {
138526496Sminshall 		FD_ZERO((char *) &mask);
138626496Sminshall 		FD_SET(fileno(cin), &mask);
138726496Sminshall 		if (empty(mask,10) < 0) {
138826048Sminshall 			perror("abort");
138926448Slepreau 			if (ptabflg)
139026048Sminshall 				code = -1;
139126048Sminshall 			lostpeer();
139226048Sminshall 		}
139326048Sminshall 		(void) getreply(0);
139426048Sminshall 		(void) getreply(0);
139526048Sminshall 	}
139626448Slepreau 	if (proxy)
139726048Sminshall 		pswitch(0);
139826048Sminshall 	switch (oldtype) {
139926048Sminshall 		case 0:
140026048Sminshall 			break;
140126048Sminshall 		case TYPE_A:
140226048Sminshall 			setascii();
140326048Sminshall 			break;
140426048Sminshall 		case TYPE_I:
140526048Sminshall 			setbinary();
140626048Sminshall 			break;
140726048Sminshall 		case TYPE_E:
140826048Sminshall 			setebcdic();
140926048Sminshall 			break;
141026048Sminshall 		case TYPE_L:
141126048Sminshall 			settenex();
141226048Sminshall 			break;
141326048Sminshall 	}
141426048Sminshall 	pswitch(1);
141526448Slepreau 	if (ptabflg)
141626048Sminshall 		code = -1;
141726048Sminshall 	(void) signal(SIGINT, oldintr);
141826048Sminshall }
141926048Sminshall 
142026048Sminshall reset()
142126048Sminshall {
142226496Sminshall 	struct fd_set mask;
142326496Sminshall 	int nfnd = 1;
142426048Sminshall 
142526496Sminshall 	FD_ZERO((char *) &mask);
142626496Sminshall 	while (nfnd) {
142726496Sminshall 		FD_SET(fileno(cin), &mask);
142826496Sminshall 		if ((nfnd = empty(mask,0)) < 0) {
142926048Sminshall 			perror("reset");
143026048Sminshall 			code = -1;
143126048Sminshall 			lostpeer();
143226048Sminshall 		}
143326496Sminshall 		else {
143426048Sminshall 			(void) getreply(0);
143526496Sminshall 		}
143626048Sminshall 	}
143726048Sminshall }
143826048Sminshall 
143926048Sminshall char *
144026048Sminshall gunique(local)
144126048Sminshall 	char *local;
144226048Sminshall {
144326048Sminshall 	static char new[MAXPATHLEN];
144426048Sminshall 	char *cp = rindex(local, '/');
144526048Sminshall 	int d, count=0;
144626048Sminshall 	char ext = '1';
144726048Sminshall 
144826448Slepreau 	if (cp)
144926048Sminshall 		*cp = '\0';
145026048Sminshall 	d = access(cp ? local : ".", 2);
145126448Slepreau 	if (cp)
145226048Sminshall 		*cp = '/';
145326048Sminshall 	if (d < 0) {
145426048Sminshall 		perror(local);
145526048Sminshall 		return((char *) 0);
145626048Sminshall 	}
145726048Sminshall 	(void) strcpy(new, local);
145826048Sminshall 	cp = new + strlen(new);
145926048Sminshall 	*cp++ = '.';
146026048Sminshall 	while (!d) {
146126048Sminshall 		if (++count == 100) {
146226048Sminshall 			printf("runique: can't find unique file name.\n");
146326048Sminshall 			return((char *) 0);
146426048Sminshall 		}
146526048Sminshall 		*cp++ = ext;
146626048Sminshall 		*cp = '\0';
146726448Slepreau 		if (ext == '9')
146826048Sminshall 			ext = '0';
146926448Slepreau 		else
147026048Sminshall 			ext++;
147126448Slepreau 		if ((d = access(new, 0)) < 0)
147226048Sminshall 			break;
147326448Slepreau 		if (ext != '0')
147426048Sminshall 			cp--;
147526448Slepreau 		else if (*(cp - 2) == '.')
147626048Sminshall 			*(cp - 1) = '1';
147726048Sminshall 		else {
147826048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
147926048Sminshall 			cp--;
148026048Sminshall 		}
148126048Sminshall 	}
148226048Sminshall 	return(new);
148326048Sminshall }
1484