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