155682Smarkm/*
255682Smarkm * Copyright (c) 1985, 1989, 1993, 1994
355682Smarkm *	The Regents of the University of California.  All rights reserved.
455682Smarkm *
555682Smarkm * Redistribution and use in source and binary forms, with or without
655682Smarkm * modification, are permitted provided that the following conditions
755682Smarkm * are met:
855682Smarkm * 1. Redistributions of source code must retain the above copyright
955682Smarkm *    notice, this list of conditions and the following disclaimer.
1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer in the
1255682Smarkm *    documentation and/or other materials provided with the distribution.
1355682Smarkm * 3. All advertising materials mentioning features or use of this software
1455682Smarkm *    must display the following acknowledgement:
1555682Smarkm *	This product includes software developed by the University of
1655682Smarkm *	California, Berkeley and its contributors.
1755682Smarkm * 4. Neither the name of the University nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "ftp_locl.h"
35233294SstasRCSID ("$Id$");
3655682Smarkm
3755682Smarkmstruct sockaddr_storage hisctladdr_ss;
3855682Smarkmstruct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss;
3955682Smarkmstruct sockaddr_storage data_addr_ss;
4055682Smarkmstruct sockaddr *data_addr  = (struct sockaddr *)&data_addr_ss;
4155682Smarkmstruct sockaddr_storage myctladdr_ss;
4255682Smarkmstruct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss;
4355682Smarkmint data = -1;
4455682Smarkmint abrtflag = 0;
4555682Smarkmjmp_buf ptabort;
4655682Smarkmint ptabflg;
4755682Smarkmint ptflag = 0;
4855682Smarkmoff_t restart_point = 0;
4955682Smarkm
5055682Smarkm
5155682SmarkmFILE *cin, *cout;
5255682Smarkm
5355682Smarkmtypedef void (*sighand) (int);
5455682Smarkm
5555682Smarkmchar *
5655682Smarkmhookup (const char *host, int port)
5755682Smarkm{
5855682Smarkm    static char hostnamebuf[MaxHostNameLen];
5955682Smarkm    struct addrinfo *ai, *a;
6055682Smarkm    struct addrinfo hints;
6155682Smarkm    int error;
6255682Smarkm    char portstr[NI_MAXSERV];
6372445Sassar    socklen_t len;
6455682Smarkm    int s;
6555682Smarkm
6655682Smarkm    memset (&hints, 0, sizeof(hints));
6755682Smarkm    hints.ai_socktype = SOCK_STREAM;
6855682Smarkm    hints.ai_protocol = IPPROTO_TCP;
6955682Smarkm    hints.ai_flags    = AI_CANONNAME;
7055682Smarkm
7155682Smarkm    snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
7255682Smarkm
7355682Smarkm    error = getaddrinfo (host, portstr, &hints, &ai);
7455682Smarkm    if (error) {
7555682Smarkm	warnx ("%s: %s", host, gai_strerror(error));
7655682Smarkm	code = -1;
7755682Smarkm	return NULL;
7855682Smarkm    }
7955682Smarkm    strlcpy (hostnamebuf, host, sizeof(hostnamebuf));
8055682Smarkm    hostname = hostnamebuf;
8155682Smarkm
82178825Sdfr    s = -1;
8355682Smarkm    for (a = ai; a != NULL; a = a->ai_next) {
8455682Smarkm	s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
8555682Smarkm	if (s < 0)
8655682Smarkm	    continue;
8755682Smarkm
8855682Smarkm	if (a->ai_canonname != NULL)
8955682Smarkm	    strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf));
9055682Smarkm
9155682Smarkm	memcpy (hisctladdr, a->ai_addr, a->ai_addrlen);
92233294Sstas
9355682Smarkm	error = connect (s, a->ai_addr, a->ai_addrlen);
9455682Smarkm	if (error < 0) {
9555682Smarkm	    char addrstr[256];
9655682Smarkm
9755682Smarkm	    if (getnameinfo (a->ai_addr, a->ai_addrlen,
9855682Smarkm			     addrstr, sizeof(addrstr),
9955682Smarkm			     NULL, 0, NI_NUMERICHOST) != 0)
10055682Smarkm		strlcpy (addrstr, "unknown address", sizeof(addrstr));
101233294Sstas
10255682Smarkm	    warn ("connect %s", addrstr);
10355682Smarkm	    close (s);
104178825Sdfr	    s = -1;
10555682Smarkm	    continue;
10655682Smarkm	}
10755682Smarkm	break;
10855682Smarkm    }
10955682Smarkm    freeaddrinfo (ai);
110178825Sdfr    if (s < 0) {
11155682Smarkm	warnx ("failed to contact %s", host);
11255682Smarkm	code = -1;
11355682Smarkm	return NULL;
11455682Smarkm    }
11555682Smarkm
11655682Smarkm    len = sizeof(myctladdr_ss);
11755682Smarkm    if (getsockname (s, myctladdr, &len) < 0) {
11855682Smarkm	warn ("getsockname");
11955682Smarkm	code = -1;
12055682Smarkm	close (s);
12155682Smarkm	return NULL;
12255682Smarkm    }
12355682Smarkm#ifdef IPTOS_LOWDELAY
12455682Smarkm    socket_set_tos (s, IPTOS_LOWDELAY);
12555682Smarkm#endif
12655682Smarkm    cin = fdopen (s, "r");
12755682Smarkm    cout = fdopen (s, "w");
12855682Smarkm    if (cin == NULL || cout == NULL) {
12955682Smarkm	warnx ("fdopen failed.");
13055682Smarkm	if (cin)
13155682Smarkm	    fclose (cin);
13255682Smarkm	if (cout)
13355682Smarkm	    fclose (cout);
13455682Smarkm	code = -1;
13555682Smarkm	goto bad;
13655682Smarkm    }
13755682Smarkm    if (verbose)
13855682Smarkm	printf ("Connected to %s.\n", hostname);
13955682Smarkm    if (getreply (0) > 2) {	/* read startup message from server */
14055682Smarkm	if (cin)
14155682Smarkm	    fclose (cin);
14255682Smarkm	if (cout)
14355682Smarkm	    fclose (cout);
14455682Smarkm	code = -1;
14555682Smarkm	goto bad;
14655682Smarkm    }
14755682Smarkm#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
14855682Smarkm    {
14955682Smarkm	int on = 1;
15055682Smarkm
15155682Smarkm	if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on))
15255682Smarkm	    < 0 && debug) {
15355682Smarkm	    warn ("setsockopt");
15455682Smarkm	}
15555682Smarkm    }
15655682Smarkm#endif				/* SO_OOBINLINE */
15755682Smarkm
15855682Smarkm    return (hostname);
15955682Smarkmbad:
16055682Smarkm    close (s);
16155682Smarkm    return NULL;
16255682Smarkm}
16355682Smarkm
16455682Smarkmint
16555682Smarkmlogin (char *host)
16655682Smarkm{
16755682Smarkm    char tmp[80];
16855682Smarkm    char defaultpass[128];
169178825Sdfr    char *userstr, *pass, *acctstr;
170233294Sstas    char *ruserstr, *rpass, *racctstr;
17155682Smarkm    int n, aflag = 0;
17255682Smarkm
17355682Smarkm    char *myname = NULL;
17455682Smarkm    struct passwd *pw = k_getpwuid(getuid());
17555682Smarkm
17655682Smarkm    if (pw != NULL)
17755682Smarkm	myname = pw->pw_name;
17855682Smarkm
179233294Sstas    ruserstr = rpass = racctstr = NULL;
18055682Smarkm
18155682Smarkm    if(sec_login(host))
18255682Smarkm	printf("\n*** Using plaintext user and password ***\n\n");
18355682Smarkm    else{
18455682Smarkm	printf("Authentication successful.\n\n");
18555682Smarkm    }
18655682Smarkm
187233294Sstas    if (ruserpassword (host, &ruserstr, &rpass, &racctstr) < 0) {
18855682Smarkm	code = -1;
18955682Smarkm	return (0);
19055682Smarkm    }
191233294Sstas    userstr = ruserstr;
192233294Sstas    pass = rpass;
193233294Sstas    acctstr = racctstr;
194233294Sstas
195178825Sdfr    while (userstr == NULL) {
19655682Smarkm	if (myname)
19755682Smarkm	    printf ("Name (%s:%s): ", host, myname);
19855682Smarkm	else
19955682Smarkm	    printf ("Name (%s): ", host);
20072445Sassar	*tmp = '\0';
20172445Sassar	if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL)
20272445Sassar	    tmp[strlen (tmp) - 1] = '\0';
20355682Smarkm	if (*tmp == '\0')
204178825Sdfr	    userstr = myname;
20555682Smarkm	else
206178825Sdfr	    userstr = tmp;
20755682Smarkm    }
208178825Sdfr    strlcpy(username, userstr, sizeof(username));
209233294Sstas    if (ruserstr)
210233294Sstas	free(ruserstr);
211233294Sstas
212178825Sdfr    n = command("USER %s", userstr);
213233294Sstas    if (n == COMPLETE)
21472445Sassar       n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */
21572445Sassar    else if(n == CONTINUE) {
21672445Sassar	if (pass == NULL) {
21755682Smarkm	    char prompt[128];
218233294Sstas	    if(myname &&
219178825Sdfr	       (!strcmp(userstr, "ftp") || !strcmp(userstr, "anonymous"))) {
220233294Sstas		snprintf(defaultpass, sizeof(defaultpass),
22155682Smarkm			 "%s@%s", myname, mydomain);
222233294Sstas		snprintf(prompt, sizeof(prompt),
22355682Smarkm			 "Password (%s): ", defaultpass);
22472445Sassar	    } else if (sec_complete) {
22572445Sassar		pass = myname;
22672445Sassar	    } else {
22755682Smarkm		*defaultpass = '\0';
22855682Smarkm		snprintf(prompt, sizeof(prompt), "Password: ");
22955682Smarkm	    }
23072445Sassar	    if (pass == NULL) {
23172445Sassar		pass = defaultpass;
232178825Sdfr		UI_UTIL_read_pw_string (tmp, sizeof (tmp), prompt, 0);
23372445Sassar		if (tmp[0])
23472445Sassar		    pass = tmp;
23572445Sassar	    }
23655682Smarkm	}
23755682Smarkm	n = command ("PASS %s", pass);
238233294Sstas	if (rpass)
239233294Sstas	    free(rpass);
24055682Smarkm    }
24155682Smarkm    if (n == CONTINUE) {
24255682Smarkm	aflag++;
243233294Sstas	UI_UTIL_read_pw_string (tmp, sizeof(tmp), "Account:", 0);
244178825Sdfr	acctstr = tmp;
245178825Sdfr	n = command ("ACCT %s", acctstr);
24655682Smarkm    }
24755682Smarkm    if (n != COMPLETE) {
248233294Sstas	if (racctstr)
249233294Sstas	    free(racctstr);
25055682Smarkm	warnx ("Login failed.");
25155682Smarkm	return (0);
25255682Smarkm    }
253178825Sdfr    if (!aflag && acctstr != NULL)
254178825Sdfr	command ("ACCT %s", acctstr);
255233294Sstas    if (racctstr)
256233294Sstas	free(racctstr);
25755682Smarkm    if (proxy)
25855682Smarkm	return (1);
25955682Smarkm    for (n = 0; n < macnum; ++n) {
26055682Smarkm	if (!strcmp("init", macros[n].mac_name)) {
26155682Smarkm	    strlcpy (line, "$init", sizeof (line));
26255682Smarkm	    makeargv();
26355682Smarkm	    domacro(margc, margv);
26455682Smarkm	    break;
26555682Smarkm	}
26655682Smarkm    }
26755682Smarkm    sec_set_protection_level ();
26855682Smarkm    return (1);
26955682Smarkm}
27055682Smarkm
27155682Smarkmvoid
27255682Smarkmcmdabort (int sig)
27355682Smarkm{
27455682Smarkm
27555682Smarkm    printf ("\n");
27655682Smarkm    fflush (stdout);
27755682Smarkm    abrtflag++;
27855682Smarkm    if (ptflag)
27955682Smarkm	longjmp (ptabort, 1);
28055682Smarkm}
28155682Smarkm
28255682Smarkmint
28355682Smarkmcommand (char *fmt,...)
28455682Smarkm{
28555682Smarkm    va_list ap;
28655682Smarkm    int r;
28755682Smarkm    sighand oldintr;
28855682Smarkm
28955682Smarkm    abrtflag = 0;
29055682Smarkm    if (cout == NULL) {
29155682Smarkm	warn ("No control connection for command");
29255682Smarkm	code = -1;
29355682Smarkm	return (0);
29455682Smarkm    }
29555682Smarkm    oldintr = signal(SIGINT, cmdabort);
29655682Smarkm    if(debug){
29755682Smarkm	printf("---> ");
29855682Smarkm	if (strncmp("PASS ", fmt, 5) == 0)
29955682Smarkm	    printf("PASS XXXX");
300102644Snectar	else {
301102644Snectar	    va_start(ap, fmt);
30255682Smarkm	    vfprintf(stdout, fmt, ap);
303102644Snectar	    va_end(ap);
304102644Snectar	}
30555682Smarkm    }
306102644Snectar    va_start(ap, fmt);
30755682Smarkm    sec_vfprintf(cout, fmt, ap);
30855682Smarkm    va_end(ap);
30955682Smarkm    if(debug){
31055682Smarkm	printf("\n");
31155682Smarkm	fflush(stdout);
31255682Smarkm    }
31355682Smarkm    fprintf (cout, "\r\n");
31455682Smarkm    fflush (cout);
31555682Smarkm    cpend = 1;
31655682Smarkm    r = getreply (!strcmp (fmt, "QUIT"));
31755682Smarkm    if (abrtflag && oldintr != SIG_IGN)
31855682Smarkm	(*oldintr) (SIGINT);
31955682Smarkm    signal (SIGINT, oldintr);
32055682Smarkm    return (r);
32155682Smarkm}
32255682Smarkm
32355682Smarkmchar reply_string[BUFSIZ];	/* last line of previous reply */
32455682Smarkm
32555682Smarkmint
32655682Smarkmgetreply (int expecteof)
32755682Smarkm{
32855682Smarkm    char *p;
32955682Smarkm    char *lead_string;
33055682Smarkm    int c;
33155682Smarkm    struct sigaction sa, osa;
332102644Snectar    char buf[8192];
333102644Snectar    int reply_code;
334102644Snectar    int long_warn = 0;
33555682Smarkm
33655682Smarkm    sigemptyset (&sa.sa_mask);
33755682Smarkm    sa.sa_flags = 0;
33855682Smarkm    sa.sa_handler = cmdabort;
33955682Smarkm    sigaction (SIGINT, &sa, &osa);
34055682Smarkm
34155682Smarkm    p = buf;
34255682Smarkm
343102644Snectar    reply_code = 0;
34455682Smarkm    while (1) {
34555682Smarkm	c = getc (cin);
34655682Smarkm	switch (c) {
34755682Smarkm	case EOF:
34855682Smarkm	    if (expecteof) {
34955682Smarkm		sigaction (SIGINT, &osa, NULL);
35055682Smarkm		code = 221;
35155682Smarkm		return 0;
35255682Smarkm	    }
35355682Smarkm	    lostpeer (0);
35455682Smarkm	    if (verbose) {
35555682Smarkm		printf ("421 Service not available, "
35655682Smarkm			"remote server has closed connection\n");
35755682Smarkm		fflush (stdout);
35855682Smarkm	    }
35955682Smarkm	    code = 421;
36055682Smarkm	    return (4);
36155682Smarkm	case IAC:
36255682Smarkm	    c = getc (cin);
36355682Smarkm	    if (c == WILL || c == WONT)
36455682Smarkm		fprintf (cout, "%c%c%c", IAC, DONT, getc (cin));
36555682Smarkm	    if (c == DO || c == DONT)
36655682Smarkm		fprintf (cout, "%c%c%c", IAC, WONT, getc (cin));
36755682Smarkm	    continue;
36855682Smarkm	case '\n':
36955682Smarkm	    *p++ = '\0';
370178825Sdfr	    if(isdigit((unsigned char)buf[0])){
37155682Smarkm		sscanf(buf, "%d", &code);
37255682Smarkm		if(code == 631){
373102644Snectar		    code = 0;
37455682Smarkm		    sec_read_msg(buf, prot_safe);
37555682Smarkm		    sscanf(buf, "%d", &code);
37655682Smarkm		    lead_string = "S:";
37755682Smarkm		} else if(code == 632){
378102644Snectar		    code = 0;
37955682Smarkm		    sec_read_msg(buf, prot_private);
38055682Smarkm		    sscanf(buf, "%d", &code);
38155682Smarkm		    lead_string = "P:";
38255682Smarkm		}else if(code == 633){
383102644Snectar		    code = 0;
38455682Smarkm		    sec_read_msg(buf, prot_confidential);
38555682Smarkm		    sscanf(buf, "%d", &code);
38655682Smarkm		    lead_string = "C:";
38755682Smarkm		}else if(sec_complete)
38855682Smarkm		    lead_string = "!!";
38955682Smarkm		else
39055682Smarkm		    lead_string = "";
391102644Snectar		if(code != 0 && reply_code == 0)
392102644Snectar		    reply_code = code;
39355682Smarkm		if (verbose > 0 || (verbose > -1 && code > 499))
39455682Smarkm		    fprintf (stdout, "%s%s\n", lead_string, buf);
395102644Snectar		if (code == reply_code && buf[3] == ' ') {
396102644Snectar		    strlcpy (reply_string, buf, sizeof(reply_string));
39755682Smarkm		    if (code >= 200)
39855682Smarkm			cpend = 0;
39955682Smarkm		    sigaction (SIGINT, &osa, NULL);
40055682Smarkm		    if (code == 421)
40155682Smarkm			lostpeer (0);
40255682Smarkm#if 1
40355682Smarkm		    if (abrtflag &&
40455682Smarkm			osa.sa_handler != cmdabort &&
40555682Smarkm			osa.sa_handler != SIG_IGN)
40655682Smarkm			osa.sa_handler (SIGINT);
40755682Smarkm#endif
40855682Smarkm		    if (code == 227 || code == 229) {
409178825Sdfr			char *q;
41055682Smarkm
411178825Sdfr			q = strchr (reply_string, '(');
412178825Sdfr			if (q) {
413178825Sdfr			    q++;
414178825Sdfr			    strlcpy(pasv, q, sizeof(pasv));
415178825Sdfr			    q = strrchr(pasv, ')');
416178825Sdfr			    if (q)
417178825Sdfr				*q = '\0';
41855682Smarkm			}
41955682Smarkm		    }
42055682Smarkm		    return code / 100;
42155682Smarkm		}
42255682Smarkm	    }else{
42355682Smarkm		if(verbose > 0 || (verbose > -1 && code > 499)){
42455682Smarkm		    if(sec_complete)
42555682Smarkm			fprintf(stdout, "!!");
42655682Smarkm		    fprintf(stdout, "%s\n", buf);
42755682Smarkm		}
42855682Smarkm	    }
42955682Smarkm	    p = buf;
430102644Snectar	    long_warn = 0;
43155682Smarkm	    continue;
43255682Smarkm	default:
433102644Snectar	    if(p < buf + sizeof(buf) - 1)
434233294Sstas		*p++ = c;
435102644Snectar	    else if(long_warn == 0) {
436102644Snectar		fprintf(stderr, "WARNING: incredibly long line received\n");
437102644Snectar		long_warn = 1;
438102644Snectar	    }
43955682Smarkm	}
44055682Smarkm    }
44155682Smarkm
44255682Smarkm}
44355682Smarkm
44455682Smarkm
44555682Smarkm#if 0
44655682Smarkmint
44755682Smarkmgetreply (int expecteof)
44855682Smarkm{
44955682Smarkm    int c, n;
45055682Smarkm    int dig;
45155682Smarkm    int originalcode = 0, continuation = 0;
45255682Smarkm    sighand oldintr;
45355682Smarkm    int pflag = 0;
45455682Smarkm    char *cp, *pt = pasv;
45555682Smarkm
45655682Smarkm    oldintr = signal (SIGINT, cmdabort);
45755682Smarkm    for (;;) {
45855682Smarkm	dig = n = code = 0;
45955682Smarkm	cp = reply_string;
46055682Smarkm	while ((c = getc (cin)) != '\n') {
46155682Smarkm	    if (c == IAC) {	/* handle telnet commands */
46255682Smarkm		switch (c = getc (cin)) {
46355682Smarkm		case WILL:
46455682Smarkm		case WONT:
46555682Smarkm		    c = getc (cin);
46655682Smarkm		    fprintf (cout, "%c%c%c", IAC, DONT, c);
46755682Smarkm		    fflush (cout);
46855682Smarkm		    break;
46955682Smarkm		case DO:
47055682Smarkm		case DONT:
47155682Smarkm		    c = getc (cin);
47255682Smarkm		    fprintf (cout, "%c%c%c", IAC, WONT, c);
47355682Smarkm		    fflush (cout);
47455682Smarkm		    break;
47555682Smarkm		default:
47655682Smarkm		    break;
47755682Smarkm		}
47855682Smarkm		continue;
47955682Smarkm	    }
48055682Smarkm	    dig++;
48155682Smarkm	    if (c == EOF) {
48255682Smarkm		if (expecteof) {
48355682Smarkm		    signal (SIGINT, oldintr);
48455682Smarkm		    code = 221;
48555682Smarkm		    return (0);
48655682Smarkm		}
48755682Smarkm		lostpeer (0);
48855682Smarkm		if (verbose) {
48955682Smarkm		    printf ("421 Service not available, remote server has closed connection\n");
49055682Smarkm		    fflush (stdout);
49155682Smarkm		}
49255682Smarkm		code = 421;
49355682Smarkm		return (4);
49455682Smarkm	    }
49555682Smarkm	    if (c != '\r' && (verbose > 0 ||
49655682Smarkm			      (verbose > -1 && n == '5' && dig > 4))) {
49755682Smarkm		if (proxflag &&
49855682Smarkm		    (dig == 1 || dig == 5 && verbose == 0))
49955682Smarkm		    printf ("%s:", hostname);
50055682Smarkm		putchar (c);
50155682Smarkm	    }
50255682Smarkm	    if (dig < 4 && isdigit (c))
50355682Smarkm		code = code * 10 + (c - '0');
50455682Smarkm	    if (!pflag && code == 227)
50555682Smarkm		pflag = 1;
50655682Smarkm	    if (dig > 4 && pflag == 1 && isdigit (c))
50755682Smarkm		pflag = 2;
50855682Smarkm	    if (pflag == 2) {
50955682Smarkm		if (c != '\r' && c != ')')
51055682Smarkm		    *pt++ = c;
51155682Smarkm		else {
51255682Smarkm		    *pt = '\0';
51355682Smarkm		    pflag = 3;
51455682Smarkm		}
51555682Smarkm	    }
51655682Smarkm	    if (dig == 4 && c == '-') {
51755682Smarkm		if (continuation)
51855682Smarkm		    code = 0;
51955682Smarkm		continuation++;
52055682Smarkm	    }
52155682Smarkm	    if (n == 0)
52255682Smarkm		n = c;
52355682Smarkm	    if (cp < &reply_string[sizeof (reply_string) - 1])
52455682Smarkm		*cp++ = c;
52555682Smarkm	}
52655682Smarkm	if (verbose > 0 || verbose > -1 && n == '5') {
52755682Smarkm	    putchar (c);
52855682Smarkm	    fflush (stdout);
52955682Smarkm	}
53055682Smarkm	if (continuation && code != originalcode) {
53155682Smarkm	    if (originalcode == 0)
53255682Smarkm		originalcode = code;
53355682Smarkm	    continue;
53455682Smarkm	}
53555682Smarkm	*cp = '\0';
53655682Smarkm	if(sec_complete){
53755682Smarkm	    if(code == 631)
53855682Smarkm		sec_read_msg(reply_string, prot_safe);
53955682Smarkm	    else if(code == 632)
54055682Smarkm		sec_read_msg(reply_string, prot_private);
54155682Smarkm	    else if(code == 633)
54255682Smarkm		sec_read_msg(reply_string, prot_confidential);
54355682Smarkm	    n = code / 100 + '0';
54455682Smarkm	}
54555682Smarkm	if (n != '1')
54655682Smarkm	    cpend = 0;
54755682Smarkm	signal (SIGINT, oldintr);
54855682Smarkm	if (code == 421 || originalcode == 421)
54955682Smarkm	    lostpeer (0);
55055682Smarkm	if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
55155682Smarkm	    (*oldintr) (SIGINT);
55255682Smarkm	return (n - '0');
55355682Smarkm    }
55455682Smarkm}
55555682Smarkm
55655682Smarkm#endif
55755682Smarkm
55855682Smarkmint
55955682Smarkmempty (fd_set * mask, int sec)
56055682Smarkm{
56155682Smarkm    struct timeval t;
56255682Smarkm
56372445Sassar    t.tv_sec = sec;
56455682Smarkm    t.tv_usec = 0;
56572445Sassar    return (select (FD_SETSIZE, mask, NULL, NULL, &t));
56655682Smarkm}
56755682Smarkm
56855682Smarkmjmp_buf sendabort;
56955682Smarkm
57055682Smarkmstatic RETSIGTYPE
57155682Smarkmabortsend (int sig)
57255682Smarkm{
57355682Smarkm
57455682Smarkm    mflag = 0;
57555682Smarkm    abrtflag = 0;
57655682Smarkm    printf ("\nsend aborted\nwaiting for remote to finish abort\n");
57755682Smarkm    fflush (stdout);
57855682Smarkm    longjmp (sendabort, 1);
57955682Smarkm}
58055682Smarkm
58155682Smarkm#define HASHBYTES 1024
58255682Smarkm
58355682Smarkmstatic int
58455682Smarkmcopy_stream (FILE * from, FILE * to)
58555682Smarkm{
58655682Smarkm    static size_t bufsize;
58755682Smarkm    static char *buf;
58855682Smarkm    int n;
58955682Smarkm    int bytes = 0;
59055682Smarkm    int werr = 0;
59155682Smarkm    int hashbytes = HASHBYTES;
59255682Smarkm    struct stat st;
59355682Smarkm
59455682Smarkm#if defined(HAVE_MMAP) && !defined(NO_MMAP)
59555682Smarkm    void *chunk;
596233294Sstas    size_t off;
59755682Smarkm
598233294Sstas#define BLOCKSIZE (1024 * 1024 * 10)
599233294Sstas
60055682Smarkm#ifndef MAP_FAILED
60155682Smarkm#define MAP_FAILED (-1)
60255682Smarkm#endif
60355682Smarkm
60455682Smarkm    if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) {
60555682Smarkm	/*
60655682Smarkm	 * mmap zero bytes has potential of loosing, don't do it.
60755682Smarkm	 */
60855682Smarkm	if (st.st_size == 0)
60955682Smarkm	    return 0;
610233294Sstas	off = 0;
611233294Sstas	while (off != st.st_size) {
612233294Sstas	    size_t len;
613233294Sstas	    ssize_t res;
61455682Smarkm
615233294Sstas	    len = st.st_size - off;
616233294Sstas	    if (len > BLOCKSIZE)
617233294Sstas		len = BLOCKSIZE;
618233294Sstas
619233294Sstas	    chunk = mmap (0, len, PROT_READ, MAP_SHARED, fileno (from), off);
620233294Sstas	    if (chunk == (void *) MAP_FAILED) {
621233294Sstas		if (off == 0) /* try read if mmap doesn't work */
622233294Sstas		    goto try_read;
623233294Sstas		break;
624233294Sstas	    }
625233294Sstas
626233294Sstas	    res = sec_write (fileno (to), chunk, len);
627233294Sstas	    if (msync (chunk, len, MS_ASYNC))
628233294Sstas		warn ("msync");
629233294Sstas	    if (munmap (chunk, len) < 0)
63055682Smarkm		warn ("munmap");
63155682Smarkm	    sec_fflush (to);
632233294Sstas	    if (res != len)
633233294Sstas		return off;
634233294Sstas	    off += len;
63555682Smarkm	}
636233294Sstas	return off;
63755682Smarkm    }
638233294Sstastry_read:
63955682Smarkm#endif
64055682Smarkm
64155682Smarkm    buf = alloc_buffer (buf, &bufsize,
64255682Smarkm			fstat (fileno (from), &st) >= 0 ? &st : NULL);
64355682Smarkm    if (buf == NULL)
64455682Smarkm	return -1;
64555682Smarkm
64655682Smarkm    while ((n = read (fileno (from), buf, bufsize)) > 0) {
64755682Smarkm	werr = sec_write (fileno (to), buf, n);
64855682Smarkm	if (werr < 0)
64955682Smarkm	    break;
65055682Smarkm	bytes += werr;
65155682Smarkm	while (hash && bytes > hashbytes) {
65255682Smarkm	    putchar ('#');
65355682Smarkm	    hashbytes += HASHBYTES;
65455682Smarkm	}
65555682Smarkm    }
65655682Smarkm    sec_fflush (to);
65755682Smarkm    if (n < 0)
65855682Smarkm	warn ("local");
65955682Smarkm
66055682Smarkm    if (werr < 0) {
66155682Smarkm	if (errno != EPIPE)
66255682Smarkm	    warn ("netout");
66355682Smarkm	bytes = -1;
66455682Smarkm    }
66555682Smarkm    return bytes;
66655682Smarkm}
66755682Smarkm
66855682Smarkmvoid
66955682Smarkmsendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames)
67055682Smarkm{
67155682Smarkm    struct stat st;
67255682Smarkm    struct timeval start, stop;
67355682Smarkm    int c, d;
67455682Smarkm    FILE *fin, *dout = 0;
67555682Smarkm    int (*closefunc) (FILE *);
67672445Sassar    RETSIGTYPE (*oldintr)(int), (*oldintp)(int);
67755682Smarkm    long bytes = 0, hashbytes = HASHBYTES;
67855682Smarkm    char *rmode = "w";
67955682Smarkm
68055682Smarkm    if (verbose && printnames) {
681233294Sstas	if (strcmp (local, "-") != 0)
68255682Smarkm	    printf ("local: %s ", local);
68355682Smarkm	if (remote)
68455682Smarkm	    printf ("remote: %s\n", remote);
68555682Smarkm    }
68655682Smarkm    if (proxy) {
68755682Smarkm	proxtrans (cmd, local, remote);
68855682Smarkm	return;
68955682Smarkm    }
69055682Smarkm    if (curtype != type)
69155682Smarkm	changetype (type, 0);
69255682Smarkm    closefunc = NULL;
69355682Smarkm    oldintr = NULL;
69455682Smarkm    oldintp = NULL;
69555682Smarkm
69655682Smarkm    if (setjmp (sendabort)) {
69755682Smarkm	while (cpend) {
69855682Smarkm	    getreply (0);
69955682Smarkm	}
70055682Smarkm	if (data >= 0) {
70155682Smarkm	    close (data);
70255682Smarkm	    data = -1;
70355682Smarkm	}
70455682Smarkm	if (oldintr)
70555682Smarkm	    signal (SIGINT, oldintr);
70655682Smarkm	if (oldintp)
70755682Smarkm	    signal (SIGPIPE, oldintp);
70855682Smarkm	code = -1;
70955682Smarkm	return;
71055682Smarkm    }
71155682Smarkm    oldintr = signal (SIGINT, abortsend);
71255682Smarkm    if (strcmp (local, "-") == 0)
71355682Smarkm	fin = stdin;
71455682Smarkm    else if (*local == '|') {
71555682Smarkm	oldintp = signal (SIGPIPE, SIG_IGN);
71655682Smarkm	fin = popen (local + 1, lmode);
71755682Smarkm	if (fin == NULL) {
71855682Smarkm	    warn ("%s", local + 1);
71955682Smarkm	    signal (SIGINT, oldintr);
72055682Smarkm	    signal (SIGPIPE, oldintp);
72155682Smarkm	    code = -1;
72255682Smarkm	    return;
72355682Smarkm	}
72455682Smarkm	closefunc = pclose;
72555682Smarkm    } else {
72655682Smarkm	fin = fopen (local, lmode);
72755682Smarkm	if (fin == NULL) {
72855682Smarkm	    warn ("local: %s", local);
72955682Smarkm	    signal (SIGINT, oldintr);
73055682Smarkm	    code = -1;
73155682Smarkm	    return;
73255682Smarkm	}
73355682Smarkm	closefunc = fclose;
734233294Sstas	if (fstat (fileno (fin), &st) < 0 || !S_ISREG(st.st_mode)) {
73555682Smarkm	    fprintf (stdout, "%s: not a plain file.\n", local);
73655682Smarkm	    signal (SIGINT, oldintr);
73755682Smarkm	    fclose (fin);
73855682Smarkm	    code = -1;
73955682Smarkm	    return;
74055682Smarkm	}
74155682Smarkm    }
74255682Smarkm    if (initconn ()) {
74355682Smarkm	signal (SIGINT, oldintr);
74455682Smarkm	if (oldintp)
74555682Smarkm	    signal (SIGPIPE, oldintp);
74655682Smarkm	code = -1;
74755682Smarkm	if (closefunc != NULL)
74855682Smarkm	    (*closefunc) (fin);
74955682Smarkm	return;
75055682Smarkm    }
75155682Smarkm    if (setjmp (sendabort))
75255682Smarkm	goto abort;
75355682Smarkm
75455682Smarkm    if (restart_point &&
75555682Smarkm	(strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) {
75655682Smarkm	int rc;
75755682Smarkm
75855682Smarkm	switch (curtype) {
75955682Smarkm	case TYPE_A:
76055682Smarkm	    rc = fseek (fin, (long) restart_point, SEEK_SET);
76155682Smarkm	    break;
76255682Smarkm	case TYPE_I:
76355682Smarkm	case TYPE_L:
76455682Smarkm	    rc = lseek (fileno (fin), restart_point, SEEK_SET);
76555682Smarkm	    break;
766178825Sdfr	default:
767178825Sdfr	    abort();
76855682Smarkm	}
76955682Smarkm	if (rc < 0) {
77055682Smarkm	    warn ("local: %s", local);
77155682Smarkm	    restart_point = 0;
77255682Smarkm	    if (closefunc != NULL)
77355682Smarkm		(*closefunc) (fin);
77455682Smarkm	    return;
77555682Smarkm	}
77655682Smarkm	if (command ("REST %ld", (long) restart_point)
77755682Smarkm	    != CONTINUE) {
77855682Smarkm	    restart_point = 0;
77955682Smarkm	    if (closefunc != NULL)
78055682Smarkm		(*closefunc) (fin);
78155682Smarkm	    return;
78255682Smarkm	}
78355682Smarkm	restart_point = 0;
78455682Smarkm	rmode = "r+w";
78555682Smarkm    }
78655682Smarkm    if (remote) {
78755682Smarkm	if (command ("%s %s", cmd, remote) != PRELIM) {
78855682Smarkm	    signal (SIGINT, oldintr);
78955682Smarkm	    if (oldintp)
79055682Smarkm		signal (SIGPIPE, oldintp);
79155682Smarkm	    if (closefunc != NULL)
79255682Smarkm		(*closefunc) (fin);
79355682Smarkm	    return;
79455682Smarkm	}
79555682Smarkm    } else if (command ("%s", cmd) != PRELIM) {
79655682Smarkm	    signal(SIGINT, oldintr);
79755682Smarkm	    if (oldintp)
79855682Smarkm		signal(SIGPIPE, oldintp);
79955682Smarkm	    if (closefunc != NULL)
80055682Smarkm		(*closefunc)(fin);
80155682Smarkm	    return;
80255682Smarkm	}
80355682Smarkm    dout = dataconn(rmode);
80455682Smarkm    if (dout == NULL)
80555682Smarkm	goto abort;
80655682Smarkm    set_buffer_size (fileno (dout), 0);
80755682Smarkm    gettimeofday (&start, (struct timezone *) 0);
80855682Smarkm    oldintp = signal (SIGPIPE, SIG_IGN);
80955682Smarkm    switch (curtype) {
81055682Smarkm
81155682Smarkm    case TYPE_I:
81255682Smarkm    case TYPE_L:
81355682Smarkm	errno = d = c = 0;
81455682Smarkm	bytes = copy_stream (fin, dout);
81555682Smarkm	break;
81655682Smarkm
81755682Smarkm    case TYPE_A:
81855682Smarkm	while ((c = getc (fin)) != EOF) {
81955682Smarkm	    if (c == '\n') {
82055682Smarkm		while (hash && (bytes >= hashbytes)) {
82155682Smarkm		    putchar ('#');
82255682Smarkm		    fflush (stdout);
82355682Smarkm		    hashbytes += HASHBYTES;
82455682Smarkm		}
82555682Smarkm		if (ferror (dout))
82655682Smarkm		    break;
82755682Smarkm		sec_putc ('\r', dout);
82855682Smarkm		bytes++;
82955682Smarkm	    }
83055682Smarkm	    sec_putc (c, dout);
83155682Smarkm	    bytes++;
83255682Smarkm	}
83355682Smarkm	sec_fflush (dout);
83455682Smarkm	if (hash) {
83555682Smarkm	    if (bytes < hashbytes)
83655682Smarkm		putchar ('#');
83755682Smarkm	    putchar ('\n');
83855682Smarkm	    fflush (stdout);
83955682Smarkm	}
84055682Smarkm	if (ferror (fin))
84155682Smarkm	    warn ("local: %s", local);
84255682Smarkm	if (ferror (dout)) {
84355682Smarkm	    if (errno != EPIPE)
84455682Smarkm		warn ("netout");
84555682Smarkm	    bytes = -1;
84655682Smarkm	}
84755682Smarkm	break;
84855682Smarkm    }
84955682Smarkm    if (closefunc != NULL)
85055682Smarkm	(*closefunc) (fin);
85155682Smarkm    fclose (dout);
85255682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
85355682Smarkm    getreply (0);
85455682Smarkm    signal (SIGINT, oldintr);
85555682Smarkm    if (oldintp)
85655682Smarkm	signal (SIGPIPE, oldintp);
85755682Smarkm    if (bytes > 0)
85855682Smarkm	ptransfer ("sent", bytes, &start, &stop);
85955682Smarkm    return;
86055682Smarkmabort:
86155682Smarkm    signal (SIGINT, oldintr);
86255682Smarkm    if (oldintp)
86355682Smarkm	signal (SIGPIPE, oldintp);
86455682Smarkm    if (!cpend) {
86555682Smarkm	code = -1;
86655682Smarkm	return;
86755682Smarkm    }
86855682Smarkm    if (data >= 0) {
86955682Smarkm	close (data);
87055682Smarkm	data = -1;
87155682Smarkm    }
87255682Smarkm    if (dout)
87355682Smarkm	fclose (dout);
87455682Smarkm    getreply (0);
87555682Smarkm    code = -1;
87655682Smarkm    if (closefunc != NULL && fin != NULL)
87755682Smarkm	(*closefunc) (fin);
87855682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
87955682Smarkm    if (bytes > 0)
88055682Smarkm	ptransfer ("sent", bytes, &start, &stop);
88155682Smarkm}
88255682Smarkm
88355682Smarkmjmp_buf recvabort;
88455682Smarkm
88555682Smarkmvoid
88655682Smarkmabortrecv (int sig)
88755682Smarkm{
88855682Smarkm
88955682Smarkm    mflag = 0;
89055682Smarkm    abrtflag = 0;
89155682Smarkm    printf ("\nreceive aborted\nwaiting for remote to finish abort\n");
89255682Smarkm    fflush (stdout);
89355682Smarkm    longjmp (recvabort, 1);
89455682Smarkm}
89555682Smarkm
89655682Smarkmvoid
89755682Smarkmrecvrequest (char *cmd, char *local, char *remote,
89855682Smarkm	     char *lmode, int printnames, int local_given)
89955682Smarkm{
900178825Sdfr    FILE *fout = NULL, *din = NULL;
90155682Smarkm    int (*closefunc) (FILE *);
90255682Smarkm    sighand oldintr, oldintp;
90355682Smarkm    int c, d, is_retr, tcrflag, bare_lfs = 0;
90455682Smarkm    static size_t bufsize;
90555682Smarkm    static char *buf;
90655682Smarkm    long bytes = 0, hashbytes = HASHBYTES;
90755682Smarkm    struct timeval start, stop;
90855682Smarkm    struct stat st;
90955682Smarkm
91055682Smarkm    is_retr = strcmp (cmd, "RETR") == 0;
91155682Smarkm    if (is_retr && verbose && printnames) {
912233294Sstas	if (strcmp (local, "-") != 0)
91355682Smarkm	    printf ("local: %s ", local);
91455682Smarkm	if (remote)
91555682Smarkm	    printf ("remote: %s\n", remote);
91655682Smarkm    }
91755682Smarkm    if (proxy && is_retr) {
91855682Smarkm	proxtrans (cmd, local, remote);
91955682Smarkm	return;
92055682Smarkm    }
92155682Smarkm    closefunc = NULL;
92255682Smarkm    oldintr = NULL;
92355682Smarkm    oldintp = NULL;
92455682Smarkm    tcrflag = !crflag && is_retr;
92555682Smarkm    if (setjmp (recvabort)) {
92655682Smarkm	while (cpend) {
92755682Smarkm	    getreply (0);
92855682Smarkm	}
92955682Smarkm	if (data >= 0) {
93055682Smarkm	    close (data);
93155682Smarkm	    data = -1;
93255682Smarkm	}
93355682Smarkm	if (oldintr)
93455682Smarkm	    signal (SIGINT, oldintr);
93555682Smarkm	code = -1;
93655682Smarkm	return;
93755682Smarkm    }
93855682Smarkm    oldintr = signal (SIGINT, abortrecv);
939233294Sstas    if (!local_given || (strcmp(local, "-") && *local != '|')) {
94055682Smarkm	if (access (local, 2) < 0) {
94155682Smarkm	    char *dir = strrchr (local, '/');
94255682Smarkm
94355682Smarkm	    if (errno != ENOENT && errno != EACCES) {
94455682Smarkm		warn ("local: %s", local);
94555682Smarkm		signal (SIGINT, oldintr);
94655682Smarkm		code = -1;
94755682Smarkm		return;
94855682Smarkm	    }
94955682Smarkm	    if (dir != NULL)
95055682Smarkm		*dir = 0;
95155682Smarkm	    d = access (dir ? local : ".", 2);
95255682Smarkm	    if (dir != NULL)
95355682Smarkm		*dir = '/';
95455682Smarkm	    if (d < 0) {
95555682Smarkm		warn ("local: %s", local);
95655682Smarkm		signal (SIGINT, oldintr);
95755682Smarkm		code = -1;
95855682Smarkm		return;
95955682Smarkm	    }
96055682Smarkm	    if (!runique && errno == EACCES &&
96155682Smarkm		chmod (local, 0600) < 0) {
96255682Smarkm		warn ("local: %s", local);
96355682Smarkm		signal (SIGINT, oldintr);
96455682Smarkm		signal (SIGINT, oldintr);
96555682Smarkm		code = -1;
96655682Smarkm		return;
96755682Smarkm	    }
96855682Smarkm	    if (runique && errno == EACCES &&
96955682Smarkm		(local = gunique (local)) == NULL) {
97055682Smarkm		signal (SIGINT, oldintr);
97155682Smarkm		code = -1;
97255682Smarkm		return;
97355682Smarkm	    }
97455682Smarkm	} else if (runique && (local = gunique (local)) == NULL) {
97555682Smarkm	    signal(SIGINT, oldintr);
97655682Smarkm	    code = -1;
97755682Smarkm	    return;
97855682Smarkm	}
97955682Smarkm    }
98055682Smarkm    if (!is_retr) {
98155682Smarkm	if (curtype != TYPE_A)
98255682Smarkm	    changetype (TYPE_A, 0);
98355682Smarkm    } else if (curtype != type)
98455682Smarkm	changetype (type, 0);
98555682Smarkm    if (initconn ()) {
98655682Smarkm	signal (SIGINT, oldintr);
98755682Smarkm	code = -1;
98855682Smarkm	return;
98955682Smarkm    }
99055682Smarkm    if (setjmp (recvabort))
99155682Smarkm	goto abort;
99255682Smarkm    if (is_retr && restart_point &&
99355682Smarkm	command ("REST %ld", (long) restart_point) != CONTINUE)
99455682Smarkm	return;
99555682Smarkm    if (remote) {
99655682Smarkm	if (command ("%s %s", cmd, remote) != PRELIM) {
99755682Smarkm	    signal (SIGINT, oldintr);
99855682Smarkm	    return;
99955682Smarkm	}
100055682Smarkm    } else {
100155682Smarkm	if (command ("%s", cmd) != PRELIM) {
100255682Smarkm	    signal (SIGINT, oldintr);
100355682Smarkm	    return;
100455682Smarkm	}
100555682Smarkm    }
100655682Smarkm    din = dataconn ("r");
100755682Smarkm    if (din == NULL)
100855682Smarkm	goto abort;
100955682Smarkm    set_buffer_size (fileno (din), 1);
101055682Smarkm    if (local_given && strcmp (local, "-") == 0)
101155682Smarkm	fout = stdout;
101255682Smarkm    else if (local_given && *local == '|') {
101355682Smarkm	oldintp = signal (SIGPIPE, SIG_IGN);
101455682Smarkm	fout = popen (local + 1, "w");
101555682Smarkm	if (fout == NULL) {
101655682Smarkm	    warn ("%s", local + 1);
101755682Smarkm	    goto abort;
101855682Smarkm	}
101955682Smarkm	closefunc = pclose;
102055682Smarkm    } else {
102155682Smarkm	fout = fopen (local, lmode);
102255682Smarkm	if (fout == NULL) {
102355682Smarkm	    warn ("local: %s", local);
102455682Smarkm	    goto abort;
102555682Smarkm	}
102655682Smarkm	closefunc = fclose;
102755682Smarkm    }
102855682Smarkm    buf = alloc_buffer (buf, &bufsize,
102955682Smarkm			fstat (fileno (fout), &st) >= 0 ? &st : NULL);
103055682Smarkm    if (buf == NULL)
103155682Smarkm	goto abort;
103255682Smarkm
103355682Smarkm    gettimeofday (&start, (struct timezone *) 0);
103455682Smarkm    switch (curtype) {
103555682Smarkm
103655682Smarkm    case TYPE_I:
103755682Smarkm    case TYPE_L:
103855682Smarkm	if (restart_point &&
103955682Smarkm	    lseek (fileno (fout), restart_point, SEEK_SET) < 0) {
104055682Smarkm	    warn ("local: %s", local);
104155682Smarkm	    if (closefunc != NULL)
104255682Smarkm		(*closefunc) (fout);
104355682Smarkm	    return;
104455682Smarkm	}
104555682Smarkm	errno = d = 0;
104655682Smarkm	while ((c = sec_read (fileno (din), buf, bufsize)) > 0) {
104755682Smarkm	    if ((d = write (fileno (fout), buf, c)) != c)
104855682Smarkm		break;
104955682Smarkm	    bytes += c;
105055682Smarkm	    if (hash) {
105155682Smarkm		while (bytes >= hashbytes) {
105255682Smarkm		    putchar ('#');
105355682Smarkm		    hashbytes += HASHBYTES;
105455682Smarkm		}
105555682Smarkm		fflush (stdout);
105655682Smarkm	    }
105755682Smarkm	}
105855682Smarkm	if (hash && bytes > 0) {
105955682Smarkm	    if (bytes < HASHBYTES)
106055682Smarkm		putchar ('#');
106155682Smarkm	    putchar ('\n');
106255682Smarkm	    fflush (stdout);
106355682Smarkm	}
106455682Smarkm	if (c < 0) {
106555682Smarkm	    if (errno != EPIPE)
106655682Smarkm		warn ("netin");
106755682Smarkm	    bytes = -1;
106855682Smarkm	}
106955682Smarkm	if (d < c) {
107055682Smarkm	    if (d < 0)
107155682Smarkm		warn ("local: %s", local);
107255682Smarkm	    else
107355682Smarkm		warnx ("%s: short write", local);
107455682Smarkm	}
107555682Smarkm	break;
107655682Smarkm
107755682Smarkm    case TYPE_A:
107855682Smarkm	if (restart_point) {
107955682Smarkm	    int i, n, ch;
108055682Smarkm
108155682Smarkm	    if (fseek (fout, 0L, SEEK_SET) < 0)
108255682Smarkm		goto done;
108355682Smarkm	    n = restart_point;
108455682Smarkm	    for (i = 0; i++ < n;) {
108555682Smarkm		if ((ch = sec_getc (fout)) == EOF)
108655682Smarkm		    goto done;
108755682Smarkm		if (ch == '\n')
108855682Smarkm		    i++;
108955682Smarkm	    }
109055682Smarkm	    if (fseek (fout, 0L, SEEK_CUR) < 0) {
109155682Smarkm	done:
109255682Smarkm		warn ("local: %s", local);
109355682Smarkm		if (closefunc != NULL)
109455682Smarkm		    (*closefunc) (fout);
109555682Smarkm		return;
109655682Smarkm	    }
109755682Smarkm	}
109855682Smarkm	while ((c = sec_getc(din)) != EOF) {
109955682Smarkm	    if (c == '\n')
110055682Smarkm		bare_lfs++;
110155682Smarkm	    while (c == '\r') {
110255682Smarkm		while (hash && (bytes >= hashbytes)) {
110355682Smarkm		    putchar ('#');
110455682Smarkm		    fflush (stdout);
110555682Smarkm		    hashbytes += HASHBYTES;
110655682Smarkm		}
110755682Smarkm		bytes++;
110855682Smarkm		if ((c = sec_getc (din)) != '\n' || tcrflag) {
110955682Smarkm		    if (ferror (fout))
111055682Smarkm			goto break2;
111155682Smarkm		    putc ('\r', fout);
111255682Smarkm		    if (c == '\0') {
111355682Smarkm			bytes++;
111455682Smarkm			goto contin2;
111555682Smarkm		    }
111655682Smarkm		    if (c == EOF)
111755682Smarkm			goto contin2;
111855682Smarkm		}
111955682Smarkm	    }
112055682Smarkm	    putc (c, fout);
112155682Smarkm	    bytes++;
112255682Smarkm    contin2:;
112355682Smarkm	}
112455682Smarkmbreak2:
112555682Smarkm	if (bare_lfs) {
112655682Smarkm	    printf ("WARNING! %d bare linefeeds received in ASCII mode\n",
112755682Smarkm		    bare_lfs);
112855682Smarkm	    printf ("File may not have transferred correctly.\n");
112955682Smarkm	}
113055682Smarkm	if (hash) {
113155682Smarkm	    if (bytes < hashbytes)
113255682Smarkm		putchar ('#');
113355682Smarkm	    putchar ('\n');
113455682Smarkm	    fflush (stdout);
113555682Smarkm	}
113655682Smarkm	if (ferror (din)) {
113755682Smarkm	    if (errno != EPIPE)
113855682Smarkm		warn ("netin");
113955682Smarkm	    bytes = -1;
114055682Smarkm	}
114155682Smarkm	if (ferror (fout))
114255682Smarkm	    warn ("local: %s", local);
114355682Smarkm	break;
114455682Smarkm    }
114555682Smarkm    if (closefunc != NULL)
114655682Smarkm	(*closefunc) (fout);
114755682Smarkm    signal (SIGINT, oldintr);
114855682Smarkm    if (oldintp)
114955682Smarkm	signal (SIGPIPE, oldintp);
115055682Smarkm    fclose (din);
115155682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
115255682Smarkm    getreply (0);
115355682Smarkm    if (bytes > 0 && is_retr)
115455682Smarkm	ptransfer ("received", bytes, &start, &stop);
115555682Smarkm    return;
115655682Smarkmabort:
115755682Smarkm
115855682Smarkm    /* abort using RFC959 recommended IP,SYNC sequence  */
115955682Smarkm
116055682Smarkm    if (oldintp)
116155682Smarkm	signal (SIGPIPE, oldintr);
116255682Smarkm    signal (SIGINT, SIG_IGN);
116355682Smarkm    if (!cpend) {
116455682Smarkm	code = -1;
116555682Smarkm	signal (SIGINT, oldintr);
116655682Smarkm	return;
116755682Smarkm    }
116855682Smarkm    abort_remote(din);
116955682Smarkm    code = -1;
117055682Smarkm    if (data >= 0) {
117155682Smarkm	close (data);
117255682Smarkm	data = -1;
117355682Smarkm    }
117455682Smarkm    if (closefunc != NULL && fout != NULL)
117555682Smarkm	(*closefunc) (fout);
117655682Smarkm    if (din)
117755682Smarkm	fclose (din);
117855682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
117955682Smarkm    if (bytes > 0)
118055682Smarkm	ptransfer ("received", bytes, &start, &stop);
118155682Smarkm    signal (SIGINT, oldintr);
118255682Smarkm}
118355682Smarkm
118455682Smarkmstatic int
118555682Smarkmparse_epsv (const char *str)
118655682Smarkm{
118755682Smarkm    char sep;
118855682Smarkm    char *end;
118955682Smarkm    int port;
119055682Smarkm
119155682Smarkm    if (*str == '\0')
119255682Smarkm	return -1;
119355682Smarkm    sep = *str++;
119455682Smarkm    if (sep != *str++)
119555682Smarkm	return -1;
119655682Smarkm    if (sep != *str++)
119755682Smarkm	return -1;
119855682Smarkm    port = strtol (str, &end, 0);
119955682Smarkm    if (str == end)
120055682Smarkm	return -1;
120155682Smarkm    if (end[0] != sep || end[1] != '\0')
120255682Smarkm	return -1;
120355682Smarkm    return htons(port);
120455682Smarkm}
120555682Smarkm
120655682Smarkmstatic int
1207178825Sdfrparse_pasv (struct sockaddr_in *sin4, const char *str)
120855682Smarkm{
120955682Smarkm    int a0, a1, a2, a3, p0, p1;
121055682Smarkm
121155682Smarkm    /*
121255682Smarkm     * What we've got at this point is a string of comma separated
121355682Smarkm     * one-byte unsigned integer values. The first four are the an IP
121455682Smarkm     * address. The fifth is the MSB of the port number, the sixth is the
121555682Smarkm     * LSB. From that we'll prepare a sockaddr_in.
121655682Smarkm     */
121755682Smarkm
121855682Smarkm    if (sscanf (str, "%d,%d,%d,%d,%d,%d",
121955682Smarkm		&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
122055682Smarkm	printf ("Passive mode address scan failure. "
122155682Smarkm		"Shouldn't happen!\n");
122255682Smarkm	return -1;
122355682Smarkm    }
122455682Smarkm    if (a0 < 0 || a0 > 255 ||
122555682Smarkm	a1 < 0 || a1 > 255 ||
122655682Smarkm	a2 < 0 || a2 > 255 ||
122755682Smarkm	a3 < 0 || a3 > 255 ||
122855682Smarkm	p0 < 0 || p0 > 255 ||
122955682Smarkm	p1 < 0 || p1 > 255) {
123055682Smarkm	printf ("Can't parse passive mode string.\n");
123155682Smarkm	return -1;
123255682Smarkm    }
1233178825Sdfr    memset (sin4, 0, sizeof(*sin4));
1234178825Sdfr    sin4->sin_family      = AF_INET;
1235178825Sdfr    sin4->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
123655682Smarkm				  (a2 << 8) | a3);
1237178825Sdfr    sin4->sin_port = htons ((p0 << 8) | p1);
123855682Smarkm    return 0;
123955682Smarkm}
124055682Smarkm
124155682Smarkmstatic int
124255682Smarkmpassive_mode (void)
124355682Smarkm{
124455682Smarkm    int port;
124555682Smarkm
124655682Smarkm    data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
124755682Smarkm    if (data < 0) {
124855682Smarkm	warn ("socket");
124955682Smarkm	return (1);
125055682Smarkm    }
125155682Smarkm    if (options & SO_DEBUG)
125255682Smarkm	socket_set_debug (data);
125355682Smarkm    if (command ("EPSV") != COMPLETE) {
125455682Smarkm	if (command ("PASV") != COMPLETE) {
125555682Smarkm	    printf ("Passive mode refused.\n");
125655682Smarkm	    goto bad;
125755682Smarkm	}
125855682Smarkm    }
125955682Smarkm
126055682Smarkm    /*
126155682Smarkm     * Parse the reply to EPSV or PASV
126255682Smarkm     */
126355682Smarkm
126455682Smarkm    port = parse_epsv (pasv);
126555682Smarkm    if (port > 0) {
126655682Smarkm	data_addr->sa_family = myctladdr->sa_family;
126755682Smarkm	socket_set_address_and_port (data_addr,
126855682Smarkm				     socket_get_address (hisctladdr),
126955682Smarkm				     port);
127055682Smarkm    } else {
127155682Smarkm	if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
127255682Smarkm	    goto bad;
127355682Smarkm    }
127455682Smarkm
127555682Smarkm    if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
127655682Smarkm	warn ("connect");
127755682Smarkm	goto bad;
127855682Smarkm    }
127955682Smarkm#ifdef IPTOS_THROUGHPUT
128055682Smarkm    socket_set_tos (data, IPTOS_THROUGHPUT);
128155682Smarkm#endif
128255682Smarkm    return (0);
128355682Smarkmbad:
128455682Smarkm    close (data);
128555682Smarkm    data = -1;
128655682Smarkm    sendport = 1;
128755682Smarkm    return (1);
128855682Smarkm}
128955682Smarkm
129055682Smarkm
129155682Smarkmstatic int
129255682Smarkmactive_mode (void)
129355682Smarkm{
129455682Smarkm    int tmpno = 0;
129572445Sassar    socklen_t len;
129655682Smarkm    int result;
129755682Smarkm
129855682Smarkmnoport:
129955682Smarkm    data_addr->sa_family = myctladdr->sa_family;
130055682Smarkm    socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
130155682Smarkm				 sendport ? 0 : socket_get_port (myctladdr));
130255682Smarkm
130355682Smarkm    if (data != -1)
130455682Smarkm	close (data);
130555682Smarkm    data = socket (data_addr->sa_family, SOCK_STREAM, 0);
130655682Smarkm    if (data < 0) {
130755682Smarkm	warn ("socket");
130855682Smarkm	if (tmpno)
130955682Smarkm	    sendport = 1;
131055682Smarkm	return (1);
131155682Smarkm    }
131255682Smarkm    if (!sendport)
131355682Smarkm	socket_set_reuseaddr (data, 1);
131455682Smarkm    if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
131555682Smarkm	warn ("bind");
131655682Smarkm	goto bad;
131755682Smarkm    }
131855682Smarkm    if (options & SO_DEBUG)
131955682Smarkm	socket_set_debug (data);
132055682Smarkm    len = sizeof (data_addr_ss);
132155682Smarkm    if (getsockname (data, data_addr, &len) < 0) {
132255682Smarkm	warn ("getsockname");
132355682Smarkm	goto bad;
132455682Smarkm    }
132555682Smarkm    if (listen (data, 1) < 0)
132655682Smarkm	warn ("listen");
132755682Smarkm    if (sendport) {
132855682Smarkm	char addr_str[256];
132955682Smarkm	int inet_af;
133055682Smarkm	int overbose;
133155682Smarkm
133255682Smarkm	if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
133355682Smarkm		       addr_str, sizeof(addr_str)) == NULL)
133455682Smarkm	    errx (1, "inet_ntop failed");
133555682Smarkm	switch (data_addr->sa_family) {
133655682Smarkm	case AF_INET :
133755682Smarkm	    inet_af = 1;
133855682Smarkm	    break;
133955682Smarkm#ifdef HAVE_IPV6
134055682Smarkm	case AF_INET6 :
134155682Smarkm	    inet_af = 2;
134255682Smarkm	    break;
134355682Smarkm#endif
134455682Smarkm	default :
134555682Smarkm	    errx (1, "bad address family %d", data_addr->sa_family);
134655682Smarkm	}
134755682Smarkm
134855682Smarkm
134955682Smarkm	overbose = verbose;
135055682Smarkm	if (debug == 0)
135155682Smarkm	    verbose  = -1;
135255682Smarkm
1353103423Snectar	result = command ("EPRT |%d|%s|%d|",
1354233294Sstas			  inet_af, addr_str,
1355103423Snectar			  ntohs(socket_get_port (data_addr)));
135655682Smarkm	verbose = overbose;
135755682Smarkm
135855682Smarkm	if (result == ERROR) {
1359178825Sdfr	    struct sockaddr_in *sin4 = (struct sockaddr_in *)data_addr;
136055682Smarkm
1361178825Sdfr	    unsigned int a = ntohl(sin4->sin_addr.s_addr);
1362178825Sdfr	    unsigned int p = ntohs(sin4->sin_port);
136355682Smarkm
136455682Smarkm	    if (data_addr->sa_family != AF_INET) {
136555682Smarkm		warnx ("remote server doesn't support EPRT");
136655682Smarkm		goto bad;
136755682Smarkm	    }
136855682Smarkm
1369233294Sstas	    result = command("PORT %d,%d,%d,%d,%d,%d",
137055682Smarkm			     (a >> 24) & 0xff,
137155682Smarkm			     (a >> 16) & 0xff,
137255682Smarkm			     (a >> 8) & 0xff,
137355682Smarkm			     a & 0xff,
137455682Smarkm			     (p >> 8) & 0xff,
137555682Smarkm			     p & 0xff);
137655682Smarkm	    if (result == ERROR && sendport == -1) {
137755682Smarkm		sendport = 0;
137855682Smarkm		tmpno = 1;
137955682Smarkm		goto noport;
138055682Smarkm	    }
138155682Smarkm	    return (result != COMPLETE);
138255682Smarkm	}
138355682Smarkm	return result != COMPLETE;
138455682Smarkm    }
138555682Smarkm    if (tmpno)
138655682Smarkm	sendport = 1;
138755682Smarkm
138855682Smarkm
138955682Smarkm#ifdef IPTOS_THROUGHPUT
139055682Smarkm    socket_set_tos (data, IPTOS_THROUGHPUT);
139155682Smarkm#endif
139255682Smarkm    return (0);
139355682Smarkmbad:
139455682Smarkm    close (data);
139555682Smarkm    data = -1;
139655682Smarkm    if (tmpno)
139755682Smarkm	sendport = 1;
139855682Smarkm    return (1);
139955682Smarkm}
140055682Smarkm
140155682Smarkm/*
140255682Smarkm * Need to start a listen on the data channel before we send the command,
140355682Smarkm * otherwise the server's connect may fail.
140455682Smarkm */
140555682Smarkmint
140655682Smarkminitconn (void)
140755682Smarkm{
1408233294Sstas    if (passivemode)
140955682Smarkm	return passive_mode ();
141055682Smarkm    else
141155682Smarkm	return active_mode ();
141255682Smarkm}
141355682Smarkm
141455682SmarkmFILE *
141555682Smarkmdataconn (const char *lmode)
141655682Smarkm{
141755682Smarkm    struct sockaddr_storage from_ss;
141855682Smarkm    struct sockaddr *from = (struct sockaddr *)&from_ss;
141972445Sassar    socklen_t fromlen = sizeof(from_ss);
142072445Sassar    int s;
142155682Smarkm
142255682Smarkm    if (passivemode)
142355682Smarkm	return (fdopen (data, lmode));
142455682Smarkm
142555682Smarkm    s = accept (data, from, &fromlen);
142655682Smarkm    if (s < 0) {
142755682Smarkm	warn ("accept");
142855682Smarkm	close (data), data = -1;
142955682Smarkm	return (NULL);
143055682Smarkm    }
143155682Smarkm    close (data);
143255682Smarkm    data = s;
143355682Smarkm#ifdef IPTOS_THROUGHPUT
143455682Smarkm    socket_set_tos (s, IPTOS_THROUGHPUT);
143555682Smarkm#endif
143655682Smarkm    return (fdopen (data, lmode));
143755682Smarkm}
143855682Smarkm
143955682Smarkmvoid
144055682Smarkmptransfer (char *direction, long int bytes,
144155682Smarkm	   struct timeval * t0, struct timeval * t1)
144255682Smarkm{
144355682Smarkm    struct timeval td;
144455682Smarkm    float s;
144555682Smarkm    float bs;
144655682Smarkm    int prec;
144755682Smarkm    char *unit;
144855682Smarkm
144955682Smarkm    if (verbose) {
145055682Smarkm	td.tv_sec = t1->tv_sec - t0->tv_sec;
145155682Smarkm	td.tv_usec = t1->tv_usec - t0->tv_usec;
145255682Smarkm	if (td.tv_usec < 0) {
145355682Smarkm	    td.tv_sec--;
145455682Smarkm	    td.tv_usec += 1000000;
145555682Smarkm	}
145655682Smarkm	s = td.tv_sec + (td.tv_usec / 1000000.);
145755682Smarkm	bs = bytes / (s ? s : 1);
145855682Smarkm	if (bs >= 1048576) {
145955682Smarkm	    bs /= 1048576;
146055682Smarkm	    unit = "M";
146155682Smarkm	    prec = 2;
146255682Smarkm	} else if (bs >= 1024) {
146355682Smarkm	    bs /= 1024;
146455682Smarkm	    unit = "k";
146555682Smarkm	    prec = 1;
146655682Smarkm	} else {
146755682Smarkm	    unit = "";
146855682Smarkm	    prec = 0;
146955682Smarkm	}
147055682Smarkm
147155682Smarkm	printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n",
147255682Smarkm		bytes, direction, s, prec, bs, unit);
147355682Smarkm    }
147455682Smarkm}
147555682Smarkm
147655682Smarkmvoid
147755682Smarkmpsabort (int sig)
147855682Smarkm{
147955682Smarkm
148055682Smarkm    abrtflag++;
148155682Smarkm}
148255682Smarkm
148355682Smarkmvoid
148455682Smarkmpswitch (int flag)
148555682Smarkm{
148655682Smarkm    sighand oldintr;
148755682Smarkm    static struct comvars {
148855682Smarkm	int connect;
148955682Smarkm	char name[MaxHostNameLen];
149055682Smarkm	struct sockaddr_storage mctl;
149155682Smarkm	struct sockaddr_storage hctl;
149255682Smarkm	FILE *in;
149355682Smarkm	FILE *out;
149455682Smarkm	int tpe;
149555682Smarkm	int curtpe;
149655682Smarkm	int cpnd;
149755682Smarkm	int sunqe;
149855682Smarkm	int runqe;
149955682Smarkm	int mcse;
150055682Smarkm	int ntflg;
150155682Smarkm	char nti[17];
150255682Smarkm	char nto[17];
150355682Smarkm	int mapflg;
150455682Smarkm	char mi[MaxPathLen];
150555682Smarkm	char mo[MaxPathLen];
150655682Smarkm    } proxstruct, tmpstruct;
150755682Smarkm    struct comvars *ip, *op;
150855682Smarkm
150955682Smarkm    abrtflag = 0;
151055682Smarkm    oldintr = signal (SIGINT, psabort);
151155682Smarkm    if (flag) {
151255682Smarkm	if (proxy)
151355682Smarkm	    return;
151455682Smarkm	ip = &tmpstruct;
151555682Smarkm	op = &proxstruct;
151655682Smarkm	proxy++;
151755682Smarkm    } else {
151855682Smarkm	if (!proxy)
151955682Smarkm	    return;
152055682Smarkm	ip = &proxstruct;
152155682Smarkm	op = &tmpstruct;
152255682Smarkm	proxy = 0;
152355682Smarkm    }
152455682Smarkm    ip->connect = connected;
152555682Smarkm    connected = op->connect;
152655682Smarkm    if (hostname) {
152755682Smarkm	strlcpy (ip->name, hostname, sizeof (ip->name));
152855682Smarkm    } else
152955682Smarkm	ip->name[0] = 0;
153055682Smarkm    hostname = op->name;
153155682Smarkm    ip->hctl = hisctladdr_ss;
153255682Smarkm    hisctladdr_ss = op->hctl;
153355682Smarkm    ip->mctl = myctladdr_ss;
153455682Smarkm    myctladdr_ss = op->mctl;
153555682Smarkm    ip->in = cin;
153655682Smarkm    cin = op->in;
153755682Smarkm    ip->out = cout;
153855682Smarkm    cout = op->out;
153955682Smarkm    ip->tpe = type;
154055682Smarkm    type = op->tpe;
154155682Smarkm    ip->curtpe = curtype;
154255682Smarkm    curtype = op->curtpe;
154355682Smarkm    ip->cpnd = cpend;
154455682Smarkm    cpend = op->cpnd;
154555682Smarkm    ip->sunqe = sunique;
154655682Smarkm    sunique = op->sunqe;
154755682Smarkm    ip->runqe = runique;
154855682Smarkm    runique = op->runqe;
154955682Smarkm    ip->mcse = mcase;
155055682Smarkm    mcase = op->mcse;
155155682Smarkm    ip->ntflg = ntflag;
155255682Smarkm    ntflag = op->ntflg;
155355682Smarkm    strlcpy (ip->nti, ntin, sizeof (ip->nti));
155455682Smarkm    strlcpy (ntin, op->nti, 17);
155555682Smarkm    strlcpy (ip->nto, ntout, sizeof (ip->nto));
155655682Smarkm    strlcpy (ntout, op->nto, 17);
155755682Smarkm    ip->mapflg = mapflag;
155855682Smarkm    mapflag = op->mapflg;
155955682Smarkm    strlcpy (ip->mi, mapin, MaxPathLen);
156055682Smarkm    strlcpy (mapin, op->mi, MaxPathLen);
156155682Smarkm    strlcpy (ip->mo, mapout, MaxPathLen);
156255682Smarkm    strlcpy (mapout, op->mo, MaxPathLen);
156355682Smarkm    signal(SIGINT, oldintr);
156455682Smarkm    if (abrtflag) {
156555682Smarkm	abrtflag = 0;
156655682Smarkm	(*oldintr) (SIGINT);
156755682Smarkm    }
156855682Smarkm}
156955682Smarkm
157055682Smarkmvoid
157155682Smarkmabortpt (int sig)
157255682Smarkm{
157355682Smarkm
157455682Smarkm    printf ("\n");
157555682Smarkm    fflush (stdout);
157655682Smarkm    ptabflg++;
157755682Smarkm    mflag = 0;
157855682Smarkm    abrtflag = 0;
157955682Smarkm    longjmp (ptabort, 1);
158055682Smarkm}
158155682Smarkm
158255682Smarkmvoid
158355682Smarkmproxtrans (char *cmd, char *local, char *remote)
158455682Smarkm{
1585178825Sdfr    sighand oldintr = NULL;
158655682Smarkm    int secndflag = 0, prox_type, nfnd;
158755682Smarkm    char *cmd2;
158855682Smarkm    fd_set mask;
158955682Smarkm
159055682Smarkm    if (strcmp (cmd, "RETR"))
159155682Smarkm	cmd2 = "RETR";
159255682Smarkm    else
159355682Smarkm	cmd2 = runique ? "STOU" : "STOR";
159455682Smarkm    if ((prox_type = type) == 0) {
159555682Smarkm	if (unix_server && unix_proxy)
159655682Smarkm	    prox_type = TYPE_I;
159755682Smarkm	else
159855682Smarkm	    prox_type = TYPE_A;
159955682Smarkm    }
160055682Smarkm    if (curtype != prox_type)
160155682Smarkm	changetype (prox_type, 1);
160255682Smarkm    if (command ("PASV") != COMPLETE) {
160355682Smarkm	printf ("proxy server does not support third party transfers.\n");
160455682Smarkm	return;
160555682Smarkm    }
160655682Smarkm    pswitch (0);
160755682Smarkm    if (!connected) {
160855682Smarkm	printf ("No primary connection\n");
160955682Smarkm	pswitch (1);
161055682Smarkm	code = -1;
161155682Smarkm	return;
161255682Smarkm    }
161355682Smarkm    if (curtype != prox_type)
161455682Smarkm	changetype (prox_type, 1);
161555682Smarkm    if (command ("PORT %s", pasv) != COMPLETE) {
161655682Smarkm	pswitch (1);
161755682Smarkm	return;
161855682Smarkm    }
161955682Smarkm    if (setjmp (ptabort))
162055682Smarkm	goto abort;
162155682Smarkm    oldintr = signal (SIGINT, abortpt);
162255682Smarkm    if (command ("%s %s", cmd, remote) != PRELIM) {
162355682Smarkm	signal (SIGINT, oldintr);
162455682Smarkm	pswitch (1);
162555682Smarkm	return;
162655682Smarkm    }
162755682Smarkm    sleep (2);
162855682Smarkm    pswitch (1);
162955682Smarkm    secndflag++;
163055682Smarkm    if (command ("%s %s", cmd2, local) != PRELIM)
163155682Smarkm	goto abort;
163255682Smarkm    ptflag++;
163355682Smarkm    getreply (0);
163455682Smarkm    pswitch (0);
163555682Smarkm    getreply (0);
163655682Smarkm    signal (SIGINT, oldintr);
163755682Smarkm    pswitch (1);
163855682Smarkm    ptflag = 0;
163955682Smarkm    printf ("local: %s remote: %s\n", local, remote);
164055682Smarkm    return;
164155682Smarkmabort:
164255682Smarkm    signal (SIGINT, SIG_IGN);
164355682Smarkm    ptflag = 0;
164455682Smarkm    if (strcmp (cmd, "RETR") && !proxy)
164555682Smarkm	pswitch (1);
164655682Smarkm    else if (!strcmp (cmd, "RETR") && proxy)
164755682Smarkm	pswitch (0);
164855682Smarkm    if (!cpend && !secndflag) {	/* only here if cmd = "STOR" (proxy=1) */
164955682Smarkm	if (command ("%s %s", cmd2, local) != PRELIM) {
165055682Smarkm	    pswitch (0);
165155682Smarkm	    if (cpend)
165255682Smarkm		abort_remote ((FILE *) NULL);
165355682Smarkm	}
165455682Smarkm	pswitch (1);
165555682Smarkm	if (ptabflg)
165655682Smarkm	    code = -1;
1657178825Sdfr	if (oldintr)
1658178825Sdfr	    signal (SIGINT, oldintr);
165955682Smarkm	return;
166055682Smarkm    }
166155682Smarkm    if (cpend)
166255682Smarkm	abort_remote ((FILE *) NULL);
166355682Smarkm    pswitch (!proxy);
166455682Smarkm    if (!cpend && !secndflag) {	/* only if cmd = "RETR" (proxy=1) */
166555682Smarkm	if (command ("%s %s", cmd2, local) != PRELIM) {
166655682Smarkm	    pswitch (0);
166755682Smarkm	    if (cpend)
166855682Smarkm		abort_remote ((FILE *) NULL);
166955682Smarkm	    pswitch (1);
167055682Smarkm	    if (ptabflg)
167155682Smarkm		code = -1;
167255682Smarkm	    signal (SIGINT, oldintr);
167355682Smarkm	    return;
167455682Smarkm	}
167555682Smarkm    }
167655682Smarkm    if (cpend)
167755682Smarkm	abort_remote ((FILE *) NULL);
167855682Smarkm    pswitch (!proxy);
167955682Smarkm    if (cpend) {
168055682Smarkm	FD_ZERO (&mask);
168172445Sassar	if (fileno(cin) >= FD_SETSIZE)
168272445Sassar	    errx (1, "fd too large");
168355682Smarkm	FD_SET (fileno (cin), &mask);
168455682Smarkm	if ((nfnd = empty (&mask, 10)) <= 0) {
168555682Smarkm	    if (nfnd < 0) {
168655682Smarkm		warn ("abort");
168755682Smarkm	    }
168855682Smarkm	    if (ptabflg)
168955682Smarkm		code = -1;
169055682Smarkm	    lostpeer (0);
169155682Smarkm	}
169255682Smarkm	getreply (0);
169355682Smarkm	getreply (0);
169455682Smarkm    }
169555682Smarkm    if (proxy)
169655682Smarkm	pswitch (0);
169755682Smarkm    pswitch (1);
169855682Smarkm    if (ptabflg)
169955682Smarkm	code = -1;
170055682Smarkm    signal (SIGINT, oldintr);
170155682Smarkm}
170255682Smarkm
170355682Smarkmvoid
170455682Smarkmreset (int argc, char **argv)
170555682Smarkm{
170655682Smarkm    fd_set mask;
170755682Smarkm    int nfnd = 1;
170855682Smarkm
170955682Smarkm    FD_ZERO (&mask);
171055682Smarkm    while (nfnd > 0) {
171172445Sassar	if (fileno (cin) >= FD_SETSIZE)
171272445Sassar	    errx (1, "fd too large");
171355682Smarkm	FD_SET (fileno (cin), &mask);
171455682Smarkm	if ((nfnd = empty (&mask, 0)) < 0) {
171555682Smarkm	    warn ("reset");
171655682Smarkm	    code = -1;
171755682Smarkm	    lostpeer(0);
171855682Smarkm	} else if (nfnd) {
171955682Smarkm	    getreply(0);
172055682Smarkm	}
172155682Smarkm    }
172255682Smarkm}
172355682Smarkm
172455682Smarkmchar *
172555682Smarkmgunique (char *local)
172655682Smarkm{
172755682Smarkm    static char new[MaxPathLen];
172855682Smarkm    char *cp = strrchr (local, '/');
172955682Smarkm    int d, count = 0;
173055682Smarkm    char ext = '1';
173155682Smarkm
173255682Smarkm    if (cp)
173355682Smarkm	*cp = '\0';
173455682Smarkm    d = access (cp ? local : ".", 2);
173555682Smarkm    if (cp)
173655682Smarkm	*cp = '/';
173755682Smarkm    if (d < 0) {
173855682Smarkm	warn ("local: %s", local);
173955682Smarkm	return NULL;
174055682Smarkm    }
174155682Smarkm    strlcpy (new, local, sizeof(new));
174255682Smarkm    cp = new + strlen(new);
174355682Smarkm    *cp++ = '.';
174455682Smarkm    while (!d) {
174555682Smarkm	if (++count == 100) {
174655682Smarkm	    printf ("runique: can't find unique file name.\n");
174755682Smarkm	    return NULL;
174855682Smarkm	}
174955682Smarkm	*cp++ = ext;
175055682Smarkm	*cp = '\0';
175155682Smarkm	if (ext == '9')
175255682Smarkm	    ext = '0';
175355682Smarkm	else
175455682Smarkm	    ext++;
175555682Smarkm	if ((d = access (new, 0)) < 0)
175655682Smarkm	    break;
175755682Smarkm	if (ext != '0')
175855682Smarkm	    cp--;
175955682Smarkm	else if (*(cp - 2) == '.')
176055682Smarkm	    *(cp - 1) = '1';
176155682Smarkm	else {
176255682Smarkm	    *(cp - 2) = *(cp - 2) + 1;
176355682Smarkm	    cp--;
176455682Smarkm	}
176555682Smarkm    }
176655682Smarkm    return (new);
176755682Smarkm}
176855682Smarkm
176955682Smarkmvoid
177055682Smarkmabort_remote (FILE * din)
177155682Smarkm{
177255682Smarkm    char buf[BUFSIZ];
177355682Smarkm    int nfnd;
177455682Smarkm    fd_set mask;
177555682Smarkm
177655682Smarkm    /*
177755682Smarkm     * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
177855682Smarkm     * after urgent byte rather than before as is protocol now
177955682Smarkm     */
178055682Smarkm    snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC);
178155682Smarkm    if (send (fileno (cout), buf, 3, MSG_OOB) != 3)
178255682Smarkm	warn ("abort");
1783142403Snectar    fprintf (cout, "%c", DM);
1784142403Snectar    sec_fprintf(cout, "ABOR");
1785142403Snectar    sec_fflush (cout);
1786142403Snectar    fprintf (cout, "\r\n");
1787142403Snectar    fflush(cout);
178855682Smarkm    FD_ZERO (&mask);
178972445Sassar    if (fileno (cin) >= FD_SETSIZE)
179072445Sassar	errx (1, "fd too large");
179155682Smarkm    FD_SET (fileno (cin), &mask);
179255682Smarkm    if (din) {
1793178825Sdfr	if (fileno (din) >= FD_SETSIZE)
1794178825Sdfr	    errx (1, "fd too large");
179555682Smarkm	FD_SET (fileno (din), &mask);
179655682Smarkm    }
179755682Smarkm    if ((nfnd = empty (&mask, 10)) <= 0) {
179855682Smarkm	if (nfnd < 0) {
179955682Smarkm	    warn ("abort");
180055682Smarkm	}
180155682Smarkm	if (ptabflg)
180255682Smarkm	    code = -1;
180355682Smarkm	lostpeer (0);
180455682Smarkm    }
180555682Smarkm    if (din && FD_ISSET (fileno (din), &mask)) {
180655682Smarkm	while (read (fileno (din), buf, BUFSIZ) > 0)
180755682Smarkm	     /* LOOP */ ;
180855682Smarkm    }
180955682Smarkm    if (getreply (0) == ERROR && code == 552) {
181055682Smarkm	/* 552 needed for nic style abort */
181155682Smarkm	getreply (0);
181255682Smarkm    }
181355682Smarkm    getreply (0);
181455682Smarkm}
1815