xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 26067)
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*26067Sminshall static char sccsid[] = "@(#)ftp.c	5.7 (Berkeley) 02/04/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>
1710296Ssam 
1810296Ssam #include <netinet/in.h>
1912397Ssam #include <arpa/ftp.h>
2026048Sminshall #include <arpa/telnet.h>
2110296Ssam 
2210296Ssam #include <stdio.h>
2310296Ssam #include <signal.h>
2410296Ssam #include <errno.h>
2510296Ssam #include <netdb.h>
2626048Sminshall #include <fcntl.h>
2726048Sminshall #include <pwd.h>
2810296Ssam 
2910296Ssam struct	sockaddr_in hisctladdr;
3010296Ssam struct	sockaddr_in data_addr;
3110296Ssam int	data = -1;
3226048Sminshall int     telflag = 0;
3326048Sminshall int	abrtflag = 0;
3426048Sminshall int	ptflag = 0;
3510296Ssam int	connected;
3610296Ssam struct	sockaddr_in myctladdr;
3710296Ssam 
3810296Ssam FILE	*cin, *cout;
3910296Ssam FILE	*dataconn();
4010296Ssam 
4125904Skarels char *
4210296Ssam hookup(host, port)
4310296Ssam 	char *host;
4410296Ssam 	int port;
4510296Ssam {
4625904Skarels 	register struct hostent *hp = 0;
4726048Sminshall 	int s,len,oldverbose;
4825904Skarels 	static char hostnamebuf[80];
4926048Sminshall 	char msg[2];
5010296Ssam 
5110296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5225904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
5325904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
5425904Skarels 		hisctladdr.sin_family = AF_INET;
5525904Skarels 		(void) strcpy(hostnamebuf, host);
5626048Sminshall 	}
5726048Sminshall 	else {
5825100Sbloom 		hp = gethostbyname(host);
5925904Skarels 		if (hp == NULL) {
6025904Skarels 			printf("%s: unknown host\n", host);
6126048Sminshall 			code = -1;
6226048Sminshall 			return((char *) 0);
6325904Skarels 		}
6425904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
6525904Skarels 		bcopy(hp->h_addr_list[0],
6625904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
6725904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
6810296Ssam 	}
6925904Skarels 	hostname = hostnamebuf;
7025904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7110296Ssam 	if (s < 0) {
7210296Ssam 		perror("ftp: socket");
7326048Sminshall 		code = -1;
7410296Ssam 		return (0);
7510296Ssam 	}
7610296Ssam 	hisctladdr.sin_port = port;
7725904Skarels 	while (connect(s, (caddr_t)&hisctladdr, sizeof (hisctladdr)) < 0) {
7825904Skarels 		if (hp && hp->h_addr_list[1]) {
7925904Skarels 			int oerrno = errno;
8025904Skarels 
8125904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
8225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
8325904Skarels 			errno = oerrno;
8425904Skarels 			perror(0);
8525904Skarels 			hp->h_addr_list++;
8625904Skarels 			bcopy(hp->h_addr_list[0],
8726048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8825904Skarels 			fprintf(stderr, "Trying %s...\n",
8925904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9025904Skarels 			continue;
9125904Skarels 		}
9210296Ssam 		perror("ftp: connect");
9326048Sminshall 		code = -1;
9410296Ssam 		goto bad;
9510296Ssam 	}
9611627Ssam 	len = sizeof (myctladdr);
9711627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
9811627Ssam 		perror("ftp: getsockname");
9926048Sminshall 		code = -1;
10010296Ssam 		goto bad;
10110296Ssam 	}
10210296Ssam 	cin = fdopen(s, "r");
10310296Ssam 	cout = fdopen(s, "w");
10411219Ssam 	if (cin == NULL || cout == NULL) {
10510296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
10610296Ssam 		if (cin)
10710296Ssam 			fclose(cin);
10810296Ssam 		if (cout)
10910296Ssam 			fclose(cout);
11026048Sminshall 		code = -1;
11110296Ssam 		goto bad;
11210296Ssam 	}
11310296Ssam 	if (verbose)
114*26067Sminshall 		printf("Connected to %s.\n", hostname);
11526048Sminshall 	if (getreply(0) != 2) { 	/* read startup message from server */
11626048Sminshall 		if (cin)
11726048Sminshall 			fclose(cin);
11826048Sminshall 		if (cout)
11926048Sminshall 			fclose(cout);
12026048Sminshall 		code = -1;
12126048Sminshall 		goto bad;
12226048Sminshall 	}
12326048Sminshall 
12426048Sminshall /* test to see if server command parser understands TELNET SYNC command */
12526048Sminshall 
12626048Sminshall 	fprintf(cout,"%c%c",IAC,NOP);
12726048Sminshall 	(void) fflush(cout);
12826048Sminshall 	*msg = IAC;
12926048Sminshall 	*(msg+1) = DM;
13026048Sminshall 	if (send(s,msg,2,MSG_OOB) != 2) {
13126048Sminshall 		perror("sync");
13226048Sminshall 	}
13326048Sminshall 	oldverbose = verbose;
13426048Sminshall 	if (!debug) {
13526048Sminshall 		verbose = -1;
13626048Sminshall 	}
13726048Sminshall 	if (command("NOOP") == COMPLETE) {
13826048Sminshall 		telflag = 1;
13926048Sminshall 	}
14026048Sminshall 	else {
14126048Sminshall 		telflag = 0;
14226048Sminshall 	}
14326048Sminshall 	verbose = oldverbose;
14425904Skarels 	return (hostname);
14510296Ssam bad:
14610296Ssam 	close(s);
14725904Skarels 	return ((char *)0);
14810296Ssam }
14910296Ssam 
15025904Skarels login(host)
15125904Skarels 	char *host;
15210296Ssam {
15326048Sminshall 	char tmp[80];
15426048Sminshall 	char *user, *pass, *acct, *getlogin(), *getpass();
15526048Sminshall 	int n, aflag = 0;
15610296Ssam 
15726048Sminshall 	user = pass = acct = 0;
15826048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
15926048Sminshall 		disconnect();
16026048Sminshall 		code = -1;
16126048Sminshall 		return(0);
16226048Sminshall 	}
16326048Sminshall 	if (user == NULL) {
16426048Sminshall 		char *myname = getlogin();
16526048Sminshall 
16626048Sminshall 		if (myname == NULL) {
16726048Sminshall 			struct passwd *pp = getpwuid(getuid());
16826048Sminshall 
16926048Sminshall 			if (pp != NULL) {
17026048Sminshall 				myname = pp->pw_name;
17126048Sminshall 			}
17226048Sminshall 		}
17326048Sminshall 		printf("Name (%s:%s): ", host, myname);
17426048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
17526048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
17626048Sminshall 		if (*tmp == '\0') {
17726048Sminshall 			user = myname;
17826048Sminshall 		}
17926048Sminshall 		else {
18026048Sminshall 			user = tmp;
18126048Sminshall 		}
18226048Sminshall 	}
18310296Ssam 	n = command("USER %s", user);
18426048Sminshall 	if (n == CONTINUE) {
18526048Sminshall 		if (pass == NULL) {
18626048Sminshall 			pass = getpass("Password:");
18726048Sminshall 		}
18810296Ssam 		n = command("PASS %s", pass);
18926048Sminshall 	}
19010296Ssam 	if (n == CONTINUE) {
19126048Sminshall 		aflag++;
19226048Sminshall 		acct = getpass("Account:");
19310296Ssam 		n = command("ACCT %s", acct);
19410296Ssam 	}
19510296Ssam 	if (n != COMPLETE) {
19610296Ssam 		fprintf(stderr, "Login failed.\n");
19710296Ssam 		return (0);
19810296Ssam 	}
19926048Sminshall 	if (!aflag && acct != NULL) {
20026048Sminshall 		(void) command("ACCT %s", acct);
20126048Sminshall 	}
20226048Sminshall 	if (proxy) {
20326048Sminshall 		return(1);
20426048Sminshall 	}
20526048Sminshall 	for (n = 0; n < macnum; ++n) {
20626048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
20726048Sminshall 			strcpy(line, "$init");
20826048Sminshall 			makeargv();
20926048Sminshall 			domacro(margc, margv);
21026048Sminshall 			break;
21126048Sminshall 		}
21226048Sminshall 	}
21310296Ssam 	return (1);
21410296Ssam }
21510296Ssam 
21626048Sminshall cmdabort()
21726048Sminshall {
21826048Sminshall 	extern jmp_buf ptabort;
21926048Sminshall 
22026048Sminshall 	printf("\n");
22126048Sminshall 	(void) fflush(stdout);
22226048Sminshall 	abrtflag++;
22326048Sminshall 	if (ptflag) {
22426048Sminshall 		longjmp(ptabort,1);
22526048Sminshall 	}
22626048Sminshall }
22726048Sminshall 
22810296Ssam /*VARARGS 1*/
22910296Ssam command(fmt, args)
23010296Ssam 	char *fmt;
23110296Ssam {
23226048Sminshall 	int r, (*oldintr)(), cmdabort();
23310296Ssam 
23426048Sminshall 	abrtflag = 0;
23510296Ssam 	if (debug) {
23610296Ssam 		printf("---> ");
23710296Ssam 		_doprnt(fmt, &args, stdout);
23810296Ssam 		printf("\n");
23910296Ssam 		(void) fflush(stdout);
24010296Ssam 	}
24111219Ssam 	if (cout == NULL) {
24211219Ssam 		perror ("No control connection for command");
24326048Sminshall 		code = -1;
24411219Ssam 		return (0);
24511219Ssam 	}
24626048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24710296Ssam 	_doprnt(fmt, &args, cout);
24810296Ssam 	fprintf(cout, "\r\n");
24910296Ssam 	(void) fflush(cout);
25026048Sminshall 	cpend = 1;
25126048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25226048Sminshall 	if (abrtflag && oldintr != SIG_IGN) {
25326048Sminshall 		(*oldintr)();
25426048Sminshall 	}
25526048Sminshall 	(void) signal(SIGINT, oldintr);
25626048Sminshall 	return(r);
25710296Ssam }
25810296Ssam 
25910296Ssam #include <ctype.h>
26010296Ssam 
26110296Ssam getreply(expecteof)
26210296Ssam 	int expecteof;
26310296Ssam {
26411219Ssam 	register int c, n;
26526048Sminshall 	register int dig;
26626048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
26726048Sminshall 	int pflag = 0;
26826048Sminshall 	char *pt = pasv;
26910296Ssam 
27026048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27110296Ssam 	for (;;) {
27210296Ssam 		dig = n = code = 0;
27310296Ssam 		while ((c = getc(cin)) != '\n') {
27410296Ssam 			dig++;
27510296Ssam 			if (c == EOF) {
27626048Sminshall 				if (expecteof) {
27726048Sminshall 					(void) signal(SIGINT,oldintr);
27826048Sminshall 					code = 221;
27910296Ssam 					return (0);
28026048Sminshall 				}
28110296Ssam 				lostpeer();
28226048Sminshall 				if (verbose) {
28326048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
28426048Sminshall 					(void) fflush(stdout);
28526048Sminshall 					code = 421;
28626048Sminshall 					return(4);
28726048Sminshall 				}
28810296Ssam 			}
28926048Sminshall 			if (c != '\r' && (verbose > 0 ||
29026048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
29126048Sminshall 				if ( proxflag &&
29226048Sminshall 				   (dig == 1 || dig == 5 && verbose == 0)) {
29326048Sminshall 					printf("%s:",hostname);
29426048Sminshall 				}
29510296Ssam 				putchar(c);
29626048Sminshall 			}
29710296Ssam 			if (dig < 4 && isdigit(c))
29810296Ssam 				code = code * 10 + (c - '0');
29926048Sminshall 			if (!pflag && code == 227) {
30026048Sminshall 				pflag = 1;
30126048Sminshall 			}
30226048Sminshall 			if (dig > 4 && pflag == 1 && isdigit(c)) {
30326048Sminshall 				pflag = 2;
30426048Sminshall 			}
30526048Sminshall 			if (pflag == 2) {
30626048Sminshall 				if (c != '\r' && c != ')') {
30726048Sminshall 					*pt++ = c;
30826048Sminshall 				}
30926048Sminshall 				else {
31026048Sminshall 					*pt = '\0';
31126048Sminshall 					pflag = 3;
31226048Sminshall 				}
31326048Sminshall 			}
31426048Sminshall 			if (dig == 4 && c == '-') {
31526048Sminshall 				if (continuation) {
31626048Sminshall 					code = 0;
31726048Sminshall 				}
31810296Ssam 				continuation++;
31926048Sminshall 			}
32010296Ssam 			if (n == 0)
32110296Ssam 				n = c;
32210296Ssam 		}
32326048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
32410296Ssam 			putchar(c);
32511346Ssam 			(void) fflush (stdout);
32611346Ssam 		}
32710296Ssam 		if (continuation && code != originalcode) {
32810296Ssam 			if (originalcode == 0)
32910296Ssam 				originalcode = code;
33010296Ssam 			continue;
33110296Ssam 		}
33226048Sminshall 		if (n != '1') {
33326048Sminshall 			cpend = 0;
33426048Sminshall 		}
33526048Sminshall 		(void) signal(SIGINT,oldintr);
33626048Sminshall 		if (code == 421 || originalcode == 421) {
33726048Sminshall 			lostpeer();
33826048Sminshall 		}
33926048Sminshall 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) {
34026048Sminshall 			(*oldintr)();
34126048Sminshall 		}
34225907Smckusick 		return (n - '0');
34310296Ssam 	}
34410296Ssam }
34510296Ssam 
34626048Sminshall empty(mask, sec)
34726048Sminshall 	long mask;
34826048Sminshall 	int sec;
34926048Sminshall {
35026048Sminshall 	struct timeval t;
35126048Sminshall 
35226048Sminshall 	t.tv_sec = (long) sec;
35326048Sminshall 	t.tv_usec = 0;
35426048Sminshall 	if (select(20, &mask, 0, 0, &t) < 0) {
35526048Sminshall 		return(-1);
35626048Sminshall 	}
35726048Sminshall 	return (mask);
35826048Sminshall }
35926048Sminshall 
36010296Ssam jmp_buf	sendabort;
36110296Ssam 
36210296Ssam abortsend()
36310296Ssam {
36410296Ssam 
36526048Sminshall 	mflag = 0;
36626048Sminshall 	abrtflag = 0;
36726048Sminshall 	printf("\nsend aborted\n");
36826048Sminshall 	(void) fflush(stdout);
36910296Ssam 	longjmp(sendabort, 1);
37010296Ssam }
37110296Ssam 
37210296Ssam sendrequest(cmd, local, remote)
37310296Ssam 	char *cmd, *local, *remote;
37410296Ssam {
37526048Sminshall 	FILE *fin, *dout = 0, *popen();
37626048Sminshall 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
37726048Sminshall 	int abortsend();
37811219Ssam 	char buf[BUFSIZ];
37911651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
38011346Ssam 	register int c, d;
38110296Ssam 	struct stat st;
38210296Ssam 	struct timeval start, stop;
38310296Ssam 
38426048Sminshall 	if (proxy) {
38526048Sminshall 		proxtrans(cmd, local, remote);
38626048Sminshall 		return;
38726048Sminshall 	}
38810296Ssam 	closefunc = NULL;
38926048Sminshall 	oldintr = NULL;
39026048Sminshall 	oldintp = NULL;
39126048Sminshall 	if (setjmp(sendabort)) {
39226048Sminshall 		while (cpend) {
39326048Sminshall 			(void) getreply(0);
39426048Sminshall 		}
39526048Sminshall 		if (data >= 0) {
39626048Sminshall 			(void) close(data);
39726048Sminshall 			data = -1;
39826048Sminshall 		}
39926048Sminshall 		if (oldintr) {
40026048Sminshall 			(void) signal(SIGINT,oldintr);
40126048Sminshall 		}
40226048Sminshall 		if (oldintp) {
40326048Sminshall 			(void) signal(SIGPIPE,oldintp);
40426048Sminshall 		}
40526048Sminshall 		code = -1;
40626048Sminshall 		return;
40726048Sminshall 	}
40810296Ssam 	oldintr = signal(SIGINT, abortsend);
40910296Ssam 	if (strcmp(local, "-") == 0)
41010296Ssam 		fin = stdin;
41110296Ssam 	else if (*local == '|') {
41226048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
41326048Sminshall 		fin = popen(local + 1, "r");
41410296Ssam 		if (fin == NULL) {
41526048Sminshall 			perror(local + 1);
41626048Sminshall 			(void) signal(SIGINT, oldintr);
41726048Sminshall 			(void) signal(SIGPIPE, oldintp);
41826048Sminshall 			code = -1;
41926048Sminshall 			return;
42010296Ssam 		}
42110296Ssam 		closefunc = pclose;
42210296Ssam 	} else {
42310296Ssam 		fin = fopen(local, "r");
42410296Ssam 		if (fin == NULL) {
42510296Ssam 			perror(local);
42626048Sminshall 			(void) signal(SIGINT, oldintr);
42726048Sminshall 			code = -1;
42826048Sminshall 			return;
42910296Ssam 		}
43010296Ssam 		closefunc = fclose;
43110296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
43210296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
43317949Sralph 			fprintf(stderr, "%s: not a plain file.\n", local);
43426048Sminshall 			(void) signal(SIGINT, oldintr);
43526048Sminshall 			code = -1;
43626048Sminshall 			return;
43710296Ssam 		}
43810296Ssam 	}
43926048Sminshall 	if (initconn()) {
44026048Sminshall 		(void) signal(SIGINT, oldintr);
44126048Sminshall 		if (oldintp) {
44226048Sminshall 			(void) signal(SIGPIPE, oldintp);
44326048Sminshall 		}
44426048Sminshall 		code = -1;
44526048Sminshall 		return;
44626048Sminshall 	}
44726048Sminshall 	if (setjmp(sendabort)) {
44826048Sminshall 		goto abort;
44926048Sminshall 	}
45010296Ssam 	if (remote) {
45126048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
45226048Sminshall 			(void) signal(SIGINT, oldintr);
45326048Sminshall 			if (oldintp) {
45426048Sminshall 				(void) signal(SIGPIPE, oldintp);
45526048Sminshall 			}
45626048Sminshall 			return;
45726048Sminshall 		}
45810296Ssam 	} else
45926048Sminshall 		if (command("%s", cmd) != PRELIM) {
46026048Sminshall 			(void) signal(SIGINT, oldintr);
46126048Sminshall 			if (oldintp) {
46226048Sminshall 				(void) signal(SIGPIPE, oldintp);
46326048Sminshall 			}
46426048Sminshall 			return;
46526048Sminshall 		}
46610296Ssam 	dout = dataconn("w");
46726048Sminshall 	if (dout == NULL) {
46826048Sminshall 		goto abort;
46926048Sminshall 	}
47010296Ssam 	gettimeofday(&start, (struct timezone *)0);
47111219Ssam 	switch (type) {
47211219Ssam 
47311219Ssam 	case TYPE_I:
47411219Ssam 	case TYPE_L:
47511346Ssam 		errno = d = 0;
47611219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
47711346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
47811219Ssam 				break;
47911219Ssam 			bytes += c;
48011651Ssam 			if (hash) {
48111651Ssam 				putchar('#');
48211651Ssam 				fflush(stdout);
48311651Ssam 			}
48411219Ssam 		}
48513213Ssam 		if (hash && bytes > 0) {
48611651Ssam 			putchar('\n');
48711651Ssam 			fflush(stdout);
48811651Ssam 		}
48911219Ssam 		if (c < 0)
49011219Ssam 			perror(local);
49111346Ssam 		if (d < 0)
49211219Ssam 			perror("netout");
49311219Ssam 		break;
49411219Ssam 
49511219Ssam 	case TYPE_A:
49611219Ssam 		while ((c = getc(fin)) != EOF) {
49711219Ssam 			if (c == '\n') {
49811651Ssam 				while (hash && (bytes >= hashbytes)) {
49911651Ssam 					putchar('#');
50011651Ssam 					fflush(stdout);
50111651Ssam 					hashbytes += sizeof (buf);
50211651Ssam 				}
50311219Ssam 				if (ferror(dout))
50411219Ssam 					break;
50511219Ssam 				putc('\r', dout);
50611219Ssam 				bytes++;
50711219Ssam 			}
50811219Ssam 			putc(c, dout);
50911219Ssam 			bytes++;
51026048Sminshall 	/*		if (c == '\r') {			  	*/
51126048Sminshall 	/*			putc('\0', dout);  /* this violates rfc */
51226048Sminshall 	/*			bytes++;				*/
51326048Sminshall 	/*		}                          			*/
51411219Ssam 		}
51511651Ssam 		if (hash) {
51613213Ssam 			if (bytes < hashbytes)
51713213Ssam 				putchar('#');
51811651Ssam 			putchar('\n');
51911651Ssam 			fflush(stdout);
52011651Ssam 		}
52111219Ssam 		if (ferror(fin))
52211219Ssam 			perror(local);
52311346Ssam 		if (ferror(dout))
52411219Ssam 			perror("netout");
52511219Ssam 		break;
52610296Ssam 	}
52710296Ssam 	gettimeofday(&stop, (struct timezone *)0);
52810296Ssam 	if (closefunc != NULL)
52926048Sminshall 		(*closefunc)(fin);
53010296Ssam 	(void) fclose(dout);
53126048Sminshall 	(void) getreply(0);
53226048Sminshall 	(void) signal(SIGINT, oldintr);
53310296Ssam 	if (bytes > 0 && verbose)
53426048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53510296Ssam 	return;
53626048Sminshall abort:
53726048Sminshall 	gettimeofday(&stop, (struct timezone *)0);
53826048Sminshall 	(void) signal(SIGINT, oldintr);
53926048Sminshall 	if (oldintp) {
54026048Sminshall 		(void) signal(SIGPIPE, oldintp);
54126048Sminshall 	}
54226048Sminshall 	if (!cpend) {
54326048Sminshall 		code = -1;
54426048Sminshall 		return;
54526048Sminshall 	}
54626048Sminshall 	if (data >= 0) {
54726048Sminshall 		(void) close(data);
54826048Sminshall 		data = -1;
54926048Sminshall 	}
55026048Sminshall 	if (dout) {
55126048Sminshall 		(void) fclose(dout);
55226048Sminshall 	}
55326048Sminshall 	(void) getreply(0);
55426048Sminshall 	code = -1;
55510296Ssam 	if (closefunc != NULL && fin != NULL)
55626048Sminshall 		(*closefunc)(fin);
55726048Sminshall 	if (bytes > 0 && verbose)
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 {
57626048Sminshall 	FILE *fout, *din = 0, *popen();
57726048Sminshall 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
57826048Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag;
57926048Sminshall 	char buf[BUFSIZ], *gunique();
58026048Sminshall 	long bytes = 0, hashbytes = sizeof (buf), mask;
58111346Ssam 	register int c, d;
58210296Ssam 	struct timeval start, stop;
58310296Ssam 
58426048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
58526048Sminshall 		proxtrans(cmd, local, remote);
58626048Sminshall 		return;
58726048Sminshall 	}
58810296Ssam 	closefunc = NULL;
58926048Sminshall 	oldintr = NULL;
59026048Sminshall 	oldintp = NULL;
59126048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
59226048Sminshall 	if (setjmp(recvabort)) {
59326048Sminshall 		while (cpend) {
59426048Sminshall 			(void) getreply(0);
59526048Sminshall 		}
59626048Sminshall 		if (data >= 0) {
59726048Sminshall 			(void) close(data);
59826048Sminshall 			data = -1;
59926048Sminshall 		}
60026048Sminshall 		if (oldintr) {
60126048Sminshall 			(void) signal(SIGINT, oldintr);
60226048Sminshall 		}
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 	}
65326048Sminshall 	if (setjmp(recvabort)) {
65426048Sminshall 		goto abort;
65526048Sminshall 	}
65626048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
65726048Sminshall 		oldtype = type;
65826048Sminshall 		oldverbose = verbose;
65926048Sminshall 		if (!debug) {
66026048Sminshall 			verbose = 0;
66126048Sminshall 		}
66226048Sminshall 		setascii();
66326048Sminshall 		verbose = oldverbose;
66426048Sminshall 	}
66510296Ssam 	if (remote) {
66626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
66726048Sminshall 			(void) signal(SIGINT, oldintr);
66826048Sminshall 			if (oldtype) {
66926048Sminshall 				if (!debug) {
67026048Sminshall 					verbose = 0;
67126048Sminshall 				}
67226048Sminshall 				switch (oldtype) {
67326048Sminshall 					case TYPE_I:
67426048Sminshall 						setbinary();
67526048Sminshall 						break;
67626048Sminshall 					case TYPE_E:
67726048Sminshall 						setebcdic();
67826048Sminshall 						break;
67926048Sminshall 					case TYPE_L:
68026048Sminshall 						settenex();
68126048Sminshall 						break;
68226048Sminshall 				}
68326048Sminshall 				verbose = oldverbose;
68426048Sminshall 			}
68526048Sminshall 			return;
68626048Sminshall 		}
68726048Sminshall 	} else {
68826048Sminshall 		if (command("%s", cmd) != PRELIM) {
68926048Sminshall 			(void) signal(SIGINT, oldintr);
69026048Sminshall 			if (oldtype) {
69126048Sminshall 				if (!debug) {
69226048Sminshall 					verbose = 0;
69326048Sminshall 				}
69426048Sminshall 				switch (oldtype) {
69526048Sminshall 					case TYPE_I:
69626048Sminshall 						setbinary();
69726048Sminshall 						break;
69826048Sminshall 					case TYPE_E:
69926048Sminshall 						setebcdic();
70026048Sminshall 						break;
70126048Sminshall 					case TYPE_L:
70226048Sminshall 						settenex();
70326048Sminshall 						break;
70426048Sminshall 				}
70526048Sminshall 				verbose = oldverbose;
70626048Sminshall 			}
70726048Sminshall 			return;
70826048Sminshall 		}
70926048Sminshall 	}
71026048Sminshall 	din = dataconn("r");
71126048Sminshall 	if (din == NULL)
71226048Sminshall 		goto abort;
71326048Sminshall 	if (strcmp(local, "-") == 0) {
71410296Ssam 		fout = stdout;
71526048Sminshall 	}
71610296Ssam 	else if (*local == '|') {
71726048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
71826048Sminshall 		fout = popen(local + 1, "w");
71926048Sminshall 		if (fout == NULL) {
72026048Sminshall 			perror(local+1);
72126048Sminshall 			goto abort;
72226048Sminshall 		}
72310296Ssam 		closefunc = pclose;
72426048Sminshall 	}
72526048Sminshall 	else {
72611651Ssam 		fout = fopen(local, mode);
72726048Sminshall 		if (fout == NULL) {
72826048Sminshall 			perror(local);
72926048Sminshall 			goto abort;
73026048Sminshall 		}
73110296Ssam 		closefunc = fclose;
73210296Ssam 	}
73310296Ssam 	gettimeofday(&start, (struct timezone *)0);
73411219Ssam 	switch (type) {
73511219Ssam 
73611219Ssam 	case TYPE_I:
73711219Ssam 	case TYPE_L:
73811346Ssam 		errno = d = 0;
73911219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
74011346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
74111219Ssam 				break;
74211219Ssam 			bytes += c;
74311651Ssam 			if (hash) {
74411651Ssam 				putchar('#');
74511651Ssam 				fflush(stdout);
74611651Ssam 			}
74711219Ssam 		}
74813213Ssam 		if (hash && bytes > 0) {
74911651Ssam 			putchar('\n');
75011651Ssam 			fflush(stdout);
75111651Ssam 		}
75211219Ssam 		if (c < 0)
75311219Ssam 			perror("netin");
75411346Ssam 		if (d < 0)
75510296Ssam 			perror(local);
75611219Ssam 		break;
75711219Ssam 
75811219Ssam 	case TYPE_A:
75911219Ssam 		while ((c = getc(din)) != EOF) {
76011219Ssam 			if (c == '\r') {
76111651Ssam 				while (hash && (bytes >= hashbytes)) {
76211651Ssam 					putchar('#');
76311651Ssam 					fflush(stdout);
76411651Ssam 					hashbytes += sizeof (buf);
76511651Ssam 				}
76610296Ssam 				bytes++;
76726048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
76811219Ssam 					if (ferror (fout))
76911219Ssam 						break;
77011219Ssam 					putc ('\r', fout);
77111219Ssam 				}
77226048Sminshall 				/*if (c == '\0') {
77311219Ssam 					bytes++;
77411219Ssam 					continue;
77526048Sminshall 				}*/
77611219Ssam 			}
77711219Ssam 			putc (c, fout);
77811219Ssam 			bytes++;
77910296Ssam 		}
78011651Ssam 		if (hash) {
78113213Ssam 			if (bytes < hashbytes)
78213213Ssam 				putchar('#');
78311651Ssam 			putchar('\n');
78411651Ssam 			fflush(stdout);
78511651Ssam 		}
78611219Ssam 		if (ferror (din))
78711219Ssam 			perror ("netin");
78811219Ssam 		if (ferror (fout))
78911219Ssam 			perror (local);
79011219Ssam 		break;
79110296Ssam 	}
79226048Sminshall 	if (closefunc != NULL) {
79326048Sminshall 		(*closefunc)(fout);
79426048Sminshall 	}
79526048Sminshall 	signal(SIGINT, oldintr);
79626048Sminshall 	if (oldintp) {
79726048Sminshall 		(void) signal(SIGPIPE, oldintp);
79826048Sminshall 	}
79910296Ssam 	gettimeofday(&stop, (struct timezone *)0);
80010296Ssam 	(void) fclose(din);
80126048Sminshall 	(void) getreply(0);
80226048Sminshall 	if (bytes > 0 && verbose)
80326048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
80426048Sminshall 	if (oldtype) {
80526048Sminshall 		if (!debug) {
80626048Sminshall 			verbose = 0;
80726048Sminshall 		}
80826048Sminshall 		switch (oldtype) {
80926048Sminshall 			case TYPE_I:
81026048Sminshall 				setbinary();
81126048Sminshall 				break;
81226048Sminshall 			case TYPE_E:
81326048Sminshall 				setebcdic();
81426048Sminshall 				break;
81526048Sminshall 			case TYPE_L:
81626048Sminshall 				settenex();
81726048Sminshall 				break;
81826048Sminshall 		}
81926048Sminshall 		verbose = oldverbose;
82026048Sminshall 	}
82126048Sminshall 	return;
82226048Sminshall abort:
82326048Sminshall 
82426048Sminshall /* if server command parser understands TELNET commands, abort using */
82526048Sminshall /* recommended IP,SYNC sequence                                      */
82626048Sminshall 
82726048Sminshall 	gettimeofday(&stop, (struct timezone *)0);
82826048Sminshall 	if (oldintp) {
82926048Sminshall 		(void) signal(SIGPIPE, oldintr);
83026048Sminshall 	}
83126048Sminshall 	(void) signal(SIGINT,SIG_IGN);
83226048Sminshall 	if (oldtype) {
83326048Sminshall 		if (!debug) {
83426048Sminshall 			verbose = 0;
83526048Sminshall 		}
83626048Sminshall 		switch (oldtype) {
83726048Sminshall 			case TYPE_I:
83826048Sminshall 				setbinary();
83926048Sminshall 				break;
84026048Sminshall 			case TYPE_E:
84126048Sminshall 				setebcdic();
84226048Sminshall 				break;
84326048Sminshall 			case TYPE_L:
84426048Sminshall 				settenex();
84526048Sminshall 				break;
84626048Sminshall 		}
84726048Sminshall 		verbose = oldverbose;
84826048Sminshall 	}
84926048Sminshall 	if (!cpend) {
85026048Sminshall 		code = -1;
85126048Sminshall 		(void) signal(SIGINT,oldintr);
85226048Sminshall 		return;
85326048Sminshall 	}
85426048Sminshall 	if (telflag) {
85526048Sminshall 		char msg[2];
85626048Sminshall 
85726048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
85826048Sminshall 		(void) fflush(cout);
85926048Sminshall 		*msg = IAC;
86026048Sminshall 		*(msg+1) = DM;
86126048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
86226048Sminshall 			perror("abort");
86326048Sminshall 		}
86426048Sminshall 	}
86526048Sminshall 	fprintf(cout,"ABOR\r\n");
86626048Sminshall 	(void) fflush(cout);
86726048Sminshall 	mask = (1 << fileno(cin)) | (din ? (1 << fileno(din)) : 0);
86826048Sminshall 	if ((mask = empty(mask,10)) < 0) {
86926048Sminshall 		perror("abort");
87026048Sminshall 		code = -1;
87126048Sminshall 		lostpeer();
87226048Sminshall 	}
87326048Sminshall 	if (din && mask & (1 << fileno(din))) {
87426048Sminshall 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0);
87526048Sminshall 	}
87626048Sminshall 	if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */
87726048Sminshall 		if (data >= 0) {
87826048Sminshall 			close(data);
87926048Sminshall 			data = -1;
88026048Sminshall 		}
88125907Smckusick 		(void) getreply(0);
88225907Smckusick 	}
88326048Sminshall 	(void) getreply(0);
88426048Sminshall 	code = -1;
88526048Sminshall 	if (data >= 0) {
88626048Sminshall 		(void) close(data);
88726048Sminshall 		data = -1;
88826048Sminshall 	}
88926048Sminshall 	if (closefunc != NULL && fout != NULL) {
89026048Sminshall 		(*closefunc)(fout);
89126048Sminshall 	}
89226048Sminshall 	if (din) {
89326048Sminshall 		(void) fclose(din);
89426048Sminshall 	}
89510296Ssam 	if (bytes > 0 && verbose)
89626048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
89726048Sminshall 	(void) signal(SIGINT,oldintr);
89810296Ssam }
89910296Ssam 
90010296Ssam /*
90110296Ssam  * Need to start a listen on the data channel
90210296Ssam  * before we send the command, otherwise the
90310296Ssam  * server's connect may fail.
90410296Ssam  */
90511651Ssam static int sendport = -1;
90611651Ssam 
90710296Ssam initconn()
90810296Ssam {
90910296Ssam 	register char *p, *a;
91026048Sminshall 	int result, len, tmpno = 0;
91117450Slepreau 	int on = 1;
91210296Ssam 
91311651Ssam noport:
91410296Ssam 	data_addr = myctladdr;
91511651Ssam 	if (sendport)
91611651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
91711651Ssam 	if (data != -1)
91811651Ssam 		(void) close (data);
91918287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
92010296Ssam 	if (data < 0) {
92110296Ssam 		perror("ftp: socket");
92226048Sminshall 		if (tmpno) {
92326048Sminshall 			sendport = 1;
92426048Sminshall 		}
92510296Ssam 		return (1);
92610296Ssam 	}
92712397Ssam 	if (!sendport)
92817450Slepreau 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
92926048Sminshall 			perror("ftp: setsockopt (resuse address)");
93012397Ssam 			goto bad;
93112397Ssam 		}
93210296Ssam 	if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
93310296Ssam 		perror("ftp: bind");
93410296Ssam 		goto bad;
93510296Ssam 	}
93610296Ssam 	if (options & SO_DEBUG &&
93717450Slepreau 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
93810296Ssam 		perror("ftp: setsockopt (ignored)");
93911627Ssam 	len = sizeof (data_addr);
94011627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
94111627Ssam 		perror("ftp: getsockname");
94210296Ssam 		goto bad;
94310296Ssam 	}
94410296Ssam 	if (listen(data, 1) < 0) {
94510296Ssam 		perror("ftp: listen");
94626048Sminshall 
94710296Ssam 	}
94811651Ssam 	if (sendport) {
94911651Ssam 		a = (char *)&data_addr.sin_addr;
95011651Ssam 		p = (char *)&data_addr.sin_port;
95110296Ssam #define	UC(b)	(((int)b)&0xff)
95211651Ssam 		result =
95311651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
95411651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
95511651Ssam 		      UC(p[0]), UC(p[1]));
95611651Ssam 		if (result == ERROR && sendport == -1) {
95711651Ssam 			sendport = 0;
95826048Sminshall 			tmpno = 1;
95911651Ssam 			goto noport;
96011651Ssam 		}
96111651Ssam 		return (result != COMPLETE);
96211651Ssam 	}
96326048Sminshall 	if (tmpno) {
96426048Sminshall 		sendport = 1;
96526048Sminshall 	}
96611651Ssam 	return (0);
96710296Ssam bad:
96810296Ssam 	(void) close(data), data = -1;
96926048Sminshall 	if (tmpno) {
97026048Sminshall 		sendport = 1;
97126048Sminshall 	}
97210296Ssam 	return (1);
97310296Ssam }
97410296Ssam 
97510296Ssam FILE *
97610296Ssam dataconn(mode)
97710296Ssam 	char *mode;
97810296Ssam {
97910296Ssam 	struct sockaddr_in from;
98010296Ssam 	int s, fromlen = sizeof (from);
98110296Ssam 
98210296Ssam 	s = accept(data, &from, &fromlen, 0);
98310296Ssam 	if (s < 0) {
98410296Ssam 		perror("ftp: accept");
98510296Ssam 		(void) close(data), data = -1;
98610296Ssam 		return (NULL);
98710296Ssam 	}
98810296Ssam 	(void) close(data);
98910296Ssam 	data = s;
99010296Ssam 	return (fdopen(data, mode));
99110296Ssam }
99210296Ssam 
99326048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
99426048Sminshall 	char *direction, *local, *remote;
99511651Ssam 	long bytes;
99610296Ssam 	struct timeval *t0, *t1;
99710296Ssam {
99810296Ssam 	struct timeval td;
99916437Sleres 	float s, bs;
100010296Ssam 
100110296Ssam 	tvsub(&td, t1, t0);
100216437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
100310296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
100416437Sleres 	bs = bytes / nz(s);
100526048Sminshall 	if (local && *local != '-') {
100626048Sminshall 		printf("local: %s ", local);
100726048Sminshall 	}
100826048Sminshall 	if (remote) {
100926048Sminshall 		printf("remote: %s\n", remote);
101026048Sminshall 	}
101116437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
101216437Sleres 		bytes, direction, s, bs / 1024.);
101310296Ssam }
101410296Ssam 
101510296Ssam tvadd(tsum, t0)
101610296Ssam 	struct timeval *tsum, *t0;
101710296Ssam {
101810296Ssam 
101910296Ssam 	tsum->tv_sec += t0->tv_sec;
102010296Ssam 	tsum->tv_usec += t0->tv_usec;
102110296Ssam 	if (tsum->tv_usec > 1000000)
102210296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
102310296Ssam }
102410296Ssam 
102510296Ssam tvsub(tdiff, t1, t0)
102610296Ssam 	struct timeval *tdiff, *t1, *t0;
102710296Ssam {
102810296Ssam 
102910296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
103010296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
103110296Ssam 	if (tdiff->tv_usec < 0)
103210296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
103310296Ssam }
103426048Sminshall 
103526048Sminshall psabort()
103626048Sminshall {
103726048Sminshall 	extern int abrtflag;
103826048Sminshall 
103926048Sminshall 	abrtflag++;
104026048Sminshall }
104126048Sminshall 
104226048Sminshall pswitch(flag)
104326048Sminshall 	int flag;
104426048Sminshall {
104526048Sminshall 	extern int proxy, abrtflag;
104626048Sminshall 	int (*oldintr)();
104726048Sminshall 	static struct comvars {
104826048Sminshall 		int connect;
104926048Sminshall 		char name[32];
105026048Sminshall 		struct sockaddr_in mctl;
105126048Sminshall 		struct sockaddr_in hctl;
105226048Sminshall 		FILE *in;
105326048Sminshall 		FILE *out;
105426048Sminshall 		int tflag;
105526048Sminshall 		int tpe;
105626048Sminshall 		int cpnd;
105726048Sminshall 		int sunqe;
105826048Sminshall 		int runqe;
105926048Sminshall 		int mcse;
106026048Sminshall 		int ntflg;
106126048Sminshall 		char nti[17];
106226048Sminshall 		char nto[17];
106326048Sminshall 		int mapflg;
106426048Sminshall 		char mi[MAXPATHLEN];
106526048Sminshall 		char mo[MAXPATHLEN];
106626048Sminshall 		} proxstruct, tmpstruct;
106726048Sminshall 	struct comvars *ip, *op;
106826048Sminshall 
106926048Sminshall 	abrtflag = 0;
107026048Sminshall 	oldintr = signal(SIGINT, psabort);
107126048Sminshall 	if (flag) {
107226048Sminshall 		if (proxy) {
107326048Sminshall 			return;
107426048Sminshall 		}
107526048Sminshall 		ip = &tmpstruct;
107626048Sminshall 		op = &proxstruct;
107726048Sminshall 		proxy++;
107826048Sminshall 	}
107926048Sminshall 	else {
108026048Sminshall 		if (!proxy) {
108126048Sminshall 			return;
108226048Sminshall 		}
108326048Sminshall 		ip = &proxstruct;
108426048Sminshall 		op = &tmpstruct;
108526048Sminshall 		proxy = 0;
108626048Sminshall 	}
108726048Sminshall 	ip->connect = connected;
108826048Sminshall 	connected = op->connect;
108926048Sminshall 	strncpy(ip->name, hostname, 31);
109026048Sminshall 	(ip->name)[strlen(ip->name)] = '\0';
109126048Sminshall 	hostname = op->name;
109226048Sminshall 	ip->hctl = hisctladdr;
109326048Sminshall 	hisctladdr = op->hctl;
109426048Sminshall 	ip->mctl = myctladdr;
109526048Sminshall 	myctladdr = op->mctl;
109626048Sminshall 	ip->in = cin;
109726048Sminshall 	cin = op->in;
109826048Sminshall 	ip->out = cout;
109926048Sminshall 	cout = op->out;
110026048Sminshall 	ip->tflag = telflag;
110126048Sminshall 	telflag = op->tflag;
110226048Sminshall 	ip->tpe = type;
110326048Sminshall 	type = op->tpe;
110426048Sminshall 	if (!type) {
110526048Sminshall 		type = 1;
110626048Sminshall 	}
110726048Sminshall 	ip->cpnd = cpend;
110826048Sminshall 	cpend = op->cpnd;
110926048Sminshall 	ip->sunqe = sunique;
111026048Sminshall 	sunique = op->sunqe;
111126048Sminshall 	ip->runqe = runique;
111226048Sminshall 	runique = op->runqe;
111326048Sminshall 	ip->mcse = mcase;
111426048Sminshall 	mcase = op->mcse;
111526048Sminshall 	ip->ntflg = ntflag;
111626048Sminshall 	ntflag = op->ntflg;
111726048Sminshall 	strncpy(ip->nti, ntin, 16);
111826048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
111926048Sminshall 	strcpy(ntin, op->nti);
112026048Sminshall 	strncpy(ip->nto, ntout, 16);
112126048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
112226048Sminshall 	strcpy(ntout, op->nto);
112326048Sminshall 	ip->mapflg = mapflag;
112426048Sminshall 	mapflag = op->mapflg;
112526048Sminshall 	strncpy(ip->mi, mapin, MAXPATHLEN - 1);
112626048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
112726048Sminshall 	strcpy(mapin, op->mi);
112826048Sminshall 	strncpy(ip->mo, mapout, MAXPATHLEN - 1);
112926048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
113026048Sminshall 	strcpy(mapout, op->mo);
113126048Sminshall 	(void) signal(SIGINT, oldintr);
113226048Sminshall 	if (abrtflag) {
113326048Sminshall 		abrtflag = 0;
113426048Sminshall 		(*oldintr)();
113526048Sminshall 		}
113626048Sminshall }
113726048Sminshall 
113826048Sminshall jmp_buf ptabort;
113926048Sminshall int ptabflg;
114026048Sminshall 
114126048Sminshall abortpt()
114226048Sminshall {
114326048Sminshall 	printf("\n");
114426048Sminshall 	fflush(stdout);
114526048Sminshall 	ptabflg++;
114626048Sminshall 	mflag = 0;
114726048Sminshall 	abrtflag = 0;
114826048Sminshall 	longjmp(ptabort, 1);
114926048Sminshall }
115026048Sminshall 
115126048Sminshall proxtrans(cmd, local, remote)
115226048Sminshall 	char *cmd, *local, *remote;
115326048Sminshall {
115426048Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0;
115526048Sminshall 	extern jmp_buf ptabort;
115626048Sminshall 	char *cmd2;
115726048Sminshall 	long mask;
115826048Sminshall 
115926048Sminshall 	if (strcmp(cmd, "RETR")) {
116026048Sminshall 		cmd2 = "RETR";
116126048Sminshall 	}
116226048Sminshall 	else {
116326048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
116426048Sminshall 	}
116526048Sminshall 	if (command("PASV") != COMPLETE) {
116626048Sminshall 		printf("proxy server does not support third part transfers.\n");
116726048Sminshall 		return;
116826048Sminshall 	}
116926048Sminshall 	tmptype = type;
117026048Sminshall 	pswitch(0);
117126048Sminshall 	if (!connected) {
117226048Sminshall 		printf("No primary connection\n");
117326048Sminshall 		pswitch(1);
117426048Sminshall 		code = -1;
117526048Sminshall 		return;
117626048Sminshall 	}
117726048Sminshall 	if (type != tmptype) {
117826048Sminshall 		oldtype = type;
117926048Sminshall 		switch (tmptype) {
118026048Sminshall 			case TYPE_A:
118126048Sminshall 				setascii();
118226048Sminshall 				break;
118326048Sminshall 			case TYPE_I:
118426048Sminshall 				setbinary();
118526048Sminshall 				break;
118626048Sminshall 			case TYPE_E:
118726048Sminshall 				setebcdic();
118826048Sminshall 				break;
118926048Sminshall 			case TYPE_L:
119026048Sminshall 				settenex();
119126048Sminshall 				break;
119226048Sminshall 		}
119326048Sminshall 	}
119426048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
119526048Sminshall 		switch (oldtype) {
119626048Sminshall 			case 0:
119726048Sminshall 				break;
119826048Sminshall 			case TYPE_A:
119926048Sminshall 				setascii();
120026048Sminshall 				break;
120126048Sminshall 			case TYPE_I:
120226048Sminshall 				setbinary();
120326048Sminshall 				break;
120426048Sminshall 			case TYPE_E:
120526048Sminshall 				setebcdic();
120626048Sminshall 				break;
120726048Sminshall 			case TYPE_L:
120826048Sminshall 				settenex();
120926048Sminshall 				break;
121026048Sminshall 		}
121126048Sminshall 		pswitch(1);
121226048Sminshall 		return;
121326048Sminshall 	}
121426048Sminshall 	if (setjmp(ptabort)) {
121526048Sminshall 		goto abort;
121626048Sminshall 	}
121726048Sminshall 	oldintr = signal(SIGINT, abortpt);
121826048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
121926048Sminshall 		(void) signal(SIGINT, oldintr);
122026048Sminshall 		switch (oldtype) {
122126048Sminshall 			case 0:
122226048Sminshall 				break;
122326048Sminshall 			case TYPE_A:
122426048Sminshall 				setascii();
122526048Sminshall 				break;
122626048Sminshall 			case TYPE_I:
122726048Sminshall 				setbinary();
122826048Sminshall 				break;
122926048Sminshall 			case TYPE_E:
123026048Sminshall 				setebcdic();
123126048Sminshall 				break;
123226048Sminshall 			case TYPE_L:
123326048Sminshall 				settenex();
123426048Sminshall 				break;
123526048Sminshall 		}
123626048Sminshall 		pswitch(1);
123726048Sminshall 		return;
123826048Sminshall 	}
123926048Sminshall 	sleep(2);
124026048Sminshall 	pswitch(1);
124126048Sminshall 	secndflag++;
124226048Sminshall 	if (command("%s %s", cmd2, local) != PRELIM) {
124326048Sminshall 		goto abort;
124426048Sminshall 	}
124526048Sminshall 	ptflag++;
124626048Sminshall 	(void) getreply(0);
124726048Sminshall 	pswitch(0);
124826048Sminshall 	(void) getreply(0);
124926048Sminshall 	(void) signal(SIGINT, oldintr);
125026048Sminshall 	switch (oldtype) {
125126048Sminshall 		case 0:
125226048Sminshall 			break;
125326048Sminshall 		case TYPE_A:
125426048Sminshall 			setascii();
125526048Sminshall 			break;
125626048Sminshall 		case TYPE_I:
125726048Sminshall 			setbinary();
125826048Sminshall 			break;
125926048Sminshall 		case TYPE_E:
126026048Sminshall 			setebcdic();
126126048Sminshall 			break;
126226048Sminshall 		case TYPE_L:
126326048Sminshall 			settenex();
126426048Sminshall 			break;
126526048Sminshall 	}
126626048Sminshall 	pswitch(1);
126726048Sminshall 	ptflag = 0;
126826048Sminshall 	printf("local: %s remote: %s\n", local, remote);
126926048Sminshall 	return;
127026048Sminshall abort:
127126048Sminshall 	(void) signal(SIGINT, SIG_IGN);
127226048Sminshall 	ptflag = 0;
127326048Sminshall 	if (strcmp(cmd, "RETR") && !proxy) {
127426048Sminshall 		pswitch(1);
127526048Sminshall 	}
127626048Sminshall 	else if (!strcmp(cmd, "RETR") && proxy) {
127726048Sminshall 		pswitch(0);
127826048Sminshall 	}
127926048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
128026048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
128126048Sminshall 			pswitch(0);
128226048Sminshall 			switch (oldtype) {
128326048Sminshall 				case 0:
128426048Sminshall 					break;
128526048Sminshall 				case TYPE_A:
128626048Sminshall 					setascii();
128726048Sminshall 					break;
128826048Sminshall 				case TYPE_I:
128926048Sminshall 					setbinary();
129026048Sminshall 					break;
129126048Sminshall 				case TYPE_E:
129226048Sminshall 					setebcdic();
129326048Sminshall 					break;
129426048Sminshall 				case TYPE_L:
129526048Sminshall 					settenex();
129626048Sminshall 					break;
129726048Sminshall 			}
129826048Sminshall 			if (cpend && telflag) {
129926048Sminshall 				char msg[2];
130026048Sminshall 
130126048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
130226048Sminshall 				(void) fflush(cout);
130326048Sminshall 				*msg = IAC;
130426048Sminshall 				*(msg+1) = DM;
130526048Sminshall 				if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
130626048Sminshall 					perror("abort");
130726048Sminshall 				}
130826048Sminshall 			}
130926048Sminshall 			if (cpend) {
131026048Sminshall 				fprintf(cout,"ABOR\r\n");
131126048Sminshall 				(void) fflush(cout);
131226048Sminshall 				mask = 1 << fileno(cin);
131326048Sminshall 				if ((mask = empty(mask,10)) < 0) {
131426048Sminshall 					perror("abort");
131526048Sminshall 					if (ptabflg) {
131626048Sminshall 						code = -1;
131726048Sminshall 					}
131826048Sminshall 					lostpeer();
131926048Sminshall 				}
132026048Sminshall 				(void) getreply(0);
132126048Sminshall 				(void) getreply(0);
132226048Sminshall 			}
132326048Sminshall 		}
132426048Sminshall 		pswitch(1);
132526048Sminshall 		if (ptabflg) {
132626048Sminshall 			code = -1;
132726048Sminshall 		}
132826048Sminshall 		(void) signal(SIGINT, oldintr);
132926048Sminshall 		return;
133026048Sminshall 	}
133126048Sminshall 	if (cpend && telflag) {
133226048Sminshall 		char msg[2];
133326048Sminshall 
133426048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
133526048Sminshall 		(void) fflush(cout);
133626048Sminshall 		*msg = IAC;
133726048Sminshall 		*(msg+1) = DM;
133826048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
133926048Sminshall 			perror("abort");
134026048Sminshall 		}
134126048Sminshall 	}
134226048Sminshall 	if (cpend) {
134326048Sminshall 		fprintf(cout,"ABOR\r\n");
134426048Sminshall 		(void) fflush(cout);
134526048Sminshall 		mask = 1 << fileno(cin);
134626048Sminshall 		if ((mask = empty(mask,10)) < 0) {
134726048Sminshall 			perror("abort");
134826048Sminshall 			if (ptabflg) {
134926048Sminshall 				code = -1;
135026048Sminshall 			}
135126048Sminshall 			lostpeer();
135226048Sminshall 		}
135326048Sminshall 		(void) getreply(0);
135426048Sminshall 		(void) getreply(0);
135526048Sminshall 	}
135626048Sminshall 	pswitch(!proxy);
135726048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
135826048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
135926048Sminshall 			pswitch(0);
136026048Sminshall 			switch (oldtype) {
136126048Sminshall 				case 0:
136226048Sminshall 					break;
136326048Sminshall 				case TYPE_A:
136426048Sminshall 					setascii();
136526048Sminshall 					break;
136626048Sminshall 				case TYPE_I:
136726048Sminshall 					setbinary();
136826048Sminshall 					break;
136926048Sminshall 				case TYPE_E:
137026048Sminshall 					setebcdic();
137126048Sminshall 					break;
137226048Sminshall 				case TYPE_L:
137326048Sminshall 					settenex();
137426048Sminshall 					break;
137526048Sminshall 			}
137626048Sminshall 			if (cpend && telflag) {
137726048Sminshall 				char msg[2];
137826048Sminshall 
137926048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
138026048Sminshall 				(void) fflush(cout);
138126048Sminshall 				*msg = IAC;
138226048Sminshall 				*(msg+1) = DM;
138326048Sminshall 				if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
138426048Sminshall 					perror("abort");
138526048Sminshall 				}
138626048Sminshall 			}
138726048Sminshall 			if (cpend) {
138826048Sminshall 				fprintf(cout,"ABOR\r\n");
138926048Sminshall 				(void) fflush(cout);
139026048Sminshall 				mask = 1 << fileno(cin);
139126048Sminshall 				if ((mask = empty(mask,10)) < 0) {
139226048Sminshall 					perror("abort");
139326048Sminshall 					if (ptabflg) {
139426048Sminshall 						code = -1;
139526048Sminshall 					}
139626048Sminshall 					lostpeer();
139726048Sminshall 				}
139826048Sminshall 				(void) getreply(0);
139926048Sminshall 				(void) getreply(0);
140026048Sminshall 			}
140126048Sminshall 			pswitch(1);
140226048Sminshall 			if (ptabflg) {
140326048Sminshall 				code = -1;
140426048Sminshall 			}
140526048Sminshall 			(void) signal(SIGINT, oldintr);
140626048Sminshall 			return;
140726048Sminshall 		}
140826048Sminshall 	}
140926048Sminshall 	if (cpend && telflag) {
141026048Sminshall 		char msg[2];
141126048Sminshall 
141226048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
141326048Sminshall 		(void) fflush(cout);
141426048Sminshall 		*msg = IAC;
141526048Sminshall 		*(msg+1) = DM;
141626048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
141726048Sminshall 			perror("abort");
141826048Sminshall 		}
141926048Sminshall 	}
142026048Sminshall 	if (cpend) {
142126048Sminshall 		fprintf(cout,"ABOR\r\n");
142226048Sminshall 		(void) fflush(cout);
142326048Sminshall 		mask = 1 << fileno(cin);
142426048Sminshall 		if ((mask = empty(mask,10)) < 0) {
142526048Sminshall 			perror("abort");
142626048Sminshall 			if (ptabflg) {
142726048Sminshall 				code = -1;
142826048Sminshall 			}
142926048Sminshall 			lostpeer();
143026048Sminshall 		}
143126048Sminshall 		(void) getreply(0);
143226048Sminshall 		(void) getreply(0);
143326048Sminshall 	}
143426048Sminshall 	pswitch(!proxy);
143526048Sminshall 	if (cpend) {
143626048Sminshall 		mask = 1 << fileno(cin);
143726048Sminshall 		if ((mask = empty(mask,10)) < 0) {
143826048Sminshall 			perror("abort");
143926048Sminshall 			if (ptabflg) {
144026048Sminshall 				code = -1;
144126048Sminshall 			}
144226048Sminshall 			lostpeer();
144326048Sminshall 		}
144426048Sminshall 		(void) getreply(0);
144526048Sminshall 		(void) getreply(0);
144626048Sminshall 	}
144726048Sminshall 	if (proxy) {
144826048Sminshall 		pswitch(0);
144926048Sminshall 	}
145026048Sminshall 	switch (oldtype) {
145126048Sminshall 		case 0:
145226048Sminshall 			break;
145326048Sminshall 		case TYPE_A:
145426048Sminshall 			setascii();
145526048Sminshall 			break;
145626048Sminshall 		case TYPE_I:
145726048Sminshall 			setbinary();
145826048Sminshall 			break;
145926048Sminshall 		case TYPE_E:
146026048Sminshall 			setebcdic();
146126048Sminshall 			break;
146226048Sminshall 		case TYPE_L:
146326048Sminshall 			settenex();
146426048Sminshall 			break;
146526048Sminshall 	}
146626048Sminshall 	pswitch(1);
146726048Sminshall 	if (ptabflg) {
146826048Sminshall 		code = -1;
146926048Sminshall 	}
147026048Sminshall 	(void) signal(SIGINT, oldintr);
147126048Sminshall }
147226048Sminshall 
147326048Sminshall reset()
147426048Sminshall {
147526048Sminshall 	long mask;
147626048Sminshall 
147726048Sminshall 	mask = 1 << fileno(cin);
147826048Sminshall 	while (mask > 0) {
147926048Sminshall 		if ((mask = empty(mask,0)) < 0) {
148026048Sminshall 			perror("reset");
148126048Sminshall 			code = -1;
148226048Sminshall 			lostpeer();
148326048Sminshall 		}
148426048Sminshall 		if (mask > 0) {
148526048Sminshall 			(void) getreply(0);
148626048Sminshall 		}
148726048Sminshall 	}
148826048Sminshall }
148926048Sminshall 
149026048Sminshall char *
149126048Sminshall gunique(local)
149226048Sminshall 	char *local;
149326048Sminshall {
149426048Sminshall 	static char new[MAXPATHLEN];
149526048Sminshall 	char *cp = rindex(local, '/');
149626048Sminshall 	int d, count=0;
149726048Sminshall 	char ext = '1';
149826048Sminshall 
149926048Sminshall 	if (cp) {
150026048Sminshall 		*cp = '\0';
150126048Sminshall 	}
150226048Sminshall 	d = access(cp ? local : ".", 2);
150326048Sminshall 	if (cp) {
150426048Sminshall 		*cp = '/';
150526048Sminshall 	}
150626048Sminshall 	if (d < 0) {
150726048Sminshall 		perror(local);
150826048Sminshall 		return((char *) 0);
150926048Sminshall 	}
151026048Sminshall 	(void) strcpy(new, local);
151126048Sminshall 	cp = new + strlen(new);
151226048Sminshall 	*cp++ = '.';
151326048Sminshall 	while (!d) {
151426048Sminshall 		if (++count == 100) {
151526048Sminshall 			printf("runique: can't find unique file name.\n");
151626048Sminshall 			return((char *) 0);
151726048Sminshall 		}
151826048Sminshall 		*cp++ = ext;
151926048Sminshall 		*cp = '\0';
152026048Sminshall 		if (ext == '9') {
152126048Sminshall 			ext = '0';
152226048Sminshall 		}
152326048Sminshall 		else {
152426048Sminshall 			ext++;
152526048Sminshall 		}
152626048Sminshall 		if ((d = access(new, 0)) < 0) {
152726048Sminshall 			break;
152826048Sminshall 		}
152926048Sminshall 		if (ext != '0') {
153026048Sminshall 			cp--;
153126048Sminshall 		}
153226048Sminshall 		else if (*(cp - 2) == '.') {
153326048Sminshall 			*(cp - 1) = '1';
153426048Sminshall 		}
153526048Sminshall 		else {
153626048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
153726048Sminshall 			cp--;
153826048Sminshall 		}
153926048Sminshall 	}
154026048Sminshall 	return(new);
154126048Sminshall }
1542