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/*
3555682Smarkm * FTP User Program -- Command Routines.
3655682Smarkm */
3755682Smarkm
3855682Smarkm#include "ftp_locl.h"
39233294SstasRCSID("$Id$");
4055682Smarkm
4155682Smarkmtypedef void (*sighand)(int);
4255682Smarkm
4355682Smarkmjmp_buf	jabort;
4455682Smarkmchar   *mname;
4555682Smarkmchar   *home = "/";
4655682Smarkm
4755682Smarkm/*
4855682Smarkm * `Another' gets another argument, and stores the new argc and argv.
4955682Smarkm * It reverts to the top level (via main.c's intr()) on EOF/error.
5055682Smarkm *
5155682Smarkm * Returns false if no new arguments have been added.
5255682Smarkm */
5355682Smarkmint
5455682Smarkmanother(int *pargc, char ***pargv, char *prompt)
5555682Smarkm{
5655682Smarkm	int len = strlen(line), ret;
5755682Smarkm
5855682Smarkm	if (len >= sizeof(line) - 3) {
5955682Smarkm		printf("sorry, arguments too long\n");
6055682Smarkm		intr(0);
6155682Smarkm	}
6255682Smarkm	printf("(%s) ", prompt);
6355682Smarkm	line[len++] = ' ';
6455682Smarkm	if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
6555682Smarkm		intr(0);
6655682Smarkm	len += strlen(&line[len]);
6755682Smarkm	if (len > 0 && line[len - 1] == '\n')
6855682Smarkm		line[len - 1] = '\0';
6955682Smarkm	makeargv();
7055682Smarkm	ret = margc > *pargc;
7155682Smarkm	*pargc = margc;
7255682Smarkm	*pargv = margv;
7355682Smarkm	return (ret);
7455682Smarkm}
7555682Smarkm
7655682Smarkm/*
7755682Smarkm * Connect to peer server and
7855682Smarkm * auto-login, if possible.
7955682Smarkm */
8055682Smarkmvoid
8155682Smarkmsetpeer(int argc, char **argv)
8255682Smarkm{
8355682Smarkm	char *host;
8478527Sassar	u_short port;
8555682Smarkm	struct servent *sp;
8655682Smarkm
8755682Smarkm	if (connected) {
8855682Smarkm		printf("Already connected to %s, use close first.\n",
8955682Smarkm			hostname);
9055682Smarkm		code = -1;
9155682Smarkm		return;
9255682Smarkm	}
9355682Smarkm	if (argc < 2)
9455682Smarkm		another(&argc, &argv, "to");
9555682Smarkm	if (argc < 2 || argc > 3) {
9655682Smarkm		printf("usage: %s host-name [port]\n", argv[0]);
9755682Smarkm		code = -1;
9855682Smarkm		return;
9955682Smarkm	}
10055682Smarkm	sp = getservbyname("ftp", "tcp");
10155682Smarkm	if (sp == NULL)
10255682Smarkm		errx(1, "You bastard. You removed ftp/tcp from services");
10355682Smarkm	port = sp->s_port;
10455682Smarkm	if (argc > 2) {
10578527Sassar		sp = getservbyname(argv[2], "tcp");
10678527Sassar		if (sp != NULL) {
10778527Sassar			port = sp->s_port;
10878527Sassar		} else {
10978527Sassar			char *ep;
11078527Sassar
11178527Sassar			port = strtol(argv[2], &ep, 0);
11278527Sassar			if (argv[2] == ep) {
11378527Sassar				printf("%s: bad port number-- %s\n",
11478527Sassar				       argv[1], argv[2]);
11578527Sassar				printf ("usage: %s host-name [port]\n",
11678527Sassar					argv[0]);
11778527Sassar				code = -1;
11878527Sassar				return;
11978527Sassar			}
12078527Sassar			port = htons(port);
12155682Smarkm		}
12255682Smarkm	}
12355682Smarkm	host = hookup(argv[1], port);
12455682Smarkm	if (host) {
12555682Smarkm		int overbose;
12655682Smarkm
12755682Smarkm		connected = 1;
12855682Smarkm		/*
12955682Smarkm		 * Set up defaults for FTP.
13055682Smarkm		 */
13155682Smarkm		strlcpy(typename, "ascii", sizeof(typename));
13255682Smarkm		type = TYPE_A;
13355682Smarkm		curtype = TYPE_A;
13455682Smarkm		strlcpy(formname, "non-print", sizeof(formname));
13555682Smarkm		form = FORM_N;
13655682Smarkm		strlcpy(modename, "stream", sizeof(modename));
13755682Smarkm		mode = MODE_S;
13855682Smarkm		strlcpy(structname, "file", sizeof(structname));
13955682Smarkm		stru = STRU_F;
14055682Smarkm		strlcpy(bytename, "8", sizeof(bytename));
14155682Smarkm		bytesize = 8;
14255682Smarkm		if (autologin)
14355682Smarkm			login(argv[1]);
14455682Smarkm
145178825Sdfr#if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__) || defined(__APPLE__)) && NBBY == 8
14655682Smarkm/*
14755682Smarkm * this ifdef is to keep someone form "porting" this to an incompatible
14855682Smarkm * system and not checking this out. This way they have to think about it.
14955682Smarkm */
15055682Smarkm		overbose = verbose;
15155682Smarkm		if (debug == 0)
15255682Smarkm			verbose = -1;
153178825Sdfr		if (command("SYST") == COMPLETE && overbose && strlen(reply_string) > 4) {
154178825Sdfr			char *cp, *p;
155178825Sdfr
156178825Sdfr			cp = strdup(reply_string + 4);
15755682Smarkm			if (cp == NULL)
158178825Sdfr			    errx(1, "strdup: out of memory");
159178825Sdfr			p = strchr(cp, ' ');
160178825Sdfr			if (p == NULL)
161178825Sdfr				p = strchr(cp, '\r');
162178825Sdfr			if (p) {
163178825Sdfr				if (p[-1] == '.')
164178825Sdfr					p--;
165178825Sdfr				*p = '\0';
16655682Smarkm			}
16755682Smarkm
168178825Sdfr			printf("Remote system type is %s.\n", cp);
169178825Sdfr			free(cp);
17055682Smarkm		}
17155682Smarkm		if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
17255682Smarkm			if (proxy)
17355682Smarkm				unix_proxy = 1;
17455682Smarkm			else
17555682Smarkm				unix_server = 1;
17655682Smarkm			/*
17755682Smarkm			 * Set type to 0 (not specified by user),
17855682Smarkm			 * meaning binary by default, but don't bother
17955682Smarkm			 * telling server.  We can use binary
18055682Smarkm			 * for text files unless changed by the user.
18155682Smarkm			 */
18255682Smarkm			type = 0;
18355682Smarkm			strlcpy(typename, "binary", sizeof(typename));
18455682Smarkm			if (overbose)
18555682Smarkm			    printf("Using %s mode to transfer files.\n",
18655682Smarkm				typename);
18755682Smarkm		} else {
18855682Smarkm			if (proxy)
18955682Smarkm				unix_proxy = 0;
19055682Smarkm			else
19155682Smarkm				unix_server = 0;
192233294Sstas			if (overbose &&
19355682Smarkm			    !strncmp(reply_string, "215 TOPS20", 10))
19455682Smarkm				printf(
19555682Smarkm"Remember to set tenex mode when transfering binary files from this machine.\n");
19655682Smarkm		}
19755682Smarkm		verbose = overbose;
19855682Smarkm#endif /* unix */
19955682Smarkm	}
20055682Smarkm}
20155682Smarkm
20255682Smarkmstruct	types {
20355682Smarkm	char	*t_name;
20455682Smarkm	char	*t_mode;
20555682Smarkm	int	t_type;
20655682Smarkm	char	*t_arg;
20755682Smarkm} types[] = {
20855682Smarkm	{ "ascii",	"A",	TYPE_A,	0 },
20955682Smarkm	{ "binary",	"I",	TYPE_I,	0 },
21055682Smarkm	{ "image",	"I",	TYPE_I,	0 },
21155682Smarkm	{ "ebcdic",	"E",	TYPE_E,	0 },
21255682Smarkm	{ "tenex",	"L",	TYPE_L,	bytename },
21355682Smarkm	{ NULL }
21455682Smarkm};
21555682Smarkm
21655682Smarkm/*
21755682Smarkm * Set transfer type.
21855682Smarkm */
21955682Smarkmvoid
22055682Smarkmsettype(int argc, char **argv)
22155682Smarkm{
22255682Smarkm	struct types *p;
22355682Smarkm	int comret;
22455682Smarkm
22555682Smarkm	if (argc > 2) {
22655682Smarkm		char *sep;
22755682Smarkm
22855682Smarkm		printf("usage: %s [", argv[0]);
22955682Smarkm		sep = " ";
23055682Smarkm		for (p = types; p->t_name; p++) {
23155682Smarkm			printf("%s%s", sep, p->t_name);
23255682Smarkm			sep = " | ";
23355682Smarkm		}
23455682Smarkm		printf(" ]\n");
23555682Smarkm		code = -1;
23655682Smarkm		return;
23755682Smarkm	}
23855682Smarkm	if (argc < 2) {
23955682Smarkm		printf("Using %s mode to transfer files.\n", typename);
24055682Smarkm		code = 0;
24155682Smarkm		return;
24255682Smarkm	}
24355682Smarkm	for (p = types; p->t_name; p++)
24455682Smarkm		if (strcmp(argv[1], p->t_name) == 0)
24555682Smarkm			break;
24655682Smarkm	if (p->t_name == 0) {
24755682Smarkm		printf("%s: unknown mode\n", argv[1]);
24855682Smarkm		code = -1;
24955682Smarkm		return;
25055682Smarkm	}
25155682Smarkm	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
25255682Smarkm		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
25355682Smarkm	else
25455682Smarkm		comret = command("TYPE %s", p->t_mode);
25555682Smarkm	if (comret == COMPLETE) {
25655682Smarkm		strlcpy(typename, p->t_name, sizeof(typename));
25755682Smarkm		curtype = type = p->t_type;
25855682Smarkm	}
25955682Smarkm}
26055682Smarkm
26155682Smarkm/*
26255682Smarkm * Internal form of settype; changes current type in use with server
26355682Smarkm * without changing our notion of the type for data transfers.
26455682Smarkm * Used to change to and from ascii for listings.
26555682Smarkm */
26655682Smarkmvoid
26755682Smarkmchangetype(int newtype, int show)
26855682Smarkm{
26955682Smarkm	struct types *p;
27055682Smarkm	int comret, oldverbose = verbose;
27155682Smarkm
27255682Smarkm	if (newtype == 0)
27355682Smarkm		newtype = TYPE_I;
27455682Smarkm	if (newtype == curtype)
27555682Smarkm		return;
27655682Smarkm	if (debug == 0 && show == 0)
27755682Smarkm		verbose = 0;
27855682Smarkm	for (p = types; p->t_name; p++)
27955682Smarkm		if (newtype == p->t_type)
28055682Smarkm			break;
28155682Smarkm	if (p->t_name == 0) {
28255682Smarkm		printf("ftp: internal error: unknown type %d\n", newtype);
28355682Smarkm		return;
28455682Smarkm	}
28555682Smarkm	if (newtype == TYPE_L && bytename[0] != '\0')
28655682Smarkm		comret = command("TYPE %s %s", p->t_mode, bytename);
28755682Smarkm	else
28855682Smarkm		comret = command("TYPE %s", p->t_mode);
28955682Smarkm	if (comret == COMPLETE)
29055682Smarkm		curtype = newtype;
29155682Smarkm	verbose = oldverbose;
29255682Smarkm}
29355682Smarkm
29455682Smarkmchar *stype[] = {
29555682Smarkm	"type",
29655682Smarkm	"",
29755682Smarkm	0
29855682Smarkm};
29955682Smarkm
30055682Smarkm/*
30155682Smarkm * Set binary transfer type.
30255682Smarkm */
30355682Smarkm/*VARARGS*/
30455682Smarkmvoid
30555682Smarkmsetbinary(int argc, char **argv)
30655682Smarkm{
30755682Smarkm
30855682Smarkm	stype[1] = "binary";
30955682Smarkm	settype(2, stype);
31055682Smarkm}
31155682Smarkm
31255682Smarkm/*
31355682Smarkm * Set ascii transfer type.
31455682Smarkm */
31555682Smarkm/*VARARGS*/
31655682Smarkmvoid
31755682Smarkmsetascii(int argc, char **argv)
31855682Smarkm{
31955682Smarkm
32055682Smarkm	stype[1] = "ascii";
32155682Smarkm	settype(2, stype);
32255682Smarkm}
32355682Smarkm
32455682Smarkm/*
32555682Smarkm * Set tenex transfer type.
32655682Smarkm */
32755682Smarkm/*VARARGS*/
32855682Smarkmvoid
32955682Smarkmsettenex(int argc, char **argv)
33055682Smarkm{
33155682Smarkm
33255682Smarkm	stype[1] = "tenex";
33355682Smarkm	settype(2, stype);
33455682Smarkm}
33555682Smarkm
33655682Smarkm/*
33755682Smarkm * Set file transfer mode.
33855682Smarkm */
33955682Smarkm/*ARGSUSED*/
34055682Smarkmvoid
34155682Smarkmsetftmode(int argc, char **argv)
34255682Smarkm{
34355682Smarkm
34455682Smarkm	printf("We only support %s mode, sorry.\n", modename);
34555682Smarkm	code = -1;
34655682Smarkm}
34755682Smarkm
34855682Smarkm/*
34955682Smarkm * Set file transfer format.
35055682Smarkm */
35155682Smarkm/*ARGSUSED*/
35255682Smarkmvoid
35355682Smarkmsetform(int argc, char **argv)
35455682Smarkm{
35555682Smarkm
35655682Smarkm	printf("We only support %s format, sorry.\n", formname);
35755682Smarkm	code = -1;
35855682Smarkm}
35955682Smarkm
36055682Smarkm/*
36155682Smarkm * Set file transfer structure.
36255682Smarkm */
36355682Smarkm/*ARGSUSED*/
36455682Smarkmvoid
36555682Smarkmsetstruct(int argc, char **argv)
36655682Smarkm{
36755682Smarkm
36855682Smarkm	printf("We only support %s structure, sorry.\n", structname);
36955682Smarkm	code = -1;
37055682Smarkm}
37155682Smarkm
37255682Smarkm/*
37355682Smarkm * Send a single file.
37455682Smarkm */
37555682Smarkmvoid
37655682Smarkmput(int argc, char **argv)
37755682Smarkm{
37855682Smarkm	char *cmd;
37955682Smarkm	int loc = 0;
38055682Smarkm	char *oldargv1, *oldargv2;
38155682Smarkm
38255682Smarkm	if (argc == 2) {
38355682Smarkm		argc++;
38455682Smarkm		argv[2] = argv[1];
38555682Smarkm		loc++;
38655682Smarkm	}
38755682Smarkm	if (argc < 2 && !another(&argc, &argv, "local-file"))
38855682Smarkm		goto usage;
38955682Smarkm	if (argc < 3 && !another(&argc, &argv, "remote-file")) {
39055682Smarkmusage:
39155682Smarkm		printf("usage: %s local-file remote-file\n", argv[0]);
39255682Smarkm		code = -1;
39355682Smarkm		return;
39455682Smarkm	}
39555682Smarkm	oldargv1 = argv[1];
39655682Smarkm	oldargv2 = argv[2];
39755682Smarkm	if (!globulize(&argv[1])) {
39855682Smarkm		code = -1;
39955682Smarkm		return;
40055682Smarkm	}
40155682Smarkm	/*
40255682Smarkm	 * If "globulize" modifies argv[1], and argv[2] is a copy of
40355682Smarkm	 * the old argv[1], make it a copy of the new argv[1].
40455682Smarkm	 */
40555682Smarkm	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
40655682Smarkm		argv[2] = argv[1];
40755682Smarkm	}
40855682Smarkm	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
40955682Smarkm	if (loc && ntflag) {
41055682Smarkm		argv[2] = dotrans(argv[2]);
41155682Smarkm	}
41255682Smarkm	if (loc && mapflag) {
41355682Smarkm		argv[2] = domap(argv[2]);
41455682Smarkm	}
41555682Smarkm	sendrequest(cmd, argv[1], argv[2],
41655682Smarkm		    curtype == TYPE_I ? "rb" : "r",
41755682Smarkm		    argv[1] != oldargv1 || argv[2] != oldargv2);
41855682Smarkm}
41955682Smarkm
42055682Smarkm/* ARGSUSED */
42155682Smarkmstatic RETSIGTYPE
42255682Smarkmmabort(int signo)
42355682Smarkm{
42455682Smarkm	int ointer;
42555682Smarkm
42655682Smarkm	printf("\n");
42755682Smarkm	fflush(stdout);
42855682Smarkm	if (mflag && fromatty) {
42955682Smarkm		ointer = interactive;
43055682Smarkm		interactive = 1;
43155682Smarkm		if (confirm("Continue with", mname)) {
43255682Smarkm			interactive = ointer;
43355682Smarkm			longjmp(jabort,0);
43455682Smarkm		}
43555682Smarkm		interactive = ointer;
43655682Smarkm	}
43755682Smarkm	mflag = 0;
43855682Smarkm	longjmp(jabort,0);
43955682Smarkm}
44055682Smarkm
44155682Smarkm/*
44255682Smarkm * Send multiple files.
44355682Smarkm */
44455682Smarkmvoid
44555682Smarkmmput(int argc, char **argv)
44655682Smarkm{
44755682Smarkm    int i;
44872445Sassar    RETSIGTYPE (*oldintr)(int);
44955682Smarkm    int ointer;
45055682Smarkm    char *tp;
45155682Smarkm
45255682Smarkm    if (argc < 2 && !another(&argc, &argv, "local-files")) {
45355682Smarkm	printf("usage: %s local-files\n", argv[0]);
45455682Smarkm	code = -1;
45555682Smarkm	return;
45655682Smarkm    }
45755682Smarkm    mname = argv[0];
45855682Smarkm    mflag = 1;
45955682Smarkm    oldintr = signal(SIGINT, mabort);
46055682Smarkm    setjmp(jabort);
46155682Smarkm    if (proxy) {
46255682Smarkm	char *cp, *tp2, tmpbuf[MaxPathLen];
46355682Smarkm
46455682Smarkm	while ((cp = remglob(argv,0)) != NULL) {
46555682Smarkm	    if (*cp == 0) {
46655682Smarkm		mflag = 0;
46755682Smarkm		continue;
46855682Smarkm	    }
46955682Smarkm	    if (mflag && confirm(argv[0], cp)) {
47055682Smarkm		tp = cp;
47155682Smarkm		if (mcase) {
47290926Snectar		    while (*tp && !islower((unsigned char)*tp)) {
47355682Smarkm			tp++;
47455682Smarkm		    }
47555682Smarkm		    if (!*tp) {
47655682Smarkm			tp = cp;
47755682Smarkm			tp2 = tmpbuf;
47855682Smarkm			while ((*tp2 = *tp) != '\0') {
47990926Snectar			    if (isupper((unsigned char)*tp2)) {
48055682Smarkm				*tp2 = 'a' + *tp2 - 'A';
48155682Smarkm			    }
48255682Smarkm			    tp++;
48355682Smarkm			    tp2++;
48455682Smarkm			}
48555682Smarkm		    }
48655682Smarkm		    tp = tmpbuf;
48755682Smarkm		}
48855682Smarkm		if (ntflag) {
48955682Smarkm		    tp = dotrans(tp);
49055682Smarkm		}
49155682Smarkm		if (mapflag) {
49255682Smarkm		    tp = domap(tp);
49355682Smarkm		}
49455682Smarkm		sendrequest((sunique) ? "STOU" : "STOR",
49555682Smarkm			    cp, tp,
49655682Smarkm			    curtype == TYPE_I ? "rb" : "r",
49755682Smarkm			    cp != tp || !interactive);
49855682Smarkm		if (!mflag && fromatty) {
49955682Smarkm		    ointer = interactive;
50055682Smarkm		    interactive = 1;
50155682Smarkm		    if (confirm("Continue with","mput")) {
50255682Smarkm			mflag++;
50355682Smarkm		    }
50455682Smarkm		    interactive = ointer;
50555682Smarkm		}
50655682Smarkm	    }
50755682Smarkm	}
50855682Smarkm	signal(SIGINT, oldintr);
50955682Smarkm	mflag = 0;
51055682Smarkm	return;
51155682Smarkm    }
51255682Smarkm    for (i = 1; i < argc; i++) {
51355682Smarkm	char **cpp;
51455682Smarkm	glob_t gl;
51555682Smarkm	int flags;
51655682Smarkm
51755682Smarkm	if (!doglob) {
51855682Smarkm	    if (mflag && confirm(argv[0], argv[i])) {
51955682Smarkm		tp = (ntflag) ? dotrans(argv[i]) : argv[i];
52055682Smarkm		tp = (mapflag) ? domap(tp) : tp;
52155682Smarkm		sendrequest((sunique) ? "STOU" : "STOR",
52255682Smarkm			    argv[i],
52355682Smarkm			    curtype == TYPE_I ? "rb" : "r",
52455682Smarkm			    tp, tp != argv[i] || !interactive);
52555682Smarkm		if (!mflag && fromatty) {
52655682Smarkm		    ointer = interactive;
52755682Smarkm		    interactive = 1;
52855682Smarkm		    if (confirm("Continue with","mput")) {
52955682Smarkm			mflag++;
53055682Smarkm		    }
53155682Smarkm		    interactive = ointer;
53255682Smarkm		}
53355682Smarkm	    }
53455682Smarkm	    continue;
53555682Smarkm	}
53655682Smarkm
53755682Smarkm	memset(&gl, 0, sizeof(gl));
53855682Smarkm	flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
53955682Smarkm	if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
54055682Smarkm	    warnx("%s: not found", argv[i]);
54155682Smarkm	    globfree(&gl);
54255682Smarkm	    continue;
54355682Smarkm	}
54455682Smarkm	for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
54555682Smarkm	    if (mflag && confirm(argv[0], *cpp)) {
54655682Smarkm		tp = (ntflag) ? dotrans(*cpp) : *cpp;
54755682Smarkm		tp = (mapflag) ? domap(tp) : tp;
54855682Smarkm		sendrequest((sunique) ? "STOU" : "STOR",
54955682Smarkm			    *cpp, tp,
55055682Smarkm			    curtype == TYPE_I ? "rb" : "r",
55155682Smarkm			    *cpp != tp || !interactive);
55255682Smarkm		if (!mflag && fromatty) {
55355682Smarkm		    ointer = interactive;
55455682Smarkm		    interactive = 1;
55555682Smarkm		    if (confirm("Continue with","mput")) {
55655682Smarkm			mflag++;
55755682Smarkm		    }
55855682Smarkm		    interactive = ointer;
55955682Smarkm		}
56055682Smarkm	    }
56155682Smarkm	}
56255682Smarkm	globfree(&gl);
56355682Smarkm    }
56455682Smarkm    signal(SIGINT, oldintr);
56555682Smarkm    mflag = 0;
56655682Smarkm}
56755682Smarkm
56855682Smarkmvoid
56955682Smarkmreget(int argc, char **argv)
57055682Smarkm{
57155682Smarkm    getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w");
57255682Smarkm}
57355682Smarkm
57455682Smarkmvoid
57555682Smarkmget(int argc, char **argv)
57655682Smarkm{
577178825Sdfr    char *filemode;
57855682Smarkm
57972445Sassar    if (restart_point) {
58055682Smarkm	if (curtype == TYPE_I)
581178825Sdfr	    filemode = "r+wb";
58255682Smarkm	else
583178825Sdfr	    filemode = "r+w";
58472445Sassar    } else {
58555682Smarkm	if (curtype == TYPE_I)
586178825Sdfr	    filemode = "wb";
58755682Smarkm	else
588178825Sdfr	    filemode = "w";
58972445Sassar    }
59055682Smarkm
591178825Sdfr    getit(argc, argv, 0, filemode);
59255682Smarkm}
59355682Smarkm
59455682Smarkm/*
59555682Smarkm * Receive one file.
59655682Smarkm */
59755682Smarkmint
598178825Sdfrgetit(int argc, char **argv, int restartit, char *filemode)
59955682Smarkm{
60055682Smarkm	int loc = 0;
60155682Smarkm	int local_given = 1;
60255682Smarkm	char *oldargv1, *oldargv2;
60355682Smarkm
60455682Smarkm	if (argc == 2) {
60555682Smarkm		argc++;
60655682Smarkm		local_given = 0;
60755682Smarkm		argv[2] = argv[1];
60855682Smarkm		loc++;
60955682Smarkm	}
61055682Smarkm	if ((argc < 2 && !another(&argc, &argv, "remote-file")) ||
61155682Smarkm	    (argc < 3 && !another(&argc, &argv, "local-file"))) {
61255682Smarkm		printf("usage: %s remote-file [ local-file ]\n", argv[0]);
61355682Smarkm		code = -1;
61455682Smarkm		return (0);
61555682Smarkm	}
61655682Smarkm	oldargv1 = argv[1];
61755682Smarkm	oldargv2 = argv[2];
61855682Smarkm	if (!globulize(&argv[2])) {
61955682Smarkm		code = -1;
62055682Smarkm		return (0);
62155682Smarkm	}
62255682Smarkm	if (loc && mcase) {
62355682Smarkm		char *tp = argv[1], *tp2, tmpbuf[MaxPathLen];
62455682Smarkm
62590926Snectar		while (*tp && !islower((unsigned char)*tp)) {
62655682Smarkm			tp++;
62755682Smarkm		}
62855682Smarkm		if (!*tp) {
62955682Smarkm			tp = argv[2];
63055682Smarkm			tp2 = tmpbuf;
63155682Smarkm			while ((*tp2 = *tp) != '\0') {
63290926Snectar				if (isupper((unsigned char)*tp2)) {
63355682Smarkm					*tp2 = 'a' + *tp2 - 'A';
63455682Smarkm				}
63555682Smarkm				tp++;
63655682Smarkm				tp2++;
63755682Smarkm			}
63855682Smarkm			argv[2] = tmpbuf;
63955682Smarkm		}
64055682Smarkm	}
64155682Smarkm	if (loc && ntflag)
64255682Smarkm		argv[2] = dotrans(argv[2]);
64355682Smarkm	if (loc && mapflag)
64455682Smarkm		argv[2] = domap(argv[2]);
64555682Smarkm	if (restartit) {
64655682Smarkm		struct stat stbuf;
64755682Smarkm		int ret;
64855682Smarkm
64955682Smarkm		ret = stat(argv[2], &stbuf);
65055682Smarkm		if (restartit == 1) {
65155682Smarkm			if (ret < 0) {
65255682Smarkm				warn("local: %s", argv[2]);
65355682Smarkm				return (0);
65455682Smarkm			}
65555682Smarkm			restart_point = stbuf.st_size;
65655682Smarkm		} else if (ret == 0) {
65755682Smarkm			int overbose;
65855682Smarkm			int cmdret;
65955682Smarkm			int yy, mo, day, hour, min, sec;
66055682Smarkm			struct tm *tm;
66172445Sassar			time_t mtime = stbuf.st_mtime;
66255682Smarkm
66355682Smarkm			overbose = verbose;
66455682Smarkm			if (debug == 0)
66555682Smarkm				verbose = -1;
66655682Smarkm			cmdret = command("MDTM %s", argv[1]);
66755682Smarkm			verbose = overbose;
66855682Smarkm			if (cmdret != COMPLETE) {
66955682Smarkm				printf("%s\n", reply_string);
67055682Smarkm				return (0);
67155682Smarkm			}
67255682Smarkm			if (sscanf(reply_string,
67355682Smarkm				   "%*s %04d%02d%02d%02d%02d%02d",
67455682Smarkm				   &yy, &mo, &day, &hour, &min, &sec)
67555682Smarkm			    != 6) {
67655682Smarkm				printf ("bad MDTM result\n");
67755682Smarkm				return (0);
67855682Smarkm			}
67955682Smarkm
68072445Sassar			tm = gmtime(&mtime);
68155682Smarkm			tm->tm_mon++;
68255682Smarkm			tm->tm_year += 1900;
68355682Smarkm
68455682Smarkm			if ((tm->tm_year > yy) ||
685233294Sstas			    (tm->tm_year == yy &&
68655682Smarkm			     tm->tm_mon > mo) ||
687233294Sstas			    (tm->tm_mon == mo &&
68855682Smarkm			     tm->tm_mday > day) ||
689233294Sstas			    (tm->tm_mday == day &&
69055682Smarkm			     tm->tm_hour > hour) ||
691233294Sstas			    (tm->tm_hour == hour &&
69255682Smarkm			     tm->tm_min > min) ||
693233294Sstas			    (tm->tm_min == min &&
69455682Smarkm			     tm->tm_sec > sec))
69555682Smarkm				return (1);
69655682Smarkm		}
69755682Smarkm	}
69855682Smarkm
699178825Sdfr	recvrequest("RETR", argv[2], argv[1], filemode,
70055682Smarkm		    argv[1] != oldargv1 || argv[2] != oldargv2, local_given);
70155682Smarkm	restart_point = 0;
70255682Smarkm	return (0);
70355682Smarkm}
70455682Smarkm
70555682Smarkmstatic int
70655682Smarkmsuspicious_filename(const char *fn)
70755682Smarkm{
70855682Smarkm    return strstr(fn, "../") != NULL || *fn == '/';
70955682Smarkm}
71055682Smarkm
71155682Smarkm/*
71255682Smarkm * Get multiple files.
71355682Smarkm */
71455682Smarkmvoid
71555682Smarkmmget(int argc, char **argv)
71655682Smarkm{
71755682Smarkm	sighand oldintr;
71855682Smarkm	int ch, ointer;
71955682Smarkm	char *cp, *tp, *tp2, tmpbuf[MaxPathLen];
72055682Smarkm
72155682Smarkm	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
72255682Smarkm		printf("usage: %s remote-files\n", argv[0]);
72355682Smarkm		code = -1;
72455682Smarkm		return;
72555682Smarkm	}
72655682Smarkm	mname = argv[0];
72755682Smarkm	mflag = 1;
72855682Smarkm	oldintr = signal(SIGINT, mabort);
72955682Smarkm	setjmp(jabort);
73055682Smarkm	while ((cp = remglob(argv,proxy)) != NULL) {
73155682Smarkm		if (*cp == '\0') {
73255682Smarkm			mflag = 0;
73355682Smarkm			continue;
73455682Smarkm		}
73555682Smarkm		if (mflag && suspicious_filename(cp))
73655682Smarkm		    printf("*** Suspicious filename: %s\n", cp);
73755682Smarkm		if (mflag && confirm(argv[0], cp)) {
73855682Smarkm			tp = cp;
73955682Smarkm			if (mcase) {
740178825Sdfr				for (tp2 = tmpbuf;(ch = (unsigned char)*tp++);)
74190926Snectar					*tp2++ = tolower(ch);
74255682Smarkm				*tp2 = '\0';
74355682Smarkm				tp = tmpbuf;
74455682Smarkm			}
74555682Smarkm			if (ntflag) {
74655682Smarkm				tp = dotrans(tp);
74755682Smarkm			}
74855682Smarkm			if (mapflag) {
74955682Smarkm				tp = domap(tp);
75055682Smarkm			}
75155682Smarkm			recvrequest("RETR", tp, cp,
75255682Smarkm				    curtype == TYPE_I ? "wb" : "w",
75355682Smarkm				    tp != cp || !interactive, 0);
75455682Smarkm			if (!mflag && fromatty) {
75555682Smarkm				ointer = interactive;
75655682Smarkm				interactive = 1;
75755682Smarkm				if (confirm("Continue with","mget")) {
75855682Smarkm					mflag++;
75955682Smarkm				}
76055682Smarkm				interactive = ointer;
76155682Smarkm			}
76255682Smarkm		}
76355682Smarkm	}
76455682Smarkm	signal(SIGINT,oldintr);
76555682Smarkm	mflag = 0;
76655682Smarkm}
76755682Smarkm
76855682Smarkmchar *
76955682Smarkmremglob(char **argv, int doswitch)
77055682Smarkm{
77155682Smarkm    char temp[16];
77255682Smarkm    static char buf[MaxPathLen];
77355682Smarkm    static FILE *ftemp = NULL;
77455682Smarkm    static char **args;
77555682Smarkm    int oldverbose, oldhash;
776178825Sdfr    char *cp, *filemode;
77755682Smarkm
77855682Smarkm    if (!mflag) {
77955682Smarkm	if (!doglob) {
78055682Smarkm	    args = NULL;
78155682Smarkm	}
78255682Smarkm	else {
78355682Smarkm	    if (ftemp) {
78455682Smarkm		fclose(ftemp);
78555682Smarkm		ftemp = NULL;
78655682Smarkm	    }
78755682Smarkm	}
78855682Smarkm	return (NULL);
78955682Smarkm    }
79055682Smarkm    if (!doglob) {
79155682Smarkm	if (args == NULL)
79255682Smarkm	    args = argv;
79355682Smarkm	if ((cp = *++args) == NULL)
79455682Smarkm	    args = NULL;
79555682Smarkm	return (cp);
79655682Smarkm    }
79755682Smarkm    if (ftemp == NULL) {
79855682Smarkm	int fd;
79955682Smarkm	strlcpy(temp, _PATH_TMP_XXX, sizeof(temp));
80055682Smarkm	fd = mkstemp(temp);
80155682Smarkm	if(fd < 0){
80255682Smarkm	    warn("unable to create temporary file %s", temp);
80355682Smarkm	    return NULL;
80455682Smarkm	}
80555682Smarkm	close(fd);
80655682Smarkm	oldverbose = verbose, verbose = 0;
80755682Smarkm	oldhash = hash, hash = 0;
80855682Smarkm	if (doswitch) {
80955682Smarkm	    pswitch(!proxy);
81055682Smarkm	}
811178825Sdfr	for (filemode = "w"; *++argv != NULL; filemode = "a")
812178825Sdfr	    recvrequest ("NLST", temp, *argv, filemode, 0, 0);
81355682Smarkm	if (doswitch) {
81455682Smarkm	    pswitch(!proxy);
81555682Smarkm	}
81655682Smarkm	verbose = oldverbose; hash = oldhash;
81755682Smarkm	ftemp = fopen(temp, "r");
81855682Smarkm	unlink(temp);
81955682Smarkm	if (ftemp == NULL) {
82055682Smarkm	    printf("can't find list of remote files, oops\n");
82155682Smarkm	    return (NULL);
82255682Smarkm	}
82355682Smarkm    }
82455682Smarkm    while(fgets(buf, sizeof (buf), ftemp)) {
82555682Smarkm	if ((cp = strchr(buf, '\n')) != NULL)
82655682Smarkm	    *cp = '\0';
82755682Smarkm	if(!interactive && suspicious_filename(buf)){
82855682Smarkm	    printf("Ignoring remote globbed file `%s'\n", buf);
82955682Smarkm	    continue;
83055682Smarkm	}
83155682Smarkm	return buf;
83255682Smarkm    }
83355682Smarkm    fclose(ftemp);
83455682Smarkm    ftemp = NULL;
83555682Smarkm    return (NULL);
83655682Smarkm}
83755682Smarkm
83855682Smarkmchar *
83955682Smarkmonoff(int bool)
84055682Smarkm{
84155682Smarkm
84255682Smarkm	return (bool ? "on" : "off");
84355682Smarkm}
84455682Smarkm
84555682Smarkm/*
84655682Smarkm * Show status.
84755682Smarkm */
84855682Smarkm/*ARGSUSED*/
84955682Smarkmvoid
85055682Smarkmstatus(int argc, char **argv)
85155682Smarkm{
85255682Smarkm	int i;
85355682Smarkm
85455682Smarkm	if (connected)
85555682Smarkm		printf("Connected to %s.\n", hostname);
85655682Smarkm	else
85755682Smarkm		printf("Not connected.\n");
85855682Smarkm	if (!proxy) {
85955682Smarkm		pswitch(1);
86055682Smarkm		if (connected) {
86155682Smarkm			printf("Connected for proxy commands to %s.\n", hostname);
86255682Smarkm		}
86355682Smarkm		else {
86455682Smarkm			printf("No proxy connection.\n");
86555682Smarkm		}
86655682Smarkm		pswitch(0);
86755682Smarkm	}
86855682Smarkm	sec_status();
86955682Smarkm	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
87055682Smarkm		modename, typename, formname, structname);
871233294Sstas	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
87255682Smarkm		onoff(verbose), onoff(bell), onoff(interactive),
87355682Smarkm		onoff(doglob));
87455682Smarkm	printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
87555682Smarkm		onoff(runique));
87655682Smarkm	printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
87755682Smarkm	if (ntflag) {
87855682Smarkm		printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
87955682Smarkm	}
88055682Smarkm	else {
88155682Smarkm		printf("Ntrans: off\n");
88255682Smarkm	}
88355682Smarkm	if (mapflag) {
88455682Smarkm		printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
88555682Smarkm	}
88655682Smarkm	else {
88755682Smarkm		printf("Nmap: off\n");
88855682Smarkm	}
88955682Smarkm	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
89055682Smarkm		onoff(hash), onoff(sendport));
89155682Smarkm	if (macnum > 0) {
89255682Smarkm		printf("Macros:\n");
89355682Smarkm		for (i=0; i<macnum; i++) {
89455682Smarkm			printf("\t%s\n",macros[i].mac_name);
89555682Smarkm		}
89655682Smarkm	}
89755682Smarkm	code = 0;
89855682Smarkm}
89955682Smarkm
90055682Smarkm/*
90155682Smarkm * Set beep on cmd completed mode.
90255682Smarkm */
90355682Smarkm/*VARARGS*/
90455682Smarkmvoid
90555682Smarkmsetbell(int argc, char **argv)
90655682Smarkm{
90755682Smarkm
90855682Smarkm	bell = !bell;
90955682Smarkm	printf("Bell mode %s.\n", onoff(bell));
91055682Smarkm	code = bell;
91155682Smarkm}
91255682Smarkm
91355682Smarkm/*
91455682Smarkm * Turn on packet tracing.
91555682Smarkm */
91655682Smarkm/*VARARGS*/
91755682Smarkmvoid
91855682Smarkmsettrace(int argc, char **argv)
91955682Smarkm{
92055682Smarkm
92155682Smarkm	trace = !trace;
92255682Smarkm	printf("Packet tracing %s.\n", onoff(trace));
92355682Smarkm	code = trace;
92455682Smarkm}
92555682Smarkm
92655682Smarkm/*
92755682Smarkm * Toggle hash mark printing during transfers.
92855682Smarkm */
92955682Smarkm/*VARARGS*/
93055682Smarkmvoid
93155682Smarkmsethash(int argc, char **argv)
93255682Smarkm{
93355682Smarkm
93455682Smarkm	hash = !hash;
93555682Smarkm	printf("Hash mark printing %s", onoff(hash));
93655682Smarkm	code = hash;
93755682Smarkm	if (hash)
93855682Smarkm		printf(" (%d bytes/hash mark)", 1024);
93955682Smarkm	printf(".\n");
94055682Smarkm}
94155682Smarkm
94255682Smarkm/*
94355682Smarkm * Turn on printing of server echo's.
94455682Smarkm */
94555682Smarkm/*VARARGS*/
94655682Smarkmvoid
94755682Smarkmsetverbose(int argc, char **argv)
94855682Smarkm{
94955682Smarkm
95055682Smarkm	verbose = !verbose;
95155682Smarkm	printf("Verbose mode %s.\n", onoff(verbose));
95255682Smarkm	code = verbose;
95355682Smarkm}
95455682Smarkm
95555682Smarkm/*
95655682Smarkm * Toggle PORT cmd use before each data connection.
95755682Smarkm */
95855682Smarkm/*VARARGS*/
95955682Smarkmvoid
96055682Smarkmsetport(int argc, char **argv)
96155682Smarkm{
96255682Smarkm
96355682Smarkm	sendport = !sendport;
96455682Smarkm	printf("Use of PORT cmds %s.\n", onoff(sendport));
96555682Smarkm	code = sendport;
96655682Smarkm}
96755682Smarkm
96855682Smarkm/*
96955682Smarkm * Turn on interactive prompting
97055682Smarkm * during mget, mput, and mdelete.
97155682Smarkm */
97255682Smarkm/*VARARGS*/
97355682Smarkmvoid
97455682Smarkmsetprompt(int argc, char **argv)
97555682Smarkm{
97655682Smarkm
97755682Smarkm	interactive = !interactive;
97855682Smarkm	printf("Interactive mode %s.\n", onoff(interactive));
97955682Smarkm	code = interactive;
98055682Smarkm}
98155682Smarkm
98255682Smarkm/*
98355682Smarkm * Toggle metacharacter interpretation
98455682Smarkm * on local file names.
98555682Smarkm */
98655682Smarkm/*VARARGS*/
98755682Smarkmvoid
98855682Smarkmsetglob(int argc, char **argv)
98955682Smarkm{
990233294Sstas
99155682Smarkm	doglob = !doglob;
99255682Smarkm	printf("Globbing %s.\n", onoff(doglob));
99355682Smarkm	code = doglob;
99455682Smarkm}
99555682Smarkm
99655682Smarkm/*
99755682Smarkm * Set debugging mode on/off and/or
99855682Smarkm * set level of debugging.
99955682Smarkm */
100055682Smarkm/*VARARGS*/
100155682Smarkmvoid
100255682Smarkmsetdebug(int argc, char **argv)
100355682Smarkm{
100455682Smarkm	int val;
100555682Smarkm
100655682Smarkm	if (argc > 1) {
100755682Smarkm		val = atoi(argv[1]);
100855682Smarkm		if (val < 0) {
100955682Smarkm			printf("%s: bad debugging value.\n", argv[1]);
101055682Smarkm			code = -1;
101155682Smarkm			return;
101255682Smarkm		}
101355682Smarkm	} else
101455682Smarkm		val = !debug;
101555682Smarkm	debug = val;
101655682Smarkm	if (debug)
101755682Smarkm		options |= SO_DEBUG;
101855682Smarkm	else
101955682Smarkm		options &= ~SO_DEBUG;
102055682Smarkm	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
102155682Smarkm	code = debug > 0;
102255682Smarkm}
102355682Smarkm
102455682Smarkm/*
102555682Smarkm * Set current working directory
102655682Smarkm * on remote machine.
102755682Smarkm */
102855682Smarkmvoid
102955682Smarkmcd(int argc, char **argv)
103055682Smarkm{
103155682Smarkm
103255682Smarkm	if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
103355682Smarkm		printf("usage: %s remote-directory\n", argv[0]);
103455682Smarkm		code = -1;
103555682Smarkm		return;
103655682Smarkm	}
103755682Smarkm	if (command("CWD %s", argv[1]) == ERROR && code == 500) {
103855682Smarkm		if (verbose)
103955682Smarkm			printf("CWD command not recognized, trying XCWD\n");
104055682Smarkm		command("XCWD %s", argv[1]);
104155682Smarkm	}
104255682Smarkm}
104355682Smarkm
104455682Smarkm/*
104555682Smarkm * Set current working directory
104655682Smarkm * on local machine.
104755682Smarkm */
104855682Smarkmvoid
104955682Smarkmlcd(int argc, char **argv)
105055682Smarkm{
105155682Smarkm	char buf[MaxPathLen];
105255682Smarkm
105355682Smarkm	if (argc < 2)
105455682Smarkm		argc++, argv[1] = home;
105555682Smarkm	if (argc != 2) {
105655682Smarkm		printf("usage: %s local-directory\n", argv[0]);
105755682Smarkm		code = -1;
105855682Smarkm		return;
105955682Smarkm	}
106055682Smarkm	if (!globulize(&argv[1])) {
106155682Smarkm		code = -1;
106255682Smarkm		return;
106355682Smarkm	}
106455682Smarkm	if (chdir(argv[1]) < 0) {
106555682Smarkm		warn("local: %s", argv[1]);
106655682Smarkm		code = -1;
106755682Smarkm		return;
106855682Smarkm	}
106955682Smarkm	if (getcwd(buf, sizeof(buf)) != NULL)
107055682Smarkm		printf("Local directory now %s\n", buf);
107155682Smarkm	else
107255682Smarkm		warnx("getwd: %s", buf);
107355682Smarkm	code = 0;
107455682Smarkm}
107555682Smarkm
107655682Smarkm/*
107755682Smarkm * Delete a single file.
107855682Smarkm */
107955682Smarkmvoid
108055682Smarkmdelete(int argc, char **argv)
108155682Smarkm{
108255682Smarkm
108355682Smarkm	if (argc < 2 && !another(&argc, &argv, "remote-file")) {
108455682Smarkm		printf("usage: %s remote-file\n", argv[0]);
108555682Smarkm		code = -1;
108655682Smarkm		return;
108755682Smarkm	}
108855682Smarkm	command("DELE %s", argv[1]);
108955682Smarkm}
109055682Smarkm
109155682Smarkm/*
109255682Smarkm * Delete multiple files.
109355682Smarkm */
109455682Smarkmvoid
109555682Smarkmmdelete(int argc, char **argv)
109655682Smarkm{
109755682Smarkm    sighand oldintr;
109855682Smarkm    int ointer;
109955682Smarkm    char *cp;
110055682Smarkm
110155682Smarkm    if (argc < 2 && !another(&argc, &argv, "remote-files")) {
110255682Smarkm	printf("usage: %s remote-files\n", argv[0]);
110355682Smarkm	code = -1;
110455682Smarkm	return;
110555682Smarkm    }
110655682Smarkm    mname = argv[0];
110755682Smarkm    mflag = 1;
110855682Smarkm    oldintr = signal(SIGINT, mabort);
110955682Smarkm    setjmp(jabort);
111055682Smarkm    while ((cp = remglob(argv,0)) != NULL) {
111155682Smarkm	if (*cp == '\0') {
111255682Smarkm	    mflag = 0;
111355682Smarkm	    continue;
111455682Smarkm	}
111555682Smarkm	if (mflag && confirm(argv[0], cp)) {
111655682Smarkm	    command("DELE %s", cp);
111755682Smarkm	    if (!mflag && fromatty) {
111855682Smarkm		ointer = interactive;
111955682Smarkm		interactive = 1;
112055682Smarkm		if (confirm("Continue with", "mdelete")) {
112155682Smarkm		    mflag++;
112255682Smarkm		}
112355682Smarkm		interactive = ointer;
112455682Smarkm	    }
112555682Smarkm	}
112655682Smarkm    }
112755682Smarkm    signal(SIGINT, oldintr);
112855682Smarkm    mflag = 0;
112955682Smarkm}
113055682Smarkm
113155682Smarkm/*
113255682Smarkm * Rename a remote file.
113355682Smarkm */
113455682Smarkmvoid
113555682Smarkmrenamefile(int argc, char **argv)
113655682Smarkm{
113755682Smarkm
113855682Smarkm	if (argc < 2 && !another(&argc, &argv, "from-name"))
113955682Smarkm		goto usage;
114055682Smarkm	if (argc < 3 && !another(&argc, &argv, "to-name")) {
114155682Smarkmusage:
114255682Smarkm		printf("%s from-name to-name\n", argv[0]);
114355682Smarkm		code = -1;
114455682Smarkm		return;
114555682Smarkm	}
114655682Smarkm	if (command("RNFR %s", argv[1]) == CONTINUE)
114755682Smarkm		command("RNTO %s", argv[2]);
114855682Smarkm}
114955682Smarkm
115055682Smarkm/*
115155682Smarkm * Get a directory listing
115255682Smarkm * of remote files.
115355682Smarkm */
115455682Smarkmvoid
115555682Smarkmls(int argc, char **argv)
115655682Smarkm{
115755682Smarkm	char *cmd;
115855682Smarkm
115955682Smarkm	if (argc < 2)
116055682Smarkm		argc++, argv[1] = NULL;
116155682Smarkm	if (argc < 3)
116255682Smarkm		argc++, argv[2] = "-";
116355682Smarkm	if (argc > 3) {
116455682Smarkm		printf("usage: %s remote-directory local-file\n", argv[0]);
116555682Smarkm		code = -1;
116655682Smarkm		return;
116755682Smarkm	}
116855682Smarkm	cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
116955682Smarkm	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
117055682Smarkm		code = -1;
117155682Smarkm		return;
117255682Smarkm	}
117355682Smarkm	if (strcmp(argv[2], "-") && *argv[2] != '|')
1174233294Sstas	    if (!globulize(&argv[2]) || !confirm("output to local-file:",
117555682Smarkm						 argv[2])) {
117655682Smarkm		code = -1;
117755682Smarkm		return;
117855682Smarkm	    }
117955682Smarkm	recvrequest(cmd, argv[2], argv[1], "w", 0, 1);
118055682Smarkm}
118155682Smarkm
118255682Smarkm/*
118355682Smarkm * Get a directory listing
118455682Smarkm * of multiple remote files.
118555682Smarkm */
118655682Smarkmvoid
118755682Smarkmmls(int argc, char **argv)
118855682Smarkm{
118955682Smarkm	sighand oldintr;
119055682Smarkm	int ointer, i;
1191178825Sdfr	char *cmd, filemode[2], *dest;
119255682Smarkm
119355682Smarkm	if (argc < 2 && !another(&argc, &argv, "remote-files"))
119455682Smarkm		goto usage;
119555682Smarkm	if (argc < 3 && !another(&argc, &argv, "local-file")) {
119655682Smarkmusage:
119755682Smarkm		printf("usage: %s remote-files local-file\n", argv[0]);
119855682Smarkm		code = -1;
119955682Smarkm		return;
120055682Smarkm	}
120155682Smarkm	dest = argv[argc - 1];
120255682Smarkm	argv[argc - 1] = NULL;
120355682Smarkm	if (strcmp(dest, "-") && *dest != '|')
120455682Smarkm		if (!globulize(&dest) ||
120555682Smarkm		    !confirm("output to local-file:", dest)) {
120655682Smarkm			code = -1;
120755682Smarkm			return;
120855682Smarkm	}
120955682Smarkm	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
121055682Smarkm	mname = argv[0];
121155682Smarkm	mflag = 1;
121255682Smarkm	oldintr = signal(SIGINT, mabort);
121355682Smarkm	setjmp(jabort);
1214178825Sdfr	filemode[1] = '\0';
121555682Smarkm	for (i = 1; mflag && i < argc-1; ++i) {
1216178825Sdfr		*filemode = (i == 1) ? 'w' : 'a';
1217178825Sdfr		recvrequest(cmd, dest, argv[i], filemode, 0, 1);
121855682Smarkm		if (!mflag && fromatty) {
121955682Smarkm			ointer = interactive;
122055682Smarkm			interactive = 1;
122155682Smarkm			if (confirm("Continue with", argv[0])) {
122255682Smarkm				mflag ++;
122355682Smarkm			}
122455682Smarkm			interactive = ointer;
122555682Smarkm		}
122655682Smarkm	}
122755682Smarkm	signal(SIGINT, oldintr);
122855682Smarkm	mflag = 0;
122955682Smarkm}
123055682Smarkm
123155682Smarkm/*
123255682Smarkm * Do a shell escape
123355682Smarkm */
123455682Smarkm/*ARGSUSED*/
123555682Smarkmvoid
123655682Smarkmshell(int argc, char **argv)
123755682Smarkm{
123855682Smarkm	pid_t pid;
123972445Sassar	RETSIGTYPE (*old1)(int), (*old2)(int);
1240233294Sstas	char shellnam[40], *shellpath, *namep;
1241178825Sdfr	int waitstatus;
124255682Smarkm
124355682Smarkm	old1 = signal (SIGINT, SIG_IGN);
124455682Smarkm	old2 = signal (SIGQUIT, SIG_IGN);
124555682Smarkm	if ((pid = fork()) == 0) {
124655682Smarkm		for (pid = 3; pid < 20; pid++)
124755682Smarkm			close(pid);
124855682Smarkm		signal(SIGINT, SIG_DFL);
124955682Smarkm		signal(SIGQUIT, SIG_DFL);
1250178825Sdfr		shellpath = getenv("SHELL");
1251178825Sdfr		if (shellpath == NULL)
1252178825Sdfr			shellpath = _PATH_BSHELL;
1253178825Sdfr		namep = strrchr(shellpath, '/');
125455682Smarkm		if (namep == NULL)
1255178825Sdfr			namep = shellpath;
125655682Smarkm		snprintf (shellnam, sizeof(shellnam),
125755682Smarkm			  "-%s", ++namep);
125855682Smarkm		if (strcmp(namep, "sh") != 0)
125955682Smarkm			shellnam[0] = '+';
126055682Smarkm		if (debug) {
1261178825Sdfr			printf ("%s\n", shellpath);
126255682Smarkm			fflush (stdout);
126355682Smarkm		}
126455682Smarkm		if (argc > 1) {
1265178825Sdfr			execl(shellpath,shellnam,"-c",altarg,(char *)0);
126655682Smarkm		}
126755682Smarkm		else {
1268178825Sdfr			execl(shellpath,shellnam,(char *)0);
126955682Smarkm		}
1270178825Sdfr		warn("%s", shellpath);
127155682Smarkm		code = -1;
127255682Smarkm		exit(1);
127355682Smarkm	}
127455682Smarkm	if (pid > 0)
1275178825Sdfr		while (waitpid(-1, &waitstatus, 0) != pid)
127655682Smarkm			;
127755682Smarkm	signal(SIGINT, old1);
127855682Smarkm	signal(SIGQUIT, old2);
127955682Smarkm	if (pid == -1) {
128055682Smarkm		warn("%s", "Try again later");
128155682Smarkm		code = -1;
128255682Smarkm	}
128355682Smarkm	else {
128455682Smarkm		code = 0;
128555682Smarkm	}
128655682Smarkm}
128755682Smarkm
128855682Smarkm/*
128955682Smarkm * Send new user information (re-login)
129055682Smarkm */
129155682Smarkmvoid
129255682Smarkmuser(int argc, char **argv)
129355682Smarkm{
1294178825Sdfr	char acctstr[80];
129555682Smarkm	int n, aflag = 0;
129655682Smarkm	char tmp[256];
129755682Smarkm
129855682Smarkm	if (argc < 2)
129955682Smarkm		another(&argc, &argv, "username");
130055682Smarkm	if (argc < 2 || argc > 4) {
130155682Smarkm		printf("usage: %s username [password] [account]\n", argv[0]);
130255682Smarkm		code = -1;
130355682Smarkm		return;
130455682Smarkm	}
130555682Smarkm	n = command("USER %s", argv[1]);
130655682Smarkm	if (n == CONTINUE) {
130755682Smarkm	    if (argc < 3 ) {
1308178825Sdfr		UI_UTIL_read_pw_string (tmp,
130955682Smarkm				    sizeof(tmp),
131055682Smarkm				    "Password: ", 0);
131155682Smarkm		argv[2] = tmp;
131255682Smarkm		argc++;
131355682Smarkm	    }
131455682Smarkm	    n = command("PASS %s", argv[2]);
131555682Smarkm	}
131655682Smarkm	if (n == CONTINUE) {
131755682Smarkm		if (argc < 4) {
131855682Smarkm			printf("Account: "); fflush(stdout);
1319178825Sdfr			fgets(acctstr, sizeof(acctstr) - 1, stdin);
1320178825Sdfr			acctstr[strcspn(acctstr, "\r\n")] = '\0';
1321178825Sdfr			argv[3] = acctstr; argc++;
132255682Smarkm		}
132355682Smarkm		n = command("ACCT %s", argv[3]);
132455682Smarkm		aflag++;
132555682Smarkm	}
132655682Smarkm	if (n != COMPLETE) {
132755682Smarkm		fprintf(stdout, "Login failed.\n");
132855682Smarkm		return;
132955682Smarkm	}
133055682Smarkm	if (!aflag && argc == 4) {
133155682Smarkm		command("ACCT %s", argv[3]);
133255682Smarkm	}
133355682Smarkm}
133455682Smarkm
133555682Smarkm/*
133655682Smarkm * Print working directory.
133755682Smarkm */
133855682Smarkm/*VARARGS*/
133955682Smarkmvoid
134055682Smarkmpwd(int argc, char **argv)
134155682Smarkm{
134255682Smarkm	int oldverbose = verbose;
134355682Smarkm
134455682Smarkm	/*
134555682Smarkm	 * If we aren't verbose, this doesn't do anything!
134655682Smarkm	 */
134755682Smarkm	verbose = 1;
134855682Smarkm	if (command("PWD") == ERROR && code == 500) {
134955682Smarkm		printf("PWD command not recognized, trying XPWD\n");
135055682Smarkm		command("XPWD");
135155682Smarkm	}
135255682Smarkm	verbose = oldverbose;
135355682Smarkm}
135455682Smarkm
135555682Smarkm/*
135655682Smarkm * Make a directory.
135755682Smarkm */
135855682Smarkmvoid
135955682Smarkmmakedir(int argc, char **argv)
136055682Smarkm{
136155682Smarkm
136255682Smarkm	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
136355682Smarkm		printf("usage: %s directory-name\n", argv[0]);
136455682Smarkm		code = -1;
136555682Smarkm		return;
136655682Smarkm	}
136755682Smarkm	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
136855682Smarkm		if (verbose)
136955682Smarkm			printf("MKD command not recognized, trying XMKD\n");
137055682Smarkm		command("XMKD %s", argv[1]);
137155682Smarkm	}
137255682Smarkm}
137355682Smarkm
137455682Smarkm/*
137555682Smarkm * Remove a directory.
137655682Smarkm */
137755682Smarkmvoid
137855682Smarkmremovedir(int argc, char **argv)
137955682Smarkm{
138055682Smarkm
138155682Smarkm	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
138255682Smarkm		printf("usage: %s directory-name\n", argv[0]);
138355682Smarkm		code = -1;
138455682Smarkm		return;
138555682Smarkm	}
138655682Smarkm	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
138755682Smarkm		if (verbose)
138855682Smarkm			printf("RMD command not recognized, trying XRMD\n");
138955682Smarkm		command("XRMD %s", argv[1]);
139055682Smarkm	}
139155682Smarkm}
139255682Smarkm
139355682Smarkm/*
139455682Smarkm * Send a line, verbatim, to the remote machine.
139555682Smarkm */
139655682Smarkmvoid
139755682Smarkmquote(int argc, char **argv)
139855682Smarkm{
139955682Smarkm
140055682Smarkm	if (argc < 2 && !another(&argc, &argv, "command line to send")) {
140155682Smarkm		printf("usage: %s line-to-send\n", argv[0]);
140255682Smarkm		code = -1;
140355682Smarkm		return;
140455682Smarkm	}
140555682Smarkm	quote1("", argc, argv);
140655682Smarkm}
140755682Smarkm
140855682Smarkm/*
140955682Smarkm * Send a SITE command to the remote machine.  The line
141055682Smarkm * is sent verbatim to the remote machine, except that the
141155682Smarkm * word "SITE" is added at the front.
141255682Smarkm */
141355682Smarkmvoid
141455682Smarkmsite(int argc, char **argv)
141555682Smarkm{
141655682Smarkm
141755682Smarkm	if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
141855682Smarkm		printf("usage: %s line-to-send\n", argv[0]);
141955682Smarkm		code = -1;
142055682Smarkm		return;
142155682Smarkm	}
142255682Smarkm	quote1("SITE ", argc, argv);
142355682Smarkm}
142455682Smarkm
142555682Smarkm/*
142655682Smarkm * Turn argv[1..argc) into a space-separated string, then prepend initial text.
142755682Smarkm * Send the result as a one-line command and get response.
142855682Smarkm */
142955682Smarkmvoid
143055682Smarkmquote1(char *initial, int argc, char **argv)
143155682Smarkm{
143255682Smarkm    int i;
143355682Smarkm    char buf[BUFSIZ];		/* must be >= sizeof(line) */
143455682Smarkm
143555682Smarkm    strlcpy(buf, initial, sizeof(buf));
143655682Smarkm    for(i = 1; i < argc; i++) {
143755682Smarkm	if(i > 1)
143855682Smarkm	    strlcat(buf, " ", sizeof(buf));
143955682Smarkm	strlcat(buf, argv[i], sizeof(buf));
144055682Smarkm    }
144155682Smarkm    if (command("%s", buf) == PRELIM) {
144255682Smarkm	while (getreply(0) == PRELIM)
144355682Smarkm	    continue;
144455682Smarkm    }
144555682Smarkm}
144655682Smarkm
144755682Smarkmvoid
144855682Smarkmdo_chmod(int argc, char **argv)
144955682Smarkm{
145055682Smarkm
145155682Smarkm	if (argc < 2 && !another(&argc, &argv, "mode"))
145255682Smarkm		goto usage;
145355682Smarkm	if (argc < 3 && !another(&argc, &argv, "file-name")) {
145455682Smarkmusage:
145555682Smarkm		printf("usage: %s mode file-name\n", argv[0]);
145655682Smarkm		code = -1;
145755682Smarkm		return;
145855682Smarkm	}
145955682Smarkm	command("SITE CHMOD %s %s", argv[1], argv[2]);
146055682Smarkm}
146155682Smarkm
146255682Smarkmvoid
146355682Smarkmdo_umask(int argc, char **argv)
146455682Smarkm{
146555682Smarkm	int oldverbose = verbose;
146655682Smarkm
146755682Smarkm	verbose = 1;
146855682Smarkm	command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
146955682Smarkm	verbose = oldverbose;
147055682Smarkm}
147155682Smarkm
147255682Smarkmvoid
147355682Smarkmftp_idle(int argc, char **argv)
147455682Smarkm{
147555682Smarkm	int oldverbose = verbose;
147655682Smarkm
147755682Smarkm	verbose = 1;
147855682Smarkm	command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
147955682Smarkm	verbose = oldverbose;
148055682Smarkm}
148155682Smarkm
148255682Smarkm/*
148355682Smarkm * Ask the other side for help.
148455682Smarkm */
148555682Smarkmvoid
148655682Smarkmrmthelp(int argc, char **argv)
148755682Smarkm{
148855682Smarkm	int oldverbose = verbose;
148955682Smarkm
149055682Smarkm	verbose = 1;
149155682Smarkm	command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
149255682Smarkm	verbose = oldverbose;
149355682Smarkm}
149455682Smarkm
149555682Smarkm/*
149655682Smarkm * Terminate session and exit.
149755682Smarkm */
149855682Smarkm/*VARARGS*/
149955682Smarkmvoid
150055682Smarkmquit(int argc, char **argv)
150155682Smarkm{
150255682Smarkm
150355682Smarkm	if (connected)
150455682Smarkm		disconnect(0, 0);
150555682Smarkm	pswitch(1);
150655682Smarkm	if (connected) {
150755682Smarkm		disconnect(0, 0);
150855682Smarkm	}
150955682Smarkm	exit(0);
151055682Smarkm}
151155682Smarkm
151255682Smarkm/*
151355682Smarkm * Terminate session, but don't exit.
151455682Smarkm */
151555682Smarkmvoid
151655682Smarkmdisconnect(int argc, char **argv)
151755682Smarkm{
151855682Smarkm
151955682Smarkm	if (!connected)
152055682Smarkm		return;
152155682Smarkm	command("QUIT");
152255682Smarkm	if (cout) {
152355682Smarkm		fclose(cout);
152455682Smarkm	}
152555682Smarkm	cout = NULL;
152655682Smarkm	connected = 0;
152755682Smarkm	sec_end();
152855682Smarkm	data = -1;
152955682Smarkm	if (!proxy) {
153055682Smarkm		macnum = 0;
153155682Smarkm	}
153255682Smarkm}
153355682Smarkm
153455682Smarkmint
153555682Smarkmconfirm(char *cmd, char *file)
153655682Smarkm{
1537178825Sdfr	char buf[BUFSIZ];
153855682Smarkm
153955682Smarkm	if (!interactive)
154055682Smarkm		return (1);
154155682Smarkm	printf("%s %s? ", cmd, file);
154255682Smarkm	fflush(stdout);
1543178825Sdfr	if (fgets(buf, sizeof buf, stdin) == NULL)
154455682Smarkm		return (0);
1545178825Sdfr	return (*buf == 'y' || *buf == 'Y');
154655682Smarkm}
154755682Smarkm
154855682Smarkmvoid
154955682Smarkmfatal(char *msg)
155055682Smarkm{
155155682Smarkm
155255682Smarkm	errx(1, "%s", msg);
155355682Smarkm}
155455682Smarkm
155555682Smarkm/*
155655682Smarkm * Glob a local file name specification with
155755682Smarkm * the expectation of a single return value.
155855682Smarkm * Can't control multiple values being expanded
155955682Smarkm * from the expression, we return only the first.
156055682Smarkm */
156155682Smarkmint
156255682Smarkmglobulize(char **cpp)
156355682Smarkm{
156455682Smarkm	glob_t gl;
156555682Smarkm	int flags;
156655682Smarkm
156755682Smarkm	if (!doglob)
156855682Smarkm		return (1);
156955682Smarkm
157055682Smarkm	flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
157155682Smarkm	memset(&gl, 0, sizeof(gl));
157255682Smarkm	if (glob(*cpp, flags, NULL, &gl) ||
157355682Smarkm	    gl.gl_pathc == 0) {
157455682Smarkm		warnx("%s: not found", *cpp);
157555682Smarkm		globfree(&gl);
157655682Smarkm		return (0);
157755682Smarkm	}
157855682Smarkm	*cpp = strdup(gl.gl_pathv[0]);	/* XXX - wasted memory */
157955682Smarkm	globfree(&gl);
158055682Smarkm	return (1);
158155682Smarkm}
158255682Smarkm
158355682Smarkmvoid
158455682Smarkmaccount(int argc, char **argv)
158555682Smarkm{
1586178825Sdfr	char acctstr[50];
158755682Smarkm
158855682Smarkm	if (argc > 1) {
158955682Smarkm		++argv;
159055682Smarkm		--argc;
1591178825Sdfr		strlcpy (acctstr, *argv, sizeof(acctstr));
159255682Smarkm		while (argc > 1) {
159355682Smarkm			--argc;
159455682Smarkm			++argv;
1595178825Sdfr			strlcat(acctstr, *argv, sizeof(acctstr));
159655682Smarkm		}
159755682Smarkm	}
159855682Smarkm	else {
1599178825Sdfr	    UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0);
160055682Smarkm	}
1601178825Sdfr	command("ACCT %s", acctstr);
160255682Smarkm}
160355682Smarkm
160455682Smarkmjmp_buf abortprox;
160555682Smarkm
160655682Smarkmstatic RETSIGTYPE
160755682Smarkmproxabort(int sig)
160855682Smarkm{
160955682Smarkm
161055682Smarkm	if (!proxy) {
161155682Smarkm		pswitch(1);
161255682Smarkm	}
161355682Smarkm	if (connected) {
161455682Smarkm		proxflag = 1;
161555682Smarkm	}
161655682Smarkm	else {
161755682Smarkm		proxflag = 0;
161855682Smarkm	}
161955682Smarkm	pswitch(0);
162055682Smarkm	longjmp(abortprox,1);
162155682Smarkm}
162255682Smarkm
162355682Smarkmvoid
162455682Smarkmdoproxy(int argc, char **argv)
162555682Smarkm{
162655682Smarkm	struct cmd *c;
162772445Sassar	RETSIGTYPE (*oldintr)(int);
162855682Smarkm
162955682Smarkm	if (argc < 2 && !another(&argc, &argv, "command")) {
163055682Smarkm		printf("usage: %s command\n", argv[0]);
163155682Smarkm		code = -1;
163255682Smarkm		return;
163355682Smarkm	}
163455682Smarkm	c = getcmd(argv[1]);
163555682Smarkm	if (c == (struct cmd *) -1) {
163655682Smarkm		printf("?Ambiguous command\n");
163755682Smarkm		fflush(stdout);
163855682Smarkm		code = -1;
163955682Smarkm		return;
164055682Smarkm	}
164155682Smarkm	if (c == 0) {
164255682Smarkm		printf("?Invalid command\n");
164355682Smarkm		fflush(stdout);
164455682Smarkm		code = -1;
164555682Smarkm		return;
164655682Smarkm	}
164755682Smarkm	if (!c->c_proxy) {
164855682Smarkm		printf("?Invalid proxy command\n");
164955682Smarkm		fflush(stdout);
165055682Smarkm		code = -1;
165155682Smarkm		return;
165255682Smarkm	}
165355682Smarkm	if (setjmp(abortprox)) {
165455682Smarkm		code = -1;
165555682Smarkm		return;
165655682Smarkm	}
165755682Smarkm	oldintr = signal(SIGINT, proxabort);
165855682Smarkm	pswitch(1);
165955682Smarkm	if (c->c_conn && !connected) {
166055682Smarkm		printf("Not connected\n");
166155682Smarkm		fflush(stdout);
166255682Smarkm		pswitch(0);
166355682Smarkm		signal(SIGINT, oldintr);
166455682Smarkm		code = -1;
166555682Smarkm		return;
166655682Smarkm	}
166755682Smarkm	(*c->c_handler)(argc-1, argv+1);
166855682Smarkm	if (connected) {
166955682Smarkm		proxflag = 1;
167055682Smarkm	}
167155682Smarkm	else {
167255682Smarkm		proxflag = 0;
167355682Smarkm	}
167455682Smarkm	pswitch(0);
167555682Smarkm	signal(SIGINT, oldintr);
167655682Smarkm}
167755682Smarkm
167855682Smarkmvoid
167955682Smarkmsetcase(int argc, char **argv)
168055682Smarkm{
168155682Smarkm
168255682Smarkm	mcase = !mcase;
168355682Smarkm	printf("Case mapping %s.\n", onoff(mcase));
168455682Smarkm	code = mcase;
168555682Smarkm}
168655682Smarkm
168755682Smarkmvoid
168855682Smarkmsetcr(int argc, char **argv)
168955682Smarkm{
169055682Smarkm
169155682Smarkm	crflag = !crflag;
169255682Smarkm	printf("Carriage Return stripping %s.\n", onoff(crflag));
169355682Smarkm	code = crflag;
169455682Smarkm}
169555682Smarkm
169655682Smarkmvoid
169755682Smarkmsetntrans(int argc, char **argv)
169855682Smarkm{
169955682Smarkm	if (argc == 1) {
170055682Smarkm		ntflag = 0;
170155682Smarkm		printf("Ntrans off.\n");
170255682Smarkm		code = ntflag;
170355682Smarkm		return;
170455682Smarkm	}
170555682Smarkm	ntflag++;
170655682Smarkm	code = ntflag;
170755682Smarkm	strlcpy (ntin, argv[1], 17);
170855682Smarkm	if (argc == 2) {
170955682Smarkm		ntout[0] = '\0';
171055682Smarkm		return;
171155682Smarkm	}
171255682Smarkm	strlcpy (ntout, argv[2], 17);
171355682Smarkm}
171455682Smarkm
171555682Smarkmchar *
171655682Smarkmdotrans(char *name)
171755682Smarkm{
171855682Smarkm	static char new[MaxPathLen];
171955682Smarkm	char *cp1, *cp2 = new;
172055682Smarkm	int i, ostop, found;
172155682Smarkm
172255682Smarkm	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
172355682Smarkm		continue;
172455682Smarkm	for (cp1 = name; *cp1; cp1++) {
172555682Smarkm		found = 0;
172655682Smarkm		for (i = 0; *(ntin + i) && i < 16; i++) {
172755682Smarkm			if (*cp1 == *(ntin + i)) {
172855682Smarkm				found++;
172955682Smarkm				if (i < ostop) {
173055682Smarkm					*cp2++ = *(ntout + i);
173155682Smarkm				}
173255682Smarkm				break;
173355682Smarkm			}
173455682Smarkm		}
173555682Smarkm		if (!found) {
173655682Smarkm			*cp2++ = *cp1;
173755682Smarkm		}
173855682Smarkm	}
173955682Smarkm	*cp2 = '\0';
174055682Smarkm	return (new);
174155682Smarkm}
174255682Smarkm
174355682Smarkmvoid
174455682Smarkmsetnmap(int argc, char **argv)
174555682Smarkm{
174655682Smarkm	char *cp;
174755682Smarkm
174855682Smarkm	if (argc == 1) {
174955682Smarkm		mapflag = 0;
175055682Smarkm		printf("Nmap off.\n");
175155682Smarkm		code = mapflag;
175255682Smarkm		return;
175355682Smarkm	}
175455682Smarkm	if (argc < 3 && !another(&argc, &argv, "mapout")) {
175555682Smarkm		printf("Usage: %s [mapin mapout]\n",argv[0]);
175655682Smarkm		code = -1;
175755682Smarkm		return;
175855682Smarkm	}
175955682Smarkm	mapflag = 1;
176055682Smarkm	code = 1;
176155682Smarkm	cp = strchr(altarg, ' ');
1762233294Sstas	if (cp == NULL) {
1763233294Sstas		printf("Usage: %s missing space\n",argv[0]);
1764233294Sstas		code = -1;
1765233294Sstas		return;
1766233294Sstas	}
176755682Smarkm	if (proxy) {
176855682Smarkm		while(*++cp == ' ')
176955682Smarkm			continue;
177055682Smarkm		altarg = cp;
177155682Smarkm		cp = strchr(altarg, ' ');
177255682Smarkm	}
177355682Smarkm	*cp = '\0';
177455682Smarkm	strlcpy(mapin, altarg, MaxPathLen);
177555682Smarkm	while (*++cp == ' ')
177655682Smarkm		continue;
177755682Smarkm	strlcpy(mapout, cp, MaxPathLen);
177855682Smarkm}
177955682Smarkm
178055682Smarkmchar *
178155682Smarkmdomap(char *name)
178255682Smarkm{
178355682Smarkm	static char new[MaxPathLen];
178455682Smarkm	char *cp1 = name, *cp2 = mapin;
178555682Smarkm	char *tp[9], *te[9];
178655682Smarkm	int i, toks[9], toknum = 0, match = 1;
178755682Smarkm
178855682Smarkm	for (i=0; i < 9; ++i) {
178955682Smarkm		toks[i] = 0;
179055682Smarkm	}
179155682Smarkm	while (match && *cp1 && *cp2) {
179255682Smarkm		switch (*cp2) {
179355682Smarkm			case '\\':
179455682Smarkm				if (*++cp2 != *cp1) {
179555682Smarkm					match = 0;
179655682Smarkm				}
179755682Smarkm				break;
179855682Smarkm			case '$':
179955682Smarkm				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
180055682Smarkm					if (*cp1 != *(++cp2+1)) {
180155682Smarkm						toks[toknum = *cp2 - '1']++;
180255682Smarkm						tp[toknum] = cp1;
180355682Smarkm						while (*++cp1 && *(cp2+1)
180455682Smarkm							!= *cp1);
180555682Smarkm						te[toknum] = cp1;
180655682Smarkm					}
180755682Smarkm					cp2++;
180855682Smarkm					break;
180955682Smarkm				}
181055682Smarkm				/* FALLTHROUGH */
181155682Smarkm			default:
181255682Smarkm				if (*cp2 != *cp1) {
181355682Smarkm					match = 0;
181455682Smarkm				}
181555682Smarkm				break;
181655682Smarkm		}
181755682Smarkm		if (match && *cp1) {
181855682Smarkm			cp1++;
181955682Smarkm		}
182055682Smarkm		if (match && *cp2) {
182155682Smarkm			cp2++;
182255682Smarkm		}
182355682Smarkm	}
182455682Smarkm	if (!match && *cp1) /* last token mismatch */
182555682Smarkm	{
182655682Smarkm		toks[toknum] = 0;
182755682Smarkm	}
182855682Smarkm	cp1 = new;
182955682Smarkm	*cp1 = '\0';
183055682Smarkm	cp2 = mapout;
183155682Smarkm	while (*cp2) {
183255682Smarkm		match = 0;
183355682Smarkm		switch (*cp2) {
183455682Smarkm			case '\\':
183555682Smarkm				if (*(cp2 + 1)) {
183655682Smarkm					*cp1++ = *++cp2;
183755682Smarkm				}
183855682Smarkm				break;
183955682Smarkm			case '[':
184055682SmarkmLOOP:
1841233294Sstas				if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) {
184255682Smarkm					if (*++cp2 == '0') {
184355682Smarkm						char *cp3 = name;
184455682Smarkm
184555682Smarkm						while (*cp3) {
184655682Smarkm							*cp1++ = *cp3++;
184755682Smarkm						}
184855682Smarkm						match = 1;
184955682Smarkm					}
185055682Smarkm					else if (toks[toknum = *cp2 - '1']) {
185155682Smarkm						char *cp3 = tp[toknum];
185255682Smarkm
185355682Smarkm						while (cp3 != te[toknum]) {
185455682Smarkm							*cp1++ = *cp3++;
185555682Smarkm						}
185655682Smarkm						match = 1;
185755682Smarkm					}
185855682Smarkm				}
185955682Smarkm				else {
1860233294Sstas					while (*cp2 && *cp2 != ',' &&
186155682Smarkm					    *cp2 != ']') {
186255682Smarkm						if (*cp2 == '\\') {
186355682Smarkm							cp2++;
186455682Smarkm						}
186555682Smarkm						else if (*cp2 == '$' &&
186690926Snectar   						        isdigit((unsigned char)*(cp2+1))) {
186755682Smarkm							if (*++cp2 == '0') {
186855682Smarkm							   char *cp3 = name;
186955682Smarkm
187055682Smarkm							   while (*cp3) {
187155682Smarkm								*cp1++ = *cp3++;
187255682Smarkm							   }
187355682Smarkm							}
187455682Smarkm							else if (toks[toknum =
187555682Smarkm							    *cp2 - '1']) {
187655682Smarkm							   char *cp3=tp[toknum];
187755682Smarkm
187855682Smarkm							   while (cp3 !=
187955682Smarkm								  te[toknum]) {
188055682Smarkm								*cp1++ = *cp3++;
188155682Smarkm							   }
188255682Smarkm							}
188355682Smarkm						}
188455682Smarkm						else if (*cp2) {
188555682Smarkm							*cp1++ = *cp2++;
188655682Smarkm						}
188755682Smarkm					}
188855682Smarkm					if (!*cp2) {
188955682Smarkm						printf("nmap: unbalanced brackets\n");
189055682Smarkm						return (name);
189155682Smarkm					}
189255682Smarkm					match = 1;
189355682Smarkm					cp2--;
189455682Smarkm				}
189555682Smarkm				if (match) {
189655682Smarkm					while (*++cp2 && *cp2 != ']') {
189755682Smarkm					      if (*cp2 == '\\' && *(cp2 + 1)) {
189855682Smarkm							cp2++;
189955682Smarkm					      }
190055682Smarkm					}
190155682Smarkm					if (!*cp2) {
190255682Smarkm						printf("nmap: unbalanced brackets\n");
190355682Smarkm						return (name);
190455682Smarkm					}
190555682Smarkm					break;
190655682Smarkm				}
190755682Smarkm				switch (*++cp2) {
190855682Smarkm					case ',':
190955682Smarkm						goto LOOP;
191055682Smarkm					case ']':
191155682Smarkm						break;
191255682Smarkm					default:
191355682Smarkm						cp2--;
191455682Smarkm						goto LOOP;
191555682Smarkm				}
191655682Smarkm				break;
191755682Smarkm			case '$':
191890926Snectar				if (isdigit((unsigned char)*(cp2 + 1))) {
191955682Smarkm					if (*++cp2 == '0') {
192055682Smarkm						char *cp3 = name;
192155682Smarkm
192255682Smarkm						while (*cp3) {
192355682Smarkm							*cp1++ = *cp3++;
192455682Smarkm						}
192555682Smarkm					}
192655682Smarkm					else if (toks[toknum = *cp2 - '1']) {
192755682Smarkm						char *cp3 = tp[toknum];
192855682Smarkm
192955682Smarkm						while (cp3 != te[toknum]) {
193055682Smarkm							*cp1++ = *cp3++;
193155682Smarkm						}
193255682Smarkm					}
193355682Smarkm					break;
193455682Smarkm				}
193555682Smarkm				/* intentional drop through */
193655682Smarkm			default:
193755682Smarkm				*cp1++ = *cp2;
193855682Smarkm				break;
193955682Smarkm		}
194055682Smarkm		cp2++;
194155682Smarkm	}
194255682Smarkm	*cp1 = '\0';
194355682Smarkm	if (!*new) {
194455682Smarkm		return (name);
194555682Smarkm	}
194655682Smarkm	return (new);
194755682Smarkm}
194855682Smarkm
194955682Smarkmvoid
195055682Smarkmsetpassive(int argc, char **argv)
195155682Smarkm{
195255682Smarkm
195355682Smarkm	passivemode = !passivemode;
195455682Smarkm	printf("Passive mode %s.\n", onoff(passivemode));
195555682Smarkm	code = passivemode;
195655682Smarkm}
195755682Smarkm
195855682Smarkmvoid
195955682Smarkmsetsunique(int argc, char **argv)
196055682Smarkm{
196155682Smarkm
196255682Smarkm	sunique = !sunique;
196355682Smarkm	printf("Store unique %s.\n", onoff(sunique));
196455682Smarkm	code = sunique;
196555682Smarkm}
196655682Smarkm
196755682Smarkmvoid
196855682Smarkmsetrunique(int argc, char **argv)
196955682Smarkm{
197055682Smarkm
197155682Smarkm	runique = !runique;
197255682Smarkm	printf("Receive unique %s.\n", onoff(runique));
197355682Smarkm	code = runique;
197455682Smarkm}
197555682Smarkm
197655682Smarkm/* change directory to perent directory */
197755682Smarkmvoid
197855682Smarkmcdup(int argc, char **argv)
197955682Smarkm{
198055682Smarkm
198155682Smarkm	if (command("CDUP") == ERROR && code == 500) {
198255682Smarkm		if (verbose)
198355682Smarkm			printf("CDUP command not recognized, trying XCUP\n");
198455682Smarkm		command("XCUP");
198555682Smarkm	}
198655682Smarkm}
198755682Smarkm
198855682Smarkm/* restart transfer at specific point */
198955682Smarkmvoid
199055682Smarkmrestart(int argc, char **argv)
199155682Smarkm{
199255682Smarkm
199355682Smarkm    if (argc != 2)
199455682Smarkm	printf("restart: offset not specified\n");
199555682Smarkm    else {
199655682Smarkm	restart_point = atol(argv[1]);
199755682Smarkm	printf("restarting at %ld. %s\n", (long)restart_point,
199855682Smarkm	       "execute get, put or append to initiate transfer");
199955682Smarkm    }
200055682Smarkm}
200155682Smarkm
200255682Smarkm/* show remote system type */
200355682Smarkmvoid
200455682Smarkmsyst(int argc, char **argv)
200555682Smarkm{
200655682Smarkm
200755682Smarkm	command("SYST");
200855682Smarkm}
200955682Smarkm
201055682Smarkmvoid
201155682Smarkmmacdef(int argc, char **argv)
201255682Smarkm{
201355682Smarkm	char *tmp;
201455682Smarkm	int c;
201555682Smarkm
201655682Smarkm	if (macnum == 16) {
201755682Smarkm		printf("Limit of 16 macros have already been defined\n");
201855682Smarkm		code = -1;
201955682Smarkm		return;
202055682Smarkm	}
202155682Smarkm	if (argc < 2 && !another(&argc, &argv, "macro name")) {
202255682Smarkm		printf("Usage: %s macro_name\n",argv[0]);
202355682Smarkm		code = -1;
202455682Smarkm		return;
202555682Smarkm	}
202655682Smarkm	if (interactive) {
202755682Smarkm		printf("Enter macro line by line, terminating it with a null line\n");
202855682Smarkm	}
202955682Smarkm	strlcpy(macros[macnum].mac_name,
203055682Smarkm			argv[1],
203155682Smarkm			sizeof(macros[macnum].mac_name));
203255682Smarkm	if (macnum == 0) {
203355682Smarkm		macros[macnum].mac_start = macbuf;
203455682Smarkm	}
203555682Smarkm	else {
203655682Smarkm		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
203755682Smarkm	}
203855682Smarkm	tmp = macros[macnum].mac_start;
203955682Smarkm	while (tmp != macbuf+4096) {
204055682Smarkm		if ((c = getchar()) == EOF) {
204155682Smarkm			printf("macdef:end of file encountered\n");
204255682Smarkm			code = -1;
204355682Smarkm			return;
204455682Smarkm		}
204555682Smarkm		if ((*tmp = c) == '\n') {
204655682Smarkm			if (tmp == macros[macnum].mac_start) {
204755682Smarkm				macros[macnum++].mac_end = tmp;
204855682Smarkm				code = 0;
204955682Smarkm				return;
205055682Smarkm			}
205155682Smarkm			if (*(tmp-1) == '\0') {
205255682Smarkm				macros[macnum++].mac_end = tmp - 1;
205355682Smarkm				code = 0;
205455682Smarkm				return;
205555682Smarkm			}
205655682Smarkm			*tmp = '\0';
205755682Smarkm		}
205855682Smarkm		tmp++;
205955682Smarkm	}
206055682Smarkm	while (1) {
206155682Smarkm		while ((c = getchar()) != '\n' && c != EOF)
206255682Smarkm			/* LOOP */;
206355682Smarkm		if (c == EOF || getchar() == '\n') {
206455682Smarkm			printf("Macro not defined - 4k buffer exceeded\n");
206555682Smarkm			code = -1;
206655682Smarkm			return;
206755682Smarkm		}
206855682Smarkm	}
206955682Smarkm}
207055682Smarkm
207155682Smarkm/*
207255682Smarkm * get size of file on remote machine
207355682Smarkm */
207455682Smarkmvoid
207555682Smarkmsizecmd(int argc, char **argv)
207655682Smarkm{
207755682Smarkm
207855682Smarkm	if (argc < 2 && !another(&argc, &argv, "filename")) {
207955682Smarkm		printf("usage: %s filename\n", argv[0]);
208055682Smarkm		code = -1;
208155682Smarkm		return;
208255682Smarkm	}
208355682Smarkm	command("SIZE %s", argv[1]);
208455682Smarkm}
208555682Smarkm
208655682Smarkm/*
208755682Smarkm * get last modification time of file on remote machine
208855682Smarkm */
208955682Smarkmvoid
209055682Smarkmmodtime(int argc, char **argv)
209155682Smarkm{
209255682Smarkm	int overbose;
209355682Smarkm
209455682Smarkm	if (argc < 2 && !another(&argc, &argv, "filename")) {
209555682Smarkm		printf("usage: %s filename\n", argv[0]);
209655682Smarkm		code = -1;
209755682Smarkm		return;
209855682Smarkm	}
209955682Smarkm	overbose = verbose;
210055682Smarkm	if (debug == 0)
210155682Smarkm		verbose = -1;
210255682Smarkm	if (command("MDTM %s", argv[1]) == COMPLETE) {
210355682Smarkm		int yy, mo, day, hour, min, sec;
210455682Smarkm		sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
210555682Smarkm			&day, &hour, &min, &sec);
210655682Smarkm		/* might want to print this in local time */
210755682Smarkm		printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
210855682Smarkm			mo, day, yy, hour, min, sec);
210955682Smarkm	} else
211055682Smarkm		printf("%s\n", reply_string);
211155682Smarkm	verbose = overbose;
211255682Smarkm}
211355682Smarkm
211455682Smarkm/*
211555682Smarkm * show status on reomte machine
211655682Smarkm */
211755682Smarkmvoid
211855682Smarkmrmtstatus(int argc, char **argv)
211955682Smarkm{
212055682Smarkm
212155682Smarkm	command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
212255682Smarkm}
212355682Smarkm
212455682Smarkm/*
212555682Smarkm * get file if modtime is more recent than current file
212655682Smarkm */
212755682Smarkmvoid
212855682Smarkmnewer(int argc, char **argv)
212955682Smarkm{
213055682Smarkm
213155682Smarkm	if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w"))
213255682Smarkm		printf("Local file \"%s\" is newer than remote file \"%s\"\n",
213355682Smarkm			argv[2], argv[1]);
213455682Smarkm}
2135178825Sdfr
2136178825Sdfrvoid
2137178825Sdfrklist(int argc, char **argv)
2138178825Sdfr{
2139178825Sdfr    int ret;
2140178825Sdfr    if(argc != 1){
2141178825Sdfr	printf("usage: %s\n", argv[0]);
2142178825Sdfr	code = -1;
2143178825Sdfr	return;
2144178825Sdfr    }
2145233294Sstas
2146178825Sdfr    ret = command("SITE KLIST");
2147178825Sdfr    code = (ret == COMPLETE);
2148178825Sdfr}
2149