xref: /netbsd-src/usr.bin/ftp/ftp.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: ftp.c,v 1.25 1997/04/14 09:09:22 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, 1989, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)ftp.c	8.6 (Berkeley) 10/27/94";
39 #else
40 static char rcsid[] = "$NetBSD: ftp.c,v 1.25 1997/04/14 09:09:22 lukem Exp $";
41 #endif
42 #endif /* not lint */
43 
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/socket.h>
47 
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/ip.h>
51 #include <arpa/inet.h>
52 #include <arpa/ftp.h>
53 #include <arpa/telnet.h>
54 
55 #include <ctype.h>
56 #include <err.h>
57 #include <errno.h>
58 #include <netdb.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #ifdef __STDC__
64 #include <stdarg.h>
65 #else
66 #include <varargs.h>
67 #endif
68 
69 #include "ftp_var.h"
70 
71 struct	sockaddr_in hisctladdr;
72 struct	sockaddr_in data_addr;
73 int	data = -1;
74 int	abrtflag = 0;
75 jmp_buf	ptabort;
76 int	ptabflg;
77 int	ptflag = 0;
78 struct	sockaddr_in myctladdr;
79 off_t	restart_point = 0;
80 
81 
82 FILE	*cin, *cout;
83 
84 char *
85 hookup(host, port)
86 	const char *host;
87 	int port;
88 {
89 	struct hostent *hp = 0;
90 	int s, len, tos;
91 	static char hostnamebuf[MAXHOSTNAMELEN];
92 
93 	memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
94 	if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
95 		hisctladdr.sin_family = AF_INET;
96 		(void)strncpy(hostnamebuf, host, sizeof(hostnamebuf) - 1);
97 		hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
98 	} else {
99 		hp = gethostbyname(host);
100 		if (hp == NULL) {
101 			warnx("%s: %s", host, hstrerror(h_errno));
102 			code = -1;
103 			return ((char *) 0);
104 		}
105 		hisctladdr.sin_family = hp->h_addrtype;
106 		memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
107 		(void)strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf) - 1);
108 		hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
109 	}
110 	hostname = hostnamebuf;
111 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
112 	if (s < 0) {
113 		warn("socket");
114 		code = -1;
115 		return (0);
116 	}
117 	hisctladdr.sin_port = port;
118 	while (connect(s, (struct sockaddr *)&hisctladdr,
119 			sizeof(hisctladdr)) < 0) {
120 		if (hp && hp->h_addr_list[1]) {
121 			int oerrno = errno;
122 			char *ia;
123 
124 			ia = inet_ntoa(hisctladdr.sin_addr);
125 			errno = oerrno;
126 			warn("connect to address %s", ia);
127 			hp->h_addr_list++;
128 			memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
129 			printf("Trying %s...\n",
130 			    inet_ntoa(hisctladdr.sin_addr));
131 			(void)close(s);
132 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
133 			if (s < 0) {
134 				warn("socket");
135 				code = -1;
136 				return (0);
137 			}
138 			continue;
139 		}
140 		warn("connect");
141 		code = -1;
142 		goto bad;
143 	}
144 	len = sizeof(myctladdr);
145 	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
146 		warn("getsockname");
147 		code = -1;
148 		goto bad;
149 	}
150 #ifdef IP_TOS
151 	tos = IPTOS_LOWDELAY;
152 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
153 		warn("setsockopt TOS (ignored)");
154 #endif
155 	cin = fdopen(s, "r");
156 	cout = fdopen(s, "w");
157 	if (cin == NULL || cout == NULL) {
158 		warnx("fdopen failed.");
159 		if (cin)
160 			(void)fclose(cin);
161 		if (cout)
162 			(void)fclose(cout);
163 		code = -1;
164 		goto bad;
165 	}
166 	if (verbose)
167 		printf("Connected to %s.\n", hostname);
168 	if (getreply(0) > 2) { 	/* read startup message from server */
169 		if (cin)
170 			(void)fclose(cin);
171 		if (cout)
172 			(void)fclose(cout);
173 		code = -1;
174 		goto bad;
175 	}
176 #ifdef SO_OOBINLINE
177 	{
178 	int on = 1;
179 
180 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
181 		< 0 && debug) {
182 			warn("setsockopt");
183 		}
184 	}
185 #endif /* SO_OOBINLINE */
186 
187 	return (hostname);
188 bad:
189 	(void)close(s);
190 	return ((char *)0);
191 }
192 
193 void
194 cmdabort(notused)
195 	int notused;
196 {
197 
198 	alarmtimer(0);
199 	putchar('\n');
200 	(void)fflush(stdout);
201 	abrtflag++;
202 	if (ptflag)
203 		longjmp(ptabort, 1);
204 }
205 
206 /*VARARGS*/
207 int
208 #ifdef __STDC__
209 command(const char *fmt, ...)
210 #else
211 command(va_alist)
212 	va_dcl
213 #endif
214 {
215 	va_list ap;
216 	int r;
217 	sig_t oldintr;
218 #ifndef __STDC__
219 	const char *fmt;
220 #endif
221 
222 	abrtflag = 0;
223 	if (debug) {
224 		fputs("---> ", stdout);
225 #ifdef __STDC__
226 		va_start(ap, fmt);
227 #else
228 		va_start(ap);
229 		fmt = va_arg(ap, const char *);
230 #endif
231 		if (strncmp("PASS ", fmt, 5) == 0)
232 			fputs("PASS XXXX", stdout);
233 		else if (strncmp("ACCT ", fmt, 5) == 0)
234 			fputs("ACCT XXXX", stdout);
235 		else
236 			vprintf(fmt, ap);
237 		va_end(ap);
238 		putchar('\n');
239 		(void)fflush(stdout);
240 	}
241 	if (cout == NULL) {
242 		warnx("No control connection for command.");
243 		code = -1;
244 		return (0);
245 	}
246 	oldintr = signal(SIGINT, cmdabort);
247 #ifdef __STDC__
248 	va_start(ap, fmt);
249 #else
250 	va_start(ap);
251 	fmt = va_arg(ap, char *);
252 #endif
253 	vfprintf(cout, fmt, ap);
254 	va_end(ap);
255 	fputs("\r\n", cout);
256 	(void)fflush(cout);
257 	cpend = 1;
258 	r = getreply(!strcmp(fmt, "QUIT"));
259 	if (abrtflag && oldintr != SIG_IGN)
260 		(*oldintr)(SIGINT);
261 	(void)signal(SIGINT, oldintr);
262 	return (r);
263 }
264 
265 char reply_string[BUFSIZ];		/* first line of previous reply */
266 
267 int
268 getreply(expecteof)
269 	int expecteof;
270 {
271 	char current_line[BUFSIZ];	/* last line of previous reply */
272 	int c, n, line;
273 	int dig;
274 	int originalcode = 0, continuation = 0;
275 	sig_t oldintr;
276 	int pflag = 0;
277 	char *cp, *pt = pasv;
278 
279 	oldintr = signal(SIGINT, cmdabort);
280 	for (line = 0 ;; line++) {
281 		dig = n = code = 0;
282 		cp = current_line;
283 		while ((c = getc(cin)) != '\n') {
284 			if (c == IAC) {     /* handle telnet commands */
285 				switch (c = getc(cin)) {
286 				case WILL:
287 				case WONT:
288 					c = getc(cin);
289 					fprintf(cout, "%c%c%c", IAC, DONT, c);
290 					(void)fflush(cout);
291 					break;
292 				case DO:
293 				case DONT:
294 					c = getc(cin);
295 					fprintf(cout, "%c%c%c", IAC, WONT, c);
296 					(void)fflush(cout);
297 					break;
298 				default:
299 					break;
300 				}
301 				continue;
302 			}
303 			dig++;
304 			if (c == EOF) {
305 				if (expecteof) {
306 					(void)signal(SIGINT, oldintr);
307 					code = 221;
308 					return (0);
309 				}
310 				lostpeer();
311 				if (verbose) {
312 					puts(
313 "421 Service not available, remote server has closed connection.");
314 					(void)fflush(stdout);
315 				}
316 				code = 421;
317 				return (4);
318 			}
319 			if (c != '\r' && (verbose > 0 ||
320 			    (verbose > -1 && n == '5' && dig > 4))) {
321 				if (proxflag &&
322 				   (dig == 1 || (dig == 5 && verbose == 0)))
323 					printf("%s:", hostname);
324 				(void)putchar(c);
325 			}
326 			if (dig < 4 && isdigit(c))
327 				code = code * 10 + (c - '0');
328 			if (!pflag && code == 227)
329 				pflag = 1;
330 			if (dig > 4 && pflag == 1 && isdigit(c))
331 				pflag = 2;
332 			if (pflag == 2) {
333 				if (c != '\r' && c != ')')
334 					*pt++ = c;
335 				else {
336 					*pt = '\0';
337 					pflag = 3;
338 				}
339 			}
340 			if (dig == 4 && c == '-') {
341 				if (continuation)
342 					code = 0;
343 				continuation++;
344 			}
345 			if (n == 0)
346 				n = c;
347 			if (cp < &current_line[sizeof(current_line) - 1])
348 				*cp++ = c;
349 		}
350 		if (verbose > 0 || (verbose > -1 && n == '5')) {
351 			(void)putchar(c);
352 			(void)fflush (stdout);
353 		}
354 		if (line == 0) {
355 			size_t len = cp - current_line;
356 
357 			if (len > sizeof(reply_string))
358 				len = sizeof(reply_string);
359 
360 			(void)strncpy(reply_string, current_line, len);
361 			reply_string[len] = '\0';
362 		}
363 		if (continuation && code != originalcode) {
364 			if (originalcode == 0)
365 				originalcode = code;
366 			continue;
367 		}
368 		*cp = '\0';
369 		if (n != '1')
370 			cpend = 0;
371 		(void)signal(SIGINT, oldintr);
372 		if (code == 421 || originalcode == 421)
373 			lostpeer();
374 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
375 			(*oldintr)(SIGINT);
376 		return (n - '0');
377 	}
378 }
379 
380 int
381 empty(mask, sec)
382 	struct fd_set *mask;
383 	int sec;
384 {
385 	struct timeval t;
386 
387 	t.tv_sec = (long) sec;
388 	t.tv_usec = 0;
389 	return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
390 }
391 
392 jmp_buf	sendabort;
393 
394 void
395 abortsend(notused)
396 	int notused;
397 {
398 
399 	alarmtimer(0);
400 	mflag = 0;
401 	abrtflag = 0;
402 	puts("\nsend aborted\nwaiting for remote to finish abort.");
403 	(void)fflush(stdout);
404 	longjmp(sendabort, 1);
405 }
406 
407 void
408 sendrequest(cmd, local, remote, printnames)
409 	const char *cmd, *local, *remote;
410 	int printnames;
411 {
412 	struct stat st;
413 	int c, d;
414 	FILE *fin, *dout = 0;
415 	int (*closefunc) __P((FILE *));
416 	sig_t oldinti, oldintr, oldintp;
417 	off_t hashbytes;
418 	char *lmode, buf[BUFSIZ], *bufp;
419 	int oprogress;
420 
421 	hashbytes = mark;
422 	direction = "sent";
423 	bytes = 0;
424 	filesize = -1;
425 	oprogress = progress;
426 	if (verbose && printnames) {
427 		if (local && *local != '-')
428 			printf("local: %s ", local);
429 		if (remote)
430 			printf("remote: %s\n", remote);
431 	}
432 	if (proxy) {
433 		proxtrans(cmd, local, remote);
434 		return;
435 	}
436 	if (curtype != type)
437 		changetype(type, 0);
438 	closefunc = NULL;
439 	oldintr = NULL;
440 	oldintp = NULL;
441 	oldinti = NULL;
442 	lmode = "w";
443 	if (setjmp(sendabort)) {
444 		while (cpend) {
445 			(void)getreply(0);
446 		}
447 		if (data >= 0) {
448 			(void)close(data);
449 			data = -1;
450 		}
451 		if (oldintr)
452 			(void)signal(SIGINT, oldintr);
453 		if (oldintp)
454 			(void)signal(SIGPIPE, oldintp);
455 		if (oldinti)
456 			(void)signal(SIGINFO, oldinti);
457 		progress = oprogress;
458 		code = -1;
459 		return;
460 	}
461 	oldintr = signal(SIGINT, abortsend);
462 	oldinti = signal(SIGINFO, psummary);
463 	if (strcmp(local, "-") == 0) {
464 		fin = stdin;
465 		progress = 0;
466 	} else if (*local == '|') {
467 		oldintp = signal(SIGPIPE, SIG_IGN);
468 		fin = popen(local + 1, "r");
469 		if (fin == NULL) {
470 			warn("%s", local + 1);
471 			(void)signal(SIGINT, oldintr);
472 			(void)signal(SIGPIPE, oldintp);
473 			(void)signal(SIGINFO, oldinti);
474 			code = -1;
475 			return;
476 		}
477 		progress = 0;
478 		closefunc = pclose;
479 	} else {
480 		fin = fopen(local, "r");
481 		if (fin == NULL) {
482 			warn("local: %s", local);
483 			(void)signal(SIGINT, oldintr);
484 			(void)signal(SIGINFO, oldinti);
485 			code = -1;
486 			return;
487 		}
488 		closefunc = fclose;
489 		if (fstat(fileno(fin), &st) < 0 ||
490 		    (st.st_mode & S_IFMT) != S_IFREG) {
491 			printf("%s: not a plain file.\n", local);
492 			(void)signal(SIGINT, oldintr);
493 			(void)signal(SIGINFO, oldinti);
494 			fclose(fin);
495 			code = -1;
496 			return;
497 		}
498 		filesize = st.st_size;
499 	}
500 	if (initconn()) {
501 		(void)signal(SIGINT, oldintr);
502 		(void)signal(SIGINFO, oldinti);
503 		if (oldintp)
504 			(void)signal(SIGPIPE, oldintp);
505 		code = -1;
506 		progress = oprogress;
507 		if (closefunc != NULL)
508 			(*closefunc)(fin);
509 		return;
510 	}
511 	if (setjmp(sendabort))
512 		goto abort;
513 
514 	if (restart_point &&
515 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
516 		int rc;
517 
518 		rc = -1;
519 		switch (curtype) {
520 		case TYPE_A:
521 			rc = fseek(fin, (long) restart_point, SEEK_SET);
522 			break;
523 		case TYPE_I:
524 		case TYPE_L:
525 			rc = lseek(fileno(fin), restart_point, SEEK_SET);
526 			break;
527 		}
528 		if (rc < 0) {
529 			warn("local: %s", local);
530 			restart_point = 0;
531 			progress = oprogress;
532 			if (closefunc != NULL)
533 				(*closefunc)(fin);
534 			return;
535 		}
536 		if (command("REST %ld", (long) restart_point)
537 			!= CONTINUE) {
538 			restart_point = 0;
539 			progress = oprogress;
540 			if (closefunc != NULL)
541 				(*closefunc)(fin);
542 			return;
543 		}
544 		restart_point = 0;
545 		lmode = "r+w";
546 	}
547 	if (remote) {
548 		if (command("%s %s", cmd, remote) != PRELIM) {
549 			(void)signal(SIGINT, oldintr);
550 			(void)signal(SIGINFO, oldinti);
551 			progress = oprogress;
552 			if (oldintp)
553 				(void)signal(SIGPIPE, oldintp);
554 			if (closefunc != NULL)
555 				(*closefunc)(fin);
556 			return;
557 		}
558 	} else
559 		if (command("%s", cmd) != PRELIM) {
560 			(void)signal(SIGINT, oldintr);
561 			(void)signal(SIGINFO, oldinti);
562 			progress = oprogress;
563 			if (oldintp)
564 				(void)signal(SIGPIPE, oldintp);
565 			if (closefunc != NULL)
566 				(*closefunc)(fin);
567 			return;
568 		}
569 	dout = dataconn(lmode);
570 	if (dout == NULL)
571 		goto abort;
572 	progressmeter(-1);
573 	oldintp = signal(SIGPIPE, SIG_IGN);
574 	switch (curtype) {
575 
576 	case TYPE_I:
577 	case TYPE_L:
578 		errno = d = 0;
579 		while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
580 			bytes += c;
581 			for (bufp = buf; c > 0; c -= d, bufp += d)
582 				if ((d = write(fileno(dout), bufp, c)) <= 0)
583 					break;
584 			if (hash && (!progress || filesize < 0) ) {
585 				while (bytes >= hashbytes) {
586 					(void)putchar('#');
587 					hashbytes += mark;
588 				}
589 				(void)fflush(stdout);
590 			}
591 		}
592 		if (hash && (!progress || filesize < 0) && bytes > 0) {
593 			if (bytes < mark)
594 				(void)putchar('#');
595 			(void)putchar('\n');
596 			(void)fflush(stdout);
597 		}
598 		if (c < 0)
599 			warn("local: %s", local);
600 		if (d < 0) {
601 			if (errno != EPIPE)
602 				warn("netout");
603 			bytes = -1;
604 		}
605 		break;
606 
607 	case TYPE_A:
608 		while ((c = getc(fin)) != EOF) {
609 			if (c == '\n') {
610 				while (hash && (!progress || filesize < 0) &&
611 				    (bytes >= hashbytes)) {
612 					(void)putchar('#');
613 					(void)fflush(stdout);
614 					hashbytes += mark;
615 				}
616 				if (ferror(dout))
617 					break;
618 				(void)putc('\r', dout);
619 				bytes++;
620 			}
621 			(void)putc(c, dout);
622 			bytes++;
623 #if 0	/* this violates RFC */
624 			if (c == '\r') {
625 				(void)putc('\0', dout);
626 				bytes++;
627 			}
628 #endif
629 		}
630 		if (hash && (!progress || filesize < 0)) {
631 			if (bytes < hashbytes)
632 				(void)putchar('#');
633 			(void)putchar('\n');
634 			(void)fflush(stdout);
635 		}
636 		if (ferror(fin))
637 			warn("local: %s", local);
638 		if (ferror(dout)) {
639 			if (errno != EPIPE)
640 				warn("netout");
641 			bytes = -1;
642 		}
643 		break;
644 	}
645 	progressmeter(1);
646 	progress = oprogress;
647 	if (closefunc != NULL)
648 		(*closefunc)(fin);
649 	(void)fclose(dout);
650 	(void)getreply(0);
651 	(void)signal(SIGINT, oldintr);
652 	(void)signal(SIGINFO, oldinti);
653 	if (oldintp)
654 		(void)signal(SIGPIPE, oldintp);
655 	if (bytes > 0)
656 		ptransfer(0);
657 	return;
658 abort:
659 	(void)signal(SIGINT, oldintr);
660 	(void)signal(SIGINFO, oldinti);
661 	progress = oprogress;
662 	if (oldintp)
663 		(void)signal(SIGPIPE, oldintp);
664 	if (!cpend) {
665 		code = -1;
666 		return;
667 	}
668 	if (data >= 0) {
669 		(void)close(data);
670 		data = -1;
671 	}
672 	if (dout)
673 		(void)fclose(dout);
674 	(void)getreply(0);
675 	code = -1;
676 	if (closefunc != NULL && fin != NULL)
677 		(*closefunc)(fin);
678 	if (bytes > 0)
679 		ptransfer(0);
680 }
681 
682 jmp_buf	recvabort;
683 
684 void
685 abortrecv(notused)
686 	int notused;
687 {
688 
689 	alarmtimer(0);
690 	mflag = 0;
691 	abrtflag = 0;
692 	puts("\nreceive aborted\nwaiting for remote to finish abort.");
693 	(void)fflush(stdout);
694 	longjmp(recvabort, 1);
695 }
696 
697 void
698 recvrequest(cmd, local, remote, lmode, printnames)
699 	const char *cmd, *local, *remote, *lmode;
700 	int printnames;
701 {
702 	FILE *fout, *din = 0;
703 	int (*closefunc) __P((FILE *));
704 	sig_t oldinti, oldintr, oldintp;
705 	int c, d, is_retr, tcrflag, bare_lfs = 0;
706 	static int bufsize;
707 	static char *buf;
708 	off_t hashbytes;
709 	struct stat st;
710 	time_t mtime;
711 	struct timeval tval[2];
712 	int oprogress;
713 	int opreserve;
714 
715 	hashbytes = mark;
716 	direction = "received";
717 	bytes = 0;
718 	filesize = -1;
719 	oprogress = progress;
720 	opreserve = preserve;
721 	is_retr = strcmp(cmd, "RETR") == 0;
722 	if (is_retr && verbose && printnames) {
723 		if (local && *local != '-')
724 			printf("local: %s ", local);
725 		if (remote)
726 			printf("remote: %s\n", remote);
727 	}
728 	if (proxy && is_retr) {
729 		proxtrans(cmd, local, remote);
730 		return;
731 	}
732 	closefunc = NULL;
733 	oldintr = NULL;
734 	oldintp = NULL;
735 	tcrflag = !crflag && is_retr;
736 	if (setjmp(recvabort)) {
737 		while (cpend) {
738 			(void)getreply(0);
739 		}
740 		if (data >= 0) {
741 			(void)close(data);
742 			data = -1;
743 		}
744 		if (oldintr)
745 			(void)signal(SIGINT, oldintr);
746 		if (oldinti)
747 			(void)signal(SIGINFO, oldinti);
748 		progress = oprogress;
749 		preserve = opreserve;
750 		code = -1;
751 		return;
752 	}
753 	oldintr = signal(SIGINT, abortrecv);
754 	oldinti = signal(SIGINFO, psummary);
755 	if (strcmp(local, "-") && *local != '|') {
756 		if (access(local, 2) < 0) {
757 			char *dir = strrchr(local, '/');
758 
759 			if (errno != ENOENT && errno != EACCES) {
760 				warn("local: %s", local);
761 				(void)signal(SIGINT, oldintr);
762 				(void)signal(SIGINFO, oldinti);
763 				code = -1;
764 				return;
765 			}
766 			if (dir != NULL)
767 				*dir = 0;
768 			d = access(dir == local ? "/" : dir ? local : ".", 2);
769 			if (dir != NULL)
770 				*dir = '/';
771 			if (d < 0) {
772 				warn("local: %s", local);
773 				(void)signal(SIGINT, oldintr);
774 				(void)signal(SIGINFO, oldinti);
775 				code = -1;
776 				return;
777 			}
778 			if (!runique && errno == EACCES &&
779 			    chmod(local, 0600) < 0) {
780 				warn("local: %s", local);
781 				(void)signal(SIGINT, oldintr);
782 				(void)signal(SIGINFO, oldinti);
783 				code = -1;
784 				return;
785 			}
786 			if (runique && errno == EACCES &&
787 			   (local = gunique(local)) == NULL) {
788 				(void)signal(SIGINT, oldintr);
789 				(void)signal(SIGINFO, oldinti);
790 				code = -1;
791 				return;
792 			}
793 		}
794 		else if (runique && (local = gunique(local)) == NULL) {
795 			(void)signal(SIGINT, oldintr);
796 			(void)signal(SIGINFO, oldinti);
797 			code = -1;
798 			return;
799 		}
800 	}
801 	if (!is_retr) {
802 		if (curtype != TYPE_A)
803 			changetype(TYPE_A, 0);
804 	} else {
805 		if (curtype != type)
806 			changetype(type, 0);
807 		filesize = remotesize(remote, 0);
808 	}
809 	if (initconn()) {
810 		(void)signal(SIGINT, oldintr);
811 		(void)signal(SIGINFO, oldinti);
812 		code = -1;
813 		return;
814 	}
815 	if (setjmp(recvabort))
816 		goto abort;
817 	if (is_retr && restart_point &&
818 	    command("REST %ld", (long) restart_point) != CONTINUE)
819 		return;
820 	if (remote) {
821 		if (command("%s %s", cmd, remote) != PRELIM) {
822 			(void)signal(SIGINT, oldintr);
823 			(void)signal(SIGINFO, oldinti);
824 			return;
825 		}
826 	} else {
827 		if (command("%s", cmd) != PRELIM) {
828 			(void)signal(SIGINT, oldintr);
829 			(void)signal(SIGINFO, oldinti);
830 			return;
831 		}
832 	}
833 	din = dataconn("r");
834 	if (din == NULL)
835 		goto abort;
836 	if (strcmp(local, "-") == 0) {
837 		fout = stdout;
838 		progress = 0;
839 		preserve = 0;
840 	} else if (*local == '|') {
841 		oldintp = signal(SIGPIPE, SIG_IGN);
842 		fout = popen(local + 1, "w");
843 		if (fout == NULL) {
844 			warn("%s", local+1);
845 			goto abort;
846 		}
847 		progress = 0;
848 		preserve = 0;
849 		closefunc = pclose;
850 	} else {
851 		fout = fopen(local, lmode);
852 		if (fout == NULL) {
853 			warn("local: %s", local);
854 			goto abort;
855 		}
856 		closefunc = fclose;
857 	}
858 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
859 		st.st_blksize = BUFSIZ;
860 	if (st.st_blksize > bufsize) {
861 		if (buf)
862 			(void)free(buf);
863 		buf = malloc((unsigned)st.st_blksize);
864 		if (buf == NULL) {
865 			warn("malloc");
866 			bufsize = 0;
867 			goto abort;
868 		}
869 		bufsize = st.st_blksize;
870 	}
871 	if ((st.st_mode & S_IFMT) != S_IFREG) {
872 		progress = 0;
873 		preserve = 0;
874 	}
875 	progressmeter(-1);
876 	switch (curtype) {
877 
878 	case TYPE_I:
879 	case TYPE_L:
880 		if (restart_point &&
881 		    lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
882 			warn("local: %s", local);
883 			progress = oprogress;
884 			preserve = opreserve;
885 			if (closefunc != NULL)
886 				(*closefunc)(fout);
887 			return;
888 		}
889 		errno = d = 0;
890 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
891 			if ((d = write(fileno(fout), buf, c)) != c)
892 				break;
893 			bytes += c;
894 			if (hash && (!progress || filesize < 0)) {
895 				while (bytes >= hashbytes) {
896 					(void)putchar('#');
897 					hashbytes += mark;
898 				}
899 				(void)fflush(stdout);
900 			}
901 		}
902 		if (hash && (!progress || filesize < 0) && bytes > 0) {
903 			if (bytes < mark)
904 				(void)putchar('#');
905 			(void)putchar('\n');
906 			(void)fflush(stdout);
907 		}
908 		if (c < 0) {
909 			if (errno != EPIPE)
910 				warn("netin");
911 			bytes = -1;
912 		}
913 		if (d < c) {
914 			if (d < 0)
915 				warn("local: %s", local);
916 			else
917 				warnx("%s: short write", local);
918 		}
919 		break;
920 
921 	case TYPE_A:
922 		if (restart_point) {
923 			int i, n, ch;
924 
925 			if (fseek(fout, 0L, SEEK_SET) < 0)
926 				goto done;
927 			n = restart_point;
928 			for (i = 0; i++ < n;) {
929 				if ((ch = getc(fout)) == EOF)
930 					goto done;
931 				if (ch == '\n')
932 					i++;
933 			}
934 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
935 done:
936 				warn("local: %s", local);
937 				progress = oprogress;
938 				preserve = opreserve;
939 				if (closefunc != NULL)
940 					(*closefunc)(fout);
941 				return;
942 			}
943 		}
944 		while ((c = getc(din)) != EOF) {
945 			if (c == '\n')
946 				bare_lfs++;
947 			while (c == '\r') {
948 				while (hash && (!progress || filesize < 0) &&
949 				    (bytes >= hashbytes)) {
950 					(void)putchar('#');
951 					(void)fflush(stdout);
952 					hashbytes += mark;
953 				}
954 				bytes++;
955 				if ((c = getc(din)) != '\n' || tcrflag) {
956 					if (ferror(fout))
957 						goto break2;
958 					(void)putc('\r', fout);
959 					if (c == '\0') {
960 						bytes++;
961 						goto contin2;
962 					}
963 					if (c == EOF)
964 						goto contin2;
965 				}
966 			}
967 			(void)putc(c, fout);
968 			bytes++;
969 	contin2:	;
970 		}
971 break2:
972 		if (bare_lfs) {
973 			printf(
974 "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
975 			puts("File may not have transferred correctly.");
976 		}
977 		if (hash && (!progress || filesize < 0)) {
978 			if (bytes < hashbytes)
979 				(void)putchar('#');
980 			(void)putchar('\n');
981 			(void)fflush(stdout);
982 		}
983 		if (ferror(din)) {
984 			if (errno != EPIPE)
985 				warn("netin");
986 			bytes = -1;
987 		}
988 		if (ferror(fout))
989 			warn("local: %s", local);
990 		break;
991 	}
992 	progressmeter(1);
993 	progress = oprogress;
994 	preserve = opreserve;
995 	if (closefunc != NULL)
996 		(*closefunc)(fout);
997 	(void)signal(SIGINT, oldintr);
998 	(void)signal(SIGINFO, oldinti);
999 	if (oldintp)
1000 		(void)signal(SIGPIPE, oldintp);
1001 	(void)fclose(din);
1002 	(void)getreply(0);
1003 	if (bytes >= 0 && is_retr) {
1004 		if (bytes > 0)
1005 			ptransfer(0);
1006 		if (preserve && (closefunc == fclose)) {
1007 			mtime = remotemodtime(remote, 0);
1008 			if (mtime != -1) {
1009 				(void)gettimeofday(&tval[0],
1010 				    (struct timezone *)0);
1011 				tval[1].tv_sec = mtime;
1012 				tval[1].tv_usec = 0;
1013 				if (utimes(local, tval) == -1) {
1014 					printf(
1015 				"Can't change modification time on %s to %s",
1016 					    local, asctime(localtime(&mtime)));
1017 				}
1018 			}
1019 		}
1020 	}
1021 	return;
1022 
1023 abort:
1024 
1025 /* abort using RFC959 recommended IP,SYNC sequence */
1026 
1027 	progress = oprogress;
1028 	preserve = opreserve;
1029 	if (oldintp)
1030 		(void)signal(SIGPIPE, oldintp);
1031 	(void)signal(SIGINT, SIG_IGN);
1032 	if (!cpend) {
1033 		code = -1;
1034 		(void)signal(SIGINT, oldintr);
1035 		(void)signal(SIGINFO, oldinti);
1036 		return;
1037 	}
1038 
1039 	abort_remote(din);
1040 	code = -1;
1041 	if (data >= 0) {
1042 		(void)close(data);
1043 		data = -1;
1044 	}
1045 	if (closefunc != NULL && fout != NULL)
1046 		(*closefunc)(fout);
1047 	if (din)
1048 		(void)fclose(din);
1049 	if (bytes > 0)
1050 		ptransfer(0);
1051 	(void)signal(SIGINT, oldintr);
1052 	(void)signal(SIGINFO, oldinti);
1053 }
1054 
1055 /*
1056  * Need to start a listen on the data channel before we send the command,
1057  * otherwise the server's connect may fail.
1058  */
1059 int
1060 initconn()
1061 {
1062 	char *p, *a;
1063 	int result, len, tmpno = 0;
1064 	int on = 1;
1065 	int a0, a1, a2, a3, p0, p1;
1066 
1067 	if (passivemode) {
1068 		data = socket(AF_INET, SOCK_STREAM, 0);
1069 		if (data < 0) {
1070 			warn("socket");
1071 			return (1);
1072 		}
1073 		if ((options & SO_DEBUG) &&
1074 		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1075 			       sizeof(on)) < 0)
1076 			warn("setsockopt (ignored)");
1077 		if (command("PASV") != COMPLETE) {
1078 			puts("Passive mode refused.");
1079 			goto bad;
1080 		}
1081 
1082 		/*
1083 		 * What we've got at this point is a string of comma
1084 		 * separated one-byte unsigned integer values.
1085 		 * The first four are the an IP address. The fifth is
1086 		 * the MSB of the port number, the sixth is the LSB.
1087 		 * From that we'll prepare a sockaddr_in.
1088 		 */
1089 
1090 		if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1091 			   &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1092 			puts(
1093 "Passive mode address scan failure. Shouldn't happen!");
1094 			goto bad;
1095 		}
1096 
1097 		memset(&data_addr, 0, sizeof(data_addr));
1098 		data_addr.sin_family = AF_INET;
1099 		a = (char *)&data_addr.sin_addr.s_addr;
1100 		a[0] = a0 & 0xff;
1101 		a[1] = a1 & 0xff;
1102 		a[2] = a2 & 0xff;
1103 		a[3] = a3 & 0xff;
1104 		p = (char *)&data_addr.sin_port;
1105 		p[0] = p0 & 0xff;
1106 		p[1] = p1 & 0xff;
1107 
1108 		if (connect(data, (struct sockaddr *)&data_addr,
1109 			    sizeof(data_addr)) < 0) {
1110 			warn("connect");
1111 			goto bad;
1112 		}
1113 #ifdef IP_TOS
1114 		on = IPTOS_THROUGHPUT;
1115 		if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1116 			       sizeof(int)) < 0)
1117 			warn("setsockopt TOS (ignored)");
1118 #endif
1119 		return (0);
1120 	}
1121 
1122 noport:
1123 	data_addr = myctladdr;
1124 	if (sendport)
1125 		data_addr.sin_port = 0;	/* let system pick one */
1126 	if (data != -1)
1127 		(void)close(data);
1128 	data = socket(AF_INET, SOCK_STREAM, 0);
1129 	if (data < 0) {
1130 		warn("socket");
1131 		if (tmpno)
1132 			sendport = 1;
1133 		return (1);
1134 	}
1135 	if (!sendport)
1136 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1137 				sizeof(on)) < 0) {
1138 			warn("setsockopt (reuse address)");
1139 			goto bad;
1140 		}
1141 	if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1142 		warn("bind");
1143 		goto bad;
1144 	}
1145 	if (options & SO_DEBUG &&
1146 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1147 			sizeof(on)) < 0)
1148 		warn("setsockopt (ignored)");
1149 	len = sizeof(data_addr);
1150 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1151 		warn("getsockname");
1152 		goto bad;
1153 	}
1154 	if (listen(data, 1) < 0)
1155 		warn("listen");
1156 	if (sendport) {
1157 		a = (char *)&data_addr.sin_addr;
1158 		p = (char *)&data_addr.sin_port;
1159 #define	UC(b)	(((int)b)&0xff)
1160 		result =
1161 		    command("PORT %d,%d,%d,%d,%d,%d",
1162 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1163 		      UC(p[0]), UC(p[1]));
1164 		if (result == ERROR && sendport == -1) {
1165 			sendport = 0;
1166 			tmpno = 1;
1167 			goto noport;
1168 		}
1169 		return (result != COMPLETE);
1170 	}
1171 	if (tmpno)
1172 		sendport = 1;
1173 #ifdef IP_TOS
1174 	on = IPTOS_THROUGHPUT;
1175 	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1176 		warn("setsockopt TOS (ignored)");
1177 #endif
1178 	return (0);
1179 bad:
1180 	(void)close(data), data = -1;
1181 	if (tmpno)
1182 		sendport = 1;
1183 	return (1);
1184 }
1185 
1186 FILE *
1187 dataconn(lmode)
1188 	const char *lmode;
1189 {
1190 	struct sockaddr_in from;
1191 	int s, fromlen, tos;
1192 
1193 	fromlen = sizeof(from);
1194 
1195 	if (passivemode)
1196 		return (fdopen(data, lmode));
1197 
1198 	s = accept(data, (struct sockaddr *) &from, &fromlen);
1199 	if (s < 0) {
1200 		warn("accept");
1201 		(void)close(data), data = -1;
1202 		return (NULL);
1203 	}
1204 	(void)close(data);
1205 	data = s;
1206 #ifdef IP_TOS
1207 	tos = IPTOS_THROUGHPUT;
1208 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1209 		warn("setsockopt TOS (ignored)");
1210 #endif
1211 	return (fdopen(data, lmode));
1212 }
1213 
1214 void
1215 psummary(notused)
1216 	int notused;
1217 {
1218 
1219 	if (bytes > 0)
1220 		ptransfer(1);
1221 }
1222 
1223 void
1224 psabort(notused)
1225 	int notused;
1226 {
1227 
1228 	alarmtimer(0);
1229 	abrtflag++;
1230 }
1231 
1232 void
1233 pswitch(flag)
1234 	int flag;
1235 {
1236 	sig_t oldintr;
1237 	static struct comvars {
1238 		int connect;
1239 		char name[MAXHOSTNAMELEN];
1240 		struct sockaddr_in mctl;
1241 		struct sockaddr_in hctl;
1242 		FILE *in;
1243 		FILE *out;
1244 		int tpe;
1245 		int curtpe;
1246 		int cpnd;
1247 		int sunqe;
1248 		int runqe;
1249 		int mcse;
1250 		int ntflg;
1251 		char nti[17];
1252 		char nto[17];
1253 		int mapflg;
1254 		char mi[MAXPATHLEN];
1255 		char mo[MAXPATHLEN];
1256 	} proxstruct, tmpstruct;
1257 	struct comvars *ip, *op;
1258 
1259 	abrtflag = 0;
1260 	oldintr = signal(SIGINT, psabort);
1261 	if (flag) {
1262 		if (proxy)
1263 			return;
1264 		ip = &tmpstruct;
1265 		op = &proxstruct;
1266 		proxy++;
1267 	} else {
1268 		if (!proxy)
1269 			return;
1270 		ip = &proxstruct;
1271 		op = &tmpstruct;
1272 		proxy = 0;
1273 	}
1274 	ip->connect = connected;
1275 	connected = op->connect;
1276 	if (hostname) {
1277 		(void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1278 		ip->name[sizeof(ip->name) - 1] = '\0';
1279 	} else
1280 		ip->name[0] = '\0';
1281 	hostname = op->name;
1282 	ip->hctl = hisctladdr;
1283 	hisctladdr = op->hctl;
1284 	ip->mctl = myctladdr;
1285 	myctladdr = op->mctl;
1286 	ip->in = cin;
1287 	cin = op->in;
1288 	ip->out = cout;
1289 	cout = op->out;
1290 	ip->tpe = type;
1291 	type = op->tpe;
1292 	ip->curtpe = curtype;
1293 	curtype = op->curtpe;
1294 	ip->cpnd = cpend;
1295 	cpend = op->cpnd;
1296 	ip->sunqe = sunique;
1297 	sunique = op->sunqe;
1298 	ip->runqe = runique;
1299 	runique = op->runqe;
1300 	ip->mcse = mcase;
1301 	mcase = op->mcse;
1302 	ip->ntflg = ntflag;
1303 	ntflag = op->ntflg;
1304 	(void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1305 	(ip->nti)[sizeof(ip->nti) - 1] = '\0';
1306 	(void)strcpy(ntin, op->nti);
1307 	(void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1308 	(ip->nto)[sizeof(ip->nto) - 1] = '\0';
1309 	(void)strcpy(ntout, op->nto);
1310 	ip->mapflg = mapflag;
1311 	mapflag = op->mapflg;
1312 	(void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1313 	(ip->mi)[sizeof(ip->mi) - 1] = '\0';
1314 	(void)strcpy(mapin, op->mi);
1315 	(void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1316 	(ip->mo)[sizeof(ip->mo) - 1] = '\0';
1317 	(void)strcpy(mapout, op->mo);
1318 	(void)signal(SIGINT, oldintr);
1319 	if (abrtflag) {
1320 		abrtflag = 0;
1321 		(*oldintr)(SIGINT);
1322 	}
1323 }
1324 
1325 void
1326 abortpt(notused)
1327 	int notused;
1328 {
1329 
1330 	alarmtimer(0);
1331 	putchar('\n');
1332 	(void)fflush(stdout);
1333 	ptabflg++;
1334 	mflag = 0;
1335 	abrtflag = 0;
1336 	longjmp(ptabort, 1);
1337 }
1338 
1339 void
1340 proxtrans(cmd, local, remote)
1341 	const char *cmd, *local, *remote;
1342 {
1343 	sig_t oldintr;
1344 	int secndflag = 0, prox_type, nfnd;
1345 	char *cmd2;
1346 	struct fd_set mask;
1347 
1348 	if (strcmp(cmd, "RETR"))
1349 		cmd2 = "RETR";
1350 	else
1351 		cmd2 = runique ? "STOU" : "STOR";
1352 	if ((prox_type = type) == 0) {
1353 		if (unix_server && unix_proxy)
1354 			prox_type = TYPE_I;
1355 		else
1356 			prox_type = TYPE_A;
1357 	}
1358 	if (curtype != prox_type)
1359 		changetype(prox_type, 1);
1360 	if (command("PASV") != COMPLETE) {
1361 		puts("proxy server does not support third party transfers.");
1362 		return;
1363 	}
1364 	pswitch(0);
1365 	if (!connected) {
1366 		puts("No primary connection.");
1367 		pswitch(1);
1368 		code = -1;
1369 		return;
1370 	}
1371 	if (curtype != prox_type)
1372 		changetype(prox_type, 1);
1373 	if (command("PORT %s", pasv) != COMPLETE) {
1374 		pswitch(1);
1375 		return;
1376 	}
1377 	if (setjmp(ptabort))
1378 		goto abort;
1379 	oldintr = signal(SIGINT, abortpt);
1380 	if (command("%s %s", cmd, remote) != PRELIM) {
1381 		(void)signal(SIGINT, oldintr);
1382 		pswitch(1);
1383 		return;
1384 	}
1385 	sleep(2);
1386 	pswitch(1);
1387 	secndflag++;
1388 	if (command("%s %s", cmd2, local) != PRELIM)
1389 		goto abort;
1390 	ptflag++;
1391 	(void)getreply(0);
1392 	pswitch(0);
1393 	(void)getreply(0);
1394 	(void)signal(SIGINT, oldintr);
1395 	pswitch(1);
1396 	ptflag = 0;
1397 	printf("local: %s remote: %s\n", local, remote);
1398 	return;
1399 abort:
1400 	(void)signal(SIGINT, SIG_IGN);
1401 	ptflag = 0;
1402 	if (strcmp(cmd, "RETR") && !proxy)
1403 		pswitch(1);
1404 	else if (!strcmp(cmd, "RETR") && proxy)
1405 		pswitch(0);
1406 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1407 		if (command("%s %s", cmd2, local) != PRELIM) {
1408 			pswitch(0);
1409 			if (cpend)
1410 				abort_remote((FILE *) NULL);
1411 		}
1412 		pswitch(1);
1413 		if (ptabflg)
1414 			code = -1;
1415 		(void)signal(SIGINT, oldintr);
1416 		return;
1417 	}
1418 	if (cpend)
1419 		abort_remote((FILE *) NULL);
1420 	pswitch(!proxy);
1421 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1422 		if (command("%s %s", cmd2, local) != PRELIM) {
1423 			pswitch(0);
1424 			if (cpend)
1425 				abort_remote((FILE *) NULL);
1426 			pswitch(1);
1427 			if (ptabflg)
1428 				code = -1;
1429 			(void)signal(SIGINT, oldintr);
1430 			return;
1431 		}
1432 	}
1433 	if (cpend)
1434 		abort_remote((FILE *) NULL);
1435 	pswitch(!proxy);
1436 	if (cpend) {
1437 		FD_ZERO(&mask);
1438 		FD_SET(fileno(cin), &mask);
1439 		if ((nfnd = empty(&mask, 10)) <= 0) {
1440 			if (nfnd < 0) {
1441 				warn("abort");
1442 			}
1443 			if (ptabflg)
1444 				code = -1;
1445 			lostpeer();
1446 		}
1447 		(void)getreply(0);
1448 		(void)getreply(0);
1449 	}
1450 	if (proxy)
1451 		pswitch(0);
1452 	pswitch(1);
1453 	if (ptabflg)
1454 		code = -1;
1455 	(void)signal(SIGINT, oldintr);
1456 }
1457 
1458 void
1459 reset(argc, argv)
1460 	int argc;
1461 	char *argv[];
1462 {
1463 	struct fd_set mask;
1464 	int nfnd = 1;
1465 
1466 	FD_ZERO(&mask);
1467 	while (nfnd > 0) {
1468 		FD_SET(fileno(cin), &mask);
1469 		if ((nfnd = empty(&mask, 0)) < 0) {
1470 			warn("reset");
1471 			code = -1;
1472 			lostpeer();
1473 		}
1474 		else if (nfnd) {
1475 			(void)getreply(0);
1476 		}
1477 	}
1478 }
1479 
1480 char *
1481 gunique(local)
1482 	const char *local;
1483 {
1484 	static char new[MAXPATHLEN];
1485 	char *cp = strrchr(local, '/');
1486 	int d, count=0;
1487 	char ext = '1';
1488 
1489 	if (cp)
1490 		*cp = '\0';
1491 	d = access(cp == local ? "/" : cp ? local : ".", 2);
1492 	if (cp)
1493 		*cp = '/';
1494 	if (d < 0) {
1495 		warn("local: %s", local);
1496 		return ((char *) 0);
1497 	}
1498 	(void)strcpy(new, local);
1499 	cp = new + strlen(new);
1500 	*cp++ = '.';
1501 	while (!d) {
1502 		if (++count == 100) {
1503 			puts("runique: can't find unique file name.");
1504 			return ((char *) 0);
1505 		}
1506 		*cp++ = ext;
1507 		*cp = '\0';
1508 		if (ext == '9')
1509 			ext = '0';
1510 		else
1511 			ext++;
1512 		if ((d = access(new, 0)) < 0)
1513 			break;
1514 		if (ext != '0')
1515 			cp--;
1516 		else if (*(cp - 2) == '.')
1517 			*(cp - 1) = '1';
1518 		else {
1519 			*(cp - 2) = *(cp - 2) + 1;
1520 			cp--;
1521 		}
1522 	}
1523 	return (new);
1524 }
1525 
1526 void
1527 abort_remote(din)
1528 	FILE *din;
1529 {
1530 	char buf[BUFSIZ];
1531 	int nfnd;
1532 	struct fd_set mask;
1533 
1534 	if (cout == NULL) {
1535 		warnx("Lost control connection for abort.");
1536 		if (ptabflg)
1537 			code = -1;
1538 		lostpeer();
1539 		return;
1540 	}
1541 	/*
1542 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1543 	 * after urgent byte rather than before as is protocol now
1544 	 */
1545 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
1546 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1547 		warn("abort");
1548 	fprintf(cout, "%cABOR\r\n", DM);
1549 	(void)fflush(cout);
1550 	FD_ZERO(&mask);
1551 	FD_SET(fileno(cin), &mask);
1552 	if (din) {
1553 		FD_SET(fileno(din), &mask);
1554 	}
1555 	if ((nfnd = empty(&mask, 10)) <= 0) {
1556 		if (nfnd < 0) {
1557 			warn("abort");
1558 		}
1559 		if (ptabflg)
1560 			code = -1;
1561 		lostpeer();
1562 	}
1563 	if (din && FD_ISSET(fileno(din), &mask)) {
1564 		while (read(fileno(din), buf, BUFSIZ) > 0)
1565 			/* LOOP */;
1566 	}
1567 	if (getreply(0) == ERROR && code == 552) {
1568 		/* 552 needed for nic style abort */
1569 		(void)getreply(0);
1570 	}
1571 	(void)getreply(0);
1572 }
1573