xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 36935)
121739Sdist /*
226048Sminshall  * Copyright (c) 1985 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*36935Skarels  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621739Sdist  */
1721739Sdist 
1810296Ssam #ifndef lint
19*36935Skarels static char sccsid[] = "@(#)ftp.c	5.23 (Berkeley) 02/28/89";
2033737Sbostic #endif /* not lint */
2110296Ssam 
2226048Sminshall #include "ftp_var.h"
2326048Sminshall 
2410296Ssam #include <sys/stat.h>
2510296Ssam #include <sys/ioctl.h>
2610296Ssam #include <sys/socket.h>
2713614Ssam #include <sys/time.h>
2828469Skarels #include <sys/param.h>
29*36935Skarels #include <sys/file.h>
3010296Ssam 
3110296Ssam #include <netinet/in.h>
3212397Ssam #include <arpa/ftp.h>
3326048Sminshall #include <arpa/telnet.h>
3410296Ssam 
3510296Ssam #include <stdio.h>
3610296Ssam #include <signal.h>
3710296Ssam #include <errno.h>
3810296Ssam #include <netdb.h>
3926048Sminshall #include <fcntl.h>
4026048Sminshall #include <pwd.h>
4110296Ssam 
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*36935Skarels 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;
6825904Skarels 		(void) strcpy(hostnamebuf, host);
6926048Sminshall 	}
7026048Sminshall 	else {
7125100Sbloom 		hp = gethostbyname(host);
7225904Skarels 		if (hp == NULL) {
7335792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
7435792Sbostic 			herror((char *)NULL);
7526048Sminshall 			code = -1;
7626048Sminshall 			return((char *) 0);
7725904Skarels 		}
7825904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7925904Skarels 		bcopy(hp->h_addr_list[0],
8025904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8125904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
8210296Ssam 	}
8325904Skarels 	hostname = hostnamebuf;
8425904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8510296Ssam 	if (s < 0) {
8610296Ssam 		perror("ftp: socket");
8726048Sminshall 		code = -1;
8810296Ssam 		return (0);
8910296Ssam 	}
9010296Ssam 	hisctladdr.sin_port = port;
9126496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
9225904Skarels 		if (hp && hp->h_addr_list[1]) {
9325904Skarels 			int oerrno = errno;
9425904Skarels 
9525904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9625904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9725904Skarels 			errno = oerrno;
9826496Sminshall 			perror((char *) 0);
9925904Skarels 			hp->h_addr_list++;
10025904Skarels 			bcopy(hp->h_addr_list[0],
10126048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
10226496Sminshall 			fprintf(stdout, "Trying %s...\n",
10325904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10426813Skarels 			(void) close(s);
10526813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10626813Skarels 			if (s < 0) {
10726813Skarels 				perror("ftp: socket");
10826813Skarels 				code = -1;
10926813Skarels 				return (0);
11026813Skarels 			}
11125904Skarels 			continue;
11225904Skarels 		}
11310296Ssam 		perror("ftp: connect");
11426048Sminshall 		code = -1;
11510296Ssam 		goto bad;
11610296Ssam 	}
11711627Ssam 	len = sizeof (myctladdr);
11811627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
11911627Ssam 		perror("ftp: getsockname");
12026048Sminshall 		code = -1;
12110296Ssam 		goto bad;
12210296Ssam 	}
12310296Ssam 	cin = fdopen(s, "r");
12410296Ssam 	cout = fdopen(s, "w");
12511219Ssam 	if (cin == NULL || cout == NULL) {
12610296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12710296Ssam 		if (cin)
12826496Sminshall 			(void) fclose(cin);
12910296Ssam 		if (cout)
13026496Sminshall 			(void) fclose(cout);
13126048Sminshall 		code = -1;
13210296Ssam 		goto bad;
13310296Ssam 	}
13410296Ssam 	if (verbose)
13526067Sminshall 		printf("Connected to %s.\n", hostname);
13627687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13726048Sminshall 		if (cin)
13826496Sminshall 			(void) fclose(cin);
13926048Sminshall 		if (cout)
14026496Sminshall 			(void) fclose(cout);
14126048Sminshall 		code = -1;
14226048Sminshall 		goto bad;
14326048Sminshall 	}
14427687Sminshall #ifdef SO_OOBINLINE
14527687Sminshall 	{
14627687Sminshall 	int on = 1;
14726048Sminshall 
14827687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
14927687Sminshall 		< 0 && debug) {
15027687Sminshall 			perror("ftp: setsockopt");
15127687Sminshall 		}
15227687Sminshall 	}
15327687Sminshall #endif SO_OOBINLINE
15426048Sminshall 
15525904Skarels 	return (hostname);
15610296Ssam bad:
15726496Sminshall 	(void) close(s);
15825904Skarels 	return ((char *)0);
15910296Ssam }
16010296Ssam 
16125904Skarels login(host)
16225904Skarels 	char *host;
16310296Ssam {
16426048Sminshall 	char tmp[80];
16535659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16626048Sminshall 	int n, aflag = 0;
16710296Ssam 
16826048Sminshall 	user = pass = acct = 0;
16926048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
17026048Sminshall 		disconnect();
17126048Sminshall 		code = -1;
17226048Sminshall 		return(0);
17326048Sminshall 	}
17426048Sminshall 	if (user == NULL) {
17526048Sminshall 		char *myname = getlogin();
17626048Sminshall 
17726048Sminshall 		if (myname == NULL) {
17826048Sminshall 			struct passwd *pp = getpwuid(getuid());
17926048Sminshall 
18026448Slepreau 			if (pp != NULL)
18126048Sminshall 				myname = pp->pw_name;
18226048Sminshall 		}
18326048Sminshall 		printf("Name (%s:%s): ", host, myname);
18426048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18526048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18626448Slepreau 		if (*tmp == '\0')
18726048Sminshall 			user = myname;
18826448Slepreau 		else
18926048Sminshall 			user = tmp;
19026048Sminshall 	}
19110296Ssam 	n = command("USER %s", user);
19226048Sminshall 	if (n == CONTINUE) {
19326448Slepreau 		if (pass == NULL)
19435659Sbostic 			pass = getpass("Password:");
19510296Ssam 		n = command("PASS %s", pass);
19626048Sminshall 	}
19710296Ssam 	if (n == CONTINUE) {
19826048Sminshall 		aflag++;
19935659Sbostic 		acct = getpass("Account:");
20010296Ssam 		n = command("ACCT %s", acct);
20110296Ssam 	}
20210296Ssam 	if (n != COMPLETE) {
20310296Ssam 		fprintf(stderr, "Login failed.\n");
20410296Ssam 		return (0);
20510296Ssam 	}
20626448Slepreau 	if (!aflag && acct != NULL)
20726048Sminshall 		(void) command("ACCT %s", acct);
20826448Slepreau 	if (proxy)
20926048Sminshall 		return(1);
21026048Sminshall 	for (n = 0; n < macnum; ++n) {
21126048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21226496Sminshall 			(void) strcpy(line, "$init");
21326048Sminshall 			makeargv();
21426048Sminshall 			domacro(margc, margv);
21526048Sminshall 			break;
21626048Sminshall 		}
21726048Sminshall 	}
21810296Ssam 	return (1);
21910296Ssam }
22010296Ssam 
22126048Sminshall cmdabort()
22226048Sminshall {
22326048Sminshall 	extern jmp_buf ptabort;
22426048Sminshall 
22526048Sminshall 	printf("\n");
22626048Sminshall 	(void) fflush(stdout);
22726048Sminshall 	abrtflag++;
22826448Slepreau 	if (ptflag)
22926048Sminshall 		longjmp(ptabort,1);
23026048Sminshall }
23126048Sminshall 
23226496Sminshall /*VARARGS1*/
23310296Ssam command(fmt, args)
23410296Ssam 	char *fmt;
23510296Ssam {
23626048Sminshall 	int r, (*oldintr)(), cmdabort();
23710296Ssam 
23826048Sminshall 	abrtflag = 0;
23910296Ssam 	if (debug) {
24010296Ssam 		printf("---> ");
24110296Ssam 		_doprnt(fmt, &args, stdout);
24210296Ssam 		printf("\n");
24310296Ssam 		(void) fflush(stdout);
24410296Ssam 	}
24511219Ssam 	if (cout == NULL) {
24611219Ssam 		perror ("No control connection for command");
24726048Sminshall 		code = -1;
24811219Ssam 		return (0);
24911219Ssam 	}
25026048Sminshall 	oldintr = signal(SIGINT,cmdabort);
25110296Ssam 	_doprnt(fmt, &args, cout);
25210296Ssam 	fprintf(cout, "\r\n");
25310296Ssam 	(void) fflush(cout);
25426048Sminshall 	cpend = 1;
25526048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25626448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
25726048Sminshall 		(*oldintr)();
25826048Sminshall 	(void) signal(SIGINT, oldintr);
25926048Sminshall 	return(r);
26010296Ssam }
26110296Ssam 
262*36935Skarels char reply_string[BUFSIZ];
263*36935Skarels 
26410296Ssam #include <ctype.h>
26510296Ssam 
26610296Ssam getreply(expecteof)
26710296Ssam 	int expecteof;
26810296Ssam {
26911219Ssam 	register int c, n;
27026048Sminshall 	register int dig;
271*36935Skarels 	register char *cp;
27226048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
27326048Sminshall 	int pflag = 0;
27426048Sminshall 	char *pt = pasv;
27510296Ssam 
276*36935Skarels 	cp = reply_string;
27726048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27810296Ssam 	for (;;) {
27910296Ssam 		dig = n = code = 0;
28010296Ssam 		while ((c = getc(cin)) != '\n') {
28127687Sminshall 			if (c == IAC) {     /* handle telnet commands */
28227687Sminshall 				switch (c = getc(cin)) {
28327687Sminshall 				case WILL:
28427687Sminshall 				case WONT:
28527687Sminshall 					c = getc(cin);
28627687Sminshall 					fprintf(cout, "%c%c%c",IAC,WONT,c);
28727687Sminshall 					(void) fflush(cout);
28827687Sminshall 					break;
28927687Sminshall 				case DO:
29027687Sminshall 				case DONT:
29127687Sminshall 					c = getc(cin);
29227687Sminshall 					fprintf(cout, "%c%c%c",IAC,DONT,c);
29327687Sminshall 					(void) fflush(cout);
29427687Sminshall 					break;
29527687Sminshall 				default:
29627687Sminshall 					break;
29727687Sminshall 				}
29827687Sminshall 				continue;
29927687Sminshall 			}
30010296Ssam 			dig++;
30110296Ssam 			if (c == EOF) {
30226048Sminshall 				if (expecteof) {
30326048Sminshall 					(void) signal(SIGINT,oldintr);
30426048Sminshall 					code = 221;
30510296Ssam 					return (0);
30626048Sminshall 				}
30710296Ssam 				lostpeer();
30826048Sminshall 				if (verbose) {
30926048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
31026048Sminshall 					(void) fflush(stdout);
31126048Sminshall 				}
31233772Scsvsj 				code = 421;
31333772Scsvsj 				return(4);
31410296Ssam 			}
31526048Sminshall 			if (c != '\r' && (verbose > 0 ||
31626048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
31726448Slepreau 				if (proxflag &&
31826448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
31926048Sminshall 					printf("%s:",hostname);
32026496Sminshall 				(void) putchar(c);
32126048Sminshall 			}
32210296Ssam 			if (dig < 4 && isdigit(c))
32310296Ssam 				code = code * 10 + (c - '0');
32426448Slepreau 			if (!pflag && code == 227)
32526048Sminshall 				pflag = 1;
32626448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
32726048Sminshall 				pflag = 2;
32826048Sminshall 			if (pflag == 2) {
32926448Slepreau 				if (c != '\r' && c != ')')
33026048Sminshall 					*pt++ = c;
33126048Sminshall 				else {
33226048Sminshall 					*pt = '\0';
33326048Sminshall 					pflag = 3;
33426048Sminshall 				}
33526048Sminshall 			}
33626048Sminshall 			if (dig == 4 && c == '-') {
33726448Slepreau 				if (continuation)
33826048Sminshall 					code = 0;
33910296Ssam 				continuation++;
34026048Sminshall 			}
34110296Ssam 			if (n == 0)
34210296Ssam 				n = c;
343*36935Skarels 			*cp++ = c;
34410296Ssam 		}
34526048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
34626496Sminshall 			(void) putchar(c);
34711346Ssam 			(void) fflush (stdout);
34811346Ssam 		}
34910296Ssam 		if (continuation && code != originalcode) {
35010296Ssam 			if (originalcode == 0)
35110296Ssam 				originalcode = code;
35210296Ssam 			continue;
35310296Ssam 		}
354*36935Skarels 		*cp = '\0';
35526448Slepreau 		if (n != '1')
35626048Sminshall 			cpend = 0;
35726048Sminshall 		(void) signal(SIGINT,oldintr);
35826448Slepreau 		if (code == 421 || originalcode == 421)
35926048Sminshall 			lostpeer();
36026448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
36126048Sminshall 			(*oldintr)();
36225907Smckusick 		return (n - '0');
36310296Ssam 	}
36410296Ssam }
36510296Ssam 
36626048Sminshall empty(mask, sec)
36727687Sminshall 	struct fd_set *mask;
36826048Sminshall 	int sec;
36926048Sminshall {
37026048Sminshall 	struct timeval t;
37126048Sminshall 
37226048Sminshall 	t.tv_sec = (long) sec;
37326048Sminshall 	t.tv_usec = 0;
37427687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
37526048Sminshall }
37626048Sminshall 
37710296Ssam jmp_buf	sendabort;
37810296Ssam 
37910296Ssam abortsend()
38010296Ssam {
38110296Ssam 
38226048Sminshall 	mflag = 0;
38326048Sminshall 	abrtflag = 0;
38426048Sminshall 	printf("\nsend aborted\n");
38526048Sminshall 	(void) fflush(stdout);
38610296Ssam 	longjmp(sendabort, 1);
38710296Ssam }
38810296Ssam 
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();
39511219Ssam 	char buf[BUFSIZ];
39611651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
39711346Ssam 	register int c, d;
39810296Ssam 	struct stat st;
39910296Ssam 	struct timeval start, stop;
400*36935Skarels 	char *mode;
40110296Ssam 
40226048Sminshall 	if (proxy) {
40326048Sminshall 		proxtrans(cmd, local, remote);
40426048Sminshall 		return;
40526048Sminshall 	}
40610296Ssam 	closefunc = NULL;
40726048Sminshall 	oldintr = NULL;
40826048Sminshall 	oldintp = NULL;
409*36935Skarels 	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);
452*36935Skarels 			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;
462*36935Skarels 		if (closefunc != NULL)
463*36935Skarels 			(*closefunc)(fin);
46426048Sminshall 		return;
46526048Sminshall 	}
46626448Slepreau 	if (setjmp(sendabort))
46726048Sminshall 		goto abort;
468*36935Skarels 
469*36935Skarels 	if (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0) {
470*36935Skarels 		if (restart_point) {
471*36935Skarels 			if (fseek(fin, (long) restart_point, 0) < 0) {
472*36935Skarels 				perror(local);
473*36935Skarels 				restart_point = 0;
474*36935Skarels 				if (closefunc != NULL)
475*36935Skarels 					(*closefunc)(fin);
476*36935Skarels 				return;
477*36935Skarels 			}
478*36935Skarels 			if (command("REST %ld", (long) restart_point)
479*36935Skarels 				!= CONTINUE) {
480*36935Skarels 				restart_point = 0;
481*36935Skarels 				if (closefunc != NULL)
482*36935Skarels 					(*closefunc)(fin);
483*36935Skarels 				return;
484*36935Skarels 			}
485*36935Skarels 			restart_point = 0;
486*36935Skarels 			mode = "r+w";
487*36935Skarels 		}
488*36935Skarels 	}
48910296Ssam 	if (remote) {
49026048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
49126048Sminshall 			(void) signal(SIGINT, oldintr);
49226448Slepreau 			if (oldintp)
49326048Sminshall 				(void) signal(SIGPIPE, oldintp);
494*36935Skarels 			if (closefunc != NULL)
495*36935Skarels 				(*closefunc)(fin);
49626048Sminshall 			return;
49726048Sminshall 		}
49810296Ssam 	} else
49926048Sminshall 		if (command("%s", cmd) != PRELIM) {
50026048Sminshall 			(void) signal(SIGINT, oldintr);
50126448Slepreau 			if (oldintp)
50226048Sminshall 				(void) signal(SIGPIPE, oldintp);
503*36935Skarels 			if (closefunc != NULL)
504*36935Skarels 				(*closefunc)(fin);
50526048Sminshall 			return;
50626048Sminshall 		}
507*36935Skarels 	dout = dataconn(mode);
50826448Slepreau 	if (dout == NULL)
50926048Sminshall 		goto abort;
51026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
511*36935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
51211219Ssam 	switch (type) {
51311219Ssam 
51411219Ssam 	case TYPE_I:
51511219Ssam 	case TYPE_L:
51611346Ssam 		errno = d = 0;
51711219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
518*36935Skarels 			if ((d = write(fileno (dout), buf, c)) != c)
51911219Ssam 				break;
52011219Ssam 			bytes += c;
52111651Ssam 			if (hash) {
52226496Sminshall 				(void) putchar('#');
52326496Sminshall 				(void) fflush(stdout);
52411651Ssam 			}
52511219Ssam 		}
52613213Ssam 		if (hash && bytes > 0) {
52726496Sminshall 			(void) putchar('\n');
52826496Sminshall 			(void) fflush(stdout);
52911651Ssam 		}
53011219Ssam 		if (c < 0)
53111219Ssam 			perror(local);
532*36935Skarels 		if (d < 0) {
533*36935Skarels 			if (errno != EPIPE)
534*36935Skarels 				perror("netout");
535*36935Skarels 			bytes = -1;
536*36935Skarels 		}
53711219Ssam 		break;
53811219Ssam 
53911219Ssam 	case TYPE_A:
54011219Ssam 		while ((c = getc(fin)) != EOF) {
54111219Ssam 			if (c == '\n') {
54211651Ssam 				while (hash && (bytes >= hashbytes)) {
54326496Sminshall 					(void) putchar('#');
54426496Sminshall 					(void) fflush(stdout);
54511651Ssam 					hashbytes += sizeof (buf);
54611651Ssam 				}
54711219Ssam 				if (ferror(dout))
54811219Ssam 					break;
54926496Sminshall 				(void) putc('\r', dout);
55011219Ssam 				bytes++;
55111219Ssam 			}
55226496Sminshall 			(void) putc(c, dout);
55311219Ssam 			bytes++;
55426048Sminshall 	/*		if (c == '\r') {			  	*/
55526496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
55626048Sminshall 	/*			bytes++;				*/
55726048Sminshall 	/*		}                          			*/
55811219Ssam 		}
55911651Ssam 		if (hash) {
56013213Ssam 			if (bytes < hashbytes)
56126496Sminshall 				(void) putchar('#');
56226496Sminshall 			(void) putchar('\n');
56326496Sminshall 			(void) fflush(stdout);
56411651Ssam 		}
56511219Ssam 		if (ferror(fin))
56611219Ssam 			perror(local);
567*36935Skarels 		if (ferror(dout)) {
568*36935Skarels 			if (errno != EPIPE)
569*36935Skarels 				perror("netout");
570*36935Skarels 			bytes = -1;
571*36935Skarels 		}
57211219Ssam 		break;
57310296Ssam 	}
57426496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
57510296Ssam 	if (closefunc != NULL)
57626048Sminshall 		(*closefunc)(fin);
57710296Ssam 	(void) fclose(dout);
57826048Sminshall 	(void) getreply(0);
57926048Sminshall 	(void) signal(SIGINT, oldintr);
580*36935Skarels 	if (oldintp)
581*36935Skarels 		(void) signal(SIGPIPE, oldintp);
58235699Sbostic 	if (bytes > 0)
58326048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
58410296Ssam 	return;
58526048Sminshall abort:
58626496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
58726048Sminshall 	(void) signal(SIGINT, oldintr);
58826448Slepreau 	if (oldintp)
58926048Sminshall 		(void) signal(SIGPIPE, oldintp);
59026048Sminshall 	if (!cpend) {
59126048Sminshall 		code = -1;
59226048Sminshall 		return;
59326048Sminshall 	}
59426048Sminshall 	if (data >= 0) {
59526048Sminshall 		(void) close(data);
59626048Sminshall 		data = -1;
59726048Sminshall 	}
59826448Slepreau 	if (dout)
59926048Sminshall 		(void) fclose(dout);
60026048Sminshall 	(void) getreply(0);
60126048Sminshall 	code = -1;
60210296Ssam 	if (closefunc != NULL && fin != NULL)
60326048Sminshall 		(*closefunc)(fin);
60435699Sbostic 	if (bytes > 0)
60526048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
60610296Ssam }
60710296Ssam 
60810296Ssam jmp_buf	recvabort;
60910296Ssam 
61010296Ssam abortrecv()
61110296Ssam {
61210296Ssam 
61326048Sminshall 	mflag = 0;
61426048Sminshall 	abrtflag = 0;
61526048Sminshall 	printf("\n");
61626048Sminshall 	(void) fflush(stdout);
61710296Ssam 	longjmp(recvabort, 1);
61810296Ssam }
61910296Ssam 
62011651Ssam recvrequest(cmd, local, remote, mode)
62111651Ssam 	char *cmd, *local, *remote, *mode;
62210296Ssam {
62335659Sbostic 	FILE *fout, *din = 0, *popen();
62435659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
625*36935Skarels 	int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd;
62627687Sminshall 	char buf[BUFSIZ], *gunique(), msg;
62726496Sminshall 	long bytes = 0, hashbytes = sizeof (buf);
62826496Sminshall 	struct fd_set mask;
62911346Ssam 	register int c, d;
63010296Ssam 	struct timeval start, stop;
63110296Ssam 
632*36935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
633*36935Skarels 	if (proxy && is_retr) {
63426048Sminshall 		proxtrans(cmd, local, remote);
63526048Sminshall 		return;
63626048Sminshall 	}
63710296Ssam 	closefunc = NULL;
63826048Sminshall 	oldintr = NULL;
63926048Sminshall 	oldintp = NULL;
640*36935Skarels 	tcrflag = !crflag && is_retr;
64126048Sminshall 	if (setjmp(recvabort)) {
64226048Sminshall 		while (cpend) {
64326048Sminshall 			(void) getreply(0);
64426048Sminshall 		}
64526048Sminshall 		if (data >= 0) {
64626048Sminshall 			(void) close(data);
64726048Sminshall 			data = -1;
64826048Sminshall 		}
64926448Slepreau 		if (oldintr)
65026048Sminshall 			(void) signal(SIGINT, oldintr);
65126048Sminshall 		code = -1;
65226048Sminshall 		return;
65326048Sminshall 	}
65410296Ssam 	oldintr = signal(SIGINT, abortrecv);
65526048Sminshall 	if (strcmp(local, "-") && *local != '|') {
65610296Ssam 		if (access(local, 2) < 0) {
65726048Sminshall 			char *dir = rindex(local, '/');
65810296Ssam 
65926048Sminshall 			if (errno != ENOENT && errno != EACCES) {
66010296Ssam 				perror(local);
66126048Sminshall 				(void) signal(SIGINT, oldintr);
66226048Sminshall 				code = -1;
66326048Sminshall 				return;
66410296Ssam 			}
66526048Sminshall 			if (dir != NULL)
66626048Sminshall 				*dir = 0;
66726048Sminshall 			d = access(dir ? local : ".", 2);
66826048Sminshall 			if (dir != NULL)
66926048Sminshall 				*dir = '/';
67026048Sminshall 			if (d < 0) {
67126048Sminshall 				perror(local);
67226048Sminshall 				(void) signal(SIGINT, oldintr);
67326048Sminshall 				code = -1;
67426048Sminshall 				return;
67526048Sminshall 			}
67626048Sminshall 			if (!runique && errno == EACCES &&
677*36935Skarels 			    chmod(local, 0600) < 0) {
67826048Sminshall 				perror(local);
67926048Sminshall 				(void) signal(SIGINT, oldintr);
68026048Sminshall 				code = -1;
68126048Sminshall 				return;
68226048Sminshall 			}
68326048Sminshall 			if (runique && errno == EACCES &&
68426048Sminshall 			   (local = gunique(local)) == NULL) {
68526048Sminshall 				(void) signal(SIGINT, oldintr);
68626048Sminshall 				code = -1;
68726048Sminshall 				return;
68826048Sminshall 			}
68910296Ssam 		}
69026048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
69126048Sminshall 			(void) signal(SIGINT, oldintr);
69226048Sminshall 			code = -1;
69326048Sminshall 			return;
69426048Sminshall 		}
69526048Sminshall 	}
69626048Sminshall 	if (initconn()) {
69726048Sminshall 		(void) signal(SIGINT, oldintr);
69826048Sminshall 		code = -1;
69926048Sminshall 		return;
70026048Sminshall 	}
70126448Slepreau 	if (setjmp(recvabort))
70226048Sminshall 		goto abort;
703*36935Skarels 	if (!is_retr) {
704*36935Skarels 		if (type != TYPE_A) {
705*36935Skarels 			oldtype = type;
706*36935Skarels 			oldverbose = verbose;
707*36935Skarels 			if (!debug)
708*36935Skarels 				verbose = 0;
709*36935Skarels 			setascii();
710*36935Skarels 			verbose = oldverbose;
711*36935Skarels 		}
712*36935Skarels 	} else if (restart_point) {
713*36935Skarels 		if (command("REST %ld", (long) restart_point) != CONTINUE)
714*36935Skarels 			return;
71526048Sminshall 	}
71610296Ssam 	if (remote) {
71726048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
71826048Sminshall 			(void) signal(SIGINT, oldintr);
71926048Sminshall 			if (oldtype) {
72026448Slepreau 				if (!debug)
72126048Sminshall 					verbose = 0;
72226048Sminshall 				switch (oldtype) {
72326048Sminshall 					case TYPE_I:
72426048Sminshall 						setbinary();
72526048Sminshall 						break;
72626048Sminshall 					case TYPE_E:
72726048Sminshall 						setebcdic();
72826048Sminshall 						break;
72926048Sminshall 					case TYPE_L:
73026048Sminshall 						settenex();
73126048Sminshall 						break;
732*36935Skarels 					}
73326048Sminshall 				verbose = oldverbose;
73426048Sminshall 			}
73526048Sminshall 			return;
73626048Sminshall 		}
73726048Sminshall 	} else {
73826048Sminshall 		if (command("%s", cmd) != PRELIM) {
73926048Sminshall 			(void) signal(SIGINT, oldintr);
74026048Sminshall 			if (oldtype) {
74126448Slepreau 				if (!debug)
74226048Sminshall 					verbose = 0;
74326048Sminshall 				switch (oldtype) {
74426048Sminshall 					case TYPE_I:
74526048Sminshall 						setbinary();
74626048Sminshall 						break;
74726048Sminshall 					case TYPE_E:
74826048Sminshall 						setebcdic();
74926048Sminshall 						break;
75026048Sminshall 					case TYPE_L:
75126048Sminshall 						settenex();
75226048Sminshall 						break;
753*36935Skarels 					}
75426048Sminshall 				verbose = oldverbose;
75526048Sminshall 			}
75626048Sminshall 			return;
75726048Sminshall 		}
75826048Sminshall 	}
75926048Sminshall 	din = dataconn("r");
76026048Sminshall 	if (din == NULL)
76126048Sminshall 		goto abort;
76226448Slepreau 	if (strcmp(local, "-") == 0)
76310296Ssam 		fout = stdout;
76410296Ssam 	else if (*local == '|') {
76526048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
76635659Sbostic 		fout = popen(local + 1, "w");
76726048Sminshall 		if (fout == NULL) {
76826048Sminshall 			perror(local+1);
76926048Sminshall 			goto abort;
77026048Sminshall 		}
77135659Sbostic 		closefunc = pclose;
77226048Sminshall 	}
77326048Sminshall 	else {
77411651Ssam 		fout = fopen(local, mode);
77526048Sminshall 		if (fout == NULL) {
77626048Sminshall 			perror(local);
77726048Sminshall 			goto abort;
77826048Sminshall 		}
77910296Ssam 		closefunc = fclose;
78010296Ssam 	}
78126496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
78211219Ssam 	switch (type) {
78311219Ssam 
78411219Ssam 	case TYPE_I:
78511219Ssam 	case TYPE_L:
786*36935Skarels 		if (restart_point &&
787*36935Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
788*36935Skarels 			perror(local);
789*36935Skarels 			if (closefunc != NULL)
790*36935Skarels 				(*closefunc)(fout);
791*36935Skarels 			return;
792*36935Skarels 		}
79311346Ssam 		errno = d = 0;
79411219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
795*36935Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
79611219Ssam 				break;
79711219Ssam 			bytes += c;
79811651Ssam 			if (hash) {
79926496Sminshall 				(void) putchar('#');
80026496Sminshall 				(void) fflush(stdout);
80111651Ssam 			}
80211219Ssam 		}
80313213Ssam 		if (hash && bytes > 0) {
80426496Sminshall 			(void) putchar('\n');
80526496Sminshall 			(void) fflush(stdout);
80611651Ssam 		}
807*36935Skarels 		if (c < 0) {
808*36935Skarels 			if (errno != EPIPE)
809*36935Skarels 				perror("netin");
810*36935Skarels 			bytes = -1;
811*36935Skarels 		}
81211346Ssam 		if (d < 0)
81310296Ssam 			perror(local);
81411219Ssam 		break;
81511219Ssam 
81611219Ssam 	case TYPE_A:
817*36935Skarels 		if (restart_point) {
818*36935Skarels 			register int i, n, c;
819*36935Skarels 			if (fseek(fout, 0L, L_SET) < 0)
820*36935Skarels 				goto done;
821*36935Skarels 			n = restart_point;
822*36935Skarels 			i = 0;
823*36935Skarels 			while(i++ < n) {
824*36935Skarels 				if ((c=getc(fout)) == EOF)
825*36935Skarels 					goto done;
826*36935Skarels 				if (c == '\n')
827*36935Skarels 					i++;
828*36935Skarels 			}
829*36935Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
830*36935Skarels done:
831*36935Skarels 				perror(local);
832*36935Skarels 				if (closefunc != NULL)
833*36935Skarels 					(*closefunc)(fout);
834*36935Skarels 				return;
835*36935Skarels 			}
836*36935Skarels 		}
83711219Ssam 		while ((c = getc(din)) != EOF) {
83827749Sminshall 			while (c == '\r') {
83911651Ssam 				while (hash && (bytes >= hashbytes)) {
84026496Sminshall 					(void) putchar('#');
84126496Sminshall 					(void) fflush(stdout);
84211651Ssam 					hashbytes += sizeof (buf);
84311651Ssam 				}
84410296Ssam 				bytes++;
84526048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
84611219Ssam 					if (ferror (fout))
84711219Ssam 						break;
84826496Sminshall 					(void) putc ('\r', fout);
84911219Ssam 				}
85011219Ssam 			}
85126496Sminshall 			(void) putc (c, fout);
85211219Ssam 			bytes++;
85310296Ssam 		}
85411651Ssam 		if (hash) {
85513213Ssam 			if (bytes < hashbytes)
85626496Sminshall 				(void) putchar('#');
85726496Sminshall 			(void) putchar('\n');
85826496Sminshall 			(void) fflush(stdout);
85911651Ssam 		}
860*36935Skarels 		if (ferror (din)){
861*36935Skarels 			if (errno != EPIPE)
862*36935Skarels 				perror ("netin");
863*36935Skarels 			bytes = -1;
864*36935Skarels 		}
86511219Ssam 		if (ferror (fout))
86611219Ssam 			perror (local);
86711219Ssam 		break;
86810296Ssam 	}
86926448Slepreau 	if (closefunc != NULL)
87026048Sminshall 		(*closefunc)(fout);
87126496Sminshall 	(void) signal(SIGINT, oldintr);
87226448Slepreau 	if (oldintp)
87326048Sminshall 		(void) signal(SIGPIPE, oldintp);
87426496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
87510296Ssam 	(void) fclose(din);
87626048Sminshall 	(void) getreply(0);
877*36935Skarels 	if (bytes > 0 && is_retr)
87826048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
87926048Sminshall 	if (oldtype) {
88026448Slepreau 		if (!debug)
88126048Sminshall 			verbose = 0;
88226048Sminshall 		switch (oldtype) {
88326048Sminshall 			case TYPE_I:
88426048Sminshall 				setbinary();
88526048Sminshall 				break;
88626048Sminshall 			case TYPE_E:
88726048Sminshall 				setebcdic();
88826048Sminshall 				break;
88926048Sminshall 			case TYPE_L:
89026048Sminshall 				settenex();
89126048Sminshall 				break;
89226048Sminshall 		}
89326048Sminshall 		verbose = oldverbose;
89426048Sminshall 	}
89526048Sminshall 	return;
89626048Sminshall abort:
89726048Sminshall 
89827687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
89926048Sminshall 
90026496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
90126448Slepreau 	if (oldintp)
90226048Sminshall 		(void) signal(SIGPIPE, oldintr);
90326048Sminshall 	(void) signal(SIGINT,SIG_IGN);
90426048Sminshall 	if (oldtype) {
90526448Slepreau 		if (!debug)
90626048Sminshall 			verbose = 0;
90726048Sminshall 		switch (oldtype) {
90826048Sminshall 			case TYPE_I:
90926048Sminshall 				setbinary();
91026048Sminshall 				break;
91126048Sminshall 			case TYPE_E:
91226048Sminshall 				setebcdic();
91326048Sminshall 				break;
91426048Sminshall 			case TYPE_L:
91526048Sminshall 				settenex();
91626048Sminshall 				break;
91726048Sminshall 		}
91826048Sminshall 		verbose = oldverbose;
91926048Sminshall 	}
92026048Sminshall 	if (!cpend) {
92126048Sminshall 		code = -1;
92226048Sminshall 		(void) signal(SIGINT,oldintr);
92326048Sminshall 		return;
92426048Sminshall 	}
92526048Sminshall 
92627687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
92727687Sminshall 	(void) fflush(cout);
92827687Sminshall 	msg = IAC;
92927687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
93027687Sminshall /* after urgent byte rather than before as now is protocol            */
93127687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
93227687Sminshall 		perror("abort");
93326048Sminshall 	}
93427687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
93526048Sminshall 	(void) fflush(cout);
93627687Sminshall 	FD_ZERO(&mask);
93726496Sminshall 	FD_SET(fileno(cin), &mask);
93826496Sminshall 	if (din) {
93926496Sminshall 		FD_SET(fileno(din), &mask);
94026496Sminshall 	}
94127687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
94227687Sminshall 		if (nfnd < 0) {
94327687Sminshall 			perror("abort");
94427687Sminshall 		}
94526048Sminshall 		code = -1;
94626048Sminshall 		lostpeer();
94726048Sminshall 	}
94826496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
94926448Slepreau 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0)
95026448Slepreau 			;
95126496Sminshall 	}
95227687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
95326048Sminshall 		if (data >= 0) {
95426496Sminshall 			(void) close(data);
95526048Sminshall 			data = -1;
95626048Sminshall 		}
95725907Smckusick 		(void) getreply(0);
95825907Smckusick 	}
95926048Sminshall 	(void) getreply(0);
96026048Sminshall 	code = -1;
96126048Sminshall 	if (data >= 0) {
96226048Sminshall 		(void) close(data);
96326048Sminshall 		data = -1;
96426048Sminshall 	}
96526448Slepreau 	if (closefunc != NULL && fout != NULL)
96626048Sminshall 		(*closefunc)(fout);
96726448Slepreau 	if (din)
96826048Sminshall 		(void) fclose(din);
96935699Sbostic 	if (bytes > 0)
97026048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
97126048Sminshall 	(void) signal(SIGINT,oldintr);
97210296Ssam }
97310296Ssam 
97410296Ssam /*
97510296Ssam  * Need to start a listen on the data channel
97610296Ssam  * before we send the command, otherwise the
97710296Ssam  * server's connect may fail.
97810296Ssam  */
97933224Sbostic int sendport = -1;
98011651Ssam 
98110296Ssam initconn()
98210296Ssam {
98310296Ssam 	register char *p, *a;
98426048Sminshall 	int result, len, tmpno = 0;
98526993Skarels 	int on = 1;
98610296Ssam 
98711651Ssam noport:
98810296Ssam 	data_addr = myctladdr;
98911651Ssam 	if (sendport)
99011651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
99111651Ssam 	if (data != -1)
99211651Ssam 		(void) close (data);
99318287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
99410296Ssam 	if (data < 0) {
99510296Ssam 		perror("ftp: socket");
99626448Slepreau 		if (tmpno)
99726048Sminshall 			sendport = 1;
99810296Ssam 		return (1);
99910296Ssam 	}
100012397Ssam 	if (!sendport)
100127687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
100233224Sbostic 			perror("ftp: setsockopt (reuse address)");
100312397Ssam 			goto bad;
100412397Ssam 		}
100526496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
100610296Ssam 		perror("ftp: bind");
100710296Ssam 		goto bad;
100810296Ssam 	}
100910296Ssam 	if (options & SO_DEBUG &&
101027687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
101110296Ssam 		perror("ftp: setsockopt (ignored)");
101211627Ssam 	len = sizeof (data_addr);
101311627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
101411627Ssam 		perror("ftp: getsockname");
101510296Ssam 		goto bad;
101610296Ssam 	}
101726448Slepreau 	if (listen(data, 1) < 0)
101810296Ssam 		perror("ftp: listen");
101911651Ssam 	if (sendport) {
102011651Ssam 		a = (char *)&data_addr.sin_addr;
102111651Ssam 		p = (char *)&data_addr.sin_port;
102210296Ssam #define	UC(b)	(((int)b)&0xff)
102311651Ssam 		result =
102411651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
102511651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
102611651Ssam 		      UC(p[0]), UC(p[1]));
102711651Ssam 		if (result == ERROR && sendport == -1) {
102811651Ssam 			sendport = 0;
102926048Sminshall 			tmpno = 1;
103011651Ssam 			goto noport;
103111651Ssam 		}
103211651Ssam 		return (result != COMPLETE);
103311651Ssam 	}
103426448Slepreau 	if (tmpno)
103526048Sminshall 		sendport = 1;
103611651Ssam 	return (0);
103710296Ssam bad:
103810296Ssam 	(void) close(data), data = -1;
103926448Slepreau 	if (tmpno)
104026048Sminshall 		sendport = 1;
104110296Ssam 	return (1);
104210296Ssam }
104310296Ssam 
104410296Ssam FILE *
104510296Ssam dataconn(mode)
104610296Ssam 	char *mode;
104710296Ssam {
104810296Ssam 	struct sockaddr_in from;
104910296Ssam 	int s, fromlen = sizeof (from);
105010296Ssam 
105126496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
105210296Ssam 	if (s < 0) {
105310296Ssam 		perror("ftp: accept");
105410296Ssam 		(void) close(data), data = -1;
105510296Ssam 		return (NULL);
105610296Ssam 	}
105710296Ssam 	(void) close(data);
105810296Ssam 	data = s;
105910296Ssam 	return (fdopen(data, mode));
106010296Ssam }
106110296Ssam 
106226048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
106326048Sminshall 	char *direction, *local, *remote;
106411651Ssam 	long bytes;
106510296Ssam 	struct timeval *t0, *t1;
106610296Ssam {
106710296Ssam 	struct timeval td;
106816437Sleres 	float s, bs;
106910296Ssam 
107035699Sbostic 	if (verbose) {
107135699Sbostic 		tvsub(&td, t1, t0);
107235699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
107310296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
107435699Sbostic 		bs = bytes / nz(s);
107535699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
107635699Sbostic 		    bytes, direction, s, bs / 1024.);
107735699Sbostic 	} else {
107835699Sbostic 		if (local && *local != '-')
107935699Sbostic 			printf("local: %s ", local);
108035699Sbostic 		if (remote)
108135699Sbostic 			printf("remote: %s\n", remote);
108235699Sbostic 	}
108310296Ssam }
108410296Ssam 
108526496Sminshall /*tvadd(tsum, t0)
108610296Ssam 	struct timeval *tsum, *t0;
108710296Ssam {
108810296Ssam 
108910296Ssam 	tsum->tv_sec += t0->tv_sec;
109010296Ssam 	tsum->tv_usec += t0->tv_usec;
109110296Ssam 	if (tsum->tv_usec > 1000000)
109210296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
109326496Sminshall } */
109410296Ssam 
109510296Ssam tvsub(tdiff, t1, t0)
109610296Ssam 	struct timeval *tdiff, *t1, *t0;
109710296Ssam {
109810296Ssam 
109910296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
110010296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
110110296Ssam 	if (tdiff->tv_usec < 0)
110210296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
110310296Ssam }
110426048Sminshall 
110526048Sminshall psabort()
110626048Sminshall {
110726048Sminshall 	extern int abrtflag;
110826048Sminshall 
110926048Sminshall 	abrtflag++;
111026048Sminshall }
111126048Sminshall 
111226048Sminshall pswitch(flag)
111326048Sminshall 	int flag;
111426048Sminshall {
111526048Sminshall 	extern int proxy, abrtflag;
111626048Sminshall 	int (*oldintr)();
111726048Sminshall 	static struct comvars {
111826048Sminshall 		int connect;
111928469Skarels 		char name[MAXHOSTNAMELEN];
112026048Sminshall 		struct sockaddr_in mctl;
112126048Sminshall 		struct sockaddr_in hctl;
112226048Sminshall 		FILE *in;
112326048Sminshall 		FILE *out;
112426048Sminshall 		int tpe;
112526048Sminshall 		int cpnd;
112626048Sminshall 		int sunqe;
112726048Sminshall 		int runqe;
112826048Sminshall 		int mcse;
112926048Sminshall 		int ntflg;
113026048Sminshall 		char nti[17];
113126048Sminshall 		char nto[17];
113226048Sminshall 		int mapflg;
113326048Sminshall 		char mi[MAXPATHLEN];
113426048Sminshall 		char mo[MAXPATHLEN];
113526048Sminshall 		} proxstruct, tmpstruct;
113626048Sminshall 	struct comvars *ip, *op;
113726048Sminshall 
113826048Sminshall 	abrtflag = 0;
113926048Sminshall 	oldintr = signal(SIGINT, psabort);
114026048Sminshall 	if (flag) {
114126448Slepreau 		if (proxy)
114226048Sminshall 			return;
114326048Sminshall 		ip = &tmpstruct;
114426048Sminshall 		op = &proxstruct;
114526048Sminshall 		proxy++;
114626048Sminshall 	}
114726048Sminshall 	else {
114826448Slepreau 		if (!proxy)
114926048Sminshall 			return;
115026048Sminshall 		ip = &proxstruct;
115126048Sminshall 		op = &tmpstruct;
115226048Sminshall 		proxy = 0;
115326048Sminshall 	}
115426048Sminshall 	ip->connect = connected;
115526048Sminshall 	connected = op->connect;
115628469Skarels 	if (hostname) {
115728469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
115828469Skarels 		ip->name[strlen(ip->name)] = '\0';
115928469Skarels 	} else
116028469Skarels 		ip->name[0] = 0;
116126048Sminshall 	hostname = op->name;
116226048Sminshall 	ip->hctl = hisctladdr;
116326048Sminshall 	hisctladdr = op->hctl;
116426048Sminshall 	ip->mctl = myctladdr;
116526048Sminshall 	myctladdr = op->mctl;
116626048Sminshall 	ip->in = cin;
116726048Sminshall 	cin = op->in;
116826048Sminshall 	ip->out = cout;
116926048Sminshall 	cout = op->out;
117026048Sminshall 	ip->tpe = type;
117126048Sminshall 	type = op->tpe;
117226448Slepreau 	if (!type)
117326048Sminshall 		type = 1;
117426048Sminshall 	ip->cpnd = cpend;
117526048Sminshall 	cpend = op->cpnd;
117626048Sminshall 	ip->sunqe = sunique;
117726048Sminshall 	sunique = op->sunqe;
117826048Sminshall 	ip->runqe = runique;
117926048Sminshall 	runique = op->runqe;
118026048Sminshall 	ip->mcse = mcase;
118126048Sminshall 	mcase = op->mcse;
118226048Sminshall 	ip->ntflg = ntflag;
118326048Sminshall 	ntflag = op->ntflg;
118426496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
118526048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
118626496Sminshall 	(void) strcpy(ntin, op->nti);
118726496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
118826048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
118926496Sminshall 	(void) strcpy(ntout, op->nto);
119026048Sminshall 	ip->mapflg = mapflag;
119126048Sminshall 	mapflag = op->mapflg;
119226496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
119326048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
119426496Sminshall 	(void) strcpy(mapin, op->mi);
119526496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
119626048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
119726496Sminshall 	(void) strcpy(mapout, op->mo);
119826048Sminshall 	(void) signal(SIGINT, oldintr);
119926048Sminshall 	if (abrtflag) {
120026048Sminshall 		abrtflag = 0;
120126048Sminshall 		(*oldintr)();
120226448Slepreau 	}
120326048Sminshall }
120426048Sminshall 
120526048Sminshall jmp_buf ptabort;
120626048Sminshall int ptabflg;
120726048Sminshall 
120826048Sminshall abortpt()
120926048Sminshall {
121026048Sminshall 	printf("\n");
121126496Sminshall 	(void) fflush(stdout);
121226048Sminshall 	ptabflg++;
121326048Sminshall 	mflag = 0;
121426048Sminshall 	abrtflag = 0;
121526048Sminshall 	longjmp(ptabort, 1);
121626048Sminshall }
121726048Sminshall 
121826048Sminshall proxtrans(cmd, local, remote)
121926048Sminshall 	char *cmd, *local, *remote;
122026048Sminshall {
122127687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
122226048Sminshall 	extern jmp_buf ptabort;
122326048Sminshall 	char *cmd2;
122426496Sminshall 	struct fd_set mask;
122526048Sminshall 
122626448Slepreau 	if (strcmp(cmd, "RETR"))
122726048Sminshall 		cmd2 = "RETR";
122826448Slepreau 	else
122926048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
123026048Sminshall 	if (command("PASV") != COMPLETE) {
123126048Sminshall 		printf("proxy server does not support third part transfers.\n");
123226048Sminshall 		return;
123326048Sminshall 	}
123426048Sminshall 	tmptype = type;
123526048Sminshall 	pswitch(0);
123626048Sminshall 	if (!connected) {
123726048Sminshall 		printf("No primary connection\n");
123826048Sminshall 		pswitch(1);
123926048Sminshall 		code = -1;
124026048Sminshall 		return;
124126048Sminshall 	}
124226048Sminshall 	if (type != tmptype) {
124326048Sminshall 		oldtype = type;
124426048Sminshall 		switch (tmptype) {
124526048Sminshall 			case TYPE_A:
124626048Sminshall 				setascii();
124726048Sminshall 				break;
124826048Sminshall 			case TYPE_I:
124926048Sminshall 				setbinary();
125026048Sminshall 				break;
125126048Sminshall 			case TYPE_E:
125226048Sminshall 				setebcdic();
125326048Sminshall 				break;
125426048Sminshall 			case TYPE_L:
125526048Sminshall 				settenex();
125626048Sminshall 				break;
125726048Sminshall 		}
125826048Sminshall 	}
125926048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
126026048Sminshall 		switch (oldtype) {
126126048Sminshall 			case 0:
126226048Sminshall 				break;
126326048Sminshall 			case TYPE_A:
126426048Sminshall 				setascii();
126526048Sminshall 				break;
126626048Sminshall 			case TYPE_I:
126726048Sminshall 				setbinary();
126826048Sminshall 				break;
126926048Sminshall 			case TYPE_E:
127026048Sminshall 				setebcdic();
127126048Sminshall 				break;
127226048Sminshall 			case TYPE_L:
127326048Sminshall 				settenex();
127426048Sminshall 				break;
127526048Sminshall 		}
127626048Sminshall 		pswitch(1);
127726048Sminshall 		return;
127826048Sminshall 	}
127926448Slepreau 	if (setjmp(ptabort))
128026048Sminshall 		goto abort;
128126048Sminshall 	oldintr = signal(SIGINT, abortpt);
128226048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
128326048Sminshall 		(void) signal(SIGINT, oldintr);
128426048Sminshall 		switch (oldtype) {
128526048Sminshall 			case 0:
128626048Sminshall 				break;
128726048Sminshall 			case TYPE_A:
128826048Sminshall 				setascii();
128926048Sminshall 				break;
129026048Sminshall 			case TYPE_I:
129126048Sminshall 				setbinary();
129226048Sminshall 				break;
129326048Sminshall 			case TYPE_E:
129426048Sminshall 				setebcdic();
129526048Sminshall 				break;
129626048Sminshall 			case TYPE_L:
129726048Sminshall 				settenex();
129826048Sminshall 				break;
129926048Sminshall 		}
130026048Sminshall 		pswitch(1);
130126048Sminshall 		return;
130226048Sminshall 	}
130326048Sminshall 	sleep(2);
130426048Sminshall 	pswitch(1);
130526048Sminshall 	secndflag++;
130626448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
130726048Sminshall 		goto abort;
130826048Sminshall 	ptflag++;
130926048Sminshall 	(void) getreply(0);
131026048Sminshall 	pswitch(0);
131126048Sminshall 	(void) getreply(0);
131226048Sminshall 	(void) signal(SIGINT, oldintr);
131326048Sminshall 	switch (oldtype) {
131426048Sminshall 		case 0:
131526048Sminshall 			break;
131626048Sminshall 		case TYPE_A:
131726048Sminshall 			setascii();
131826048Sminshall 			break;
131926048Sminshall 		case TYPE_I:
132026048Sminshall 			setbinary();
132126048Sminshall 			break;
132226048Sminshall 		case TYPE_E:
132326048Sminshall 			setebcdic();
132426048Sminshall 			break;
132526048Sminshall 		case TYPE_L:
132626048Sminshall 			settenex();
132726048Sminshall 			break;
132826048Sminshall 	}
132926048Sminshall 	pswitch(1);
133026048Sminshall 	ptflag = 0;
133126048Sminshall 	printf("local: %s remote: %s\n", local, remote);
133226048Sminshall 	return;
133326048Sminshall abort:
133426048Sminshall 	(void) signal(SIGINT, SIG_IGN);
133526048Sminshall 	ptflag = 0;
133626448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
133726048Sminshall 		pswitch(1);
133826448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
133926048Sminshall 		pswitch(0);
134026048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
134126048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
134226048Sminshall 			pswitch(0);
134326048Sminshall 			switch (oldtype) {
134426048Sminshall 				case 0:
134526048Sminshall 					break;
134626048Sminshall 				case TYPE_A:
134726048Sminshall 					setascii();
134826048Sminshall 					break;
134926048Sminshall 				case TYPE_I:
135026048Sminshall 					setbinary();
135126048Sminshall 					break;
135226048Sminshall 				case TYPE_E:
135326048Sminshall 					setebcdic();
135426048Sminshall 					break;
135526048Sminshall 				case TYPE_L:
135626048Sminshall 					settenex();
135726048Sminshall 					break;
135826048Sminshall 			}
135927687Sminshall 			if (cpend) {
136026048Sminshall 				char msg[2];
136126048Sminshall 
136226048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
136326048Sminshall 				(void) fflush(cout);
136426048Sminshall 				*msg = IAC;
136526048Sminshall 				*(msg+1) = DM;
136626448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
136726048Sminshall 					perror("abort");
136826048Sminshall 				fprintf(cout,"ABOR\r\n");
136926048Sminshall 				(void) fflush(cout);
137027687Sminshall 				FD_ZERO(&mask);
137126496Sminshall 				FD_SET(fileno(cin), &mask);
137227687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
137327687Sminshall 					if (nfnd < 0) {
137427687Sminshall 						perror("abort");
137527687Sminshall 					}
137626448Slepreau 					if (ptabflg)
137726048Sminshall 						code = -1;
137826048Sminshall 					lostpeer();
137926048Sminshall 				}
138026048Sminshall 				(void) getreply(0);
138126048Sminshall 				(void) getreply(0);
138226048Sminshall 			}
138326048Sminshall 		}
138426048Sminshall 		pswitch(1);
138526448Slepreau 		if (ptabflg)
138626048Sminshall 			code = -1;
138726048Sminshall 		(void) signal(SIGINT, oldintr);
138826048Sminshall 		return;
138926048Sminshall 	}
139027687Sminshall 	if (cpend) {
139126048Sminshall 		char msg[2];
139226048Sminshall 
139326048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
139426048Sminshall 		(void) fflush(cout);
139526048Sminshall 		*msg = IAC;
139626048Sminshall 		*(msg+1) = DM;
139726448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
139826048Sminshall 			perror("abort");
139926048Sminshall 		fprintf(cout,"ABOR\r\n");
140026048Sminshall 		(void) fflush(cout);
140127687Sminshall 		FD_ZERO(&mask);
140226496Sminshall 		FD_SET(fileno(cin), &mask);
140327687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
140427687Sminshall 			if (nfnd < 0) {
140527687Sminshall 				perror("abort");
140627687Sminshall 			}
140726448Slepreau 			if (ptabflg)
140826048Sminshall 				code = -1;
140926048Sminshall 			lostpeer();
141026048Sminshall 		}
141126048Sminshall 		(void) getreply(0);
141226048Sminshall 		(void) getreply(0);
141326048Sminshall 	}
141426048Sminshall 	pswitch(!proxy);
141526048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
141626048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
141726048Sminshall 			pswitch(0);
141826048Sminshall 			switch (oldtype) {
141926048Sminshall 				case 0:
142026048Sminshall 					break;
142126048Sminshall 				case TYPE_A:
142226048Sminshall 					setascii();
142326048Sminshall 					break;
142426048Sminshall 				case TYPE_I:
142526048Sminshall 					setbinary();
142626048Sminshall 					break;
142726048Sminshall 				case TYPE_E:
142826048Sminshall 					setebcdic();
142926048Sminshall 					break;
143026048Sminshall 				case TYPE_L:
143126048Sminshall 					settenex();
143226048Sminshall 					break;
143326048Sminshall 			}
143427687Sminshall 			if (cpend) {
143526048Sminshall 				char msg[2];
143626048Sminshall 
143726048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
143826048Sminshall 				(void) fflush(cout);
143926048Sminshall 				*msg = IAC;
144026048Sminshall 				*(msg+1) = DM;
144126448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
144226048Sminshall 					perror("abort");
144326048Sminshall 				fprintf(cout,"ABOR\r\n");
144426048Sminshall 				(void) fflush(cout);
144527687Sminshall 				FD_ZERO(&mask);
144626496Sminshall 				FD_SET(fileno(cin), &mask);
144727687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
144827687Sminshall 					if (nfnd < 0) {
144927687Sminshall 						perror("abort");
145027687Sminshall 					}
145126448Slepreau 					if (ptabflg)
145226048Sminshall 						code = -1;
145326048Sminshall 					lostpeer();
145426048Sminshall 				}
145526048Sminshall 				(void) getreply(0);
145626048Sminshall 				(void) getreply(0);
145726048Sminshall 			}
145826048Sminshall 			pswitch(1);
145926448Slepreau 			if (ptabflg)
146026048Sminshall 				code = -1;
146126048Sminshall 			(void) signal(SIGINT, oldintr);
146226048Sminshall 			return;
146326048Sminshall 		}
146426048Sminshall 	}
146527687Sminshall 	if (cpend) {
146626048Sminshall 		char msg[2];
146726048Sminshall 
146826048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
146926048Sminshall 		(void) fflush(cout);
147026048Sminshall 		*msg = IAC;
147126048Sminshall 		*(msg+1) = DM;
147226448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
147326048Sminshall 			perror("abort");
147426048Sminshall 		fprintf(cout,"ABOR\r\n");
147526048Sminshall 		(void) fflush(cout);
147627687Sminshall 		FD_ZERO(&mask);
147726496Sminshall 		FD_SET(fileno(cin), &mask);
147827687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
147927687Sminshall 			if (nfnd < 0) {
148027687Sminshall 				perror("abort");
148127687Sminshall 			}
148226448Slepreau 			if (ptabflg)
148326048Sminshall 				code = -1;
148426048Sminshall 			lostpeer();
148526048Sminshall 		}
148626048Sminshall 		(void) getreply(0);
148726048Sminshall 		(void) getreply(0);
148826048Sminshall 	}
148926048Sminshall 	pswitch(!proxy);
149026048Sminshall 	if (cpend) {
149127687Sminshall 		FD_ZERO(&mask);
149226496Sminshall 		FD_SET(fileno(cin), &mask);
149327687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
149427687Sminshall 			if (nfnd < 0) {
149527687Sminshall 				perror("abort");
149627687Sminshall 			}
149726448Slepreau 			if (ptabflg)
149826048Sminshall 				code = -1;
149926048Sminshall 			lostpeer();
150026048Sminshall 		}
150126048Sminshall 		(void) getreply(0);
150226048Sminshall 		(void) getreply(0);
150326048Sminshall 	}
150426448Slepreau 	if (proxy)
150526048Sminshall 		pswitch(0);
150626048Sminshall 	switch (oldtype) {
150726048Sminshall 		case 0:
150826048Sminshall 			break;
150926048Sminshall 		case TYPE_A:
151026048Sminshall 			setascii();
151126048Sminshall 			break;
151226048Sminshall 		case TYPE_I:
151326048Sminshall 			setbinary();
151426048Sminshall 			break;
151526048Sminshall 		case TYPE_E:
151626048Sminshall 			setebcdic();
151726048Sminshall 			break;
151826048Sminshall 		case TYPE_L:
151926048Sminshall 			settenex();
152026048Sminshall 			break;
152126048Sminshall 	}
152226048Sminshall 	pswitch(1);
152326448Slepreau 	if (ptabflg)
152426048Sminshall 		code = -1;
152526048Sminshall 	(void) signal(SIGINT, oldintr);
152626048Sminshall }
152726048Sminshall 
152826048Sminshall reset()
152926048Sminshall {
153026496Sminshall 	struct fd_set mask;
153126496Sminshall 	int nfnd = 1;
153226048Sminshall 
153327687Sminshall 	FD_ZERO(&mask);
153430946Scsvsj 	while (nfnd > 0) {
153526496Sminshall 		FD_SET(fileno(cin), &mask);
153627687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
153726048Sminshall 			perror("reset");
153826048Sminshall 			code = -1;
153926048Sminshall 			lostpeer();
154026048Sminshall 		}
154127687Sminshall 		else if (nfnd) {
154226048Sminshall 			(void) getreply(0);
154326496Sminshall 		}
154426048Sminshall 	}
154526048Sminshall }
154626048Sminshall 
154726048Sminshall char *
154826048Sminshall gunique(local)
154926048Sminshall 	char *local;
155026048Sminshall {
155126048Sminshall 	static char new[MAXPATHLEN];
155226048Sminshall 	char *cp = rindex(local, '/');
155326048Sminshall 	int d, count=0;
155426048Sminshall 	char ext = '1';
155526048Sminshall 
155626448Slepreau 	if (cp)
155726048Sminshall 		*cp = '\0';
155826048Sminshall 	d = access(cp ? local : ".", 2);
155926448Slepreau 	if (cp)
156026048Sminshall 		*cp = '/';
156126048Sminshall 	if (d < 0) {
156226048Sminshall 		perror(local);
156326048Sminshall 		return((char *) 0);
156426048Sminshall 	}
156526048Sminshall 	(void) strcpy(new, local);
156626048Sminshall 	cp = new + strlen(new);
156726048Sminshall 	*cp++ = '.';
156826048Sminshall 	while (!d) {
156926048Sminshall 		if (++count == 100) {
157026048Sminshall 			printf("runique: can't find unique file name.\n");
157126048Sminshall 			return((char *) 0);
157226048Sminshall 		}
157326048Sminshall 		*cp++ = ext;
157426048Sminshall 		*cp = '\0';
157526448Slepreau 		if (ext == '9')
157626048Sminshall 			ext = '0';
157726448Slepreau 		else
157826048Sminshall 			ext++;
157926448Slepreau 		if ((d = access(new, 0)) < 0)
158026048Sminshall 			break;
158126448Slepreau 		if (ext != '0')
158226048Sminshall 			cp--;
158326448Slepreau 		else if (*(cp - 2) == '.')
158426048Sminshall 			*(cp - 1) = '1';
158526048Sminshall 		else {
158626048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
158726048Sminshall 			cp--;
158826048Sminshall 		}
158926048Sminshall 	}
159026048Sminshall 	return(new);
159126048Sminshall }
1592