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