xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 38033)
121739Sdist /*
236942Skarels  * Copyright (c) 1985, 1989 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1536935Skarels  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621739Sdist  */
1721739Sdist 
1810296Ssam #ifndef lint
19*38033Skarels static char sccsid[] = "@(#)ftp.c	5.29 (Berkeley) 05/17/89";
2033737Sbostic #endif /* not lint */
2110296Ssam 
2236940Skarels #include <sys/param.h>
2310296Ssam #include <sys/stat.h>
2410296Ssam #include <sys/ioctl.h>
2510296Ssam #include <sys/socket.h>
2613614Ssam #include <sys/time.h>
2736935Skarels #include <sys/file.h>
2810296Ssam 
2910296Ssam #include <netinet/in.h>
3012397Ssam #include <arpa/ftp.h>
3126048Sminshall #include <arpa/telnet.h>
3210296Ssam 
3310296Ssam #include <stdio.h>
3410296Ssam #include <signal.h>
3510296Ssam #include <errno.h>
3610296Ssam #include <netdb.h>
3726048Sminshall #include <fcntl.h>
3826048Sminshall #include <pwd.h>
3910296Ssam 
4036940Skarels #include "ftp_var.h"
4136940Skarels 
4210296Ssam struct	sockaddr_in hisctladdr;
4310296Ssam struct	sockaddr_in data_addr;
4410296Ssam int	data = -1;
4526048Sminshall int	abrtflag = 0;
4626048Sminshall int	ptflag = 0;
4710296Ssam int	connected;
4810296Ssam struct	sockaddr_in myctladdr;
4926496Sminshall uid_t	getuid();
5037225Skarels off_t	restart_point = 0;
5110296Ssam 
5210296Ssam FILE	*cin, *cout;
5310296Ssam FILE	*dataconn();
5410296Ssam 
5525904Skarels char *
5610296Ssam hookup(host, port)
5710296Ssam 	char *host;
5810296Ssam 	int port;
5910296Ssam {
6025904Skarels 	register struct hostent *hp = 0;
6127687Sminshall 	int s,len;
6225904Skarels 	static char hostnamebuf[80];
6310296Ssam 
6410296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
6525904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6625904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6725904Skarels 		hisctladdr.sin_family = AF_INET;
6836940Skarels 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
6936940Skarels 	} else {
7025100Sbloom 		hp = gethostbyname(host);
7125904Skarels 		if (hp == NULL) {
7235792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
7335792Sbostic 			herror((char *)NULL);
7426048Sminshall 			code = -1;
7526048Sminshall 			return((char *) 0);
7625904Skarels 		}
7725904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7825904Skarels 		bcopy(hp->h_addr_list[0],
7925904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8036940Skarels 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
8110296Ssam 	}
8225904Skarels 	hostname = hostnamebuf;
8325904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8410296Ssam 	if (s < 0) {
8510296Ssam 		perror("ftp: socket");
8626048Sminshall 		code = -1;
8710296Ssam 		return (0);
8810296Ssam 	}
8910296Ssam 	hisctladdr.sin_port = port;
9026496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
9125904Skarels 		if (hp && hp->h_addr_list[1]) {
9225904Skarels 			int oerrno = errno;
9325904Skarels 
9425904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9525904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9625904Skarels 			errno = oerrno;
9726496Sminshall 			perror((char *) 0);
9825904Skarels 			hp->h_addr_list++;
9925904Skarels 			bcopy(hp->h_addr_list[0],
10026048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
10126496Sminshall 			fprintf(stdout, "Trying %s...\n",
10225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10326813Skarels 			(void) close(s);
10426813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10526813Skarels 			if (s < 0) {
10626813Skarels 				perror("ftp: socket");
10726813Skarels 				code = -1;
10826813Skarels 				return (0);
10926813Skarels 			}
11025904Skarels 			continue;
11125904Skarels 		}
11210296Ssam 		perror("ftp: connect");
11326048Sminshall 		code = -1;
11410296Ssam 		goto bad;
11510296Ssam 	}
11611627Ssam 	len = sizeof (myctladdr);
11711627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
11811627Ssam 		perror("ftp: getsockname");
11926048Sminshall 		code = -1;
12010296Ssam 		goto bad;
12110296Ssam 	}
12210296Ssam 	cin = fdopen(s, "r");
12310296Ssam 	cout = fdopen(s, "w");
12411219Ssam 	if (cin == NULL || cout == NULL) {
12510296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12610296Ssam 		if (cin)
12726496Sminshall 			(void) fclose(cin);
12810296Ssam 		if (cout)
12926496Sminshall 			(void) fclose(cout);
13026048Sminshall 		code = -1;
13110296Ssam 		goto bad;
13210296Ssam 	}
13310296Ssam 	if (verbose)
13426067Sminshall 		printf("Connected to %s.\n", hostname);
13527687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13626048Sminshall 		if (cin)
13726496Sminshall 			(void) fclose(cin);
13826048Sminshall 		if (cout)
13926496Sminshall 			(void) fclose(cout);
14026048Sminshall 		code = -1;
14126048Sminshall 		goto bad;
14226048Sminshall 	}
14327687Sminshall #ifdef SO_OOBINLINE
14427687Sminshall 	{
14527687Sminshall 	int on = 1;
14626048Sminshall 
14727687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
14827687Sminshall 		< 0 && debug) {
14927687Sminshall 			perror("ftp: setsockopt");
15027687Sminshall 		}
15127687Sminshall 	}
15227687Sminshall #endif SO_OOBINLINE
15326048Sminshall 
15425904Skarels 	return (hostname);
15510296Ssam bad:
15626496Sminshall 	(void) close(s);
15725904Skarels 	return ((char *)0);
15810296Ssam }
15910296Ssam 
16025904Skarels login(host)
16125904Skarels 	char *host;
16210296Ssam {
16326048Sminshall 	char tmp[80];
16435659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16526048Sminshall 	int n, aflag = 0;
16610296Ssam 
16726048Sminshall 	user = pass = acct = 0;
16826048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16926048Sminshall 		code = -1;
17026048Sminshall 		return(0);
17126048Sminshall 	}
17237458Skarels 	while (user == NULL) {
17326048Sminshall 		char *myname = getlogin();
17426048Sminshall 
17526048Sminshall 		if (myname == NULL) {
17626048Sminshall 			struct passwd *pp = getpwuid(getuid());
17726048Sminshall 
17826448Slepreau 			if (pp != NULL)
17926048Sminshall 				myname = pp->pw_name;
18026048Sminshall 		}
18137458Skarels 		if (myname)
18237458Skarels 			printf("Name (%s:%s): ", host, myname);
18337458Skarels 		else
18437458Skarels 			printf("Name (%s): ", host);
18526048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18626048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18726448Slepreau 		if (*tmp == '\0')
18826048Sminshall 			user = myname;
18926448Slepreau 		else
19026048Sminshall 			user = tmp;
19126048Sminshall 	}
19210296Ssam 	n = command("USER %s", user);
19326048Sminshall 	if (n == CONTINUE) {
19426448Slepreau 		if (pass == NULL)
19535659Sbostic 			pass = getpass("Password:");
19610296Ssam 		n = command("PASS %s", pass);
19726048Sminshall 	}
19810296Ssam 	if (n == CONTINUE) {
19926048Sminshall 		aflag++;
20035659Sbostic 		acct = getpass("Account:");
20110296Ssam 		n = command("ACCT %s", acct);
20210296Ssam 	}
20310296Ssam 	if (n != COMPLETE) {
20410296Ssam 		fprintf(stderr, "Login failed.\n");
20510296Ssam 		return (0);
20610296Ssam 	}
20726448Slepreau 	if (!aflag && acct != NULL)
20826048Sminshall 		(void) command("ACCT %s", acct);
20926448Slepreau 	if (proxy)
21026048Sminshall 		return(1);
21126048Sminshall 	for (n = 0; n < macnum; ++n) {
21226048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21326496Sminshall 			(void) strcpy(line, "$init");
21426048Sminshall 			makeargv();
21526048Sminshall 			domacro(margc, margv);
21626048Sminshall 			break;
21726048Sminshall 		}
21826048Sminshall 	}
21910296Ssam 	return (1);
22010296Ssam }
22110296Ssam 
22226048Sminshall cmdabort()
22326048Sminshall {
22426048Sminshall 	extern jmp_buf ptabort;
22526048Sminshall 
22626048Sminshall 	printf("\n");
22726048Sminshall 	(void) fflush(stdout);
22826048Sminshall 	abrtflag++;
22926448Slepreau 	if (ptflag)
23026048Sminshall 		longjmp(ptabort,1);
23126048Sminshall }
23226048Sminshall 
23326496Sminshall /*VARARGS1*/
23410296Ssam command(fmt, args)
23510296Ssam 	char *fmt;
23610296Ssam {
23726048Sminshall 	int r, (*oldintr)(), cmdabort();
238*38033Skarels 	char *xxx = "XXX";
23910296Ssam 
24026048Sminshall 	abrtflag = 0;
24110296Ssam 	if (debug) {
24210296Ssam 		printf("---> ");
243*38033Skarels 		if (strncmp(fmt, "PASS", 4) == 0)
244*38033Skarels 			_doprnt(fmt, (int *)&xxx, stdout);
245*38033Skarels 		else
246*38033Skarels 			_doprnt(fmt, &args, stdout);
24710296Ssam 		printf("\n");
24810296Ssam 		(void) fflush(stdout);
24910296Ssam 	}
25011219Ssam 	if (cout == NULL) {
25111219Ssam 		perror ("No control connection for command");
25226048Sminshall 		code = -1;
25311219Ssam 		return (0);
25411219Ssam 	}
25526048Sminshall 	oldintr = signal(SIGINT,cmdabort);
25610296Ssam 	_doprnt(fmt, &args, cout);
25710296Ssam 	fprintf(cout, "\r\n");
25810296Ssam 	(void) fflush(cout);
25926048Sminshall 	cpend = 1;
26026048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
26126448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
26226048Sminshall 		(*oldintr)();
26326048Sminshall 	(void) signal(SIGINT, oldintr);
26426048Sminshall 	return(r);
26510296Ssam }
26610296Ssam 
26737229Skarels char reply_string[BUFSIZ];		/* last line of previous reply */
26836935Skarels 
26910296Ssam #include <ctype.h>
27010296Ssam 
27110296Ssam getreply(expecteof)
27210296Ssam 	int expecteof;
27310296Ssam {
27411219Ssam 	register int c, n;
27526048Sminshall 	register int dig;
27636935Skarels 	register char *cp;
27726048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
27826048Sminshall 	int pflag = 0;
27926048Sminshall 	char *pt = pasv;
28010296Ssam 
28126048Sminshall 	oldintr = signal(SIGINT,cmdabort);
28210296Ssam 	for (;;) {
28310296Ssam 		dig = n = code = 0;
28437229Skarels 		cp = reply_string;
28510296Ssam 		while ((c = getc(cin)) != '\n') {
28627687Sminshall 			if (c == IAC) {     /* handle telnet commands */
28727687Sminshall 				switch (c = getc(cin)) {
28827687Sminshall 				case WILL:
28927687Sminshall 				case WONT:
29027687Sminshall 					c = getc(cin);
29136940Skarels 					fprintf(cout, "%c%c%c",IAC,DONT,c);
29227687Sminshall 					(void) fflush(cout);
29327687Sminshall 					break;
29427687Sminshall 				case DO:
29527687Sminshall 				case DONT:
29627687Sminshall 					c = getc(cin);
29736940Skarels 					fprintf(cout, "%c%c%c",IAC,WONT,c);
29827687Sminshall 					(void) fflush(cout);
29927687Sminshall 					break;
30027687Sminshall 				default:
30127687Sminshall 					break;
30227687Sminshall 				}
30327687Sminshall 				continue;
30427687Sminshall 			}
30510296Ssam 			dig++;
30610296Ssam 			if (c == EOF) {
30726048Sminshall 				if (expecteof) {
30826048Sminshall 					(void) signal(SIGINT,oldintr);
30926048Sminshall 					code = 221;
31010296Ssam 					return (0);
31126048Sminshall 				}
31210296Ssam 				lostpeer();
31326048Sminshall 				if (verbose) {
31426048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
31526048Sminshall 					(void) fflush(stdout);
31626048Sminshall 				}
31733772Scsvsj 				code = 421;
31833772Scsvsj 				return(4);
31910296Ssam 			}
32026048Sminshall 			if (c != '\r' && (verbose > 0 ||
32126048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
32226448Slepreau 				if (proxflag &&
32326448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
32426048Sminshall 					printf("%s:",hostname);
32526496Sminshall 				(void) putchar(c);
32626048Sminshall 			}
32710296Ssam 			if (dig < 4 && isdigit(c))
32810296Ssam 				code = code * 10 + (c - '0');
32926448Slepreau 			if (!pflag && code == 227)
33026048Sminshall 				pflag = 1;
33126448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
33226048Sminshall 				pflag = 2;
33326048Sminshall 			if (pflag == 2) {
33426448Slepreau 				if (c != '\r' && c != ')')
33526048Sminshall 					*pt++ = c;
33626048Sminshall 				else {
33726048Sminshall 					*pt = '\0';
33826048Sminshall 					pflag = 3;
33926048Sminshall 				}
34026048Sminshall 			}
34126048Sminshall 			if (dig == 4 && c == '-') {
34226448Slepreau 				if (continuation)
34326048Sminshall 					code = 0;
34410296Ssam 				continuation++;
34526048Sminshall 			}
34610296Ssam 			if (n == 0)
34710296Ssam 				n = c;
34837229Skarels 			if (cp < &reply_string[sizeof(reply_string) - 1])
34937229Skarels 				*cp++ = c;
35010296Ssam 		}
35126048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
35226496Sminshall 			(void) putchar(c);
35311346Ssam 			(void) fflush (stdout);
35411346Ssam 		}
35510296Ssam 		if (continuation && code != originalcode) {
35610296Ssam 			if (originalcode == 0)
35710296Ssam 				originalcode = code;
35810296Ssam 			continue;
35910296Ssam 		}
36036935Skarels 		*cp = '\0';
36126448Slepreau 		if (n != '1')
36226048Sminshall 			cpend = 0;
36326048Sminshall 		(void) signal(SIGINT,oldintr);
36426448Slepreau 		if (code == 421 || originalcode == 421)
36526048Sminshall 			lostpeer();
36626448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
36726048Sminshall 			(*oldintr)();
36825907Smckusick 		return (n - '0');
36910296Ssam 	}
37010296Ssam }
37110296Ssam 
37226048Sminshall empty(mask, sec)
37327687Sminshall 	struct fd_set *mask;
37426048Sminshall 	int sec;
37526048Sminshall {
37626048Sminshall 	struct timeval t;
37726048Sminshall 
37826048Sminshall 	t.tv_sec = (long) sec;
37926048Sminshall 	t.tv_usec = 0;
38027687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
38126048Sminshall }
38226048Sminshall 
38310296Ssam jmp_buf	sendabort;
38410296Ssam 
38510296Ssam abortsend()
38610296Ssam {
38710296Ssam 
38826048Sminshall 	mflag = 0;
38926048Sminshall 	abrtflag = 0;
39026048Sminshall 	printf("\nsend aborted\n");
39126048Sminshall 	(void) fflush(stdout);
39210296Ssam 	longjmp(sendabort, 1);
39310296Ssam }
39410296Ssam 
39536940Skarels #define HASHBYTES 1024
39636940Skarels 
39737225Skarels sendrequest(cmd, local, remote, printnames)
39810296Ssam 	char *cmd, *local, *remote;
39937225Skarels 	int printnames;
40010296Ssam {
40135659Sbostic 	FILE *fin, *dout = 0, *popen();
40235659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
40326048Sminshall 	int abortsend();
40436942Skarels 	char buf[BUFSIZ], *bufp;
40536940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
40611346Ssam 	register int c, d;
40710296Ssam 	struct stat st;
40810296Ssam 	struct timeval start, stop;
40936935Skarels 	char *mode;
41010296Ssam 
41137225Skarels 	if (verbose && printnames) {
41237225Skarels 		if (local && *local != '-')
41337225Skarels 			printf("local: %s ", local);
41437225Skarels 		if (remote)
41537225Skarels 			printf("remote: %s\n", remote);
41637225Skarels 	}
41726048Sminshall 	if (proxy) {
41826048Sminshall 		proxtrans(cmd, local, remote);
41926048Sminshall 		return;
42026048Sminshall 	}
421*38033Skarels 	if (curtype != type)
422*38033Skarels 		changetype(type, 0);
42310296Ssam 	closefunc = NULL;
42426048Sminshall 	oldintr = NULL;
42526048Sminshall 	oldintp = NULL;
42636935Skarels 	mode = "w";
42726048Sminshall 	if (setjmp(sendabort)) {
42826048Sminshall 		while (cpend) {
42926048Sminshall 			(void) getreply(0);
43026048Sminshall 		}
43126048Sminshall 		if (data >= 0) {
43226048Sminshall 			(void) close(data);
43326048Sminshall 			data = -1;
43426048Sminshall 		}
43526448Slepreau 		if (oldintr)
43626048Sminshall 			(void) signal(SIGINT,oldintr);
43726448Slepreau 		if (oldintp)
43826048Sminshall 			(void) signal(SIGPIPE,oldintp);
43926048Sminshall 		code = -1;
44026048Sminshall 		return;
44126048Sminshall 	}
44210296Ssam 	oldintr = signal(SIGINT, abortsend);
44310296Ssam 	if (strcmp(local, "-") == 0)
44410296Ssam 		fin = stdin;
44510296Ssam 	else if (*local == '|') {
44626048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
44735659Sbostic 		fin = popen(local + 1, "r");
44810296Ssam 		if (fin == NULL) {
44926048Sminshall 			perror(local + 1);
45026048Sminshall 			(void) signal(SIGINT, oldintr);
45126048Sminshall 			(void) signal(SIGPIPE, oldintp);
45226048Sminshall 			code = -1;
45326048Sminshall 			return;
45410296Ssam 		}
45535659Sbostic 		closefunc = pclose;
45610296Ssam 	} else {
45710296Ssam 		fin = fopen(local, "r");
45810296Ssam 		if (fin == NULL) {
45910296Ssam 			perror(local);
46026048Sminshall 			(void) signal(SIGINT, oldintr);
46126048Sminshall 			code = -1;
46226048Sminshall 			return;
46310296Ssam 		}
46410296Ssam 		closefunc = fclose;
46510296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
46610296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
46726496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
46826048Sminshall 			(void) signal(SIGINT, oldintr);
46936935Skarels 			fclose(fin);
47026048Sminshall 			code = -1;
47126048Sminshall 			return;
47210296Ssam 		}
47310296Ssam 	}
47426048Sminshall 	if (initconn()) {
47526048Sminshall 		(void) signal(SIGINT, oldintr);
47626448Slepreau 		if (oldintp)
47726048Sminshall 			(void) signal(SIGPIPE, oldintp);
47826048Sminshall 		code = -1;
47936935Skarels 		if (closefunc != NULL)
48036935Skarels 			(*closefunc)(fin);
48126048Sminshall 		return;
48226048Sminshall 	}
48326448Slepreau 	if (setjmp(sendabort))
48426048Sminshall 		goto abort;
48536935Skarels 
48637225Skarels 	if (restart_point &&
48737225Skarels 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
48837225Skarels 		if (fseek(fin, (long) restart_point, 0) < 0) {
48937225Skarels 			perror(local);
49037225Skarels 			restart_point = 0;
49137225Skarels 			if (closefunc != NULL)
49237225Skarels 				(*closefunc)(fin);
49337225Skarels 			return;
49437225Skarels 		}
49537225Skarels 		if (command("REST %ld", (long) restart_point)
49637225Skarels 			!= CONTINUE) {
49737225Skarels 			restart_point = 0;
49837225Skarels 			if (closefunc != NULL)
49937225Skarels 				(*closefunc)(fin);
50037225Skarels 			return;
50137225Skarels 		}
50237225Skarels 		restart_point = 0;
50337225Skarels 		mode = "r+w";
50437225Skarels 	}
50510296Ssam 	if (remote) {
50626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
50726048Sminshall 			(void) signal(SIGINT, oldintr);
50826448Slepreau 			if (oldintp)
50926048Sminshall 				(void) signal(SIGPIPE, oldintp);
51036935Skarels 			if (closefunc != NULL)
51136935Skarels 				(*closefunc)(fin);
51226048Sminshall 			return;
51326048Sminshall 		}
51410296Ssam 	} else
51526048Sminshall 		if (command("%s", cmd) != PRELIM) {
51626048Sminshall 			(void) signal(SIGINT, oldintr);
51726448Slepreau 			if (oldintp)
51826048Sminshall 				(void) signal(SIGPIPE, oldintp);
51936935Skarels 			if (closefunc != NULL)
52036935Skarels 				(*closefunc)(fin);
52126048Sminshall 			return;
52226048Sminshall 		}
52336935Skarels 	dout = dataconn(mode);
52426448Slepreau 	if (dout == NULL)
52526048Sminshall 		goto abort;
52626496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
52736935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
52811219Ssam 	switch (type) {
52911219Ssam 
53011219Ssam 	case TYPE_I:
53111219Ssam 	case TYPE_L:
53211346Ssam 		errno = d = 0;
53336942Skarels 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
53411219Ssam 			bytes += c;
53536942Skarels 			for (bufp = buf; c > 0; c -= d, bufp += d)
53636942Skarels 				if ((d = write(fileno(dout), bufp, c)) <= 0)
53736942Skarels 					break;
53811651Ssam 			if (hash) {
53936940Skarels 				while (bytes >= hashbytes) {
54036940Skarels 					(void) putchar('#');
54136940Skarels 					hashbytes += HASHBYTES;
54236940Skarels 				}
54326496Sminshall 				(void) fflush(stdout);
54411651Ssam 			}
54511219Ssam 		}
54613213Ssam 		if (hash && bytes > 0) {
54736940Skarels 			if (bytes < HASHBYTES)
54836940Skarels 				(void) putchar('#');
54926496Sminshall 			(void) putchar('\n');
55026496Sminshall 			(void) fflush(stdout);
55111651Ssam 		}
55211219Ssam 		if (c < 0)
55311219Ssam 			perror(local);
55436942Skarels 		if (d <= 0) {
55536942Skarels 			if (d == 0)
55636942Skarels 				fprintf(stderr, "netout: write returned 0?\n");
55736942Skarels 			else if (errno != EPIPE)
55836935Skarels 				perror("netout");
55936935Skarels 			bytes = -1;
56036935Skarels 		}
56111219Ssam 		break;
56211219Ssam 
56311219Ssam 	case TYPE_A:
56411219Ssam 		while ((c = getc(fin)) != EOF) {
56511219Ssam 			if (c == '\n') {
56611651Ssam 				while (hash && (bytes >= hashbytes)) {
56726496Sminshall 					(void) putchar('#');
56826496Sminshall 					(void) fflush(stdout);
56936940Skarels 					hashbytes += HASHBYTES;
57011651Ssam 				}
57111219Ssam 				if (ferror(dout))
57211219Ssam 					break;
57326496Sminshall 				(void) putc('\r', dout);
57411219Ssam 				bytes++;
57511219Ssam 			}
57626496Sminshall 			(void) putc(c, dout);
57711219Ssam 			bytes++;
57826048Sminshall 	/*		if (c == '\r') {			  	*/
57926496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
58026048Sminshall 	/*			bytes++;				*/
58126048Sminshall 	/*		}                          			*/
58211219Ssam 		}
58311651Ssam 		if (hash) {
58413213Ssam 			if (bytes < hashbytes)
58526496Sminshall 				(void) putchar('#');
58626496Sminshall 			(void) putchar('\n');
58726496Sminshall 			(void) fflush(stdout);
58811651Ssam 		}
58911219Ssam 		if (ferror(fin))
59011219Ssam 			perror(local);
59136935Skarels 		if (ferror(dout)) {
59236935Skarels 			if (errno != EPIPE)
59336935Skarels 				perror("netout");
59436935Skarels 			bytes = -1;
59536935Skarels 		}
59611219Ssam 		break;
59710296Ssam 	}
59826496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
59910296Ssam 	if (closefunc != NULL)
60026048Sminshall 		(*closefunc)(fin);
60110296Ssam 	(void) fclose(dout);
60226048Sminshall 	(void) getreply(0);
60326048Sminshall 	(void) signal(SIGINT, oldintr);
60436935Skarels 	if (oldintp)
60536935Skarels 		(void) signal(SIGPIPE, oldintp);
60635699Sbostic 	if (bytes > 0)
60737225Skarels 		ptransfer("sent", bytes, &start, &stop);
60810296Ssam 	return;
60926048Sminshall abort:
61026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
61126048Sminshall 	(void) signal(SIGINT, oldintr);
61226448Slepreau 	if (oldintp)
61326048Sminshall 		(void) signal(SIGPIPE, oldintp);
61426048Sminshall 	if (!cpend) {
61526048Sminshall 		code = -1;
61626048Sminshall 		return;
61726048Sminshall 	}
61826048Sminshall 	if (data >= 0) {
61926048Sminshall 		(void) close(data);
62026048Sminshall 		data = -1;
62126048Sminshall 	}
62226448Slepreau 	if (dout)
62326048Sminshall 		(void) fclose(dout);
62426048Sminshall 	(void) getreply(0);
62526048Sminshall 	code = -1;
62610296Ssam 	if (closefunc != NULL && fin != NULL)
62726048Sminshall 		(*closefunc)(fin);
62835699Sbostic 	if (bytes > 0)
62937225Skarels 		ptransfer("sent", bytes, &start, &stop);
63010296Ssam }
63110296Ssam 
63210296Ssam jmp_buf	recvabort;
63310296Ssam 
63410296Ssam abortrecv()
63510296Ssam {
63610296Ssam 
63726048Sminshall 	mflag = 0;
63826048Sminshall 	abrtflag = 0;
63926048Sminshall 	printf("\n");
64026048Sminshall 	(void) fflush(stdout);
64110296Ssam 	longjmp(recvabort, 1);
64210296Ssam }
64310296Ssam 
64437225Skarels recvrequest(cmd, local, remote, mode, printnames)
64511651Ssam 	char *cmd, *local, *remote, *mode;
64610296Ssam {
64735659Sbostic 	FILE *fout, *din = 0, *popen();
64835659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
649*38033Skarels 	int abortrecv(), is_retr, tcrflag, nfnd;
65036944Skarels 	char *bufp, *gunique(), msg;
65136944Skarels 	static char *buf;
65236940Skarels 	static int bufsize;
65336940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
65426496Sminshall 	struct fd_set mask;
65511346Ssam 	register int c, d;
65610296Ssam 	struct timeval start, stop;
65736940Skarels 	struct stat st;
65836940Skarels 	extern char *malloc();
65910296Ssam 
66036935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
66137225Skarels 	if (is_retr && verbose && printnames) {
66237225Skarels 		if (local && *local != '-')
66337225Skarels 			printf("local: %s ", local);
66437225Skarels 		if (remote)
66537225Skarels 			printf("remote: %s\n", remote);
66637225Skarels 	}
66736935Skarels 	if (proxy && is_retr) {
66826048Sminshall 		proxtrans(cmd, local, remote);
66926048Sminshall 		return;
67026048Sminshall 	}
67110296Ssam 	closefunc = NULL;
67226048Sminshall 	oldintr = NULL;
67326048Sminshall 	oldintp = NULL;
67436935Skarels 	tcrflag = !crflag && is_retr;
67526048Sminshall 	if (setjmp(recvabort)) {
67626048Sminshall 		while (cpend) {
67726048Sminshall 			(void) getreply(0);
67826048Sminshall 		}
67926048Sminshall 		if (data >= 0) {
68026048Sminshall 			(void) close(data);
68126048Sminshall 			data = -1;
68226048Sminshall 		}
68326448Slepreau 		if (oldintr)
68426048Sminshall 			(void) signal(SIGINT, oldintr);
68526048Sminshall 		code = -1;
68626048Sminshall 		return;
68726048Sminshall 	}
68810296Ssam 	oldintr = signal(SIGINT, abortrecv);
68926048Sminshall 	if (strcmp(local, "-") && *local != '|') {
69010296Ssam 		if (access(local, 2) < 0) {
69126048Sminshall 			char *dir = rindex(local, '/');
69210296Ssam 
69326048Sminshall 			if (errno != ENOENT && errno != EACCES) {
69410296Ssam 				perror(local);
69526048Sminshall 				(void) signal(SIGINT, oldintr);
69626048Sminshall 				code = -1;
69726048Sminshall 				return;
69810296Ssam 			}
69926048Sminshall 			if (dir != NULL)
70026048Sminshall 				*dir = 0;
70126048Sminshall 			d = access(dir ? local : ".", 2);
70226048Sminshall 			if (dir != NULL)
70326048Sminshall 				*dir = '/';
70426048Sminshall 			if (d < 0) {
70526048Sminshall 				perror(local);
70626048Sminshall 				(void) signal(SIGINT, oldintr);
70726048Sminshall 				code = -1;
70826048Sminshall 				return;
70926048Sminshall 			}
71026048Sminshall 			if (!runique && errno == EACCES &&
71136935Skarels 			    chmod(local, 0600) < 0) {
71226048Sminshall 				perror(local);
71326048Sminshall 				(void) signal(SIGINT, oldintr);
71426048Sminshall 				code = -1;
71526048Sminshall 				return;
71626048Sminshall 			}
71726048Sminshall 			if (runique && errno == EACCES &&
71826048Sminshall 			   (local = gunique(local)) == NULL) {
71926048Sminshall 				(void) signal(SIGINT, oldintr);
72026048Sminshall 				code = -1;
72126048Sminshall 				return;
72226048Sminshall 			}
72310296Ssam 		}
72426048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
72526048Sminshall 			(void) signal(SIGINT, oldintr);
72626048Sminshall 			code = -1;
72726048Sminshall 			return;
72826048Sminshall 		}
72926048Sminshall 	}
730*38033Skarels 	if (!is_retr) {
731*38033Skarels 		if (curtype != TYPE_A)
732*38033Skarels 			changetype(TYPE_A, 0);
733*38033Skarels 	} else if (curtype != type)
734*38033Skarels 		changetype(type, 0);
73526048Sminshall 	if (initconn()) {
73626048Sminshall 		(void) signal(SIGINT, oldintr);
73726048Sminshall 		code = -1;
73826048Sminshall 		return;
73926048Sminshall 	}
74026448Slepreau 	if (setjmp(recvabort))
74126048Sminshall 		goto abort;
742*38033Skarels 	if (is_retr && restart_point &&
743*38033Skarels 	    command("REST %ld", (long) restart_point) != CONTINUE)
744*38033Skarels 		return;
74510296Ssam 	if (remote) {
74626048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
74726048Sminshall 			(void) signal(SIGINT, oldintr);
74826048Sminshall 			return;
74926048Sminshall 		}
75026048Sminshall 	} else {
75126048Sminshall 		if (command("%s", cmd) != PRELIM) {
75226048Sminshall 			(void) signal(SIGINT, oldintr);
75326048Sminshall 			return;
75426048Sminshall 		}
75526048Sminshall 	}
75626048Sminshall 	din = dataconn("r");
75726048Sminshall 	if (din == NULL)
75826048Sminshall 		goto abort;
75926448Slepreau 	if (strcmp(local, "-") == 0)
76010296Ssam 		fout = stdout;
76110296Ssam 	else if (*local == '|') {
76226048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
76335659Sbostic 		fout = popen(local + 1, "w");
76426048Sminshall 		if (fout == NULL) {
76526048Sminshall 			perror(local+1);
76626048Sminshall 			goto abort;
76726048Sminshall 		}
76835659Sbostic 		closefunc = pclose;
76936940Skarels 	} else {
77011651Ssam 		fout = fopen(local, mode);
77126048Sminshall 		if (fout == NULL) {
77226048Sminshall 			perror(local);
77326048Sminshall 			goto abort;
77426048Sminshall 		}
77510296Ssam 		closefunc = fclose;
77610296Ssam 	}
77736940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
77836940Skarels 		st.st_blksize = BUFSIZ;
77936940Skarels 	if (st.st_blksize > bufsize) {
78036940Skarels 		if (buf)
78136940Skarels 			(void) free(buf);
78236940Skarels 		buf = malloc(st.st_blksize);
78336940Skarels 		if (buf == NULL) {
78436940Skarels 			perror("malloc");
78536944Skarels 			bufsize = 0;
78636940Skarels 			goto abort;
78736940Skarels 		}
78836940Skarels 		bufsize = st.st_blksize;
78936940Skarels 	}
79026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
791*38033Skarels 	switch (curtype) {
79211219Ssam 
79311219Ssam 	case TYPE_I:
79411219Ssam 	case TYPE_L:
79537225Skarels 		if (restart_point &&
79637225Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
79737225Skarels 			perror(local);
79837225Skarels 			if (closefunc != NULL)
79937225Skarels 				(*closefunc)(fout);
80037225Skarels 			return;
80137225Skarels 		}
80211346Ssam 		errno = d = 0;
80336940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
80436944Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
80511219Ssam 				break;
80611219Ssam 			bytes += c;
80711651Ssam 			if (hash) {
80836940Skarels 				while (bytes >= hashbytes) {
80936940Skarels 					(void) putchar('#');
81036940Skarels 					hashbytes += HASHBYTES;
81136940Skarels 				}
81226496Sminshall 				(void) fflush(stdout);
81311651Ssam 			}
81411219Ssam 		}
81513213Ssam 		if (hash && bytes > 0) {
81636940Skarels 			if (bytes < HASHBYTES)
81736940Skarels 				(void) putchar('#');
81826496Sminshall 			(void) putchar('\n');
81926496Sminshall 			(void) fflush(stdout);
82011651Ssam 		}
82136935Skarels 		if (c < 0) {
82236935Skarels 			if (errno != EPIPE)
82336935Skarels 				perror("netin");
82436935Skarels 			bytes = -1;
82536935Skarels 		}
82636942Skarels 		if (d < c) {
82736942Skarels 			if (d < 0)
82836942Skarels 				perror(local);
82936942Skarels 			else
83036942Skarels 				fprintf(stderr, "%s: short write\n", local);
83136942Skarels 		}
83211219Ssam 		break;
83311219Ssam 
83411219Ssam 	case TYPE_A:
83537225Skarels 		if (restart_point) {
83637225Skarels 			register int i, n, c;
83737225Skarels 
83837225Skarels 			if (fseek(fout, 0L, L_SET) < 0)
83937225Skarels 				goto done;
84037225Skarels 			n = restart_point;
84137225Skarels 			i = 0;
84237225Skarels 			while (i++ < n) {
84337225Skarels 				if ((c=getc(fout)) == EOF)
84437225Skarels 					goto done;
84537225Skarels 				if (c == '\n')
84637225Skarels 					i++;
84737225Skarels 			}
84837225Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
84937225Skarels done:
85037225Skarels 				perror(local);
85137225Skarels 				if (closefunc != NULL)
85237225Skarels 					(*closefunc)(fout);
85337225Skarels 				return;
85437225Skarels 			}
85537225Skarels 		}
85611219Ssam 		while ((c = getc(din)) != EOF) {
85727749Sminshall 			while (c == '\r') {
85811651Ssam 				while (hash && (bytes >= hashbytes)) {
85926496Sminshall 					(void) putchar('#');
86026496Sminshall 					(void) fflush(stdout);
86136940Skarels 					hashbytes += HASHBYTES;
86211651Ssam 				}
86310296Ssam 				bytes++;
86426048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
86536940Skarels 					if (ferror(fout))
86636940Skarels 						goto break2;
86736940Skarels 					(void) putc('\r', fout);
86836942Skarels 					if (c == '\0') {
86936942Skarels 						bytes++;
87036940Skarels 						goto contin2;
87136942Skarels 					}
87236942Skarels 					if (c == EOF)
87336942Skarels 						goto contin2;
87411219Ssam 				}
87511219Ssam 			}
87636940Skarels 			(void) putc(c, fout);
87711219Ssam 			bytes++;
87836940Skarels 	contin2:	;
87910296Ssam 		}
88036940Skarels break2:
88111651Ssam 		if (hash) {
88213213Ssam 			if (bytes < hashbytes)
88326496Sminshall 				(void) putchar('#');
88426496Sminshall 			(void) putchar('\n');
88526496Sminshall 			(void) fflush(stdout);
88611651Ssam 		}
88736944Skarels 		if (ferror(din)) {
88836935Skarels 			if (errno != EPIPE)
88936944Skarels 				perror("netin");
89036935Skarels 			bytes = -1;
89136935Skarels 		}
89236940Skarels 		if (ferror(fout))
89336944Skarels 			perror(local);
89411219Ssam 		break;
89510296Ssam 	}
89626448Slepreau 	if (closefunc != NULL)
89726048Sminshall 		(*closefunc)(fout);
89826496Sminshall 	(void) signal(SIGINT, oldintr);
89926448Slepreau 	if (oldintp)
90026048Sminshall 		(void) signal(SIGPIPE, oldintp);
90126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
90210296Ssam 	(void) fclose(din);
90326048Sminshall 	(void) getreply(0);
90436935Skarels 	if (bytes > 0 && is_retr)
90537225Skarels 		ptransfer("received", bytes, &start, &stop);
90626048Sminshall 	return;
90726048Sminshall abort:
90826048Sminshall 
90927687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
91026048Sminshall 
91126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
91226448Slepreau 	if (oldintp)
91326048Sminshall 		(void) signal(SIGPIPE, oldintr);
91426048Sminshall 	(void) signal(SIGINT,SIG_IGN);
91526048Sminshall 	if (!cpend) {
91626048Sminshall 		code = -1;
91726048Sminshall 		(void) signal(SIGINT,oldintr);
91826048Sminshall 		return;
91926048Sminshall 	}
92026048Sminshall 
92127687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
92227687Sminshall 	(void) fflush(cout);
92327687Sminshall 	msg = IAC;
92427687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
92527687Sminshall /* after urgent byte rather than before as now is protocol            */
92627687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
92727687Sminshall 		perror("abort");
92826048Sminshall 	}
92927687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
93026048Sminshall 	(void) fflush(cout);
93127687Sminshall 	FD_ZERO(&mask);
93226496Sminshall 	FD_SET(fileno(cin), &mask);
93326496Sminshall 	if (din) {
93426496Sminshall 		FD_SET(fileno(din), &mask);
93526496Sminshall 	}
93627687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
93727687Sminshall 		if (nfnd < 0) {
93827687Sminshall 			perror("abort");
93927687Sminshall 		}
94026048Sminshall 		code = -1;
94126048Sminshall 		lostpeer();
94226048Sminshall 	}
94326496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
94436940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0)
94526448Slepreau 			;
94626496Sminshall 	}
94727687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
94826048Sminshall 		if (data >= 0) {
94926496Sminshall 			(void) close(data);
95026048Sminshall 			data = -1;
95126048Sminshall 		}
95225907Smckusick 		(void) getreply(0);
95325907Smckusick 	}
95426048Sminshall 	(void) getreply(0);
95526048Sminshall 	code = -1;
95626048Sminshall 	if (data >= 0) {
95726048Sminshall 		(void) close(data);
95826048Sminshall 		data = -1;
95926048Sminshall 	}
96026448Slepreau 	if (closefunc != NULL && fout != NULL)
96126048Sminshall 		(*closefunc)(fout);
96226448Slepreau 	if (din)
96326048Sminshall 		(void) fclose(din);
96435699Sbostic 	if (bytes > 0)
96537225Skarels 		ptransfer("received", bytes, &start, &stop);
96626048Sminshall 	(void) signal(SIGINT,oldintr);
96710296Ssam }
96810296Ssam 
96910296Ssam /*
97010296Ssam  * Need to start a listen on the data channel
97110296Ssam  * before we send the command, otherwise the
97210296Ssam  * server's connect may fail.
97310296Ssam  */
97433224Sbostic int sendport = -1;
97511651Ssam 
97610296Ssam initconn()
97710296Ssam {
97810296Ssam 	register char *p, *a;
97926048Sminshall 	int result, len, tmpno = 0;
98026993Skarels 	int on = 1;
98110296Ssam 
98211651Ssam noport:
98310296Ssam 	data_addr = myctladdr;
98411651Ssam 	if (sendport)
98511651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
98611651Ssam 	if (data != -1)
98711651Ssam 		(void) close (data);
98818287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
98910296Ssam 	if (data < 0) {
99010296Ssam 		perror("ftp: socket");
99126448Slepreau 		if (tmpno)
99226048Sminshall 			sendport = 1;
99310296Ssam 		return (1);
99410296Ssam 	}
99512397Ssam 	if (!sendport)
99627687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
99733224Sbostic 			perror("ftp: setsockopt (reuse address)");
99812397Ssam 			goto bad;
99912397Ssam 		}
100026496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
100110296Ssam 		perror("ftp: bind");
100210296Ssam 		goto bad;
100310296Ssam 	}
100410296Ssam 	if (options & SO_DEBUG &&
100527687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
100610296Ssam 		perror("ftp: setsockopt (ignored)");
100711627Ssam 	len = sizeof (data_addr);
100811627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
100911627Ssam 		perror("ftp: getsockname");
101010296Ssam 		goto bad;
101110296Ssam 	}
101226448Slepreau 	if (listen(data, 1) < 0)
101310296Ssam 		perror("ftp: listen");
101411651Ssam 	if (sendport) {
101511651Ssam 		a = (char *)&data_addr.sin_addr;
101611651Ssam 		p = (char *)&data_addr.sin_port;
101710296Ssam #define	UC(b)	(((int)b)&0xff)
101811651Ssam 		result =
101911651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
102011651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
102111651Ssam 		      UC(p[0]), UC(p[1]));
102211651Ssam 		if (result == ERROR && sendport == -1) {
102311651Ssam 			sendport = 0;
102426048Sminshall 			tmpno = 1;
102511651Ssam 			goto noport;
102611651Ssam 		}
102711651Ssam 		return (result != COMPLETE);
102811651Ssam 	}
102926448Slepreau 	if (tmpno)
103026048Sminshall 		sendport = 1;
103111651Ssam 	return (0);
103210296Ssam bad:
103310296Ssam 	(void) close(data), data = -1;
103426448Slepreau 	if (tmpno)
103526048Sminshall 		sendport = 1;
103610296Ssam 	return (1);
103710296Ssam }
103810296Ssam 
103910296Ssam FILE *
104010296Ssam dataconn(mode)
104110296Ssam 	char *mode;
104210296Ssam {
104310296Ssam 	struct sockaddr_in from;
104410296Ssam 	int s, fromlen = sizeof (from);
104510296Ssam 
104626496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
104710296Ssam 	if (s < 0) {
104810296Ssam 		perror("ftp: accept");
104910296Ssam 		(void) close(data), data = -1;
105010296Ssam 		return (NULL);
105110296Ssam 	}
105210296Ssam 	(void) close(data);
105310296Ssam 	data = s;
105410296Ssam 	return (fdopen(data, mode));
105510296Ssam }
105610296Ssam 
105737225Skarels ptransfer(direction, bytes, t0, t1)
105837225Skarels 	char *direction;
105911651Ssam 	long bytes;
106010296Ssam 	struct timeval *t0, *t1;
106110296Ssam {
106210296Ssam 	struct timeval td;
106316437Sleres 	float s, bs;
106410296Ssam 
106535699Sbostic 	if (verbose) {
106635699Sbostic 		tvsub(&td, t1, t0);
106735699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
106810296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
106935699Sbostic 		bs = bytes / nz(s);
107035699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
107135699Sbostic 		    bytes, direction, s, bs / 1024.);
107235699Sbostic 	}
107310296Ssam }
107410296Ssam 
107526496Sminshall /*tvadd(tsum, t0)
107610296Ssam 	struct timeval *tsum, *t0;
107710296Ssam {
107810296Ssam 
107910296Ssam 	tsum->tv_sec += t0->tv_sec;
108010296Ssam 	tsum->tv_usec += t0->tv_usec;
108110296Ssam 	if (tsum->tv_usec > 1000000)
108210296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
108326496Sminshall } */
108410296Ssam 
108510296Ssam tvsub(tdiff, t1, t0)
108610296Ssam 	struct timeval *tdiff, *t1, *t0;
108710296Ssam {
108810296Ssam 
108910296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
109010296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
109110296Ssam 	if (tdiff->tv_usec < 0)
109210296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
109310296Ssam }
109426048Sminshall 
109526048Sminshall psabort()
109626048Sminshall {
109726048Sminshall 	extern int abrtflag;
109826048Sminshall 
109926048Sminshall 	abrtflag++;
110026048Sminshall }
110126048Sminshall 
110226048Sminshall pswitch(flag)
110326048Sminshall 	int flag;
110426048Sminshall {
110526048Sminshall 	extern int proxy, abrtflag;
110626048Sminshall 	int (*oldintr)();
110726048Sminshall 	static struct comvars {
110826048Sminshall 		int connect;
110928469Skarels 		char name[MAXHOSTNAMELEN];
111026048Sminshall 		struct sockaddr_in mctl;
111126048Sminshall 		struct sockaddr_in hctl;
111226048Sminshall 		FILE *in;
111326048Sminshall 		FILE *out;
111426048Sminshall 		int tpe;
1115*38033Skarels 		int curtpe;
111626048Sminshall 		int cpnd;
111726048Sminshall 		int sunqe;
111826048Sminshall 		int runqe;
111926048Sminshall 		int mcse;
112026048Sminshall 		int ntflg;
112126048Sminshall 		char nti[17];
112226048Sminshall 		char nto[17];
112326048Sminshall 		int mapflg;
112426048Sminshall 		char mi[MAXPATHLEN];
112526048Sminshall 		char mo[MAXPATHLEN];
1126*38033Skarels 	} proxstruct, tmpstruct;
112726048Sminshall 	struct comvars *ip, *op;
112826048Sminshall 
112926048Sminshall 	abrtflag = 0;
113026048Sminshall 	oldintr = signal(SIGINT, psabort);
113126048Sminshall 	if (flag) {
113226448Slepreau 		if (proxy)
113326048Sminshall 			return;
113426048Sminshall 		ip = &tmpstruct;
113526048Sminshall 		op = &proxstruct;
113626048Sminshall 		proxy++;
1137*38033Skarels 	} else {
113826448Slepreau 		if (!proxy)
113926048Sminshall 			return;
114026048Sminshall 		ip = &proxstruct;
114126048Sminshall 		op = &tmpstruct;
114226048Sminshall 		proxy = 0;
114326048Sminshall 	}
114426048Sminshall 	ip->connect = connected;
114526048Sminshall 	connected = op->connect;
114628469Skarels 	if (hostname) {
114728469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
114828469Skarels 		ip->name[strlen(ip->name)] = '\0';
114928469Skarels 	} else
115028469Skarels 		ip->name[0] = 0;
115126048Sminshall 	hostname = op->name;
115226048Sminshall 	ip->hctl = hisctladdr;
115326048Sminshall 	hisctladdr = op->hctl;
115426048Sminshall 	ip->mctl = myctladdr;
115526048Sminshall 	myctladdr = op->mctl;
115626048Sminshall 	ip->in = cin;
115726048Sminshall 	cin = op->in;
115826048Sminshall 	ip->out = cout;
115926048Sminshall 	cout = op->out;
116026048Sminshall 	ip->tpe = type;
116126048Sminshall 	type = op->tpe;
1162*38033Skarels 	ip->curtpe = curtype;
1163*38033Skarels 	curtype = op->curtpe;
116426048Sminshall 	ip->cpnd = cpend;
116526048Sminshall 	cpend = op->cpnd;
116626048Sminshall 	ip->sunqe = sunique;
116726048Sminshall 	sunique = op->sunqe;
116826048Sminshall 	ip->runqe = runique;
116926048Sminshall 	runique = op->runqe;
117026048Sminshall 	ip->mcse = mcase;
117126048Sminshall 	mcase = op->mcse;
117226048Sminshall 	ip->ntflg = ntflag;
117326048Sminshall 	ntflag = op->ntflg;
117426496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
117526048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
117626496Sminshall 	(void) strcpy(ntin, op->nti);
117726496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
117826048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
117926496Sminshall 	(void) strcpy(ntout, op->nto);
118026048Sminshall 	ip->mapflg = mapflag;
118126048Sminshall 	mapflag = op->mapflg;
118226496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
118326048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
118426496Sminshall 	(void) strcpy(mapin, op->mi);
118526496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
118626048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
118726496Sminshall 	(void) strcpy(mapout, op->mo);
118826048Sminshall 	(void) signal(SIGINT, oldintr);
118926048Sminshall 	if (abrtflag) {
119026048Sminshall 		abrtflag = 0;
119126048Sminshall 		(*oldintr)();
119226448Slepreau 	}
119326048Sminshall }
119426048Sminshall 
119526048Sminshall jmp_buf ptabort;
119626048Sminshall int ptabflg;
119726048Sminshall 
119826048Sminshall abortpt()
119926048Sminshall {
120026048Sminshall 	printf("\n");
120126496Sminshall 	(void) fflush(stdout);
120226048Sminshall 	ptabflg++;
120326048Sminshall 	mflag = 0;
120426048Sminshall 	abrtflag = 0;
120526048Sminshall 	longjmp(ptabort, 1);
120626048Sminshall }
120726048Sminshall 
120826048Sminshall proxtrans(cmd, local, remote)
120926048Sminshall 	char *cmd, *local, *remote;
121026048Sminshall {
1211*38033Skarels 	int (*oldintr)(), abortpt(), prox_type, secndflag = 0, nfnd;
121226048Sminshall 	extern jmp_buf ptabort;
121326048Sminshall 	char *cmd2;
121426496Sminshall 	struct fd_set mask;
121526048Sminshall 
121626448Slepreau 	if (strcmp(cmd, "RETR"))
121726048Sminshall 		cmd2 = "RETR";
121826448Slepreau 	else
121926048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
1220*38033Skarels 	if ((prox_type = type) == 0) {
1221*38033Skarels 		if (unix_server && unix_proxy)
1222*38033Skarels 			prox_type = TYPE_I;
1223*38033Skarels 		else
1224*38033Skarels 			prox_type = TYPE_A;
1225*38033Skarels 	}
1226*38033Skarels 	if (curtype != prox_type)
1227*38033Skarels 		changetype(prox_type, 1);
122826048Sminshall 	if (command("PASV") != COMPLETE) {
1229*38033Skarels 		printf("proxy server does not support third party transfers.\n");
123026048Sminshall 		return;
123126048Sminshall 	}
123226048Sminshall 	pswitch(0);
123326048Sminshall 	if (!connected) {
123426048Sminshall 		printf("No primary connection\n");
123526048Sminshall 		pswitch(1);
123626048Sminshall 		code = -1;
123726048Sminshall 		return;
123826048Sminshall 	}
1239*38033Skarels 	if (curtype != prox_type)
1240*38033Skarels 		changetype(prox_type, 1);
124126048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
124226048Sminshall 		pswitch(1);
124326048Sminshall 		return;
124426048Sminshall 	}
124526448Slepreau 	if (setjmp(ptabort))
124626048Sminshall 		goto abort;
124726048Sminshall 	oldintr = signal(SIGINT, abortpt);
124826048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
124926048Sminshall 		(void) signal(SIGINT, oldintr);
125026048Sminshall 		pswitch(1);
125126048Sminshall 		return;
125226048Sminshall 	}
125326048Sminshall 	sleep(2);
125426048Sminshall 	pswitch(1);
125526048Sminshall 	secndflag++;
125626448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
125726048Sminshall 		goto abort;
125826048Sminshall 	ptflag++;
125926048Sminshall 	(void) getreply(0);
126026048Sminshall 	pswitch(0);
126126048Sminshall 	(void) getreply(0);
126226048Sminshall 	(void) signal(SIGINT, oldintr);
126326048Sminshall 	pswitch(1);
126426048Sminshall 	ptflag = 0;
126526048Sminshall 	printf("local: %s remote: %s\n", local, remote);
126626048Sminshall 	return;
126726048Sminshall abort:
126826048Sminshall 	(void) signal(SIGINT, SIG_IGN);
126926048Sminshall 	ptflag = 0;
127026448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
127126048Sminshall 		pswitch(1);
127226448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
127326048Sminshall 		pswitch(0);
127426048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
127526048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
127626048Sminshall 			pswitch(0);
127727687Sminshall 			if (cpend) {
127826048Sminshall 				char msg[2];
127926048Sminshall 
128026048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
128126048Sminshall 				(void) fflush(cout);
128226048Sminshall 				*msg = IAC;
128326048Sminshall 				*(msg+1) = DM;
128426448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
128526048Sminshall 					perror("abort");
128626048Sminshall 				fprintf(cout,"ABOR\r\n");
128726048Sminshall 				(void) fflush(cout);
128827687Sminshall 				FD_ZERO(&mask);
128926496Sminshall 				FD_SET(fileno(cin), &mask);
129027687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
129127687Sminshall 					if (nfnd < 0) {
129227687Sminshall 						perror("abort");
129327687Sminshall 					}
129426448Slepreau 					if (ptabflg)
129526048Sminshall 						code = -1;
129626048Sminshall 					lostpeer();
129726048Sminshall 				}
129826048Sminshall 				(void) getreply(0);
129926048Sminshall 				(void) getreply(0);
130026048Sminshall 			}
130126048Sminshall 		}
130226048Sminshall 		pswitch(1);
130326448Slepreau 		if (ptabflg)
130426048Sminshall 			code = -1;
130526048Sminshall 		(void) signal(SIGINT, oldintr);
130626048Sminshall 		return;
130726048Sminshall 	}
130827687Sminshall 	if (cpend) {
130926048Sminshall 		char msg[2];
131026048Sminshall 
131126048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
131226048Sminshall 		(void) fflush(cout);
131326048Sminshall 		*msg = IAC;
131426048Sminshall 		*(msg+1) = DM;
131526448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
131626048Sminshall 			perror("abort");
131726048Sminshall 		fprintf(cout,"ABOR\r\n");
131826048Sminshall 		(void) fflush(cout);
131927687Sminshall 		FD_ZERO(&mask);
132026496Sminshall 		FD_SET(fileno(cin), &mask);
132127687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
132227687Sminshall 			if (nfnd < 0) {
132327687Sminshall 				perror("abort");
132427687Sminshall 			}
132526448Slepreau 			if (ptabflg)
132626048Sminshall 				code = -1;
132726048Sminshall 			lostpeer();
132826048Sminshall 		}
132926048Sminshall 		(void) getreply(0);
133026048Sminshall 		(void) getreply(0);
133126048Sminshall 	}
133226048Sminshall 	pswitch(!proxy);
133326048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
133426048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
133526048Sminshall 			pswitch(0);
133627687Sminshall 			if (cpend) {
133726048Sminshall 				char msg[2];
133826048Sminshall 
133926048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
134026048Sminshall 				(void) fflush(cout);
134126048Sminshall 				*msg = IAC;
134226048Sminshall 				*(msg+1) = DM;
134326448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
134426048Sminshall 					perror("abort");
134526048Sminshall 				fprintf(cout,"ABOR\r\n");
134626048Sminshall 				(void) fflush(cout);
134727687Sminshall 				FD_ZERO(&mask);
134826496Sminshall 				FD_SET(fileno(cin), &mask);
134927687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
135027687Sminshall 					if (nfnd < 0) {
135127687Sminshall 						perror("abort");
135227687Sminshall 					}
135326448Slepreau 					if (ptabflg)
135426048Sminshall 						code = -1;
135526048Sminshall 					lostpeer();
135626048Sminshall 				}
135726048Sminshall 				(void) getreply(0);
135826048Sminshall 				(void) getreply(0);
135926048Sminshall 			}
136026048Sminshall 			pswitch(1);
136126448Slepreau 			if (ptabflg)
136226048Sminshall 				code = -1;
136326048Sminshall 			(void) signal(SIGINT, oldintr);
136426048Sminshall 			return;
136526048Sminshall 		}
136626048Sminshall 	}
136727687Sminshall 	if (cpend) {
136826048Sminshall 		char msg[2];
136926048Sminshall 
137026048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
137126048Sminshall 		(void) fflush(cout);
137226048Sminshall 		*msg = IAC;
137326048Sminshall 		*(msg+1) = DM;
137426448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
137526048Sminshall 			perror("abort");
137626048Sminshall 		fprintf(cout,"ABOR\r\n");
137726048Sminshall 		(void) fflush(cout);
137827687Sminshall 		FD_ZERO(&mask);
137926496Sminshall 		FD_SET(fileno(cin), &mask);
138027687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
138127687Sminshall 			if (nfnd < 0) {
138227687Sminshall 				perror("abort");
138327687Sminshall 			}
138426448Slepreau 			if (ptabflg)
138526048Sminshall 				code = -1;
138626048Sminshall 			lostpeer();
138726048Sminshall 		}
138826048Sminshall 		(void) getreply(0);
138926048Sminshall 		(void) getreply(0);
139026048Sminshall 	}
139126048Sminshall 	pswitch(!proxy);
139226048Sminshall 	if (cpend) {
139327687Sminshall 		FD_ZERO(&mask);
139426496Sminshall 		FD_SET(fileno(cin), &mask);
139527687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
139627687Sminshall 			if (nfnd < 0) {
139727687Sminshall 				perror("abort");
139827687Sminshall 			}
139926448Slepreau 			if (ptabflg)
140026048Sminshall 				code = -1;
140126048Sminshall 			lostpeer();
140226048Sminshall 		}
140326048Sminshall 		(void) getreply(0);
140426048Sminshall 		(void) getreply(0);
140526048Sminshall 	}
140626448Slepreau 	if (proxy)
140726048Sminshall 		pswitch(0);
140826048Sminshall 	pswitch(1);
140926448Slepreau 	if (ptabflg)
141026048Sminshall 		code = -1;
141126048Sminshall 	(void) signal(SIGINT, oldintr);
141226048Sminshall }
141326048Sminshall 
141426048Sminshall reset()
141526048Sminshall {
141626496Sminshall 	struct fd_set mask;
141726496Sminshall 	int nfnd = 1;
141826048Sminshall 
141927687Sminshall 	FD_ZERO(&mask);
142030946Scsvsj 	while (nfnd > 0) {
142126496Sminshall 		FD_SET(fileno(cin), &mask);
142227687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
142326048Sminshall 			perror("reset");
142426048Sminshall 			code = -1;
142526048Sminshall 			lostpeer();
142626048Sminshall 		}
142727687Sminshall 		else if (nfnd) {
142826048Sminshall 			(void) getreply(0);
142926496Sminshall 		}
143026048Sminshall 	}
143126048Sminshall }
143226048Sminshall 
143326048Sminshall char *
143426048Sminshall gunique(local)
143526048Sminshall 	char *local;
143626048Sminshall {
143726048Sminshall 	static char new[MAXPATHLEN];
143826048Sminshall 	char *cp = rindex(local, '/');
143926048Sminshall 	int d, count=0;
144026048Sminshall 	char ext = '1';
144126048Sminshall 
144226448Slepreau 	if (cp)
144326048Sminshall 		*cp = '\0';
144426048Sminshall 	d = access(cp ? local : ".", 2);
144526448Slepreau 	if (cp)
144626048Sminshall 		*cp = '/';
144726048Sminshall 	if (d < 0) {
144826048Sminshall 		perror(local);
144926048Sminshall 		return((char *) 0);
145026048Sminshall 	}
145126048Sminshall 	(void) strcpy(new, local);
145226048Sminshall 	cp = new + strlen(new);
145326048Sminshall 	*cp++ = '.';
145426048Sminshall 	while (!d) {
145526048Sminshall 		if (++count == 100) {
145626048Sminshall 			printf("runique: can't find unique file name.\n");
145726048Sminshall 			return((char *) 0);
145826048Sminshall 		}
145926048Sminshall 		*cp++ = ext;
146026048Sminshall 		*cp = '\0';
146126448Slepreau 		if (ext == '9')
146226048Sminshall 			ext = '0';
146326448Slepreau 		else
146426048Sminshall 			ext++;
146526448Slepreau 		if ((d = access(new, 0)) < 0)
146626048Sminshall 			break;
146726448Slepreau 		if (ext != '0')
146826048Sminshall 			cp--;
146926448Slepreau 		else if (*(cp - 2) == '.')
147026048Sminshall 			*(cp - 1) = '1';
147126048Sminshall 		else {
147226048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
147326048Sminshall 			cp--;
147426048Sminshall 		}
147526048Sminshall 	}
147626048Sminshall 	return(new);
147726048Sminshall }
1478