xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 11353)
110294Ssam #ifndef lint
2*11353Ssam static char sccsid[] = "@(#)cmds.c	4.3 (Berkeley) 03/01/83";
310294Ssam #endif
410294Ssam 
510294Ssam /*
610294Ssam  * FTP User Program -- Command Routines.
710294Ssam  */
8*11353Ssam #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>
15*11353Ssam #include <stat.h>
1610294Ssam 
1710294Ssam #include "ftp.h"
1810294Ssam #include "ftp_var.h"
1910294Ssam 
20*11353Ssam extern	char *globerr;
21*11353Ssam extern	char **glob();
22*11353Ssam 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  */
20010294Ssam put(argc, argv)
20110294Ssam 	char *argv[];
20210294Ssam {
20310294Ssam 
20410294Ssam 	if (!connected) {
20510294Ssam 		printf("Not connected.\n");
20610294Ssam 		return;
20710294Ssam 	}
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;
233*11353Ssam 	if (!globulize(&argv[1]))
234*11353Ssam 		return;
23510294Ssam 	sendrequest("STOR", argv[1], argv[2]);
23610294Ssam }
23710294Ssam 
23810294Ssam /*
239*11353Ssam  * Send one or more files.
24010294Ssam  */
241*11353Ssam mput(argc, argv)
242*11353Ssam 	char *argv[];
243*11353Ssam {
244*11353Ssam 	char **cpp, *dst;
245*11353Ssam 	int i;
246*11353Ssam 
247*11353Ssam 	if (!connected) {
248*11353Ssam 		printf("Not connected.\n");
249*11353Ssam 		return;
250*11353Ssam 	}
251*11353Ssam 	if (argc < 2) {
252*11353Ssam 		printf("%s local-file remote-file, or\n", argv[0]);
253*11353Ssam 		printf("%s local-files\n", argv[0]);
254*11353Ssam 		return;
255*11353Ssam 	}
256*11353Ssam 	if (argc == 3)  {
257*11353Ssam 		if (!globulize(&argv[1]))
258*11353Ssam 			return;
259*11353Ssam 		sendrequest("STOR", argv[1], argv[2]);
260*11353Ssam 		return;
261*11353Ssam 	}
262*11353Ssam 	/*
263*11353Ssam 	 * Check for shell metacharacters which we might
264*11353Ssam 	 * want to expand into a list of file names.
265*11353Ssam 	 */
266*11353Ssam 	for (i = 1; i < argc; i++) {
267*11353Ssam 		if (!doglob) {
268*11353Ssam 			if (!skip(argv[0], argv[i]))
269*11353Ssam 				sendrequest("STOR", argv[i], argv[i]);
270*11353Ssam 			continue;
271*11353Ssam 		}
272*11353Ssam 		cpp = glob(argv[i]);
273*11353Ssam 		if (globerr != NULL) {
274*11353Ssam 			printf("%s: %s\n", argv[i], globerr);
275*11353Ssam 			if (cpp)
276*11353Ssam 				blkfree(cpp);
277*11353Ssam 			continue;
278*11353Ssam 		}
279*11353Ssam 		if (cpp == NULL) {
280*11353Ssam 			printf("%s: no match\n", argv[i]);
281*11353Ssam 			continue;
282*11353Ssam 		}
283*11353Ssam 		while (*cpp != NULL) {
284*11353Ssam 			if (!skip(argv[0], *cpp))
285*11353Ssam 				sendrequest("STOR", *cpp, *cpp);
286*11353Ssam 			free(*cpp), cpp++;
287*11353Ssam 		}
288*11353Ssam 	}
289*11353Ssam }
290*11353Ssam 
291*11353Ssam /*
292*11353Ssam  * Receive one file.
293*11353Ssam  */
29410294Ssam get(argc, argv)
29510294Ssam 	char *argv[];
29610294Ssam {
29710294Ssam 
29810294Ssam 	if (!connected) {
29910294Ssam 		printf("Not connected.\n");
30010294Ssam 		return;
30110294Ssam 	}
30210294Ssam 	if (argc == 2)
30310294Ssam 		argc++, argv[2] = argv[1];
30410294Ssam 	if (argc < 2) {
30510294Ssam 		strcat(line, " ");
30610294Ssam 		printf("(remote-file) ");
30710294Ssam 		gets(&line[strlen(line)]);
30810294Ssam 		makeargv();
30910294Ssam 		argc = margc;
31010294Ssam 		argv = margv;
31110294Ssam 	}
31210294Ssam 	if (argc < 2) {
31310294Ssam usage:
314*11353Ssam 		printf("%s remote-file [ local-file ]\n", argv[0]);
31510294Ssam 		return;
31610294Ssam 	}
31710294Ssam 	if (argc < 3) {
31810294Ssam 		strcat(line, " ");
31910294Ssam 		printf("(local-file) ");
32010294Ssam 		gets(&line[strlen(line)]);
32110294Ssam 		makeargv();
32210294Ssam 		argc = margc;
32310294Ssam 		argv = margv;
32410294Ssam 	}
32510294Ssam 	if (argc < 3)
32610294Ssam 		goto usage;
327*11353Ssam 	if (!globulize(&argv[2]))
328*11353Ssam 		return;
32910294Ssam 	recvrequest("RETR", argv[2], argv[1]);
33010294Ssam }
33110294Ssam 
332*11353Ssam /*
333*11353Ssam  * Get multiple files.
334*11353Ssam  */
335*11353Ssam mget(argc, argv)
336*11353Ssam 	char *argv[];
337*11353Ssam {
338*11353Ssam 	char temp[16], *dst, dstpath[MAXPATHLEN], buf[MAXPATHLEN];
339*11353Ssam 	FILE *ftemp;
340*11353Ssam 	int madedir = 0, oldverbose;
341*11353Ssam 	struct stat stb;
342*11353Ssam 
343*11353Ssam 	if (!connected) {
344*11353Ssam 		printf("Not connected.\n");
345*11353Ssam 		return;
346*11353Ssam 	}
347*11353Ssam 	if (argc == 2)
348*11353Ssam 		argc++, argv[2] = argv[1];
349*11353Ssam 	if (argc < 2) {
350*11353Ssam 		strcat(line, " ");
351*11353Ssam 		printf("(remote-directory) ");
352*11353Ssam 		gets(&line[strlen(line)]);
353*11353Ssam 		makeargv();
354*11353Ssam 		argc = margc;
355*11353Ssam 		argv = margv;
356*11353Ssam 	}
357*11353Ssam 	if (argc < 2) {
358*11353Ssam usage:
359*11353Ssam 		printf("%s remote-directory [ local-directory ], or\n",
360*11353Ssam 			argv[0]);
361*11353Ssam 		printf("%s remote-files local-directory\n", argv[0]);
362*11353Ssam 		return;
363*11353Ssam 	}
364*11353Ssam 	if (argc < 3) {
365*11353Ssam 		strcat(line, " ");
366*11353Ssam 		printf("(local-directory) ");
367*11353Ssam 		gets(&line[strlen(line)]);
368*11353Ssam 		makeargv();
369*11353Ssam 		argc = margc;
370*11353Ssam 		argv = margv;
371*11353Ssam 	}
372*11353Ssam 	if (argc < 3)
373*11353Ssam 		goto usage;
374*11353Ssam 	dst = argv[argc - 1];
375*11353Ssam 	if (!globulize(&dst))
376*11353Ssam 		return;
377*11353Ssam 	/*
378*11353Ssam 	 * If destination doesn't exist,
379*11353Ssam 	 * try and create it.
380*11353Ssam 	 */
381*11353Ssam 	if (stat(dst, &stb) < 0) {
382*11353Ssam 		if (mkdir(dst, 0777) < 0) {
383*11353Ssam 			perror(dst);
384*11353Ssam 			return;
385*11353Ssam 		}
386*11353Ssam 		madedir++;
387*11353Ssam 	} else {
388*11353Ssam 		if ((stb.st_mode & S_IFMT) != S_IFDIR) {
389*11353Ssam 			printf("%s: not a directory\n", dst);
390*11353Ssam 			return;
391*11353Ssam 		}
392*11353Ssam 	}
393*11353Ssam 	/*
394*11353Ssam 	 * Multiple files, just get each one without an nlst.
395*11353Ssam 	 */
396*11353Ssam 	if (argc > 3) {
397*11353Ssam 		int i;
398*11353Ssam 
399*11353Ssam 		for (i = 1; i < argc - 1; i++)
400*11353Ssam 			recvrequest("RETR",
401*11353Ssam 			  sprintf(dstpath, "%s/%s", dst, argv[i]), argv[i]);
402*11353Ssam 		return;
403*11353Ssam 	}
404*11353Ssam 	/*
405*11353Ssam 	 * Get a directory full of files.  Perform an
406*11353Ssam 	 * nlst to find the file names, then retrieve
407*11353Ssam 	 * each individually.  If prompting is on, ask
408*11353Ssam 	 * before grabbing each file.
409*11353Ssam 	 */
410*11353Ssam 	strcpy(temp, "/tmp/ftpXXXXXX");
411*11353Ssam 	mktemp(temp);
412*11353Ssam 	oldverbose = verbose, verbose = 0;
413*11353Ssam 	recvrequest("NLST", temp, argv[1]);
414*11353Ssam 	verbose = oldverbose;
415*11353Ssam 	ftemp = fopen(temp, "r");
416*11353Ssam 	unlink(temp);
417*11353Ssam 	if (ftemp == NULL) {
418*11353Ssam 		printf("can't find list of remote files, oops\n");
419*11353Ssam 		if (madedir)
420*11353Ssam 			(void) rmdir(dst);
421*11353Ssam 		return;
422*11353Ssam 	}
423*11353Ssam 	while (fgets(buf, sizeof (buf), ftemp) != NULL) {
424*11353Ssam 		char *cp = index(buf, '\n');
425*11353Ssam 
426*11353Ssam 		if (cp)
427*11353Ssam 			*cp = '\0';
428*11353Ssam 		if (skip(argv[0], buf))
429*11353Ssam 			continue;
430*11353Ssam 		recvrequest("RETR", sprintf(dstpath, "%s/%s", dst, buf), buf);
431*11353Ssam 	}
432*11353Ssam 	fclose(ftemp);
433*11353Ssam }
434*11353Ssam 
43510294Ssam char *
43610294Ssam onoff(bool)
43710294Ssam 	int bool;
43810294Ssam {
43910294Ssam 
44010294Ssam 	return (bool ? "on" : "off");
44110294Ssam }
44210294Ssam 
44310294Ssam /*
44410294Ssam  * Show status.
44510294Ssam  */
44610294Ssam status(argc, argv)
44710294Ssam 	char *argv[];
44810294Ssam {
44910294Ssam 
45010294Ssam 	if (connected)
45110294Ssam 		printf("Connected to %s.\n", hostname);
45210294Ssam 	else
45310294Ssam 		printf("Not connected.\n");
45410294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
45510294Ssam 		modename, typename, formname, structname);
456*11353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
457*11353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
458*11353Ssam 		onoff(doglob));
45910294Ssam }
46010294Ssam 
46110294Ssam /*
46210294Ssam  * Set beep on cmd completed mode.
46310294Ssam  */
46410294Ssam /*VARARGS*/
46510294Ssam setbell()
46610294Ssam {
46710294Ssam 
46810294Ssam 	bell = !bell;
46910294Ssam 	printf("Bell mode %s.\n", onoff(bell));
47010294Ssam }
47110294Ssam 
47210294Ssam /*
47310294Ssam  * Turn on packet tracing.
47410294Ssam  */
47510294Ssam /*VARARGS*/
47610294Ssam settrace()
47710294Ssam {
47810294Ssam 
47910294Ssam 	trace = !trace;
48010294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
48110294Ssam }
48210294Ssam 
48310294Ssam /*
48410294Ssam  * Turn on printing of server echo's.
48510294Ssam  */
48610294Ssam /*VARARGS*/
48710294Ssam setverbose()
48810294Ssam {
48910294Ssam 
49010294Ssam 	verbose = !verbose;
49110294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
49210294Ssam }
49310294Ssam 
49410294Ssam /*
49510294Ssam  * Turn on interactive prompting
49610294Ssam  * during mget, mput, and mdelete.
49710294Ssam  */
49810294Ssam /*VARARGS*/
49910294Ssam setprompt()
50010294Ssam {
50110294Ssam 
50210294Ssam 	interactive = !interactive;
50310294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
50410294Ssam }
50510294Ssam 
50610294Ssam /*
507*11353Ssam  * Toggle metacharacter interpretation
508*11353Ssam  * on local file names.
509*11353Ssam  */
510*11353Ssam /*VARARGS*/
511*11353Ssam setglob()
512*11353Ssam {
513*11353Ssam 
514*11353Ssam 	doglob = !doglob;
515*11353Ssam 	printf("Globbing %s.\n", onoff(doglob));
516*11353Ssam }
517*11353Ssam 
518*11353Ssam /*
51910294Ssam  * Set debugging mode on/off and/or
52010294Ssam  * set level of debugging.
52110294Ssam  */
52210294Ssam setdebug(argc, argv)
52310294Ssam 	char *argv[];
52410294Ssam {
52510294Ssam 	int val;
52610294Ssam 
52710294Ssam 	if (argc > 1) {
52810294Ssam 		val = atoi(argv[1]);
52910294Ssam 		if (val < 0) {
53010294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
53110294Ssam 			return;
53210294Ssam 		}
53310294Ssam 	} else
53410294Ssam 		val = !debug;
53510294Ssam 	debug = val;
53610294Ssam 	if (debug)
53710294Ssam 		options |= SO_DEBUG;
53810294Ssam 	else
53910294Ssam 		options &= ~SO_DEBUG;
54010294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
54110294Ssam }
54210294Ssam 
54310294Ssam /*
54410294Ssam  * Set current working directory
54510294Ssam  * on remote machine.
54610294Ssam  */
54710294Ssam cd(argc, argv)
54810294Ssam 	char *argv[];
54910294Ssam {
55010294Ssam 
55110294Ssam 	if (!connected) {
55210294Ssam 		printf("Not connected.\n");
55310294Ssam 		return;
55410294Ssam 	}
55510294Ssam 	if (argc < 2) {
55610294Ssam 		strcat(line, " ");
55710294Ssam 		printf("(remote-directory) ");
55810294Ssam 		gets(&line[strlen(line)]);
55910294Ssam 		makeargv();
56010294Ssam 		argc = margc;
56110294Ssam 		argv = margv;
56210294Ssam 	}
56310294Ssam 	if (argc < 2) {
56410294Ssam 		printf("%s remote-directory\n", argv[0]);
56510294Ssam 		return;
56610294Ssam 	}
56710294Ssam 	(void) command("CWD %s", argv[1]);
56810294Ssam }
56910294Ssam 
57010294Ssam /*
57110294Ssam  * Set current working directory
57210294Ssam  * on local machine.
57310294Ssam  */
57410294Ssam lcd(argc, argv)
57510294Ssam 	char *argv[];
57610294Ssam {
577*11353Ssam 	char buf[MAXPATHLEN];
578*11353Ssam 	extern char *home;
57910294Ssam 
580*11353Ssam 	if (argc < 2)
581*11353Ssam 		argc++, argv[1] = home;
58210294Ssam 	if (argc != 2) {
58310294Ssam 		printf("%s local-directory\n", argv[0]);
58410294Ssam 		return;
58510294Ssam 	}
586*11353Ssam 	if (!globulize(&argv[1]))
587*11353Ssam 		return;
588*11353Ssam 	if (chdir(argv[1]) < 0) {
58910294Ssam 		perror(argv[1]);
590*11353Ssam 		return;
591*11353Ssam 	}
592*11353Ssam 	printf("Local directory now %s\n", getwd(buf));
59310294Ssam }
59410294Ssam 
59510294Ssam /*
59610294Ssam  * Delete a single file.
59710294Ssam  */
59810294Ssam delete(argc, argv)
59910294Ssam 	char *argv[];
60010294Ssam {
60110294Ssam 
60210294Ssam 	if (argc < 2) {
60310294Ssam 		strcat(line, " ");
60410294Ssam 		printf("(remote-file) ");
60510294Ssam 		gets(&line[strlen(line)]);
60610294Ssam 		makeargv();
60710294Ssam 		argc = margc;
60810294Ssam 		argv = margv;
60910294Ssam 	}
61010294Ssam 	if (argc < 2) {
61110294Ssam 		printf("%s remote-file\n", argv[0]);
61210294Ssam 		return;
61310294Ssam 	}
61410294Ssam 	(void) command("DELE %s", argv[1]);
61510294Ssam }
61610294Ssam 
61710294Ssam /*
61810294Ssam  * Rename a remote file.
61910294Ssam  */
62010294Ssam renamefile(argc, argv)
62110294Ssam 	char *argv[];
62210294Ssam {
62310294Ssam 
62410294Ssam 	if (argc < 2) {
62510294Ssam 		strcat(line, " ");
62610294Ssam 		printf("(from-name) ");
62710294Ssam 		gets(&line[strlen(line)]);
62810294Ssam 		makeargv();
62910294Ssam 		argc = margc;
63010294Ssam 		argv = margv;
63110294Ssam 	}
63210294Ssam 	if (argc < 2) {
63310294Ssam usage:
63410294Ssam 		printf("%s from-name to-name\n", argv[0]);
63510294Ssam 		return;
63610294Ssam 	}
63710294Ssam 	if (argc < 3) {
63810294Ssam 		strcat(line, " ");
63910294Ssam 		printf("(to-name) ");
64010294Ssam 		gets(&line[strlen(line)]);
64110294Ssam 		makeargv();
64210294Ssam 		argc = margc;
64310294Ssam 		argv = margv;
64410294Ssam 	}
64510294Ssam 	if (argc < 3)
64610294Ssam 		goto usage;
64710294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
64810294Ssam 		(void) command("RNTO %s", argv[2]);
64910294Ssam }
65010294Ssam 
65110294Ssam /*
65210294Ssam  * Get a directory listing
65310294Ssam  * of remote files.
65410294Ssam  */
65510294Ssam ls(argc, argv)
65610294Ssam 	char *argv[];
65710294Ssam {
65810294Ssam 	char *cmd;
65910294Ssam 
66010294Ssam 	if (argc < 2)
66110294Ssam 		argc++, argv[1] = NULL;
66210294Ssam 	if (argc < 3)
66310294Ssam 		argc++, argv[2] = "-";
66410294Ssam 	if (argc > 3) {
66510294Ssam 		printf("usage: %s remote-directory local-file\n", argv[0]);
66610294Ssam 		return;
66710294Ssam 	}
66810294Ssam 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
669*11353Ssam 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
670*11353Ssam 		return;
67110294Ssam 	recvrequest(cmd, argv[2], argv[1]);
67210294Ssam }
67310294Ssam 
67410294Ssam /*
67510294Ssam  * Do a shell escape
67610294Ssam  */
67710294Ssam shell(argc, argv)
67810294Ssam 	char *argv[];
67910294Ssam {
68010294Ssam 
68110294Ssam 	printf("Sorry, this function is unimplemented.\n");
68210294Ssam }
68310294Ssam 
68410294Ssam /*
68510294Ssam  * Send new user information (re-login)
68610294Ssam  */
68710294Ssam user(argc, argv)
68810294Ssam 	int argc;
68910294Ssam 	char **argv;
69010294Ssam {
69110294Ssam 	char acct[80], *getpass();
69210294Ssam 	int n;
69310294Ssam 
69410294Ssam 	if (argc < 2) {
69510294Ssam 		strcat(line, " ");
69610294Ssam 		printf("(username) ");
69710294Ssam 		gets(&line[strlen(line)]);
69810294Ssam 		makeargv();
69910294Ssam 		argc = margc;
70010294Ssam 		argv = margv;
70110294Ssam 	}
70210294Ssam 	if (argc > 4) {
70310294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
70410294Ssam 		return;
70510294Ssam 	}
70610294Ssam 	n = command("USER %s", argv[1]);
70710294Ssam 	if (n == CONTINUE) {
70810294Ssam 		if (argc < 3 )
70910294Ssam 			argv[2] = getpass("Password: "), argc++;
71010294Ssam 		n = command("PASS %s", argv[2]);
71110294Ssam 	}
71210294Ssam 	if (n == CONTINUE) {
71310294Ssam 		if (argc < 4) {
71410294Ssam 			printf("Account: "); (void) fflush(stdout);
71510294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
71610294Ssam 			acct[strlen(acct) - 1] = '\0';
71710294Ssam 			argv[3] = acct; argc++;
71810294Ssam 		}
71910294Ssam 		n = command("ACCT %s", acct);
72010294Ssam 	}
72110294Ssam 	if (n != COMPLETE) {
72210294Ssam 		fprintf(stderr, "Login failed.\n");
72310294Ssam 		return (0);
72410294Ssam 	}
72510294Ssam 	return (1);
72610294Ssam }
72710294Ssam 
72810294Ssam /*
72910294Ssam  * Print working directory.
73010294Ssam  */
73110294Ssam /*VARARGS*/
73210294Ssam pwd()
73310294Ssam {
73410294Ssam 	if (!connected) {
73510294Ssam 		printf("Not connected.\n");
73610294Ssam 		return;
73710294Ssam 	}
73810294Ssam 	(void) command("XPWD");
73910294Ssam }
74010294Ssam 
74110294Ssam /*
74210294Ssam  * Make a directory.
74310294Ssam  */
74410294Ssam makedir(argc, argv)
74510294Ssam 	char *argv[];
74610294Ssam {
74710294Ssam 
74810294Ssam 	if (argc < 2) {
74910294Ssam 		strcat(line, " ");
75010294Ssam 		printf("(directory-name) ");
75110294Ssam 		gets(&line[strlen(line)]);
75210294Ssam 		makeargv();
75310294Ssam 		argc = margc;
75410294Ssam 		argv = margv;
75510294Ssam 	}
75610294Ssam 	if (argc < 2) {
75710294Ssam 		printf("%s directory-name\n", argv[0]);
75810294Ssam 		return;
75910294Ssam 	}
76010294Ssam 	(void) command("XMKD %s", argv[1]);
76110294Ssam }
76210294Ssam 
76310294Ssam /*
76410294Ssam  * Remove a directory.
76510294Ssam  */
76610294Ssam removedir(argc, argv)
76710294Ssam 	char *argv[];
76810294Ssam {
76910294Ssam 
77010294Ssam 	if (argc < 2) {
77110294Ssam 		strcat(line, " ");
77210294Ssam 		printf("(directory-name) ");
77310294Ssam 		gets(&line[strlen(line)]);
77410294Ssam 		makeargv();
77510294Ssam 		argc = margc;
77610294Ssam 		argv = margv;
77710294Ssam 	}
77810294Ssam 	if (argc < 2) {
77910294Ssam 		printf("%s directory-name\n", argv[0]);
78010294Ssam 		return;
78110294Ssam 	}
78210294Ssam 	(void) command("XRMD %s", argv[1]);
78310294Ssam }
78410294Ssam 
78510294Ssam /*
78610294Ssam  * Send a line, verbatim, to the remote machine.
78710294Ssam  */
78810294Ssam quote(argc, argv)
78910294Ssam 	char *argv[];
79010294Ssam {
79110294Ssam 	int i;
79210294Ssam 	char buf[BUFSIZ];
79310294Ssam 
79410294Ssam 	if (argc < 2) {
79510294Ssam 		strcat(line, " ");
79610294Ssam 		printf("(command line to send) ");
79710294Ssam 		gets(&line[strlen(line)]);
79810294Ssam 		makeargv();
79910294Ssam 		argc = margc;
80010294Ssam 		argv = margv;
80110294Ssam 	}
80210294Ssam 	if (argc < 2) {
80310294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
80410294Ssam 		return;
80510294Ssam 	}
80610294Ssam 	strcpy(buf, argv[1]);
80710294Ssam 	for (i = 2; i < argc; i++) {
80810294Ssam 		strcat(buf, " ");
80910294Ssam 		strcat(buf, argv[i]);
81010294Ssam 	}
81110294Ssam 	(void) command(buf);
81210294Ssam }
81310294Ssam 
81410294Ssam /*
81510294Ssam  * Ask the other side for help.
81610294Ssam  */
81710294Ssam rmthelp(argc, argv)
81810294Ssam 	char *argv[];
81910294Ssam {
82010294Ssam 	int oldverbose = verbose;
82110294Ssam 
82210294Ssam 	verbose = 1;
82310294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
82410294Ssam 	verbose = oldverbose;
82510294Ssam }
82610294Ssam 
82710294Ssam /*
82810294Ssam  * Terminate session and exit.
82910294Ssam  */
83010294Ssam /*VARARGS*/
83110294Ssam quit()
83210294Ssam {
83310294Ssam 
83410294Ssam 	disconnect();
83510294Ssam 	exit(0);
83610294Ssam }
83710294Ssam 
83810294Ssam /*
83910294Ssam  * Terminate session, but don't exit.
84010294Ssam  */
84110294Ssam disconnect()
84210294Ssam {
84310294Ssam 	extern FILE *cout;
84410294Ssam 	extern int data;
84510294Ssam 
84610294Ssam 	if (!connected)
84710294Ssam 		return;
84810294Ssam 	(void) command("QUIT");
84910294Ssam 	(void) fclose(cout);
85010294Ssam 	cout = NULL;
85110294Ssam 	connected = 0;
85210294Ssam 	data = -1;
85310294Ssam }
854*11353Ssam 
855*11353Ssam skip(cmd, file)
856*11353Ssam 	char *cmd, *file;
857*11353Ssam {
858*11353Ssam 	char line[BUFSIZ];
859*11353Ssam 
860*11353Ssam 	if (!interactive)
861*11353Ssam 		return (0);
862*11353Ssam 	printf("%s %s? ", cmd, file);
863*11353Ssam 	fflush(stdout);
864*11353Ssam 	gets(line);
865*11353Ssam 	return (*line == 'y');
866*11353Ssam }
867*11353Ssam 
868*11353Ssam fatal(msg)
869*11353Ssam 	char *msg;
870*11353Ssam {
871*11353Ssam 
872*11353Ssam 	fprintf(stderr, "ftp: %s\n");
873*11353Ssam 	exit(1);
874*11353Ssam }
875*11353Ssam 
876*11353Ssam /*
877*11353Ssam  * Glob a local file name specification with
878*11353Ssam  * the expectation of a single return value.
879*11353Ssam  * Can't control multiple values being expanded
880*11353Ssam  * from the expression, we return only the first.
881*11353Ssam  */
882*11353Ssam globulize(cpp)
883*11353Ssam 	char **cpp;
884*11353Ssam {
885*11353Ssam 	char **globbed;
886*11353Ssam 
887*11353Ssam 	if (!doglob)
888*11353Ssam 		return (1);
889*11353Ssam 	globbed = glob(*cpp);
890*11353Ssam 	if (globerr != NULL) {
891*11353Ssam 		printf("%s: %s\n", *cpp, globerr);
892*11353Ssam 		if (globbed)
893*11353Ssam 			blkfree(globbed);
894*11353Ssam 		return (0);
895*11353Ssam 	}
896*11353Ssam 	if (globbed) {
897*11353Ssam 		*cpp = *globbed++;
898*11353Ssam 		/* don't waste too much memory */
899*11353Ssam 		if (*globbed)
900*11353Ssam 			blkfree(globbed);
901*11353Ssam 	}
902*11353Ssam 	return (1);
903*11353Ssam }
904