xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 13613)
110294Ssam #ifndef lint
2*13613Ssam static char sccsid[] = "@(#)cmds.c	4.8 (Berkeley) 07/02/83";
310294Ssam #endif
410294Ssam 
510294Ssam /*
610294Ssam  * FTP User Program -- Command Routines.
710294Ssam  */
811353Ssam #include <sys/param.h>
9*13613Ssam #include <sys/stat.h>
1010294Ssam #include <sys/socket.h>
1110294Ssam 
1212396Ssam #include <arpa/ftp.h>
1312396Ssam 
1410294Ssam #include <signal.h>
1510294Ssam #include <stdio.h>
1610294Ssam #include <errno.h>
1710294Ssam #include <netdb.h>
1810294Ssam 
1910294Ssam #include "ftp_var.h"
2010294Ssam 
2111353Ssam extern	char *globerr;
2211353Ssam extern	char **glob();
2311756Ssam extern	char *home;
2411353Ssam extern	short gflag;
2511756Ssam extern	char *remglob();
2611756Ssam extern	char *getenv();
2711756Ssam extern	char *index();
2811756Ssam extern	char *rindex();
2910294Ssam 
3010294Ssam /*
3110294Ssam  * Connect to peer server and
3210294Ssam  * auto-login, if possible.
3310294Ssam  */
3410294Ssam setpeer(argc, argv)
3510294Ssam 	int argc;
3610294Ssam 	char *argv[];
3710294Ssam {
3810294Ssam 	struct hostent *host, *hookup();
3910294Ssam 	int port;
4010294Ssam 
4110294Ssam 	if (connected) {
4210294Ssam 		printf("Already connected to %s, use disconnect first.\n",
4310294Ssam 			hostname);
4410294Ssam 		return;
4510294Ssam 	}
4610294Ssam 	if (argc < 2) {
4710294Ssam 		strcat(line, " ");
4810294Ssam 		printf("(to) ");
4910294Ssam 		gets(&line[strlen(line)]);
5010294Ssam 		makeargv();
5110294Ssam 		argc = margc;
5210294Ssam 		argv = margv;
5310294Ssam 	}
5410294Ssam 	if (argc > 3) {
5510294Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
5610294Ssam 		return;
5710294Ssam 	}
5810294Ssam 	port = sp->s_port;
5910294Ssam 	if (argc > 2) {
6011218Ssam 		port = atoi(argv[2]);
6110294Ssam 		if (port <= 0) {
6211218Ssam 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
6311218Ssam 			printf ("usage: %s host-name [port]\n", argv[0]);
6410294Ssam 			return;
6510294Ssam 		}
6610294Ssam 		port = htons(port);
6710294Ssam 	}
6810294Ssam 	host = hookup(argv[1], port);
6910294Ssam 	if (host) {
7010294Ssam 		connected = 1;
7110294Ssam 		if (autologin)
7210294Ssam 			login(host);
7310294Ssam 	}
7410294Ssam }
7510294Ssam 
7610294Ssam struct	types {
7710294Ssam 	char	*t_name;
7810294Ssam 	char	*t_mode;
7910294Ssam 	int	t_type;
8011218Ssam 	char	*t_arg;
8110294Ssam } types[] = {
8211218Ssam 	{ "ascii",	"A",	TYPE_A,	0 },
8311218Ssam 	{ "binary",	"I",	TYPE_I,	0 },
8411218Ssam 	{ "image",	"I",	TYPE_I,	0 },
8511218Ssam 	{ "ebcdic",	"E",	TYPE_E,	0 },
8611218Ssam 	{ "tenex",	"L",	TYPE_L,	bytename },
8710294Ssam 	0
8810294Ssam };
8910294Ssam 
9010294Ssam /*
9110294Ssam  * Set transfer type.
9210294Ssam  */
9310294Ssam settype(argc, argv)
9410294Ssam 	char *argv[];
9510294Ssam {
9610294Ssam 	register struct types *p;
9711218Ssam 	int comret;
9810294Ssam 
9910294Ssam 	if (argc > 2) {
10010294Ssam 		char *sep;
10110294Ssam 
10210294Ssam 		printf("usage: %s [", argv[0]);
10310294Ssam 		sep = " ";
10410294Ssam 		for (p = types; p->t_name; p++) {
10510294Ssam 			printf("%s%s", sep, p->t_name);
10610294Ssam 			if (*sep == ' ')
10710294Ssam 				sep = " | ";
10810294Ssam 		}
10910294Ssam 		printf(" ]\n");
11010294Ssam 		return;
11110294Ssam 	}
11210294Ssam 	if (argc < 2) {
11310294Ssam 		printf("Using %s mode to transfer files.\n", typename);
11410294Ssam 		return;
11510294Ssam 	}
11610294Ssam 	for (p = types; p->t_name; p++)
11710294Ssam 		if (strcmp(argv[1], p->t_name) == 0)
11810294Ssam 			break;
11910294Ssam 	if (p->t_name == 0) {
12010294Ssam 		printf("%s: unknown mode\n", argv[1]);
12110294Ssam 		return;
12210294Ssam 	}
12311218Ssam 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
12411218Ssam 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
12511218Ssam 	else
12611218Ssam 		comret = command("TYPE %s", p->t_mode);
12711218Ssam 	if (comret == COMPLETE) {
12810294Ssam 		strcpy(typename, p->t_name);
12910294Ssam 		type = p->t_type;
13010294Ssam 	}
13110294Ssam }
13210294Ssam 
13310294Ssam /*
13410294Ssam  * Set binary transfer type.
13510294Ssam  */
13610294Ssam /*VARARGS*/
13710294Ssam setbinary()
13810294Ssam {
13910294Ssam 
14010294Ssam 	call(settype, "type", "binary", 0);
14110294Ssam }
14210294Ssam 
14310294Ssam /*
14410294Ssam  * Set ascii transfer type.
14510294Ssam  */
14610294Ssam /*VARARGS*/
14710294Ssam setascii()
14810294Ssam {
14910294Ssam 
15010294Ssam 	call(settype, "type", "ascii", 0);
15110294Ssam }
15210294Ssam 
15310294Ssam /*
15410294Ssam  * Set tenex transfer type.
15510294Ssam  */
15610294Ssam /*VARARGS*/
15710294Ssam settenex()
15810294Ssam {
15910294Ssam 
16010294Ssam 	call(settype, "type", "tenex", 0);
16110294Ssam }
16210294Ssam 
16310294Ssam /*
16410294Ssam  * Set ebcdic transfer type.
16510294Ssam  */
16610294Ssam /*VARARGS*/
16710294Ssam setebcdic()
16810294Ssam {
16910294Ssam 
17010294Ssam 	call(settype, "type", "ebcdic", 0);
17110294Ssam }
17210294Ssam 
17310294Ssam /*
17410294Ssam  * Set file transfer mode.
17510294Ssam  */
17610294Ssam setmode(argc, argv)
17710294Ssam 	char *argv[];
17810294Ssam {
17910294Ssam 
18010294Ssam 	printf("We only support %s mode, sorry.\n", modename);
18110294Ssam }
18210294Ssam 
18310294Ssam /*
18410294Ssam  * Set file transfer format.
18510294Ssam  */
18610294Ssam setform(argc, argv)
18710294Ssam 	char *argv[];
18810294Ssam {
18910294Ssam 
19010294Ssam 	printf("We only support %s format, sorry.\n", formname);
19110294Ssam }
19210294Ssam 
19310294Ssam /*
19410294Ssam  * Set file transfer structure.
19510294Ssam  */
19610294Ssam setstruct(argc, argv)
19710294Ssam 	char *argv[];
19810294Ssam {
19910294Ssam 
20010294Ssam 	printf("We only support %s structure, sorry.\n", structname);
20110294Ssam }
20210294Ssam 
20310294Ssam put(argc, argv)
20411756Ssam 	int argc;
20510294Ssam 	char *argv[];
20610294Ssam {
20711650Ssam 	char *cmd;
20811650Ssam 
20910294Ssam 	if (argc == 2)
21010294Ssam 		argc++, argv[2] = argv[1];
21110294Ssam 	if (argc < 2) {
21210294Ssam 		strcat(line, " ");
21310294Ssam 		printf("(local-file) ");
21410294Ssam 		gets(&line[strlen(line)]);
21510294Ssam 		makeargv();
21610294Ssam 		argc = margc;
21710294Ssam 		argv = margv;
21810294Ssam 	}
21910294Ssam 	if (argc < 2) {
22010294Ssam usage:
22110294Ssam 		printf("%s local-file remote-file\n", argv[0]);
22210294Ssam 		return;
22310294Ssam 	}
22410294Ssam 	if (argc < 3) {
22510294Ssam 		strcat(line, " ");
22610294Ssam 		printf("(remote-file) ");
22710294Ssam 		gets(&line[strlen(line)]);
22810294Ssam 		makeargv();
22910294Ssam 		argc = margc;
23010294Ssam 		argv = margv;
23110294Ssam 	}
23210294Ssam 	if (argc < 3)
23310294Ssam 		goto usage;
23411353Ssam 	if (!globulize(&argv[1]))
23511353Ssam 		return;
23611756Ssam 	cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
23711650Ssam 	sendrequest(cmd, argv[1], argv[2]);
23810294Ssam }
23910294Ssam 
24010294Ssam /*
24111756Ssam  * Send multiple files.
24210294Ssam  */
24311353Ssam mput(argc, argv)
24411353Ssam 	char *argv[];
24511353Ssam {
24613212Ssam 	register int i;
24711353Ssam 
24811650Ssam 	if (argc < 2) {
24911650Ssam 		strcat(line, " ");
25011650Ssam 		printf("(local-files) ");
25111650Ssam 		gets(&line[strlen(line)]);
25211650Ssam 		makeargv();
25311650Ssam 		argc = margc;
25411650Ssam 		argv = margv;
25511353Ssam 	}
25611353Ssam 	if (argc < 2) {
25711353Ssam 		printf("%s local-files\n", argv[0]);
25811353Ssam 		return;
25911353Ssam 	}
26013212Ssam 	for (i = 1; i < argc; i++) {
26113212Ssam 		register char **cpp, **gargs;
26213212Ssam 
26313212Ssam 		if (!doglob) {
26413212Ssam 			if (confirm(argv[0], argv[i]))
26513212Ssam 				sendrequest("STOR", argv[i], argv[i]);
26613212Ssam 			continue;
26713212Ssam 		}
26813212Ssam 		gargs = glob(argv[i]);
26911650Ssam 		if (globerr != NULL) {
27011650Ssam 			printf("%s\n", globerr);
27111650Ssam 			if (gargs)
27211650Ssam 				blkfree(gargs);
27313212Ssam 			continue;
27411353Ssam 		}
27513212Ssam 		for (cpp = gargs; cpp && *cpp != NULL; cpp++)
27613212Ssam 			if (confirm(argv[0], *cpp))
27713212Ssam 				sendrequest("STOR", *cpp, *cpp);
27813212Ssam 		if (gargs != NULL)
27913212Ssam 			blkfree(gargs);
28011353Ssam 	}
28111353Ssam }
28211353Ssam 
28311353Ssam /*
28411353Ssam  * Receive one file.
28511353Ssam  */
28610294Ssam get(argc, argv)
28710294Ssam 	char *argv[];
28810294Ssam {
28910294Ssam 
29010294Ssam 	if (argc == 2)
29110294Ssam 		argc++, argv[2] = argv[1];
29210294Ssam 	if (argc < 2) {
29310294Ssam 		strcat(line, " ");
29410294Ssam 		printf("(remote-file) ");
29510294Ssam 		gets(&line[strlen(line)]);
29610294Ssam 		makeargv();
29710294Ssam 		argc = margc;
29810294Ssam 		argv = margv;
29910294Ssam 	}
30010294Ssam 	if (argc < 2) {
30110294Ssam usage:
30211353Ssam 		printf("%s remote-file [ local-file ]\n", argv[0]);
30310294Ssam 		return;
30410294Ssam 	}
30510294Ssam 	if (argc < 3) {
30610294Ssam 		strcat(line, " ");
30710294Ssam 		printf("(local-file) ");
30810294Ssam 		gets(&line[strlen(line)]);
30910294Ssam 		makeargv();
31010294Ssam 		argc = margc;
31110294Ssam 		argv = margv;
31210294Ssam 	}
31310294Ssam 	if (argc < 3)
31410294Ssam 		goto usage;
31511353Ssam 	if (!globulize(&argv[2]))
31611353Ssam 		return;
31711650Ssam 	recvrequest("RETR", argv[2], argv[1], "w");
31810294Ssam }
31910294Ssam 
32011353Ssam /*
32111353Ssam  * Get multiple files.
32211353Ssam  */
32311353Ssam mget(argc, argv)
32411353Ssam 	char *argv[];
32511353Ssam {
32611756Ssam 	char *cp;
32711353Ssam 
32811353Ssam 	if (argc < 2) {
32911353Ssam 		strcat(line, " ");
33011756Ssam 		printf("(remote-files) ");
33111353Ssam 		gets(&line[strlen(line)]);
33211353Ssam 		makeargv();
33311353Ssam 		argc = margc;
33411353Ssam 		argv = margv;
33511353Ssam 	}
33611353Ssam 	if (argc < 2) {
33711650Ssam 		printf("%s remote-files\n", argv[0]);
33811353Ssam 		return;
33911353Ssam 	}
34011650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
34111650Ssam 		if (confirm(argv[0], cp))
34211650Ssam 			recvrequest("RETR", cp, cp, "w");
34311650Ssam }
34411650Ssam 
34511650Ssam char *
34611650Ssam remglob(argc, argv)
34711650Ssam 	char *argv[];
34811650Ssam {
34911756Ssam 	char temp[16];
35011650Ssam 	static char buf[MAXPATHLEN];
35111650Ssam 	static FILE *ftemp = NULL;
35211650Ssam 	static char **args;
35313212Ssam 	int oldverbose, oldhash;
35411756Ssam 	char *cp, *mode;
35511650Ssam 
35611650Ssam 	if (!doglob) {
35711756Ssam 		if (args == NULL)
35811650Ssam 			args = argv;
35911650Ssam 		if ((cp = *++args) == NULL)
36011650Ssam 			args = NULL;
36111650Ssam 		return (cp);
36211353Ssam 	}
36311650Ssam 	if (ftemp == NULL) {
36411650Ssam 		strcpy(temp, "/tmp/ftpXXXXXX");
36511650Ssam 		mktemp(temp);
36611650Ssam 		oldverbose = verbose, verbose = 0;
36713212Ssam 		oldhash = hash, hash = 0;
36811756Ssam 		for (mode = "w"; *++argv != NULL; mode = "a")
36911756Ssam 			recvrequest ("NLST", temp, *argv, mode);
37013212Ssam 		verbose = oldverbose; hash = oldhash;
37111650Ssam 		ftemp = fopen(temp, "r");
37211650Ssam 		unlink(temp);
37311650Ssam 		if (ftemp == NULL) {
37411650Ssam 			printf("can't find list of remote files, oops\n");
37511756Ssam 			return (NULL);
37611353Ssam 		}
37711353Ssam 	}
37811650Ssam 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
37911650Ssam 		fclose(ftemp), ftemp = NULL;
38011650Ssam 		return (NULL);
38111353Ssam 	}
38211650Ssam 	if ((cp = index(buf, '\n')) != NULL)
38311650Ssam 		*cp = '\0';
38411650Ssam 	return (buf);
38511353Ssam }
38611353Ssam 
38710294Ssam char *
38810294Ssam onoff(bool)
38910294Ssam 	int bool;
39010294Ssam {
39110294Ssam 
39210294Ssam 	return (bool ? "on" : "off");
39310294Ssam }
39410294Ssam 
39510294Ssam /*
39610294Ssam  * Show status.
39710294Ssam  */
39810294Ssam status(argc, argv)
39910294Ssam 	char *argv[];
40010294Ssam {
40110294Ssam 
40210294Ssam 	if (connected)
40310294Ssam 		printf("Connected to %s.\n", hostname);
40410294Ssam 	else
40510294Ssam 		printf("Not connected.\n");
40610294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
40710294Ssam 		modename, typename, formname, structname);
40811353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
40911353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
41011353Ssam 		onoff(doglob));
41113212Ssam 	printf("Hash mark printing: %s; Use of PORT cmds: %s; Linger: %s\n",
41213212Ssam 		onoff(hash), onoff(sendport), onoff(linger));
41310294Ssam }
41410294Ssam 
41510294Ssam /*
41610294Ssam  * Set beep on cmd completed mode.
41710294Ssam  */
41810294Ssam /*VARARGS*/
41910294Ssam setbell()
42010294Ssam {
42110294Ssam 
42210294Ssam 	bell = !bell;
42310294Ssam 	printf("Bell mode %s.\n", onoff(bell));
42410294Ssam }
42510294Ssam 
42610294Ssam /*
42710294Ssam  * Turn on packet tracing.
42810294Ssam  */
42910294Ssam /*VARARGS*/
43010294Ssam settrace()
43110294Ssam {
43210294Ssam 
43310294Ssam 	trace = !trace;
43410294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
43510294Ssam }
43610294Ssam 
43710294Ssam /*
43811650Ssam  * Toggle hash mark printing during transfers.
43911650Ssam  */
44011650Ssam /*VARARGS*/
44111650Ssam sethash()
44211650Ssam {
44311650Ssam 
44411650Ssam 	hash = !hash;
44511650Ssam 	printf("Hash mark printing %s", onoff(hash));
44611650Ssam 	if (hash)
44711650Ssam 		printf(" (%d bytes/hash mark)", BUFSIZ);
44811650Ssam 	printf(".\n");
44911650Ssam }
45011650Ssam 
45111650Ssam /*
45210294Ssam  * Turn on printing of server echo's.
45310294Ssam  */
45410294Ssam /*VARARGS*/
45510294Ssam setverbose()
45610294Ssam {
45710294Ssam 
45810294Ssam 	verbose = !verbose;
45910294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
46010294Ssam }
46110294Ssam 
46210294Ssam /*
46311650Ssam  * Toggle PORT cmd use before each data connection.
46411650Ssam  */
46511650Ssam /*VARARGS*/
46611650Ssam setport()
46711650Ssam {
46811650Ssam 
46911650Ssam 	sendport = !sendport;
47011650Ssam 	printf("Use of PORT cmds %s.\n", onoff(sendport));
47111650Ssam }
47211650Ssam 
47311650Ssam /*
47410294Ssam  * Turn on interactive prompting
47510294Ssam  * during mget, mput, and mdelete.
47610294Ssam  */
47710294Ssam /*VARARGS*/
47810294Ssam setprompt()
47910294Ssam {
48010294Ssam 
48110294Ssam 	interactive = !interactive;
48210294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
48310294Ssam }
48410294Ssam 
48510294Ssam /*
48611353Ssam  * Toggle metacharacter interpretation
48711353Ssam  * on local file names.
48811353Ssam  */
48911353Ssam /*VARARGS*/
49011353Ssam setglob()
49111353Ssam {
49211353Ssam 
49311353Ssam 	doglob = !doglob;
49411353Ssam 	printf("Globbing %s.\n", onoff(doglob));
49511353Ssam }
49611353Ssam 
49711353Ssam /*
49810294Ssam  * Set debugging mode on/off and/or
49910294Ssam  * set level of debugging.
50010294Ssam  */
50111756Ssam /*VARARGS*/
50210294Ssam setdebug(argc, argv)
50310294Ssam 	char *argv[];
50410294Ssam {
50510294Ssam 	int val;
50610294Ssam 
50710294Ssam 	if (argc > 1) {
50810294Ssam 		val = atoi(argv[1]);
50910294Ssam 		if (val < 0) {
51010294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
51110294Ssam 			return;
51210294Ssam 		}
51310294Ssam 	} else
51410294Ssam 		val = !debug;
51510294Ssam 	debug = val;
51610294Ssam 	if (debug)
51710294Ssam 		options |= SO_DEBUG;
51810294Ssam 	else
51910294Ssam 		options &= ~SO_DEBUG;
52010294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
52110294Ssam }
52210294Ssam 
52310294Ssam /*
52413212Ssam  * Set linger on data connections on/off.
52513212Ssam  */
52613212Ssam /*VARARGS*/
52713212Ssam setlinger(argc, argv)
52813212Ssam 	char *argv[];
52913212Ssam {
53013212Ssam 
53113212Ssam 	if (argc == 1)
53213212Ssam 		linger = !linger;
53313212Ssam 	else
53413212Ssam 		linger = atoi(argv[1]);
53513212Ssam 	if (argc == 1 || linger == 0) {
53613212Ssam 		printf("Linger on data connection close %s.\n", onoff(linger));
53713212Ssam 		return;
53813212Ssam 	}
53913212Ssam 	printf("Will linger for %d seconds on close of data connections.\n",
54013212Ssam 	   linger);
54113212Ssam }
54213212Ssam 
54313212Ssam /*
54410294Ssam  * Set current working directory
54510294Ssam  * on remote machine.
54610294Ssam  */
54710294Ssam cd(argc, argv)
54810294Ssam 	char *argv[];
54910294Ssam {
55010294Ssam 
55110294Ssam 	if (argc < 2) {
55210294Ssam 		strcat(line, " ");
55310294Ssam 		printf("(remote-directory) ");
55410294Ssam 		gets(&line[strlen(line)]);
55510294Ssam 		makeargv();
55610294Ssam 		argc = margc;
55710294Ssam 		argv = margv;
55810294Ssam 	}
55910294Ssam 	if (argc < 2) {
56010294Ssam 		printf("%s remote-directory\n", argv[0]);
56110294Ssam 		return;
56210294Ssam 	}
56310294Ssam 	(void) command("CWD %s", argv[1]);
56410294Ssam }
56510294Ssam 
56610294Ssam /*
56710294Ssam  * Set current working directory
56810294Ssam  * on local machine.
56910294Ssam  */
57010294Ssam lcd(argc, argv)
57110294Ssam 	char *argv[];
57210294Ssam {
57311353Ssam 	char buf[MAXPATHLEN];
57410294Ssam 
57511353Ssam 	if (argc < 2)
57611353Ssam 		argc++, argv[1] = home;
57710294Ssam 	if (argc != 2) {
57810294Ssam 		printf("%s local-directory\n", argv[0]);
57910294Ssam 		return;
58010294Ssam 	}
58111353Ssam 	if (!globulize(&argv[1]))
58211353Ssam 		return;
58311353Ssam 	if (chdir(argv[1]) < 0) {
58410294Ssam 		perror(argv[1]);
58511353Ssam 		return;
58611353Ssam 	}
58711353Ssam 	printf("Local directory now %s\n", getwd(buf));
58810294Ssam }
58910294Ssam 
59010294Ssam /*
59110294Ssam  * Delete a single file.
59210294Ssam  */
59310294Ssam delete(argc, argv)
59410294Ssam 	char *argv[];
59510294Ssam {
59610294Ssam 
59710294Ssam 	if (argc < 2) {
59810294Ssam 		strcat(line, " ");
59910294Ssam 		printf("(remote-file) ");
60010294Ssam 		gets(&line[strlen(line)]);
60110294Ssam 		makeargv();
60210294Ssam 		argc = margc;
60310294Ssam 		argv = margv;
60410294Ssam 	}
60510294Ssam 	if (argc < 2) {
60610294Ssam 		printf("%s remote-file\n", argv[0]);
60710294Ssam 		return;
60810294Ssam 	}
60910294Ssam 	(void) command("DELE %s", argv[1]);
61010294Ssam }
61110294Ssam 
61210294Ssam /*
61311650Ssam  * Delete multiple files.
61411650Ssam  */
61511650Ssam mdelete(argc, argv)
61611650Ssam 	char *argv[];
61711650Ssam {
61811650Ssam 	char *cp;
61911650Ssam 
62011650Ssam 	if (argc < 2) {
62111650Ssam 		strcat(line, " ");
62211650Ssam 		printf("(remote-files) ");
62311650Ssam 		gets(&line[strlen(line)]);
62411650Ssam 		makeargv();
62511650Ssam 		argc = margc;
62611650Ssam 		argv = margv;
62711650Ssam 	}
62811650Ssam 	if (argc < 2) {
62911650Ssam 		printf("%s remote-files\n", argv[0]);
63011650Ssam 		return;
63111650Ssam 	}
63211650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
63311650Ssam 		if (confirm(argv[0], cp))
63411650Ssam 			(void) command("DELE %s", cp);
63511650Ssam }
63611756Ssam 
63711650Ssam /*
63810294Ssam  * Rename a remote file.
63910294Ssam  */
64010294Ssam renamefile(argc, argv)
64110294Ssam 	char *argv[];
64210294Ssam {
64310294Ssam 
64410294Ssam 	if (argc < 2) {
64510294Ssam 		strcat(line, " ");
64610294Ssam 		printf("(from-name) ");
64710294Ssam 		gets(&line[strlen(line)]);
64810294Ssam 		makeargv();
64910294Ssam 		argc = margc;
65010294Ssam 		argv = margv;
65110294Ssam 	}
65210294Ssam 	if (argc < 2) {
65310294Ssam usage:
65410294Ssam 		printf("%s from-name to-name\n", argv[0]);
65510294Ssam 		return;
65610294Ssam 	}
65710294Ssam 	if (argc < 3) {
65810294Ssam 		strcat(line, " ");
65910294Ssam 		printf("(to-name) ");
66010294Ssam 		gets(&line[strlen(line)]);
66110294Ssam 		makeargv();
66210294Ssam 		argc = margc;
66310294Ssam 		argv = margv;
66410294Ssam 	}
66510294Ssam 	if (argc < 3)
66610294Ssam 		goto usage;
66710294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
66810294Ssam 		(void) command("RNTO %s", argv[2]);
66910294Ssam }
67010294Ssam 
67110294Ssam /*
67210294Ssam  * Get a directory listing
67310294Ssam  * of remote files.
67410294Ssam  */
67510294Ssam ls(argc, argv)
67610294Ssam 	char *argv[];
67710294Ssam {
67811756Ssam 	char *cmd;
67910294Ssam 
68010294Ssam 	if (argc < 2)
68110294Ssam 		argc++, argv[1] = NULL;
68210294Ssam 	if (argc < 3)
68310294Ssam 		argc++, argv[2] = "-";
68411756Ssam 	if (argc > 3) {
68511756Ssam 		printf("usage: %s remote-directory local-file\n", argv[0]);
68611756Ssam 		return;
68711756Ssam 	}
68810294Ssam 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
68911353Ssam 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
69011353Ssam 		return;
69111756Ssam 	recvrequest(cmd, argv[2], argv[1], "w");
69210294Ssam }
69310294Ssam 
69410294Ssam /*
69511756Ssam  * Get a directory listing
69611756Ssam  * of multiple remote files.
69711756Ssam  */
69811756Ssam mls(argc, argv)
69911756Ssam 	char *argv[];
70011756Ssam {
70113212Ssam 	char *cmd, *mode, *cp, *dest;
70211756Ssam 
70313212Ssam 	if (argc < 2) {
70413212Ssam 		strcat(line, " ");
70513212Ssam 		printf("(remote-files) ");
70613212Ssam 		gets(&line[strlen(line)]);
70713212Ssam 		makeargv();
70813212Ssam 		argc = margc;
70913212Ssam 		argv = margv;
71013212Ssam 	}
71113212Ssam 	if (argc < 3) {
71213212Ssam 		strcat(line, " ");
71313212Ssam 		printf("(local-file) ");
71413212Ssam 		gets(&line[strlen(line)]);
71513212Ssam 		makeargv();
71613212Ssam 		argc = margc;
71713212Ssam 		argv = margv;
71813212Ssam 	}
71913212Ssam 	if (argc < 3) {
72013212Ssam 		printf("%s remote-files local-file\n", argv[0]);
72113212Ssam 		return;
72213212Ssam 	}
72313212Ssam 	dest = argv[argc - 1];
72413212Ssam 	argv[argc - 1] = NULL;
72513212Ssam 	if (strcmp(dest, "-"))
72613212Ssam 		if (globulize(&dest) && confirm("local-file", dest))
72713212Ssam 			return;
72811756Ssam 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
72913212Ssam 	for (mode = "w"; cp = remglob(argc, argv); mode = "a")
73013212Ssam 		if (confirm(argv[0], cp))
73113212Ssam 			recvrequest(cmd, dest, cp, mode);
73211756Ssam }
73311756Ssam 
73411756Ssam /*
73510294Ssam  * Do a shell escape
73610294Ssam  */
73710294Ssam shell(argc, argv)
73810294Ssam 	char *argv[];
73910294Ssam {
74011756Ssam 	int pid, status, (*old1)(), (*old2)();
74111756Ssam 	char shellnam[40], *shell, *namep;
74211756Ssam 	char **cpp, **gargs;
74310294Ssam 
74411756Ssam 	old1 = signal (SIGINT, SIG_IGN);
74511756Ssam 	old2 = signal (SIGQUIT, SIG_IGN);
74611756Ssam 	if ((pid = fork()) == 0) {
74711756Ssam 		for (pid = 3; pid < 20; pid++)
74811756Ssam 			close(pid);
74911756Ssam 		signal(SIGINT, SIG_DFL);
75011756Ssam 		signal(SIGQUIT, SIG_DFL);
75111756Ssam 		if (argc <= 1) {
75211756Ssam 			shell = getenv("SHELL");
75311756Ssam 			if (shell == NULL)
75411756Ssam 				shell = "/bin/sh";
75511756Ssam 			namep = rindex(shell,'/');
75611756Ssam 			if (namep == NULL)
75711756Ssam 				namep = shell;
75811756Ssam 			strcpy(shellnam,"-");
75911756Ssam 			strcat(shellnam, ++namep);
76011756Ssam 			if (strcmp(namep, "sh") != 0)
76111756Ssam 				shellnam[0] = '+';
76211756Ssam 			if (debug) {
76311756Ssam 				printf ("%s\n", shell);
76411756Ssam 				fflush (stdout);
76511756Ssam 			}
76611756Ssam 			execl(shell, shellnam, 0);
76711756Ssam 			perror(shell);
76811756Ssam 			exit(1);
76911756Ssam 		}
77011756Ssam 		cpp = &argv[1];
77111756Ssam 		if (argc > 2) {
77211756Ssam 			if ((gargs = glob(cpp)) != NULL)
77311756Ssam 				cpp = gargs;
77411756Ssam 			if (globerr != NULL) {
77511756Ssam 				printf("%s\n", globerr);
77611756Ssam 				exit(1);
77711756Ssam 			}
77811756Ssam 		}
77911756Ssam 		if (debug) {
78011756Ssam 			register char **zip = cpp;
78111756Ssam 
78211756Ssam 			printf("%s", *zip);
78311756Ssam 			while (*++zip != NULL)
78411756Ssam 				printf(" %s", *zip);
78511756Ssam 			printf("\n");
78611756Ssam 			fflush(stdout);
78711756Ssam 		}
78811756Ssam 		execvp(argv[1], cpp);
78911756Ssam 		perror(argv[1]);
79011756Ssam 		exit(1);
79111756Ssam 	}
79211756Ssam 	if (pid > 0)
79311756Ssam 		while (wait(&status) != pid)
79411756Ssam 			;
79511756Ssam 	signal(SIGINT, old1);
79611756Ssam 	signal(SIGQUIT, old2);
79711756Ssam 	if (pid == -1)
79811756Ssam 		perror("Try again later");
79911756Ssam 	return (0);
80010294Ssam }
80110294Ssam 
80210294Ssam /*
80310294Ssam  * Send new user information (re-login)
80410294Ssam  */
80510294Ssam user(argc, argv)
80610294Ssam 	int argc;
80710294Ssam 	char **argv;
80810294Ssam {
80910294Ssam 	char acct[80], *getpass();
81010294Ssam 	int n;
81110294Ssam 
81210294Ssam 	if (argc < 2) {
81310294Ssam 		strcat(line, " ");
81410294Ssam 		printf("(username) ");
81510294Ssam 		gets(&line[strlen(line)]);
81610294Ssam 		makeargv();
81710294Ssam 		argc = margc;
81810294Ssam 		argv = margv;
81910294Ssam 	}
82010294Ssam 	if (argc > 4) {
82110294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
82211756Ssam 		return (0);
82310294Ssam 	}
82410294Ssam 	n = command("USER %s", argv[1]);
82510294Ssam 	if (n == CONTINUE) {
82610294Ssam 		if (argc < 3 )
82710294Ssam 			argv[2] = getpass("Password: "), argc++;
82810294Ssam 		n = command("PASS %s", argv[2]);
82910294Ssam 	}
83010294Ssam 	if (n == CONTINUE) {
83110294Ssam 		if (argc < 4) {
83210294Ssam 			printf("Account: "); (void) fflush(stdout);
83310294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
83410294Ssam 			acct[strlen(acct) - 1] = '\0';
83510294Ssam 			argv[3] = acct; argc++;
83610294Ssam 		}
83710294Ssam 		n = command("ACCT %s", acct);
83810294Ssam 	}
83910294Ssam 	if (n != COMPLETE) {
84010294Ssam 		fprintf(stderr, "Login failed.\n");
84110294Ssam 		return (0);
84210294Ssam 	}
84310294Ssam 	return (1);
84410294Ssam }
84510294Ssam 
84610294Ssam /*
84710294Ssam  * Print working directory.
84810294Ssam  */
84910294Ssam /*VARARGS*/
85010294Ssam pwd()
85110294Ssam {
85211756Ssam 
85310294Ssam 	(void) command("XPWD");
85410294Ssam }
85510294Ssam 
85610294Ssam /*
85710294Ssam  * Make a directory.
85810294Ssam  */
85910294Ssam makedir(argc, argv)
86010294Ssam 	char *argv[];
86110294Ssam {
86210294Ssam 
86310294Ssam 	if (argc < 2) {
86410294Ssam 		strcat(line, " ");
86510294Ssam 		printf("(directory-name) ");
86610294Ssam 		gets(&line[strlen(line)]);
86710294Ssam 		makeargv();
86810294Ssam 		argc = margc;
86910294Ssam 		argv = margv;
87010294Ssam 	}
87110294Ssam 	if (argc < 2) {
87210294Ssam 		printf("%s directory-name\n", argv[0]);
87310294Ssam 		return;
87410294Ssam 	}
87510294Ssam 	(void) command("XMKD %s", argv[1]);
87610294Ssam }
87710294Ssam 
87810294Ssam /*
87910294Ssam  * Remove a directory.
88010294Ssam  */
88110294Ssam removedir(argc, argv)
88210294Ssam 	char *argv[];
88310294Ssam {
88410294Ssam 
88510294Ssam 	if (argc < 2) {
88610294Ssam 		strcat(line, " ");
88710294Ssam 		printf("(directory-name) ");
88810294Ssam 		gets(&line[strlen(line)]);
88910294Ssam 		makeargv();
89010294Ssam 		argc = margc;
89110294Ssam 		argv = margv;
89210294Ssam 	}
89310294Ssam 	if (argc < 2) {
89410294Ssam 		printf("%s directory-name\n", argv[0]);
89510294Ssam 		return;
89610294Ssam 	}
89710294Ssam 	(void) command("XRMD %s", argv[1]);
89810294Ssam }
89910294Ssam 
90010294Ssam /*
90110294Ssam  * Send a line, verbatim, to the remote machine.
90210294Ssam  */
90310294Ssam quote(argc, argv)
90410294Ssam 	char *argv[];
90510294Ssam {
90610294Ssam 	int i;
90710294Ssam 	char buf[BUFSIZ];
90810294Ssam 
90910294Ssam 	if (argc < 2) {
91010294Ssam 		strcat(line, " ");
91110294Ssam 		printf("(command line to send) ");
91210294Ssam 		gets(&line[strlen(line)]);
91310294Ssam 		makeargv();
91410294Ssam 		argc = margc;
91510294Ssam 		argv = margv;
91610294Ssam 	}
91710294Ssam 	if (argc < 2) {
91810294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
91910294Ssam 		return;
92010294Ssam 	}
92110294Ssam 	strcpy(buf, argv[1]);
92210294Ssam 	for (i = 2; i < argc; i++) {
92310294Ssam 		strcat(buf, " ");
92410294Ssam 		strcat(buf, argv[i]);
92510294Ssam 	}
92610294Ssam 	(void) command(buf);
92710294Ssam }
92810294Ssam 
92910294Ssam /*
93010294Ssam  * Ask the other side for help.
93110294Ssam  */
93210294Ssam rmthelp(argc, argv)
93310294Ssam 	char *argv[];
93410294Ssam {
93510294Ssam 	int oldverbose = verbose;
93610294Ssam 
93710294Ssam 	verbose = 1;
93810294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
93910294Ssam 	verbose = oldverbose;
94010294Ssam }
94110294Ssam 
94210294Ssam /*
94310294Ssam  * Terminate session and exit.
94410294Ssam  */
94510294Ssam /*VARARGS*/
94610294Ssam quit()
94710294Ssam {
94810294Ssam 
94910294Ssam 	disconnect();
95010294Ssam 	exit(0);
95110294Ssam }
95210294Ssam 
95310294Ssam /*
95410294Ssam  * Terminate session, but don't exit.
95510294Ssam  */
95610294Ssam disconnect()
95710294Ssam {
95810294Ssam 	extern FILE *cout;
95910294Ssam 	extern int data;
96010294Ssam 
96110294Ssam 	if (!connected)
96210294Ssam 		return;
96310294Ssam 	(void) command("QUIT");
96410294Ssam 	(void) fclose(cout);
96510294Ssam 	cout = NULL;
96610294Ssam 	connected = 0;
96710294Ssam 	data = -1;
96810294Ssam }
96911353Ssam 
97011650Ssam confirm(cmd, file)
97111353Ssam 	char *cmd, *file;
97211353Ssam {
97311353Ssam 	char line[BUFSIZ];
97411353Ssam 
97511353Ssam 	if (!interactive)
97611650Ssam 		return (1);
97711353Ssam 	printf("%s %s? ", cmd, file);
97811353Ssam 	fflush(stdout);
97911353Ssam 	gets(line);
98011650Ssam 	return (*line != 'n' && *line != 'N');
98111353Ssam }
98211353Ssam 
98311353Ssam fatal(msg)
98411353Ssam 	char *msg;
98511353Ssam {
98611353Ssam 
98711353Ssam 	fprintf(stderr, "ftp: %s\n");
98811353Ssam 	exit(1);
98911353Ssam }
99011353Ssam 
99111353Ssam /*
99211353Ssam  * Glob a local file name specification with
99311353Ssam  * the expectation of a single return value.
99411353Ssam  * Can't control multiple values being expanded
99511353Ssam  * from the expression, we return only the first.
99611353Ssam  */
99711353Ssam globulize(cpp)
99811353Ssam 	char **cpp;
99911353Ssam {
100011353Ssam 	char **globbed;
100111353Ssam 
100211353Ssam 	if (!doglob)
100311353Ssam 		return (1);
100411353Ssam 	globbed = glob(*cpp);
100511353Ssam 	if (globerr != NULL) {
100611353Ssam 		printf("%s: %s\n", *cpp, globerr);
100711353Ssam 		if (globbed)
100811353Ssam 			blkfree(globbed);
100911353Ssam 		return (0);
101011353Ssam 	}
101111353Ssam 	if (globbed) {
101211353Ssam 		*cpp = *globbed++;
101311353Ssam 		/* don't waste too much memory */
101411353Ssam 		if (*globbed)
101511353Ssam 			blkfree(globbed);
101611353Ssam 	}
101711353Ssam 	return (1);
101811353Ssam }
1019