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