xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 36944)
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*36944Skarels static char sccsid[] = "@(#)ftp.c	5.25 (Berkeley) 03/01/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();
50*36944Skarels 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 	}
17226048Sminshall 	if (user == NULL) {
17326048Sminshall 		char *myname = getlogin();
17426048Sminshall 
17526048Sminshall 		if (myname == NULL) {
17626048Sminshall 			struct passwd *pp = getpwuid(getuid());
17726048Sminshall 
17826448Slepreau 			if (pp != NULL)
17926048Sminshall 				myname = pp->pw_name;
18026048Sminshall 		}
18126048Sminshall 		printf("Name (%s:%s): ", host, myname);
18226048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18326048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18426448Slepreau 		if (*tmp == '\0')
18526048Sminshall 			user = myname;
18626448Slepreau 		else
18726048Sminshall 			user = tmp;
18826048Sminshall 	}
18910296Ssam 	n = command("USER %s", user);
19026048Sminshall 	if (n == CONTINUE) {
19126448Slepreau 		if (pass == NULL)
19235659Sbostic 			pass = getpass("Password:");
19310296Ssam 		n = command("PASS %s", pass);
19426048Sminshall 	}
19510296Ssam 	if (n == CONTINUE) {
19626048Sminshall 		aflag++;
19735659Sbostic 		acct = getpass("Account:");
19810296Ssam 		n = command("ACCT %s", acct);
19910296Ssam 	}
20010296Ssam 	if (n != COMPLETE) {
20110296Ssam 		fprintf(stderr, "Login failed.\n");
20210296Ssam 		return (0);
20310296Ssam 	}
20426448Slepreau 	if (!aflag && acct != NULL)
20526048Sminshall 		(void) command("ACCT %s", acct);
20626448Slepreau 	if (proxy)
20726048Sminshall 		return(1);
20826048Sminshall 	for (n = 0; n < macnum; ++n) {
20926048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21026496Sminshall 			(void) strcpy(line, "$init");
21126048Sminshall 			makeargv();
21226048Sminshall 			domacro(margc, margv);
21326048Sminshall 			break;
21426048Sminshall 		}
21526048Sminshall 	}
21610296Ssam 	return (1);
21710296Ssam }
21810296Ssam 
21926048Sminshall cmdabort()
22026048Sminshall {
22126048Sminshall 	extern jmp_buf ptabort;
22226048Sminshall 
22326048Sminshall 	printf("\n");
22426048Sminshall 	(void) fflush(stdout);
22526048Sminshall 	abrtflag++;
22626448Slepreau 	if (ptflag)
22726048Sminshall 		longjmp(ptabort,1);
22826048Sminshall }
22926048Sminshall 
23026496Sminshall /*VARARGS1*/
23110296Ssam command(fmt, args)
23210296Ssam 	char *fmt;
23310296Ssam {
23426048Sminshall 	int r, (*oldintr)(), cmdabort();
23510296Ssam 
23626048Sminshall 	abrtflag = 0;
23710296Ssam 	if (debug) {
23810296Ssam 		printf("---> ");
23910296Ssam 		_doprnt(fmt, &args, stdout);
24010296Ssam 		printf("\n");
24110296Ssam 		(void) fflush(stdout);
24210296Ssam 	}
24311219Ssam 	if (cout == NULL) {
24411219Ssam 		perror ("No control connection for command");
24526048Sminshall 		code = -1;
24611219Ssam 		return (0);
24711219Ssam 	}
24826048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24910296Ssam 	_doprnt(fmt, &args, cout);
25010296Ssam 	fprintf(cout, "\r\n");
25110296Ssam 	(void) fflush(cout);
25226048Sminshall 	cpend = 1;
25326048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25426448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
25526048Sminshall 		(*oldintr)();
25626048Sminshall 	(void) signal(SIGINT, oldintr);
25726048Sminshall 	return(r);
25810296Ssam }
25910296Ssam 
26036935Skarels char reply_string[BUFSIZ];
26136935Skarels 
26210296Ssam #include <ctype.h>
26310296Ssam 
26410296Ssam getreply(expecteof)
26510296Ssam 	int expecteof;
26610296Ssam {
26711219Ssam 	register int c, n;
26826048Sminshall 	register int dig;
26936935Skarels 	register char *cp;
27026048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
27126048Sminshall 	int pflag = 0;
27226048Sminshall 	char *pt = pasv;
27310296Ssam 
27436935Skarels 	cp = reply_string;
27526048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27610296Ssam 	for (;;) {
27710296Ssam 		dig = n = code = 0;
27810296Ssam 		while ((c = getc(cin)) != '\n') {
27927687Sminshall 			if (c == IAC) {     /* handle telnet commands */
28027687Sminshall 				switch (c = getc(cin)) {
28127687Sminshall 				case WILL:
28227687Sminshall 				case WONT:
28327687Sminshall 					c = getc(cin);
28436940Skarels 					fprintf(cout, "%c%c%c",IAC,DONT,c);
28527687Sminshall 					(void) fflush(cout);
28627687Sminshall 					break;
28727687Sminshall 				case DO:
28827687Sminshall 				case DONT:
28927687Sminshall 					c = getc(cin);
29036940Skarels 					fprintf(cout, "%c%c%c",IAC,WONT,c);
29127687Sminshall 					(void) fflush(cout);
29227687Sminshall 					break;
29327687Sminshall 				default:
29427687Sminshall 					break;
29527687Sminshall 				}
29627687Sminshall 				continue;
29727687Sminshall 			}
29810296Ssam 			dig++;
29910296Ssam 			if (c == EOF) {
30026048Sminshall 				if (expecteof) {
30126048Sminshall 					(void) signal(SIGINT,oldintr);
30226048Sminshall 					code = 221;
30310296Ssam 					return (0);
30426048Sminshall 				}
30510296Ssam 				lostpeer();
30626048Sminshall 				if (verbose) {
30726048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
30826048Sminshall 					(void) fflush(stdout);
30926048Sminshall 				}
31033772Scsvsj 				code = 421;
31133772Scsvsj 				return(4);
31210296Ssam 			}
31326048Sminshall 			if (c != '\r' && (verbose > 0 ||
31426048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
31526448Slepreau 				if (proxflag &&
31626448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
31726048Sminshall 					printf("%s:",hostname);
31826496Sminshall 				(void) putchar(c);
31926048Sminshall 			}
32010296Ssam 			if (dig < 4 && isdigit(c))
32110296Ssam 				code = code * 10 + (c - '0');
32226448Slepreau 			if (!pflag && code == 227)
32326048Sminshall 				pflag = 1;
32426448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
32526048Sminshall 				pflag = 2;
32626048Sminshall 			if (pflag == 2) {
32726448Slepreau 				if (c != '\r' && c != ')')
32826048Sminshall 					*pt++ = c;
32926048Sminshall 				else {
33026048Sminshall 					*pt = '\0';
33126048Sminshall 					pflag = 3;
33226048Sminshall 				}
33326048Sminshall 			}
33426048Sminshall 			if (dig == 4 && c == '-') {
33526448Slepreau 				if (continuation)
33626048Sminshall 					code = 0;
33710296Ssam 				continuation++;
33826048Sminshall 			}
33910296Ssam 			if (n == 0)
34010296Ssam 				n = c;
34136935Skarels 			*cp++ = c;
34210296Ssam 		}
34326048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
34426496Sminshall 			(void) putchar(c);
34511346Ssam 			(void) fflush (stdout);
34611346Ssam 		}
34710296Ssam 		if (continuation && code != originalcode) {
34810296Ssam 			if (originalcode == 0)
34910296Ssam 				originalcode = code;
35010296Ssam 			continue;
35110296Ssam 		}
35236935Skarels 		*cp = '\0';
35326448Slepreau 		if (n != '1')
35426048Sminshall 			cpend = 0;
35526048Sminshall 		(void) signal(SIGINT,oldintr);
35626448Slepreau 		if (code == 421 || originalcode == 421)
35726048Sminshall 			lostpeer();
35826448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
35926048Sminshall 			(*oldintr)();
36025907Smckusick 		return (n - '0');
36110296Ssam 	}
36210296Ssam }
36310296Ssam 
36426048Sminshall empty(mask, sec)
36527687Sminshall 	struct fd_set *mask;
36626048Sminshall 	int sec;
36726048Sminshall {
36826048Sminshall 	struct timeval t;
36926048Sminshall 
37026048Sminshall 	t.tv_sec = (long) sec;
37126048Sminshall 	t.tv_usec = 0;
37227687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
37326048Sminshall }
37426048Sminshall 
37510296Ssam jmp_buf	sendabort;
37610296Ssam 
37710296Ssam abortsend()
37810296Ssam {
37910296Ssam 
38026048Sminshall 	mflag = 0;
38126048Sminshall 	abrtflag = 0;
38226048Sminshall 	printf("\nsend aborted\n");
38326048Sminshall 	(void) fflush(stdout);
38410296Ssam 	longjmp(sendabort, 1);
38510296Ssam }
38610296Ssam 
38736940Skarels #define HASHBYTES 1024
38836940Skarels 
38910296Ssam sendrequest(cmd, local, remote)
39010296Ssam 	char *cmd, *local, *remote;
39110296Ssam {
39235659Sbostic 	FILE *fin, *dout = 0, *popen();
39335659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
39426048Sminshall 	int abortsend();
39536942Skarels 	char buf[BUFSIZ], *bufp;
39636940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
39711346Ssam 	register int c, d;
39810296Ssam 	struct stat st;
39910296Ssam 	struct timeval start, stop;
40036935Skarels 	char *mode;
40110296Ssam 
40226048Sminshall 	if (proxy) {
40326048Sminshall 		proxtrans(cmd, local, remote);
40426048Sminshall 		return;
40526048Sminshall 	}
40610296Ssam 	closefunc = NULL;
40726048Sminshall 	oldintr = NULL;
40826048Sminshall 	oldintp = NULL;
40936935Skarels 	mode = "w";
41026048Sminshall 	if (setjmp(sendabort)) {
41126048Sminshall 		while (cpend) {
41226048Sminshall 			(void) getreply(0);
41326048Sminshall 		}
41426048Sminshall 		if (data >= 0) {
41526048Sminshall 			(void) close(data);
41626048Sminshall 			data = -1;
41726048Sminshall 		}
41826448Slepreau 		if (oldintr)
41926048Sminshall 			(void) signal(SIGINT,oldintr);
42026448Slepreau 		if (oldintp)
42126048Sminshall 			(void) signal(SIGPIPE,oldintp);
42226048Sminshall 		code = -1;
42326048Sminshall 		return;
42426048Sminshall 	}
42510296Ssam 	oldintr = signal(SIGINT, abortsend);
42610296Ssam 	if (strcmp(local, "-") == 0)
42710296Ssam 		fin = stdin;
42810296Ssam 	else if (*local == '|') {
42926048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
43035659Sbostic 		fin = popen(local + 1, "r");
43110296Ssam 		if (fin == NULL) {
43226048Sminshall 			perror(local + 1);
43326048Sminshall 			(void) signal(SIGINT, oldintr);
43426048Sminshall 			(void) signal(SIGPIPE, oldintp);
43526048Sminshall 			code = -1;
43626048Sminshall 			return;
43710296Ssam 		}
43835659Sbostic 		closefunc = pclose;
43910296Ssam 	} else {
44010296Ssam 		fin = fopen(local, "r");
44110296Ssam 		if (fin == NULL) {
44210296Ssam 			perror(local);
44326048Sminshall 			(void) signal(SIGINT, oldintr);
44426048Sminshall 			code = -1;
44526048Sminshall 			return;
44610296Ssam 		}
44710296Ssam 		closefunc = fclose;
44810296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
44910296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
45026496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
45126048Sminshall 			(void) signal(SIGINT, oldintr);
45236935Skarels 			fclose(fin);
45326048Sminshall 			code = -1;
45426048Sminshall 			return;
45510296Ssam 		}
45610296Ssam 	}
45726048Sminshall 	if (initconn()) {
45826048Sminshall 		(void) signal(SIGINT, oldintr);
45926448Slepreau 		if (oldintp)
46026048Sminshall 			(void) signal(SIGPIPE, oldintp);
46126048Sminshall 		code = -1;
46236935Skarels 		if (closefunc != NULL)
46336935Skarels 			(*closefunc)(fin);
46426048Sminshall 		return;
46526048Sminshall 	}
46626448Slepreau 	if (setjmp(sendabort))
46726048Sminshall 		goto abort;
46836935Skarels 
469*36944Skarels 	if (restart_point &&
470*36944Skarels 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
471*36944Skarels 		if (fseek(fin, (long) restart_point, 0) < 0) {
472*36944Skarels 			perror(local);
473*36944Skarels 			restart_point = 0;
474*36944Skarels 			if (closefunc != NULL)
475*36944Skarels 				(*closefunc)(fin);
476*36944Skarels 			return;
477*36944Skarels 		}
478*36944Skarels 		if (command("REST %ld", (long) restart_point)
479*36944Skarels 			!= CONTINUE) {
480*36944Skarels 			restart_point = 0;
481*36944Skarels 			if (closefunc != NULL)
482*36944Skarels 				(*closefunc)(fin);
483*36944Skarels 			return;
484*36944Skarels 		}
485*36944Skarels 		restart_point = 0;
486*36944Skarels 		mode = "r+w";
487*36944Skarels 	}
48810296Ssam 	if (remote) {
48926048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
49026048Sminshall 			(void) signal(SIGINT, oldintr);
49126448Slepreau 			if (oldintp)
49226048Sminshall 				(void) signal(SIGPIPE, oldintp);
49336935Skarels 			if (closefunc != NULL)
49436935Skarels 				(*closefunc)(fin);
49526048Sminshall 			return;
49626048Sminshall 		}
49710296Ssam 	} else
49826048Sminshall 		if (command("%s", cmd) != PRELIM) {
49926048Sminshall 			(void) signal(SIGINT, oldintr);
50026448Slepreau 			if (oldintp)
50126048Sminshall 				(void) signal(SIGPIPE, oldintp);
50236935Skarels 			if (closefunc != NULL)
50336935Skarels 				(*closefunc)(fin);
50426048Sminshall 			return;
50526048Sminshall 		}
50636935Skarels 	dout = dataconn(mode);
50726448Slepreau 	if (dout == NULL)
50826048Sminshall 		goto abort;
50926496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
51036935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
51111219Ssam 	switch (type) {
51211219Ssam 
51311219Ssam 	case TYPE_I:
51411219Ssam 	case TYPE_L:
51511346Ssam 		errno = d = 0;
51636942Skarels 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
51711219Ssam 			bytes += c;
51836942Skarels 			for (bufp = buf; c > 0; c -= d, bufp += d)
51936942Skarels 				if ((d = write(fileno(dout), bufp, c)) <= 0)
52036942Skarels 					break;
52111651Ssam 			if (hash) {
52236940Skarels 				while (bytes >= hashbytes) {
52336940Skarels 					(void) putchar('#');
52436940Skarels 					hashbytes += HASHBYTES;
52536940Skarels 				}
52626496Sminshall 				(void) fflush(stdout);
52711651Ssam 			}
52811219Ssam 		}
52913213Ssam 		if (hash && bytes > 0) {
53036940Skarels 			if (bytes < HASHBYTES)
53136940Skarels 				(void) putchar('#');
53226496Sminshall 			(void) putchar('\n');
53326496Sminshall 			(void) fflush(stdout);
53411651Ssam 		}
53511219Ssam 		if (c < 0)
53611219Ssam 			perror(local);
53736942Skarels 		if (d <= 0) {
53836942Skarels 			if (d == 0)
53936942Skarels 				fprintf(stderr, "netout: write returned 0?\n");
54036942Skarels 			else if (errno != EPIPE)
54136935Skarels 				perror("netout");
54236935Skarels 			bytes = -1;
54336935Skarels 		}
54411219Ssam 		break;
54511219Ssam 
54611219Ssam 	case TYPE_A:
54711219Ssam 		while ((c = getc(fin)) != EOF) {
54811219Ssam 			if (c == '\n') {
54911651Ssam 				while (hash && (bytes >= hashbytes)) {
55026496Sminshall 					(void) putchar('#');
55126496Sminshall 					(void) fflush(stdout);
55236940Skarels 					hashbytes += HASHBYTES;
55311651Ssam 				}
55411219Ssam 				if (ferror(dout))
55511219Ssam 					break;
55626496Sminshall 				(void) putc('\r', dout);
55711219Ssam 				bytes++;
55811219Ssam 			}
55926496Sminshall 			(void) putc(c, dout);
56011219Ssam 			bytes++;
56126048Sminshall 	/*		if (c == '\r') {			  	*/
56226496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
56326048Sminshall 	/*			bytes++;				*/
56426048Sminshall 	/*		}                          			*/
56511219Ssam 		}
56611651Ssam 		if (hash) {
56713213Ssam 			if (bytes < hashbytes)
56826496Sminshall 				(void) putchar('#');
56926496Sminshall 			(void) putchar('\n');
57026496Sminshall 			(void) fflush(stdout);
57111651Ssam 		}
57211219Ssam 		if (ferror(fin))
57311219Ssam 			perror(local);
57436935Skarels 		if (ferror(dout)) {
57536935Skarels 			if (errno != EPIPE)
57636935Skarels 				perror("netout");
57736935Skarels 			bytes = -1;
57836935Skarels 		}
57911219Ssam 		break;
58010296Ssam 	}
58126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
58210296Ssam 	if (closefunc != NULL)
58326048Sminshall 		(*closefunc)(fin);
58410296Ssam 	(void) fclose(dout);
58526048Sminshall 	(void) getreply(0);
58626048Sminshall 	(void) signal(SIGINT, oldintr);
58736935Skarels 	if (oldintp)
58836935Skarels 		(void) signal(SIGPIPE, oldintp);
58935699Sbostic 	if (bytes > 0)
59026048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
59110296Ssam 	return;
59226048Sminshall abort:
59326496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
59426048Sminshall 	(void) signal(SIGINT, oldintr);
59526448Slepreau 	if (oldintp)
59626048Sminshall 		(void) signal(SIGPIPE, oldintp);
59726048Sminshall 	if (!cpend) {
59826048Sminshall 		code = -1;
59926048Sminshall 		return;
60026048Sminshall 	}
60126048Sminshall 	if (data >= 0) {
60226048Sminshall 		(void) close(data);
60326048Sminshall 		data = -1;
60426048Sminshall 	}
60526448Slepreau 	if (dout)
60626048Sminshall 		(void) fclose(dout);
60726048Sminshall 	(void) getreply(0);
60826048Sminshall 	code = -1;
60910296Ssam 	if (closefunc != NULL && fin != NULL)
61026048Sminshall 		(*closefunc)(fin);
61135699Sbostic 	if (bytes > 0)
61226048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
61310296Ssam }
61410296Ssam 
61510296Ssam jmp_buf	recvabort;
61610296Ssam 
61710296Ssam abortrecv()
61810296Ssam {
61910296Ssam 
62026048Sminshall 	mflag = 0;
62126048Sminshall 	abrtflag = 0;
62226048Sminshall 	printf("\n");
62326048Sminshall 	(void) fflush(stdout);
62410296Ssam 	longjmp(recvabort, 1);
62510296Ssam }
62610296Ssam 
62711651Ssam recvrequest(cmd, local, remote, mode)
62811651Ssam 	char *cmd, *local, *remote, *mode;
62910296Ssam {
63035659Sbostic 	FILE *fout, *din = 0, *popen();
63135659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
63236935Skarels 	int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd;
633*36944Skarels 	char *bufp, *gunique(), msg;
634*36944Skarels 	static char *buf;
63536940Skarels 	static int bufsize;
63636940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
63726496Sminshall 	struct fd_set mask;
63811346Ssam 	register int c, d;
63910296Ssam 	struct timeval start, stop;
64036940Skarels 	struct stat st;
64136940Skarels 	extern char *malloc();
64210296Ssam 
64336935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
64436935Skarels 	if (proxy && is_retr) {
64526048Sminshall 		proxtrans(cmd, local, remote);
64626048Sminshall 		return;
64726048Sminshall 	}
64810296Ssam 	closefunc = NULL;
64926048Sminshall 	oldintr = NULL;
65026048Sminshall 	oldintp = NULL;
65136935Skarels 	tcrflag = !crflag && is_retr;
65226048Sminshall 	if (setjmp(recvabort)) {
65326048Sminshall 		while (cpend) {
65426048Sminshall 			(void) getreply(0);
65526048Sminshall 		}
65626048Sminshall 		if (data >= 0) {
65726048Sminshall 			(void) close(data);
65826048Sminshall 			data = -1;
65926048Sminshall 		}
66026448Slepreau 		if (oldintr)
66126048Sminshall 			(void) signal(SIGINT, oldintr);
66226048Sminshall 		code = -1;
66326048Sminshall 		return;
66426048Sminshall 	}
66510296Ssam 	oldintr = signal(SIGINT, abortrecv);
66626048Sminshall 	if (strcmp(local, "-") && *local != '|') {
66710296Ssam 		if (access(local, 2) < 0) {
66826048Sminshall 			char *dir = rindex(local, '/');
66910296Ssam 
67026048Sminshall 			if (errno != ENOENT && errno != EACCES) {
67110296Ssam 				perror(local);
67226048Sminshall 				(void) signal(SIGINT, oldintr);
67326048Sminshall 				code = -1;
67426048Sminshall 				return;
67510296Ssam 			}
67626048Sminshall 			if (dir != NULL)
67726048Sminshall 				*dir = 0;
67826048Sminshall 			d = access(dir ? local : ".", 2);
67926048Sminshall 			if (dir != NULL)
68026048Sminshall 				*dir = '/';
68126048Sminshall 			if (d < 0) {
68226048Sminshall 				perror(local);
68326048Sminshall 				(void) signal(SIGINT, oldintr);
68426048Sminshall 				code = -1;
68526048Sminshall 				return;
68626048Sminshall 			}
68726048Sminshall 			if (!runique && errno == EACCES &&
68836935Skarels 			    chmod(local, 0600) < 0) {
68926048Sminshall 				perror(local);
69026048Sminshall 				(void) signal(SIGINT, oldintr);
69126048Sminshall 				code = -1;
69226048Sminshall 				return;
69326048Sminshall 			}
69426048Sminshall 			if (runique && errno == EACCES &&
69526048Sminshall 			   (local = gunique(local)) == NULL) {
69626048Sminshall 				(void) signal(SIGINT, oldintr);
69726048Sminshall 				code = -1;
69826048Sminshall 				return;
69926048Sminshall 			}
70010296Ssam 		}
70126048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
70226048Sminshall 			(void) signal(SIGINT, oldintr);
70326048Sminshall 			code = -1;
70426048Sminshall 			return;
70526048Sminshall 		}
70626048Sminshall 	}
70726048Sminshall 	if (initconn()) {
70826048Sminshall 		(void) signal(SIGINT, oldintr);
70926048Sminshall 		code = -1;
71026048Sminshall 		return;
71126048Sminshall 	}
71226448Slepreau 	if (setjmp(recvabort))
71326048Sminshall 		goto abort;
71436935Skarels 	if (!is_retr) {
71536935Skarels 		if (type != TYPE_A) {
71636935Skarels 			oldtype = type;
71736935Skarels 			oldverbose = verbose;
71836935Skarels 			if (!debug)
71936935Skarels 				verbose = 0;
72036935Skarels 			setascii();
72136935Skarels 			verbose = oldverbose;
72236935Skarels 		}
723*36944Skarels 	} else if (restart_point) {
724*36944Skarels 		if (command("REST %ld", (long) restart_point) != CONTINUE)
725*36944Skarels 			return;
72626048Sminshall 	}
72710296Ssam 	if (remote) {
72826048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
72926048Sminshall 			(void) signal(SIGINT, oldintr);
73026048Sminshall 			if (oldtype) {
73126448Slepreau 				if (!debug)
73226048Sminshall 					verbose = 0;
73326048Sminshall 				switch (oldtype) {
73426048Sminshall 					case TYPE_I:
73526048Sminshall 						setbinary();
73626048Sminshall 						break;
73726048Sminshall 					case TYPE_E:
73826048Sminshall 						setebcdic();
73926048Sminshall 						break;
74026048Sminshall 					case TYPE_L:
74126048Sminshall 						settenex();
74226048Sminshall 						break;
74336942Skarels 				}
74426048Sminshall 				verbose = oldverbose;
74526048Sminshall 			}
74626048Sminshall 			return;
74726048Sminshall 		}
74826048Sminshall 	} else {
74926048Sminshall 		if (command("%s", cmd) != PRELIM) {
75026048Sminshall 			(void) signal(SIGINT, oldintr);
75126048Sminshall 			if (oldtype) {
75226448Slepreau 				if (!debug)
75326048Sminshall 					verbose = 0;
75426048Sminshall 				switch (oldtype) {
75526048Sminshall 					case TYPE_I:
75626048Sminshall 						setbinary();
75726048Sminshall 						break;
75826048Sminshall 					case TYPE_E:
75926048Sminshall 						setebcdic();
76026048Sminshall 						break;
76126048Sminshall 					case TYPE_L:
76226048Sminshall 						settenex();
76326048Sminshall 						break;
76436942Skarels 				}
76526048Sminshall 				verbose = oldverbose;
76626048Sminshall 			}
76726048Sminshall 			return;
76826048Sminshall 		}
76926048Sminshall 	}
77026048Sminshall 	din = dataconn("r");
77126048Sminshall 	if (din == NULL)
77226048Sminshall 		goto abort;
77326448Slepreau 	if (strcmp(local, "-") == 0)
77410296Ssam 		fout = stdout;
77510296Ssam 	else if (*local == '|') {
77626048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
77735659Sbostic 		fout = popen(local + 1, "w");
77826048Sminshall 		if (fout == NULL) {
77926048Sminshall 			perror(local+1);
78026048Sminshall 			goto abort;
78126048Sminshall 		}
78235659Sbostic 		closefunc = pclose;
78336940Skarels 	} else {
78411651Ssam 		fout = fopen(local, mode);
78526048Sminshall 		if (fout == NULL) {
78626048Sminshall 			perror(local);
78726048Sminshall 			goto abort;
78826048Sminshall 		}
78910296Ssam 		closefunc = fclose;
79010296Ssam 	}
79136940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
79236940Skarels 		st.st_blksize = BUFSIZ;
79336940Skarels 	if (st.st_blksize > bufsize) {
79436940Skarels 		if (buf)
79536940Skarels 			(void) free(buf);
79636940Skarels 		buf = malloc(st.st_blksize);
79736940Skarels 		if (buf == NULL) {
79836940Skarels 			perror("malloc");
799*36944Skarels 			bufsize = 0;
80036940Skarels 			goto abort;
80136940Skarels 		}
80236940Skarels 		bufsize = st.st_blksize;
80336940Skarels 	}
80426496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
80511219Ssam 	switch (type) {
80611219Ssam 
80711219Ssam 	case TYPE_I:
80811219Ssam 	case TYPE_L:
809*36944Skarels 		if (restart_point &&
810*36944Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
811*36944Skarels 			perror(local);
812*36944Skarels 			if (closefunc != NULL)
813*36944Skarels 				(*closefunc)(fout);
814*36944Skarels 			return;
815*36944Skarels 		}
81611346Ssam 		errno = d = 0;
81736940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
818*36944Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
81911219Ssam 				break;
82011219Ssam 			bytes += c;
82111651Ssam 			if (hash) {
82236940Skarels 				while (bytes >= hashbytes) {
82336940Skarels 					(void) putchar('#');
82436940Skarels 					hashbytes += HASHBYTES;
82536940Skarels 				}
82626496Sminshall 				(void) fflush(stdout);
82711651Ssam 			}
82811219Ssam 		}
82913213Ssam 		if (hash && bytes > 0) {
83036940Skarels 			if (bytes < HASHBYTES)
83136940Skarels 				(void) putchar('#');
83226496Sminshall 			(void) putchar('\n');
83326496Sminshall 			(void) fflush(stdout);
83411651Ssam 		}
83536935Skarels 		if (c < 0) {
83636935Skarels 			if (errno != EPIPE)
83736935Skarels 				perror("netin");
83836935Skarels 			bytes = -1;
83936935Skarels 		}
84036942Skarels 		if (d < c) {
84136942Skarels 			if (d < 0)
84236942Skarels 				perror(local);
84336942Skarels 			else
84436942Skarels 				fprintf(stderr, "%s: short write\n", local);
84536942Skarels 		}
84611219Ssam 		break;
84711219Ssam 
84811219Ssam 	case TYPE_A:
849*36944Skarels 		if (restart_point) {
850*36944Skarels 			register int i, n, c;
851*36944Skarels 
852*36944Skarels 			if (fseek(fout, 0L, L_SET) < 0)
853*36944Skarels 				goto done;
854*36944Skarels 			n = restart_point;
855*36944Skarels 			i = 0;
856*36944Skarels 			while (i++ < n) {
857*36944Skarels 				if ((c=getc(fout)) == EOF)
858*36944Skarels 					goto done;
859*36944Skarels 				if (c == '\n')
860*36944Skarels 					i++;
861*36944Skarels 			}
862*36944Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
863*36944Skarels done:
864*36944Skarels 				perror(local);
865*36944Skarels 				if (closefunc != NULL)
866*36944Skarels 					(*closefunc)(fout);
867*36944Skarels 				return;
868*36944Skarels 			}
869*36944Skarels 		}
87011219Ssam 		while ((c = getc(din)) != EOF) {
87127749Sminshall 			while (c == '\r') {
87211651Ssam 				while (hash && (bytes >= hashbytes)) {
87326496Sminshall 					(void) putchar('#');
87426496Sminshall 					(void) fflush(stdout);
87536940Skarels 					hashbytes += HASHBYTES;
87611651Ssam 				}
87710296Ssam 				bytes++;
87826048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
87936940Skarels 					if (ferror(fout))
88036940Skarels 						goto break2;
88136940Skarels 					(void) putc('\r', fout);
88236942Skarels 					if (c == '\0') {
88336942Skarels 						bytes++;
88436940Skarels 						goto contin2;
88536942Skarels 					}
88636942Skarels 					if (c == EOF)
88736942Skarels 						goto contin2;
88811219Ssam 				}
88911219Ssam 			}
89036940Skarels 			(void) putc(c, fout);
89111219Ssam 			bytes++;
89236940Skarels 	contin2:	;
89310296Ssam 		}
89436940Skarels break2:
89511651Ssam 		if (hash) {
89613213Ssam 			if (bytes < hashbytes)
89726496Sminshall 				(void) putchar('#');
89826496Sminshall 			(void) putchar('\n');
89926496Sminshall 			(void) fflush(stdout);
90011651Ssam 		}
901*36944Skarels 		if (ferror(din)) {
90236935Skarels 			if (errno != EPIPE)
903*36944Skarels 				perror("netin");
90436935Skarels 			bytes = -1;
90536935Skarels 		}
90636940Skarels 		if (ferror(fout))
907*36944Skarels 			perror(local);
90811219Ssam 		break;
90910296Ssam 	}
91026448Slepreau 	if (closefunc != NULL)
91126048Sminshall 		(*closefunc)(fout);
91226496Sminshall 	(void) signal(SIGINT, oldintr);
91326448Slepreau 	if (oldintp)
91426048Sminshall 		(void) signal(SIGPIPE, oldintp);
91526496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
91610296Ssam 	(void) fclose(din);
91726048Sminshall 	(void) getreply(0);
91836935Skarels 	if (bytes > 0 && is_retr)
91926048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
92026048Sminshall 	if (oldtype) {
92126448Slepreau 		if (!debug)
92226048Sminshall 			verbose = 0;
92326048Sminshall 		switch (oldtype) {
92426048Sminshall 			case TYPE_I:
92526048Sminshall 				setbinary();
92626048Sminshall 				break;
92726048Sminshall 			case TYPE_E:
92826048Sminshall 				setebcdic();
92926048Sminshall 				break;
93026048Sminshall 			case TYPE_L:
93126048Sminshall 				settenex();
93226048Sminshall 				break;
93326048Sminshall 		}
93426048Sminshall 		verbose = oldverbose;
93526048Sminshall 	}
93626048Sminshall 	return;
93726048Sminshall abort:
93826048Sminshall 
93927687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
94026048Sminshall 
94126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
94226448Slepreau 	if (oldintp)
94326048Sminshall 		(void) signal(SIGPIPE, oldintr);
94426048Sminshall 	(void) signal(SIGINT,SIG_IGN);
94526048Sminshall 	if (oldtype) {
94626448Slepreau 		if (!debug)
94726048Sminshall 			verbose = 0;
94826048Sminshall 		switch (oldtype) {
94926048Sminshall 			case TYPE_I:
95026048Sminshall 				setbinary();
95126048Sminshall 				break;
95226048Sminshall 			case TYPE_E:
95326048Sminshall 				setebcdic();
95426048Sminshall 				break;
95526048Sminshall 			case TYPE_L:
95626048Sminshall 				settenex();
95726048Sminshall 				break;
95826048Sminshall 		}
95926048Sminshall 		verbose = oldverbose;
96026048Sminshall 	}
96126048Sminshall 	if (!cpend) {
96226048Sminshall 		code = -1;
96326048Sminshall 		(void) signal(SIGINT,oldintr);
96426048Sminshall 		return;
96526048Sminshall 	}
96626048Sminshall 
96727687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
96827687Sminshall 	(void) fflush(cout);
96927687Sminshall 	msg = IAC;
97027687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
97127687Sminshall /* after urgent byte rather than before as now is protocol            */
97227687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
97327687Sminshall 		perror("abort");
97426048Sminshall 	}
97527687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
97626048Sminshall 	(void) fflush(cout);
97727687Sminshall 	FD_ZERO(&mask);
97826496Sminshall 	FD_SET(fileno(cin), &mask);
97926496Sminshall 	if (din) {
98026496Sminshall 		FD_SET(fileno(din), &mask);
98126496Sminshall 	}
98227687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
98327687Sminshall 		if (nfnd < 0) {
98427687Sminshall 			perror("abort");
98527687Sminshall 		}
98626048Sminshall 		code = -1;
98726048Sminshall 		lostpeer();
98826048Sminshall 	}
98926496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
99036940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0)
99126448Slepreau 			;
99226496Sminshall 	}
99327687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
99426048Sminshall 		if (data >= 0) {
99526496Sminshall 			(void) close(data);
99626048Sminshall 			data = -1;
99726048Sminshall 		}
99825907Smckusick 		(void) getreply(0);
99925907Smckusick 	}
100026048Sminshall 	(void) getreply(0);
100126048Sminshall 	code = -1;
100226048Sminshall 	if (data >= 0) {
100326048Sminshall 		(void) close(data);
100426048Sminshall 		data = -1;
100526048Sminshall 	}
100626448Slepreau 	if (closefunc != NULL && fout != NULL)
100726048Sminshall 		(*closefunc)(fout);
100826448Slepreau 	if (din)
100926048Sminshall 		(void) fclose(din);
101035699Sbostic 	if (bytes > 0)
101126048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
101226048Sminshall 	(void) signal(SIGINT,oldintr);
101310296Ssam }
101410296Ssam 
101510296Ssam /*
101610296Ssam  * Need to start a listen on the data channel
101710296Ssam  * before we send the command, otherwise the
101810296Ssam  * server's connect may fail.
101910296Ssam  */
102033224Sbostic int sendport = -1;
102111651Ssam 
102210296Ssam initconn()
102310296Ssam {
102410296Ssam 	register char *p, *a;
102526048Sminshall 	int result, len, tmpno = 0;
102626993Skarels 	int on = 1;
102710296Ssam 
102811651Ssam noport:
102910296Ssam 	data_addr = myctladdr;
103011651Ssam 	if (sendport)
103111651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
103211651Ssam 	if (data != -1)
103311651Ssam 		(void) close (data);
103418287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
103510296Ssam 	if (data < 0) {
103610296Ssam 		perror("ftp: socket");
103726448Slepreau 		if (tmpno)
103826048Sminshall 			sendport = 1;
103910296Ssam 		return (1);
104010296Ssam 	}
104112397Ssam 	if (!sendport)
104227687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
104333224Sbostic 			perror("ftp: setsockopt (reuse address)");
104412397Ssam 			goto bad;
104512397Ssam 		}
104626496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
104710296Ssam 		perror("ftp: bind");
104810296Ssam 		goto bad;
104910296Ssam 	}
105010296Ssam 	if (options & SO_DEBUG &&
105127687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
105210296Ssam 		perror("ftp: setsockopt (ignored)");
105311627Ssam 	len = sizeof (data_addr);
105411627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
105511627Ssam 		perror("ftp: getsockname");
105610296Ssam 		goto bad;
105710296Ssam 	}
105826448Slepreau 	if (listen(data, 1) < 0)
105910296Ssam 		perror("ftp: listen");
106011651Ssam 	if (sendport) {
106111651Ssam 		a = (char *)&data_addr.sin_addr;
106211651Ssam 		p = (char *)&data_addr.sin_port;
106310296Ssam #define	UC(b)	(((int)b)&0xff)
106411651Ssam 		result =
106511651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
106611651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
106711651Ssam 		      UC(p[0]), UC(p[1]));
106811651Ssam 		if (result == ERROR && sendport == -1) {
106911651Ssam 			sendport = 0;
107026048Sminshall 			tmpno = 1;
107111651Ssam 			goto noport;
107211651Ssam 		}
107311651Ssam 		return (result != COMPLETE);
107411651Ssam 	}
107526448Slepreau 	if (tmpno)
107626048Sminshall 		sendport = 1;
107711651Ssam 	return (0);
107810296Ssam bad:
107910296Ssam 	(void) close(data), data = -1;
108026448Slepreau 	if (tmpno)
108126048Sminshall 		sendport = 1;
108210296Ssam 	return (1);
108310296Ssam }
108410296Ssam 
108510296Ssam FILE *
108610296Ssam dataconn(mode)
108710296Ssam 	char *mode;
108810296Ssam {
108910296Ssam 	struct sockaddr_in from;
109010296Ssam 	int s, fromlen = sizeof (from);
109110296Ssam 
109226496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
109310296Ssam 	if (s < 0) {
109410296Ssam 		perror("ftp: accept");
109510296Ssam 		(void) close(data), data = -1;
109610296Ssam 		return (NULL);
109710296Ssam 	}
109810296Ssam 	(void) close(data);
109910296Ssam 	data = s;
110010296Ssam 	return (fdopen(data, mode));
110110296Ssam }
110210296Ssam 
110326048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
110426048Sminshall 	char *direction, *local, *remote;
110511651Ssam 	long bytes;
110610296Ssam 	struct timeval *t0, *t1;
110710296Ssam {
110810296Ssam 	struct timeval td;
110916437Sleres 	float s, bs;
111010296Ssam 
111135699Sbostic 	if (verbose) {
111235699Sbostic 		tvsub(&td, t1, t0);
111335699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
111410296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
111535699Sbostic 		bs = bytes / nz(s);
111635699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
111735699Sbostic 		    bytes, direction, s, bs / 1024.);
111835699Sbostic 	} else {
111935699Sbostic 		if (local && *local != '-')
112035699Sbostic 			printf("local: %s ", local);
112135699Sbostic 		if (remote)
112235699Sbostic 			printf("remote: %s\n", remote);
112335699Sbostic 	}
112410296Ssam }
112510296Ssam 
112626496Sminshall /*tvadd(tsum, t0)
112710296Ssam 	struct timeval *tsum, *t0;
112810296Ssam {
112910296Ssam 
113010296Ssam 	tsum->tv_sec += t0->tv_sec;
113110296Ssam 	tsum->tv_usec += t0->tv_usec;
113210296Ssam 	if (tsum->tv_usec > 1000000)
113310296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
113426496Sminshall } */
113510296Ssam 
113610296Ssam tvsub(tdiff, t1, t0)
113710296Ssam 	struct timeval *tdiff, *t1, *t0;
113810296Ssam {
113910296Ssam 
114010296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
114110296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
114210296Ssam 	if (tdiff->tv_usec < 0)
114310296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
114410296Ssam }
114526048Sminshall 
114626048Sminshall psabort()
114726048Sminshall {
114826048Sminshall 	extern int abrtflag;
114926048Sminshall 
115026048Sminshall 	abrtflag++;
115126048Sminshall }
115226048Sminshall 
115326048Sminshall pswitch(flag)
115426048Sminshall 	int flag;
115526048Sminshall {
115626048Sminshall 	extern int proxy, abrtflag;
115726048Sminshall 	int (*oldintr)();
115826048Sminshall 	static struct comvars {
115926048Sminshall 		int connect;
116028469Skarels 		char name[MAXHOSTNAMELEN];
116126048Sminshall 		struct sockaddr_in mctl;
116226048Sminshall 		struct sockaddr_in hctl;
116326048Sminshall 		FILE *in;
116426048Sminshall 		FILE *out;
116526048Sminshall 		int tpe;
116626048Sminshall 		int cpnd;
116726048Sminshall 		int sunqe;
116826048Sminshall 		int runqe;
116926048Sminshall 		int mcse;
117026048Sminshall 		int ntflg;
117126048Sminshall 		char nti[17];
117226048Sminshall 		char nto[17];
117326048Sminshall 		int mapflg;
117426048Sminshall 		char mi[MAXPATHLEN];
117526048Sminshall 		char mo[MAXPATHLEN];
117626048Sminshall 		} proxstruct, tmpstruct;
117726048Sminshall 	struct comvars *ip, *op;
117826048Sminshall 
117926048Sminshall 	abrtflag = 0;
118026048Sminshall 	oldintr = signal(SIGINT, psabort);
118126048Sminshall 	if (flag) {
118226448Slepreau 		if (proxy)
118326048Sminshall 			return;
118426048Sminshall 		ip = &tmpstruct;
118526048Sminshall 		op = &proxstruct;
118626048Sminshall 		proxy++;
118726048Sminshall 	}
118826048Sminshall 	else {
118926448Slepreau 		if (!proxy)
119026048Sminshall 			return;
119126048Sminshall 		ip = &proxstruct;
119226048Sminshall 		op = &tmpstruct;
119326048Sminshall 		proxy = 0;
119426048Sminshall 	}
119526048Sminshall 	ip->connect = connected;
119626048Sminshall 	connected = op->connect;
119728469Skarels 	if (hostname) {
119828469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
119928469Skarels 		ip->name[strlen(ip->name)] = '\0';
120028469Skarels 	} else
120128469Skarels 		ip->name[0] = 0;
120226048Sminshall 	hostname = op->name;
120326048Sminshall 	ip->hctl = hisctladdr;
120426048Sminshall 	hisctladdr = op->hctl;
120526048Sminshall 	ip->mctl = myctladdr;
120626048Sminshall 	myctladdr = op->mctl;
120726048Sminshall 	ip->in = cin;
120826048Sminshall 	cin = op->in;
120926048Sminshall 	ip->out = cout;
121026048Sminshall 	cout = op->out;
121126048Sminshall 	ip->tpe = type;
121226048Sminshall 	type = op->tpe;
121326448Slepreau 	if (!type)
121426048Sminshall 		type = 1;
121526048Sminshall 	ip->cpnd = cpend;
121626048Sminshall 	cpend = op->cpnd;
121726048Sminshall 	ip->sunqe = sunique;
121826048Sminshall 	sunique = op->sunqe;
121926048Sminshall 	ip->runqe = runique;
122026048Sminshall 	runique = op->runqe;
122126048Sminshall 	ip->mcse = mcase;
122226048Sminshall 	mcase = op->mcse;
122326048Sminshall 	ip->ntflg = ntflag;
122426048Sminshall 	ntflag = op->ntflg;
122526496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
122626048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
122726496Sminshall 	(void) strcpy(ntin, op->nti);
122826496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
122926048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
123026496Sminshall 	(void) strcpy(ntout, op->nto);
123126048Sminshall 	ip->mapflg = mapflag;
123226048Sminshall 	mapflag = op->mapflg;
123326496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
123426048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
123526496Sminshall 	(void) strcpy(mapin, op->mi);
123626496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
123726048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
123826496Sminshall 	(void) strcpy(mapout, op->mo);
123926048Sminshall 	(void) signal(SIGINT, oldintr);
124026048Sminshall 	if (abrtflag) {
124126048Sminshall 		abrtflag = 0;
124226048Sminshall 		(*oldintr)();
124326448Slepreau 	}
124426048Sminshall }
124526048Sminshall 
124626048Sminshall jmp_buf ptabort;
124726048Sminshall int ptabflg;
124826048Sminshall 
124926048Sminshall abortpt()
125026048Sminshall {
125126048Sminshall 	printf("\n");
125226496Sminshall 	(void) fflush(stdout);
125326048Sminshall 	ptabflg++;
125426048Sminshall 	mflag = 0;
125526048Sminshall 	abrtflag = 0;
125626048Sminshall 	longjmp(ptabort, 1);
125726048Sminshall }
125826048Sminshall 
125926048Sminshall proxtrans(cmd, local, remote)
126026048Sminshall 	char *cmd, *local, *remote;
126126048Sminshall {
126227687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
126326048Sminshall 	extern jmp_buf ptabort;
126426048Sminshall 	char *cmd2;
126526496Sminshall 	struct fd_set mask;
126626048Sminshall 
126726448Slepreau 	if (strcmp(cmd, "RETR"))
126826048Sminshall 		cmd2 = "RETR";
126926448Slepreau 	else
127026048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
127126048Sminshall 	if (command("PASV") != COMPLETE) {
127226048Sminshall 		printf("proxy server does not support third part transfers.\n");
127326048Sminshall 		return;
127426048Sminshall 	}
127526048Sminshall 	tmptype = type;
127626048Sminshall 	pswitch(0);
127726048Sminshall 	if (!connected) {
127826048Sminshall 		printf("No primary connection\n");
127926048Sminshall 		pswitch(1);
128026048Sminshall 		code = -1;
128126048Sminshall 		return;
128226048Sminshall 	}
128326048Sminshall 	if (type != tmptype) {
128426048Sminshall 		oldtype = type;
128526048Sminshall 		switch (tmptype) {
128626048Sminshall 			case TYPE_A:
128726048Sminshall 				setascii();
128826048Sminshall 				break;
128926048Sminshall 			case TYPE_I:
129026048Sminshall 				setbinary();
129126048Sminshall 				break;
129226048Sminshall 			case TYPE_E:
129326048Sminshall 				setebcdic();
129426048Sminshall 				break;
129526048Sminshall 			case TYPE_L:
129626048Sminshall 				settenex();
129726048Sminshall 				break;
129826048Sminshall 		}
129926048Sminshall 	}
130026048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
130126048Sminshall 		switch (oldtype) {
130226048Sminshall 			case 0:
130326048Sminshall 				break;
130426048Sminshall 			case TYPE_A:
130526048Sminshall 				setascii();
130626048Sminshall 				break;
130726048Sminshall 			case TYPE_I:
130826048Sminshall 				setbinary();
130926048Sminshall 				break;
131026048Sminshall 			case TYPE_E:
131126048Sminshall 				setebcdic();
131226048Sminshall 				break;
131326048Sminshall 			case TYPE_L:
131426048Sminshall 				settenex();
131526048Sminshall 				break;
131626048Sminshall 		}
131726048Sminshall 		pswitch(1);
131826048Sminshall 		return;
131926048Sminshall 	}
132026448Slepreau 	if (setjmp(ptabort))
132126048Sminshall 		goto abort;
132226048Sminshall 	oldintr = signal(SIGINT, abortpt);
132326048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
132426048Sminshall 		(void) signal(SIGINT, oldintr);
132526048Sminshall 		switch (oldtype) {
132626048Sminshall 			case 0:
132726048Sminshall 				break;
132826048Sminshall 			case TYPE_A:
132926048Sminshall 				setascii();
133026048Sminshall 				break;
133126048Sminshall 			case TYPE_I:
133226048Sminshall 				setbinary();
133326048Sminshall 				break;
133426048Sminshall 			case TYPE_E:
133526048Sminshall 				setebcdic();
133626048Sminshall 				break;
133726048Sminshall 			case TYPE_L:
133826048Sminshall 				settenex();
133926048Sminshall 				break;
134026048Sminshall 		}
134126048Sminshall 		pswitch(1);
134226048Sminshall 		return;
134326048Sminshall 	}
134426048Sminshall 	sleep(2);
134526048Sminshall 	pswitch(1);
134626048Sminshall 	secndflag++;
134726448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
134826048Sminshall 		goto abort;
134926048Sminshall 	ptflag++;
135026048Sminshall 	(void) getreply(0);
135126048Sminshall 	pswitch(0);
135226048Sminshall 	(void) getreply(0);
135326048Sminshall 	(void) signal(SIGINT, oldintr);
135426048Sminshall 	switch (oldtype) {
135526048Sminshall 		case 0:
135626048Sminshall 			break;
135726048Sminshall 		case TYPE_A:
135826048Sminshall 			setascii();
135926048Sminshall 			break;
136026048Sminshall 		case TYPE_I:
136126048Sminshall 			setbinary();
136226048Sminshall 			break;
136326048Sminshall 		case TYPE_E:
136426048Sminshall 			setebcdic();
136526048Sminshall 			break;
136626048Sminshall 		case TYPE_L:
136726048Sminshall 			settenex();
136826048Sminshall 			break;
136926048Sminshall 	}
137026048Sminshall 	pswitch(1);
137126048Sminshall 	ptflag = 0;
137226048Sminshall 	printf("local: %s remote: %s\n", local, remote);
137326048Sminshall 	return;
137426048Sminshall abort:
137526048Sminshall 	(void) signal(SIGINT, SIG_IGN);
137626048Sminshall 	ptflag = 0;
137726448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
137826048Sminshall 		pswitch(1);
137926448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
138026048Sminshall 		pswitch(0);
138126048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
138226048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
138326048Sminshall 			pswitch(0);
138426048Sminshall 			switch (oldtype) {
138526048Sminshall 				case 0:
138626048Sminshall 					break;
138726048Sminshall 				case TYPE_A:
138826048Sminshall 					setascii();
138926048Sminshall 					break;
139026048Sminshall 				case TYPE_I:
139126048Sminshall 					setbinary();
139226048Sminshall 					break;
139326048Sminshall 				case TYPE_E:
139426048Sminshall 					setebcdic();
139526048Sminshall 					break;
139626048Sminshall 				case TYPE_L:
139726048Sminshall 					settenex();
139826048Sminshall 					break;
139926048Sminshall 			}
140027687Sminshall 			if (cpend) {
140126048Sminshall 				char msg[2];
140226048Sminshall 
140326048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
140426048Sminshall 				(void) fflush(cout);
140526048Sminshall 				*msg = IAC;
140626048Sminshall 				*(msg+1) = DM;
140726448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
140826048Sminshall 					perror("abort");
140926048Sminshall 				fprintf(cout,"ABOR\r\n");
141026048Sminshall 				(void) fflush(cout);
141127687Sminshall 				FD_ZERO(&mask);
141226496Sminshall 				FD_SET(fileno(cin), &mask);
141327687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
141427687Sminshall 					if (nfnd < 0) {
141527687Sminshall 						perror("abort");
141627687Sminshall 					}
141726448Slepreau 					if (ptabflg)
141826048Sminshall 						code = -1;
141926048Sminshall 					lostpeer();
142026048Sminshall 				}
142126048Sminshall 				(void) getreply(0);
142226048Sminshall 				(void) getreply(0);
142326048Sminshall 			}
142426048Sminshall 		}
142526048Sminshall 		pswitch(1);
142626448Slepreau 		if (ptabflg)
142726048Sminshall 			code = -1;
142826048Sminshall 		(void) signal(SIGINT, oldintr);
142926048Sminshall 		return;
143026048Sminshall 	}
143127687Sminshall 	if (cpend) {
143226048Sminshall 		char msg[2];
143326048Sminshall 
143426048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
143526048Sminshall 		(void) fflush(cout);
143626048Sminshall 		*msg = IAC;
143726048Sminshall 		*(msg+1) = DM;
143826448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
143926048Sminshall 			perror("abort");
144026048Sminshall 		fprintf(cout,"ABOR\r\n");
144126048Sminshall 		(void) fflush(cout);
144227687Sminshall 		FD_ZERO(&mask);
144326496Sminshall 		FD_SET(fileno(cin), &mask);
144427687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
144527687Sminshall 			if (nfnd < 0) {
144627687Sminshall 				perror("abort");
144727687Sminshall 			}
144826448Slepreau 			if (ptabflg)
144926048Sminshall 				code = -1;
145026048Sminshall 			lostpeer();
145126048Sminshall 		}
145226048Sminshall 		(void) getreply(0);
145326048Sminshall 		(void) getreply(0);
145426048Sminshall 	}
145526048Sminshall 	pswitch(!proxy);
145626048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
145726048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
145826048Sminshall 			pswitch(0);
145926048Sminshall 			switch (oldtype) {
146026048Sminshall 				case 0:
146126048Sminshall 					break;
146226048Sminshall 				case TYPE_A:
146326048Sminshall 					setascii();
146426048Sminshall 					break;
146526048Sminshall 				case TYPE_I:
146626048Sminshall 					setbinary();
146726048Sminshall 					break;
146826048Sminshall 				case TYPE_E:
146926048Sminshall 					setebcdic();
147026048Sminshall 					break;
147126048Sminshall 				case TYPE_L:
147226048Sminshall 					settenex();
147326048Sminshall 					break;
147426048Sminshall 			}
147527687Sminshall 			if (cpend) {
147626048Sminshall 				char msg[2];
147726048Sminshall 
147826048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
147926048Sminshall 				(void) fflush(cout);
148026048Sminshall 				*msg = IAC;
148126048Sminshall 				*(msg+1) = DM;
148226448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
148326048Sminshall 					perror("abort");
148426048Sminshall 				fprintf(cout,"ABOR\r\n");
148526048Sminshall 				(void) fflush(cout);
148627687Sminshall 				FD_ZERO(&mask);
148726496Sminshall 				FD_SET(fileno(cin), &mask);
148827687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
148927687Sminshall 					if (nfnd < 0) {
149027687Sminshall 						perror("abort");
149127687Sminshall 					}
149226448Slepreau 					if (ptabflg)
149326048Sminshall 						code = -1;
149426048Sminshall 					lostpeer();
149526048Sminshall 				}
149626048Sminshall 				(void) getreply(0);
149726048Sminshall 				(void) getreply(0);
149826048Sminshall 			}
149926048Sminshall 			pswitch(1);
150026448Slepreau 			if (ptabflg)
150126048Sminshall 				code = -1;
150226048Sminshall 			(void) signal(SIGINT, oldintr);
150326048Sminshall 			return;
150426048Sminshall 		}
150526048Sminshall 	}
150627687Sminshall 	if (cpend) {
150726048Sminshall 		char msg[2];
150826048Sminshall 
150926048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
151026048Sminshall 		(void) fflush(cout);
151126048Sminshall 		*msg = IAC;
151226048Sminshall 		*(msg+1) = DM;
151326448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
151426048Sminshall 			perror("abort");
151526048Sminshall 		fprintf(cout,"ABOR\r\n");
151626048Sminshall 		(void) fflush(cout);
151727687Sminshall 		FD_ZERO(&mask);
151826496Sminshall 		FD_SET(fileno(cin), &mask);
151927687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
152027687Sminshall 			if (nfnd < 0) {
152127687Sminshall 				perror("abort");
152227687Sminshall 			}
152326448Slepreau 			if (ptabflg)
152426048Sminshall 				code = -1;
152526048Sminshall 			lostpeer();
152626048Sminshall 		}
152726048Sminshall 		(void) getreply(0);
152826048Sminshall 		(void) getreply(0);
152926048Sminshall 	}
153026048Sminshall 	pswitch(!proxy);
153126048Sminshall 	if (cpend) {
153227687Sminshall 		FD_ZERO(&mask);
153326496Sminshall 		FD_SET(fileno(cin), &mask);
153427687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
153527687Sminshall 			if (nfnd < 0) {
153627687Sminshall 				perror("abort");
153727687Sminshall 			}
153826448Slepreau 			if (ptabflg)
153926048Sminshall 				code = -1;
154026048Sminshall 			lostpeer();
154126048Sminshall 		}
154226048Sminshall 		(void) getreply(0);
154326048Sminshall 		(void) getreply(0);
154426048Sminshall 	}
154526448Slepreau 	if (proxy)
154626048Sminshall 		pswitch(0);
154726048Sminshall 	switch (oldtype) {
154826048Sminshall 		case 0:
154926048Sminshall 			break;
155026048Sminshall 		case TYPE_A:
155126048Sminshall 			setascii();
155226048Sminshall 			break;
155326048Sminshall 		case TYPE_I:
155426048Sminshall 			setbinary();
155526048Sminshall 			break;
155626048Sminshall 		case TYPE_E:
155726048Sminshall 			setebcdic();
155826048Sminshall 			break;
155926048Sminshall 		case TYPE_L:
156026048Sminshall 			settenex();
156126048Sminshall 			break;
156226048Sminshall 	}
156326048Sminshall 	pswitch(1);
156426448Slepreau 	if (ptabflg)
156526048Sminshall 		code = -1;
156626048Sminshall 	(void) signal(SIGINT, oldintr);
156726048Sminshall }
156826048Sminshall 
156926048Sminshall reset()
157026048Sminshall {
157126496Sminshall 	struct fd_set mask;
157226496Sminshall 	int nfnd = 1;
157326048Sminshall 
157427687Sminshall 	FD_ZERO(&mask);
157530946Scsvsj 	while (nfnd > 0) {
157626496Sminshall 		FD_SET(fileno(cin), &mask);
157727687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
157826048Sminshall 			perror("reset");
157926048Sminshall 			code = -1;
158026048Sminshall 			lostpeer();
158126048Sminshall 		}
158227687Sminshall 		else if (nfnd) {
158326048Sminshall 			(void) getreply(0);
158426496Sminshall 		}
158526048Sminshall 	}
158626048Sminshall }
158726048Sminshall 
158826048Sminshall char *
158926048Sminshall gunique(local)
159026048Sminshall 	char *local;
159126048Sminshall {
159226048Sminshall 	static char new[MAXPATHLEN];
159326048Sminshall 	char *cp = rindex(local, '/');
159426048Sminshall 	int d, count=0;
159526048Sminshall 	char ext = '1';
159626048Sminshall 
159726448Slepreau 	if (cp)
159826048Sminshall 		*cp = '\0';
159926048Sminshall 	d = access(cp ? local : ".", 2);
160026448Slepreau 	if (cp)
160126048Sminshall 		*cp = '/';
160226048Sminshall 	if (d < 0) {
160326048Sminshall 		perror(local);
160426048Sminshall 		return((char *) 0);
160526048Sminshall 	}
160626048Sminshall 	(void) strcpy(new, local);
160726048Sminshall 	cp = new + strlen(new);
160826048Sminshall 	*cp++ = '.';
160926048Sminshall 	while (!d) {
161026048Sminshall 		if (++count == 100) {
161126048Sminshall 			printf("runique: can't find unique file name.\n");
161226048Sminshall 			return((char *) 0);
161326048Sminshall 		}
161426048Sminshall 		*cp++ = ext;
161526048Sminshall 		*cp = '\0';
161626448Slepreau 		if (ext == '9')
161726048Sminshall 			ext = '0';
161826448Slepreau 		else
161926048Sminshall 			ext++;
162026448Slepreau 		if ((d = access(new, 0)) < 0)
162126048Sminshall 			break;
162226448Slepreau 		if (ext != '0')
162326048Sminshall 			cp--;
162426448Slepreau 		else if (*(cp - 2) == '.')
162526048Sminshall 			*(cp - 1) = '1';
162626048Sminshall 		else {
162726048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
162826048Sminshall 			cp--;
162926048Sminshall 		}
163026048Sminshall 	}
163126048Sminshall 	return(new);
163226048Sminshall }
1633