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