xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 35792)
121739Sdist /*
226048Sminshall  * Copyright (c) 1985 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534901Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621739Sdist  */
1721739Sdist 
1810296Ssam #ifndef lint
19*35792Sbostic static char sccsid[] = "@(#)ftp.c	5.22 (Berkeley) 10/11/88";
2033737Sbostic #endif /* not lint */
2110296Ssam 
2226048Sminshall #include "ftp_var.h"
2326048Sminshall 
2410296Ssam #include <sys/stat.h>
2510296Ssam #include <sys/ioctl.h>
2610296Ssam #include <sys/socket.h>
2713614Ssam #include <sys/time.h>
2828469Skarels #include <sys/param.h>
2910296Ssam 
3010296Ssam #include <netinet/in.h>
3112397Ssam #include <arpa/ftp.h>
3226048Sminshall #include <arpa/telnet.h>
3310296Ssam 
3410296Ssam #include <stdio.h>
3510296Ssam #include <signal.h>
3610296Ssam #include <errno.h>
3710296Ssam #include <netdb.h>
3826048Sminshall #include <fcntl.h>
3926048Sminshall #include <pwd.h>
4010296Ssam 
4110296Ssam struct	sockaddr_in hisctladdr;
4210296Ssam struct	sockaddr_in data_addr;
4310296Ssam int	data = -1;
4426048Sminshall int	abrtflag = 0;
4526048Sminshall int	ptflag = 0;
4610296Ssam int	connected;
4710296Ssam struct	sockaddr_in myctladdr;
4826496Sminshall uid_t	getuid();
4910296Ssam 
5010296Ssam FILE	*cin, *cout;
5110296Ssam FILE	*dataconn();
5210296Ssam 
5325904Skarels char *
5410296Ssam hookup(host, port)
5510296Ssam 	char *host;
5610296Ssam 	int port;
5710296Ssam {
5825904Skarels 	register struct hostent *hp = 0;
5927687Sminshall 	int s,len;
6025904Skarels 	static char hostnamebuf[80];
6110296Ssam 
6210296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
6325904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6425904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6525904Skarels 		hisctladdr.sin_family = AF_INET;
6625904Skarels 		(void) strcpy(hostnamebuf, host);
6726048Sminshall 	}
6826048Sminshall 	else {
6925100Sbloom 		hp = gethostbyname(host);
7025904Skarels 		if (hp == NULL) {
71*35792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
72*35792Sbostic 			herror((char *)NULL);
7326048Sminshall 			code = -1;
7426048Sminshall 			return((char *) 0);
7525904Skarels 		}
7625904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7725904Skarels 		bcopy(hp->h_addr_list[0],
7825904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
7925904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
8010296Ssam 	}
8125904Skarels 	hostname = hostnamebuf;
8225904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8310296Ssam 	if (s < 0) {
8410296Ssam 		perror("ftp: socket");
8526048Sminshall 		code = -1;
8610296Ssam 		return (0);
8710296Ssam 	}
8810296Ssam 	hisctladdr.sin_port = port;
8926496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
9025904Skarels 		if (hp && hp->h_addr_list[1]) {
9125904Skarels 			int oerrno = errno;
9225904Skarels 
9325904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9425904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9525904Skarels 			errno = oerrno;
9626496Sminshall 			perror((char *) 0);
9725904Skarels 			hp->h_addr_list++;
9825904Skarels 			bcopy(hp->h_addr_list[0],
9926048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
10026496Sminshall 			fprintf(stdout, "Trying %s...\n",
10125904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10226813Skarels 			(void) close(s);
10326813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10426813Skarels 			if (s < 0) {
10526813Skarels 				perror("ftp: socket");
10626813Skarels 				code = -1;
10726813Skarels 				return (0);
10826813Skarels 			}
10925904Skarels 			continue;
11025904Skarels 		}
11110296Ssam 		perror("ftp: connect");
11226048Sminshall 		code = -1;
11310296Ssam 		goto bad;
11410296Ssam 	}
11511627Ssam 	len = sizeof (myctladdr);
11611627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
11711627Ssam 		perror("ftp: getsockname");
11826048Sminshall 		code = -1;
11910296Ssam 		goto bad;
12010296Ssam 	}
12110296Ssam 	cin = fdopen(s, "r");
12210296Ssam 	cout = fdopen(s, "w");
12311219Ssam 	if (cin == NULL || cout == NULL) {
12410296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12510296Ssam 		if (cin)
12626496Sminshall 			(void) fclose(cin);
12710296Ssam 		if (cout)
12826496Sminshall 			(void) fclose(cout);
12926048Sminshall 		code = -1;
13010296Ssam 		goto bad;
13110296Ssam 	}
13210296Ssam 	if (verbose)
13326067Sminshall 		printf("Connected to %s.\n", hostname);
13427687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13526048Sminshall 		if (cin)
13626496Sminshall 			(void) fclose(cin);
13726048Sminshall 		if (cout)
13826496Sminshall 			(void) fclose(cout);
13926048Sminshall 		code = -1;
14026048Sminshall 		goto bad;
14126048Sminshall 	}
14227687Sminshall #ifdef SO_OOBINLINE
14327687Sminshall 	{
14427687Sminshall 	int on = 1;
14526048Sminshall 
14627687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
14727687Sminshall 		< 0 && debug) {
14827687Sminshall 			perror("ftp: setsockopt");
14927687Sminshall 		}
15027687Sminshall 	}
15127687Sminshall #endif SO_OOBINLINE
15226048Sminshall 
15325904Skarels 	return (hostname);
15410296Ssam bad:
15526496Sminshall 	(void) close(s);
15625904Skarels 	return ((char *)0);
15710296Ssam }
15810296Ssam 
15925904Skarels login(host)
16025904Skarels 	char *host;
16110296Ssam {
16226048Sminshall 	char tmp[80];
16335659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16426048Sminshall 	int n, aflag = 0;
16510296Ssam 
16626048Sminshall 	user = pass = acct = 0;
16726048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16826048Sminshall 		disconnect();
16926048Sminshall 		code = -1;
17026048Sminshall 		return(0);
17126048Sminshall 	}
17226048Sminshall 	if (user == NULL) {
17326048Sminshall 		char *myname = getlogin();
17426048Sminshall 
17526048Sminshall 		if (myname == NULL) {
17626048Sminshall 			struct passwd *pp = getpwuid(getuid());
17726048Sminshall 
17826448Slepreau 			if (pp != NULL)
17926048Sminshall 				myname = pp->pw_name;
18026048Sminshall 		}
18126048Sminshall 		printf("Name (%s:%s): ", host, myname);
18226048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18326048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18426448Slepreau 		if (*tmp == '\0')
18526048Sminshall 			user = myname;
18626448Slepreau 		else
18726048Sminshall 			user = tmp;
18826048Sminshall 	}
18910296Ssam 	n = command("USER %s", user);
19026048Sminshall 	if (n == CONTINUE) {
19126448Slepreau 		if (pass == NULL)
19235659Sbostic 			pass = getpass("Password:");
19310296Ssam 		n = command("PASS %s", pass);
19426048Sminshall 	}
19510296Ssam 	if (n == CONTINUE) {
19626048Sminshall 		aflag++;
19735659Sbostic 		acct = getpass("Account:");
19810296Ssam 		n = command("ACCT %s", acct);
19910296Ssam 	}
20010296Ssam 	if (n != COMPLETE) {
20110296Ssam 		fprintf(stderr, "Login failed.\n");
20210296Ssam 		return (0);
20310296Ssam 	}
20426448Slepreau 	if (!aflag && acct != NULL)
20526048Sminshall 		(void) command("ACCT %s", acct);
20626448Slepreau 	if (proxy)
20726048Sminshall 		return(1);
20826048Sminshall 	for (n = 0; n < macnum; ++n) {
20926048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21026496Sminshall 			(void) strcpy(line, "$init");
21126048Sminshall 			makeargv();
21226048Sminshall 			domacro(margc, margv);
21326048Sminshall 			break;
21426048Sminshall 		}
21526048Sminshall 	}
21610296Ssam 	return (1);
21710296Ssam }
21810296Ssam 
21926048Sminshall cmdabort()
22026048Sminshall {
22126048Sminshall 	extern jmp_buf ptabort;
22226048Sminshall 
22326048Sminshall 	printf("\n");
22426048Sminshall 	(void) fflush(stdout);
22526048Sminshall 	abrtflag++;
22626448Slepreau 	if (ptflag)
22726048Sminshall 		longjmp(ptabort,1);
22826048Sminshall }
22926048Sminshall 
23026496Sminshall /*VARARGS1*/
23110296Ssam command(fmt, args)
23210296Ssam 	char *fmt;
23310296Ssam {
23426048Sminshall 	int r, (*oldintr)(), cmdabort();
23510296Ssam 
23626048Sminshall 	abrtflag = 0;
23710296Ssam 	if (debug) {
23810296Ssam 		printf("---> ");
23910296Ssam 		_doprnt(fmt, &args, stdout);
24010296Ssam 		printf("\n");
24110296Ssam 		(void) fflush(stdout);
24210296Ssam 	}
24311219Ssam 	if (cout == NULL) {
24411219Ssam 		perror ("No control connection for command");
24526048Sminshall 		code = -1;
24611219Ssam 		return (0);
24711219Ssam 	}
24826048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24910296Ssam 	_doprnt(fmt, &args, cout);
25010296Ssam 	fprintf(cout, "\r\n");
25110296Ssam 	(void) fflush(cout);
25226048Sminshall 	cpend = 1;
25326048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25426448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
25526048Sminshall 		(*oldintr)();
25626048Sminshall 	(void) signal(SIGINT, oldintr);
25726048Sminshall 	return(r);
25810296Ssam }
25910296Ssam 
26010296Ssam #include <ctype.h>
26110296Ssam 
26210296Ssam getreply(expecteof)
26310296Ssam 	int expecteof;
26410296Ssam {
26511219Ssam 	register int c, n;
26626048Sminshall 	register int dig;
26726048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
26826048Sminshall 	int pflag = 0;
26926048Sminshall 	char *pt = pasv;
27010296Ssam 
27126048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27210296Ssam 	for (;;) {
27310296Ssam 		dig = n = code = 0;
27410296Ssam 		while ((c = getc(cin)) != '\n') {
27527687Sminshall 			if (c == IAC) {     /* handle telnet commands */
27627687Sminshall 				switch (c = getc(cin)) {
27727687Sminshall 				case WILL:
27827687Sminshall 				case WONT:
27927687Sminshall 					c = getc(cin);
28027687Sminshall 					fprintf(cout, "%c%c%c",IAC,WONT,c);
28127687Sminshall 					(void) fflush(cout);
28227687Sminshall 					break;
28327687Sminshall 				case DO:
28427687Sminshall 				case DONT:
28527687Sminshall 					c = getc(cin);
28627687Sminshall 					fprintf(cout, "%c%c%c",IAC,DONT,c);
28727687Sminshall 					(void) fflush(cout);
28827687Sminshall 					break;
28927687Sminshall 				default:
29027687Sminshall 					break;
29127687Sminshall 				}
29227687Sminshall 				continue;
29327687Sminshall 			}
29410296Ssam 			dig++;
29510296Ssam 			if (c == EOF) {
29626048Sminshall 				if (expecteof) {
29726048Sminshall 					(void) signal(SIGINT,oldintr);
29826048Sminshall 					code = 221;
29910296Ssam 					return (0);
30026048Sminshall 				}
30110296Ssam 				lostpeer();
30226048Sminshall 				if (verbose) {
30326048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
30426048Sminshall 					(void) fflush(stdout);
30526048Sminshall 				}
30633772Scsvsj 				code = 421;
30733772Scsvsj 				return(4);
30810296Ssam 			}
30926048Sminshall 			if (c != '\r' && (verbose > 0 ||
31026048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
31126448Slepreau 				if (proxflag &&
31226448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
31326048Sminshall 					printf("%s:",hostname);
31426496Sminshall 				(void) putchar(c);
31526048Sminshall 			}
31610296Ssam 			if (dig < 4 && isdigit(c))
31710296Ssam 				code = code * 10 + (c - '0');
31826448Slepreau 			if (!pflag && code == 227)
31926048Sminshall 				pflag = 1;
32026448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
32126048Sminshall 				pflag = 2;
32226048Sminshall 			if (pflag == 2) {
32326448Slepreau 				if (c != '\r' && c != ')')
32426048Sminshall 					*pt++ = c;
32526048Sminshall 				else {
32626048Sminshall 					*pt = '\0';
32726048Sminshall 					pflag = 3;
32826048Sminshall 				}
32926048Sminshall 			}
33026048Sminshall 			if (dig == 4 && c == '-') {
33126448Slepreau 				if (continuation)
33226048Sminshall 					code = 0;
33310296Ssam 				continuation++;
33426048Sminshall 			}
33510296Ssam 			if (n == 0)
33610296Ssam 				n = c;
33710296Ssam 		}
33826048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
33926496Sminshall 			(void) putchar(c);
34011346Ssam 			(void) fflush (stdout);
34111346Ssam 		}
34210296Ssam 		if (continuation && code != originalcode) {
34310296Ssam 			if (originalcode == 0)
34410296Ssam 				originalcode = code;
34510296Ssam 			continue;
34610296Ssam 		}
34726448Slepreau 		if (n != '1')
34826048Sminshall 			cpend = 0;
34926048Sminshall 		(void) signal(SIGINT,oldintr);
35026448Slepreau 		if (code == 421 || originalcode == 421)
35126048Sminshall 			lostpeer();
35226448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
35326048Sminshall 			(*oldintr)();
35425907Smckusick 		return (n - '0');
35510296Ssam 	}
35610296Ssam }
35710296Ssam 
35826048Sminshall empty(mask, sec)
35927687Sminshall 	struct fd_set *mask;
36026048Sminshall 	int sec;
36126048Sminshall {
36226048Sminshall 	struct timeval t;
36326048Sminshall 
36426048Sminshall 	t.tv_sec = (long) sec;
36526048Sminshall 	t.tv_usec = 0;
36627687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
36726048Sminshall }
36826048Sminshall 
36910296Ssam jmp_buf	sendabort;
37010296Ssam 
37110296Ssam abortsend()
37210296Ssam {
37310296Ssam 
37426048Sminshall 	mflag = 0;
37526048Sminshall 	abrtflag = 0;
37626048Sminshall 	printf("\nsend aborted\n");
37726048Sminshall 	(void) fflush(stdout);
37810296Ssam 	longjmp(sendabort, 1);
37910296Ssam }
38010296Ssam 
38110296Ssam sendrequest(cmd, local, remote)
38210296Ssam 	char *cmd, *local, *remote;
38310296Ssam {
38435659Sbostic 	FILE *fin, *dout = 0, *popen();
38535659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
38626048Sminshall 	int abortsend();
38711219Ssam 	char buf[BUFSIZ];
38811651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
38911346Ssam 	register int c, d;
39010296Ssam 	struct stat st;
39110296Ssam 	struct timeval start, stop;
39210296Ssam 
39326048Sminshall 	if (proxy) {
39426048Sminshall 		proxtrans(cmd, local, remote);
39526048Sminshall 		return;
39626048Sminshall 	}
39710296Ssam 	closefunc = NULL;
39826048Sminshall 	oldintr = NULL;
39926048Sminshall 	oldintp = NULL;
40026048Sminshall 	if (setjmp(sendabort)) {
40126048Sminshall 		while (cpend) {
40226048Sminshall 			(void) getreply(0);
40326048Sminshall 		}
40426048Sminshall 		if (data >= 0) {
40526048Sminshall 			(void) close(data);
40626048Sminshall 			data = -1;
40726048Sminshall 		}
40826448Slepreau 		if (oldintr)
40926048Sminshall 			(void) signal(SIGINT,oldintr);
41026448Slepreau 		if (oldintp)
41126048Sminshall 			(void) signal(SIGPIPE,oldintp);
41226048Sminshall 		code = -1;
41326048Sminshall 		return;
41426048Sminshall 	}
41510296Ssam 	oldintr = signal(SIGINT, abortsend);
41610296Ssam 	if (strcmp(local, "-") == 0)
41710296Ssam 		fin = stdin;
41810296Ssam 	else if (*local == '|') {
41926048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
42035659Sbostic 		fin = popen(local + 1, "r");
42110296Ssam 		if (fin == NULL) {
42226048Sminshall 			perror(local + 1);
42326048Sminshall 			(void) signal(SIGINT, oldintr);
42426048Sminshall 			(void) signal(SIGPIPE, oldintp);
42526048Sminshall 			code = -1;
42626048Sminshall 			return;
42710296Ssam 		}
42835659Sbostic 		closefunc = pclose;
42910296Ssam 	} else {
43010296Ssam 		fin = fopen(local, "r");
43110296Ssam 		if (fin == NULL) {
43210296Ssam 			perror(local);
43326048Sminshall 			(void) signal(SIGINT, oldintr);
43426048Sminshall 			code = -1;
43526048Sminshall 			return;
43610296Ssam 		}
43710296Ssam 		closefunc = fclose;
43810296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
43910296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
44026496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
44126048Sminshall 			(void) signal(SIGINT, oldintr);
44226048Sminshall 			code = -1;
44326048Sminshall 			return;
44410296Ssam 		}
44510296Ssam 	}
44626048Sminshall 	if (initconn()) {
44726048Sminshall 		(void) signal(SIGINT, oldintr);
44826448Slepreau 		if (oldintp)
44926048Sminshall 			(void) signal(SIGPIPE, oldintp);
45026048Sminshall 		code = -1;
45126048Sminshall 		return;
45226048Sminshall 	}
45326448Slepreau 	if (setjmp(sendabort))
45426048Sminshall 		goto abort;
45510296Ssam 	if (remote) {
45626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
45726048Sminshall 			(void) signal(SIGINT, oldintr);
45826448Slepreau 			if (oldintp)
45926048Sminshall 				(void) signal(SIGPIPE, oldintp);
46026048Sminshall 			return;
46126048Sminshall 		}
46210296Ssam 	} else
46326048Sminshall 		if (command("%s", cmd) != PRELIM) {
46426048Sminshall 			(void) signal(SIGINT, oldintr);
46526448Slepreau 			if (oldintp)
46626048Sminshall 				(void) signal(SIGPIPE, oldintp);
46726048Sminshall 			return;
46826048Sminshall 		}
46910296Ssam 	dout = dataconn("w");
47026448Slepreau 	if (dout == NULL)
47126048Sminshall 		goto abort;
47226496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
47311219Ssam 	switch (type) {
47411219Ssam 
47511219Ssam 	case TYPE_I:
47611219Ssam 	case TYPE_L:
47711346Ssam 		errno = d = 0;
47811219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
47911346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
48011219Ssam 				break;
48111219Ssam 			bytes += c;
48211651Ssam 			if (hash) {
48326496Sminshall 				(void) putchar('#');
48426496Sminshall 				(void) fflush(stdout);
48511651Ssam 			}
48611219Ssam 		}
48713213Ssam 		if (hash && bytes > 0) {
48826496Sminshall 			(void) putchar('\n');
48926496Sminshall 			(void) fflush(stdout);
49011651Ssam 		}
49111219Ssam 		if (c < 0)
49211219Ssam 			perror(local);
49311346Ssam 		if (d < 0)
49411219Ssam 			perror("netout");
49511219Ssam 		break;
49611219Ssam 
49711219Ssam 	case TYPE_A:
49811219Ssam 		while ((c = getc(fin)) != EOF) {
49911219Ssam 			if (c == '\n') {
50011651Ssam 				while (hash && (bytes >= hashbytes)) {
50126496Sminshall 					(void) putchar('#');
50226496Sminshall 					(void) fflush(stdout);
50311651Ssam 					hashbytes += sizeof (buf);
50411651Ssam 				}
50511219Ssam 				if (ferror(dout))
50611219Ssam 					break;
50726496Sminshall 				(void) putc('\r', dout);
50811219Ssam 				bytes++;
50911219Ssam 			}
51026496Sminshall 			(void) putc(c, dout);
51111219Ssam 			bytes++;
51226048Sminshall 	/*		if (c == '\r') {			  	*/
51326496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
51426048Sminshall 	/*			bytes++;				*/
51526048Sminshall 	/*		}                          			*/
51611219Ssam 		}
51711651Ssam 		if (hash) {
51813213Ssam 			if (bytes < hashbytes)
51926496Sminshall 				(void) putchar('#');
52026496Sminshall 			(void) putchar('\n');
52126496Sminshall 			(void) fflush(stdout);
52211651Ssam 		}
52311219Ssam 		if (ferror(fin))
52411219Ssam 			perror(local);
52511346Ssam 		if (ferror(dout))
52611219Ssam 			perror("netout");
52711219Ssam 		break;
52810296Ssam 	}
52926496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
53010296Ssam 	if (closefunc != NULL)
53126048Sminshall 		(*closefunc)(fin);
53210296Ssam 	(void) fclose(dout);
53326048Sminshall 	(void) getreply(0);
53426048Sminshall 	(void) signal(SIGINT, oldintr);
53535699Sbostic 	if (bytes > 0)
53626048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53710296Ssam 	return;
53826048Sminshall abort:
53926496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
54026048Sminshall 	(void) signal(SIGINT, oldintr);
54126448Slepreau 	if (oldintp)
54226048Sminshall 		(void) signal(SIGPIPE, oldintp);
54326048Sminshall 	if (!cpend) {
54426048Sminshall 		code = -1;
54526048Sminshall 		return;
54626048Sminshall 	}
54726048Sminshall 	if (data >= 0) {
54826048Sminshall 		(void) close(data);
54926048Sminshall 		data = -1;
55026048Sminshall 	}
55126448Slepreau 	if (dout)
55226048Sminshall 		(void) fclose(dout);
55326048Sminshall 	(void) getreply(0);
55426048Sminshall 	code = -1;
55510296Ssam 	if (closefunc != NULL && fin != NULL)
55626048Sminshall 		(*closefunc)(fin);
55735699Sbostic 	if (bytes > 0)
55826048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
55910296Ssam }
56010296Ssam 
56110296Ssam jmp_buf	recvabort;
56210296Ssam 
56310296Ssam abortrecv()
56410296Ssam {
56510296Ssam 
56626048Sminshall 	mflag = 0;
56726048Sminshall 	abrtflag = 0;
56826048Sminshall 	printf("\n");
56926048Sminshall 	(void) fflush(stdout);
57010296Ssam 	longjmp(recvabort, 1);
57110296Ssam }
57210296Ssam 
57311651Ssam recvrequest(cmd, local, remote, mode)
57411651Ssam 	char *cmd, *local, *remote, *mode;
57510296Ssam {
57635659Sbostic 	FILE *fout, *din = 0, *popen();
57735659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
57827687Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag, nfnd;
57927687Sminshall 	char buf[BUFSIZ], *gunique(), msg;
58026496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
58126496Sminshall 	struct fd_set mask;
58211346Ssam 	register int c, d;
58310296Ssam 	struct timeval start, stop;
58410296Ssam 
58526048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
58626048Sminshall 		proxtrans(cmd, local, remote);
58726048Sminshall 		return;
58826048Sminshall 	}
58910296Ssam 	closefunc = NULL;
59026048Sminshall 	oldintr = NULL;
59126048Sminshall 	oldintp = NULL;
59226048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
59326048Sminshall 	if (setjmp(recvabort)) {
59426048Sminshall 		while (cpend) {
59526048Sminshall 			(void) getreply(0);
59626048Sminshall 		}
59726048Sminshall 		if (data >= 0) {
59826048Sminshall 			(void) close(data);
59926048Sminshall 			data = -1;
60026048Sminshall 		}
60126448Slepreau 		if (oldintr)
60226048Sminshall 			(void) signal(SIGINT, oldintr);
60326048Sminshall 		code = -1;
60426048Sminshall 		return;
60526048Sminshall 	}
60610296Ssam 	oldintr = signal(SIGINT, abortrecv);
60726048Sminshall 	if (strcmp(local, "-") && *local != '|') {
60810296Ssam 		if (access(local, 2) < 0) {
60926048Sminshall 			char *dir = rindex(local, '/');
61010296Ssam 
61126048Sminshall 			if (errno != ENOENT && errno != EACCES) {
61210296Ssam 				perror(local);
61326048Sminshall 				(void) signal(SIGINT, oldintr);
61426048Sminshall 				code = -1;
61526048Sminshall 				return;
61610296Ssam 			}
61726048Sminshall 			if (dir != NULL)
61826048Sminshall 				*dir = 0;
61926048Sminshall 			d = access(dir ? local : ".", 2);
62026048Sminshall 			if (dir != NULL)
62126048Sminshall 				*dir = '/';
62226048Sminshall 			if (d < 0) {
62326048Sminshall 				perror(local);
62426048Sminshall 				(void) signal(SIGINT, oldintr);
62526048Sminshall 				code = -1;
62626048Sminshall 				return;
62726048Sminshall 			}
62826048Sminshall 			if (!runique && errno == EACCES &&
62926048Sminshall 			    chmod(local,0600) < 0) {
63026048Sminshall 				perror(local);
63126048Sminshall 				(void) signal(SIGINT, oldintr);
63226048Sminshall 				code = -1;
63326048Sminshall 				return;
63426048Sminshall 			}
63526048Sminshall 			if (runique && errno == EACCES &&
63626048Sminshall 			   (local = gunique(local)) == NULL) {
63726048Sminshall 				(void) signal(SIGINT, oldintr);
63826048Sminshall 				code = -1;
63926048Sminshall 				return;
64026048Sminshall 			}
64110296Ssam 		}
64226048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
64326048Sminshall 			(void) signal(SIGINT, oldintr);
64426048Sminshall 			code = -1;
64526048Sminshall 			return;
64626048Sminshall 		}
64726048Sminshall 	}
64826048Sminshall 	if (initconn()) {
64926048Sminshall 		(void) signal(SIGINT, oldintr);
65026048Sminshall 		code = -1;
65126048Sminshall 		return;
65226048Sminshall 	}
65326448Slepreau 	if (setjmp(recvabort))
65426048Sminshall 		goto abort;
65526048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
65626048Sminshall 		oldtype = type;
65726048Sminshall 		oldverbose = verbose;
65826448Slepreau 		if (!debug)
65926048Sminshall 			verbose = 0;
66026048Sminshall 		setascii();
66126048Sminshall 		verbose = oldverbose;
66226048Sminshall 	}
66310296Ssam 	if (remote) {
66426048Sminshall 		if (command("%s %s", cmd, remote) != 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 	} else {
68526048Sminshall 		if (command("%s", cmd) != PRELIM) {
68626048Sminshall 			(void) signal(SIGINT, oldintr);
68726048Sminshall 			if (oldtype) {
68826448Slepreau 				if (!debug)
68926048Sminshall 					verbose = 0;
69026048Sminshall 				switch (oldtype) {
69126048Sminshall 					case TYPE_I:
69226048Sminshall 						setbinary();
69326048Sminshall 						break;
69426048Sminshall 					case TYPE_E:
69526048Sminshall 						setebcdic();
69626048Sminshall 						break;
69726048Sminshall 					case TYPE_L:
69826048Sminshall 						settenex();
69926048Sminshall 						break;
70026048Sminshall 				}
70126048Sminshall 				verbose = oldverbose;
70226048Sminshall 			}
70326048Sminshall 			return;
70426048Sminshall 		}
70526048Sminshall 	}
70626048Sminshall 	din = dataconn("r");
70726048Sminshall 	if (din == NULL)
70826048Sminshall 		goto abort;
70926448Slepreau 	if (strcmp(local, "-") == 0)
71010296Ssam 		fout = stdout;
71110296Ssam 	else if (*local == '|') {
71226048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
71335659Sbostic 		fout = popen(local + 1, "w");
71426048Sminshall 		if (fout == NULL) {
71526048Sminshall 			perror(local+1);
71626048Sminshall 			goto abort;
71726048Sminshall 		}
71835659Sbostic 		closefunc = pclose;
71926048Sminshall 	}
72026048Sminshall 	else {
72111651Ssam 		fout = fopen(local, mode);
72226048Sminshall 		if (fout == NULL) {
72326048Sminshall 			perror(local);
72426048Sminshall 			goto abort;
72526048Sminshall 		}
72610296Ssam 		closefunc = fclose;
72710296Ssam 	}
72826496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
72911219Ssam 	switch (type) {
73011219Ssam 
73111219Ssam 	case TYPE_I:
73211219Ssam 	case TYPE_L:
73311346Ssam 		errno = d = 0;
73411219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
73511346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
73611219Ssam 				break;
73711219Ssam 			bytes += c;
73811651Ssam 			if (hash) {
73926496Sminshall 				(void) putchar('#');
74026496Sminshall 				(void) fflush(stdout);
74111651Ssam 			}
74211219Ssam 		}
74313213Ssam 		if (hash && bytes > 0) {
74426496Sminshall 			(void) putchar('\n');
74526496Sminshall 			(void) fflush(stdout);
74611651Ssam 		}
74711219Ssam 		if (c < 0)
74811219Ssam 			perror("netin");
74911346Ssam 		if (d < 0)
75010296Ssam 			perror(local);
75111219Ssam 		break;
75211219Ssam 
75311219Ssam 	case TYPE_A:
75411219Ssam 		while ((c = getc(din)) != EOF) {
75527749Sminshall 			while (c == '\r') {
75611651Ssam 				while (hash && (bytes >= hashbytes)) {
75726496Sminshall 					(void) putchar('#');
75826496Sminshall 					(void) fflush(stdout);
75911651Ssam 					hashbytes += sizeof (buf);
76011651Ssam 				}
76110296Ssam 				bytes++;
76226048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
76311219Ssam 					if (ferror (fout))
76411219Ssam 						break;
76526496Sminshall 					(void) putc ('\r', fout);
76611219Ssam 				}
76726048Sminshall 				/*if (c == '\0') {
76811219Ssam 					bytes++;
76911219Ssam 					continue;
77026048Sminshall 				}*/
77111219Ssam 			}
77226496Sminshall 			(void) putc (c, fout);
77311219Ssam 			bytes++;
77410296Ssam 		}
77511651Ssam 		if (hash) {
77613213Ssam 			if (bytes < hashbytes)
77726496Sminshall 				(void) putchar('#');
77826496Sminshall 			(void) putchar('\n');
77926496Sminshall 			(void) fflush(stdout);
78011651Ssam 		}
78111219Ssam 		if (ferror (din))
78211219Ssam 			perror ("netin");
78311219Ssam 		if (ferror (fout))
78411219Ssam 			perror (local);
78511219Ssam 		break;
78610296Ssam 	}
78726448Slepreau 	if (closefunc != NULL)
78826048Sminshall 		(*closefunc)(fout);
78926496Sminshall 	(void) signal(SIGINT, oldintr);
79026448Slepreau 	if (oldintp)
79126048Sminshall 		(void) signal(SIGPIPE, oldintp);
79226496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
79310296Ssam 	(void) fclose(din);
79426048Sminshall 	(void) getreply(0);
79535699Sbostic 	if (bytes > 0)
79626048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
79726048Sminshall 	if (oldtype) {
79826448Slepreau 		if (!debug)
79926048Sminshall 			verbose = 0;
80026048Sminshall 		switch (oldtype) {
80126048Sminshall 			case TYPE_I:
80226048Sminshall 				setbinary();
80326048Sminshall 				break;
80426048Sminshall 			case TYPE_E:
80526048Sminshall 				setebcdic();
80626048Sminshall 				break;
80726048Sminshall 			case TYPE_L:
80826048Sminshall 				settenex();
80926048Sminshall 				break;
81026048Sminshall 		}
81126048Sminshall 		verbose = oldverbose;
81226048Sminshall 	}
81326048Sminshall 	return;
81426048Sminshall abort:
81526048Sminshall 
81627687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
81726048Sminshall 
81826496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
81926448Slepreau 	if (oldintp)
82026048Sminshall 		(void) signal(SIGPIPE, oldintr);
82126048Sminshall 	(void) signal(SIGINT,SIG_IGN);
82226048Sminshall 	if (oldtype) {
82326448Slepreau 		if (!debug)
82426048Sminshall 			verbose = 0;
82526048Sminshall 		switch (oldtype) {
82626048Sminshall 			case TYPE_I:
82726048Sminshall 				setbinary();
82826048Sminshall 				break;
82926048Sminshall 			case TYPE_E:
83026048Sminshall 				setebcdic();
83126048Sminshall 				break;
83226048Sminshall 			case TYPE_L:
83326048Sminshall 				settenex();
83426048Sminshall 				break;
83526048Sminshall 		}
83626048Sminshall 		verbose = oldverbose;
83726048Sminshall 	}
83826048Sminshall 	if (!cpend) {
83926048Sminshall 		code = -1;
84026048Sminshall 		(void) signal(SIGINT,oldintr);
84126048Sminshall 		return;
84226048Sminshall 	}
84326048Sminshall 
84427687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
84527687Sminshall 	(void) fflush(cout);
84627687Sminshall 	msg = IAC;
84727687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
84827687Sminshall /* after urgent byte rather than before as now is protocol            */
84927687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
85027687Sminshall 		perror("abort");
85126048Sminshall 	}
85227687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
85326048Sminshall 	(void) fflush(cout);
85427687Sminshall 	FD_ZERO(&mask);
85526496Sminshall 	FD_SET(fileno(cin), &mask);
85626496Sminshall 	if (din) {
85726496Sminshall 		FD_SET(fileno(din), &mask);
85826496Sminshall 	}
85927687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
86027687Sminshall 		if (nfnd < 0) {
86127687Sminshall 			perror("abort");
86227687Sminshall 		}
86326048Sminshall 		code = -1;
86426048Sminshall 		lostpeer();
86526048Sminshall 	}
86626496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
86726448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
86826448Slepreau 			;
86926496Sminshall 	}
87027687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
87126048Sminshall 		if (data >= 0) {
87226496Sminshall 			(void) close(data);
87326048Sminshall 			data = -1;
87426048Sminshall 		}
87525907Smckusick 		(void) getreply(0);
87625907Smckusick 	}
87726048Sminshall 	(void) getreply(0);
87826048Sminshall 	code = -1;
87926048Sminshall 	if (data >= 0) {
88026048Sminshall 		(void) close(data);
88126048Sminshall 		data = -1;
88226048Sminshall 	}
88326448Slepreau 	if (closefunc != NULL && fout != NULL)
88426048Sminshall 		(*closefunc)(fout);
88526448Slepreau 	if (din)
88626048Sminshall 		(void) fclose(din);
88735699Sbostic 	if (bytes > 0)
88826048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
88926048Sminshall 	(void) signal(SIGINT,oldintr);
89010296Ssam }
89110296Ssam 
89210296Ssam /*
89310296Ssam  * Need to start a listen on the data channel
89410296Ssam  * before we send the command, otherwise the
89510296Ssam  * server's connect may fail.
89610296Ssam  */
89733224Sbostic int sendport = -1;
89811651Ssam 
89910296Ssam initconn()
90010296Ssam {
90110296Ssam 	register char *p, *a;
90226048Sminshall 	int result, len, tmpno = 0;
90326993Skarels 	int on = 1;
90410296Ssam 
90511651Ssam noport:
90610296Ssam 	data_addr = myctladdr;
90711651Ssam 	if (sendport)
90811651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
90911651Ssam 	if (data != -1)
91011651Ssam 		(void) close (data);
91118287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
91210296Ssam 	if (data < 0) {
91310296Ssam 		perror("ftp: socket");
91426448Slepreau 		if (tmpno)
91526048Sminshall 			sendport = 1;
91610296Ssam 		return (1);
91710296Ssam 	}
91812397Ssam 	if (!sendport)
91927687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
92033224Sbostic 			perror("ftp: setsockopt (reuse address)");
92112397Ssam 			goto bad;
92212397Ssam 		}
92326496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
92410296Ssam 		perror("ftp: bind");
92510296Ssam 		goto bad;
92610296Ssam 	}
92710296Ssam 	if (options & SO_DEBUG &&
92827687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
92910296Ssam 		perror("ftp: setsockopt (ignored)");
93011627Ssam 	len = sizeof (data_addr);
93111627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
93211627Ssam 		perror("ftp: getsockname");
93310296Ssam 		goto bad;
93410296Ssam 	}
93526448Slepreau 	if (listen(data, 1) < 0)
93610296Ssam 		perror("ftp: listen");
93711651Ssam 	if (sendport) {
93811651Ssam 		a = (char *)&data_addr.sin_addr;
93911651Ssam 		p = (char *)&data_addr.sin_port;
94010296Ssam #define	UC(b)	(((int)b)&0xff)
94111651Ssam 		result =
94211651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
94311651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
94411651Ssam 		      UC(p[0]), UC(p[1]));
94511651Ssam 		if (result == ERROR && sendport == -1) {
94611651Ssam 			sendport = 0;
94726048Sminshall 			tmpno = 1;
94811651Ssam 			goto noport;
94911651Ssam 		}
95011651Ssam 		return (result != COMPLETE);
95111651Ssam 	}
95226448Slepreau 	if (tmpno)
95326048Sminshall 		sendport = 1;
95411651Ssam 	return (0);
95510296Ssam bad:
95610296Ssam 	(void) close(data), data = -1;
95726448Slepreau 	if (tmpno)
95826048Sminshall 		sendport = 1;
95910296Ssam 	return (1);
96010296Ssam }
96110296Ssam 
96210296Ssam FILE *
96310296Ssam dataconn(mode)
96410296Ssam 	char *mode;
96510296Ssam {
96610296Ssam 	struct sockaddr_in from;
96710296Ssam 	int s, fromlen = sizeof (from);
96810296Ssam 
96926496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
97010296Ssam 	if (s < 0) {
97110296Ssam 		perror("ftp: accept");
97210296Ssam 		(void) close(data), data = -1;
97310296Ssam 		return (NULL);
97410296Ssam 	}
97510296Ssam 	(void) close(data);
97610296Ssam 	data = s;
97710296Ssam 	return (fdopen(data, mode));
97810296Ssam }
97910296Ssam 
98026048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
98126048Sminshall 	char *direction, *local, *remote;
98211651Ssam 	long bytes;
98310296Ssam 	struct timeval *t0, *t1;
98410296Ssam {
98510296Ssam 	struct timeval td;
98616437Sleres 	float s, bs;
98710296Ssam 
98835699Sbostic 	if (verbose) {
98935699Sbostic 		tvsub(&td, t1, t0);
99035699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
99110296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
99235699Sbostic 		bs = bytes / nz(s);
99335699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
99435699Sbostic 		    bytes, direction, s, bs / 1024.);
99535699Sbostic 	} else {
99635699Sbostic 		if (local && *local != '-')
99735699Sbostic 			printf("local: %s ", local);
99835699Sbostic 		if (remote)
99935699Sbostic 			printf("remote: %s\n", remote);
100035699Sbostic 	}
100110296Ssam }
100210296Ssam 
100326496Sminshall /*tvadd(tsum, t0)
100410296Ssam 	struct timeval *tsum, *t0;
100510296Ssam {
100610296Ssam 
100710296Ssam 	tsum->tv_sec += t0->tv_sec;
100810296Ssam 	tsum->tv_usec += t0->tv_usec;
100910296Ssam 	if (tsum->tv_usec > 1000000)
101010296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
101126496Sminshall } */
101210296Ssam 
101310296Ssam tvsub(tdiff, t1, t0)
101410296Ssam 	struct timeval *tdiff, *t1, *t0;
101510296Ssam {
101610296Ssam 
101710296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
101810296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
101910296Ssam 	if (tdiff->tv_usec < 0)
102010296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
102110296Ssam }
102226048Sminshall 
102326048Sminshall psabort()
102426048Sminshall {
102526048Sminshall 	extern int abrtflag;
102626048Sminshall 
102726048Sminshall 	abrtflag++;
102826048Sminshall }
102926048Sminshall 
103026048Sminshall pswitch(flag)
103126048Sminshall 	int flag;
103226048Sminshall {
103326048Sminshall 	extern int proxy, abrtflag;
103426048Sminshall 	int (*oldintr)();
103526048Sminshall 	static struct comvars {
103626048Sminshall 		int connect;
103728469Skarels 		char name[MAXHOSTNAMELEN];
103826048Sminshall 		struct sockaddr_in mctl;
103926048Sminshall 		struct sockaddr_in hctl;
104026048Sminshall 		FILE *in;
104126048Sminshall 		FILE *out;
104226048Sminshall 		int tpe;
104326048Sminshall 		int cpnd;
104426048Sminshall 		int sunqe;
104526048Sminshall 		int runqe;
104626048Sminshall 		int mcse;
104726048Sminshall 		int ntflg;
104826048Sminshall 		char nti[17];
104926048Sminshall 		char nto[17];
105026048Sminshall 		int mapflg;
105126048Sminshall 		char mi[MAXPATHLEN];
105226048Sminshall 		char mo[MAXPATHLEN];
105326048Sminshall 		} proxstruct, tmpstruct;
105426048Sminshall 	struct comvars *ip, *op;
105526048Sminshall 
105626048Sminshall 	abrtflag = 0;
105726048Sminshall 	oldintr = signal(SIGINT, psabort);
105826048Sminshall 	if (flag) {
105926448Slepreau 		if (proxy)
106026048Sminshall 			return;
106126048Sminshall 		ip = &tmpstruct;
106226048Sminshall 		op = &proxstruct;
106326048Sminshall 		proxy++;
106426048Sminshall 	}
106526048Sminshall 	else {
106626448Slepreau 		if (!proxy)
106726048Sminshall 			return;
106826048Sminshall 		ip = &proxstruct;
106926048Sminshall 		op = &tmpstruct;
107026048Sminshall 		proxy = 0;
107126048Sminshall 	}
107226048Sminshall 	ip->connect = connected;
107326048Sminshall 	connected = op->connect;
107428469Skarels 	if (hostname) {
107528469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
107628469Skarels 		ip->name[strlen(ip->name)] = '\0';
107728469Skarels 	} else
107828469Skarels 		ip->name[0] = 0;
107926048Sminshall 	hostname = op->name;
108026048Sminshall 	ip->hctl = hisctladdr;
108126048Sminshall 	hisctladdr = op->hctl;
108226048Sminshall 	ip->mctl = myctladdr;
108326048Sminshall 	myctladdr = op->mctl;
108426048Sminshall 	ip->in = cin;
108526048Sminshall 	cin = op->in;
108626048Sminshall 	ip->out = cout;
108726048Sminshall 	cout = op->out;
108826048Sminshall 	ip->tpe = type;
108926048Sminshall 	type = op->tpe;
109026448Slepreau 	if (!type)
109126048Sminshall 		type = 1;
109226048Sminshall 	ip->cpnd = cpend;
109326048Sminshall 	cpend = op->cpnd;
109426048Sminshall 	ip->sunqe = sunique;
109526048Sminshall 	sunique = op->sunqe;
109626048Sminshall 	ip->runqe = runique;
109726048Sminshall 	runique = op->runqe;
109826048Sminshall 	ip->mcse = mcase;
109926048Sminshall 	mcase = op->mcse;
110026048Sminshall 	ip->ntflg = ntflag;
110126048Sminshall 	ntflag = op->ntflg;
110226496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
110326048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
110426496Sminshall 	(void) strcpy(ntin, op->nti);
110526496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
110626048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
110726496Sminshall 	(void) strcpy(ntout, op->nto);
110826048Sminshall 	ip->mapflg = mapflag;
110926048Sminshall 	mapflag = op->mapflg;
111026496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
111126048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
111226496Sminshall 	(void) strcpy(mapin, op->mi);
111326496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
111426048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
111526496Sminshall 	(void) strcpy(mapout, op->mo);
111626048Sminshall 	(void) signal(SIGINT, oldintr);
111726048Sminshall 	if (abrtflag) {
111826048Sminshall 		abrtflag = 0;
111926048Sminshall 		(*oldintr)();
112026448Slepreau 	}
112126048Sminshall }
112226048Sminshall 
112326048Sminshall jmp_buf ptabort;
112426048Sminshall int ptabflg;
112526048Sminshall 
112626048Sminshall abortpt()
112726048Sminshall {
112826048Sminshall 	printf("\n");
112926496Sminshall 	(void) fflush(stdout);
113026048Sminshall 	ptabflg++;
113126048Sminshall 	mflag = 0;
113226048Sminshall 	abrtflag = 0;
113326048Sminshall 	longjmp(ptabort, 1);
113426048Sminshall }
113526048Sminshall 
113626048Sminshall proxtrans(cmd, local, remote)
113726048Sminshall 	char *cmd, *local, *remote;
113826048Sminshall {
113927687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
114026048Sminshall 	extern jmp_buf ptabort;
114126048Sminshall 	char *cmd2;
114226496Sminshall 	struct fd_set mask;
114326048Sminshall 
114426448Slepreau 	if (strcmp(cmd, "RETR"))
114526048Sminshall 		cmd2 = "RETR";
114626448Slepreau 	else
114726048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
114826048Sminshall 	if (command("PASV") != COMPLETE) {
114926048Sminshall 		printf("proxy server does not support third part transfers.\n");
115026048Sminshall 		return;
115126048Sminshall 	}
115226048Sminshall 	tmptype = type;
115326048Sminshall 	pswitch(0);
115426048Sminshall 	if (!connected) {
115526048Sminshall 		printf("No primary connection\n");
115626048Sminshall 		pswitch(1);
115726048Sminshall 		code = -1;
115826048Sminshall 		return;
115926048Sminshall 	}
116026048Sminshall 	if (type != tmptype) {
116126048Sminshall 		oldtype = type;
116226048Sminshall 		switch (tmptype) {
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 	}
117726048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
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 	}
119726448Slepreau 	if (setjmp(ptabort))
119826048Sminshall 		goto abort;
119926048Sminshall 	oldintr = signal(SIGINT, abortpt);
120026048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
120126048Sminshall 		(void) signal(SIGINT, oldintr);
120226048Sminshall 		switch (oldtype) {
120326048Sminshall 			case 0:
120426048Sminshall 				break;
120526048Sminshall 			case TYPE_A:
120626048Sminshall 				setascii();
120726048Sminshall 				break;
120826048Sminshall 			case TYPE_I:
120926048Sminshall 				setbinary();
121026048Sminshall 				break;
121126048Sminshall 			case TYPE_E:
121226048Sminshall 				setebcdic();
121326048Sminshall 				break;
121426048Sminshall 			case TYPE_L:
121526048Sminshall 				settenex();
121626048Sminshall 				break;
121726048Sminshall 		}
121826048Sminshall 		pswitch(1);
121926048Sminshall 		return;
122026048Sminshall 	}
122126048Sminshall 	sleep(2);
122226048Sminshall 	pswitch(1);
122326048Sminshall 	secndflag++;
122426448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
122526048Sminshall 		goto abort;
122626048Sminshall 	ptflag++;
122726048Sminshall 	(void) getreply(0);
122826048Sminshall 	pswitch(0);
122926048Sminshall 	(void) getreply(0);
123026048Sminshall 	(void) signal(SIGINT, oldintr);
123126048Sminshall 	switch (oldtype) {
123226048Sminshall 		case 0:
123326048Sminshall 			break;
123426048Sminshall 		case TYPE_A:
123526048Sminshall 			setascii();
123626048Sminshall 			break;
123726048Sminshall 		case TYPE_I:
123826048Sminshall 			setbinary();
123926048Sminshall 			break;
124026048Sminshall 		case TYPE_E:
124126048Sminshall 			setebcdic();
124226048Sminshall 			break;
124326048Sminshall 		case TYPE_L:
124426048Sminshall 			settenex();
124526048Sminshall 			break;
124626048Sminshall 	}
124726048Sminshall 	pswitch(1);
124826048Sminshall 	ptflag = 0;
124926048Sminshall 	printf("local: %s remote: %s\n", local, remote);
125026048Sminshall 	return;
125126048Sminshall abort:
125226048Sminshall 	(void) signal(SIGINT, SIG_IGN);
125326048Sminshall 	ptflag = 0;
125426448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
125526048Sminshall 		pswitch(1);
125626448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
125726048Sminshall 		pswitch(0);
125826048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
125926048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
126026048Sminshall 			pswitch(0);
126126048Sminshall 			switch (oldtype) {
126226048Sminshall 				case 0:
126326048Sminshall 					break;
126426048Sminshall 				case TYPE_A:
126526048Sminshall 					setascii();
126626048Sminshall 					break;
126726048Sminshall 				case TYPE_I:
126826048Sminshall 					setbinary();
126926048Sminshall 					break;
127026048Sminshall 				case TYPE_E:
127126048Sminshall 					setebcdic();
127226048Sminshall 					break;
127326048Sminshall 				case TYPE_L:
127426048Sminshall 					settenex();
127526048Sminshall 					break;
127626048Sminshall 			}
127727687Sminshall 			if (cpend) {
127826048Sminshall 				char msg[2];
127926048Sminshall 
128026048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
128126048Sminshall 				(void) fflush(cout);
128226048Sminshall 				*msg = IAC;
128326048Sminshall 				*(msg+1) = DM;
128426448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
128526048Sminshall 					perror("abort");
128626048Sminshall 				fprintf(cout,"ABOR\r\n");
128726048Sminshall 				(void) fflush(cout);
128827687Sminshall 				FD_ZERO(&mask);
128926496Sminshall 				FD_SET(fileno(cin), &mask);
129027687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
129127687Sminshall 					if (nfnd < 0) {
129227687Sminshall 						perror("abort");
129327687Sminshall 					}
129426448Slepreau 					if (ptabflg)
129526048Sminshall 						code = -1;
129626048Sminshall 					lostpeer();
129726048Sminshall 				}
129826048Sminshall 				(void) getreply(0);
129926048Sminshall 				(void) getreply(0);
130026048Sminshall 			}
130126048Sminshall 		}
130226048Sminshall 		pswitch(1);
130326448Slepreau 		if (ptabflg)
130426048Sminshall 			code = -1;
130526048Sminshall 		(void) signal(SIGINT, oldintr);
130626048Sminshall 		return;
130726048Sminshall 	}
130827687Sminshall 	if (cpend) {
130926048Sminshall 		char msg[2];
131026048Sminshall 
131126048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
131226048Sminshall 		(void) fflush(cout);
131326048Sminshall 		*msg = IAC;
131426048Sminshall 		*(msg+1) = DM;
131526448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
131626048Sminshall 			perror("abort");
131726048Sminshall 		fprintf(cout,"ABOR\r\n");
131826048Sminshall 		(void) fflush(cout);
131927687Sminshall 		FD_ZERO(&mask);
132026496Sminshall 		FD_SET(fileno(cin), &mask);
132127687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
132227687Sminshall 			if (nfnd < 0) {
132327687Sminshall 				perror("abort");
132427687Sminshall 			}
132526448Slepreau 			if (ptabflg)
132626048Sminshall 				code = -1;
132726048Sminshall 			lostpeer();
132826048Sminshall 		}
132926048Sminshall 		(void) getreply(0);
133026048Sminshall 		(void) getreply(0);
133126048Sminshall 	}
133226048Sminshall 	pswitch(!proxy);
133326048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
133426048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
133526048Sminshall 			pswitch(0);
133626048Sminshall 			switch (oldtype) {
133726048Sminshall 				case 0:
133826048Sminshall 					break;
133926048Sminshall 				case TYPE_A:
134026048Sminshall 					setascii();
134126048Sminshall 					break;
134226048Sminshall 				case TYPE_I:
134326048Sminshall 					setbinary();
134426048Sminshall 					break;
134526048Sminshall 				case TYPE_E:
134626048Sminshall 					setebcdic();
134726048Sminshall 					break;
134826048Sminshall 				case TYPE_L:
134926048Sminshall 					settenex();
135026048Sminshall 					break;
135126048Sminshall 			}
135227687Sminshall 			if (cpend) {
135326048Sminshall 				char msg[2];
135426048Sminshall 
135526048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
135626048Sminshall 				(void) fflush(cout);
135726048Sminshall 				*msg = IAC;
135826048Sminshall 				*(msg+1) = DM;
135926448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
136026048Sminshall 					perror("abort");
136126048Sminshall 				fprintf(cout,"ABOR\r\n");
136226048Sminshall 				(void) fflush(cout);
136327687Sminshall 				FD_ZERO(&mask);
136426496Sminshall 				FD_SET(fileno(cin), &mask);
136527687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
136627687Sminshall 					if (nfnd < 0) {
136727687Sminshall 						perror("abort");
136827687Sminshall 					}
136926448Slepreau 					if (ptabflg)
137026048Sminshall 						code = -1;
137126048Sminshall 					lostpeer();
137226048Sminshall 				}
137326048Sminshall 				(void) getreply(0);
137426048Sminshall 				(void) getreply(0);
137526048Sminshall 			}
137626048Sminshall 			pswitch(1);
137726448Slepreau 			if (ptabflg)
137826048Sminshall 				code = -1;
137926048Sminshall 			(void) signal(SIGINT, oldintr);
138026048Sminshall 			return;
138126048Sminshall 		}
138226048Sminshall 	}
138327687Sminshall 	if (cpend) {
138426048Sminshall 		char msg[2];
138526048Sminshall 
138626048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
138726048Sminshall 		(void) fflush(cout);
138826048Sminshall 		*msg = IAC;
138926048Sminshall 		*(msg+1) = DM;
139026448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
139126048Sminshall 			perror("abort");
139226048Sminshall 		fprintf(cout,"ABOR\r\n");
139326048Sminshall 		(void) fflush(cout);
139427687Sminshall 		FD_ZERO(&mask);
139526496Sminshall 		FD_SET(fileno(cin), &mask);
139627687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
139727687Sminshall 			if (nfnd < 0) {
139827687Sminshall 				perror("abort");
139927687Sminshall 			}
140026448Slepreau 			if (ptabflg)
140126048Sminshall 				code = -1;
140226048Sminshall 			lostpeer();
140326048Sminshall 		}
140426048Sminshall 		(void) getreply(0);
140526048Sminshall 		(void) getreply(0);
140626048Sminshall 	}
140726048Sminshall 	pswitch(!proxy);
140826048Sminshall 	if (cpend) {
140927687Sminshall 		FD_ZERO(&mask);
141026496Sminshall 		FD_SET(fileno(cin), &mask);
141127687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
141227687Sminshall 			if (nfnd < 0) {
141327687Sminshall 				perror("abort");
141427687Sminshall 			}
141526448Slepreau 			if (ptabflg)
141626048Sminshall 				code = -1;
141726048Sminshall 			lostpeer();
141826048Sminshall 		}
141926048Sminshall 		(void) getreply(0);
142026048Sminshall 		(void) getreply(0);
142126048Sminshall 	}
142226448Slepreau 	if (proxy)
142326048Sminshall 		pswitch(0);
142426048Sminshall 	switch (oldtype) {
142526048Sminshall 		case 0:
142626048Sminshall 			break;
142726048Sminshall 		case TYPE_A:
142826048Sminshall 			setascii();
142926048Sminshall 			break;
143026048Sminshall 		case TYPE_I:
143126048Sminshall 			setbinary();
143226048Sminshall 			break;
143326048Sminshall 		case TYPE_E:
143426048Sminshall 			setebcdic();
143526048Sminshall 			break;
143626048Sminshall 		case TYPE_L:
143726048Sminshall 			settenex();
143826048Sminshall 			break;
143926048Sminshall 	}
144026048Sminshall 	pswitch(1);
144126448Slepreau 	if (ptabflg)
144226048Sminshall 		code = -1;
144326048Sminshall 	(void) signal(SIGINT, oldintr);
144426048Sminshall }
144526048Sminshall 
144626048Sminshall reset()
144726048Sminshall {
144826496Sminshall 	struct fd_set mask;
144926496Sminshall 	int nfnd = 1;
145026048Sminshall 
145127687Sminshall 	FD_ZERO(&mask);
145230946Scsvsj 	while (nfnd > 0) {
145326496Sminshall 		FD_SET(fileno(cin), &mask);
145427687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
145526048Sminshall 			perror("reset");
145626048Sminshall 			code = -1;
145726048Sminshall 			lostpeer();
145826048Sminshall 		}
145927687Sminshall 		else if (nfnd) {
146026048Sminshall 			(void) getreply(0);
146126496Sminshall 		}
146226048Sminshall 	}
146326048Sminshall }
146426048Sminshall 
146526048Sminshall char *
146626048Sminshall gunique(local)
146726048Sminshall 	char *local;
146826048Sminshall {
146926048Sminshall 	static char new[MAXPATHLEN];
147026048Sminshall 	char *cp = rindex(local, '/');
147126048Sminshall 	int d, count=0;
147226048Sminshall 	char ext = '1';
147326048Sminshall 
147426448Slepreau 	if (cp)
147526048Sminshall 		*cp = '\0';
147626048Sminshall 	d = access(cp ? local : ".", 2);
147726448Slepreau 	if (cp)
147826048Sminshall 		*cp = '/';
147926048Sminshall 	if (d < 0) {
148026048Sminshall 		perror(local);
148126048Sminshall 		return((char *) 0);
148226048Sminshall 	}
148326048Sminshall 	(void) strcpy(new, local);
148426048Sminshall 	cp = new + strlen(new);
148526048Sminshall 	*cp++ = '.';
148626048Sminshall 	while (!d) {
148726048Sminshall 		if (++count == 100) {
148826048Sminshall 			printf("runique: can't find unique file name.\n");
148926048Sminshall 			return((char *) 0);
149026048Sminshall 		}
149126048Sminshall 		*cp++ = ext;
149226048Sminshall 		*cp = '\0';
149326448Slepreau 		if (ext == '9')
149426048Sminshall 			ext = '0';
149526448Slepreau 		else
149626048Sminshall 			ext++;
149726448Slepreau 		if ((d = access(new, 0)) < 0)
149826048Sminshall 			break;
149926448Slepreau 		if (ext != '0')
150026048Sminshall 			cp--;
150126448Slepreau 		else if (*(cp - 2) == '.')
150226048Sminshall 			*(cp - 1) = '1';
150326048Sminshall 		else {
150426048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
150526048Sminshall 			cp--;
150626048Sminshall 		}
150726048Sminshall 	}
150826048Sminshall 	return(new);
150926048Sminshall }
1510