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