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