xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 25908)
121737Sdist /*
221737Sdist  * Copyright (c) 1983 Regents of the University of California.
321737Sdist  * All rights reserved.  The Berkeley software License Agreement
421737Sdist  * specifies the terms and conditions for redistribution.
521737Sdist  */
621737Sdist 
710294Ssam #ifndef lint
8*25908Smckusick static char sccsid[] = "@(#)cmds.c	5.3 (Berkeley) 01/13/86";
921737Sdist #endif not lint
1010294Ssam 
1110294Ssam /*
1210294Ssam  * FTP User Program -- Command Routines.
1310294Ssam  */
1411353Ssam #include <sys/param.h>
1510294Ssam #include <sys/socket.h>
1610294Ssam 
1712396Ssam #include <arpa/ftp.h>
1812396Ssam 
1910294Ssam #include <signal.h>
2010294Ssam #include <stdio.h>
2110294Ssam #include <errno.h>
2210294Ssam #include <netdb.h>
2310294Ssam 
2410294Ssam #include "ftp_var.h"
2510294Ssam 
2611353Ssam extern	char *globerr;
2711353Ssam extern	char **glob();
2811756Ssam extern	char *home;
2911353Ssam extern	short gflag;
3011756Ssam extern	char *remglob();
3111756Ssam extern	char *getenv();
3211756Ssam extern	char *index();
3311756Ssam extern	char *rindex();
3410294Ssam 
3510294Ssam /*
3610294Ssam  * Connect to peer server and
3710294Ssam  * auto-login, if possible.
3810294Ssam  */
3910294Ssam setpeer(argc, argv)
4010294Ssam 	int argc;
4110294Ssam 	char *argv[];
4210294Ssam {
4325903Skarels 	char *host, *hookup();
4410294Ssam 	int port;
4510294Ssam 
4610294Ssam 	if (connected) {
4710294Ssam 		printf("Already connected to %s, use disconnect first.\n",
4810294Ssam 			hostname);
4910294Ssam 		return;
5010294Ssam 	}
5110294Ssam 	if (argc < 2) {
5210294Ssam 		strcat(line, " ");
5310294Ssam 		printf("(to) ");
5410294Ssam 		gets(&line[strlen(line)]);
5510294Ssam 		makeargv();
5610294Ssam 		argc = margc;
5710294Ssam 		argv = margv;
5810294Ssam 	}
5910294Ssam 	if (argc > 3) {
6010294Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
6110294Ssam 		return;
6210294Ssam 	}
6310294Ssam 	port = sp->s_port;
6410294Ssam 	if (argc > 2) {
6511218Ssam 		port = atoi(argv[2]);
6610294Ssam 		if (port <= 0) {
6711218Ssam 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
6811218Ssam 			printf ("usage: %s host-name [port]\n", argv[0]);
6910294Ssam 			return;
7010294Ssam 		}
7110294Ssam 		port = htons(port);
7210294Ssam 	}
7310294Ssam 	host = hookup(argv[1], port);
7410294Ssam 	if (host) {
7510294Ssam 		connected = 1;
7610294Ssam 		if (autologin)
7710294Ssam 			login(host);
7810294Ssam 	}
7910294Ssam }
8010294Ssam 
8110294Ssam struct	types {
8210294Ssam 	char	*t_name;
8310294Ssam 	char	*t_mode;
8410294Ssam 	int	t_type;
8511218Ssam 	char	*t_arg;
8610294Ssam } types[] = {
8711218Ssam 	{ "ascii",	"A",	TYPE_A,	0 },
8811218Ssam 	{ "binary",	"I",	TYPE_I,	0 },
8911218Ssam 	{ "image",	"I",	TYPE_I,	0 },
9011218Ssam 	{ "ebcdic",	"E",	TYPE_E,	0 },
9111218Ssam 	{ "tenex",	"L",	TYPE_L,	bytename },
9210294Ssam 	0
9310294Ssam };
9410294Ssam 
9510294Ssam /*
9610294Ssam  * Set transfer type.
9710294Ssam  */
9810294Ssam settype(argc, argv)
9910294Ssam 	char *argv[];
10010294Ssam {
10110294Ssam 	register struct types *p;
10211218Ssam 	int comret;
10310294Ssam 
10410294Ssam 	if (argc > 2) {
10510294Ssam 		char *sep;
10610294Ssam 
10710294Ssam 		printf("usage: %s [", argv[0]);
10810294Ssam 		sep = " ";
10910294Ssam 		for (p = types; p->t_name; p++) {
11010294Ssam 			printf("%s%s", sep, p->t_name);
11110294Ssam 			if (*sep == ' ')
11210294Ssam 				sep = " | ";
11310294Ssam 		}
11410294Ssam 		printf(" ]\n");
11510294Ssam 		return;
11610294Ssam 	}
11710294Ssam 	if (argc < 2) {
11810294Ssam 		printf("Using %s mode to transfer files.\n", typename);
11910294Ssam 		return;
12010294Ssam 	}
12110294Ssam 	for (p = types; p->t_name; p++)
12210294Ssam 		if (strcmp(argv[1], p->t_name) == 0)
12310294Ssam 			break;
12410294Ssam 	if (p->t_name == 0) {
12510294Ssam 		printf("%s: unknown mode\n", argv[1]);
12610294Ssam 		return;
12710294Ssam 	}
12811218Ssam 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
12911218Ssam 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
13011218Ssam 	else
13111218Ssam 		comret = command("TYPE %s", p->t_mode);
13211218Ssam 	if (comret == COMPLETE) {
13310294Ssam 		strcpy(typename, p->t_name);
13410294Ssam 		type = p->t_type;
13510294Ssam 	}
13610294Ssam }
13710294Ssam 
13810294Ssam /*
13910294Ssam  * Set binary transfer type.
14010294Ssam  */
14110294Ssam /*VARARGS*/
14210294Ssam setbinary()
14310294Ssam {
14410294Ssam 
14510294Ssam 	call(settype, "type", "binary", 0);
14610294Ssam }
14710294Ssam 
14810294Ssam /*
14910294Ssam  * Set ascii transfer type.
15010294Ssam  */
15110294Ssam /*VARARGS*/
15210294Ssam setascii()
15310294Ssam {
15410294Ssam 
15510294Ssam 	call(settype, "type", "ascii", 0);
15610294Ssam }
15710294Ssam 
15810294Ssam /*
15910294Ssam  * Set tenex transfer type.
16010294Ssam  */
16110294Ssam /*VARARGS*/
16210294Ssam settenex()
16310294Ssam {
16410294Ssam 
16510294Ssam 	call(settype, "type", "tenex", 0);
16610294Ssam }
16710294Ssam 
16810294Ssam /*
16910294Ssam  * Set ebcdic transfer type.
17010294Ssam  */
17110294Ssam /*VARARGS*/
17210294Ssam setebcdic()
17310294Ssam {
17410294Ssam 
17510294Ssam 	call(settype, "type", "ebcdic", 0);
17610294Ssam }
17710294Ssam 
17810294Ssam /*
17910294Ssam  * Set file transfer mode.
18010294Ssam  */
18110294Ssam setmode(argc, argv)
18210294Ssam 	char *argv[];
18310294Ssam {
18410294Ssam 
18510294Ssam 	printf("We only support %s mode, sorry.\n", modename);
18610294Ssam }
18710294Ssam 
18810294Ssam /*
18910294Ssam  * Set file transfer format.
19010294Ssam  */
19110294Ssam setform(argc, argv)
19210294Ssam 	char *argv[];
19310294Ssam {
19410294Ssam 
19510294Ssam 	printf("We only support %s format, sorry.\n", formname);
19610294Ssam }
19710294Ssam 
19810294Ssam /*
19910294Ssam  * Set file transfer structure.
20010294Ssam  */
20110294Ssam setstruct(argc, argv)
20210294Ssam 	char *argv[];
20310294Ssam {
20410294Ssam 
20510294Ssam 	printf("We only support %s structure, sorry.\n", structname);
20610294Ssam }
20710294Ssam 
20818286Sralph /*
20918286Sralph  * Send a single file.
21018286Sralph  */
21110294Ssam put(argc, argv)
21211756Ssam 	int argc;
21310294Ssam 	char *argv[];
21410294Ssam {
21511650Ssam 	char *cmd;
216*25908Smckusick 	char *oldargv1;
21711650Ssam 
21810294Ssam 	if (argc == 2)
21910294Ssam 		argc++, argv[2] = argv[1];
22010294Ssam 	if (argc < 2) {
22110294Ssam 		strcat(line, " ");
22210294Ssam 		printf("(local-file) ");
22310294Ssam 		gets(&line[strlen(line)]);
22410294Ssam 		makeargv();
22510294Ssam 		argc = margc;
22610294Ssam 		argv = margv;
22710294Ssam 	}
22810294Ssam 	if (argc < 2) {
22910294Ssam usage:
23010294Ssam 		printf("%s local-file remote-file\n", argv[0]);
23110294Ssam 		return;
23210294Ssam 	}
23310294Ssam 	if (argc < 3) {
23410294Ssam 		strcat(line, " ");
23510294Ssam 		printf("(remote-file) ");
23610294Ssam 		gets(&line[strlen(line)]);
23710294Ssam 		makeargv();
23810294Ssam 		argc = margc;
23910294Ssam 		argv = margv;
24010294Ssam 	}
24110294Ssam 	if (argc < 3)
24210294Ssam 		goto usage;
243*25908Smckusick 	oldargv1 = argv[1];
24411353Ssam 	if (!globulize(&argv[1]))
24511353Ssam 		return;
246*25908Smckusick 	/*
247*25908Smckusick 	 * If "globulize" modifies argv[1], and argv[2] is a copy of
248*25908Smckusick 	 * the old argv[1], make it a copy of the new argv[1].
249*25908Smckusick 	 */
250*25908Smckusick 	if (argv[1] != oldargv1 && argv[2] == oldargv1)
251*25908Smckusick 		argv[2] = argv[1];
25211756Ssam 	cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
25311650Ssam 	sendrequest(cmd, argv[1], argv[2]);
25410294Ssam }
25510294Ssam 
25610294Ssam /*
25711756Ssam  * Send multiple files.
25810294Ssam  */
25911353Ssam mput(argc, argv)
26011353Ssam 	char *argv[];
26111353Ssam {
26213212Ssam 	register int i;
26311353Ssam 
26411650Ssam 	if (argc < 2) {
26511650Ssam 		strcat(line, " ");
26611650Ssam 		printf("(local-files) ");
26711650Ssam 		gets(&line[strlen(line)]);
26811650Ssam 		makeargv();
26911650Ssam 		argc = margc;
27011650Ssam 		argv = margv;
27111353Ssam 	}
27211353Ssam 	if (argc < 2) {
27311353Ssam 		printf("%s local-files\n", argv[0]);
27411353Ssam 		return;
27511353Ssam 	}
27613212Ssam 	for (i = 1; i < argc; i++) {
27713212Ssam 		register char **cpp, **gargs;
27813212Ssam 
27913212Ssam 		if (!doglob) {
28013212Ssam 			if (confirm(argv[0], argv[i]))
28113212Ssam 				sendrequest("STOR", argv[i], argv[i]);
28213212Ssam 			continue;
28313212Ssam 		}
28413212Ssam 		gargs = glob(argv[i]);
28511650Ssam 		if (globerr != NULL) {
28611650Ssam 			printf("%s\n", globerr);
28711650Ssam 			if (gargs)
28811650Ssam 				blkfree(gargs);
28913212Ssam 			continue;
29011353Ssam 		}
29113212Ssam 		for (cpp = gargs; cpp && *cpp != NULL; cpp++)
29213212Ssam 			if (confirm(argv[0], *cpp))
29313212Ssam 				sendrequest("STOR", *cpp, *cpp);
29413212Ssam 		if (gargs != NULL)
29513212Ssam 			blkfree(gargs);
29611353Ssam 	}
29711353Ssam }
29811353Ssam 
29911353Ssam /*
30011353Ssam  * Receive one file.
30111353Ssam  */
30210294Ssam get(argc, argv)
30310294Ssam 	char *argv[];
30410294Ssam {
30510294Ssam 
30610294Ssam 	if (argc == 2)
30710294Ssam 		argc++, argv[2] = argv[1];
30810294Ssam 	if (argc < 2) {
30910294Ssam 		strcat(line, " ");
31010294Ssam 		printf("(remote-file) ");
31110294Ssam 		gets(&line[strlen(line)]);
31210294Ssam 		makeargv();
31310294Ssam 		argc = margc;
31410294Ssam 		argv = margv;
31510294Ssam 	}
31610294Ssam 	if (argc < 2) {
31710294Ssam usage:
31811353Ssam 		printf("%s remote-file [ local-file ]\n", argv[0]);
31910294Ssam 		return;
32010294Ssam 	}
32110294Ssam 	if (argc < 3) {
32210294Ssam 		strcat(line, " ");
32310294Ssam 		printf("(local-file) ");
32410294Ssam 		gets(&line[strlen(line)]);
32510294Ssam 		makeargv();
32610294Ssam 		argc = margc;
32710294Ssam 		argv = margv;
32810294Ssam 	}
32910294Ssam 	if (argc < 3)
33010294Ssam 		goto usage;
33111353Ssam 	if (!globulize(&argv[2]))
33211353Ssam 		return;
33311650Ssam 	recvrequest("RETR", argv[2], argv[1], "w");
33410294Ssam }
33510294Ssam 
33611353Ssam /*
33711353Ssam  * Get multiple files.
33811353Ssam  */
33911353Ssam mget(argc, argv)
34011353Ssam 	char *argv[];
34111353Ssam {
34211756Ssam 	char *cp;
34311353Ssam 
34411353Ssam 	if (argc < 2) {
34511353Ssam 		strcat(line, " ");
34611756Ssam 		printf("(remote-files) ");
34711353Ssam 		gets(&line[strlen(line)]);
34811353Ssam 		makeargv();
34911353Ssam 		argc = margc;
35011353Ssam 		argv = margv;
35111353Ssam 	}
35211353Ssam 	if (argc < 2) {
35311650Ssam 		printf("%s remote-files\n", argv[0]);
35411353Ssam 		return;
35511353Ssam 	}
35611650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
35711650Ssam 		if (confirm(argv[0], cp))
35811650Ssam 			recvrequest("RETR", cp, cp, "w");
35911650Ssam }
36011650Ssam 
36111650Ssam char *
36211650Ssam remglob(argc, argv)
36311650Ssam 	char *argv[];
36411650Ssam {
36511756Ssam 	char temp[16];
36611650Ssam 	static char buf[MAXPATHLEN];
36711650Ssam 	static FILE *ftemp = NULL;
36811650Ssam 	static char **args;
36913212Ssam 	int oldverbose, oldhash;
37011756Ssam 	char *cp, *mode;
37111650Ssam 
37211650Ssam 	if (!doglob) {
37311756Ssam 		if (args == NULL)
37411650Ssam 			args = argv;
37511650Ssam 		if ((cp = *++args) == NULL)
37611650Ssam 			args = NULL;
37711650Ssam 		return (cp);
37811353Ssam 	}
37911650Ssam 	if (ftemp == NULL) {
38011650Ssam 		strcpy(temp, "/tmp/ftpXXXXXX");
38111650Ssam 		mktemp(temp);
38211650Ssam 		oldverbose = verbose, verbose = 0;
38313212Ssam 		oldhash = hash, hash = 0;
38411756Ssam 		for (mode = "w"; *++argv != NULL; mode = "a")
38511756Ssam 			recvrequest ("NLST", temp, *argv, mode);
38613212Ssam 		verbose = oldverbose; hash = oldhash;
38711650Ssam 		ftemp = fopen(temp, "r");
38811650Ssam 		unlink(temp);
38911650Ssam 		if (ftemp == NULL) {
39011650Ssam 			printf("can't find list of remote files, oops\n");
39111756Ssam 			return (NULL);
39211353Ssam 		}
39311353Ssam 	}
39411650Ssam 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
39511650Ssam 		fclose(ftemp), ftemp = NULL;
39611650Ssam 		return (NULL);
39711353Ssam 	}
39811650Ssam 	if ((cp = index(buf, '\n')) != NULL)
39911650Ssam 		*cp = '\0';
40011650Ssam 	return (buf);
40111353Ssam }
40211353Ssam 
40310294Ssam char *
40410294Ssam onoff(bool)
40510294Ssam 	int bool;
40610294Ssam {
40710294Ssam 
40810294Ssam 	return (bool ? "on" : "off");
40910294Ssam }
41010294Ssam 
41110294Ssam /*
41210294Ssam  * Show status.
41310294Ssam  */
41410294Ssam status(argc, argv)
41510294Ssam 	char *argv[];
41610294Ssam {
41710294Ssam 
41810294Ssam 	if (connected)
41910294Ssam 		printf("Connected to %s.\n", hostname);
42010294Ssam 	else
42110294Ssam 		printf("Not connected.\n");
42210294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
42310294Ssam 		modename, typename, formname, structname);
42411353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
42511353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
42611353Ssam 		onoff(doglob));
42714143Ssam 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
42814143Ssam 		onoff(hash), onoff(sendport));
42910294Ssam }
43010294Ssam 
43110294Ssam /*
43210294Ssam  * Set beep on cmd completed mode.
43310294Ssam  */
43410294Ssam /*VARARGS*/
43510294Ssam setbell()
43610294Ssam {
43710294Ssam 
43810294Ssam 	bell = !bell;
43910294Ssam 	printf("Bell mode %s.\n", onoff(bell));
44010294Ssam }
44110294Ssam 
44210294Ssam /*
44310294Ssam  * Turn on packet tracing.
44410294Ssam  */
44510294Ssam /*VARARGS*/
44610294Ssam settrace()
44710294Ssam {
44810294Ssam 
44910294Ssam 	trace = !trace;
45010294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
45110294Ssam }
45210294Ssam 
45310294Ssam /*
45411650Ssam  * Toggle hash mark printing during transfers.
45511650Ssam  */
45611650Ssam /*VARARGS*/
45711650Ssam sethash()
45811650Ssam {
45911650Ssam 
46011650Ssam 	hash = !hash;
46111650Ssam 	printf("Hash mark printing %s", onoff(hash));
46211650Ssam 	if (hash)
46311650Ssam 		printf(" (%d bytes/hash mark)", BUFSIZ);
46411650Ssam 	printf(".\n");
46511650Ssam }
46611650Ssam 
46711650Ssam /*
46810294Ssam  * Turn on printing of server echo's.
46910294Ssam  */
47010294Ssam /*VARARGS*/
47110294Ssam setverbose()
47210294Ssam {
47310294Ssam 
47410294Ssam 	verbose = !verbose;
47510294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
47610294Ssam }
47710294Ssam 
47810294Ssam /*
47911650Ssam  * Toggle PORT cmd use before each data connection.
48011650Ssam  */
48111650Ssam /*VARARGS*/
48211650Ssam setport()
48311650Ssam {
48411650Ssam 
48511650Ssam 	sendport = !sendport;
48611650Ssam 	printf("Use of PORT cmds %s.\n", onoff(sendport));
48711650Ssam }
48811650Ssam 
48911650Ssam /*
49010294Ssam  * Turn on interactive prompting
49110294Ssam  * during mget, mput, and mdelete.
49210294Ssam  */
49310294Ssam /*VARARGS*/
49410294Ssam setprompt()
49510294Ssam {
49610294Ssam 
49710294Ssam 	interactive = !interactive;
49810294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
49910294Ssam }
50010294Ssam 
50110294Ssam /*
50211353Ssam  * Toggle metacharacter interpretation
50311353Ssam  * on local file names.
50411353Ssam  */
50511353Ssam /*VARARGS*/
50611353Ssam setglob()
50711353Ssam {
50811353Ssam 
50911353Ssam 	doglob = !doglob;
51011353Ssam 	printf("Globbing %s.\n", onoff(doglob));
51111353Ssam }
51211353Ssam 
51311353Ssam /*
51410294Ssam  * Set debugging mode on/off and/or
51510294Ssam  * set level of debugging.
51610294Ssam  */
51711756Ssam /*VARARGS*/
51810294Ssam setdebug(argc, argv)
51910294Ssam 	char *argv[];
52010294Ssam {
52110294Ssam 	int val;
52210294Ssam 
52310294Ssam 	if (argc > 1) {
52410294Ssam 		val = atoi(argv[1]);
52510294Ssam 		if (val < 0) {
52610294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
52710294Ssam 			return;
52810294Ssam 		}
52910294Ssam 	} else
53010294Ssam 		val = !debug;
53110294Ssam 	debug = val;
53210294Ssam 	if (debug)
53310294Ssam 		options |= SO_DEBUG;
53410294Ssam 	else
53510294Ssam 		options &= ~SO_DEBUG;
53610294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
53710294Ssam }
53810294Ssam 
53910294Ssam /*
54010294Ssam  * Set current working directory
54110294Ssam  * on remote machine.
54210294Ssam  */
54310294Ssam cd(argc, argv)
54410294Ssam 	char *argv[];
54510294Ssam {
54610294Ssam 
54710294Ssam 	if (argc < 2) {
54810294Ssam 		strcat(line, " ");
54910294Ssam 		printf("(remote-directory) ");
55010294Ssam 		gets(&line[strlen(line)]);
55110294Ssam 		makeargv();
55210294Ssam 		argc = margc;
55310294Ssam 		argv = margv;
55410294Ssam 	}
55510294Ssam 	if (argc < 2) {
55610294Ssam 		printf("%s remote-directory\n", argv[0]);
55710294Ssam 		return;
55810294Ssam 	}
55910294Ssam 	(void) command("CWD %s", argv[1]);
56010294Ssam }
56110294Ssam 
56210294Ssam /*
56310294Ssam  * Set current working directory
56410294Ssam  * on local machine.
56510294Ssam  */
56610294Ssam lcd(argc, argv)
56710294Ssam 	char *argv[];
56810294Ssam {
56911353Ssam 	char buf[MAXPATHLEN];
57010294Ssam 
57111353Ssam 	if (argc < 2)
57211353Ssam 		argc++, argv[1] = home;
57310294Ssam 	if (argc != 2) {
57410294Ssam 		printf("%s local-directory\n", argv[0]);
57510294Ssam 		return;
57610294Ssam 	}
57711353Ssam 	if (!globulize(&argv[1]))
57811353Ssam 		return;
57911353Ssam 	if (chdir(argv[1]) < 0) {
58010294Ssam 		perror(argv[1]);
58111353Ssam 		return;
58211353Ssam 	}
58311353Ssam 	printf("Local directory now %s\n", getwd(buf));
58410294Ssam }
58510294Ssam 
58610294Ssam /*
58710294Ssam  * Delete a single file.
58810294Ssam  */
58910294Ssam delete(argc, argv)
59010294Ssam 	char *argv[];
59110294Ssam {
59210294Ssam 
59310294Ssam 	if (argc < 2) {
59410294Ssam 		strcat(line, " ");
59510294Ssam 		printf("(remote-file) ");
59610294Ssam 		gets(&line[strlen(line)]);
59710294Ssam 		makeargv();
59810294Ssam 		argc = margc;
59910294Ssam 		argv = margv;
60010294Ssam 	}
60110294Ssam 	if (argc < 2) {
60210294Ssam 		printf("%s remote-file\n", argv[0]);
60310294Ssam 		return;
60410294Ssam 	}
60510294Ssam 	(void) command("DELE %s", argv[1]);
60610294Ssam }
60710294Ssam 
60810294Ssam /*
60911650Ssam  * Delete multiple files.
61011650Ssam  */
61111650Ssam mdelete(argc, argv)
61211650Ssam 	char *argv[];
61311650Ssam {
61411650Ssam 	char *cp;
61511650Ssam 
61611650Ssam 	if (argc < 2) {
61711650Ssam 		strcat(line, " ");
61811650Ssam 		printf("(remote-files) ");
61911650Ssam 		gets(&line[strlen(line)]);
62011650Ssam 		makeargv();
62111650Ssam 		argc = margc;
62211650Ssam 		argv = margv;
62311650Ssam 	}
62411650Ssam 	if (argc < 2) {
62511650Ssam 		printf("%s remote-files\n", argv[0]);
62611650Ssam 		return;
62711650Ssam 	}
62811650Ssam 	while ((cp = remglob(argc, argv)) != NULL)
62911650Ssam 		if (confirm(argv[0], cp))
63011650Ssam 			(void) command("DELE %s", cp);
63111650Ssam }
63211756Ssam 
63311650Ssam /*
63410294Ssam  * Rename a remote file.
63510294Ssam  */
63610294Ssam renamefile(argc, argv)
63710294Ssam 	char *argv[];
63810294Ssam {
63910294Ssam 
64010294Ssam 	if (argc < 2) {
64110294Ssam 		strcat(line, " ");
64210294Ssam 		printf("(from-name) ");
64310294Ssam 		gets(&line[strlen(line)]);
64410294Ssam 		makeargv();
64510294Ssam 		argc = margc;
64610294Ssam 		argv = margv;
64710294Ssam 	}
64810294Ssam 	if (argc < 2) {
64910294Ssam usage:
65010294Ssam 		printf("%s from-name to-name\n", argv[0]);
65110294Ssam 		return;
65210294Ssam 	}
65310294Ssam 	if (argc < 3) {
65410294Ssam 		strcat(line, " ");
65510294Ssam 		printf("(to-name) ");
65610294Ssam 		gets(&line[strlen(line)]);
65710294Ssam 		makeargv();
65810294Ssam 		argc = margc;
65910294Ssam 		argv = margv;
66010294Ssam 	}
66110294Ssam 	if (argc < 3)
66210294Ssam 		goto usage;
66310294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
66410294Ssam 		(void) command("RNTO %s", argv[2]);
66510294Ssam }
66610294Ssam 
66710294Ssam /*
66810294Ssam  * Get a directory listing
66910294Ssam  * of remote files.
67010294Ssam  */
67110294Ssam ls(argc, argv)
67210294Ssam 	char *argv[];
67310294Ssam {
67411756Ssam 	char *cmd;
67510294Ssam 
67610294Ssam 	if (argc < 2)
67710294Ssam 		argc++, argv[1] = NULL;
67810294Ssam 	if (argc < 3)
67910294Ssam 		argc++, argv[2] = "-";
68011756Ssam 	if (argc > 3) {
68111756Ssam 		printf("usage: %s remote-directory local-file\n", argv[0]);
68211756Ssam 		return;
68311756Ssam 	}
68410294Ssam 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
68511353Ssam 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
68611353Ssam 		return;
68711756Ssam 	recvrequest(cmd, argv[2], argv[1], "w");
68810294Ssam }
68910294Ssam 
69010294Ssam /*
69111756Ssam  * Get a directory listing
69211756Ssam  * of multiple remote files.
69311756Ssam  */
69411756Ssam mls(argc, argv)
69511756Ssam 	char *argv[];
69611756Ssam {
69713212Ssam 	char *cmd, *mode, *cp, *dest;
69811756Ssam 
69913212Ssam 	if (argc < 2) {
70013212Ssam 		strcat(line, " ");
70113212Ssam 		printf("(remote-files) ");
70213212Ssam 		gets(&line[strlen(line)]);
70313212Ssam 		makeargv();
70413212Ssam 		argc = margc;
70513212Ssam 		argv = margv;
70613212Ssam 	}
70713212Ssam 	if (argc < 3) {
70813212Ssam 		strcat(line, " ");
70913212Ssam 		printf("(local-file) ");
71013212Ssam 		gets(&line[strlen(line)]);
71113212Ssam 		makeargv();
71213212Ssam 		argc = margc;
71313212Ssam 		argv = margv;
71413212Ssam 	}
71513212Ssam 	if (argc < 3) {
71613212Ssam 		printf("%s remote-files local-file\n", argv[0]);
71713212Ssam 		return;
71813212Ssam 	}
71913212Ssam 	dest = argv[argc - 1];
72013212Ssam 	argv[argc - 1] = NULL;
72113212Ssam 	if (strcmp(dest, "-"))
72216324Sralph 		if (!globulize(&dest) || !confirm("local-file", dest))
72313212Ssam 			return;
72411756Ssam 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
72513212Ssam 	for (mode = "w"; cp = remglob(argc, argv); mode = "a")
72613212Ssam 		if (confirm(argv[0], cp))
72713212Ssam 			recvrequest(cmd, dest, cp, mode);
72811756Ssam }
72911756Ssam 
73011756Ssam /*
73110294Ssam  * Do a shell escape
73210294Ssam  */
73310294Ssam shell(argc, argv)
73410294Ssam 	char *argv[];
73510294Ssam {
73611756Ssam 	int pid, status, (*old1)(), (*old2)();
73711756Ssam 	char shellnam[40], *shell, *namep;
73811756Ssam 	char **cpp, **gargs;
73910294Ssam 
74011756Ssam 	old1 = signal (SIGINT, SIG_IGN);
74111756Ssam 	old2 = signal (SIGQUIT, SIG_IGN);
74211756Ssam 	if ((pid = fork()) == 0) {
74311756Ssam 		for (pid = 3; pid < 20; pid++)
74411756Ssam 			close(pid);
74511756Ssam 		signal(SIGINT, SIG_DFL);
74611756Ssam 		signal(SIGQUIT, SIG_DFL);
747*25908Smckusick 		shell = getenv("SHELL");
748*25908Smckusick 		if (shell == NULL)
749*25908Smckusick 			shell = "/bin/sh";
750*25908Smckusick 		namep = rindex(shell,'/');
751*25908Smckusick 		if (namep == NULL)
752*25908Smckusick 			namep = shell;
75311756Ssam 		if (argc <= 1) {
75411756Ssam 			if (debug) {
75511756Ssam 				printf ("%s\n", shell);
75611756Ssam 				fflush (stdout);
75711756Ssam 			}
758*25908Smckusick 			execl(shell, shell, (char *)0);
759*25908Smckusick 		} else {
760*25908Smckusick 			char *args[4];	/* "sh" "-c" <command> NULL */
761*25908Smckusick 
762*25908Smckusick 			args[0] = shell;
763*25908Smckusick 			args[1] = "-c";
764*25908Smckusick 			args[2] = argv[1];
765*25908Smckusick 			args[3] = NULL;
766*25908Smckusick 			if (debug) {
767*25908Smckusick 				printf("%s -c %s\n", shell, argv[1]);
768*25908Smckusick 				fflush(stdout);
76911756Ssam 			}
770*25908Smckusick 			execv(shell, args);
77111756Ssam 		}
772*25908Smckusick 		perror(shell);
77311756Ssam 		exit(1);
77411756Ssam 	}
77511756Ssam 	if (pid > 0)
77611756Ssam 		while (wait(&status) != pid)
77711756Ssam 			;
77811756Ssam 	signal(SIGINT, old1);
77911756Ssam 	signal(SIGQUIT, old2);
78011756Ssam 	if (pid == -1)
78111756Ssam 		perror("Try again later");
78211756Ssam 	return (0);
78310294Ssam }
78410294Ssam 
78510294Ssam /*
78610294Ssam  * Send new user information (re-login)
78710294Ssam  */
78810294Ssam user(argc, argv)
78910294Ssam 	int argc;
79010294Ssam 	char **argv;
79110294Ssam {
79210294Ssam 	char acct[80], *getpass();
79310294Ssam 	int n;
79410294Ssam 
79510294Ssam 	if (argc < 2) {
79610294Ssam 		strcat(line, " ");
79710294Ssam 		printf("(username) ");
79810294Ssam 		gets(&line[strlen(line)]);
79910294Ssam 		makeargv();
80010294Ssam 		argc = margc;
80110294Ssam 		argv = margv;
80210294Ssam 	}
80310294Ssam 	if (argc > 4) {
80410294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
80511756Ssam 		return (0);
80610294Ssam 	}
80710294Ssam 	n = command("USER %s", argv[1]);
80810294Ssam 	if (n == CONTINUE) {
80910294Ssam 		if (argc < 3 )
81010294Ssam 			argv[2] = getpass("Password: "), argc++;
81110294Ssam 		n = command("PASS %s", argv[2]);
81210294Ssam 	}
81310294Ssam 	if (n == CONTINUE) {
81410294Ssam 		if (argc < 4) {
81510294Ssam 			printf("Account: "); (void) fflush(stdout);
81610294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
81710294Ssam 			acct[strlen(acct) - 1] = '\0';
81810294Ssam 			argv[3] = acct; argc++;
81910294Ssam 		}
82010294Ssam 		n = command("ACCT %s", acct);
82110294Ssam 	}
82210294Ssam 	if (n != COMPLETE) {
82310294Ssam 		fprintf(stderr, "Login failed.\n");
82410294Ssam 		return (0);
82510294Ssam 	}
82610294Ssam 	return (1);
82710294Ssam }
82810294Ssam 
82910294Ssam /*
83010294Ssam  * Print working directory.
83110294Ssam  */
83210294Ssam /*VARARGS*/
83310294Ssam pwd()
83410294Ssam {
83511756Ssam 
83610294Ssam 	(void) command("XPWD");
83710294Ssam }
83810294Ssam 
83910294Ssam /*
84010294Ssam  * Make a directory.
84110294Ssam  */
84210294Ssam makedir(argc, argv)
84310294Ssam 	char *argv[];
84410294Ssam {
84510294Ssam 
84610294Ssam 	if (argc < 2) {
84710294Ssam 		strcat(line, " ");
84810294Ssam 		printf("(directory-name) ");
84910294Ssam 		gets(&line[strlen(line)]);
85010294Ssam 		makeargv();
85110294Ssam 		argc = margc;
85210294Ssam 		argv = margv;
85310294Ssam 	}
85410294Ssam 	if (argc < 2) {
85510294Ssam 		printf("%s directory-name\n", argv[0]);
85610294Ssam 		return;
85710294Ssam 	}
85810294Ssam 	(void) command("XMKD %s", argv[1]);
85910294Ssam }
86010294Ssam 
86110294Ssam /*
86210294Ssam  * Remove a directory.
86310294Ssam  */
86410294Ssam removedir(argc, argv)
86510294Ssam 	char *argv[];
86610294Ssam {
86710294Ssam 
86810294Ssam 	if (argc < 2) {
86910294Ssam 		strcat(line, " ");
87010294Ssam 		printf("(directory-name) ");
87110294Ssam 		gets(&line[strlen(line)]);
87210294Ssam 		makeargv();
87310294Ssam 		argc = margc;
87410294Ssam 		argv = margv;
87510294Ssam 	}
87610294Ssam 	if (argc < 2) {
87710294Ssam 		printf("%s directory-name\n", argv[0]);
87810294Ssam 		return;
87910294Ssam 	}
88010294Ssam 	(void) command("XRMD %s", argv[1]);
88110294Ssam }
88210294Ssam 
88310294Ssam /*
88410294Ssam  * Send a line, verbatim, to the remote machine.
88510294Ssam  */
88610294Ssam quote(argc, argv)
88710294Ssam 	char *argv[];
88810294Ssam {
88910294Ssam 	int i;
89010294Ssam 	char buf[BUFSIZ];
89110294Ssam 
89210294Ssam 	if (argc < 2) {
89310294Ssam 		strcat(line, " ");
89410294Ssam 		printf("(command line to send) ");
89510294Ssam 		gets(&line[strlen(line)]);
89610294Ssam 		makeargv();
89710294Ssam 		argc = margc;
89810294Ssam 		argv = margv;
89910294Ssam 	}
90010294Ssam 	if (argc < 2) {
90110294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
90210294Ssam 		return;
90310294Ssam 	}
90410294Ssam 	strcpy(buf, argv[1]);
90510294Ssam 	for (i = 2; i < argc; i++) {
90610294Ssam 		strcat(buf, " ");
90710294Ssam 		strcat(buf, argv[i]);
90810294Ssam 	}
90910294Ssam 	(void) command(buf);
91010294Ssam }
91110294Ssam 
91210294Ssam /*
91310294Ssam  * Ask the other side for help.
91410294Ssam  */
91510294Ssam rmthelp(argc, argv)
91610294Ssam 	char *argv[];
91710294Ssam {
91810294Ssam 	int oldverbose = verbose;
91910294Ssam 
92010294Ssam 	verbose = 1;
92110294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
92210294Ssam 	verbose = oldverbose;
92310294Ssam }
92410294Ssam 
92510294Ssam /*
92610294Ssam  * Terminate session and exit.
92710294Ssam  */
92810294Ssam /*VARARGS*/
92910294Ssam quit()
93010294Ssam {
93110294Ssam 
93218286Sralph 	if (connected)
93318286Sralph 		disconnect();
93410294Ssam 	exit(0);
93510294Ssam }
93610294Ssam 
93710294Ssam /*
93810294Ssam  * Terminate session, but don't exit.
93910294Ssam  */
94010294Ssam disconnect()
94110294Ssam {
94210294Ssam 	extern FILE *cout;
94310294Ssam 	extern int data;
94410294Ssam 
94510294Ssam 	if (!connected)
94610294Ssam 		return;
94710294Ssam 	(void) command("QUIT");
94810294Ssam 	(void) fclose(cout);
94910294Ssam 	cout = NULL;
95010294Ssam 	connected = 0;
95110294Ssam 	data = -1;
95210294Ssam }
95311353Ssam 
95411650Ssam confirm(cmd, file)
95511353Ssam 	char *cmd, *file;
95611353Ssam {
95711353Ssam 	char line[BUFSIZ];
95811353Ssam 
95911353Ssam 	if (!interactive)
96011650Ssam 		return (1);
96111353Ssam 	printf("%s %s? ", cmd, file);
96211353Ssam 	fflush(stdout);
96311353Ssam 	gets(line);
96411650Ssam 	return (*line != 'n' && *line != 'N');
96511353Ssam }
96611353Ssam 
96711353Ssam fatal(msg)
96811353Ssam 	char *msg;
96911353Ssam {
97011353Ssam 
97111353Ssam 	fprintf(stderr, "ftp: %s\n");
97211353Ssam 	exit(1);
97311353Ssam }
97411353Ssam 
97511353Ssam /*
97611353Ssam  * Glob a local file name specification with
97711353Ssam  * the expectation of a single return value.
97811353Ssam  * Can't control multiple values being expanded
97911353Ssam  * from the expression, we return only the first.
98011353Ssam  */
98111353Ssam globulize(cpp)
98211353Ssam 	char **cpp;
98311353Ssam {
98411353Ssam 	char **globbed;
98511353Ssam 
98611353Ssam 	if (!doglob)
98711353Ssam 		return (1);
98811353Ssam 	globbed = glob(*cpp);
98911353Ssam 	if (globerr != NULL) {
99011353Ssam 		printf("%s: %s\n", *cpp, globerr);
99111353Ssam 		if (globbed)
99211353Ssam 			blkfree(globbed);
99311353Ssam 		return (0);
99411353Ssam 	}
99511353Ssam 	if (globbed) {
99611353Ssam 		*cpp = *globbed++;
99711353Ssam 		/* don't waste too much memory */
99811353Ssam 		if (*globbed)
99911353Ssam 			blkfree(globbed);
100011353Ssam 	}
100111353Ssam 	return (1);
100211353Ssam }
1003