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