xref: /netbsd-src/usr.bin/ftp/ftp.c (revision f5d3fbbc6ff4a77159fb268d247bd94cb7d7e332)
1 /*	$NetBSD: ftp.c,v 1.29 1997/10/19 19:09:05 mycroft 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.29 1997/10/19 19:09:05 mycroft 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 || !S_ISREG(st.st_mode)) {
502 			printf("%s: not a plain file.\n", local);
503 			(void)signal(SIGINT, oldintr);
504 			(void)signal(SIGINFO, oldinti);
505 			fclose(fin);
506 			code = -1;
507 			return;
508 		}
509 		filesize = st.st_size;
510 	}
511 	if (initconn()) {
512 		(void)signal(SIGINT, oldintr);
513 		(void)signal(SIGINFO, oldinti);
514 		if (oldintp)
515 			(void)signal(SIGPIPE, oldintp);
516 		code = -1;
517 		progress = oprogress;
518 		if (closefunc != NULL)
519 			(*closefunc)(fin);
520 		return;
521 	}
522 	if (setjmp(sendabort))
523 		goto abort;
524 
525 	if (restart_point &&
526 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
527 		int rc;
528 
529 		rc = -1;
530 		switch (curtype) {
531 		case TYPE_A:
532 			rc = fseek(fin, (long) restart_point, SEEK_SET);
533 			break;
534 		case TYPE_I:
535 		case TYPE_L:
536 			rc = lseek(fileno(fin), restart_point, SEEK_SET);
537 			break;
538 		}
539 		if (rc < 0) {
540 			warn("local: %s", local);
541 			restart_point = 0;
542 			progress = oprogress;
543 			if (closefunc != NULL)
544 				(*closefunc)(fin);
545 			return;
546 		}
547 		if (command("REST %ld", (long) restart_point)
548 			!= CONTINUE) {
549 			restart_point = 0;
550 			progress = oprogress;
551 			if (closefunc != NULL)
552 				(*closefunc)(fin);
553 			return;
554 		}
555 		restart_point = 0;
556 		lmode = "r+w";
557 	}
558 	if (remote) {
559 		if (command("%s %s", cmd, remote) != 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 	} else
570 		if (command("%s", cmd) != PRELIM) {
571 			(void)signal(SIGINT, oldintr);
572 			(void)signal(SIGINFO, oldinti);
573 			progress = oprogress;
574 			if (oldintp)
575 				(void)signal(SIGPIPE, oldintp);
576 			if (closefunc != NULL)
577 				(*closefunc)(fin);
578 			return;
579 		}
580 	dout = dataconn(lmode);
581 	if (dout == NULL)
582 		goto abort;
583 	progressmeter(-1);
584 	oldintp = signal(SIGPIPE, SIG_IGN);
585 	switch (curtype) {
586 
587 	case TYPE_I:
588 	case TYPE_L:
589 		errno = d = 0;
590 		while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
591 			bytes += c;
592 			for (bufp = buf; c > 0; c -= d, bufp += d)
593 				if ((d = write(fileno(dout), bufp, c)) <= 0)
594 					break;
595 			if (hash && (!progress || filesize < 0) ) {
596 				while (bytes >= hashbytes) {
597 					(void)putchar('#');
598 					hashbytes += mark;
599 				}
600 				(void)fflush(stdout);
601 			}
602 		}
603 		if (hash && (!progress || filesize < 0) && bytes > 0) {
604 			if (bytes < mark)
605 				(void)putchar('#');
606 			(void)putchar('\n');
607 			(void)fflush(stdout);
608 		}
609 		if (c < 0)
610 			warn("local: %s", local);
611 		if (d < 0) {
612 			if (errno != EPIPE)
613 				warn("netout");
614 			bytes = -1;
615 		}
616 		break;
617 
618 	case TYPE_A:
619 		while ((c = getc(fin)) != EOF) {
620 			if (c == '\n') {
621 				while (hash && (!progress || filesize < 0) &&
622 				    (bytes >= hashbytes)) {
623 					(void)putchar('#');
624 					(void)fflush(stdout);
625 					hashbytes += mark;
626 				}
627 				if (ferror(dout))
628 					break;
629 				(void)putc('\r', dout);
630 				bytes++;
631 			}
632 			(void)putc(c, dout);
633 			bytes++;
634 #if 0	/* this violates RFC */
635 			if (c == '\r') {
636 				(void)putc('\0', dout);
637 				bytes++;
638 			}
639 #endif
640 		}
641 		if (hash && (!progress || filesize < 0)) {
642 			if (bytes < hashbytes)
643 				(void)putchar('#');
644 			(void)putchar('\n');
645 			(void)fflush(stdout);
646 		}
647 		if (ferror(fin))
648 			warn("local: %s", local);
649 		if (ferror(dout)) {
650 			if (errno != EPIPE)
651 				warn("netout");
652 			bytes = -1;
653 		}
654 		break;
655 	}
656 	progressmeter(1);
657 	progress = oprogress;
658 	if (closefunc != NULL)
659 		(*closefunc)(fin);
660 	(void)fclose(dout);
661 	(void)getreply(0);
662 	(void)signal(SIGINT, oldintr);
663 	(void)signal(SIGINFO, oldinti);
664 	if (oldintp)
665 		(void)signal(SIGPIPE, oldintp);
666 	if (bytes > 0)
667 		ptransfer(0);
668 	return;
669 abort:
670 	(void)signal(SIGINT, oldintr);
671 	(void)signal(SIGINFO, oldinti);
672 	progress = oprogress;
673 	if (oldintp)
674 		(void)signal(SIGPIPE, oldintp);
675 	if (!cpend) {
676 		code = -1;
677 		return;
678 	}
679 	if (data >= 0) {
680 		(void)close(data);
681 		data = -1;
682 	}
683 	if (dout)
684 		(void)fclose(dout);
685 	(void)getreply(0);
686 	code = -1;
687 	if (closefunc != NULL && fin != NULL)
688 		(*closefunc)(fin);
689 	if (bytes > 0)
690 		ptransfer(0);
691 }
692 
693 jmp_buf	recvabort;
694 
695 void
696 abortrecv(notused)
697 	int notused;
698 {
699 
700 	alarmtimer(0);
701 	mflag = 0;
702 	abrtflag = 0;
703 	puts("\nreceive aborted\nwaiting for remote to finish abort.");
704 	(void)fflush(stdout);
705 	longjmp(recvabort, 1);
706 }
707 
708 void
709 recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
710 	const char *cmd, *local, *remote, *lmode;
711 	int printnames, ignorespecial;
712 {
713 	FILE *fout, *din;
714 	int (*closefunc) __P((FILE *));
715 	sig_t oldinti, oldintr, oldintp;
716 	int c, d;
717 	volatile int is_retr, tcrflag, bare_lfs;
718 	static size_t bufsize;
719 	static char *buf;
720 	volatile off_t hashbytes;
721 	struct stat st;
722 	time_t mtime;
723 	struct timeval tval[2];
724 	int oprogress;
725 	int opreserve;
726 
727 #ifdef __GNUC__			/* XXX: to shut up gcc warnings */
728 	(void)&local;
729 	(void)&fout;
730 	(void)&din;
731 	(void)&closefunc;
732 	(void)&oldinti;
733 	(void)&oldintr;
734 	(void)&oldintp;
735 #endif
736 
737 	fout = NULL;
738 	din = NULL;
739 	oldinti = NULL;
740 	hashbytes = mark;
741 	direction = "received";
742 	bytes = 0;
743 	bare_lfs = 0;
744 	filesize = -1;
745 	oprogress = progress;
746 	opreserve = preserve;
747 	is_retr = strcmp(cmd, "RETR") == 0;
748 	if (is_retr && verbose && printnames) {
749 		if (local && (ignorespecial || *local != '-'))
750 			printf("local: %s ", local);
751 		if (remote)
752 			printf("remote: %s\n", remote);
753 	}
754 	if (proxy && is_retr) {
755 		proxtrans(cmd, local, remote);
756 		return;
757 	}
758 	closefunc = NULL;
759 	oldintr = NULL;
760 	oldintp = NULL;
761 	tcrflag = !crflag && is_retr;
762 	if (setjmp(recvabort)) {
763 		while (cpend) {
764 			(void)getreply(0);
765 		}
766 		if (data >= 0) {
767 			(void)close(data);
768 			data = -1;
769 		}
770 		if (oldintr)
771 			(void)signal(SIGINT, oldintr);
772 		if (oldinti)
773 			(void)signal(SIGINFO, oldinti);
774 		progress = oprogress;
775 		preserve = opreserve;
776 		code = -1;
777 		return;
778 	}
779 	oldintr = signal(SIGINT, abortrecv);
780 	oldinti = signal(SIGINFO, psummary);
781 	if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
782 		if (access(local, W_OK) < 0) {
783 			char *dir = strrchr(local, '/');
784 
785 			if (errno != ENOENT && errno != EACCES) {
786 				warn("local: %s", local);
787 				(void)signal(SIGINT, oldintr);
788 				(void)signal(SIGINFO, oldinti);
789 				code = -1;
790 				return;
791 			}
792 			if (dir != NULL)
793 				*dir = 0;
794 			d = access(dir == local ? "/" : dir ? local : ".", W_OK);
795 			if (dir != NULL)
796 				*dir = '/';
797 			if (d < 0) {
798 				warn("local: %s", local);
799 				(void)signal(SIGINT, oldintr);
800 				(void)signal(SIGINFO, oldinti);
801 				code = -1;
802 				return;
803 			}
804 			if (!runique && errno == EACCES &&
805 			    chmod(local, 0600) < 0) {
806 				warn("local: %s", local);
807 				(void)signal(SIGINT, oldintr);
808 				(void)signal(SIGINFO, oldinti);
809 				code = -1;
810 				return;
811 			}
812 			if (runique && errno == EACCES &&
813 			   (local = gunique(local)) == NULL) {
814 				(void)signal(SIGINT, oldintr);
815 				(void)signal(SIGINFO, oldinti);
816 				code = -1;
817 				return;
818 			}
819 		}
820 		else if (runique && (local = gunique(local)) == NULL) {
821 			(void)signal(SIGINT, oldintr);
822 			(void)signal(SIGINFO, oldinti);
823 			code = -1;
824 			return;
825 		}
826 	}
827 	if (!is_retr) {
828 		if (curtype != TYPE_A)
829 			changetype(TYPE_A, 0);
830 	} else {
831 		if (curtype != type)
832 			changetype(type, 0);
833 		filesize = remotesize(remote, 0);
834 	}
835 	if (initconn()) {
836 		(void)signal(SIGINT, oldintr);
837 		(void)signal(SIGINFO, oldinti);
838 		code = -1;
839 		return;
840 	}
841 	if (setjmp(recvabort))
842 		goto abort;
843 	if (is_retr && restart_point &&
844 	    command("REST %ld", (long) restart_point) != CONTINUE)
845 		return;
846 	if (remote) {
847 		if (command("%s %s", cmd, remote) != PRELIM) {
848 			(void)signal(SIGINT, oldintr);
849 			(void)signal(SIGINFO, oldinti);
850 			return;
851 		}
852 	} else {
853 		if (command("%s", cmd) != PRELIM) {
854 			(void)signal(SIGINT, oldintr);
855 			(void)signal(SIGINFO, oldinti);
856 			return;
857 		}
858 	}
859 	din = dataconn("r");
860 	if (din == NULL)
861 		goto abort;
862 	if (!ignorespecial && strcmp(local, "-") == 0) {
863 		fout = stdout;
864 		progress = 0;
865 		preserve = 0;
866 	} else if (!ignorespecial && *local == '|') {
867 		oldintp = signal(SIGPIPE, SIG_IGN);
868 		fout = popen(local + 1, "w");
869 		if (fout == NULL) {
870 			warn("%s", local+1);
871 			goto abort;
872 		}
873 		progress = 0;
874 		preserve = 0;
875 		closefunc = pclose;
876 	} else {
877 		fout = fopen(local, lmode);
878 		if (fout == NULL) {
879 			warn("local: %s", local);
880 			goto abort;
881 		}
882 		closefunc = fclose;
883 	}
884 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
885 		st.st_blksize = BUFSIZ;
886 	if (st.st_blksize > bufsize) {
887 		if (buf)
888 			(void)free(buf);
889 		buf = malloc((unsigned)st.st_blksize);
890 		if (buf == NULL) {
891 			warn("malloc");
892 			bufsize = 0;
893 			goto abort;
894 		}
895 		bufsize = st.st_blksize;
896 	}
897 	if (!S_ISREG(st.st_mode)) {
898 		progress = 0;
899 		preserve = 0;
900 	}
901 	progressmeter(-1);
902 	switch (curtype) {
903 
904 	case TYPE_I:
905 	case TYPE_L:
906 		if (restart_point &&
907 		    lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
908 			warn("local: %s", local);
909 			progress = oprogress;
910 			preserve = opreserve;
911 			if (closefunc != NULL)
912 				(*closefunc)(fout);
913 			return;
914 		}
915 		errno = d = 0;
916 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
917 			if ((d = write(fileno(fout), buf, c)) != c)
918 				break;
919 			bytes += c;
920 			if (hash && (!progress || filesize < 0)) {
921 				while (bytes >= hashbytes) {
922 					(void)putchar('#');
923 					hashbytes += mark;
924 				}
925 				(void)fflush(stdout);
926 			}
927 		}
928 		if (hash && (!progress || filesize < 0) && bytes > 0) {
929 			if (bytes < mark)
930 				(void)putchar('#');
931 			(void)putchar('\n');
932 			(void)fflush(stdout);
933 		}
934 		if (c < 0) {
935 			if (errno != EPIPE)
936 				warn("netin");
937 			bytes = -1;
938 		}
939 		if (d < c) {
940 			if (d < 0)
941 				warn("local: %s", local);
942 			else
943 				warnx("%s: short write", local);
944 		}
945 		break;
946 
947 	case TYPE_A:
948 		if (restart_point) {
949 			int i, n, ch;
950 
951 			if (fseek(fout, 0L, SEEK_SET) < 0)
952 				goto done;
953 			n = restart_point;
954 			for (i = 0; i++ < n;) {
955 				if ((ch = getc(fout)) == EOF)
956 					goto done;
957 				if (ch == '\n')
958 					i++;
959 			}
960 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
961 done:
962 				warn("local: %s", local);
963 				progress = oprogress;
964 				preserve = opreserve;
965 				if (closefunc != NULL)
966 					(*closefunc)(fout);
967 				return;
968 			}
969 		}
970 		while ((c = getc(din)) != EOF) {
971 			if (c == '\n')
972 				bare_lfs++;
973 			while (c == '\r') {
974 				while (hash && (!progress || filesize < 0) &&
975 				    (bytes >= hashbytes)) {
976 					(void)putchar('#');
977 					(void)fflush(stdout);
978 					hashbytes += mark;
979 				}
980 				bytes++;
981 				if ((c = getc(din)) != '\n' || tcrflag) {
982 					if (ferror(fout))
983 						goto break2;
984 					(void)putc('\r', fout);
985 					if (c == '\0') {
986 						bytes++;
987 						goto contin2;
988 					}
989 					if (c == EOF)
990 						goto contin2;
991 				}
992 			}
993 			(void)putc(c, fout);
994 			bytes++;
995 	contin2:	;
996 		}
997 break2:
998 		if (bare_lfs) {
999 			printf(
1000 "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1001 			puts("File may not have transferred correctly.");
1002 		}
1003 		if (hash && (!progress || filesize < 0)) {
1004 			if (bytes < hashbytes)
1005 				(void)putchar('#');
1006 			(void)putchar('\n');
1007 			(void)fflush(stdout);
1008 		}
1009 		if (ferror(din)) {
1010 			if (errno != EPIPE)
1011 				warn("netin");
1012 			bytes = -1;
1013 		}
1014 		if (ferror(fout))
1015 			warn("local: %s", local);
1016 		break;
1017 	}
1018 	progressmeter(1);
1019 	progress = oprogress;
1020 	preserve = opreserve;
1021 	if (closefunc != NULL)
1022 		(*closefunc)(fout);
1023 	(void)signal(SIGINT, oldintr);
1024 	(void)signal(SIGINFO, oldinti);
1025 	if (oldintp)
1026 		(void)signal(SIGPIPE, oldintp);
1027 	(void)fclose(din);
1028 	(void)getreply(0);
1029 	if (bytes >= 0 && is_retr) {
1030 		if (bytes > 0)
1031 			ptransfer(0);
1032 		if (preserve && (closefunc == fclose)) {
1033 			mtime = remotemodtime(remote, 0);
1034 			if (mtime != -1) {
1035 				(void)gettimeofday(&tval[0],
1036 				    (struct timezone *)0);
1037 				tval[1].tv_sec = mtime;
1038 				tval[1].tv_usec = 0;
1039 				if (utimes(local, tval) == -1) {
1040 					printf(
1041 				"Can't change modification time on %s to %s",
1042 					    local, asctime(localtime(&mtime)));
1043 				}
1044 			}
1045 		}
1046 	}
1047 	return;
1048 
1049 abort:
1050 
1051 /* abort using RFC959 recommended IP,SYNC sequence */
1052 
1053 	progress = oprogress;
1054 	preserve = opreserve;
1055 	if (oldintp)
1056 		(void)signal(SIGPIPE, oldintp);
1057 	(void)signal(SIGINT, SIG_IGN);
1058 	if (!cpend) {
1059 		code = -1;
1060 		(void)signal(SIGINT, oldintr);
1061 		(void)signal(SIGINFO, oldinti);
1062 		return;
1063 	}
1064 
1065 	abort_remote(din);
1066 	code = -1;
1067 	if (data >= 0) {
1068 		(void)close(data);
1069 		data = -1;
1070 	}
1071 	if (closefunc != NULL && fout != NULL)
1072 		(*closefunc)(fout);
1073 	if (din)
1074 		(void)fclose(din);
1075 	if (bytes > 0)
1076 		ptransfer(0);
1077 	(void)signal(SIGINT, oldintr);
1078 	(void)signal(SIGINFO, oldinti);
1079 }
1080 
1081 /*
1082  * Need to start a listen on the data channel before we send the command,
1083  * otherwise the server's connect may fail.
1084  */
1085 int
1086 initconn()
1087 {
1088 	char *p, *a;
1089 	int result, len, tmpno = 0;
1090 	int on = 1;
1091 	int a0, a1, a2, a3, p0, p1;
1092 
1093 	if (passivemode) {
1094 		data = socket(AF_INET, SOCK_STREAM, 0);
1095 		if (data < 0) {
1096 			warn("socket");
1097 			return (1);
1098 		}
1099 		if ((options & SO_DEBUG) &&
1100 		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1101 			       sizeof(on)) < 0)
1102 			warn("setsockopt (ignored)");
1103 		if (command("PASV") != COMPLETE) {
1104 			puts("Passive mode refused.");
1105 			goto bad;
1106 		}
1107 
1108 		/*
1109 		 * What we've got at this point is a string of comma
1110 		 * separated one-byte unsigned integer values.
1111 		 * The first four are the an IP address. The fifth is
1112 		 * the MSB of the port number, the sixth is the LSB.
1113 		 * From that we'll prepare a sockaddr_in.
1114 		 */
1115 
1116 		if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1117 			   &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1118 			puts(
1119 "Passive mode address scan failure. Shouldn't happen!");
1120 			goto bad;
1121 		}
1122 
1123 		memset(&data_addr, 0, sizeof(data_addr));
1124 		data_addr.sin_family = AF_INET;
1125 		a = (char *)&data_addr.sin_addr.s_addr;
1126 		a[0] = a0 & 0xff;
1127 		a[1] = a1 & 0xff;
1128 		a[2] = a2 & 0xff;
1129 		a[3] = a3 & 0xff;
1130 		p = (char *)&data_addr.sin_port;
1131 		p[0] = p0 & 0xff;
1132 		p[1] = p1 & 0xff;
1133 
1134 		if (connect(data, (struct sockaddr *)&data_addr,
1135 			    sizeof(data_addr)) < 0) {
1136 			warn("connect");
1137 			goto bad;
1138 		}
1139 #ifdef IP_TOS
1140 		on = IPTOS_THROUGHPUT;
1141 		if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1142 			       sizeof(int)) < 0)
1143 			warn("setsockopt TOS (ignored)");
1144 #endif
1145 		return (0);
1146 	}
1147 
1148 noport:
1149 	data_addr = myctladdr;
1150 	if (sendport)
1151 		data_addr.sin_port = 0;	/* let system pick one */
1152 	if (data != -1)
1153 		(void)close(data);
1154 	data = socket(AF_INET, SOCK_STREAM, 0);
1155 	if (data < 0) {
1156 		warn("socket");
1157 		if (tmpno)
1158 			sendport = 1;
1159 		return (1);
1160 	}
1161 	if (!sendport)
1162 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1163 				sizeof(on)) < 0) {
1164 			warn("setsockopt (reuse address)");
1165 			goto bad;
1166 		}
1167 	if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1168 		warn("bind");
1169 		goto bad;
1170 	}
1171 	if (options & SO_DEBUG &&
1172 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1173 			sizeof(on)) < 0)
1174 		warn("setsockopt (ignored)");
1175 	len = sizeof(data_addr);
1176 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1177 		warn("getsockname");
1178 		goto bad;
1179 	}
1180 	if (listen(data, 1) < 0)
1181 		warn("listen");
1182 	if (sendport) {
1183 		a = (char *)&data_addr.sin_addr;
1184 		p = (char *)&data_addr.sin_port;
1185 #define	UC(b)	(((int)b)&0xff)
1186 		result =
1187 		    command("PORT %d,%d,%d,%d,%d,%d",
1188 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1189 		      UC(p[0]), UC(p[1]));
1190 		if (result == ERROR && sendport == -1) {
1191 			sendport = 0;
1192 			tmpno = 1;
1193 			goto noport;
1194 		}
1195 		return (result != COMPLETE);
1196 	}
1197 	if (tmpno)
1198 		sendport = 1;
1199 #ifdef IP_TOS
1200 	on = IPTOS_THROUGHPUT;
1201 	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1202 		warn("setsockopt TOS (ignored)");
1203 #endif
1204 	return (0);
1205 bad:
1206 	(void)close(data), data = -1;
1207 	if (tmpno)
1208 		sendport = 1;
1209 	return (1);
1210 }
1211 
1212 FILE *
1213 dataconn(lmode)
1214 	const char *lmode;
1215 {
1216 	struct sockaddr_in from;
1217 	int s, fromlen, tos;
1218 
1219 	fromlen = sizeof(from);
1220 
1221 	if (passivemode)
1222 		return (fdopen(data, lmode));
1223 
1224 	s = accept(data, (struct sockaddr *) &from, &fromlen);
1225 	if (s < 0) {
1226 		warn("accept");
1227 		(void)close(data), data = -1;
1228 		return (NULL);
1229 	}
1230 	(void)close(data);
1231 	data = s;
1232 #ifdef IP_TOS
1233 	tos = IPTOS_THROUGHPUT;
1234 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1235 		warn("setsockopt TOS (ignored)");
1236 #endif
1237 	return (fdopen(data, lmode));
1238 }
1239 
1240 void
1241 psummary(notused)
1242 	int notused;
1243 {
1244 
1245 	if (bytes > 0)
1246 		ptransfer(1);
1247 }
1248 
1249 void
1250 psabort(notused)
1251 	int notused;
1252 {
1253 
1254 	alarmtimer(0);
1255 	abrtflag++;
1256 }
1257 
1258 void
1259 pswitch(flag)
1260 	int flag;
1261 {
1262 	sig_t oldintr;
1263 	static struct comvars {
1264 		int connect;
1265 		char name[MAXHOSTNAMELEN];
1266 		struct sockaddr_in mctl;
1267 		struct sockaddr_in hctl;
1268 		FILE *in;
1269 		FILE *out;
1270 		int tpe;
1271 		int curtpe;
1272 		int cpnd;
1273 		int sunqe;
1274 		int runqe;
1275 		int mcse;
1276 		int ntflg;
1277 		char nti[17];
1278 		char nto[17];
1279 		int mapflg;
1280 		char mi[MAXPATHLEN];
1281 		char mo[MAXPATHLEN];
1282 	} proxstruct, tmpstruct;
1283 	struct comvars *ip, *op;
1284 
1285 	abrtflag = 0;
1286 	oldintr = signal(SIGINT, psabort);
1287 	if (flag) {
1288 		if (proxy)
1289 			return;
1290 		ip = &tmpstruct;
1291 		op = &proxstruct;
1292 		proxy++;
1293 	} else {
1294 		if (!proxy)
1295 			return;
1296 		ip = &proxstruct;
1297 		op = &tmpstruct;
1298 		proxy = 0;
1299 	}
1300 	ip->connect = connected;
1301 	connected = op->connect;
1302 	if (hostname) {
1303 		(void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1304 		ip->name[sizeof(ip->name) - 1] = '\0';
1305 	} else
1306 		ip->name[0] = '\0';
1307 	hostname = op->name;
1308 	ip->hctl = hisctladdr;
1309 	hisctladdr = op->hctl;
1310 	ip->mctl = myctladdr;
1311 	myctladdr = op->mctl;
1312 	ip->in = cin;
1313 	cin = op->in;
1314 	ip->out = cout;
1315 	cout = op->out;
1316 	ip->tpe = type;
1317 	type = op->tpe;
1318 	ip->curtpe = curtype;
1319 	curtype = op->curtpe;
1320 	ip->cpnd = cpend;
1321 	cpend = op->cpnd;
1322 	ip->sunqe = sunique;
1323 	sunique = op->sunqe;
1324 	ip->runqe = runique;
1325 	runique = op->runqe;
1326 	ip->mcse = mcase;
1327 	mcase = op->mcse;
1328 	ip->ntflg = ntflag;
1329 	ntflag = op->ntflg;
1330 	(void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1331 	(ip->nti)[sizeof(ip->nti) - 1] = '\0';
1332 	(void)strcpy(ntin, op->nti);
1333 	(void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1334 	(ip->nto)[sizeof(ip->nto) - 1] = '\0';
1335 	(void)strcpy(ntout, op->nto);
1336 	ip->mapflg = mapflag;
1337 	mapflag = op->mapflg;
1338 	(void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1339 	(ip->mi)[sizeof(ip->mi) - 1] = '\0';
1340 	(void)strcpy(mapin, op->mi);
1341 	(void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1342 	(ip->mo)[sizeof(ip->mo) - 1] = '\0';
1343 	(void)strcpy(mapout, op->mo);
1344 	(void)signal(SIGINT, oldintr);
1345 	if (abrtflag) {
1346 		abrtflag = 0;
1347 		(*oldintr)(SIGINT);
1348 	}
1349 }
1350 
1351 void
1352 abortpt(notused)
1353 	int notused;
1354 {
1355 
1356 	alarmtimer(0);
1357 	putchar('\n');
1358 	(void)fflush(stdout);
1359 	ptabflg++;
1360 	mflag = 0;
1361 	abrtflag = 0;
1362 	longjmp(ptabort, 1);
1363 }
1364 
1365 void
1366 proxtrans(cmd, local, remote)
1367 	const char *cmd, *local, *remote;
1368 {
1369 	sig_t oldintr;
1370 	int prox_type, nfnd;
1371 	volatile int secndflag;
1372 	char *cmd2;
1373 	struct fd_set mask;
1374 
1375 #ifdef __GNUC__			/* XXX: to shut up gcc warnings */
1376 	(void)&oldintr;
1377 	(void)&cmd2;
1378 #endif
1379 
1380 	oldintr = NULL;
1381 	secndflag = 0;
1382 	if (strcmp(cmd, "RETR"))
1383 		cmd2 = "RETR";
1384 	else
1385 		cmd2 = runique ? "STOU" : "STOR";
1386 	if ((prox_type = type) == 0) {
1387 		if (unix_server && unix_proxy)
1388 			prox_type = TYPE_I;
1389 		else
1390 			prox_type = TYPE_A;
1391 	}
1392 	if (curtype != prox_type)
1393 		changetype(prox_type, 1);
1394 	if (command("PASV") != COMPLETE) {
1395 		puts("proxy server does not support third party transfers.");
1396 		return;
1397 	}
1398 	pswitch(0);
1399 	if (!connected) {
1400 		puts("No primary connection.");
1401 		pswitch(1);
1402 		code = -1;
1403 		return;
1404 	}
1405 	if (curtype != prox_type)
1406 		changetype(prox_type, 1);
1407 	if (command("PORT %s", pasv) != COMPLETE) {
1408 		pswitch(1);
1409 		return;
1410 	}
1411 	if (setjmp(ptabort))
1412 		goto abort;
1413 	oldintr = signal(SIGINT, abortpt);
1414 	if (command("%s %s", cmd, remote) != PRELIM) {
1415 		(void)signal(SIGINT, oldintr);
1416 		pswitch(1);
1417 		return;
1418 	}
1419 	sleep(2);
1420 	pswitch(1);
1421 	secndflag++;
1422 	if (command("%s %s", cmd2, local) != PRELIM)
1423 		goto abort;
1424 	ptflag++;
1425 	(void)getreply(0);
1426 	pswitch(0);
1427 	(void)getreply(0);
1428 	(void)signal(SIGINT, oldintr);
1429 	pswitch(1);
1430 	ptflag = 0;
1431 	printf("local: %s remote: %s\n", local, remote);
1432 	return;
1433 abort:
1434 	(void)signal(SIGINT, SIG_IGN);
1435 	ptflag = 0;
1436 	if (strcmp(cmd, "RETR") && !proxy)
1437 		pswitch(1);
1438 	else if (!strcmp(cmd, "RETR") && proxy)
1439 		pswitch(0);
1440 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1441 		if (command("%s %s", cmd2, local) != PRELIM) {
1442 			pswitch(0);
1443 			if (cpend)
1444 				abort_remote((FILE *) NULL);
1445 		}
1446 		pswitch(1);
1447 		if (ptabflg)
1448 			code = -1;
1449 		(void)signal(SIGINT, oldintr);
1450 		return;
1451 	}
1452 	if (cpend)
1453 		abort_remote((FILE *) NULL);
1454 	pswitch(!proxy);
1455 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1456 		if (command("%s %s", cmd2, local) != PRELIM) {
1457 			pswitch(0);
1458 			if (cpend)
1459 				abort_remote((FILE *) NULL);
1460 			pswitch(1);
1461 			if (ptabflg)
1462 				code = -1;
1463 			(void)signal(SIGINT, oldintr);
1464 			return;
1465 		}
1466 	}
1467 	if (cpend)
1468 		abort_remote((FILE *) NULL);
1469 	pswitch(!proxy);
1470 	if (cpend) {
1471 		FD_ZERO(&mask);
1472 		FD_SET(fileno(cin), &mask);
1473 		if ((nfnd = empty(&mask, 10)) <= 0) {
1474 			if (nfnd < 0) {
1475 				warn("abort");
1476 			}
1477 			if (ptabflg)
1478 				code = -1;
1479 			lostpeer();
1480 		}
1481 		(void)getreply(0);
1482 		(void)getreply(0);
1483 	}
1484 	if (proxy)
1485 		pswitch(0);
1486 	pswitch(1);
1487 	if (ptabflg)
1488 		code = -1;
1489 	(void)signal(SIGINT, oldintr);
1490 }
1491 
1492 void
1493 reset(argc, argv)
1494 	int argc;
1495 	char *argv[];
1496 {
1497 	struct fd_set mask;
1498 	int nfnd = 1;
1499 
1500 	FD_ZERO(&mask);
1501 	while (nfnd > 0) {
1502 		FD_SET(fileno(cin), &mask);
1503 		if ((nfnd = empty(&mask, 0)) < 0) {
1504 			warn("reset");
1505 			code = -1;
1506 			lostpeer();
1507 		}
1508 		else if (nfnd) {
1509 			(void)getreply(0);
1510 		}
1511 	}
1512 }
1513 
1514 char *
1515 gunique(local)
1516 	const char *local;
1517 {
1518 	static char new[MAXPATHLEN];
1519 	char *cp = strrchr(local, '/');
1520 	int d, count=0;
1521 	char ext = '1';
1522 
1523 	if (cp)
1524 		*cp = '\0';
1525 	d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1526 	if (cp)
1527 		*cp = '/';
1528 	if (d < 0) {
1529 		warn("local: %s", local);
1530 		return ((char *) 0);
1531 	}
1532 	(void)strcpy(new, local);
1533 	cp = new + strlen(new);
1534 	*cp++ = '.';
1535 	while (!d) {
1536 		if (++count == 100) {
1537 			puts("runique: can't find unique file name.");
1538 			return ((char *) 0);
1539 		}
1540 		*cp++ = ext;
1541 		*cp = '\0';
1542 		if (ext == '9')
1543 			ext = '0';
1544 		else
1545 			ext++;
1546 		if ((d = access(new, F_OK)) < 0)
1547 			break;
1548 		if (ext != '0')
1549 			cp--;
1550 		else if (*(cp - 2) == '.')
1551 			*(cp - 1) = '1';
1552 		else {
1553 			*(cp - 2) = *(cp - 2) + 1;
1554 			cp--;
1555 		}
1556 	}
1557 	return (new);
1558 }
1559 
1560 void
1561 abort_remote(din)
1562 	FILE *din;
1563 {
1564 	char buf[BUFSIZ];
1565 	int nfnd;
1566 	struct fd_set mask;
1567 
1568 	if (cout == NULL) {
1569 		warnx("Lost control connection for abort.");
1570 		if (ptabflg)
1571 			code = -1;
1572 		lostpeer();
1573 		return;
1574 	}
1575 	/*
1576 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1577 	 * after urgent byte rather than before as is protocol now
1578 	 */
1579 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
1580 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1581 		warn("abort");
1582 	fprintf(cout, "%cABOR\r\n", DM);
1583 	(void)fflush(cout);
1584 	FD_ZERO(&mask);
1585 	FD_SET(fileno(cin), &mask);
1586 	if (din) {
1587 		FD_SET(fileno(din), &mask);
1588 	}
1589 	if ((nfnd = empty(&mask, 10)) <= 0) {
1590 		if (nfnd < 0) {
1591 			warn("abort");
1592 		}
1593 		if (ptabflg)
1594 			code = -1;
1595 		lostpeer();
1596 	}
1597 	if (din && FD_ISSET(fileno(din), &mask)) {
1598 		while (read(fileno(din), buf, BUFSIZ) > 0)
1599 			/* LOOP */;
1600 	}
1601 	if (getreply(0) == ERROR && code == 552) {
1602 		/* 552 needed for nic style abort */
1603 		(void)getreply(0);
1604 	}
1605 	(void)getreply(0);
1606 }
1607