xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 11650)
110294Ssam #ifndef lint
2*11650Ssam static char sccsid[] = "@(#)cmds.c	4.4 (Berkeley) 03/23/83";
310294Ssam #endif
410294Ssam 
510294Ssam /*
610294Ssam  * FTP User Program -- Command Routines.
710294Ssam  */
811353Ssam #include <sys/param.h>
910294Ssam #include <sys/socket.h>
1010294Ssam 
1110294Ssam #include <signal.h>
1210294Ssam #include <stdio.h>
1310294Ssam #include <errno.h>
1410294Ssam #include <netdb.h>
1511353Ssam #include <stat.h>
1610294Ssam 
1710294Ssam #include "ftp.h"
1810294Ssam #include "ftp_var.h"
1910294Ssam 
2011353Ssam extern	char *globerr;
2111353Ssam extern	char **glob();
2211353Ssam extern	short gflag;
2310294Ssam 
2410294Ssam /*
2510294Ssam  * Connect to peer server and
2610294Ssam  * auto-login, if possible.
2710294Ssam  */
2810294Ssam setpeer(argc, argv)
2910294Ssam 	int argc;
3010294Ssam 	char *argv[];
3110294Ssam {
3210294Ssam 	struct hostent *host, *hookup();
3310294Ssam 	int port;
3410294Ssam 
3510294Ssam 	if (connected) {
3610294Ssam 		printf("Already connected to %s, use disconnect first.\n",
3710294Ssam 			hostname);
3810294Ssam 		return;
3910294Ssam 	}
4010294Ssam 	if (argc < 2) {
4110294Ssam 		strcat(line, " ");
4210294Ssam 		printf("(to) ");
4310294Ssam 		gets(&line[strlen(line)]);
4410294Ssam 		makeargv();
4510294Ssam 		argc = margc;
4610294Ssam 		argv = margv;
4710294Ssam 	}
4810294Ssam 	if (argc > 3) {
4910294Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
5010294Ssam 		return;
5110294Ssam 	}
5210294Ssam 	port = sp->s_port;
5310294Ssam 	if (argc > 2) {
5411218Ssam 		port = atoi(argv[2]);
5510294Ssam 		if (port <= 0) {
5611218Ssam 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
5711218Ssam 			printf ("usage: %s host-name [port]\n", argv[0]);
5810294Ssam 			return;
5910294Ssam 		}
6010294Ssam 		port = htons(port);
6110294Ssam 	}
6210294Ssam 	host = hookup(argv[1], port);
6310294Ssam 	if (host) {
6410294Ssam 		connected = 1;
6510294Ssam 		if (autologin)
6610294Ssam 			login(host);
6710294Ssam 	}
6810294Ssam }
6910294Ssam 
7010294Ssam struct	types {
7110294Ssam 	char	*t_name;
7210294Ssam 	char	*t_mode;
7310294Ssam 	int	t_type;
7411218Ssam 	char	*t_arg;
7510294Ssam } types[] = {
7611218Ssam 	{ "ascii",	"A",	TYPE_A,	0 },
7711218Ssam 	{ "binary",	"I",	TYPE_I,	0 },
7811218Ssam 	{ "image",	"I",	TYPE_I,	0 },
7911218Ssam 	{ "ebcdic",	"E",	TYPE_E,	0 },
8011218Ssam 	{ "tenex",	"L",	TYPE_L,	bytename },
8110294Ssam 	0
8210294Ssam };
8310294Ssam 
8410294Ssam /*
8510294Ssam  * Set transfer type.
8610294Ssam  */
8710294Ssam settype(argc, argv)
8810294Ssam 	char *argv[];
8910294Ssam {
9010294Ssam 	register struct types *p;
9111218Ssam 	int comret;
9210294Ssam 
9310294Ssam 	if (argc > 2) {
9410294Ssam 		char *sep;
9510294Ssam 
9610294Ssam 		printf("usage: %s [", argv[0]);
9710294Ssam 		sep = " ";
9810294Ssam 		for (p = types; p->t_name; p++) {
9910294Ssam 			printf("%s%s", sep, p->t_name);
10010294Ssam 			if (*sep == ' ')
10110294Ssam 				sep = " | ";
10210294Ssam 		}
10310294Ssam 		printf(" ]\n");
10410294Ssam 		return;
10510294Ssam 	}
10610294Ssam 	if (argc < 2) {
10710294Ssam 		printf("Using %s mode to transfer files.\n", typename);
10810294Ssam 		return;
10910294Ssam 	}
11010294Ssam 	for (p = types; p->t_name; p++)
11110294Ssam 		if (strcmp(argv[1], p->t_name) == 0)
11210294Ssam 			break;
11310294Ssam 	if (p->t_name == 0) {
11410294Ssam 		printf("%s: unknown mode\n", argv[1]);
11510294Ssam 		return;
11610294Ssam 	}
11711218Ssam 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
11811218Ssam 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
11911218Ssam 	else
12011218Ssam 		comret = command("TYPE %s", p->t_mode);
12111218Ssam 	if (comret == COMPLETE) {
12210294Ssam 		strcpy(typename, p->t_name);
12310294Ssam 		type = p->t_type;
12410294Ssam 	}
12510294Ssam }
12610294Ssam 
12710294Ssam /*
12810294Ssam  * Set binary transfer type.
12910294Ssam  */
13010294Ssam /*VARARGS*/
13110294Ssam setbinary()
13210294Ssam {
13310294Ssam 
13410294Ssam 	call(settype, "type", "binary", 0);
13510294Ssam }
13610294Ssam 
13710294Ssam /*
13810294Ssam  * Set ascii transfer type.
13910294Ssam  */
14010294Ssam /*VARARGS*/
14110294Ssam setascii()
14210294Ssam {
14310294Ssam 
14410294Ssam 	call(settype, "type", "ascii", 0);
14510294Ssam }
14610294Ssam 
14710294Ssam /*
14810294Ssam  * Set tenex transfer type.
14910294Ssam  */
15010294Ssam /*VARARGS*/
15110294Ssam settenex()
15210294Ssam {
15310294Ssam 
15410294Ssam 	call(settype, "type", "tenex", 0);
15510294Ssam }
15610294Ssam 
15710294Ssam /*
15810294Ssam  * Set ebcdic transfer type.
15910294Ssam  */
16010294Ssam /*VARARGS*/
16110294Ssam setebcdic()
16210294Ssam {
16310294Ssam 
16410294Ssam 	call(settype, "type", "ebcdic", 0);
16510294Ssam }
16610294Ssam 
16710294Ssam /*
16810294Ssam  * Set file transfer mode.
16910294Ssam  */
17010294Ssam setmode(argc, argv)
17110294Ssam 	char *argv[];
17210294Ssam {
17310294Ssam 
17410294Ssam 	printf("We only support %s mode, sorry.\n", modename);
17510294Ssam }
17610294Ssam 
17710294Ssam /*
17810294Ssam  * Set file transfer format.
17910294Ssam  */
18010294Ssam setform(argc, argv)
18110294Ssam 	char *argv[];
18210294Ssam {
18310294Ssam 
18410294Ssam 	printf("We only support %s format, sorry.\n", formname);
18510294Ssam }
18610294Ssam 
18710294Ssam /*
18810294Ssam  * Set file transfer structure.
18910294Ssam  */
19010294Ssam setstruct(argc, argv)
19110294Ssam 	char *argv[];
19210294Ssam {
19310294Ssam 
19410294Ssam 	printf("We only support %s structure, sorry.\n", structname);
19510294Ssam }
19610294Ssam 
19710294Ssam /*
19810294Ssam  * Send a single file.
19910294Ssam  */
200*11650Ssam append(argc, argv)
201*11650Ssam 	char *argv[];
202*11650Ssam {
203*11650Ssam 
204*11650Ssam 	return (put1("APPE", argc, argv));
205*11650Ssam }
206*11650Ssam 
20710294Ssam put(argc, argv)
20810294Ssam 	char *argv[];
20910294Ssam {
21010294Ssam 
211*11650Ssam 	return (put1("STOR", argc, argv));
212*11650Ssam }
213*11650Ssam 
214*11650Ssam put1(cmd, argc, argv)
215*11650Ssam 	char *cmd;
216*11650Ssam 	int argc;
217*11650Ssam 	char *argv[];
218*11650Ssam {
219*11650Ssam 
22010294Ssam 	if (argc == 2)
22110294Ssam 		argc++, argv[2] = argv[1];
22210294Ssam 	if (argc < 2) {
22310294Ssam 		strcat(line, " ");
22410294Ssam 		printf("(local-file) ");
22510294Ssam 		gets(&line[strlen(line)]);
22610294Ssam 		makeargv();
22710294Ssam 		argc = margc;
22810294Ssam 		argv = margv;
22910294Ssam 	}
23010294Ssam 	if (argc < 2) {
23110294Ssam usage:
23210294Ssam 		printf("%s local-file remote-file\n", argv[0]);
23310294Ssam 		return;
23410294Ssam 	}
23510294Ssam 	if (argc < 3) {
23610294Ssam 		strcat(line, " ");
23710294Ssam 		printf("(remote-file) ");
23810294Ssam 		gets(&line[strlen(line)]);
23910294Ssam 		makeargv();
24010294Ssam 		argc = margc;
24110294Ssam 		argv = margv;
24210294Ssam 	}
24310294Ssam 	if (argc < 3)
24410294Ssam 		goto usage;
24511353Ssam 	if (!globulize(&argv[1]))
24611353Ssam 		return;
247*11650Ssam 	sendrequest(cmd, argv[1], argv[2]);
24810294Ssam }
24910294Ssam 
25010294Ssam /*
25111353Ssam  * Send one or more files.
25210294Ssam  */
25311353Ssam mput(argc, argv)
25411353Ssam 	char *argv[];
25511353Ssam {
256*11650Ssam 	char **cpp, **gargs = NULL;
25711353Ssam 	int i;
25811353Ssam 
259*11650Ssam 	if (argc < 2) {
260*11650Ssam 		strcat(line, " ");
261*11650Ssam 		printf("(local-files) ");
262*11650Ssam 		gets(&line[strlen(line)]);
263*11650Ssam 		makeargv();
264*11650Ssam 		argc = margc;
265*11650Ssam 		argv = margv;
26611353Ssam 	}
26711353Ssam 	if (argc < 2) {
26811353Ssam 		printf("%s local-files\n", argv[0]);
26911353Ssam 		return;
27011353Ssam 	}
271*11650Ssam 	cpp = argv + 1;
272*11650Ssam 	if (doglob) {
273*11650Ssam 		gargs = glob(cpp);
274*11650Ssam 		if (globerr != NULL) {
275*11650Ssam 			printf("%s\n", globerr);
276*11650Ssam 			if (gargs)
277*11650Ssam 				blkfree(gargs);
27811353Ssam 			return;
27911353Ssam 		}
28011353Ssam 	}
281*11650Ssam 	if (gargs != NULL)
282*11650Ssam 		cpp = gargs;
283*11650Ssam 	for (; *cpp != NULL; cpp++)
284*11650Ssam 		if (confirm(argv[0], *cpp))
285*11650Ssam 			sendrequest("STOR", *cpp, *cpp);
286*11650Ssam 	if (gargs != NULL)
287*11650Ssam 		blkfree(gargs);
28811353Ssam }
28911353Ssam 
29011353Ssam /*
29111353Ssam  * Receive one file.
29211353Ssam  */
29310294Ssam get(argc, argv)
29410294Ssam 	char *argv[];
29510294Ssam {
29610294Ssam 
29710294Ssam 	if (argc == 2)
29810294Ssam 		argc++, argv[2] = argv[1];
29910294Ssam 	if (argc < 2) {
30010294Ssam 		strcat(line, " ");
30110294Ssam 		printf("(remote-file) ");
30210294Ssam 		gets(&line[strlen(line)]);
30310294Ssam 		makeargv();
30410294Ssam 		argc = margc;
30510294Ssam 		argv = margv;
30610294Ssam 	}
30710294Ssam 	if (argc < 2) {
30810294Ssam usage:
30911353Ssam 		printf("%s remote-file [ local-file ]\n", argv[0]);
31010294Ssam 		return;
31110294Ssam 	}
31210294Ssam 	if (argc < 3) {
31310294Ssam 		strcat(line, " ");
31410294Ssam 		printf("(local-file) ");
31510294Ssam 		gets(&line[strlen(line)]);
31610294Ssam 		makeargv();
31710294Ssam 		argc = margc;
31810294Ssam 		argv = margv;
31910294Ssam 	}
32010294Ssam 	if (argc < 3)
32110294Ssam 		goto usage;
32211353Ssam 	if (!globulize(&argv[2]))
32311353Ssam 		return;
324*11650Ssam 	recvrequest("RETR", argv[2], argv[1], "w");
32510294Ssam }
32610294Ssam 
32711353Ssam /*
32811353Ssam  * Get multiple files.
32911353Ssam  */
33011353Ssam mget(argc, argv)
33111353Ssam 	char *argv[];
33211353Ssam {
333*11650Ssam 	register char *cp;
33411353Ssam 
33511353Ssam 	if (argc < 2) {
33611353Ssam 		strcat(line, " ");
33711353Ssam 		printf("(remote-directory) ");
33811353Ssam 		gets(&line[strlen(line)]);
33911353Ssam 		makeargv();
34011353Ssam 		argc = margc;
34111353Ssam 		argv = margv;
34211353Ssam 	}
34311353Ssam 	if (argc < 2) {
344*11650Ssam 		printf("%s remote-files\n", argv[0]);
34511353Ssam 		return;
34611353Ssam 	}
347*11650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
348*11650Ssam 		if (confirm(argv[0], cp))
349*11650Ssam 			recvrequest("RETR", cp, cp, "w");
350*11650Ssam }
351*11650Ssam 
352*11650Ssam char *
353*11650Ssam remglob(argc, argv)
354*11650Ssam 	char *argv[];
355*11650Ssam {
356*11650Ssam 	char temp[16], *cp;
357*11650Ssam 	static char buf[MAXPATHLEN];
358*11650Ssam 	static FILE *ftemp = NULL;
359*11650Ssam 	static char **args;
360*11650Ssam 	int oldverbose;
361*11650Ssam 
362*11650Ssam 	if (!doglob) {
363*11650Ssam 		if (argc == NULL)
364*11650Ssam 			args = argv;
365*11650Ssam 		if ((cp = *++args) == NULL)
366*11650Ssam 			args = NULL;
367*11650Ssam 		return (cp);
36811353Ssam 	}
369*11650Ssam 	if (ftemp == NULL) {
370*11650Ssam 		strcpy(temp, "/tmp/ftpXXXXXX");
371*11650Ssam 		mktemp(temp);
372*11650Ssam 		oldverbose = verbose, verbose = 0;
373*11650Ssam 		recvrequest("NLST", temp, argv[1], "w");
374*11650Ssam 		verbose = oldverbose;
375*11650Ssam 		ftemp = fopen(temp, "r");
376*11650Ssam 		unlink(temp);
377*11650Ssam 		if (ftemp == NULL) {
378*11650Ssam 			printf("can't find list of remote files, oops\n");
37911353Ssam 			return;
38011353Ssam 		}
38111353Ssam 	}
382*11650Ssam 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
383*11650Ssam 		fclose(ftemp), ftemp = NULL;
384*11650Ssam 		return (NULL);
38511353Ssam 	}
386*11650Ssam 	if ((cp = index(buf, '\n')) != NULL)
387*11650Ssam 		*cp = '\0';
388*11650Ssam 	return (buf);
38911353Ssam }
39011353Ssam 
39110294Ssam char *
39210294Ssam onoff(bool)
39310294Ssam 	int bool;
39410294Ssam {
39510294Ssam 
39610294Ssam 	return (bool ? "on" : "off");
39710294Ssam }
39810294Ssam 
39910294Ssam /*
40010294Ssam  * Show status.
40110294Ssam  */
40210294Ssam status(argc, argv)
40310294Ssam 	char *argv[];
40410294Ssam {
40510294Ssam 
40610294Ssam 	if (connected)
40710294Ssam 		printf("Connected to %s.\n", hostname);
40810294Ssam 	else
40910294Ssam 		printf("Not connected.\n");
41010294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
41110294Ssam 		modename, typename, formname, structname);
41211353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
41311353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
41411353Ssam 		onoff(doglob));
415*11650Ssam 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
416*11650Ssam 		onoff(hash), onoff(sendport));
41710294Ssam }
41810294Ssam 
41910294Ssam /*
42010294Ssam  * Set beep on cmd completed mode.
42110294Ssam  */
42210294Ssam /*VARARGS*/
42310294Ssam setbell()
42410294Ssam {
42510294Ssam 
42610294Ssam 	bell = !bell;
42710294Ssam 	printf("Bell mode %s.\n", onoff(bell));
42810294Ssam }
42910294Ssam 
43010294Ssam /*
43110294Ssam  * Turn on packet tracing.
43210294Ssam  */
43310294Ssam /*VARARGS*/
43410294Ssam settrace()
43510294Ssam {
43610294Ssam 
43710294Ssam 	trace = !trace;
43810294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
43910294Ssam }
44010294Ssam 
44110294Ssam /*
442*11650Ssam  * Toggle hash mark printing during transfers.
443*11650Ssam  */
444*11650Ssam /*VARARGS*/
445*11650Ssam sethash()
446*11650Ssam {
447*11650Ssam 
448*11650Ssam 	hash = !hash;
449*11650Ssam 	printf("Hash mark printing %s", onoff(hash));
450*11650Ssam 	if (hash)
451*11650Ssam 		printf(" (%d bytes/hash mark)", BUFSIZ);
452*11650Ssam 	printf(".\n");
453*11650Ssam }
454*11650Ssam 
455*11650Ssam /*
45610294Ssam  * Turn on printing of server echo's.
45710294Ssam  */
45810294Ssam /*VARARGS*/
45910294Ssam setverbose()
46010294Ssam {
46110294Ssam 
46210294Ssam 	verbose = !verbose;
46310294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
46410294Ssam }
46510294Ssam 
46610294Ssam /*
467*11650Ssam  * Toggle PORT cmd use before each data connection.
468*11650Ssam  */
469*11650Ssam /*VARARGS*/
470*11650Ssam setport()
471*11650Ssam {
472*11650Ssam 
473*11650Ssam 	sendport = !sendport;
474*11650Ssam 	printf("Use of PORT cmds %s.\n", onoff(sendport));
475*11650Ssam }
476*11650Ssam 
477*11650Ssam /*
47810294Ssam  * Turn on interactive prompting
47910294Ssam  * during mget, mput, and mdelete.
48010294Ssam  */
48110294Ssam /*VARARGS*/
48210294Ssam setprompt()
48310294Ssam {
48410294Ssam 
48510294Ssam 	interactive = !interactive;
48610294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
48710294Ssam }
48810294Ssam 
48910294Ssam /*
49011353Ssam  * Toggle metacharacter interpretation
49111353Ssam  * on local file names.
49211353Ssam  */
49311353Ssam /*VARARGS*/
49411353Ssam setglob()
49511353Ssam {
49611353Ssam 
49711353Ssam 	doglob = !doglob;
49811353Ssam 	printf("Globbing %s.\n", onoff(doglob));
49911353Ssam }
50011353Ssam 
50111353Ssam /*
50210294Ssam  * Set debugging mode on/off and/or
50310294Ssam  * set level of debugging.
50410294Ssam  */
50510294Ssam setdebug(argc, argv)
50610294Ssam 	char *argv[];
50710294Ssam {
50810294Ssam 	int val;
50910294Ssam 
51010294Ssam 	if (argc > 1) {
51110294Ssam 		val = atoi(argv[1]);
51210294Ssam 		if (val < 0) {
51310294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
51410294Ssam 			return;
51510294Ssam 		}
51610294Ssam 	} else
51710294Ssam 		val = !debug;
51810294Ssam 	debug = val;
51910294Ssam 	if (debug)
52010294Ssam 		options |= SO_DEBUG;
52110294Ssam 	else
52210294Ssam 		options &= ~SO_DEBUG;
52310294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
52410294Ssam }
52510294Ssam 
52610294Ssam /*
52710294Ssam  * Set current working directory
52810294Ssam  * on remote machine.
52910294Ssam  */
53010294Ssam cd(argc, argv)
53110294Ssam 	char *argv[];
53210294Ssam {
53310294Ssam 
53410294Ssam 	if (!connected) {
53510294Ssam 		printf("Not connected.\n");
53610294Ssam 		return;
53710294Ssam 	}
53810294Ssam 	if (argc < 2) {
53910294Ssam 		strcat(line, " ");
54010294Ssam 		printf("(remote-directory) ");
54110294Ssam 		gets(&line[strlen(line)]);
54210294Ssam 		makeargv();
54310294Ssam 		argc = margc;
54410294Ssam 		argv = margv;
54510294Ssam 	}
54610294Ssam 	if (argc < 2) {
54710294Ssam 		printf("%s remote-directory\n", argv[0]);
54810294Ssam 		return;
54910294Ssam 	}
55010294Ssam 	(void) command("CWD %s", argv[1]);
55110294Ssam }
55210294Ssam 
55310294Ssam /*
55410294Ssam  * Set current working directory
55510294Ssam  * on local machine.
55610294Ssam  */
55710294Ssam lcd(argc, argv)
55810294Ssam 	char *argv[];
55910294Ssam {
56011353Ssam 	char buf[MAXPATHLEN];
56111353Ssam 	extern char *home;
56210294Ssam 
56311353Ssam 	if (argc < 2)
56411353Ssam 		argc++, argv[1] = home;
56510294Ssam 	if (argc != 2) {
56610294Ssam 		printf("%s local-directory\n", argv[0]);
56710294Ssam 		return;
56810294Ssam 	}
56911353Ssam 	if (!globulize(&argv[1]))
57011353Ssam 		return;
57111353Ssam 	if (chdir(argv[1]) < 0) {
57210294Ssam 		perror(argv[1]);
57311353Ssam 		return;
57411353Ssam 	}
57511353Ssam 	printf("Local directory now %s\n", getwd(buf));
57610294Ssam }
57710294Ssam 
57810294Ssam /*
57910294Ssam  * Delete a single file.
58010294Ssam  */
58110294Ssam delete(argc, argv)
58210294Ssam 	char *argv[];
58310294Ssam {
58410294Ssam 
58510294Ssam 	if (argc < 2) {
58610294Ssam 		strcat(line, " ");
58710294Ssam 		printf("(remote-file) ");
58810294Ssam 		gets(&line[strlen(line)]);
58910294Ssam 		makeargv();
59010294Ssam 		argc = margc;
59110294Ssam 		argv = margv;
59210294Ssam 	}
59310294Ssam 	if (argc < 2) {
59410294Ssam 		printf("%s remote-file\n", argv[0]);
59510294Ssam 		return;
59610294Ssam 	}
59710294Ssam 	(void) command("DELE %s", argv[1]);
59810294Ssam }
59910294Ssam 
60010294Ssam /*
601*11650Ssam  * Delete multiple files.
602*11650Ssam  */
603*11650Ssam mdelete(argc, argv)
604*11650Ssam 	char *argv[];
605*11650Ssam {
606*11650Ssam 	char *cp;
607*11650Ssam 
608*11650Ssam 	if (argc < 2) {
609*11650Ssam 		strcat(line, " ");
610*11650Ssam 		printf("(remote-files) ");
611*11650Ssam 		gets(&line[strlen(line)]);
612*11650Ssam 		makeargv();
613*11650Ssam 		argc = margc;
614*11650Ssam 		argv = margv;
615*11650Ssam 	}
616*11650Ssam 	if (argc < 2) {
617*11650Ssam 		printf("%s remote-files\n", argv[0]);
618*11650Ssam 		return;
619*11650Ssam 	}
620*11650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
621*11650Ssam 		if (confirm(argv[0], cp))
622*11650Ssam 			(void) command("DELE %s", cp);
623*11650Ssam }
624*11650Ssam /*
62510294Ssam  * Rename a remote file.
62610294Ssam  */
62710294Ssam renamefile(argc, argv)
62810294Ssam 	char *argv[];
62910294Ssam {
63010294Ssam 
63110294Ssam 	if (argc < 2) {
63210294Ssam 		strcat(line, " ");
63310294Ssam 		printf("(from-name) ");
63410294Ssam 		gets(&line[strlen(line)]);
63510294Ssam 		makeargv();
63610294Ssam 		argc = margc;
63710294Ssam 		argv = margv;
63810294Ssam 	}
63910294Ssam 	if (argc < 2) {
64010294Ssam usage:
64110294Ssam 		printf("%s from-name to-name\n", argv[0]);
64210294Ssam 		return;
64310294Ssam 	}
64410294Ssam 	if (argc < 3) {
64510294Ssam 		strcat(line, " ");
64610294Ssam 		printf("(to-name) ");
64710294Ssam 		gets(&line[strlen(line)]);
64810294Ssam 		makeargv();
64910294Ssam 		argc = margc;
65010294Ssam 		argv = margv;
65110294Ssam 	}
65210294Ssam 	if (argc < 3)
65310294Ssam 		goto usage;
65410294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
65510294Ssam 		(void) command("RNTO %s", argv[2]);
65610294Ssam }
65710294Ssam 
65810294Ssam /*
65910294Ssam  * Get a directory listing
66010294Ssam  * of remote files.
66110294Ssam  */
66210294Ssam ls(argc, argv)
66310294Ssam 	char *argv[];
66410294Ssam {
665*11650Ssam 	char *cmd, *mode;
666*11650Ssam 	int i;
66710294Ssam 
66810294Ssam 	if (argc < 2)
66910294Ssam 		argc++, argv[1] = NULL;
67010294Ssam 	if (argc < 3)
67110294Ssam 		argc++, argv[2] = "-";
67210294Ssam 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
67311353Ssam 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
67411353Ssam 		return;
675*11650Ssam 	mode = argc > 3 ? "a" : "w";
676*11650Ssam 	for (i = 1; i < argc - 1; i++)
677*11650Ssam 		recvrequest(cmd, argv[argc - 1], argv[i], mode);
67810294Ssam }
67910294Ssam 
68010294Ssam /*
68110294Ssam  * Do a shell escape
68210294Ssam  */
68310294Ssam shell(argc, argv)
68410294Ssam 	char *argv[];
68510294Ssam {
68610294Ssam 
68710294Ssam 	printf("Sorry, this function is unimplemented.\n");
68810294Ssam }
68910294Ssam 
69010294Ssam /*
69110294Ssam  * Send new user information (re-login)
69210294Ssam  */
69310294Ssam user(argc, argv)
69410294Ssam 	int argc;
69510294Ssam 	char **argv;
69610294Ssam {
69710294Ssam 	char acct[80], *getpass();
69810294Ssam 	int n;
69910294Ssam 
70010294Ssam 	if (argc < 2) {
70110294Ssam 		strcat(line, " ");
70210294Ssam 		printf("(username) ");
70310294Ssam 		gets(&line[strlen(line)]);
70410294Ssam 		makeargv();
70510294Ssam 		argc = margc;
70610294Ssam 		argv = margv;
70710294Ssam 	}
70810294Ssam 	if (argc > 4) {
70910294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
71010294Ssam 		return;
71110294Ssam 	}
71210294Ssam 	n = command("USER %s", argv[1]);
71310294Ssam 	if (n == CONTINUE) {
71410294Ssam 		if (argc < 3 )
71510294Ssam 			argv[2] = getpass("Password: "), argc++;
71610294Ssam 		n = command("PASS %s", argv[2]);
71710294Ssam 	}
71810294Ssam 	if (n == CONTINUE) {
71910294Ssam 		if (argc < 4) {
72010294Ssam 			printf("Account: "); (void) fflush(stdout);
72110294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
72210294Ssam 			acct[strlen(acct) - 1] = '\0';
72310294Ssam 			argv[3] = acct; argc++;
72410294Ssam 		}
72510294Ssam 		n = command("ACCT %s", acct);
72610294Ssam 	}
72710294Ssam 	if (n != COMPLETE) {
72810294Ssam 		fprintf(stderr, "Login failed.\n");
72910294Ssam 		return (0);
73010294Ssam 	}
73110294Ssam 	return (1);
73210294Ssam }
73310294Ssam 
73410294Ssam /*
73510294Ssam  * Print working directory.
73610294Ssam  */
73710294Ssam /*VARARGS*/
73810294Ssam pwd()
73910294Ssam {
74010294Ssam 	if (!connected) {
74110294Ssam 		printf("Not connected.\n");
74210294Ssam 		return;
74310294Ssam 	}
74410294Ssam 	(void) command("XPWD");
74510294Ssam }
74610294Ssam 
74710294Ssam /*
74810294Ssam  * Make a directory.
74910294Ssam  */
75010294Ssam makedir(argc, argv)
75110294Ssam 	char *argv[];
75210294Ssam {
75310294Ssam 
75410294Ssam 	if (argc < 2) {
75510294Ssam 		strcat(line, " ");
75610294Ssam 		printf("(directory-name) ");
75710294Ssam 		gets(&line[strlen(line)]);
75810294Ssam 		makeargv();
75910294Ssam 		argc = margc;
76010294Ssam 		argv = margv;
76110294Ssam 	}
76210294Ssam 	if (argc < 2) {
76310294Ssam 		printf("%s directory-name\n", argv[0]);
76410294Ssam 		return;
76510294Ssam 	}
76610294Ssam 	(void) command("XMKD %s", argv[1]);
76710294Ssam }
76810294Ssam 
76910294Ssam /*
77010294Ssam  * Remove a directory.
77110294Ssam  */
77210294Ssam removedir(argc, argv)
77310294Ssam 	char *argv[];
77410294Ssam {
77510294Ssam 
77610294Ssam 	if (argc < 2) {
77710294Ssam 		strcat(line, " ");
77810294Ssam 		printf("(directory-name) ");
77910294Ssam 		gets(&line[strlen(line)]);
78010294Ssam 		makeargv();
78110294Ssam 		argc = margc;
78210294Ssam 		argv = margv;
78310294Ssam 	}
78410294Ssam 	if (argc < 2) {
78510294Ssam 		printf("%s directory-name\n", argv[0]);
78610294Ssam 		return;
78710294Ssam 	}
78810294Ssam 	(void) command("XRMD %s", argv[1]);
78910294Ssam }
79010294Ssam 
79110294Ssam /*
79210294Ssam  * Send a line, verbatim, to the remote machine.
79310294Ssam  */
79410294Ssam quote(argc, argv)
79510294Ssam 	char *argv[];
79610294Ssam {
79710294Ssam 	int i;
79810294Ssam 	char buf[BUFSIZ];
79910294Ssam 
80010294Ssam 	if (argc < 2) {
80110294Ssam 		strcat(line, " ");
80210294Ssam 		printf("(command line to send) ");
80310294Ssam 		gets(&line[strlen(line)]);
80410294Ssam 		makeargv();
80510294Ssam 		argc = margc;
80610294Ssam 		argv = margv;
80710294Ssam 	}
80810294Ssam 	if (argc < 2) {
80910294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
81010294Ssam 		return;
81110294Ssam 	}
81210294Ssam 	strcpy(buf, argv[1]);
81310294Ssam 	for (i = 2; i < argc; i++) {
81410294Ssam 		strcat(buf, " ");
81510294Ssam 		strcat(buf, argv[i]);
81610294Ssam 	}
81710294Ssam 	(void) command(buf);
81810294Ssam }
81910294Ssam 
82010294Ssam /*
82110294Ssam  * Ask the other side for help.
82210294Ssam  */
82310294Ssam rmthelp(argc, argv)
82410294Ssam 	char *argv[];
82510294Ssam {
82610294Ssam 	int oldverbose = verbose;
82710294Ssam 
82810294Ssam 	verbose = 1;
82910294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
83010294Ssam 	verbose = oldverbose;
83110294Ssam }
83210294Ssam 
83310294Ssam /*
83410294Ssam  * Terminate session and exit.
83510294Ssam  */
83610294Ssam /*VARARGS*/
83710294Ssam quit()
83810294Ssam {
83910294Ssam 
84010294Ssam 	disconnect();
84110294Ssam 	exit(0);
84210294Ssam }
84310294Ssam 
84410294Ssam /*
84510294Ssam  * Terminate session, but don't exit.
84610294Ssam  */
84710294Ssam disconnect()
84810294Ssam {
84910294Ssam 	extern FILE *cout;
85010294Ssam 	extern int data;
85110294Ssam 
85210294Ssam 	if (!connected)
85310294Ssam 		return;
85410294Ssam 	(void) command("QUIT");
85510294Ssam 	(void) fclose(cout);
85610294Ssam 	cout = NULL;
85710294Ssam 	connected = 0;
85810294Ssam 	data = -1;
85910294Ssam }
86011353Ssam 
861*11650Ssam confirm(cmd, file)
86211353Ssam 	char *cmd, *file;
86311353Ssam {
86411353Ssam 	char line[BUFSIZ];
86511353Ssam 
86611353Ssam 	if (!interactive)
867*11650Ssam 		return (1);
86811353Ssam 	printf("%s %s? ", cmd, file);
86911353Ssam 	fflush(stdout);
87011353Ssam 	gets(line);
871*11650Ssam 	return (*line != 'n' && *line != 'N');
87211353Ssam }
87311353Ssam 
87411353Ssam fatal(msg)
87511353Ssam 	char *msg;
87611353Ssam {
87711353Ssam 
87811353Ssam 	fprintf(stderr, "ftp: %s\n");
87911353Ssam 	exit(1);
88011353Ssam }
88111353Ssam 
88211353Ssam /*
88311353Ssam  * Glob a local file name specification with
88411353Ssam  * the expectation of a single return value.
88511353Ssam  * Can't control multiple values being expanded
88611353Ssam  * from the expression, we return only the first.
88711353Ssam  */
88811353Ssam globulize(cpp)
88911353Ssam 	char **cpp;
89011353Ssam {
89111353Ssam 	char **globbed;
89211353Ssam 
89311353Ssam 	if (!doglob)
89411353Ssam 		return (1);
89511353Ssam 	globbed = glob(*cpp);
89611353Ssam 	if (globerr != NULL) {
89711353Ssam 		printf("%s: %s\n", *cpp, globerr);
89811353Ssam 		if (globbed)
89911353Ssam 			blkfree(globbed);
90011353Ssam 		return (0);
90111353Ssam 	}
90211353Ssam 	if (globbed) {
90311353Ssam 		*cpp = *globbed++;
90411353Ssam 		/* don't waste too much memory */
90511353Ssam 		if (*globbed)
90611353Ssam 			blkfree(globbed);
90711353Ssam 	}
90811353Ssam 	return (1);
90911353Ssam }
910