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"
35178825SdfrRCSID ("$Id: ftp.c 16650 2006-01-24 08:16:08Z lha $");
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);
9255682Smarkm
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));
10155682Smarkm
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;
17055682Smarkm    int n, aflag = 0;
17155682Smarkm
17255682Smarkm    char *myname = NULL;
17355682Smarkm    struct passwd *pw = k_getpwuid(getuid());
17455682Smarkm
17555682Smarkm    if (pw != NULL)
17655682Smarkm	myname = pw->pw_name;
17755682Smarkm
178178825Sdfr    userstr = pass = acctstr = 0;
17955682Smarkm
18055682Smarkm    if(sec_login(host))
18155682Smarkm	printf("\n*** Using plaintext user and password ***\n\n");
18255682Smarkm    else{
18355682Smarkm	printf("Authentication successful.\n\n");
18455682Smarkm    }
18555682Smarkm
186178825Sdfr    if (ruserpass (host, &userstr, &pass, &acctstr) < 0) {
18755682Smarkm	code = -1;
18855682Smarkm	return (0);
18955682Smarkm    }
190178825Sdfr    while (userstr == NULL) {
19155682Smarkm	if (myname)
19255682Smarkm	    printf ("Name (%s:%s): ", host, myname);
19355682Smarkm	else
19455682Smarkm	    printf ("Name (%s): ", host);
19572445Sassar	*tmp = '\0';
19672445Sassar	if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL)
19772445Sassar	    tmp[strlen (tmp) - 1] = '\0';
19855682Smarkm	if (*tmp == '\0')
199178825Sdfr	    userstr = myname;
20055682Smarkm	else
201178825Sdfr	    userstr = tmp;
20255682Smarkm    }
203178825Sdfr    strlcpy(username, userstr, sizeof(username));
204178825Sdfr    n = command("USER %s", userstr);
20572445Sassar    if (n == COMPLETE)
20672445Sassar       n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */
20772445Sassar    else if(n == CONTINUE) {
20872445Sassar	if (pass == NULL) {
20955682Smarkm	    char prompt[128];
21055682Smarkm	    if(myname &&
211178825Sdfr	       (!strcmp(userstr, "ftp") || !strcmp(userstr, "anonymous"))) {
21255682Smarkm		snprintf(defaultpass, sizeof(defaultpass),
21355682Smarkm			 "%s@%s", myname, mydomain);
21455682Smarkm		snprintf(prompt, sizeof(prompt),
21555682Smarkm			 "Password (%s): ", defaultpass);
21672445Sassar	    } else if (sec_complete) {
21772445Sassar		pass = myname;
21872445Sassar	    } else {
21955682Smarkm		*defaultpass = '\0';
22055682Smarkm		snprintf(prompt, sizeof(prompt), "Password: ");
22155682Smarkm	    }
22272445Sassar	    if (pass == NULL) {
22372445Sassar		pass = defaultpass;
224178825Sdfr		UI_UTIL_read_pw_string (tmp, sizeof (tmp), prompt, 0);
22572445Sassar		if (tmp[0])
22672445Sassar		    pass = tmp;
22772445Sassar	    }
22855682Smarkm	}
22955682Smarkm	n = command ("PASS %s", pass);
23055682Smarkm    }
23155682Smarkm    if (n == CONTINUE) {
23255682Smarkm	aflag++;
233178825Sdfr	acctstr = tmp;
234178825Sdfr	UI_UTIL_read_pw_string (acctstr, 128, "Account:", 0);
235178825Sdfr	n = command ("ACCT %s", acctstr);
23655682Smarkm    }
23755682Smarkm    if (n != COMPLETE) {
23855682Smarkm	warnx ("Login failed.");
23955682Smarkm	return (0);
24055682Smarkm    }
241178825Sdfr    if (!aflag && acctstr != NULL)
242178825Sdfr	command ("ACCT %s", acctstr);
24355682Smarkm    if (proxy)
24455682Smarkm	return (1);
24555682Smarkm    for (n = 0; n < macnum; ++n) {
24655682Smarkm	if (!strcmp("init", macros[n].mac_name)) {
24755682Smarkm	    strlcpy (line, "$init", sizeof (line));
24855682Smarkm	    makeargv();
24955682Smarkm	    domacro(margc, margv);
25055682Smarkm	    break;
25155682Smarkm	}
25255682Smarkm    }
25355682Smarkm    sec_set_protection_level ();
25455682Smarkm    return (1);
25555682Smarkm}
25655682Smarkm
25755682Smarkmvoid
25855682Smarkmcmdabort (int sig)
25955682Smarkm{
26055682Smarkm
26155682Smarkm    printf ("\n");
26255682Smarkm    fflush (stdout);
26355682Smarkm    abrtflag++;
26455682Smarkm    if (ptflag)
26555682Smarkm	longjmp (ptabort, 1);
26655682Smarkm}
26755682Smarkm
26855682Smarkmint
26955682Smarkmcommand (char *fmt,...)
27055682Smarkm{
27155682Smarkm    va_list ap;
27255682Smarkm    int r;
27355682Smarkm    sighand oldintr;
27455682Smarkm
27555682Smarkm    abrtflag = 0;
27655682Smarkm    if (cout == NULL) {
27755682Smarkm	warn ("No control connection for command");
27855682Smarkm	code = -1;
27955682Smarkm	return (0);
28055682Smarkm    }
28155682Smarkm    oldintr = signal(SIGINT, cmdabort);
28255682Smarkm    if(debug){
28355682Smarkm	printf("---> ");
28455682Smarkm	if (strncmp("PASS ", fmt, 5) == 0)
28555682Smarkm	    printf("PASS XXXX");
286102644Snectar	else {
287102644Snectar	    va_start(ap, fmt);
28855682Smarkm	    vfprintf(stdout, fmt, ap);
289102644Snectar	    va_end(ap);
290102644Snectar	}
29155682Smarkm    }
292102644Snectar    va_start(ap, fmt);
29355682Smarkm    sec_vfprintf(cout, fmt, ap);
29455682Smarkm    va_end(ap);
29555682Smarkm    if(debug){
29655682Smarkm	printf("\n");
29755682Smarkm	fflush(stdout);
29855682Smarkm    }
29955682Smarkm    fprintf (cout, "\r\n");
30055682Smarkm    fflush (cout);
30155682Smarkm    cpend = 1;
30255682Smarkm    r = getreply (!strcmp (fmt, "QUIT"));
30355682Smarkm    if (abrtflag && oldintr != SIG_IGN)
30455682Smarkm	(*oldintr) (SIGINT);
30555682Smarkm    signal (SIGINT, oldintr);
30655682Smarkm    return (r);
30755682Smarkm}
30855682Smarkm
30955682Smarkmchar reply_string[BUFSIZ];	/* last line of previous reply */
31055682Smarkm
31155682Smarkmint
31255682Smarkmgetreply (int expecteof)
31355682Smarkm{
31455682Smarkm    char *p;
31555682Smarkm    char *lead_string;
31655682Smarkm    int c;
31755682Smarkm    struct sigaction sa, osa;
318102644Snectar    char buf[8192];
319102644Snectar    int reply_code;
320102644Snectar    int long_warn = 0;
32155682Smarkm
32255682Smarkm    sigemptyset (&sa.sa_mask);
32355682Smarkm    sa.sa_flags = 0;
32455682Smarkm    sa.sa_handler = cmdabort;
32555682Smarkm    sigaction (SIGINT, &sa, &osa);
32655682Smarkm
32755682Smarkm    p = buf;
32855682Smarkm
329102644Snectar    reply_code = 0;
33055682Smarkm    while (1) {
33155682Smarkm	c = getc (cin);
33255682Smarkm	switch (c) {
33355682Smarkm	case EOF:
33455682Smarkm	    if (expecteof) {
33555682Smarkm		sigaction (SIGINT, &osa, NULL);
33655682Smarkm		code = 221;
33755682Smarkm		return 0;
33855682Smarkm	    }
33955682Smarkm	    lostpeer (0);
34055682Smarkm	    if (verbose) {
34155682Smarkm		printf ("421 Service not available, "
34255682Smarkm			"remote server has closed connection\n");
34355682Smarkm		fflush (stdout);
34455682Smarkm	    }
34555682Smarkm	    code = 421;
34655682Smarkm	    return (4);
34755682Smarkm	case IAC:
34855682Smarkm	    c = getc (cin);
34955682Smarkm	    if (c == WILL || c == WONT)
35055682Smarkm		fprintf (cout, "%c%c%c", IAC, DONT, getc (cin));
35155682Smarkm	    if (c == DO || c == DONT)
35255682Smarkm		fprintf (cout, "%c%c%c", IAC, WONT, getc (cin));
35355682Smarkm	    continue;
35455682Smarkm	case '\n':
35555682Smarkm	    *p++ = '\0';
356178825Sdfr	    if(isdigit((unsigned char)buf[0])){
35755682Smarkm		sscanf(buf, "%d", &code);
35855682Smarkm		if(code == 631){
359102644Snectar		    code = 0;
36055682Smarkm		    sec_read_msg(buf, prot_safe);
36155682Smarkm		    sscanf(buf, "%d", &code);
36255682Smarkm		    lead_string = "S:";
36355682Smarkm		} else if(code == 632){
364102644Snectar		    code = 0;
36555682Smarkm		    sec_read_msg(buf, prot_private);
36655682Smarkm		    sscanf(buf, "%d", &code);
36755682Smarkm		    lead_string = "P:";
36855682Smarkm		}else if(code == 633){
369102644Snectar		    code = 0;
37055682Smarkm		    sec_read_msg(buf, prot_confidential);
37155682Smarkm		    sscanf(buf, "%d", &code);
37255682Smarkm		    lead_string = "C:";
37355682Smarkm		}else if(sec_complete)
37455682Smarkm		    lead_string = "!!";
37555682Smarkm		else
37655682Smarkm		    lead_string = "";
377102644Snectar		if(code != 0 && reply_code == 0)
378102644Snectar		    reply_code = code;
37955682Smarkm		if (verbose > 0 || (verbose > -1 && code > 499))
38055682Smarkm		    fprintf (stdout, "%s%s\n", lead_string, buf);
381102644Snectar		if (code == reply_code && buf[3] == ' ') {
382102644Snectar		    strlcpy (reply_string, buf, sizeof(reply_string));
38355682Smarkm		    if (code >= 200)
38455682Smarkm			cpend = 0;
38555682Smarkm		    sigaction (SIGINT, &osa, NULL);
38655682Smarkm		    if (code == 421)
38755682Smarkm			lostpeer (0);
38855682Smarkm#if 1
38955682Smarkm		    if (abrtflag &&
39055682Smarkm			osa.sa_handler != cmdabort &&
39155682Smarkm			osa.sa_handler != SIG_IGN)
39255682Smarkm			osa.sa_handler (SIGINT);
39355682Smarkm#endif
39455682Smarkm		    if (code == 227 || code == 229) {
395178825Sdfr			char *q;
39655682Smarkm
397178825Sdfr			q = strchr (reply_string, '(');
398178825Sdfr			if (q) {
399178825Sdfr			    q++;
400178825Sdfr			    strlcpy(pasv, q, sizeof(pasv));
401178825Sdfr			    q = strrchr(pasv, ')');
402178825Sdfr			    if (q)
403178825Sdfr				*q = '\0';
40455682Smarkm			}
40555682Smarkm		    }
40655682Smarkm		    return code / 100;
40755682Smarkm		}
40855682Smarkm	    }else{
40955682Smarkm		if(verbose > 0 || (verbose > -1 && code > 499)){
41055682Smarkm		    if(sec_complete)
41155682Smarkm			fprintf(stdout, "!!");
41255682Smarkm		    fprintf(stdout, "%s\n", buf);
41355682Smarkm		}
41455682Smarkm	    }
41555682Smarkm	    p = buf;
416102644Snectar	    long_warn = 0;
41755682Smarkm	    continue;
41855682Smarkm	default:
419102644Snectar	    if(p < buf + sizeof(buf) - 1)
420102644Snectar		*p++ = c;
421102644Snectar	    else if(long_warn == 0) {
422102644Snectar		fprintf(stderr, "WARNING: incredibly long line received\n");
423102644Snectar		long_warn = 1;
424102644Snectar	    }
42555682Smarkm	}
42655682Smarkm    }
42755682Smarkm
42855682Smarkm}
42955682Smarkm
43055682Smarkm
43155682Smarkm#if 0
43255682Smarkmint
43355682Smarkmgetreply (int expecteof)
43455682Smarkm{
43555682Smarkm    int c, n;
43655682Smarkm    int dig;
43755682Smarkm    int originalcode = 0, continuation = 0;
43855682Smarkm    sighand oldintr;
43955682Smarkm    int pflag = 0;
44055682Smarkm    char *cp, *pt = pasv;
44155682Smarkm
44255682Smarkm    oldintr = signal (SIGINT, cmdabort);
44355682Smarkm    for (;;) {
44455682Smarkm	dig = n = code = 0;
44555682Smarkm	cp = reply_string;
44655682Smarkm	while ((c = getc (cin)) != '\n') {
44755682Smarkm	    if (c == IAC) {	/* handle telnet commands */
44855682Smarkm		switch (c = getc (cin)) {
44955682Smarkm		case WILL:
45055682Smarkm		case WONT:
45155682Smarkm		    c = getc (cin);
45255682Smarkm		    fprintf (cout, "%c%c%c", IAC, DONT, c);
45355682Smarkm		    fflush (cout);
45455682Smarkm		    break;
45555682Smarkm		case DO:
45655682Smarkm		case DONT:
45755682Smarkm		    c = getc (cin);
45855682Smarkm		    fprintf (cout, "%c%c%c", IAC, WONT, c);
45955682Smarkm		    fflush (cout);
46055682Smarkm		    break;
46155682Smarkm		default:
46255682Smarkm		    break;
46355682Smarkm		}
46455682Smarkm		continue;
46555682Smarkm	    }
46655682Smarkm	    dig++;
46755682Smarkm	    if (c == EOF) {
46855682Smarkm		if (expecteof) {
46955682Smarkm		    signal (SIGINT, oldintr);
47055682Smarkm		    code = 221;
47155682Smarkm		    return (0);
47255682Smarkm		}
47355682Smarkm		lostpeer (0);
47455682Smarkm		if (verbose) {
47555682Smarkm		    printf ("421 Service not available, remote server has closed connection\n");
47655682Smarkm		    fflush (stdout);
47755682Smarkm		}
47855682Smarkm		code = 421;
47955682Smarkm		return (4);
48055682Smarkm	    }
48155682Smarkm	    if (c != '\r' && (verbose > 0 ||
48255682Smarkm			      (verbose > -1 && n == '5' && dig > 4))) {
48355682Smarkm		if (proxflag &&
48455682Smarkm		    (dig == 1 || dig == 5 && verbose == 0))
48555682Smarkm		    printf ("%s:", hostname);
48655682Smarkm		putchar (c);
48755682Smarkm	    }
48855682Smarkm	    if (dig < 4 && isdigit (c))
48955682Smarkm		code = code * 10 + (c - '0');
49055682Smarkm	    if (!pflag && code == 227)
49155682Smarkm		pflag = 1;
49255682Smarkm	    if (dig > 4 && pflag == 1 && isdigit (c))
49355682Smarkm		pflag = 2;
49455682Smarkm	    if (pflag == 2) {
49555682Smarkm		if (c != '\r' && c != ')')
49655682Smarkm		    *pt++ = c;
49755682Smarkm		else {
49855682Smarkm		    *pt = '\0';
49955682Smarkm		    pflag = 3;
50055682Smarkm		}
50155682Smarkm	    }
50255682Smarkm	    if (dig == 4 && c == '-') {
50355682Smarkm		if (continuation)
50455682Smarkm		    code = 0;
50555682Smarkm		continuation++;
50655682Smarkm	    }
50755682Smarkm	    if (n == 0)
50855682Smarkm		n = c;
50955682Smarkm	    if (cp < &reply_string[sizeof (reply_string) - 1])
51055682Smarkm		*cp++ = c;
51155682Smarkm	}
51255682Smarkm	if (verbose > 0 || verbose > -1 && n == '5') {
51355682Smarkm	    putchar (c);
51455682Smarkm	    fflush (stdout);
51555682Smarkm	}
51655682Smarkm	if (continuation && code != originalcode) {
51755682Smarkm	    if (originalcode == 0)
51855682Smarkm		originalcode = code;
51955682Smarkm	    continue;
52055682Smarkm	}
52155682Smarkm	*cp = '\0';
52255682Smarkm	if(sec_complete){
52355682Smarkm	    if(code == 631)
52455682Smarkm		sec_read_msg(reply_string, prot_safe);
52555682Smarkm	    else if(code == 632)
52655682Smarkm		sec_read_msg(reply_string, prot_private);
52755682Smarkm	    else if(code == 633)
52855682Smarkm		sec_read_msg(reply_string, prot_confidential);
52955682Smarkm	    n = code / 100 + '0';
53055682Smarkm	}
53155682Smarkm	if (n != '1')
53255682Smarkm	    cpend = 0;
53355682Smarkm	signal (SIGINT, oldintr);
53455682Smarkm	if (code == 421 || originalcode == 421)
53555682Smarkm	    lostpeer (0);
53655682Smarkm	if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
53755682Smarkm	    (*oldintr) (SIGINT);
53855682Smarkm	return (n - '0');
53955682Smarkm    }
54055682Smarkm}
54155682Smarkm
54255682Smarkm#endif
54355682Smarkm
54455682Smarkmint
54555682Smarkmempty (fd_set * mask, int sec)
54655682Smarkm{
54755682Smarkm    struct timeval t;
54855682Smarkm
54972445Sassar    t.tv_sec = sec;
55055682Smarkm    t.tv_usec = 0;
55172445Sassar    return (select (FD_SETSIZE, mask, NULL, NULL, &t));
55255682Smarkm}
55355682Smarkm
55455682Smarkmjmp_buf sendabort;
55555682Smarkm
55655682Smarkmstatic RETSIGTYPE
55755682Smarkmabortsend (int sig)
55855682Smarkm{
55955682Smarkm
56055682Smarkm    mflag = 0;
56155682Smarkm    abrtflag = 0;
56255682Smarkm    printf ("\nsend aborted\nwaiting for remote to finish abort\n");
56355682Smarkm    fflush (stdout);
56455682Smarkm    longjmp (sendabort, 1);
56555682Smarkm}
56655682Smarkm
56755682Smarkm#define HASHBYTES 1024
56855682Smarkm
56955682Smarkmstatic int
57055682Smarkmcopy_stream (FILE * from, FILE * to)
57155682Smarkm{
57255682Smarkm    static size_t bufsize;
57355682Smarkm    static char *buf;
57455682Smarkm    int n;
57555682Smarkm    int bytes = 0;
57655682Smarkm    int werr = 0;
57755682Smarkm    int hashbytes = HASHBYTES;
57855682Smarkm    struct stat st;
57955682Smarkm
58055682Smarkm#if defined(HAVE_MMAP) && !defined(NO_MMAP)
58155682Smarkm    void *chunk;
58255682Smarkm
58355682Smarkm#ifndef MAP_FAILED
58455682Smarkm#define MAP_FAILED (-1)
58555682Smarkm#endif
58655682Smarkm
58755682Smarkm    if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) {
58855682Smarkm	/*
58955682Smarkm	 * mmap zero bytes has potential of loosing, don't do it.
59055682Smarkm	 */
59155682Smarkm	if (st.st_size == 0)
59255682Smarkm	    return 0;
59355682Smarkm	chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0);
59455682Smarkm	if (chunk != (void *) MAP_FAILED) {
59555682Smarkm	    int res;
59655682Smarkm
59755682Smarkm	    res = sec_write (fileno (to), chunk, st.st_size);
59855682Smarkm	    if (munmap (chunk, st.st_size) < 0)
59955682Smarkm		warn ("munmap");
60055682Smarkm	    sec_fflush (to);
60155682Smarkm	    return res;
60255682Smarkm	}
60355682Smarkm    }
60455682Smarkm#endif
60555682Smarkm
60655682Smarkm    buf = alloc_buffer (buf, &bufsize,
60755682Smarkm			fstat (fileno (from), &st) >= 0 ? &st : NULL);
60855682Smarkm    if (buf == NULL)
60955682Smarkm	return -1;
61055682Smarkm
61155682Smarkm    while ((n = read (fileno (from), buf, bufsize)) > 0) {
61255682Smarkm	werr = sec_write (fileno (to), buf, n);
61355682Smarkm	if (werr < 0)
61455682Smarkm	    break;
61555682Smarkm	bytes += werr;
61655682Smarkm	while (hash && bytes > hashbytes) {
61755682Smarkm	    putchar ('#');
61855682Smarkm	    hashbytes += HASHBYTES;
61955682Smarkm	}
62055682Smarkm    }
62155682Smarkm    sec_fflush (to);
62255682Smarkm    if (n < 0)
62355682Smarkm	warn ("local");
62455682Smarkm
62555682Smarkm    if (werr < 0) {
62655682Smarkm	if (errno != EPIPE)
62755682Smarkm	    warn ("netout");
62855682Smarkm	bytes = -1;
62955682Smarkm    }
63055682Smarkm    return bytes;
63155682Smarkm}
63255682Smarkm
63355682Smarkmvoid
63455682Smarkmsendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames)
63555682Smarkm{
63655682Smarkm    struct stat st;
63755682Smarkm    struct timeval start, stop;
63855682Smarkm    int c, d;
63955682Smarkm    FILE *fin, *dout = 0;
64055682Smarkm    int (*closefunc) (FILE *);
64172445Sassar    RETSIGTYPE (*oldintr)(int), (*oldintp)(int);
64255682Smarkm    long bytes = 0, hashbytes = HASHBYTES;
64355682Smarkm    char *rmode = "w";
64455682Smarkm
64555682Smarkm    if (verbose && printnames) {
64655682Smarkm	if (local && strcmp (local, "-") != 0)
64755682Smarkm	    printf ("local: %s ", local);
64855682Smarkm	if (remote)
64955682Smarkm	    printf ("remote: %s\n", remote);
65055682Smarkm    }
65155682Smarkm    if (proxy) {
65255682Smarkm	proxtrans (cmd, local, remote);
65355682Smarkm	return;
65455682Smarkm    }
65555682Smarkm    if (curtype != type)
65655682Smarkm	changetype (type, 0);
65755682Smarkm    closefunc = NULL;
65855682Smarkm    oldintr = NULL;
65955682Smarkm    oldintp = NULL;
66055682Smarkm
66155682Smarkm    if (setjmp (sendabort)) {
66255682Smarkm	while (cpend) {
66355682Smarkm	    getreply (0);
66455682Smarkm	}
66555682Smarkm	if (data >= 0) {
66655682Smarkm	    close (data);
66755682Smarkm	    data = -1;
66855682Smarkm	}
66955682Smarkm	if (oldintr)
67055682Smarkm	    signal (SIGINT, oldintr);
67155682Smarkm	if (oldintp)
67255682Smarkm	    signal (SIGPIPE, oldintp);
67355682Smarkm	code = -1;
67455682Smarkm	return;
67555682Smarkm    }
67655682Smarkm    oldintr = signal (SIGINT, abortsend);
67755682Smarkm    if (strcmp (local, "-") == 0)
67855682Smarkm	fin = stdin;
67955682Smarkm    else if (*local == '|') {
68055682Smarkm	oldintp = signal (SIGPIPE, SIG_IGN);
68155682Smarkm	fin = popen (local + 1, lmode);
68255682Smarkm	if (fin == NULL) {
68355682Smarkm	    warn ("%s", local + 1);
68455682Smarkm	    signal (SIGINT, oldintr);
68555682Smarkm	    signal (SIGPIPE, oldintp);
68655682Smarkm	    code = -1;
68755682Smarkm	    return;
68855682Smarkm	}
68955682Smarkm	closefunc = pclose;
69055682Smarkm    } else {
69155682Smarkm	fin = fopen (local, lmode);
69255682Smarkm	if (fin == NULL) {
69355682Smarkm	    warn ("local: %s", local);
69455682Smarkm	    signal (SIGINT, oldintr);
69555682Smarkm	    code = -1;
69655682Smarkm	    return;
69755682Smarkm	}
69855682Smarkm	closefunc = fclose;
69955682Smarkm	if (fstat (fileno (fin), &st) < 0 ||
70055682Smarkm	    (st.st_mode & S_IFMT) != S_IFREG) {
70155682Smarkm	    fprintf (stdout, "%s: not a plain file.\n", local);
70255682Smarkm	    signal (SIGINT, oldintr);
70355682Smarkm	    fclose (fin);
70455682Smarkm	    code = -1;
70555682Smarkm	    return;
70655682Smarkm	}
70755682Smarkm    }
70855682Smarkm    if (initconn ()) {
70955682Smarkm	signal (SIGINT, oldintr);
71055682Smarkm	if (oldintp)
71155682Smarkm	    signal (SIGPIPE, oldintp);
71255682Smarkm	code = -1;
71355682Smarkm	if (closefunc != NULL)
71455682Smarkm	    (*closefunc) (fin);
71555682Smarkm	return;
71655682Smarkm    }
71755682Smarkm    if (setjmp (sendabort))
71855682Smarkm	goto abort;
71955682Smarkm
72055682Smarkm    if (restart_point &&
72155682Smarkm	(strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) {
72255682Smarkm	int rc;
72355682Smarkm
72455682Smarkm	switch (curtype) {
72555682Smarkm	case TYPE_A:
72655682Smarkm	    rc = fseek (fin, (long) restart_point, SEEK_SET);
72755682Smarkm	    break;
72855682Smarkm	case TYPE_I:
72955682Smarkm	case TYPE_L:
73055682Smarkm	    rc = lseek (fileno (fin), restart_point, SEEK_SET);
73155682Smarkm	    break;
732178825Sdfr	default:
733178825Sdfr	    abort();
73455682Smarkm	}
73555682Smarkm	if (rc < 0) {
73655682Smarkm	    warn ("local: %s", local);
73755682Smarkm	    restart_point = 0;
73855682Smarkm	    if (closefunc != NULL)
73955682Smarkm		(*closefunc) (fin);
74055682Smarkm	    return;
74155682Smarkm	}
74255682Smarkm	if (command ("REST %ld", (long) restart_point)
74355682Smarkm	    != CONTINUE) {
74455682Smarkm	    restart_point = 0;
74555682Smarkm	    if (closefunc != NULL)
74655682Smarkm		(*closefunc) (fin);
74755682Smarkm	    return;
74855682Smarkm	}
74955682Smarkm	restart_point = 0;
75055682Smarkm	rmode = "r+w";
75155682Smarkm    }
75255682Smarkm    if (remote) {
75355682Smarkm	if (command ("%s %s", cmd, remote) != PRELIM) {
75455682Smarkm	    signal (SIGINT, oldintr);
75555682Smarkm	    if (oldintp)
75655682Smarkm		signal (SIGPIPE, oldintp);
75755682Smarkm	    if (closefunc != NULL)
75855682Smarkm		(*closefunc) (fin);
75955682Smarkm	    return;
76055682Smarkm	}
76155682Smarkm    } else if (command ("%s", cmd) != PRELIM) {
76255682Smarkm	    signal(SIGINT, oldintr);
76355682Smarkm	    if (oldintp)
76455682Smarkm		signal(SIGPIPE, oldintp);
76555682Smarkm	    if (closefunc != NULL)
76655682Smarkm		(*closefunc)(fin);
76755682Smarkm	    return;
76855682Smarkm	}
76955682Smarkm    dout = dataconn(rmode);
77055682Smarkm    if (dout == NULL)
77155682Smarkm	goto abort;
77255682Smarkm    set_buffer_size (fileno (dout), 0);
77355682Smarkm    gettimeofday (&start, (struct timezone *) 0);
77455682Smarkm    oldintp = signal (SIGPIPE, SIG_IGN);
77555682Smarkm    switch (curtype) {
77655682Smarkm
77755682Smarkm    case TYPE_I:
77855682Smarkm    case TYPE_L:
77955682Smarkm	errno = d = c = 0;
78055682Smarkm	bytes = copy_stream (fin, dout);
78155682Smarkm	break;
78255682Smarkm
78355682Smarkm    case TYPE_A:
78455682Smarkm	while ((c = getc (fin)) != EOF) {
78555682Smarkm	    if (c == '\n') {
78655682Smarkm		while (hash && (bytes >= hashbytes)) {
78755682Smarkm		    putchar ('#');
78855682Smarkm		    fflush (stdout);
78955682Smarkm		    hashbytes += HASHBYTES;
79055682Smarkm		}
79155682Smarkm		if (ferror (dout))
79255682Smarkm		    break;
79355682Smarkm		sec_putc ('\r', dout);
79455682Smarkm		bytes++;
79555682Smarkm	    }
79655682Smarkm	    sec_putc (c, dout);
79755682Smarkm	    bytes++;
79855682Smarkm	}
79955682Smarkm	sec_fflush (dout);
80055682Smarkm	if (hash) {
80155682Smarkm	    if (bytes < hashbytes)
80255682Smarkm		putchar ('#');
80355682Smarkm	    putchar ('\n');
80455682Smarkm	    fflush (stdout);
80555682Smarkm	}
80655682Smarkm	if (ferror (fin))
80755682Smarkm	    warn ("local: %s", local);
80855682Smarkm	if (ferror (dout)) {
80955682Smarkm	    if (errno != EPIPE)
81055682Smarkm		warn ("netout");
81155682Smarkm	    bytes = -1;
81255682Smarkm	}
81355682Smarkm	break;
81455682Smarkm    }
81555682Smarkm    if (closefunc != NULL)
81655682Smarkm	(*closefunc) (fin);
81755682Smarkm    fclose (dout);
81855682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
81955682Smarkm    getreply (0);
82055682Smarkm    signal (SIGINT, oldintr);
82155682Smarkm    if (oldintp)
82255682Smarkm	signal (SIGPIPE, oldintp);
82355682Smarkm    if (bytes > 0)
82455682Smarkm	ptransfer ("sent", bytes, &start, &stop);
82555682Smarkm    return;
82655682Smarkmabort:
82755682Smarkm    signal (SIGINT, oldintr);
82855682Smarkm    if (oldintp)
82955682Smarkm	signal (SIGPIPE, oldintp);
83055682Smarkm    if (!cpend) {
83155682Smarkm	code = -1;
83255682Smarkm	return;
83355682Smarkm    }
83455682Smarkm    if (data >= 0) {
83555682Smarkm	close (data);
83655682Smarkm	data = -1;
83755682Smarkm    }
83855682Smarkm    if (dout)
83955682Smarkm	fclose (dout);
84055682Smarkm    getreply (0);
84155682Smarkm    code = -1;
84255682Smarkm    if (closefunc != NULL && fin != NULL)
84355682Smarkm	(*closefunc) (fin);
84455682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
84555682Smarkm    if (bytes > 0)
84655682Smarkm	ptransfer ("sent", bytes, &start, &stop);
84755682Smarkm}
84855682Smarkm
84955682Smarkmjmp_buf recvabort;
85055682Smarkm
85155682Smarkmvoid
85255682Smarkmabortrecv (int sig)
85355682Smarkm{
85455682Smarkm
85555682Smarkm    mflag = 0;
85655682Smarkm    abrtflag = 0;
85755682Smarkm    printf ("\nreceive aborted\nwaiting for remote to finish abort\n");
85855682Smarkm    fflush (stdout);
85955682Smarkm    longjmp (recvabort, 1);
86055682Smarkm}
86155682Smarkm
86255682Smarkmvoid
86355682Smarkmrecvrequest (char *cmd, char *local, char *remote,
86455682Smarkm	     char *lmode, int printnames, int local_given)
86555682Smarkm{
866178825Sdfr    FILE *fout = NULL, *din = NULL;
86755682Smarkm    int (*closefunc) (FILE *);
86855682Smarkm    sighand oldintr, oldintp;
86955682Smarkm    int c, d, is_retr, tcrflag, bare_lfs = 0;
87055682Smarkm    static size_t bufsize;
87155682Smarkm    static char *buf;
87255682Smarkm    long bytes = 0, hashbytes = HASHBYTES;
87355682Smarkm    struct timeval start, stop;
87455682Smarkm    struct stat st;
87555682Smarkm
87655682Smarkm    is_retr = strcmp (cmd, "RETR") == 0;
87755682Smarkm    if (is_retr && verbose && printnames) {
87855682Smarkm	if (local && strcmp (local, "-") != 0)
87955682Smarkm	    printf ("local: %s ", local);
88055682Smarkm	if (remote)
88155682Smarkm	    printf ("remote: %s\n", remote);
88255682Smarkm    }
88355682Smarkm    if (proxy && is_retr) {
88455682Smarkm	proxtrans (cmd, local, remote);
88555682Smarkm	return;
88655682Smarkm    }
88755682Smarkm    closefunc = NULL;
88855682Smarkm    oldintr = NULL;
88955682Smarkm    oldintp = NULL;
89055682Smarkm    tcrflag = !crflag && is_retr;
89155682Smarkm    if (setjmp (recvabort)) {
89255682Smarkm	while (cpend) {
89355682Smarkm	    getreply (0);
89455682Smarkm	}
89555682Smarkm	if (data >= 0) {
89655682Smarkm	    close (data);
89755682Smarkm	    data = -1;
89855682Smarkm	}
89955682Smarkm	if (oldintr)
90055682Smarkm	    signal (SIGINT, oldintr);
90155682Smarkm	code = -1;
90255682Smarkm	return;
90355682Smarkm    }
90455682Smarkm    oldintr = signal (SIGINT, abortrecv);
90555682Smarkm    if (!local_given || (strcmp (local, "-") && *local != '|')) {
90655682Smarkm	if (access (local, 2) < 0) {
90755682Smarkm	    char *dir = strrchr (local, '/');
90855682Smarkm
90955682Smarkm	    if (errno != ENOENT && errno != EACCES) {
91055682Smarkm		warn ("local: %s", local);
91155682Smarkm		signal (SIGINT, oldintr);
91255682Smarkm		code = -1;
91355682Smarkm		return;
91455682Smarkm	    }
91555682Smarkm	    if (dir != NULL)
91655682Smarkm		*dir = 0;
91755682Smarkm	    d = access (dir ? local : ".", 2);
91855682Smarkm	    if (dir != NULL)
91955682Smarkm		*dir = '/';
92055682Smarkm	    if (d < 0) {
92155682Smarkm		warn ("local: %s", local);
92255682Smarkm		signal (SIGINT, oldintr);
92355682Smarkm		code = -1;
92455682Smarkm		return;
92555682Smarkm	    }
92655682Smarkm	    if (!runique && errno == EACCES &&
92755682Smarkm		chmod (local, 0600) < 0) {
92855682Smarkm		warn ("local: %s", local);
92955682Smarkm		signal (SIGINT, oldintr);
93055682Smarkm		signal (SIGINT, oldintr);
93155682Smarkm		code = -1;
93255682Smarkm		return;
93355682Smarkm	    }
93455682Smarkm	    if (runique && errno == EACCES &&
93555682Smarkm		(local = gunique (local)) == NULL) {
93655682Smarkm		signal (SIGINT, oldintr);
93755682Smarkm		code = -1;
93855682Smarkm		return;
93955682Smarkm	    }
94055682Smarkm	} else if (runique && (local = gunique (local)) == NULL) {
94155682Smarkm	    signal(SIGINT, oldintr);
94255682Smarkm	    code = -1;
94355682Smarkm	    return;
94455682Smarkm	}
94555682Smarkm    }
94655682Smarkm    if (!is_retr) {
94755682Smarkm	if (curtype != TYPE_A)
94855682Smarkm	    changetype (TYPE_A, 0);
94955682Smarkm    } else if (curtype != type)
95055682Smarkm	changetype (type, 0);
95155682Smarkm    if (initconn ()) {
95255682Smarkm	signal (SIGINT, oldintr);
95355682Smarkm	code = -1;
95455682Smarkm	return;
95555682Smarkm    }
95655682Smarkm    if (setjmp (recvabort))
95755682Smarkm	goto abort;
95855682Smarkm    if (is_retr && restart_point &&
95955682Smarkm	command ("REST %ld", (long) restart_point) != CONTINUE)
96055682Smarkm	return;
96155682Smarkm    if (remote) {
96255682Smarkm	if (command ("%s %s", cmd, remote) != PRELIM) {
96355682Smarkm	    signal (SIGINT, oldintr);
96455682Smarkm	    return;
96555682Smarkm	}
96655682Smarkm    } else {
96755682Smarkm	if (command ("%s", cmd) != PRELIM) {
96855682Smarkm	    signal (SIGINT, oldintr);
96955682Smarkm	    return;
97055682Smarkm	}
97155682Smarkm    }
97255682Smarkm    din = dataconn ("r");
97355682Smarkm    if (din == NULL)
97455682Smarkm	goto abort;
97555682Smarkm    set_buffer_size (fileno (din), 1);
97655682Smarkm    if (local_given && strcmp (local, "-") == 0)
97755682Smarkm	fout = stdout;
97855682Smarkm    else if (local_given && *local == '|') {
97955682Smarkm	oldintp = signal (SIGPIPE, SIG_IGN);
98055682Smarkm	fout = popen (local + 1, "w");
98155682Smarkm	if (fout == NULL) {
98255682Smarkm	    warn ("%s", local + 1);
98355682Smarkm	    goto abort;
98455682Smarkm	}
98555682Smarkm	closefunc = pclose;
98655682Smarkm    } else {
98755682Smarkm	fout = fopen (local, lmode);
98855682Smarkm	if (fout == NULL) {
98955682Smarkm	    warn ("local: %s", local);
99055682Smarkm	    goto abort;
99155682Smarkm	}
99255682Smarkm	closefunc = fclose;
99355682Smarkm    }
99455682Smarkm    buf = alloc_buffer (buf, &bufsize,
99555682Smarkm			fstat (fileno (fout), &st) >= 0 ? &st : NULL);
99655682Smarkm    if (buf == NULL)
99755682Smarkm	goto abort;
99855682Smarkm
99955682Smarkm    gettimeofday (&start, (struct timezone *) 0);
100055682Smarkm    switch (curtype) {
100155682Smarkm
100255682Smarkm    case TYPE_I:
100355682Smarkm    case TYPE_L:
100455682Smarkm	if (restart_point &&
100555682Smarkm	    lseek (fileno (fout), restart_point, SEEK_SET) < 0) {
100655682Smarkm	    warn ("local: %s", local);
100755682Smarkm	    if (closefunc != NULL)
100855682Smarkm		(*closefunc) (fout);
100955682Smarkm	    return;
101055682Smarkm	}
101155682Smarkm	errno = d = 0;
101255682Smarkm	while ((c = sec_read (fileno (din), buf, bufsize)) > 0) {
101355682Smarkm	    if ((d = write (fileno (fout), buf, c)) != c)
101455682Smarkm		break;
101555682Smarkm	    bytes += c;
101655682Smarkm	    if (hash) {
101755682Smarkm		while (bytes >= hashbytes) {
101855682Smarkm		    putchar ('#');
101955682Smarkm		    hashbytes += HASHBYTES;
102055682Smarkm		}
102155682Smarkm		fflush (stdout);
102255682Smarkm	    }
102355682Smarkm	}
102455682Smarkm	if (hash && bytes > 0) {
102555682Smarkm	    if (bytes < HASHBYTES)
102655682Smarkm		putchar ('#');
102755682Smarkm	    putchar ('\n');
102855682Smarkm	    fflush (stdout);
102955682Smarkm	}
103055682Smarkm	if (c < 0) {
103155682Smarkm	    if (errno != EPIPE)
103255682Smarkm		warn ("netin");
103355682Smarkm	    bytes = -1;
103455682Smarkm	}
103555682Smarkm	if (d < c) {
103655682Smarkm	    if (d < 0)
103755682Smarkm		warn ("local: %s", local);
103855682Smarkm	    else
103955682Smarkm		warnx ("%s: short write", local);
104055682Smarkm	}
104155682Smarkm	break;
104255682Smarkm
104355682Smarkm    case TYPE_A:
104455682Smarkm	if (restart_point) {
104555682Smarkm	    int i, n, ch;
104655682Smarkm
104755682Smarkm	    if (fseek (fout, 0L, SEEK_SET) < 0)
104855682Smarkm		goto done;
104955682Smarkm	    n = restart_point;
105055682Smarkm	    for (i = 0; i++ < n;) {
105155682Smarkm		if ((ch = sec_getc (fout)) == EOF)
105255682Smarkm		    goto done;
105355682Smarkm		if (ch == '\n')
105455682Smarkm		    i++;
105555682Smarkm	    }
105655682Smarkm	    if (fseek (fout, 0L, SEEK_CUR) < 0) {
105755682Smarkm	done:
105855682Smarkm		warn ("local: %s", local);
105955682Smarkm		if (closefunc != NULL)
106055682Smarkm		    (*closefunc) (fout);
106155682Smarkm		return;
106255682Smarkm	    }
106355682Smarkm	}
106455682Smarkm	while ((c = sec_getc(din)) != EOF) {
106555682Smarkm	    if (c == '\n')
106655682Smarkm		bare_lfs++;
106755682Smarkm	    while (c == '\r') {
106855682Smarkm		while (hash && (bytes >= hashbytes)) {
106955682Smarkm		    putchar ('#');
107055682Smarkm		    fflush (stdout);
107155682Smarkm		    hashbytes += HASHBYTES;
107255682Smarkm		}
107355682Smarkm		bytes++;
107455682Smarkm		if ((c = sec_getc (din)) != '\n' || tcrflag) {
107555682Smarkm		    if (ferror (fout))
107655682Smarkm			goto break2;
107755682Smarkm		    putc ('\r', fout);
107855682Smarkm		    if (c == '\0') {
107955682Smarkm			bytes++;
108055682Smarkm			goto contin2;
108155682Smarkm		    }
108255682Smarkm		    if (c == EOF)
108355682Smarkm			goto contin2;
108455682Smarkm		}
108555682Smarkm	    }
108655682Smarkm	    putc (c, fout);
108755682Smarkm	    bytes++;
108855682Smarkm    contin2:;
108955682Smarkm	}
109055682Smarkmbreak2:
109155682Smarkm	if (bare_lfs) {
109255682Smarkm	    printf ("WARNING! %d bare linefeeds received in ASCII mode\n",
109355682Smarkm		    bare_lfs);
109455682Smarkm	    printf ("File may not have transferred correctly.\n");
109555682Smarkm	}
109655682Smarkm	if (hash) {
109755682Smarkm	    if (bytes < hashbytes)
109855682Smarkm		putchar ('#');
109955682Smarkm	    putchar ('\n');
110055682Smarkm	    fflush (stdout);
110155682Smarkm	}
110255682Smarkm	if (ferror (din)) {
110355682Smarkm	    if (errno != EPIPE)
110455682Smarkm		warn ("netin");
110555682Smarkm	    bytes = -1;
110655682Smarkm	}
110755682Smarkm	if (ferror (fout))
110855682Smarkm	    warn ("local: %s", local);
110955682Smarkm	break;
111055682Smarkm    }
111155682Smarkm    if (closefunc != NULL)
111255682Smarkm	(*closefunc) (fout);
111355682Smarkm    signal (SIGINT, oldintr);
111455682Smarkm    if (oldintp)
111555682Smarkm	signal (SIGPIPE, oldintp);
111655682Smarkm    fclose (din);
111755682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
111855682Smarkm    getreply (0);
111955682Smarkm    if (bytes > 0 && is_retr)
112055682Smarkm	ptransfer ("received", bytes, &start, &stop);
112155682Smarkm    return;
112255682Smarkmabort:
112355682Smarkm
112455682Smarkm    /* abort using RFC959 recommended IP,SYNC sequence  */
112555682Smarkm
112655682Smarkm    if (oldintp)
112755682Smarkm	signal (SIGPIPE, oldintr);
112855682Smarkm    signal (SIGINT, SIG_IGN);
112955682Smarkm    if (!cpend) {
113055682Smarkm	code = -1;
113155682Smarkm	signal (SIGINT, oldintr);
113255682Smarkm	return;
113355682Smarkm    }
113455682Smarkm    abort_remote(din);
113555682Smarkm    code = -1;
113655682Smarkm    if (data >= 0) {
113755682Smarkm	close (data);
113855682Smarkm	data = -1;
113955682Smarkm    }
114055682Smarkm    if (closefunc != NULL && fout != NULL)
114155682Smarkm	(*closefunc) (fout);
114255682Smarkm    if (din)
114355682Smarkm	fclose (din);
114455682Smarkm    gettimeofday (&stop, (struct timezone *) 0);
114555682Smarkm    if (bytes > 0)
114655682Smarkm	ptransfer ("received", bytes, &start, &stop);
114755682Smarkm    signal (SIGINT, oldintr);
114855682Smarkm}
114955682Smarkm
115055682Smarkmstatic int
115155682Smarkmparse_epsv (const char *str)
115255682Smarkm{
115355682Smarkm    char sep;
115455682Smarkm    char *end;
115555682Smarkm    int port;
115655682Smarkm
115755682Smarkm    if (*str == '\0')
115855682Smarkm	return -1;
115955682Smarkm    sep = *str++;
116055682Smarkm    if (sep != *str++)
116155682Smarkm	return -1;
116255682Smarkm    if (sep != *str++)
116355682Smarkm	return -1;
116455682Smarkm    port = strtol (str, &end, 0);
116555682Smarkm    if (str == end)
116655682Smarkm	return -1;
116755682Smarkm    if (end[0] != sep || end[1] != '\0')
116855682Smarkm	return -1;
116955682Smarkm    return htons(port);
117055682Smarkm}
117155682Smarkm
117255682Smarkmstatic int
1173178825Sdfrparse_pasv (struct sockaddr_in *sin4, const char *str)
117455682Smarkm{
117555682Smarkm    int a0, a1, a2, a3, p0, p1;
117655682Smarkm
117755682Smarkm    /*
117855682Smarkm     * What we've got at this point is a string of comma separated
117955682Smarkm     * one-byte unsigned integer values. The first four are the an IP
118055682Smarkm     * address. The fifth is the MSB of the port number, the sixth is the
118155682Smarkm     * LSB. From that we'll prepare a sockaddr_in.
118255682Smarkm     */
118355682Smarkm
118455682Smarkm    if (sscanf (str, "%d,%d,%d,%d,%d,%d",
118555682Smarkm		&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
118655682Smarkm	printf ("Passive mode address scan failure. "
118755682Smarkm		"Shouldn't happen!\n");
118855682Smarkm	return -1;
118955682Smarkm    }
119055682Smarkm    if (a0 < 0 || a0 > 255 ||
119155682Smarkm	a1 < 0 || a1 > 255 ||
119255682Smarkm	a2 < 0 || a2 > 255 ||
119355682Smarkm	a3 < 0 || a3 > 255 ||
119455682Smarkm	p0 < 0 || p0 > 255 ||
119555682Smarkm	p1 < 0 || p1 > 255) {
119655682Smarkm	printf ("Can't parse passive mode string.\n");
119755682Smarkm	return -1;
119855682Smarkm    }
1199178825Sdfr    memset (sin4, 0, sizeof(*sin4));
1200178825Sdfr    sin4->sin_family      = AF_INET;
1201178825Sdfr    sin4->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
120255682Smarkm				  (a2 << 8) | a3);
1203178825Sdfr    sin4->sin_port = htons ((p0 << 8) | p1);
120455682Smarkm    return 0;
120555682Smarkm}
120655682Smarkm
120755682Smarkmstatic int
120855682Smarkmpassive_mode (void)
120955682Smarkm{
121055682Smarkm    int port;
121155682Smarkm
121255682Smarkm    data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
121355682Smarkm    if (data < 0) {
121455682Smarkm	warn ("socket");
121555682Smarkm	return (1);
121655682Smarkm    }
121755682Smarkm    if (options & SO_DEBUG)
121855682Smarkm	socket_set_debug (data);
121955682Smarkm    if (command ("EPSV") != COMPLETE) {
122055682Smarkm	if (command ("PASV") != COMPLETE) {
122155682Smarkm	    printf ("Passive mode refused.\n");
122255682Smarkm	    goto bad;
122355682Smarkm	}
122455682Smarkm    }
122555682Smarkm
122655682Smarkm    /*
122755682Smarkm     * Parse the reply to EPSV or PASV
122855682Smarkm     */
122955682Smarkm
123055682Smarkm    port = parse_epsv (pasv);
123155682Smarkm    if (port > 0) {
123255682Smarkm	data_addr->sa_family = myctladdr->sa_family;
123355682Smarkm	socket_set_address_and_port (data_addr,
123455682Smarkm				     socket_get_address (hisctladdr),
123555682Smarkm				     port);
123655682Smarkm    } else {
123755682Smarkm	if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
123855682Smarkm	    goto bad;
123955682Smarkm    }
124055682Smarkm
124155682Smarkm    if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
124255682Smarkm	warn ("connect");
124355682Smarkm	goto bad;
124455682Smarkm    }
124555682Smarkm#ifdef IPTOS_THROUGHPUT
124655682Smarkm    socket_set_tos (data, IPTOS_THROUGHPUT);
124755682Smarkm#endif
124855682Smarkm    return (0);
124955682Smarkmbad:
125055682Smarkm    close (data);
125155682Smarkm    data = -1;
125255682Smarkm    sendport = 1;
125355682Smarkm    return (1);
125455682Smarkm}
125555682Smarkm
125655682Smarkm
125755682Smarkmstatic int
125855682Smarkmactive_mode (void)
125955682Smarkm{
126055682Smarkm    int tmpno = 0;
126172445Sassar    socklen_t len;
126255682Smarkm    int result;
126355682Smarkm
126455682Smarkmnoport:
126555682Smarkm    data_addr->sa_family = myctladdr->sa_family;
126655682Smarkm    socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
126755682Smarkm				 sendport ? 0 : socket_get_port (myctladdr));
126855682Smarkm
126955682Smarkm    if (data != -1)
127055682Smarkm	close (data);
127155682Smarkm    data = socket (data_addr->sa_family, SOCK_STREAM, 0);
127255682Smarkm    if (data < 0) {
127355682Smarkm	warn ("socket");
127455682Smarkm	if (tmpno)
127555682Smarkm	    sendport = 1;
127655682Smarkm	return (1);
127755682Smarkm    }
127855682Smarkm    if (!sendport)
127955682Smarkm	socket_set_reuseaddr (data, 1);
128055682Smarkm    if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
128155682Smarkm	warn ("bind");
128255682Smarkm	goto bad;
128355682Smarkm    }
128455682Smarkm    if (options & SO_DEBUG)
128555682Smarkm	socket_set_debug (data);
128655682Smarkm    len = sizeof (data_addr_ss);
128755682Smarkm    if (getsockname (data, data_addr, &len) < 0) {
128855682Smarkm	warn ("getsockname");
128955682Smarkm	goto bad;
129055682Smarkm    }
129155682Smarkm    if (listen (data, 1) < 0)
129255682Smarkm	warn ("listen");
129355682Smarkm    if (sendport) {
129455682Smarkm	char addr_str[256];
129555682Smarkm	int inet_af;
129655682Smarkm	int overbose;
129755682Smarkm
129855682Smarkm	if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
129955682Smarkm		       addr_str, sizeof(addr_str)) == NULL)
130055682Smarkm	    errx (1, "inet_ntop failed");
130155682Smarkm	switch (data_addr->sa_family) {
130255682Smarkm	case AF_INET :
130355682Smarkm	    inet_af = 1;
130455682Smarkm	    break;
130555682Smarkm#ifdef HAVE_IPV6
130655682Smarkm	case AF_INET6 :
130755682Smarkm	    inet_af = 2;
130855682Smarkm	    break;
130955682Smarkm#endif
131055682Smarkm	default :
131155682Smarkm	    errx (1, "bad address family %d", data_addr->sa_family);
131255682Smarkm	}
131355682Smarkm
131455682Smarkm
131555682Smarkm	overbose = verbose;
131655682Smarkm	if (debug == 0)
131755682Smarkm	    verbose  = -1;
131855682Smarkm
1319103423Snectar	result = command ("EPRT |%d|%s|%d|",
1320103423Snectar			  inet_af, addr_str,
1321103423Snectar			  ntohs(socket_get_port (data_addr)));
132255682Smarkm	verbose = overbose;
132355682Smarkm
132455682Smarkm	if (result == ERROR) {
1325178825Sdfr	    struct sockaddr_in *sin4 = (struct sockaddr_in *)data_addr;
132655682Smarkm
1327178825Sdfr	    unsigned int a = ntohl(sin4->sin_addr.s_addr);
1328178825Sdfr	    unsigned int p = ntohs(sin4->sin_port);
132955682Smarkm
133055682Smarkm	    if (data_addr->sa_family != AF_INET) {
133155682Smarkm		warnx ("remote server doesn't support EPRT");
133255682Smarkm		goto bad;
133355682Smarkm	    }
133455682Smarkm
133555682Smarkm	    result = command("PORT %d,%d,%d,%d,%d,%d",
133655682Smarkm			     (a >> 24) & 0xff,
133755682Smarkm			     (a >> 16) & 0xff,
133855682Smarkm			     (a >> 8) & 0xff,
133955682Smarkm			     a & 0xff,
134055682Smarkm			     (p >> 8) & 0xff,
134155682Smarkm			     p & 0xff);
134255682Smarkm	    if (result == ERROR && sendport == -1) {
134355682Smarkm		sendport = 0;
134455682Smarkm		tmpno = 1;
134555682Smarkm		goto noport;
134655682Smarkm	    }
134755682Smarkm	    return (result != COMPLETE);
134855682Smarkm	}
134955682Smarkm	return result != COMPLETE;
135055682Smarkm    }
135155682Smarkm    if (tmpno)
135255682Smarkm	sendport = 1;
135355682Smarkm
135455682Smarkm
135555682Smarkm#ifdef IPTOS_THROUGHPUT
135655682Smarkm    socket_set_tos (data, IPTOS_THROUGHPUT);
135755682Smarkm#endif
135855682Smarkm    return (0);
135955682Smarkmbad:
136055682Smarkm    close (data);
136155682Smarkm    data = -1;
136255682Smarkm    if (tmpno)
136355682Smarkm	sendport = 1;
136455682Smarkm    return (1);
136555682Smarkm}
136655682Smarkm
136755682Smarkm/*
136855682Smarkm * Need to start a listen on the data channel before we send the command,
136955682Smarkm * otherwise the server's connect may fail.
137055682Smarkm */
137155682Smarkmint
137255682Smarkminitconn (void)
137355682Smarkm{
137455682Smarkm    if (passivemode)
137555682Smarkm	return passive_mode ();
137655682Smarkm    else
137755682Smarkm	return active_mode ();
137855682Smarkm}
137955682Smarkm
138055682SmarkmFILE *
138155682Smarkmdataconn (const char *lmode)
138255682Smarkm{
138355682Smarkm    struct sockaddr_storage from_ss;
138455682Smarkm    struct sockaddr *from = (struct sockaddr *)&from_ss;
138572445Sassar    socklen_t fromlen = sizeof(from_ss);
138672445Sassar    int s;
138755682Smarkm
138855682Smarkm    if (passivemode)
138955682Smarkm	return (fdopen (data, lmode));
139055682Smarkm
139155682Smarkm    s = accept (data, from, &fromlen);
139255682Smarkm    if (s < 0) {
139355682Smarkm	warn ("accept");
139455682Smarkm	close (data), data = -1;
139555682Smarkm	return (NULL);
139655682Smarkm    }
139755682Smarkm    close (data);
139855682Smarkm    data = s;
139955682Smarkm#ifdef IPTOS_THROUGHPUT
140055682Smarkm    socket_set_tos (s, IPTOS_THROUGHPUT);
140155682Smarkm#endif
140255682Smarkm    return (fdopen (data, lmode));
140355682Smarkm}
140455682Smarkm
140555682Smarkmvoid
140655682Smarkmptransfer (char *direction, long int bytes,
140755682Smarkm	   struct timeval * t0, struct timeval * t1)
140855682Smarkm{
140955682Smarkm    struct timeval td;
141055682Smarkm    float s;
141155682Smarkm    float bs;
141255682Smarkm    int prec;
141355682Smarkm    char *unit;
141455682Smarkm
141555682Smarkm    if (verbose) {
141655682Smarkm	td.tv_sec = t1->tv_sec - t0->tv_sec;
141755682Smarkm	td.tv_usec = t1->tv_usec - t0->tv_usec;
141855682Smarkm	if (td.tv_usec < 0) {
141955682Smarkm	    td.tv_sec--;
142055682Smarkm	    td.tv_usec += 1000000;
142155682Smarkm	}
142255682Smarkm	s = td.tv_sec + (td.tv_usec / 1000000.);
142355682Smarkm	bs = bytes / (s ? s : 1);
142455682Smarkm	if (bs >= 1048576) {
142555682Smarkm	    bs /= 1048576;
142655682Smarkm	    unit = "M";
142755682Smarkm	    prec = 2;
142855682Smarkm	} else if (bs >= 1024) {
142955682Smarkm	    bs /= 1024;
143055682Smarkm	    unit = "k";
143155682Smarkm	    prec = 1;
143255682Smarkm	} else {
143355682Smarkm	    unit = "";
143455682Smarkm	    prec = 0;
143555682Smarkm	}
143655682Smarkm
143755682Smarkm	printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n",
143855682Smarkm		bytes, direction, s, prec, bs, unit);
143955682Smarkm    }
144055682Smarkm}
144155682Smarkm
144255682Smarkmvoid
144355682Smarkmpsabort (int sig)
144455682Smarkm{
144555682Smarkm
144655682Smarkm    abrtflag++;
144755682Smarkm}
144855682Smarkm
144955682Smarkmvoid
145055682Smarkmpswitch (int flag)
145155682Smarkm{
145255682Smarkm    sighand oldintr;
145355682Smarkm    static struct comvars {
145455682Smarkm	int connect;
145555682Smarkm	char name[MaxHostNameLen];
145655682Smarkm	struct sockaddr_storage mctl;
145755682Smarkm	struct sockaddr_storage hctl;
145855682Smarkm	FILE *in;
145955682Smarkm	FILE *out;
146055682Smarkm	int tpe;
146155682Smarkm	int curtpe;
146255682Smarkm	int cpnd;
146355682Smarkm	int sunqe;
146455682Smarkm	int runqe;
146555682Smarkm	int mcse;
146655682Smarkm	int ntflg;
146755682Smarkm	char nti[17];
146855682Smarkm	char nto[17];
146955682Smarkm	int mapflg;
147055682Smarkm	char mi[MaxPathLen];
147155682Smarkm	char mo[MaxPathLen];
147255682Smarkm    } proxstruct, tmpstruct;
147355682Smarkm    struct comvars *ip, *op;
147455682Smarkm
147555682Smarkm    abrtflag = 0;
147655682Smarkm    oldintr = signal (SIGINT, psabort);
147755682Smarkm    if (flag) {
147855682Smarkm	if (proxy)
147955682Smarkm	    return;
148055682Smarkm	ip = &tmpstruct;
148155682Smarkm	op = &proxstruct;
148255682Smarkm	proxy++;
148355682Smarkm    } else {
148455682Smarkm	if (!proxy)
148555682Smarkm	    return;
148655682Smarkm	ip = &proxstruct;
148755682Smarkm	op = &tmpstruct;
148855682Smarkm	proxy = 0;
148955682Smarkm    }
149055682Smarkm    ip->connect = connected;
149155682Smarkm    connected = op->connect;
149255682Smarkm    if (hostname) {
149355682Smarkm	strlcpy (ip->name, hostname, sizeof (ip->name));
149455682Smarkm    } else
149555682Smarkm	ip->name[0] = 0;
149655682Smarkm    hostname = op->name;
149755682Smarkm    ip->hctl = hisctladdr_ss;
149855682Smarkm    hisctladdr_ss = op->hctl;
149955682Smarkm    ip->mctl = myctladdr_ss;
150055682Smarkm    myctladdr_ss = op->mctl;
150155682Smarkm    ip->in = cin;
150255682Smarkm    cin = op->in;
150355682Smarkm    ip->out = cout;
150455682Smarkm    cout = op->out;
150555682Smarkm    ip->tpe = type;
150655682Smarkm    type = op->tpe;
150755682Smarkm    ip->curtpe = curtype;
150855682Smarkm    curtype = op->curtpe;
150955682Smarkm    ip->cpnd = cpend;
151055682Smarkm    cpend = op->cpnd;
151155682Smarkm    ip->sunqe = sunique;
151255682Smarkm    sunique = op->sunqe;
151355682Smarkm    ip->runqe = runique;
151455682Smarkm    runique = op->runqe;
151555682Smarkm    ip->mcse = mcase;
151655682Smarkm    mcase = op->mcse;
151755682Smarkm    ip->ntflg = ntflag;
151855682Smarkm    ntflag = op->ntflg;
151955682Smarkm    strlcpy (ip->nti, ntin, sizeof (ip->nti));
152055682Smarkm    strlcpy (ntin, op->nti, 17);
152155682Smarkm    strlcpy (ip->nto, ntout, sizeof (ip->nto));
152255682Smarkm    strlcpy (ntout, op->nto, 17);
152355682Smarkm    ip->mapflg = mapflag;
152455682Smarkm    mapflag = op->mapflg;
152555682Smarkm    strlcpy (ip->mi, mapin, MaxPathLen);
152655682Smarkm    strlcpy (mapin, op->mi, MaxPathLen);
152755682Smarkm    strlcpy (ip->mo, mapout, MaxPathLen);
152855682Smarkm    strlcpy (mapout, op->mo, MaxPathLen);
152955682Smarkm    signal(SIGINT, oldintr);
153055682Smarkm    if (abrtflag) {
153155682Smarkm	abrtflag = 0;
153255682Smarkm	(*oldintr) (SIGINT);
153355682Smarkm    }
153455682Smarkm}
153555682Smarkm
153655682Smarkmvoid
153755682Smarkmabortpt (int sig)
153855682Smarkm{
153955682Smarkm
154055682Smarkm    printf ("\n");
154155682Smarkm    fflush (stdout);
154255682Smarkm    ptabflg++;
154355682Smarkm    mflag = 0;
154455682Smarkm    abrtflag = 0;
154555682Smarkm    longjmp (ptabort, 1);
154655682Smarkm}
154755682Smarkm
154855682Smarkmvoid
154955682Smarkmproxtrans (char *cmd, char *local, char *remote)
155055682Smarkm{
1551178825Sdfr    sighand oldintr = NULL;
155255682Smarkm    int secndflag = 0, prox_type, nfnd;
155355682Smarkm    char *cmd2;
155455682Smarkm    fd_set mask;
155555682Smarkm
155655682Smarkm    if (strcmp (cmd, "RETR"))
155755682Smarkm	cmd2 = "RETR";
155855682Smarkm    else
155955682Smarkm	cmd2 = runique ? "STOU" : "STOR";
156055682Smarkm    if ((prox_type = type) == 0) {
156155682Smarkm	if (unix_server && unix_proxy)
156255682Smarkm	    prox_type = TYPE_I;
156355682Smarkm	else
156455682Smarkm	    prox_type = TYPE_A;
156555682Smarkm    }
156655682Smarkm    if (curtype != prox_type)
156755682Smarkm	changetype (prox_type, 1);
156855682Smarkm    if (command ("PASV") != COMPLETE) {
156955682Smarkm	printf ("proxy server does not support third party transfers.\n");
157055682Smarkm	return;
157155682Smarkm    }
157255682Smarkm    pswitch (0);
157355682Smarkm    if (!connected) {
157455682Smarkm	printf ("No primary connection\n");
157555682Smarkm	pswitch (1);
157655682Smarkm	code = -1;
157755682Smarkm	return;
157855682Smarkm    }
157955682Smarkm    if (curtype != prox_type)
158055682Smarkm	changetype (prox_type, 1);
158155682Smarkm    if (command ("PORT %s", pasv) != COMPLETE) {
158255682Smarkm	pswitch (1);
158355682Smarkm	return;
158455682Smarkm    }
158555682Smarkm    if (setjmp (ptabort))
158655682Smarkm	goto abort;
158755682Smarkm    oldintr = signal (SIGINT, abortpt);
158855682Smarkm    if (command ("%s %s", cmd, remote) != PRELIM) {
158955682Smarkm	signal (SIGINT, oldintr);
159055682Smarkm	pswitch (1);
159155682Smarkm	return;
159255682Smarkm    }
159355682Smarkm    sleep (2);
159455682Smarkm    pswitch (1);
159555682Smarkm    secndflag++;
159655682Smarkm    if (command ("%s %s", cmd2, local) != PRELIM)
159755682Smarkm	goto abort;
159855682Smarkm    ptflag++;
159955682Smarkm    getreply (0);
160055682Smarkm    pswitch (0);
160155682Smarkm    getreply (0);
160255682Smarkm    signal (SIGINT, oldintr);
160355682Smarkm    pswitch (1);
160455682Smarkm    ptflag = 0;
160555682Smarkm    printf ("local: %s remote: %s\n", local, remote);
160655682Smarkm    return;
160755682Smarkmabort:
160855682Smarkm    signal (SIGINT, SIG_IGN);
160955682Smarkm    ptflag = 0;
161055682Smarkm    if (strcmp (cmd, "RETR") && !proxy)
161155682Smarkm	pswitch (1);
161255682Smarkm    else if (!strcmp (cmd, "RETR") && proxy)
161355682Smarkm	pswitch (0);
161455682Smarkm    if (!cpend && !secndflag) {	/* only here if cmd = "STOR" (proxy=1) */
161555682Smarkm	if (command ("%s %s", cmd2, local) != PRELIM) {
161655682Smarkm	    pswitch (0);
161755682Smarkm	    if (cpend)
161855682Smarkm		abort_remote ((FILE *) NULL);
161955682Smarkm	}
162055682Smarkm	pswitch (1);
162155682Smarkm	if (ptabflg)
162255682Smarkm	    code = -1;
1623178825Sdfr	if (oldintr)
1624178825Sdfr	    signal (SIGINT, oldintr);
162555682Smarkm	return;
162655682Smarkm    }
162755682Smarkm    if (cpend)
162855682Smarkm	abort_remote ((FILE *) NULL);
162955682Smarkm    pswitch (!proxy);
163055682Smarkm    if (!cpend && !secndflag) {	/* only if cmd = "RETR" (proxy=1) */
163155682Smarkm	if (command ("%s %s", cmd2, local) != PRELIM) {
163255682Smarkm	    pswitch (0);
163355682Smarkm	    if (cpend)
163455682Smarkm		abort_remote ((FILE *) NULL);
163555682Smarkm	    pswitch (1);
163655682Smarkm	    if (ptabflg)
163755682Smarkm		code = -1;
163855682Smarkm	    signal (SIGINT, oldintr);
163955682Smarkm	    return;
164055682Smarkm	}
164155682Smarkm    }
164255682Smarkm    if (cpend)
164355682Smarkm	abort_remote ((FILE *) NULL);
164455682Smarkm    pswitch (!proxy);
164555682Smarkm    if (cpend) {
164655682Smarkm	FD_ZERO (&mask);
164772445Sassar	if (fileno(cin) >= FD_SETSIZE)
164872445Sassar	    errx (1, "fd too large");
164955682Smarkm	FD_SET (fileno (cin), &mask);
165055682Smarkm	if ((nfnd = empty (&mask, 10)) <= 0) {
165155682Smarkm	    if (nfnd < 0) {
165255682Smarkm		warn ("abort");
165355682Smarkm	    }
165455682Smarkm	    if (ptabflg)
165555682Smarkm		code = -1;
165655682Smarkm	    lostpeer (0);
165755682Smarkm	}
165855682Smarkm	getreply (0);
165955682Smarkm	getreply (0);
166055682Smarkm    }
166155682Smarkm    if (proxy)
166255682Smarkm	pswitch (0);
166355682Smarkm    pswitch (1);
166455682Smarkm    if (ptabflg)
166555682Smarkm	code = -1;
166655682Smarkm    signal (SIGINT, oldintr);
166755682Smarkm}
166855682Smarkm
166955682Smarkmvoid
167055682Smarkmreset (int argc, char **argv)
167155682Smarkm{
167255682Smarkm    fd_set mask;
167355682Smarkm    int nfnd = 1;
167455682Smarkm
167555682Smarkm    FD_ZERO (&mask);
167655682Smarkm    while (nfnd > 0) {
167772445Sassar	if (fileno (cin) >= FD_SETSIZE)
167872445Sassar	    errx (1, "fd too large");
167955682Smarkm	FD_SET (fileno (cin), &mask);
168055682Smarkm	if ((nfnd = empty (&mask, 0)) < 0) {
168155682Smarkm	    warn ("reset");
168255682Smarkm	    code = -1;
168355682Smarkm	    lostpeer(0);
168455682Smarkm	} else if (nfnd) {
168555682Smarkm	    getreply(0);
168655682Smarkm	}
168755682Smarkm    }
168855682Smarkm}
168955682Smarkm
169055682Smarkmchar *
169155682Smarkmgunique (char *local)
169255682Smarkm{
169355682Smarkm    static char new[MaxPathLen];
169455682Smarkm    char *cp = strrchr (local, '/');
169555682Smarkm    int d, count = 0;
169655682Smarkm    char ext = '1';
169755682Smarkm
169855682Smarkm    if (cp)
169955682Smarkm	*cp = '\0';
170055682Smarkm    d = access (cp ? local : ".", 2);
170155682Smarkm    if (cp)
170255682Smarkm	*cp = '/';
170355682Smarkm    if (d < 0) {
170455682Smarkm	warn ("local: %s", local);
170555682Smarkm	return NULL;
170655682Smarkm    }
170755682Smarkm    strlcpy (new, local, sizeof(new));
170855682Smarkm    cp = new + strlen(new);
170955682Smarkm    *cp++ = '.';
171055682Smarkm    while (!d) {
171155682Smarkm	if (++count == 100) {
171255682Smarkm	    printf ("runique: can't find unique file name.\n");
171355682Smarkm	    return NULL;
171455682Smarkm	}
171555682Smarkm	*cp++ = ext;
171655682Smarkm	*cp = '\0';
171755682Smarkm	if (ext == '9')
171855682Smarkm	    ext = '0';
171955682Smarkm	else
172055682Smarkm	    ext++;
172155682Smarkm	if ((d = access (new, 0)) < 0)
172255682Smarkm	    break;
172355682Smarkm	if (ext != '0')
172455682Smarkm	    cp--;
172555682Smarkm	else if (*(cp - 2) == '.')
172655682Smarkm	    *(cp - 1) = '1';
172755682Smarkm	else {
172855682Smarkm	    *(cp - 2) = *(cp - 2) + 1;
172955682Smarkm	    cp--;
173055682Smarkm	}
173155682Smarkm    }
173255682Smarkm    return (new);
173355682Smarkm}
173455682Smarkm
173555682Smarkmvoid
173655682Smarkmabort_remote (FILE * din)
173755682Smarkm{
173855682Smarkm    char buf[BUFSIZ];
173955682Smarkm    int nfnd;
174055682Smarkm    fd_set mask;
174155682Smarkm
174255682Smarkm    /*
174355682Smarkm     * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
174455682Smarkm     * after urgent byte rather than before as is protocol now
174555682Smarkm     */
174655682Smarkm    snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC);
174755682Smarkm    if (send (fileno (cout), buf, 3, MSG_OOB) != 3)
174855682Smarkm	warn ("abort");
1749142403Snectar    fprintf (cout, "%c", DM);
1750142403Snectar    sec_fprintf(cout, "ABOR");
1751142403Snectar    sec_fflush (cout);
1752142403Snectar    fprintf (cout, "\r\n");
1753142403Snectar    fflush(cout);
175455682Smarkm    FD_ZERO (&mask);
175572445Sassar    if (fileno (cin) >= FD_SETSIZE)
175672445Sassar	errx (1, "fd too large");
175755682Smarkm    FD_SET (fileno (cin), &mask);
175855682Smarkm    if (din) {
1759178825Sdfr	if (fileno (din) >= FD_SETSIZE)
1760178825Sdfr	    errx (1, "fd too large");
176155682Smarkm	FD_SET (fileno (din), &mask);
176255682Smarkm    }
176355682Smarkm    if ((nfnd = empty (&mask, 10)) <= 0) {
176455682Smarkm	if (nfnd < 0) {
176555682Smarkm	    warn ("abort");
176655682Smarkm	}
176755682Smarkm	if (ptabflg)
176855682Smarkm	    code = -1;
176955682Smarkm	lostpeer (0);
177055682Smarkm    }
177155682Smarkm    if (din && FD_ISSET (fileno (din), &mask)) {
177255682Smarkm	while (read (fileno (din), buf, BUFSIZ) > 0)
177355682Smarkm	     /* LOOP */ ;
177455682Smarkm    }
177555682Smarkm    if (getreply (0) == ERROR && code == 552) {
177655682Smarkm	/* 552 needed for nic style abort */
177755682Smarkm	getreply (0);
177855682Smarkm    }
177955682Smarkm    getreply (0);
178055682Smarkm}
1781