xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 26496)
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*26496Sminshall static char sccsid[] = "@(#)ftp.c	5.9 (Berkeley) 03/07/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>
17*26496Sminshall #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;
38*26496Sminshall 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;
79*26496Sminshall 	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;
86*26496Sminshall 			perror((char *) 0);
8725904Skarels 			hp->h_addr_list++;
8825904Skarels 			bcopy(hp->h_addr_list[0],
8926048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
90*26496Sminshall 			fprintf(stdout, "Trying %s...\n",
9125904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9225904Skarels 			continue;
9325904Skarels 		}
9410296Ssam 		perror("ftp: connect");
9526048Sminshall 		code = -1;
9610296Ssam 		goto bad;
9710296Ssam 	}
9811627Ssam 	len = sizeof (myctladdr);
9911627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
10011627Ssam 		perror("ftp: getsockname");
10126048Sminshall 		code = -1;
10210296Ssam 		goto bad;
10310296Ssam 	}
10410296Ssam 	cin = fdopen(s, "r");
10510296Ssam 	cout = fdopen(s, "w");
10611219Ssam 	if (cin == NULL || cout == NULL) {
10710296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
10810296Ssam 		if (cin)
109*26496Sminshall 			(void) fclose(cin);
11010296Ssam 		if (cout)
111*26496Sminshall 			(void) fclose(cout);
11226048Sminshall 		code = -1;
11310296Ssam 		goto bad;
11410296Ssam 	}
11510296Ssam 	if (verbose)
11626067Sminshall 		printf("Connected to %s.\n", hostname);
11726048Sminshall 	if (getreply(0) != 2) { 	/* read startup message from server */
11826048Sminshall 		if (cin)
119*26496Sminshall 			(void) fclose(cin);
12026048Sminshall 		if (cout)
121*26496Sminshall 			(void) fclose(cout);
12226048Sminshall 		code = -1;
12326048Sminshall 		goto bad;
12426048Sminshall 	}
12526048Sminshall 
12626048Sminshall /* test to see if server command parser understands TELNET SYNC command */
12726048Sminshall 
12826048Sminshall 	fprintf(cout,"%c%c",IAC,NOP);
12926048Sminshall 	(void) fflush(cout);
13026048Sminshall 	*msg = IAC;
13126048Sminshall 	*(msg+1) = DM;
13226448Slepreau 	if (send(s,msg,2,MSG_OOB) != 2)
13326048Sminshall 		perror("sync");
13426048Sminshall 	oldverbose = verbose;
13526448Slepreau 	if (!debug)
13626048Sminshall 		verbose = -1;
13726448Slepreau 	if (command("NOOP") == COMPLETE)
13826048Sminshall 		telflag = 1;
13926448Slepreau 	else
14026048Sminshall 		telflag = 0;
14126048Sminshall 	verbose = oldverbose;
14225904Skarels 	return (hostname);
14310296Ssam bad:
144*26496Sminshall 	(void) close(s);
14525904Skarels 	return ((char *)0);
14610296Ssam }
14710296Ssam 
14825904Skarels login(host)
14925904Skarels 	char *host;
15010296Ssam {
15126048Sminshall 	char tmp[80];
152*26496Sminshall 	char *user, *pass, *acct, *getlogin(), *mygetpass();
15326048Sminshall 	int n, aflag = 0;
15410296Ssam 
15526048Sminshall 	user = pass = acct = 0;
15626048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
15726048Sminshall 		disconnect();
15826048Sminshall 		code = -1;
15926048Sminshall 		return(0);
16026048Sminshall 	}
16126048Sminshall 	if (user == NULL) {
16226048Sminshall 		char *myname = getlogin();
16326048Sminshall 
16426048Sminshall 		if (myname == NULL) {
16526048Sminshall 			struct passwd *pp = getpwuid(getuid());
16626048Sminshall 
16726448Slepreau 			if (pp != NULL)
16826048Sminshall 				myname = pp->pw_name;
16926048Sminshall 		}
17026048Sminshall 		printf("Name (%s:%s): ", host, myname);
17126048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
17226048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
17326448Slepreau 		if (*tmp == '\0')
17426048Sminshall 			user = myname;
17526448Slepreau 		else
17626048Sminshall 			user = tmp;
17726048Sminshall 	}
17810296Ssam 	n = command("USER %s", user);
17926048Sminshall 	if (n == CONTINUE) {
18026448Slepreau 		if (pass == NULL)
181*26496Sminshall 			pass = mygetpass("Password:");
18210296Ssam 		n = command("PASS %s", pass);
18326048Sminshall 	}
18410296Ssam 	if (n == CONTINUE) {
18526048Sminshall 		aflag++;
186*26496Sminshall 		acct = mygetpass("Account:");
18710296Ssam 		n = command("ACCT %s", acct);
18810296Ssam 	}
18910296Ssam 	if (n != COMPLETE) {
19010296Ssam 		fprintf(stderr, "Login failed.\n");
19110296Ssam 		return (0);
19210296Ssam 	}
19326448Slepreau 	if (!aflag && acct != NULL)
19426048Sminshall 		(void) command("ACCT %s", acct);
19526448Slepreau 	if (proxy)
19626048Sminshall 		return(1);
19726048Sminshall 	for (n = 0; n < macnum; ++n) {
19826048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
199*26496Sminshall 			(void) strcpy(line, "$init");
20026048Sminshall 			makeargv();
20126048Sminshall 			domacro(margc, margv);
20226048Sminshall 			break;
20326048Sminshall 		}
20426048Sminshall 	}
20510296Ssam 	return (1);
20610296Ssam }
20710296Ssam 
20826048Sminshall cmdabort()
20926048Sminshall {
21026048Sminshall 	extern jmp_buf ptabort;
21126048Sminshall 
21226048Sminshall 	printf("\n");
21326048Sminshall 	(void) fflush(stdout);
21426048Sminshall 	abrtflag++;
21526448Slepreau 	if (ptflag)
21626048Sminshall 		longjmp(ptabort,1);
21726048Sminshall }
21826048Sminshall 
219*26496Sminshall /*VARARGS1*/
22010296Ssam command(fmt, args)
22110296Ssam 	char *fmt;
22210296Ssam {
22326048Sminshall 	int r, (*oldintr)(), cmdabort();
22410296Ssam 
22526048Sminshall 	abrtflag = 0;
22610296Ssam 	if (debug) {
22710296Ssam 		printf("---> ");
22810296Ssam 		_doprnt(fmt, &args, stdout);
22910296Ssam 		printf("\n");
23010296Ssam 		(void) fflush(stdout);
23110296Ssam 	}
23211219Ssam 	if (cout == NULL) {
23311219Ssam 		perror ("No control connection for command");
23426048Sminshall 		code = -1;
23511219Ssam 		return (0);
23611219Ssam 	}
23726048Sminshall 	oldintr = signal(SIGINT,cmdabort);
23810296Ssam 	_doprnt(fmt, &args, cout);
23910296Ssam 	fprintf(cout, "\r\n");
24010296Ssam 	(void) fflush(cout);
24126048Sminshall 	cpend = 1;
24226048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
24326448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
24426048Sminshall 		(*oldintr)();
24526048Sminshall 	(void) signal(SIGINT, oldintr);
24626048Sminshall 	return(r);
24710296Ssam }
24810296Ssam 
24910296Ssam #include <ctype.h>
25010296Ssam 
25110296Ssam getreply(expecteof)
25210296Ssam 	int expecteof;
25310296Ssam {
25411219Ssam 	register int c, n;
25526048Sminshall 	register int dig;
25626048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
25726048Sminshall 	int pflag = 0;
25826048Sminshall 	char *pt = pasv;
25910296Ssam 
26026048Sminshall 	oldintr = signal(SIGINT,cmdabort);
26110296Ssam 	for (;;) {
26210296Ssam 		dig = n = code = 0;
26310296Ssam 		while ((c = getc(cin)) != '\n') {
26410296Ssam 			dig++;
26510296Ssam 			if (c == EOF) {
26626048Sminshall 				if (expecteof) {
26726048Sminshall 					(void) signal(SIGINT,oldintr);
26826048Sminshall 					code = 221;
26910296Ssam 					return (0);
27026048Sminshall 				}
27110296Ssam 				lostpeer();
27226048Sminshall 				if (verbose) {
27326048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
27426048Sminshall 					(void) fflush(stdout);
27526048Sminshall 					code = 421;
27626048Sminshall 					return(4);
27726048Sminshall 				}
27810296Ssam 			}
27926048Sminshall 			if (c != '\r' && (verbose > 0 ||
28026048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
28126448Slepreau 				if (proxflag &&
28226448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
28326048Sminshall 					printf("%s:",hostname);
284*26496Sminshall 				(void) putchar(c);
28526048Sminshall 			}
28610296Ssam 			if (dig < 4 && isdigit(c))
28710296Ssam 				code = code * 10 + (c - '0');
28826448Slepreau 			if (!pflag && code == 227)
28926048Sminshall 				pflag = 1;
29026448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
29126048Sminshall 				pflag = 2;
29226048Sminshall 			if (pflag == 2) {
29326448Slepreau 				if (c != '\r' && c != ')')
29426048Sminshall 					*pt++ = c;
29526048Sminshall 				else {
29626048Sminshall 					*pt = '\0';
29726048Sminshall 					pflag = 3;
29826048Sminshall 				}
29926048Sminshall 			}
30026048Sminshall 			if (dig == 4 && c == '-') {
30126448Slepreau 				if (continuation)
30226048Sminshall 					code = 0;
30310296Ssam 				continuation++;
30426048Sminshall 			}
30510296Ssam 			if (n == 0)
30610296Ssam 				n = c;
30710296Ssam 		}
30826048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
309*26496Sminshall 			(void) putchar(c);
31011346Ssam 			(void) fflush (stdout);
31111346Ssam 		}
31210296Ssam 		if (continuation && code != originalcode) {
31310296Ssam 			if (originalcode == 0)
31410296Ssam 				originalcode = code;
31510296Ssam 			continue;
31610296Ssam 		}
31726448Slepreau 		if (n != '1')
31826048Sminshall 			cpend = 0;
31926048Sminshall 		(void) signal(SIGINT,oldintr);
32026448Slepreau 		if (code == 421 || originalcode == 421)
32126048Sminshall 			lostpeer();
32226448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
32326048Sminshall 			(*oldintr)();
32425907Smckusick 		return (n - '0');
32510296Ssam 	}
32610296Ssam }
32710296Ssam 
32826048Sminshall empty(mask, sec)
329*26496Sminshall 	struct fd_set mask;
33026048Sminshall 	int sec;
33126048Sminshall {
33226048Sminshall 	struct timeval t;
33326048Sminshall 
33426048Sminshall 	t.tv_sec = (long) sec;
33526048Sminshall 	t.tv_usec = 0;
336*26496Sminshall 	if (select(20, &mask, (struct fd_set *) 0, (struct fd_set *) 0, &t) < 0)
33726048Sminshall 		return(-1);
338*26496Sminshall 	return (1);
33926048Sminshall }
34026048Sminshall 
34110296Ssam jmp_buf	sendabort;
34210296Ssam 
34310296Ssam abortsend()
34410296Ssam {
34510296Ssam 
34626048Sminshall 	mflag = 0;
34726048Sminshall 	abrtflag = 0;
34826048Sminshall 	printf("\nsend aborted\n");
34926048Sminshall 	(void) fflush(stdout);
35010296Ssam 	longjmp(sendabort, 1);
35110296Ssam }
35210296Ssam 
35310296Ssam sendrequest(cmd, local, remote)
35410296Ssam 	char *cmd, *local, *remote;
35510296Ssam {
356*26496Sminshall 	FILE *fin, *dout = 0, *mypopen();
357*26496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
35826048Sminshall 	int abortsend();
35911219Ssam 	char buf[BUFSIZ];
36011651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
36111346Ssam 	register int c, d;
36210296Ssam 	struct stat st;
36310296Ssam 	struct timeval start, stop;
36410296Ssam 
36526048Sminshall 	if (proxy) {
36626048Sminshall 		proxtrans(cmd, local, remote);
36726048Sminshall 		return;
36826048Sminshall 	}
36910296Ssam 	closefunc = NULL;
37026048Sminshall 	oldintr = NULL;
37126048Sminshall 	oldintp = NULL;
37226048Sminshall 	if (setjmp(sendabort)) {
37326048Sminshall 		while (cpend) {
37426048Sminshall 			(void) getreply(0);
37526048Sminshall 		}
37626048Sminshall 		if (data >= 0) {
37726048Sminshall 			(void) close(data);
37826048Sminshall 			data = -1;
37926048Sminshall 		}
38026448Slepreau 		if (oldintr)
38126048Sminshall 			(void) signal(SIGINT,oldintr);
38226448Slepreau 		if (oldintp)
38326048Sminshall 			(void) signal(SIGPIPE,oldintp);
38426048Sminshall 		code = -1;
38526048Sminshall 		return;
38626048Sminshall 	}
38710296Ssam 	oldintr = signal(SIGINT, abortsend);
38810296Ssam 	if (strcmp(local, "-") == 0)
38910296Ssam 		fin = stdin;
39010296Ssam 	else if (*local == '|') {
39126048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
392*26496Sminshall 		fin = mypopen(local + 1, "r");
39310296Ssam 		if (fin == NULL) {
39426048Sminshall 			perror(local + 1);
39526048Sminshall 			(void) signal(SIGINT, oldintr);
39626048Sminshall 			(void) signal(SIGPIPE, oldintp);
39726048Sminshall 			code = -1;
39826048Sminshall 			return;
39910296Ssam 		}
400*26496Sminshall 		closefunc = mypclose;
40110296Ssam 	} else {
40210296Ssam 		fin = fopen(local, "r");
40310296Ssam 		if (fin == NULL) {
40410296Ssam 			perror(local);
40526048Sminshall 			(void) signal(SIGINT, oldintr);
40626048Sminshall 			code = -1;
40726048Sminshall 			return;
40810296Ssam 		}
40910296Ssam 		closefunc = fclose;
41010296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
41110296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
412*26496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
41326048Sminshall 			(void) signal(SIGINT, oldintr);
41426048Sminshall 			code = -1;
41526048Sminshall 			return;
41610296Ssam 		}
41710296Ssam 	}
41826048Sminshall 	if (initconn()) {
41926048Sminshall 		(void) signal(SIGINT, oldintr);
42026448Slepreau 		if (oldintp)
42126048Sminshall 			(void) signal(SIGPIPE, oldintp);
42226048Sminshall 		code = -1;
42326048Sminshall 		return;
42426048Sminshall 	}
42526448Slepreau 	if (setjmp(sendabort))
42626048Sminshall 		goto abort;
42710296Ssam 	if (remote) {
42826048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
42926048Sminshall 			(void) signal(SIGINT, oldintr);
43026448Slepreau 			if (oldintp)
43126048Sminshall 				(void) signal(SIGPIPE, oldintp);
43226048Sminshall 			return;
43326048Sminshall 		}
43410296Ssam 	} else
43526048Sminshall 		if (command("%s", cmd) != PRELIM) {
43626048Sminshall 			(void) signal(SIGINT, oldintr);
43726448Slepreau 			if (oldintp)
43826048Sminshall 				(void) signal(SIGPIPE, oldintp);
43926048Sminshall 			return;
44026048Sminshall 		}
44110296Ssam 	dout = dataconn("w");
44226448Slepreau 	if (dout == NULL)
44326048Sminshall 		goto abort;
444*26496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
44511219Ssam 	switch (type) {
44611219Ssam 
44711219Ssam 	case TYPE_I:
44811219Ssam 	case TYPE_L:
44911346Ssam 		errno = d = 0;
45011219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
45111346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
45211219Ssam 				break;
45311219Ssam 			bytes += c;
45411651Ssam 			if (hash) {
455*26496Sminshall 				(void) putchar('#');
456*26496Sminshall 				(void) fflush(stdout);
45711651Ssam 			}
45811219Ssam 		}
45913213Ssam 		if (hash && bytes > 0) {
460*26496Sminshall 			(void) putchar('\n');
461*26496Sminshall 			(void) fflush(stdout);
46211651Ssam 		}
46311219Ssam 		if (c < 0)
46411219Ssam 			perror(local);
46511346Ssam 		if (d < 0)
46611219Ssam 			perror("netout");
46711219Ssam 		break;
46811219Ssam 
46911219Ssam 	case TYPE_A:
47011219Ssam 		while ((c = getc(fin)) != EOF) {
47111219Ssam 			if (c == '\n') {
47211651Ssam 				while (hash && (bytes >= hashbytes)) {
473*26496Sminshall 					(void) putchar('#');
474*26496Sminshall 					(void) fflush(stdout);
47511651Ssam 					hashbytes += sizeof (buf);
47611651Ssam 				}
47711219Ssam 				if (ferror(dout))
47811219Ssam 					break;
479*26496Sminshall 				(void) putc('\r', dout);
48011219Ssam 				bytes++;
48111219Ssam 			}
482*26496Sminshall 			(void) putc(c, dout);
48311219Ssam 			bytes++;
48426048Sminshall 	/*		if (c == '\r') {			  	*/
485*26496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
48626048Sminshall 	/*			bytes++;				*/
48726048Sminshall 	/*		}                          			*/
48811219Ssam 		}
48911651Ssam 		if (hash) {
49013213Ssam 			if (bytes < hashbytes)
491*26496Sminshall 				(void) putchar('#');
492*26496Sminshall 			(void) putchar('\n');
493*26496Sminshall 			(void) fflush(stdout);
49411651Ssam 		}
49511219Ssam 		if (ferror(fin))
49611219Ssam 			perror(local);
49711346Ssam 		if (ferror(dout))
49811219Ssam 			perror("netout");
49911219Ssam 		break;
50010296Ssam 	}
501*26496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
50210296Ssam 	if (closefunc != NULL)
50326048Sminshall 		(*closefunc)(fin);
50410296Ssam 	(void) fclose(dout);
50526048Sminshall 	(void) getreply(0);
50626048Sminshall 	(void) signal(SIGINT, oldintr);
50710296Ssam 	if (bytes > 0 && verbose)
50826048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
50910296Ssam 	return;
51026048Sminshall abort:
511*26496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
51226048Sminshall 	(void) signal(SIGINT, oldintr);
51326448Slepreau 	if (oldintp)
51426048Sminshall 		(void) signal(SIGPIPE, oldintp);
51526048Sminshall 	if (!cpend) {
51626048Sminshall 		code = -1;
51726048Sminshall 		return;
51826048Sminshall 	}
51926048Sminshall 	if (data >= 0) {
52026048Sminshall 		(void) close(data);
52126048Sminshall 		data = -1;
52226048Sminshall 	}
52326448Slepreau 	if (dout)
52426048Sminshall 		(void) fclose(dout);
52526048Sminshall 	(void) getreply(0);
52626048Sminshall 	code = -1;
52710296Ssam 	if (closefunc != NULL && fin != NULL)
52826048Sminshall 		(*closefunc)(fin);
52926048Sminshall 	if (bytes > 0 && verbose)
53026048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53110296Ssam }
53210296Ssam 
53310296Ssam jmp_buf	recvabort;
53410296Ssam 
53510296Ssam abortrecv()
53610296Ssam {
53710296Ssam 
53826048Sminshall 	mflag = 0;
53926048Sminshall 	abrtflag = 0;
54026048Sminshall 	printf("\n");
54126048Sminshall 	(void) fflush(stdout);
54210296Ssam 	longjmp(recvabort, 1);
54310296Ssam }
54410296Ssam 
54511651Ssam recvrequest(cmd, local, remote, mode)
54611651Ssam 	char *cmd, *local, *remote, *mode;
54710296Ssam {
548*26496Sminshall 	FILE *fout, *din = 0, *mypopen();
549*26496Sminshall 	int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)();
55026048Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag;
55126048Sminshall 	char buf[BUFSIZ], *gunique();
552*26496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
553*26496Sminshall 	struct fd_set mask;
55411346Ssam 	register int c, d;
55510296Ssam 	struct timeval start, stop;
55610296Ssam 
55726048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
55826048Sminshall 		proxtrans(cmd, local, remote);
55926048Sminshall 		return;
56026048Sminshall 	}
56110296Ssam 	closefunc = NULL;
56226048Sminshall 	oldintr = NULL;
56326048Sminshall 	oldintp = NULL;
56426048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
56526048Sminshall 	if (setjmp(recvabort)) {
56626048Sminshall 		while (cpend) {
56726048Sminshall 			(void) getreply(0);
56826048Sminshall 		}
56926048Sminshall 		if (data >= 0) {
57026048Sminshall 			(void) close(data);
57126048Sminshall 			data = -1;
57226048Sminshall 		}
57326448Slepreau 		if (oldintr)
57426048Sminshall 			(void) signal(SIGINT, oldintr);
57526048Sminshall 		code = -1;
57626048Sminshall 		return;
57726048Sminshall 	}
57810296Ssam 	oldintr = signal(SIGINT, abortrecv);
57926048Sminshall 	if (strcmp(local, "-") && *local != '|') {
58010296Ssam 		if (access(local, 2) < 0) {
58126048Sminshall 			char *dir = rindex(local, '/');
58210296Ssam 
58326048Sminshall 			if (errno != ENOENT && errno != EACCES) {
58410296Ssam 				perror(local);
58526048Sminshall 				(void) signal(SIGINT, oldintr);
58626048Sminshall 				code = -1;
58726048Sminshall 				return;
58810296Ssam 			}
58926048Sminshall 			if (dir != NULL)
59026048Sminshall 				*dir = 0;
59126048Sminshall 			d = access(dir ? local : ".", 2);
59226048Sminshall 			if (dir != NULL)
59326048Sminshall 				*dir = '/';
59426048Sminshall 			if (d < 0) {
59526048Sminshall 				perror(local);
59626048Sminshall 				(void) signal(SIGINT, oldintr);
59726048Sminshall 				code = -1;
59826048Sminshall 				return;
59926048Sminshall 			}
60026048Sminshall 			if (!runique && errno == EACCES &&
60126048Sminshall 			    chmod(local,0600) < 0) {
60226048Sminshall 				perror(local);
60326048Sminshall 				(void) signal(SIGINT, oldintr);
60426048Sminshall 				code = -1;
60526048Sminshall 				return;
60626048Sminshall 			}
60726048Sminshall 			if (runique && errno == EACCES &&
60826048Sminshall 			   (local = gunique(local)) == NULL) {
60926048Sminshall 				(void) signal(SIGINT, oldintr);
61026048Sminshall 				code = -1;
61126048Sminshall 				return;
61226048Sminshall 			}
61310296Ssam 		}
61426048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
61526048Sminshall 			(void) signal(SIGINT, oldintr);
61626048Sminshall 			code = -1;
61726048Sminshall 			return;
61826048Sminshall 		}
61926048Sminshall 	}
62026048Sminshall 	if (initconn()) {
62126048Sminshall 		(void) signal(SIGINT, oldintr);
62226048Sminshall 		code = -1;
62326048Sminshall 		return;
62426048Sminshall 	}
62526448Slepreau 	if (setjmp(recvabort))
62626048Sminshall 		goto abort;
62726048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
62826048Sminshall 		oldtype = type;
62926048Sminshall 		oldverbose = verbose;
63026448Slepreau 		if (!debug)
63126048Sminshall 			verbose = 0;
63226048Sminshall 		setascii();
63326048Sminshall 		verbose = oldverbose;
63426048Sminshall 	}
63510296Ssam 	if (remote) {
63626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
63726048Sminshall 			(void) signal(SIGINT, oldintr);
63826048Sminshall 			if (oldtype) {
63926448Slepreau 				if (!debug)
64026048Sminshall 					verbose = 0;
64126048Sminshall 				switch (oldtype) {
64226048Sminshall 					case TYPE_I:
64326048Sminshall 						setbinary();
64426048Sminshall 						break;
64526048Sminshall 					case TYPE_E:
64626048Sminshall 						setebcdic();
64726048Sminshall 						break;
64826048Sminshall 					case TYPE_L:
64926048Sminshall 						settenex();
65026048Sminshall 						break;
65126048Sminshall 				}
65226048Sminshall 				verbose = oldverbose;
65326048Sminshall 			}
65426048Sminshall 			return;
65526048Sminshall 		}
65626048Sminshall 	} else {
65726048Sminshall 		if (command("%s", cmd) != PRELIM) {
65826048Sminshall 			(void) signal(SIGINT, oldintr);
65926048Sminshall 			if (oldtype) {
66026448Slepreau 				if (!debug)
66126048Sminshall 					verbose = 0;
66226048Sminshall 				switch (oldtype) {
66326048Sminshall 					case TYPE_I:
66426048Sminshall 						setbinary();
66526048Sminshall 						break;
66626048Sminshall 					case TYPE_E:
66726048Sminshall 						setebcdic();
66826048Sminshall 						break;
66926048Sminshall 					case TYPE_L:
67026048Sminshall 						settenex();
67126048Sminshall 						break;
67226048Sminshall 				}
67326048Sminshall 				verbose = oldverbose;
67426048Sminshall 			}
67526048Sminshall 			return;
67626048Sminshall 		}
67726048Sminshall 	}
67826048Sminshall 	din = dataconn("r");
67926048Sminshall 	if (din == NULL)
68026048Sminshall 		goto abort;
68126448Slepreau 	if (strcmp(local, "-") == 0)
68210296Ssam 		fout = stdout;
68310296Ssam 	else if (*local == '|') {
68426048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
685*26496Sminshall 		fout = mypopen(local + 1, "w");
68626048Sminshall 		if (fout == NULL) {
68726048Sminshall 			perror(local+1);
68826048Sminshall 			goto abort;
68926048Sminshall 		}
690*26496Sminshall 		closefunc = mypclose;
69126048Sminshall 	}
69226048Sminshall 	else {
69311651Ssam 		fout = fopen(local, mode);
69426048Sminshall 		if (fout == NULL) {
69526048Sminshall 			perror(local);
69626048Sminshall 			goto abort;
69726048Sminshall 		}
69810296Ssam 		closefunc = fclose;
69910296Ssam 	}
700*26496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
70111219Ssam 	switch (type) {
70211219Ssam 
70311219Ssam 	case TYPE_I:
70411219Ssam 	case TYPE_L:
70511346Ssam 		errno = d = 0;
70611219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
70711346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
70811219Ssam 				break;
70911219Ssam 			bytes += c;
71011651Ssam 			if (hash) {
711*26496Sminshall 				(void) putchar('#');
712*26496Sminshall 				(void) fflush(stdout);
71311651Ssam 			}
71411219Ssam 		}
71513213Ssam 		if (hash && bytes > 0) {
716*26496Sminshall 			(void) putchar('\n');
717*26496Sminshall 			(void) fflush(stdout);
71811651Ssam 		}
71911219Ssam 		if (c < 0)
72011219Ssam 			perror("netin");
72111346Ssam 		if (d < 0)
72210296Ssam 			perror(local);
72311219Ssam 		break;
72411219Ssam 
72511219Ssam 	case TYPE_A:
72611219Ssam 		while ((c = getc(din)) != EOF) {
72711219Ssam 			if (c == '\r') {
72811651Ssam 				while (hash && (bytes >= hashbytes)) {
729*26496Sminshall 					(void) putchar('#');
730*26496Sminshall 					(void) fflush(stdout);
73111651Ssam 					hashbytes += sizeof (buf);
73211651Ssam 				}
73310296Ssam 				bytes++;
73426048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
73511219Ssam 					if (ferror (fout))
73611219Ssam 						break;
737*26496Sminshall 					(void) putc ('\r', fout);
73811219Ssam 				}
73926048Sminshall 				/*if (c == '\0') {
74011219Ssam 					bytes++;
74111219Ssam 					continue;
74226048Sminshall 				}*/
74311219Ssam 			}
744*26496Sminshall 			(void) putc (c, fout);
74511219Ssam 			bytes++;
74610296Ssam 		}
74711651Ssam 		if (hash) {
74813213Ssam 			if (bytes < hashbytes)
749*26496Sminshall 				(void) putchar('#');
750*26496Sminshall 			(void) putchar('\n');
751*26496Sminshall 			(void) fflush(stdout);
75211651Ssam 		}
75311219Ssam 		if (ferror (din))
75411219Ssam 			perror ("netin");
75511219Ssam 		if (ferror (fout))
75611219Ssam 			perror (local);
75711219Ssam 		break;
75810296Ssam 	}
75926448Slepreau 	if (closefunc != NULL)
76026048Sminshall 		(*closefunc)(fout);
761*26496Sminshall 	(void) signal(SIGINT, oldintr);
76226448Slepreau 	if (oldintp)
76326048Sminshall 		(void) signal(SIGPIPE, oldintp);
764*26496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
76510296Ssam 	(void) fclose(din);
76626048Sminshall 	(void) getreply(0);
76726048Sminshall 	if (bytes > 0 && verbose)
76826048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
76926048Sminshall 	if (oldtype) {
77026448Slepreau 		if (!debug)
77126048Sminshall 			verbose = 0;
77226048Sminshall 		switch (oldtype) {
77326048Sminshall 			case TYPE_I:
77426048Sminshall 				setbinary();
77526048Sminshall 				break;
77626048Sminshall 			case TYPE_E:
77726048Sminshall 				setebcdic();
77826048Sminshall 				break;
77926048Sminshall 			case TYPE_L:
78026048Sminshall 				settenex();
78126048Sminshall 				break;
78226048Sminshall 		}
78326048Sminshall 		verbose = oldverbose;
78426048Sminshall 	}
78526048Sminshall 	return;
78626048Sminshall abort:
78726048Sminshall 
78826048Sminshall /* if server command parser understands TELNET commands, abort using */
78926048Sminshall /* recommended IP,SYNC sequence                                      */
79026048Sminshall 
791*26496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
79226448Slepreau 	if (oldintp)
79326048Sminshall 		(void) signal(SIGPIPE, oldintr);
79426048Sminshall 	(void) signal(SIGINT,SIG_IGN);
79526048Sminshall 	if (oldtype) {
79626448Slepreau 		if (!debug)
79726048Sminshall 			verbose = 0;
79826048Sminshall 		switch (oldtype) {
79926048Sminshall 			case TYPE_I:
80026048Sminshall 				setbinary();
80126048Sminshall 				break;
80226048Sminshall 			case TYPE_E:
80326048Sminshall 				setebcdic();
80426048Sminshall 				break;
80526048Sminshall 			case TYPE_L:
80626048Sminshall 				settenex();
80726048Sminshall 				break;
80826048Sminshall 		}
80926048Sminshall 		verbose = oldverbose;
81026048Sminshall 	}
81126048Sminshall 	if (!cpend) {
81226048Sminshall 		code = -1;
81326048Sminshall 		(void) signal(SIGINT,oldintr);
81426048Sminshall 		return;
81526048Sminshall 	}
81626048Sminshall 	if (telflag) {
81726048Sminshall 		char msg[2];
81826048Sminshall 
81926048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
82026048Sminshall 		(void) fflush(cout);
82126048Sminshall 		*msg = IAC;
82226048Sminshall 		*(msg+1) = DM;
82326448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
82426048Sminshall 			perror("abort");
82526048Sminshall 	}
82626048Sminshall 	fprintf(cout,"ABOR\r\n");
82726048Sminshall 	(void) fflush(cout);
828*26496Sminshall 	FD_ZERO((char *) &mask);
829*26496Sminshall 	FD_SET(fileno(cin), &mask);
830*26496Sminshall 	if (din) {
831*26496Sminshall 		FD_SET(fileno(din), &mask);
832*26496Sminshall 	}
833*26496Sminshall 	if (empty(mask,10) < 0) {
83426048Sminshall 		perror("abort");
83526048Sminshall 		code = -1;
83626048Sminshall 		lostpeer();
83726048Sminshall 	}
838*26496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
83926448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
84026448Slepreau 			;
841*26496Sminshall 	}
84226048Sminshall 	if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */
84326048Sminshall 		if (data >= 0) {
844*26496Sminshall 			(void) close(data);
84526048Sminshall 			data = -1;
84626048Sminshall 		}
84725907Smckusick 		(void) getreply(0);
84825907Smckusick 	}
84926048Sminshall 	(void) getreply(0);
85026048Sminshall 	code = -1;
85126048Sminshall 	if (data >= 0) {
85226048Sminshall 		(void) close(data);
85326048Sminshall 		data = -1;
85426048Sminshall 	}
85526448Slepreau 	if (closefunc != NULL && fout != NULL)
85626048Sminshall 		(*closefunc)(fout);
85726448Slepreau 	if (din)
85826048Sminshall 		(void) fclose(din);
85910296Ssam 	if (bytes > 0 && verbose)
86026048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
86126048Sminshall 	(void) signal(SIGINT,oldintr);
86210296Ssam }
86310296Ssam 
86410296Ssam /*
86510296Ssam  * Need to start a listen on the data channel
86610296Ssam  * before we send the command, otherwise the
86710296Ssam  * server's connect may fail.
86810296Ssam  */
86911651Ssam static int sendport = -1;
87011651Ssam 
87110296Ssam initconn()
87210296Ssam {
87310296Ssam 	register char *p, *a;
87426048Sminshall 	int result, len, tmpno = 0;
875*26496Sminshall 	char on = 1;
87610296Ssam 
87711651Ssam noport:
87810296Ssam 	data_addr = myctladdr;
87911651Ssam 	if (sendport)
88011651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
88111651Ssam 	if (data != -1)
88211651Ssam 		(void) close (data);
88318287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
88410296Ssam 	if (data < 0) {
88510296Ssam 		perror("ftp: socket");
88626448Slepreau 		if (tmpno)
88726048Sminshall 			sendport = 1;
88810296Ssam 		return (1);
88910296Ssam 	}
89012397Ssam 	if (!sendport)
89117450Slepreau 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
89226048Sminshall 			perror("ftp: setsockopt (resuse address)");
89312397Ssam 			goto bad;
89412397Ssam 		}
895*26496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
89610296Ssam 		perror("ftp: bind");
89710296Ssam 		goto bad;
89810296Ssam 	}
89910296Ssam 	if (options & SO_DEBUG &&
90017450Slepreau 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
90110296Ssam 		perror("ftp: setsockopt (ignored)");
90211627Ssam 	len = sizeof (data_addr);
90311627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
90411627Ssam 		perror("ftp: getsockname");
90510296Ssam 		goto bad;
90610296Ssam 	}
90726448Slepreau 	if (listen(data, 1) < 0)
90810296Ssam 		perror("ftp: listen");
90911651Ssam 	if (sendport) {
91011651Ssam 		a = (char *)&data_addr.sin_addr;
91111651Ssam 		p = (char *)&data_addr.sin_port;
91210296Ssam #define	UC(b)	(((int)b)&0xff)
91311651Ssam 		result =
91411651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
91511651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
91611651Ssam 		      UC(p[0]), UC(p[1]));
91711651Ssam 		if (result == ERROR && sendport == -1) {
91811651Ssam 			sendport = 0;
91926048Sminshall 			tmpno = 1;
92011651Ssam 			goto noport;
92111651Ssam 		}
92211651Ssam 		return (result != COMPLETE);
92311651Ssam 	}
92426448Slepreau 	if (tmpno)
92526048Sminshall 		sendport = 1;
92611651Ssam 	return (0);
92710296Ssam bad:
92810296Ssam 	(void) close(data), data = -1;
92926448Slepreau 	if (tmpno)
93026048Sminshall 		sendport = 1;
93110296Ssam 	return (1);
93210296Ssam }
93310296Ssam 
93410296Ssam FILE *
93510296Ssam dataconn(mode)
93610296Ssam 	char *mode;
93710296Ssam {
93810296Ssam 	struct sockaddr_in from;
93910296Ssam 	int s, fromlen = sizeof (from);
94010296Ssam 
941*26496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
94210296Ssam 	if (s < 0) {
94310296Ssam 		perror("ftp: accept");
94410296Ssam 		(void) close(data), data = -1;
94510296Ssam 		return (NULL);
94610296Ssam 	}
94710296Ssam 	(void) close(data);
94810296Ssam 	data = s;
94910296Ssam 	return (fdopen(data, mode));
95010296Ssam }
95110296Ssam 
95226048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
95326048Sminshall 	char *direction, *local, *remote;
95411651Ssam 	long bytes;
95510296Ssam 	struct timeval *t0, *t1;
95610296Ssam {
95710296Ssam 	struct timeval td;
95816437Sleres 	float s, bs;
95910296Ssam 
96010296Ssam 	tvsub(&td, t1, t0);
96116437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
96210296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
96316437Sleres 	bs = bytes / nz(s);
96426448Slepreau 	if (local && *local != '-')
96526048Sminshall 		printf("local: %s ", local);
96626448Slepreau 	if (remote)
96726048Sminshall 		printf("remote: %s\n", remote);
96816437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
96916437Sleres 		bytes, direction, s, bs / 1024.);
97010296Ssam }
97110296Ssam 
972*26496Sminshall /*tvadd(tsum, t0)
97310296Ssam 	struct timeval *tsum, *t0;
97410296Ssam {
97510296Ssam 
97610296Ssam 	tsum->tv_sec += t0->tv_sec;
97710296Ssam 	tsum->tv_usec += t0->tv_usec;
97810296Ssam 	if (tsum->tv_usec > 1000000)
97910296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
980*26496Sminshall } */
98110296Ssam 
98210296Ssam tvsub(tdiff, t1, t0)
98310296Ssam 	struct timeval *tdiff, *t1, *t0;
98410296Ssam {
98510296Ssam 
98610296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
98710296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
98810296Ssam 	if (tdiff->tv_usec < 0)
98910296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
99010296Ssam }
99126048Sminshall 
99226048Sminshall psabort()
99326048Sminshall {
99426048Sminshall 	extern int abrtflag;
99526048Sminshall 
99626048Sminshall 	abrtflag++;
99726048Sminshall }
99826048Sminshall 
99926048Sminshall pswitch(flag)
100026048Sminshall 	int flag;
100126048Sminshall {
100226048Sminshall 	extern int proxy, abrtflag;
100326048Sminshall 	int (*oldintr)();
100426048Sminshall 	static struct comvars {
100526048Sminshall 		int connect;
100626048Sminshall 		char name[32];
100726048Sminshall 		struct sockaddr_in mctl;
100826048Sminshall 		struct sockaddr_in hctl;
100926048Sminshall 		FILE *in;
101026048Sminshall 		FILE *out;
101126048Sminshall 		int tflag;
101226048Sminshall 		int tpe;
101326048Sminshall 		int cpnd;
101426048Sminshall 		int sunqe;
101526048Sminshall 		int runqe;
101626048Sminshall 		int mcse;
101726048Sminshall 		int ntflg;
101826048Sminshall 		char nti[17];
101926048Sminshall 		char nto[17];
102026048Sminshall 		int mapflg;
102126048Sminshall 		char mi[MAXPATHLEN];
102226048Sminshall 		char mo[MAXPATHLEN];
102326048Sminshall 		} proxstruct, tmpstruct;
102426048Sminshall 	struct comvars *ip, *op;
102526048Sminshall 
102626048Sminshall 	abrtflag = 0;
102726048Sminshall 	oldintr = signal(SIGINT, psabort);
102826048Sminshall 	if (flag) {
102926448Slepreau 		if (proxy)
103026048Sminshall 			return;
103126048Sminshall 		ip = &tmpstruct;
103226048Sminshall 		op = &proxstruct;
103326048Sminshall 		proxy++;
103426048Sminshall 	}
103526048Sminshall 	else {
103626448Slepreau 		if (!proxy)
103726048Sminshall 			return;
103826048Sminshall 		ip = &proxstruct;
103926048Sminshall 		op = &tmpstruct;
104026048Sminshall 		proxy = 0;
104126048Sminshall 	}
104226048Sminshall 	ip->connect = connected;
104326048Sminshall 	connected = op->connect;
1044*26496Sminshall 	(void) strncpy(ip->name, hostname, 31);
104526048Sminshall 	(ip->name)[strlen(ip->name)] = '\0';
104626048Sminshall 	hostname = op->name;
104726048Sminshall 	ip->hctl = hisctladdr;
104826048Sminshall 	hisctladdr = op->hctl;
104926048Sminshall 	ip->mctl = myctladdr;
105026048Sminshall 	myctladdr = op->mctl;
105126048Sminshall 	ip->in = cin;
105226048Sminshall 	cin = op->in;
105326048Sminshall 	ip->out = cout;
105426048Sminshall 	cout = op->out;
105526048Sminshall 	ip->tflag = telflag;
105626048Sminshall 	telflag = op->tflag;
105726048Sminshall 	ip->tpe = type;
105826048Sminshall 	type = op->tpe;
105926448Slepreau 	if (!type)
106026048Sminshall 		type = 1;
106126048Sminshall 	ip->cpnd = cpend;
106226048Sminshall 	cpend = op->cpnd;
106326048Sminshall 	ip->sunqe = sunique;
106426048Sminshall 	sunique = op->sunqe;
106526048Sminshall 	ip->runqe = runique;
106626048Sminshall 	runique = op->runqe;
106726048Sminshall 	ip->mcse = mcase;
106826048Sminshall 	mcase = op->mcse;
106926048Sminshall 	ip->ntflg = ntflag;
107026048Sminshall 	ntflag = op->ntflg;
1071*26496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
107226048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
1073*26496Sminshall 	(void) strcpy(ntin, op->nti);
1074*26496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
107526048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
1076*26496Sminshall 	(void) strcpy(ntout, op->nto);
107726048Sminshall 	ip->mapflg = mapflag;
107826048Sminshall 	mapflag = op->mapflg;
1079*26496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
108026048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
1081*26496Sminshall 	(void) strcpy(mapin, op->mi);
1082*26496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
108326048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
1084*26496Sminshall 	(void) strcpy(mapout, op->mo);
108526048Sminshall 	(void) signal(SIGINT, oldintr);
108626048Sminshall 	if (abrtflag) {
108726048Sminshall 		abrtflag = 0;
108826048Sminshall 		(*oldintr)();
108926448Slepreau 	}
109026048Sminshall }
109126048Sminshall 
109226048Sminshall jmp_buf ptabort;
109326048Sminshall int ptabflg;
109426048Sminshall 
109526048Sminshall abortpt()
109626048Sminshall {
109726048Sminshall 	printf("\n");
1098*26496Sminshall 	(void) fflush(stdout);
109926048Sminshall 	ptabflg++;
110026048Sminshall 	mflag = 0;
110126048Sminshall 	abrtflag = 0;
110226048Sminshall 	longjmp(ptabort, 1);
110326048Sminshall }
110426048Sminshall 
110526048Sminshall proxtrans(cmd, local, remote)
110626048Sminshall 	char *cmd, *local, *remote;
110726048Sminshall {
110826048Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0;
110926048Sminshall 	extern jmp_buf ptabort;
111026048Sminshall 	char *cmd2;
1111*26496Sminshall 	struct fd_set mask;
111226048Sminshall 
111326448Slepreau 	if (strcmp(cmd, "RETR"))
111426048Sminshall 		cmd2 = "RETR";
111526448Slepreau 	else
111626048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
111726048Sminshall 	if (command("PASV") != COMPLETE) {
111826048Sminshall 		printf("proxy server does not support third part transfers.\n");
111926048Sminshall 		return;
112026048Sminshall 	}
112126048Sminshall 	tmptype = type;
112226048Sminshall 	pswitch(0);
112326048Sminshall 	if (!connected) {
112426048Sminshall 		printf("No primary connection\n");
112526048Sminshall 		pswitch(1);
112626048Sminshall 		code = -1;
112726048Sminshall 		return;
112826048Sminshall 	}
112926048Sminshall 	if (type != tmptype) {
113026048Sminshall 		oldtype = type;
113126048Sminshall 		switch (tmptype) {
113226048Sminshall 			case TYPE_A:
113326048Sminshall 				setascii();
113426048Sminshall 				break;
113526048Sminshall 			case TYPE_I:
113626048Sminshall 				setbinary();
113726048Sminshall 				break;
113826048Sminshall 			case TYPE_E:
113926048Sminshall 				setebcdic();
114026048Sminshall 				break;
114126048Sminshall 			case TYPE_L:
114226048Sminshall 				settenex();
114326048Sminshall 				break;
114426048Sminshall 		}
114526048Sminshall 	}
114626048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
114726048Sminshall 		switch (oldtype) {
114826048Sminshall 			case 0:
114926048Sminshall 				break;
115026048Sminshall 			case TYPE_A:
115126048Sminshall 				setascii();
115226048Sminshall 				break;
115326048Sminshall 			case TYPE_I:
115426048Sminshall 				setbinary();
115526048Sminshall 				break;
115626048Sminshall 			case TYPE_E:
115726048Sminshall 				setebcdic();
115826048Sminshall 				break;
115926048Sminshall 			case TYPE_L:
116026048Sminshall 				settenex();
116126048Sminshall 				break;
116226048Sminshall 		}
116326048Sminshall 		pswitch(1);
116426048Sminshall 		return;
116526048Sminshall 	}
116626448Slepreau 	if (setjmp(ptabort))
116726048Sminshall 		goto abort;
116826048Sminshall 	oldintr = signal(SIGINT, abortpt);
116926048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
117026048Sminshall 		(void) signal(SIGINT, oldintr);
117126048Sminshall 		switch (oldtype) {
117226048Sminshall 			case 0:
117326048Sminshall 				break;
117426048Sminshall 			case TYPE_A:
117526048Sminshall 				setascii();
117626048Sminshall 				break;
117726048Sminshall 			case TYPE_I:
117826048Sminshall 				setbinary();
117926048Sminshall 				break;
118026048Sminshall 			case TYPE_E:
118126048Sminshall 				setebcdic();
118226048Sminshall 				break;
118326048Sminshall 			case TYPE_L:
118426048Sminshall 				settenex();
118526048Sminshall 				break;
118626048Sminshall 		}
118726048Sminshall 		pswitch(1);
118826048Sminshall 		return;
118926048Sminshall 	}
119026048Sminshall 	sleep(2);
119126048Sminshall 	pswitch(1);
119226048Sminshall 	secndflag++;
119326448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
119426048Sminshall 		goto abort;
119526048Sminshall 	ptflag++;
119626048Sminshall 	(void) getreply(0);
119726048Sminshall 	pswitch(0);
119826048Sminshall 	(void) getreply(0);
119926048Sminshall 	(void) signal(SIGINT, oldintr);
120026048Sminshall 	switch (oldtype) {
120126048Sminshall 		case 0:
120226048Sminshall 			break;
120326048Sminshall 		case TYPE_A:
120426048Sminshall 			setascii();
120526048Sminshall 			break;
120626048Sminshall 		case TYPE_I:
120726048Sminshall 			setbinary();
120826048Sminshall 			break;
120926048Sminshall 		case TYPE_E:
121026048Sminshall 			setebcdic();
121126048Sminshall 			break;
121226048Sminshall 		case TYPE_L:
121326048Sminshall 			settenex();
121426048Sminshall 			break;
121526048Sminshall 	}
121626048Sminshall 	pswitch(1);
121726048Sminshall 	ptflag = 0;
121826048Sminshall 	printf("local: %s remote: %s\n", local, remote);
121926048Sminshall 	return;
122026048Sminshall abort:
122126048Sminshall 	(void) signal(SIGINT, SIG_IGN);
122226048Sminshall 	ptflag = 0;
122326448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
122426048Sminshall 		pswitch(1);
122526448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
122626048Sminshall 		pswitch(0);
122726048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
122826048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
122926048Sminshall 			pswitch(0);
123026048Sminshall 			switch (oldtype) {
123126048Sminshall 				case 0:
123226048Sminshall 					break;
123326048Sminshall 				case TYPE_A:
123426048Sminshall 					setascii();
123526048Sminshall 					break;
123626048Sminshall 				case TYPE_I:
123726048Sminshall 					setbinary();
123826048Sminshall 					break;
123926048Sminshall 				case TYPE_E:
124026048Sminshall 					setebcdic();
124126048Sminshall 					break;
124226048Sminshall 				case TYPE_L:
124326048Sminshall 					settenex();
124426048Sminshall 					break;
124526048Sminshall 			}
124626048Sminshall 			if (cpend && telflag) {
124726048Sminshall 				char msg[2];
124826048Sminshall 
124926048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
125026048Sminshall 				(void) fflush(cout);
125126048Sminshall 				*msg = IAC;
125226048Sminshall 				*(msg+1) = DM;
125326448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
125426048Sminshall 					perror("abort");
125526048Sminshall 			}
125626048Sminshall 			if (cpend) {
125726048Sminshall 				fprintf(cout,"ABOR\r\n");
125826048Sminshall 				(void) fflush(cout);
1259*26496Sminshall 				FD_ZERO((char *) &mask);
1260*26496Sminshall 				FD_SET(fileno(cin), &mask);
1261*26496Sminshall 				if (empty(mask,10) < 0) {
126226048Sminshall 					perror("abort");
126326448Slepreau 					if (ptabflg)
126426048Sminshall 						code = -1;
126526048Sminshall 					lostpeer();
126626048Sminshall 				}
126726048Sminshall 				(void) getreply(0);
126826048Sminshall 				(void) getreply(0);
126926048Sminshall 			}
127026048Sminshall 		}
127126048Sminshall 		pswitch(1);
127226448Slepreau 		if (ptabflg)
127326048Sminshall 			code = -1;
127426048Sminshall 		(void) signal(SIGINT, oldintr);
127526048Sminshall 		return;
127626048Sminshall 	}
127726048Sminshall 	if (cpend && telflag) {
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 	}
128726048Sminshall 	if (cpend) {
128826048Sminshall 		fprintf(cout,"ABOR\r\n");
128926048Sminshall 		(void) fflush(cout);
1290*26496Sminshall 		FD_ZERO((char *) &mask);
1291*26496Sminshall 		FD_SET(fileno(cin), &mask);
1292*26496Sminshall 		if ((empty(mask,10)) < 0) {
129326048Sminshall 			perror("abort");
129426448Slepreau 			if (ptabflg)
129526048Sminshall 				code = -1;
129626048Sminshall 			lostpeer();
129726048Sminshall 		}
129826048Sminshall 		(void) getreply(0);
129926048Sminshall 		(void) getreply(0);
130026048Sminshall 	}
130126048Sminshall 	pswitch(!proxy);
130226048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
130326048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
130426048Sminshall 			pswitch(0);
130526048Sminshall 			switch (oldtype) {
130626048Sminshall 				case 0:
130726048Sminshall 					break;
130826048Sminshall 				case TYPE_A:
130926048Sminshall 					setascii();
131026048Sminshall 					break;
131126048Sminshall 				case TYPE_I:
131226048Sminshall 					setbinary();
131326048Sminshall 					break;
131426048Sminshall 				case TYPE_E:
131526048Sminshall 					setebcdic();
131626048Sminshall 					break;
131726048Sminshall 				case TYPE_L:
131826048Sminshall 					settenex();
131926048Sminshall 					break;
132026048Sminshall 			}
132126048Sminshall 			if (cpend && telflag) {
132226048Sminshall 				char msg[2];
132326048Sminshall 
132426048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
132526048Sminshall 				(void) fflush(cout);
132626048Sminshall 				*msg = IAC;
132726048Sminshall 				*(msg+1) = DM;
132826448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
132926048Sminshall 					perror("abort");
133026048Sminshall 			}
133126048Sminshall 			if (cpend) {
133226048Sminshall 				fprintf(cout,"ABOR\r\n");
133326048Sminshall 				(void) fflush(cout);
1334*26496Sminshall 				FD_ZERO((char *) &mask);
1335*26496Sminshall 				FD_SET(fileno(cin), &mask);
1336*26496Sminshall 				if (empty(mask,10) < 0) {
133726048Sminshall 					perror("abort");
133826448Slepreau 					if (ptabflg)
133926048Sminshall 						code = -1;
134026048Sminshall 					lostpeer();
134126048Sminshall 				}
134226048Sminshall 				(void) getreply(0);
134326048Sminshall 				(void) getreply(0);
134426048Sminshall 			}
134526048Sminshall 			pswitch(1);
134626448Slepreau 			if (ptabflg)
134726048Sminshall 				code = -1;
134826048Sminshall 			(void) signal(SIGINT, oldintr);
134926048Sminshall 			return;
135026048Sminshall 		}
135126048Sminshall 	}
135226048Sminshall 	if (cpend && telflag) {
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 	}
136226048Sminshall 	if (cpend) {
136326048Sminshall 		fprintf(cout,"ABOR\r\n");
136426048Sminshall 		(void) fflush(cout);
1365*26496Sminshall 		FD_ZERO((char *) &mask);
1366*26496Sminshall 		FD_SET(fileno(cin), &mask);
1367*26496Sminshall 		if (empty(mask,10) < 0) {
136826048Sminshall 			perror("abort");
136926448Slepreau 			if (ptabflg)
137026048Sminshall 				code = -1;
137126048Sminshall 			lostpeer();
137226048Sminshall 		}
137326048Sminshall 		(void) getreply(0);
137426048Sminshall 		(void) getreply(0);
137526048Sminshall 	}
137626048Sminshall 	pswitch(!proxy);
137726048Sminshall 	if (cpend) {
1378*26496Sminshall 		FD_ZERO((char *) &mask);
1379*26496Sminshall 		FD_SET(fileno(cin), &mask);
1380*26496Sminshall 		if (empty(mask,10) < 0) {
138126048Sminshall 			perror("abort");
138226448Slepreau 			if (ptabflg)
138326048Sminshall 				code = -1;
138426048Sminshall 			lostpeer();
138526048Sminshall 		}
138626048Sminshall 		(void) getreply(0);
138726048Sminshall 		(void) getreply(0);
138826048Sminshall 	}
138926448Slepreau 	if (proxy)
139026048Sminshall 		pswitch(0);
139126048Sminshall 	switch (oldtype) {
139226048Sminshall 		case 0:
139326048Sminshall 			break;
139426048Sminshall 		case TYPE_A:
139526048Sminshall 			setascii();
139626048Sminshall 			break;
139726048Sminshall 		case TYPE_I:
139826048Sminshall 			setbinary();
139926048Sminshall 			break;
140026048Sminshall 		case TYPE_E:
140126048Sminshall 			setebcdic();
140226048Sminshall 			break;
140326048Sminshall 		case TYPE_L:
140426048Sminshall 			settenex();
140526048Sminshall 			break;
140626048Sminshall 	}
140726048Sminshall 	pswitch(1);
140826448Slepreau 	if (ptabflg)
140926048Sminshall 		code = -1;
141026048Sminshall 	(void) signal(SIGINT, oldintr);
141126048Sminshall }
141226048Sminshall 
141326048Sminshall reset()
141426048Sminshall {
1415*26496Sminshall 	struct fd_set mask;
1416*26496Sminshall 	int nfnd = 1;
141726048Sminshall 
1418*26496Sminshall 	FD_ZERO((char *) &mask);
1419*26496Sminshall 	while (nfnd) {
1420*26496Sminshall 		FD_SET(fileno(cin), &mask);
1421*26496Sminshall 		if ((nfnd = empty(mask,0)) < 0) {
142226048Sminshall 			perror("reset");
142326048Sminshall 			code = -1;
142426048Sminshall 			lostpeer();
142526048Sminshall 		}
1426*26496Sminshall 		else {
142726048Sminshall 			(void) getreply(0);
1428*26496Sminshall 		}
142926048Sminshall 	}
143026048Sminshall }
143126048Sminshall 
143226048Sminshall char *
143326048Sminshall gunique(local)
143426048Sminshall 	char *local;
143526048Sminshall {
143626048Sminshall 	static char new[MAXPATHLEN];
143726048Sminshall 	char *cp = rindex(local, '/');
143826048Sminshall 	int d, count=0;
143926048Sminshall 	char ext = '1';
144026048Sminshall 
144126448Slepreau 	if (cp)
144226048Sminshall 		*cp = '\0';
144326048Sminshall 	d = access(cp ? local : ".", 2);
144426448Slepreau 	if (cp)
144526048Sminshall 		*cp = '/';
144626048Sminshall 	if (d < 0) {
144726048Sminshall 		perror(local);
144826048Sminshall 		return((char *) 0);
144926048Sminshall 	}
145026048Sminshall 	(void) strcpy(new, local);
145126048Sminshall 	cp = new + strlen(new);
145226048Sminshall 	*cp++ = '.';
145326048Sminshall 	while (!d) {
145426048Sminshall 		if (++count == 100) {
145526048Sminshall 			printf("runique: can't find unique file name.\n");
145626048Sminshall 			return((char *) 0);
145726048Sminshall 		}
145826048Sminshall 		*cp++ = ext;
145926048Sminshall 		*cp = '\0';
146026448Slepreau 		if (ext == '9')
146126048Sminshall 			ext = '0';
146226448Slepreau 		else
146326048Sminshall 			ext++;
146426448Slepreau 		if ((d = access(new, 0)) < 0)
146526048Sminshall 			break;
146626448Slepreau 		if (ext != '0')
146726048Sminshall 			cp--;
146826448Slepreau 		else if (*(cp - 2) == '.')
146926048Sminshall 			*(cp - 1) = '1';
147026048Sminshall 		else {
147126048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
147226048Sminshall 			cp--;
147326048Sminshall 		}
147426048Sminshall 	}
147526048Sminshall 	return(new);
147626048Sminshall }
1477