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