xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 11756)
110294Ssam #ifndef lint
2*11756Ssam static char sccsid[] = "@(#)cmds.c	4.5 (Berkeley) 03/29/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();
22*11756Ssam extern	char *home;
2311353Ssam extern	short gflag;
24*11756Ssam extern	char *remglob();
25*11756Ssam extern	char *getenv();
26*11756Ssam extern	char *index();
27*11756Ssam extern	char *rindex();
2810294Ssam 
2910294Ssam /*
3010294Ssam  * Connect to peer server and
3110294Ssam  * auto-login, if possible.
3210294Ssam  */
3310294Ssam setpeer(argc, argv)
3410294Ssam 	int argc;
3510294Ssam 	char *argv[];
3610294Ssam {
3710294Ssam 	struct hostent *host, *hookup();
3810294Ssam 	int port;
3910294Ssam 
4010294Ssam 	if (connected) {
4110294Ssam 		printf("Already connected to %s, use disconnect first.\n",
4210294Ssam 			hostname);
4310294Ssam 		return;
4410294Ssam 	}
4510294Ssam 	if (argc < 2) {
4610294Ssam 		strcat(line, " ");
4710294Ssam 		printf("(to) ");
4810294Ssam 		gets(&line[strlen(line)]);
4910294Ssam 		makeargv();
5010294Ssam 		argc = margc;
5110294Ssam 		argv = margv;
5210294Ssam 	}
5310294Ssam 	if (argc > 3) {
5410294Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
5510294Ssam 		return;
5610294Ssam 	}
5710294Ssam 	port = sp->s_port;
5810294Ssam 	if (argc > 2) {
5911218Ssam 		port = atoi(argv[2]);
6010294Ssam 		if (port <= 0) {
6111218Ssam 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
6211218Ssam 			printf ("usage: %s host-name [port]\n", argv[0]);
6310294Ssam 			return;
6410294Ssam 		}
6510294Ssam 		port = htons(port);
6610294Ssam 	}
6710294Ssam 	host = hookup(argv[1], port);
6810294Ssam 	if (host) {
6910294Ssam 		connected = 1;
7010294Ssam 		if (autologin)
7110294Ssam 			login(host);
7210294Ssam 	}
7310294Ssam }
7410294Ssam 
7510294Ssam struct	types {
7610294Ssam 	char	*t_name;
7710294Ssam 	char	*t_mode;
7810294Ssam 	int	t_type;
7911218Ssam 	char	*t_arg;
8010294Ssam } types[] = {
8111218Ssam 	{ "ascii",	"A",	TYPE_A,	0 },
8211218Ssam 	{ "binary",	"I",	TYPE_I,	0 },
8311218Ssam 	{ "image",	"I",	TYPE_I,	0 },
8411218Ssam 	{ "ebcdic",	"E",	TYPE_E,	0 },
8511218Ssam 	{ "tenex",	"L",	TYPE_L,	bytename },
8610294Ssam 	0
8710294Ssam };
8810294Ssam 
8910294Ssam /*
9010294Ssam  * Set transfer type.
9110294Ssam  */
9210294Ssam settype(argc, argv)
9310294Ssam 	char *argv[];
9410294Ssam {
9510294Ssam 	register struct types *p;
9611218Ssam 	int comret;
9710294Ssam 
9810294Ssam 	if (argc > 2) {
9910294Ssam 		char *sep;
10010294Ssam 
10110294Ssam 		printf("usage: %s [", argv[0]);
10210294Ssam 		sep = " ";
10310294Ssam 		for (p = types; p->t_name; p++) {
10410294Ssam 			printf("%s%s", sep, p->t_name);
10510294Ssam 			if (*sep == ' ')
10610294Ssam 				sep = " | ";
10710294Ssam 		}
10810294Ssam 		printf(" ]\n");
10910294Ssam 		return;
11010294Ssam 	}
11110294Ssam 	if (argc < 2) {
11210294Ssam 		printf("Using %s mode to transfer files.\n", typename);
11310294Ssam 		return;
11410294Ssam 	}
11510294Ssam 	for (p = types; p->t_name; p++)
11610294Ssam 		if (strcmp(argv[1], p->t_name) == 0)
11710294Ssam 			break;
11810294Ssam 	if (p->t_name == 0) {
11910294Ssam 		printf("%s: unknown mode\n", argv[1]);
12010294Ssam 		return;
12110294Ssam 	}
12211218Ssam 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
12311218Ssam 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
12411218Ssam 	else
12511218Ssam 		comret = command("TYPE %s", p->t_mode);
12611218Ssam 	if (comret == COMPLETE) {
12710294Ssam 		strcpy(typename, p->t_name);
12810294Ssam 		type = p->t_type;
12910294Ssam 	}
13010294Ssam }
13110294Ssam 
13210294Ssam /*
13310294Ssam  * Set binary transfer type.
13410294Ssam  */
13510294Ssam /*VARARGS*/
13610294Ssam setbinary()
13710294Ssam {
13810294Ssam 
13910294Ssam 	call(settype, "type", "binary", 0);
14010294Ssam }
14110294Ssam 
14210294Ssam /*
14310294Ssam  * Set ascii transfer type.
14410294Ssam  */
14510294Ssam /*VARARGS*/
14610294Ssam setascii()
14710294Ssam {
14810294Ssam 
14910294Ssam 	call(settype, "type", "ascii", 0);
15010294Ssam }
15110294Ssam 
15210294Ssam /*
15310294Ssam  * Set tenex transfer type.
15410294Ssam  */
15510294Ssam /*VARARGS*/
15610294Ssam settenex()
15710294Ssam {
15810294Ssam 
15910294Ssam 	call(settype, "type", "tenex", 0);
16010294Ssam }
16110294Ssam 
16210294Ssam /*
16310294Ssam  * Set ebcdic transfer type.
16410294Ssam  */
16510294Ssam /*VARARGS*/
16610294Ssam setebcdic()
16710294Ssam {
16810294Ssam 
16910294Ssam 	call(settype, "type", "ebcdic", 0);
17010294Ssam }
17110294Ssam 
17210294Ssam /*
17310294Ssam  * Set file transfer mode.
17410294Ssam  */
17510294Ssam setmode(argc, argv)
17610294Ssam 	char *argv[];
17710294Ssam {
17810294Ssam 
17910294Ssam 	printf("We only support %s mode, sorry.\n", modename);
18010294Ssam }
18110294Ssam 
18210294Ssam /*
18310294Ssam  * Set file transfer format.
18410294Ssam  */
18510294Ssam setform(argc, argv)
18610294Ssam 	char *argv[];
18710294Ssam {
18810294Ssam 
18910294Ssam 	printf("We only support %s format, sorry.\n", formname);
19010294Ssam }
19110294Ssam 
19210294Ssam /*
19310294Ssam  * Set file transfer structure.
19410294Ssam  */
19510294Ssam setstruct(argc, argv)
19610294Ssam 	char *argv[];
19710294Ssam {
19810294Ssam 
19910294Ssam 	printf("We only support %s structure, sorry.\n", structname);
20010294Ssam }
20110294Ssam 
20210294Ssam put(argc, argv)
203*11756Ssam 	int argc;
20410294Ssam 	char *argv[];
20510294Ssam {
20611650Ssam 	char *cmd;
20711650Ssam 
20810294Ssam 	if (argc == 2)
20910294Ssam 		argc++, argv[2] = argv[1];
21010294Ssam 	if (argc < 2) {
21110294Ssam 		strcat(line, " ");
21210294Ssam 		printf("(local-file) ");
21310294Ssam 		gets(&line[strlen(line)]);
21410294Ssam 		makeargv();
21510294Ssam 		argc = margc;
21610294Ssam 		argv = margv;
21710294Ssam 	}
21810294Ssam 	if (argc < 2) {
21910294Ssam usage:
22010294Ssam 		printf("%s local-file remote-file\n", argv[0]);
22110294Ssam 		return;
22210294Ssam 	}
22310294Ssam 	if (argc < 3) {
22410294Ssam 		strcat(line, " ");
22510294Ssam 		printf("(remote-file) ");
22610294Ssam 		gets(&line[strlen(line)]);
22710294Ssam 		makeargv();
22810294Ssam 		argc = margc;
22910294Ssam 		argv = margv;
23010294Ssam 	}
23110294Ssam 	if (argc < 3)
23210294Ssam 		goto usage;
23311353Ssam 	if (!globulize(&argv[1]))
23411353Ssam 		return;
235*11756Ssam 	cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
23611650Ssam 	sendrequest(cmd, argv[1], argv[2]);
23710294Ssam }
23810294Ssam 
23910294Ssam /*
240*11756Ssam  * Send multiple files.
24110294Ssam  */
24211353Ssam mput(argc, argv)
24311353Ssam 	char *argv[];
24411353Ssam {
24511650Ssam 	char **cpp, **gargs = NULL;
24611353Ssam 
24711650Ssam 	if (argc < 2) {
24811650Ssam 		strcat(line, " ");
24911650Ssam 		printf("(local-files) ");
25011650Ssam 		gets(&line[strlen(line)]);
25111650Ssam 		makeargv();
25211650Ssam 		argc = margc;
25311650Ssam 		argv = margv;
25411353Ssam 	}
25511353Ssam 	if (argc < 2) {
25611353Ssam 		printf("%s local-files\n", argv[0]);
25711353Ssam 		return;
25811353Ssam 	}
25911650Ssam 	cpp = argv + 1;
26011650Ssam 	if (doglob) {
26111650Ssam 		gargs = glob(cpp);
26211650Ssam 		if (globerr != NULL) {
26311650Ssam 			printf("%s\n", globerr);
26411650Ssam 			if (gargs)
26511650Ssam 				blkfree(gargs);
26611353Ssam 			return;
26711353Ssam 		}
26811353Ssam 	}
26911650Ssam 	if (gargs != NULL)
27011650Ssam 		cpp = gargs;
27111650Ssam 	for (; *cpp != NULL; cpp++)
27211650Ssam 		if (confirm(argv[0], *cpp))
27311650Ssam 			sendrequest("STOR", *cpp, *cpp);
27411650Ssam 	if (gargs != NULL)
27511650Ssam 		blkfree(gargs);
27611353Ssam }
27711353Ssam 
27811353Ssam /*
27911353Ssam  * Receive one file.
28011353Ssam  */
28110294Ssam get(argc, argv)
28210294Ssam 	char *argv[];
28310294Ssam {
28410294Ssam 
28510294Ssam 	if (argc == 2)
28610294Ssam 		argc++, argv[2] = argv[1];
28710294Ssam 	if (argc < 2) {
28810294Ssam 		strcat(line, " ");
28910294Ssam 		printf("(remote-file) ");
29010294Ssam 		gets(&line[strlen(line)]);
29110294Ssam 		makeargv();
29210294Ssam 		argc = margc;
29310294Ssam 		argv = margv;
29410294Ssam 	}
29510294Ssam 	if (argc < 2) {
29610294Ssam usage:
29711353Ssam 		printf("%s remote-file [ local-file ]\n", argv[0]);
29810294Ssam 		return;
29910294Ssam 	}
30010294Ssam 	if (argc < 3) {
30110294Ssam 		strcat(line, " ");
30210294Ssam 		printf("(local-file) ");
30310294Ssam 		gets(&line[strlen(line)]);
30410294Ssam 		makeargv();
30510294Ssam 		argc = margc;
30610294Ssam 		argv = margv;
30710294Ssam 	}
30810294Ssam 	if (argc < 3)
30910294Ssam 		goto usage;
31011353Ssam 	if (!globulize(&argv[2]))
31111353Ssam 		return;
31211650Ssam 	recvrequest("RETR", argv[2], argv[1], "w");
31310294Ssam }
31410294Ssam 
31511353Ssam /*
31611353Ssam  * Get multiple files.
31711353Ssam  */
31811353Ssam mget(argc, argv)
31911353Ssam 	char *argv[];
32011353Ssam {
321*11756Ssam 	char *cp;
32211353Ssam 
32311353Ssam 	if (argc < 2) {
32411353Ssam 		strcat(line, " ");
325*11756Ssam 		printf("(remote-files) ");
32611353Ssam 		gets(&line[strlen(line)]);
32711353Ssam 		makeargv();
32811353Ssam 		argc = margc;
32911353Ssam 		argv = margv;
33011353Ssam 	}
33111353Ssam 	if (argc < 2) {
33211650Ssam 		printf("%s remote-files\n", argv[0]);
33311353Ssam 		return;
33411353Ssam 	}
33511650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
33611650Ssam 		if (confirm(argv[0], cp))
33711650Ssam 			recvrequest("RETR", cp, cp, "w");
33811650Ssam }
33911650Ssam 
34011650Ssam char *
34111650Ssam remglob(argc, argv)
34211650Ssam 	char *argv[];
34311650Ssam {
344*11756Ssam 	char temp[16];
34511650Ssam 	static char buf[MAXPATHLEN];
34611650Ssam 	static FILE *ftemp = NULL;
34711650Ssam 	static char **args;
34811650Ssam 	int oldverbose;
349*11756Ssam 	char *cp, *mode;
35011650Ssam 
35111650Ssam 	if (!doglob) {
352*11756Ssam 		if (args == NULL)
35311650Ssam 			args = argv;
35411650Ssam 		if ((cp = *++args) == NULL)
35511650Ssam 			args = NULL;
35611650Ssam 		return (cp);
35711353Ssam 	}
35811650Ssam 	if (ftemp == NULL) {
35911650Ssam 		strcpy(temp, "/tmp/ftpXXXXXX");
36011650Ssam 		mktemp(temp);
36111650Ssam 		oldverbose = verbose, verbose = 0;
362*11756Ssam 		for (mode = "w"; *++argv != NULL; mode = "a")
363*11756Ssam 			recvrequest ("NLST", temp, *argv, mode);
36411650Ssam 		verbose = oldverbose;
36511650Ssam 		ftemp = fopen(temp, "r");
36611650Ssam 		unlink(temp);
36711650Ssam 		if (ftemp == NULL) {
36811650Ssam 			printf("can't find list of remote files, oops\n");
369*11756Ssam 			return (NULL);
37011353Ssam 		}
37111353Ssam 	}
37211650Ssam 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
37311650Ssam 		fclose(ftemp), ftemp = NULL;
37411650Ssam 		return (NULL);
37511353Ssam 	}
37611650Ssam 	if ((cp = index(buf, '\n')) != NULL)
37711650Ssam 		*cp = '\0';
37811650Ssam 	return (buf);
37911353Ssam }
38011353Ssam 
38110294Ssam char *
38210294Ssam onoff(bool)
38310294Ssam 	int bool;
38410294Ssam {
38510294Ssam 
38610294Ssam 	return (bool ? "on" : "off");
38710294Ssam }
38810294Ssam 
38910294Ssam /*
39010294Ssam  * Show status.
39110294Ssam  */
39210294Ssam status(argc, argv)
39310294Ssam 	char *argv[];
39410294Ssam {
39510294Ssam 
39610294Ssam 	if (connected)
39710294Ssam 		printf("Connected to %s.\n", hostname);
39810294Ssam 	else
39910294Ssam 		printf("Not connected.\n");
40010294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
40110294Ssam 		modename, typename, formname, structname);
40211353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
40311353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
40411353Ssam 		onoff(doglob));
40511650Ssam 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
40611650Ssam 		onoff(hash), onoff(sendport));
40710294Ssam }
40810294Ssam 
40910294Ssam /*
41010294Ssam  * Set beep on cmd completed mode.
41110294Ssam  */
41210294Ssam /*VARARGS*/
41310294Ssam setbell()
41410294Ssam {
41510294Ssam 
41610294Ssam 	bell = !bell;
41710294Ssam 	printf("Bell mode %s.\n", onoff(bell));
41810294Ssam }
41910294Ssam 
42010294Ssam /*
42110294Ssam  * Turn on packet tracing.
42210294Ssam  */
42310294Ssam /*VARARGS*/
42410294Ssam settrace()
42510294Ssam {
42610294Ssam 
42710294Ssam 	trace = !trace;
42810294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
42910294Ssam }
43010294Ssam 
43110294Ssam /*
43211650Ssam  * Toggle hash mark printing during transfers.
43311650Ssam  */
43411650Ssam /*VARARGS*/
43511650Ssam sethash()
43611650Ssam {
43711650Ssam 
43811650Ssam 	hash = !hash;
43911650Ssam 	printf("Hash mark printing %s", onoff(hash));
44011650Ssam 	if (hash)
44111650Ssam 		printf(" (%d bytes/hash mark)", BUFSIZ);
44211650Ssam 	printf(".\n");
44311650Ssam }
44411650Ssam 
44511650Ssam /*
44610294Ssam  * Turn on printing of server echo's.
44710294Ssam  */
44810294Ssam /*VARARGS*/
44910294Ssam setverbose()
45010294Ssam {
45110294Ssam 
45210294Ssam 	verbose = !verbose;
45310294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
45410294Ssam }
45510294Ssam 
45610294Ssam /*
45711650Ssam  * Toggle PORT cmd use before each data connection.
45811650Ssam  */
45911650Ssam /*VARARGS*/
46011650Ssam setport()
46111650Ssam {
46211650Ssam 
46311650Ssam 	sendport = !sendport;
46411650Ssam 	printf("Use of PORT cmds %s.\n", onoff(sendport));
46511650Ssam }
46611650Ssam 
46711650Ssam /*
46810294Ssam  * Turn on interactive prompting
46910294Ssam  * during mget, mput, and mdelete.
47010294Ssam  */
47110294Ssam /*VARARGS*/
47210294Ssam setprompt()
47310294Ssam {
47410294Ssam 
47510294Ssam 	interactive = !interactive;
47610294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
47710294Ssam }
47810294Ssam 
47910294Ssam /*
48011353Ssam  * Toggle metacharacter interpretation
48111353Ssam  * on local file names.
48211353Ssam  */
48311353Ssam /*VARARGS*/
48411353Ssam setglob()
48511353Ssam {
48611353Ssam 
48711353Ssam 	doglob = !doglob;
48811353Ssam 	printf("Globbing %s.\n", onoff(doglob));
48911353Ssam }
49011353Ssam 
49111353Ssam /*
49210294Ssam  * Set debugging mode on/off and/or
49310294Ssam  * set level of debugging.
49410294Ssam  */
495*11756Ssam /*VARARGS*/
49610294Ssam setdebug(argc, argv)
49710294Ssam 	char *argv[];
49810294Ssam {
49910294Ssam 	int val;
50010294Ssam 
50110294Ssam 	if (argc > 1) {
50210294Ssam 		val = atoi(argv[1]);
50310294Ssam 		if (val < 0) {
50410294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
50510294Ssam 			return;
50610294Ssam 		}
50710294Ssam 	} else
50810294Ssam 		val = !debug;
50910294Ssam 	debug = val;
51010294Ssam 	if (debug)
51110294Ssam 		options |= SO_DEBUG;
51210294Ssam 	else
51310294Ssam 		options &= ~SO_DEBUG;
51410294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
51510294Ssam }
51610294Ssam 
51710294Ssam /*
51810294Ssam  * Set current working directory
51910294Ssam  * on remote machine.
52010294Ssam  */
52110294Ssam cd(argc, argv)
52210294Ssam 	char *argv[];
52310294Ssam {
52410294Ssam 
52510294Ssam 	if (argc < 2) {
52610294Ssam 		strcat(line, " ");
52710294Ssam 		printf("(remote-directory) ");
52810294Ssam 		gets(&line[strlen(line)]);
52910294Ssam 		makeargv();
53010294Ssam 		argc = margc;
53110294Ssam 		argv = margv;
53210294Ssam 	}
53310294Ssam 	if (argc < 2) {
53410294Ssam 		printf("%s remote-directory\n", argv[0]);
53510294Ssam 		return;
53610294Ssam 	}
53710294Ssam 	(void) command("CWD %s", argv[1]);
53810294Ssam }
53910294Ssam 
54010294Ssam /*
54110294Ssam  * Set current working directory
54210294Ssam  * on local machine.
54310294Ssam  */
54410294Ssam lcd(argc, argv)
54510294Ssam 	char *argv[];
54610294Ssam {
54711353Ssam 	char buf[MAXPATHLEN];
54810294Ssam 
54911353Ssam 	if (argc < 2)
55011353Ssam 		argc++, argv[1] = home;
55110294Ssam 	if (argc != 2) {
55210294Ssam 		printf("%s local-directory\n", argv[0]);
55310294Ssam 		return;
55410294Ssam 	}
55511353Ssam 	if (!globulize(&argv[1]))
55611353Ssam 		return;
55711353Ssam 	if (chdir(argv[1]) < 0) {
55810294Ssam 		perror(argv[1]);
55911353Ssam 		return;
56011353Ssam 	}
56111353Ssam 	printf("Local directory now %s\n", getwd(buf));
56210294Ssam }
56310294Ssam 
56410294Ssam /*
56510294Ssam  * Delete a single file.
56610294Ssam  */
56710294Ssam delete(argc, argv)
56810294Ssam 	char *argv[];
56910294Ssam {
57010294Ssam 
57110294Ssam 	if (argc < 2) {
57210294Ssam 		strcat(line, " ");
57310294Ssam 		printf("(remote-file) ");
57410294Ssam 		gets(&line[strlen(line)]);
57510294Ssam 		makeargv();
57610294Ssam 		argc = margc;
57710294Ssam 		argv = margv;
57810294Ssam 	}
57910294Ssam 	if (argc < 2) {
58010294Ssam 		printf("%s remote-file\n", argv[0]);
58110294Ssam 		return;
58210294Ssam 	}
58310294Ssam 	(void) command("DELE %s", argv[1]);
58410294Ssam }
58510294Ssam 
58610294Ssam /*
58711650Ssam  * Delete multiple files.
58811650Ssam  */
58911650Ssam mdelete(argc, argv)
59011650Ssam 	char *argv[];
59111650Ssam {
59211650Ssam 	char *cp;
59311650Ssam 
59411650Ssam 	if (argc < 2) {
59511650Ssam 		strcat(line, " ");
59611650Ssam 		printf("(remote-files) ");
59711650Ssam 		gets(&line[strlen(line)]);
59811650Ssam 		makeargv();
59911650Ssam 		argc = margc;
60011650Ssam 		argv = margv;
60111650Ssam 	}
60211650Ssam 	if (argc < 2) {
60311650Ssam 		printf("%s remote-files\n", argv[0]);
60411650Ssam 		return;
60511650Ssam 	}
60611650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
60711650Ssam 		if (confirm(argv[0], cp))
60811650Ssam 			(void) command("DELE %s", cp);
60911650Ssam }
610*11756Ssam 
61111650Ssam /*
61210294Ssam  * Rename a remote file.
61310294Ssam  */
61410294Ssam renamefile(argc, argv)
61510294Ssam 	char *argv[];
61610294Ssam {
61710294Ssam 
61810294Ssam 	if (argc < 2) {
61910294Ssam 		strcat(line, " ");
62010294Ssam 		printf("(from-name) ");
62110294Ssam 		gets(&line[strlen(line)]);
62210294Ssam 		makeargv();
62310294Ssam 		argc = margc;
62410294Ssam 		argv = margv;
62510294Ssam 	}
62610294Ssam 	if (argc < 2) {
62710294Ssam usage:
62810294Ssam 		printf("%s from-name to-name\n", argv[0]);
62910294Ssam 		return;
63010294Ssam 	}
63110294Ssam 	if (argc < 3) {
63210294Ssam 		strcat(line, " ");
63310294Ssam 		printf("(to-name) ");
63410294Ssam 		gets(&line[strlen(line)]);
63510294Ssam 		makeargv();
63610294Ssam 		argc = margc;
63710294Ssam 		argv = margv;
63810294Ssam 	}
63910294Ssam 	if (argc < 3)
64010294Ssam 		goto usage;
64110294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
64210294Ssam 		(void) command("RNTO %s", argv[2]);
64310294Ssam }
64410294Ssam 
64510294Ssam /*
64610294Ssam  * Get a directory listing
64710294Ssam  * of remote files.
64810294Ssam  */
64910294Ssam ls(argc, argv)
65010294Ssam 	char *argv[];
65110294Ssam {
652*11756Ssam 	char *cmd;
65310294Ssam 
65410294Ssam 	if (argc < 2)
65510294Ssam 		argc++, argv[1] = NULL;
65610294Ssam 	if (argc < 3)
65710294Ssam 		argc++, argv[2] = "-";
658*11756Ssam 	if (argc > 3) {
659*11756Ssam 		printf("usage: %s remote-directory local-file\n", argv[0]);
660*11756Ssam 		return;
661*11756Ssam 	}
66210294Ssam 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
66311353Ssam 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
66411353Ssam 		return;
665*11756Ssam 	recvrequest(cmd, argv[2], argv[1], "w");
66610294Ssam }
66710294Ssam 
66810294Ssam /*
669*11756Ssam  * Get a directory listing
670*11756Ssam  * of multiple remote files.
671*11756Ssam  */
672*11756Ssam mls(argc, argv)
673*11756Ssam 	char *argv[];
674*11756Ssam {
675*11756Ssam 	char *cmd, *mode;
676*11756Ssam 	int i, dest;
677*11756Ssam 
678*11756Ssam 	if (argc < 2)
679*11756Ssam 		argc++, argv[1] = NULL;
680*11756Ssam 	if (argc < 3)
681*11756Ssam 		argc++, argv[2] = "-";
682*11756Ssam 	dest = argc - 1;
683*11756Ssam 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
684*11756Ssam 	if (strcmp(argv[dest], "-") != 0)
685*11756Ssam 		if (globulize(&argv[dest]) && confirm("local-file", argv[dest]))
686*11756Ssam 			return;
687*11756Ssam 	for (i = 1, mode = "w"; i < dest; i++, mode = "a")
688*11756Ssam 		recvrequest(cmd, argv[dest], argv[i], mode);
689*11756Ssam }
690*11756Ssam 
691*11756Ssam /*
69210294Ssam  * Do a shell escape
69310294Ssam  */
69410294Ssam shell(argc, argv)
69510294Ssam 	char *argv[];
69610294Ssam {
697*11756Ssam 	int pid, status, (*old1)(), (*old2)();
698*11756Ssam 	char shellnam[40], *shell, *namep;
699*11756Ssam 	char **cpp, **gargs;
70010294Ssam 
701*11756Ssam 	old1 = signal (SIGINT, SIG_IGN);
702*11756Ssam 	old2 = signal (SIGQUIT, SIG_IGN);
703*11756Ssam 	if ((pid = fork()) == 0) {
704*11756Ssam 		for (pid = 3; pid < 20; pid++)
705*11756Ssam 			close(pid);
706*11756Ssam 		signal(SIGINT, SIG_DFL);
707*11756Ssam 		signal(SIGQUIT, SIG_DFL);
708*11756Ssam 		if (argc <= 1) {
709*11756Ssam 			shell = getenv("SHELL");
710*11756Ssam 			if (shell == NULL)
711*11756Ssam 				shell = "/bin/sh";
712*11756Ssam 			namep = rindex(shell,'/');
713*11756Ssam 			if (namep == NULL)
714*11756Ssam 				namep = shell;
715*11756Ssam 			strcpy(shellnam,"-");
716*11756Ssam 			strcat(shellnam, ++namep);
717*11756Ssam 			if (strcmp(namep, "sh") != 0)
718*11756Ssam 				shellnam[0] = '+';
719*11756Ssam 			if (debug) {
720*11756Ssam 				printf ("%s\n", shell);
721*11756Ssam 				fflush (stdout);
722*11756Ssam 			}
723*11756Ssam 			execl(shell, shellnam, 0);
724*11756Ssam 			perror(shell);
725*11756Ssam 			exit(1);
726*11756Ssam 		}
727*11756Ssam 		cpp = &argv[1];
728*11756Ssam 		if (argc > 2) {
729*11756Ssam 			if ((gargs = glob(cpp)) != NULL)
730*11756Ssam 				cpp = gargs;
731*11756Ssam 			if (globerr != NULL) {
732*11756Ssam 				printf("%s\n", globerr);
733*11756Ssam 				exit(1);
734*11756Ssam 			}
735*11756Ssam 		}
736*11756Ssam 		if (debug) {
737*11756Ssam 			register char **zip = cpp;
738*11756Ssam 
739*11756Ssam 			printf("%s", *zip);
740*11756Ssam 			while (*++zip != NULL)
741*11756Ssam 				printf(" %s", *zip);
742*11756Ssam 			printf("\n");
743*11756Ssam 			fflush(stdout);
744*11756Ssam 		}
745*11756Ssam 		execvp(argv[1], cpp);
746*11756Ssam 		perror(argv[1]);
747*11756Ssam 		exit(1);
748*11756Ssam 	}
749*11756Ssam 	if (pid > 0)
750*11756Ssam 		while (wait(&status) != pid)
751*11756Ssam 			;
752*11756Ssam 	signal(SIGINT, old1);
753*11756Ssam 	signal(SIGQUIT, old2);
754*11756Ssam 	if (pid == -1)
755*11756Ssam 		perror("Try again later");
756*11756Ssam 	return (0);
75710294Ssam }
75810294Ssam 
75910294Ssam /*
76010294Ssam  * Send new user information (re-login)
76110294Ssam  */
76210294Ssam user(argc, argv)
76310294Ssam 	int argc;
76410294Ssam 	char **argv;
76510294Ssam {
76610294Ssam 	char acct[80], *getpass();
76710294Ssam 	int n;
76810294Ssam 
76910294Ssam 	if (argc < 2) {
77010294Ssam 		strcat(line, " ");
77110294Ssam 		printf("(username) ");
77210294Ssam 		gets(&line[strlen(line)]);
77310294Ssam 		makeargv();
77410294Ssam 		argc = margc;
77510294Ssam 		argv = margv;
77610294Ssam 	}
77710294Ssam 	if (argc > 4) {
77810294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
779*11756Ssam 		return (0);
78010294Ssam 	}
78110294Ssam 	n = command("USER %s", argv[1]);
78210294Ssam 	if (n == CONTINUE) {
78310294Ssam 		if (argc < 3 )
78410294Ssam 			argv[2] = getpass("Password: "), argc++;
78510294Ssam 		n = command("PASS %s", argv[2]);
78610294Ssam 	}
78710294Ssam 	if (n == CONTINUE) {
78810294Ssam 		if (argc < 4) {
78910294Ssam 			printf("Account: "); (void) fflush(stdout);
79010294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
79110294Ssam 			acct[strlen(acct) - 1] = '\0';
79210294Ssam 			argv[3] = acct; argc++;
79310294Ssam 		}
79410294Ssam 		n = command("ACCT %s", acct);
79510294Ssam 	}
79610294Ssam 	if (n != COMPLETE) {
79710294Ssam 		fprintf(stderr, "Login failed.\n");
79810294Ssam 		return (0);
79910294Ssam 	}
80010294Ssam 	return (1);
80110294Ssam }
80210294Ssam 
80310294Ssam /*
80410294Ssam  * Print working directory.
80510294Ssam  */
80610294Ssam /*VARARGS*/
80710294Ssam pwd()
80810294Ssam {
809*11756Ssam 
81010294Ssam 	(void) command("XPWD");
81110294Ssam }
81210294Ssam 
81310294Ssam /*
81410294Ssam  * Make a directory.
81510294Ssam  */
81610294Ssam makedir(argc, argv)
81710294Ssam 	char *argv[];
81810294Ssam {
81910294Ssam 
82010294Ssam 	if (argc < 2) {
82110294Ssam 		strcat(line, " ");
82210294Ssam 		printf("(directory-name) ");
82310294Ssam 		gets(&line[strlen(line)]);
82410294Ssam 		makeargv();
82510294Ssam 		argc = margc;
82610294Ssam 		argv = margv;
82710294Ssam 	}
82810294Ssam 	if (argc < 2) {
82910294Ssam 		printf("%s directory-name\n", argv[0]);
83010294Ssam 		return;
83110294Ssam 	}
83210294Ssam 	(void) command("XMKD %s", argv[1]);
83310294Ssam }
83410294Ssam 
83510294Ssam /*
83610294Ssam  * Remove a directory.
83710294Ssam  */
83810294Ssam removedir(argc, argv)
83910294Ssam 	char *argv[];
84010294Ssam {
84110294Ssam 
84210294Ssam 	if (argc < 2) {
84310294Ssam 		strcat(line, " ");
84410294Ssam 		printf("(directory-name) ");
84510294Ssam 		gets(&line[strlen(line)]);
84610294Ssam 		makeargv();
84710294Ssam 		argc = margc;
84810294Ssam 		argv = margv;
84910294Ssam 	}
85010294Ssam 	if (argc < 2) {
85110294Ssam 		printf("%s directory-name\n", argv[0]);
85210294Ssam 		return;
85310294Ssam 	}
85410294Ssam 	(void) command("XRMD %s", argv[1]);
85510294Ssam }
85610294Ssam 
85710294Ssam /*
85810294Ssam  * Send a line, verbatim, to the remote machine.
85910294Ssam  */
86010294Ssam quote(argc, argv)
86110294Ssam 	char *argv[];
86210294Ssam {
86310294Ssam 	int i;
86410294Ssam 	char buf[BUFSIZ];
86510294Ssam 
86610294Ssam 	if (argc < 2) {
86710294Ssam 		strcat(line, " ");
86810294Ssam 		printf("(command line to send) ");
86910294Ssam 		gets(&line[strlen(line)]);
87010294Ssam 		makeargv();
87110294Ssam 		argc = margc;
87210294Ssam 		argv = margv;
87310294Ssam 	}
87410294Ssam 	if (argc < 2) {
87510294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
87610294Ssam 		return;
87710294Ssam 	}
87810294Ssam 	strcpy(buf, argv[1]);
87910294Ssam 	for (i = 2; i < argc; i++) {
88010294Ssam 		strcat(buf, " ");
88110294Ssam 		strcat(buf, argv[i]);
88210294Ssam 	}
88310294Ssam 	(void) command(buf);
88410294Ssam }
88510294Ssam 
88610294Ssam /*
88710294Ssam  * Ask the other side for help.
88810294Ssam  */
88910294Ssam rmthelp(argc, argv)
89010294Ssam 	char *argv[];
89110294Ssam {
89210294Ssam 	int oldverbose = verbose;
89310294Ssam 
89410294Ssam 	verbose = 1;
89510294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
89610294Ssam 	verbose = oldverbose;
89710294Ssam }
89810294Ssam 
89910294Ssam /*
90010294Ssam  * Terminate session and exit.
90110294Ssam  */
90210294Ssam /*VARARGS*/
90310294Ssam quit()
90410294Ssam {
90510294Ssam 
90610294Ssam 	disconnect();
90710294Ssam 	exit(0);
90810294Ssam }
90910294Ssam 
91010294Ssam /*
91110294Ssam  * Terminate session, but don't exit.
91210294Ssam  */
91310294Ssam disconnect()
91410294Ssam {
91510294Ssam 	extern FILE *cout;
91610294Ssam 	extern int data;
91710294Ssam 
91810294Ssam 	if (!connected)
91910294Ssam 		return;
92010294Ssam 	(void) command("QUIT");
92110294Ssam 	(void) fclose(cout);
92210294Ssam 	cout = NULL;
92310294Ssam 	connected = 0;
92410294Ssam 	data = -1;
92510294Ssam }
92611353Ssam 
92711650Ssam confirm(cmd, file)
92811353Ssam 	char *cmd, *file;
92911353Ssam {
93011353Ssam 	char line[BUFSIZ];
93111353Ssam 
93211353Ssam 	if (!interactive)
93311650Ssam 		return (1);
93411353Ssam 	printf("%s %s? ", cmd, file);
93511353Ssam 	fflush(stdout);
93611353Ssam 	gets(line);
93711650Ssam 	return (*line != 'n' && *line != 'N');
93811353Ssam }
93911353Ssam 
94011353Ssam fatal(msg)
94111353Ssam 	char *msg;
94211353Ssam {
94311353Ssam 
94411353Ssam 	fprintf(stderr, "ftp: %s\n");
94511353Ssam 	exit(1);
94611353Ssam }
94711353Ssam 
94811353Ssam /*
94911353Ssam  * Glob a local file name specification with
95011353Ssam  * the expectation of a single return value.
95111353Ssam  * Can't control multiple values being expanded
95211353Ssam  * from the expression, we return only the first.
95311353Ssam  */
95411353Ssam globulize(cpp)
95511353Ssam 	char **cpp;
95611353Ssam {
95711353Ssam 	char **globbed;
95811353Ssam 
95911353Ssam 	if (!doglob)
96011353Ssam 		return (1);
96111353Ssam 	globbed = glob(*cpp);
96211353Ssam 	if (globerr != NULL) {
96311353Ssam 		printf("%s: %s\n", *cpp, globerr);
96411353Ssam 		if (globbed)
96511353Ssam 			blkfree(globbed);
96611353Ssam 		return (0);
96711353Ssam 	}
96811353Ssam 	if (globbed) {
96911353Ssam 		*cpp = *globbed++;
97011353Ssam 		/* don't waste too much memory */
97111353Ssam 		if (*globbed)
97211353Ssam 			blkfree(globbed);
97311353Ssam 	}
97411353Ssam 	return (1);
97511353Ssam }
976