xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 38032)
121737Sdist /*
236942Skarels  * Copyright (c) 1985, 1989 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1536935Skarels  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621737Sdist  */
1721737Sdist 
1810294Ssam #ifndef lint
19*38032Skarels static char sccsid[] = "@(#)cmds.c	5.19 (Berkeley) 05/17/89";
2033737Sbostic #endif /* not lint */
2110294Ssam 
2210294Ssam /*
2310294Ssam  * FTP User Program -- Command Routines.
2410294Ssam  */
2536940Skarels #include <sys/param.h>
2636940Skarels #include <sys/wait.h>
2736940Skarels #include <sys/stat.h>
2810294Ssam #include <sys/socket.h>
2910294Ssam 
3012396Ssam #include <arpa/ftp.h>
3112396Ssam 
3210294Ssam #include <signal.h>
3310294Ssam #include <stdio.h>
3410294Ssam #include <errno.h>
3510294Ssam #include <netdb.h>
3626049Sminshall #include <ctype.h>
3736935Skarels #include <time.h>
3810294Ssam 
3936940Skarels #include "ftp_var.h"
4037458Skarels #include "pathnames.h"
4110294Ssam 
4211353Ssam extern	char *globerr;
4311353Ssam extern	char **glob();
4411756Ssam extern	char *home;
4511756Ssam extern	char *remglob();
4611756Ssam extern	char *getenv();
4711756Ssam extern	char *index();
4811756Ssam extern	char *rindex();
4937224Skarels extern off_t restart_point;
5036935Skarels extern char reply_string[];
5136935Skarels 
5226049Sminshall char *mname;
5326049Sminshall jmp_buf jabort;
5426049Sminshall char *dotrans(), *domap();
5510294Ssam 
5610294Ssam /*
5710294Ssam  * Connect to peer server and
5810294Ssam  * auto-login, if possible.
5910294Ssam  */
6010294Ssam setpeer(argc, argv)
6110294Ssam 	int argc;
6210294Ssam 	char *argv[];
6310294Ssam {
6425903Skarels 	char *host, *hookup();
6510294Ssam 	int port;
6610294Ssam 
6710294Ssam 	if (connected) {
6826049Sminshall 		printf("Already connected to %s, use close first.\n",
6910294Ssam 			hostname);
7026049Sminshall 		code = -1;
7110294Ssam 		return;
7210294Ssam 	}
7310294Ssam 	if (argc < 2) {
7426497Sminshall 		(void) strcat(line, " ");
7510294Ssam 		printf("(to) ");
7626497Sminshall 		(void) gets(&line[strlen(line)]);
7710294Ssam 		makeargv();
7810294Ssam 		argc = margc;
7910294Ssam 		argv = margv;
8010294Ssam 	}
8110294Ssam 	if (argc > 3) {
8210294Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
8326049Sminshall 		code = -1;
8410294Ssam 		return;
8510294Ssam 	}
8610294Ssam 	port = sp->s_port;
8710294Ssam 	if (argc > 2) {
8811218Ssam 		port = atoi(argv[2]);
8910294Ssam 		if (port <= 0) {
9011218Ssam 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
9111218Ssam 			printf ("usage: %s host-name [port]\n", argv[0]);
9226049Sminshall 			code = -1;
9310294Ssam 			return;
9410294Ssam 		}
9510294Ssam 		port = htons(port);
9610294Ssam 	}
9710294Ssam 	host = hookup(argv[1], port);
9810294Ssam 	if (host) {
9937228Skarels 		int overbose;
10037228Skarels 
10110294Ssam 		connected = 1;
102*38032Skarels 		/*
103*38032Skarels 		 * Set up defaults for FTP.
104*38032Skarels 		 */
105*38032Skarels 		(void) strcpy(typename, "ascii"), type = TYPE_A;
106*38032Skarels 		curtype = TYPE_A;
107*38032Skarels 		(void) strcpy(formname, "non-print"), form = FORM_N;
108*38032Skarels 		(void) strcpy(modename, "stream"), mode = MODE_S;
109*38032Skarels 		(void) strcpy(structname, "file"), stru = STRU_F;
110*38032Skarels 		(void) strcpy(bytename, "8"), bytesize = 8;
11137228Skarels 		if (autologin)
11237228Skarels 			(void) login(argv[1]);
11336940Skarels 
11436935Skarels #if defined(unix) && NBBY == 8
11536935Skarels /*
11636935Skarels  * this ifdef is to keep someone form "porting" this to an incompatible
11736935Skarels  * system and not checking this out. This way they have to think about it.
11836935Skarels  */
11937228Skarels 		overbose = verbose;
12037228Skarels 		if (debug == 0)
12137228Skarels 			verbose = -1;
12237228Skarels 		if (command("SYST") == COMPLETE && overbose) {
12337228Skarels 			register char *cp, c;
12437228Skarels 			cp = index(reply_string+4, ' ');
12537228Skarels 			if (cp == NULL)
12637228Skarels 				cp = index(reply_string+4, '\r');
12737228Skarels 			if (cp) {
12837228Skarels 				if (cp[-1] == '.')
12937228Skarels 					cp--;
13037228Skarels 				c = *cp;
13137228Skarels 				*cp = '\0';
13237228Skarels 			}
13336935Skarels 
13437228Skarels 			printf("Remote system type is %s.\n",
13537228Skarels 				reply_string+4);
13637228Skarels 			if (cp)
13737228Skarels 				*cp = c;
13837228Skarels 		}
13937228Skarels 		if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
140*38032Skarels 			if (proxy)
141*38032Skarels 				unix_proxy = 1;
142*38032Skarels 			else
143*38032Skarels 				unix_server = 1;
144*38032Skarels 			/*
145*38032Skarels 			 * Set type to 0 (not specified by user),
146*38032Skarels 			 * meaning binary by default, but don't bother
147*38032Skarels 			 * telling server.  We can use binary
148*38032Skarels 			 * for text files unless changed by the user.
149*38032Skarels 			 */
150*38032Skarels 			type = 0;
151*38032Skarels 			(void) strcpy(typename, "binary");
15237228Skarels 			if (overbose)
15337228Skarels 			    printf("Using %s mode to transfer files.\n",
15437228Skarels 				typename);
155*38032Skarels 		} else {
156*38032Skarels 			if (proxy)
157*38032Skarels 				unix_proxy = 0;
158*38032Skarels 			else
159*38032Skarels 				unix_server = 0;
160*38032Skarels 			if (overbose &&
161*38032Skarels 			    !strncmp(reply_string, "215 TOPS20", 10))
162*38032Skarels 				printf(
16336940Skarels "Remember to set tenex mode when transfering binary files from this machine.\n");
16437228Skarels 		}
16537228Skarels 		verbose = overbose;
16636935Skarels #endif /* unix */
16710294Ssam 	}
16810294Ssam }
16910294Ssam 
17010294Ssam struct	types {
17110294Ssam 	char	*t_name;
17210294Ssam 	char	*t_mode;
17310294Ssam 	int	t_type;
17411218Ssam 	char	*t_arg;
17510294Ssam } types[] = {
17611218Ssam 	{ "ascii",	"A",	TYPE_A,	0 },
17711218Ssam 	{ "binary",	"I",	TYPE_I,	0 },
17811218Ssam 	{ "image",	"I",	TYPE_I,	0 },
17911218Ssam 	{ "ebcdic",	"E",	TYPE_E,	0 },
18011218Ssam 	{ "tenex",	"L",	TYPE_L,	bytename },
18110294Ssam 	0
18210294Ssam };
18310294Ssam 
18410294Ssam /*
18510294Ssam  * Set transfer type.
18610294Ssam  */
18710294Ssam settype(argc, argv)
18810294Ssam 	char *argv[];
18910294Ssam {
19010294Ssam 	register struct types *p;
19111218Ssam 	int comret;
19210294Ssam 
19310294Ssam 	if (argc > 2) {
19410294Ssam 		char *sep;
19510294Ssam 
19610294Ssam 		printf("usage: %s [", argv[0]);
19710294Ssam 		sep = " ";
19810294Ssam 		for (p = types; p->t_name; p++) {
19910294Ssam 			printf("%s%s", sep, p->t_name);
200*38032Skarels 			sep = " | ";
20110294Ssam 		}
20210294Ssam 		printf(" ]\n");
20326049Sminshall 		code = -1;
20410294Ssam 		return;
20510294Ssam 	}
20610294Ssam 	if (argc < 2) {
20710294Ssam 		printf("Using %s mode to transfer files.\n", typename);
20826049Sminshall 		code = 0;
20910294Ssam 		return;
21010294Ssam 	}
21110294Ssam 	for (p = types; p->t_name; p++)
21210294Ssam 		if (strcmp(argv[1], p->t_name) == 0)
21310294Ssam 			break;
21410294Ssam 	if (p->t_name == 0) {
21510294Ssam 		printf("%s: unknown mode\n", argv[1]);
21626049Sminshall 		code = -1;
21710294Ssam 		return;
21810294Ssam 	}
21911218Ssam 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
22011218Ssam 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
22111218Ssam 	else
22211218Ssam 		comret = command("TYPE %s", p->t_mode);
22311218Ssam 	if (comret == COMPLETE) {
22426497Sminshall 		(void) strcpy(typename, p->t_name);
225*38032Skarels 		curtype = type = p->t_type;
22610294Ssam 	}
22710294Ssam }
22810294Ssam 
22910294Ssam /*
230*38032Skarels  * Internal form of settype; changes current type in use with server
231*38032Skarels  * without changing our notion of the type for data transfers.
232*38032Skarels  * Used to change to and from ascii for listings.
233*38032Skarels  */
234*38032Skarels changetype(newtype, show)
235*38032Skarels 	int newtype, show;
236*38032Skarels {
237*38032Skarels 	register struct types *p;
238*38032Skarels 	int comret, oldverbose = verbose;
239*38032Skarels 
240*38032Skarels 	if (newtype == 0)
241*38032Skarels 		newtype = TYPE_I;
242*38032Skarels 	if (newtype == curtype)
243*38032Skarels 		return;
244*38032Skarels 	if (debug == 0 && show == 0)
245*38032Skarels 		verbose = 0;
246*38032Skarels 	for (p = types; p->t_name; p++)
247*38032Skarels 		if (newtype == p->t_type)
248*38032Skarels 			break;
249*38032Skarels 	if (p->t_name == 0) {
250*38032Skarels 		printf("ftp: internal error: unknown type %d\n", newtype);
251*38032Skarels 		return;
252*38032Skarels 	}
253*38032Skarels 	if (newtype == TYPE_L && bytename[0] != '\0')
254*38032Skarels 		comret = command("TYPE %s %s", p->t_mode, bytename);
255*38032Skarels 	else
256*38032Skarels 		comret = command("TYPE %s", p->t_mode);
257*38032Skarels 	if (comret == COMPLETE)
258*38032Skarels 		curtype = newtype;
259*38032Skarels 	verbose = oldverbose;
260*38032Skarels }
261*38032Skarels 
262*38032Skarels /*
26310294Ssam  * Set binary transfer type.
26410294Ssam  */
26510294Ssam /*VARARGS*/
26610294Ssam setbinary()
26710294Ssam {
26810294Ssam 
26910294Ssam 	call(settype, "type", "binary", 0);
27010294Ssam }
27110294Ssam 
27210294Ssam /*
27310294Ssam  * Set ascii transfer type.
27410294Ssam  */
27510294Ssam /*VARARGS*/
27610294Ssam setascii()
27710294Ssam {
27810294Ssam 
27910294Ssam 	call(settype, "type", "ascii", 0);
28010294Ssam }
28110294Ssam 
28210294Ssam /*
28310294Ssam  * Set tenex transfer type.
28410294Ssam  */
28510294Ssam /*VARARGS*/
28610294Ssam settenex()
28710294Ssam {
28810294Ssam 
28910294Ssam 	call(settype, "type", "tenex", 0);
29010294Ssam }
29110294Ssam 
29210294Ssam /*
29310294Ssam  * Set ebcdic transfer type.
29410294Ssam  */
29510294Ssam /*VARARGS*/
29610294Ssam setebcdic()
29710294Ssam {
29810294Ssam 
29910294Ssam 	call(settype, "type", "ebcdic", 0);
30010294Ssam }
30110294Ssam 
30210294Ssam /*
30310294Ssam  * Set file transfer mode.
30410294Ssam  */
30526497Sminshall /*ARGSUSED*/
30610294Ssam setmode(argc, argv)
30710294Ssam 	char *argv[];
30810294Ssam {
30910294Ssam 
31010294Ssam 	printf("We only support %s mode, sorry.\n", modename);
31126049Sminshall 	code = -1;
31210294Ssam }
31310294Ssam 
31410294Ssam /*
31510294Ssam  * Set file transfer format.
31610294Ssam  */
31726497Sminshall /*ARGSUSED*/
31810294Ssam setform(argc, argv)
31910294Ssam 	char *argv[];
32010294Ssam {
32110294Ssam 
32210294Ssam 	printf("We only support %s format, sorry.\n", formname);
32326049Sminshall 	code = -1;
32410294Ssam }
32510294Ssam 
32610294Ssam /*
32710294Ssam  * Set file transfer structure.
32810294Ssam  */
32926497Sminshall /*ARGSUSED*/
33010294Ssam setstruct(argc, argv)
33110294Ssam 	char *argv[];
33210294Ssam {
33310294Ssam 
33410294Ssam 	printf("We only support %s structure, sorry.\n", structname);
33526049Sminshall 	code = -1;
33610294Ssam }
33710294Ssam 
33818286Sralph /*
33918286Sralph  * Send a single file.
34018286Sralph  */
34110294Ssam put(argc, argv)
34211756Ssam 	int argc;
34310294Ssam 	char *argv[];
34410294Ssam {
34511650Ssam 	char *cmd;
34626049Sminshall 	int loc = 0;
34737225Skarels 	char *oldargv1, *oldargv2;
34811650Ssam 
34926049Sminshall 	if (argc == 2) {
35026049Sminshall 		argc++;
35126049Sminshall 		argv[2] = argv[1];
35226049Sminshall 		loc++;
35326049Sminshall 	}
35410294Ssam 	if (argc < 2) {
35526497Sminshall 		(void) strcat(line, " ");
35610294Ssam 		printf("(local-file) ");
35726497Sminshall 		(void) gets(&line[strlen(line)]);
35810294Ssam 		makeargv();
35910294Ssam 		argc = margc;
36010294Ssam 		argv = margv;
36110294Ssam 	}
36210294Ssam 	if (argc < 2) {
36310294Ssam usage:
36426049Sminshall 		printf("usage:%s local-file remote-file\n", argv[0]);
36526049Sminshall 		code = -1;
36610294Ssam 		return;
36710294Ssam 	}
36810294Ssam 	if (argc < 3) {
36926497Sminshall 		(void) strcat(line, " ");
37010294Ssam 		printf("(remote-file) ");
37126497Sminshall 		(void) gets(&line[strlen(line)]);
37210294Ssam 		makeargv();
37310294Ssam 		argc = margc;
37410294Ssam 		argv = margv;
37510294Ssam 	}
37610294Ssam 	if (argc < 3)
37710294Ssam 		goto usage;
37825908Smckusick 	oldargv1 = argv[1];
37937225Skarels 	oldargv2 = argv[2];
38026049Sminshall 	if (!globulize(&argv[1])) {
38126049Sminshall 		code = -1;
38211353Ssam 		return;
38326049Sminshall 	}
38425908Smckusick 	/*
38525908Smckusick 	 * If "globulize" modifies argv[1], and argv[2] is a copy of
38625908Smckusick 	 * the old argv[1], make it a copy of the new argv[1].
38725908Smckusick 	 */
38826049Sminshall 	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
38925908Smckusick 		argv[2] = argv[1];
39026049Sminshall 	}
39126049Sminshall 	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
39226049Sminshall 	if (loc && ntflag) {
39326049Sminshall 		argv[2] = dotrans(argv[2]);
39426049Sminshall 	}
39526049Sminshall 	if (loc && mapflag) {
39626049Sminshall 		argv[2] = domap(argv[2]);
39726049Sminshall 	}
39837225Skarels 	sendrequest(cmd, argv[1], argv[2],
39937225Skarels 	    argv[1] != oldargv1 || argv[2] != oldargv2);
40010294Ssam }
40110294Ssam 
40210294Ssam /*
40311756Ssam  * Send multiple files.
40410294Ssam  */
40511353Ssam mput(argc, argv)
40611353Ssam 	char *argv[];
40711353Ssam {
40813212Ssam 	register int i;
40926049Sminshall 	int ointer, (*oldintr)(), mabort();
41026049Sminshall 	extern jmp_buf jabort;
41126049Sminshall 	char *tp;
41211353Ssam 
41311650Ssam 	if (argc < 2) {
41426497Sminshall 		(void) strcat(line, " ");
41511650Ssam 		printf("(local-files) ");
41626497Sminshall 		(void) gets(&line[strlen(line)]);
41711650Ssam 		makeargv();
41811650Ssam 		argc = margc;
41911650Ssam 		argv = margv;
42011353Ssam 	}
42111353Ssam 	if (argc < 2) {
42226049Sminshall 		printf("usage:%s local-files\n", argv[0]);
42326049Sminshall 		code = -1;
42411353Ssam 		return;
42511353Ssam 	}
42626049Sminshall 	mname = argv[0];
42726049Sminshall 	mflag = 1;
42826049Sminshall 	oldintr = signal(SIGINT, mabort);
42926049Sminshall 	(void) setjmp(jabort);
43026049Sminshall 	if (proxy) {
43126049Sminshall 		char *cp, *tp2, tmpbuf[MAXPATHLEN];
43226049Sminshall 
43326497Sminshall 		while ((cp = remglob(argv,0)) != NULL) {
43426049Sminshall 			if (*cp == 0) {
43526049Sminshall 				mflag = 0;
43626049Sminshall 				continue;
43726049Sminshall 			}
43826049Sminshall 			if (mflag && confirm(argv[0], cp)) {
43926049Sminshall 				tp = cp;
44026049Sminshall 				if (mcase) {
44126049Sminshall 					while (*tp && !islower(*tp)) {
44226049Sminshall 						tp++;
44326049Sminshall 					}
44426049Sminshall 					if (!*tp) {
44526049Sminshall 						tp = cp;
44626049Sminshall 						tp2 = tmpbuf;
44726049Sminshall 						while ((*tp2 = *tp) != NULL) {
44826049Sminshall 						     if (isupper(*tp2)) {
44926049Sminshall 						        *tp2 = 'a' + *tp2 - 'A';
45026049Sminshall 						     }
45126049Sminshall 						     tp++;
45226049Sminshall 						     tp2++;
45326049Sminshall 						}
45426049Sminshall 					}
45526049Sminshall 					tp = tmpbuf;
45626049Sminshall 				}
45726049Sminshall 				if (ntflag) {
45826049Sminshall 					tp = dotrans(tp);
45926049Sminshall 				}
46026049Sminshall 				if (mapflag) {
46126049Sminshall 					tp = domap(tp);
46226049Sminshall 				}
46337225Skarels 				sendrequest((sunique) ? "STOU" : "STOR",
46437225Skarels 				    cp, tp, cp != tp || !interactive);
46526049Sminshall 				if (!mflag && fromatty) {
46626049Sminshall 					ointer = interactive;
46726049Sminshall 					interactive = 1;
46826049Sminshall 					if (confirm("Continue with","mput")) {
46926049Sminshall 						mflag++;
47026049Sminshall 					}
47126049Sminshall 					interactive = ointer;
47226049Sminshall 				}
47326049Sminshall 			}
47426049Sminshall 		}
47526049Sminshall 		(void) signal(SIGINT, oldintr);
47626049Sminshall 		mflag = 0;
47726049Sminshall 		return;
47826049Sminshall 	}
47913212Ssam 	for (i = 1; i < argc; i++) {
48013212Ssam 		register char **cpp, **gargs;
48113212Ssam 
48213212Ssam 		if (!doglob) {
48326049Sminshall 			if (mflag && confirm(argv[0], argv[i])) {
48426049Sminshall 				tp = (ntflag) ? dotrans(argv[i]) : argv[i];
48526049Sminshall 				tp = (mapflag) ? domap(tp) : tp;
48626049Sminshall 				sendrequest((sunique) ? "STOU" : "STOR",
48737225Skarels 				    argv[i], tp, tp != argv[i] || !interactive);
48826049Sminshall 				if (!mflag && fromatty) {
48926049Sminshall 					ointer = interactive;
49026049Sminshall 					interactive = 1;
49126049Sminshall 					if (confirm("Continue with","mput")) {
49226049Sminshall 						mflag++;
49326049Sminshall 					}
49426049Sminshall 					interactive = ointer;
49526049Sminshall 				}
49626049Sminshall 			}
49713212Ssam 			continue;
49813212Ssam 		}
49913212Ssam 		gargs = glob(argv[i]);
50011650Ssam 		if (globerr != NULL) {
50111650Ssam 			printf("%s\n", globerr);
50236421Sbostic 			if (gargs) {
50311650Ssam 				blkfree(gargs);
50436421Sbostic 				free(gargs);
50536421Sbostic 			}
50613212Ssam 			continue;
50711353Ssam 		}
50826049Sminshall 		for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
50926049Sminshall 			if (mflag && confirm(argv[0], *cpp)) {
51026049Sminshall 				tp = (ntflag) ? dotrans(*cpp) : *cpp;
51126049Sminshall 				tp = (mapflag) ? domap(tp) : tp;
51226049Sminshall 				sendrequest((sunique) ? "STOU" : "STOR",
51337225Skarels 				    *cpp, tp, *cpp != tp || !interactive);
51426049Sminshall 				if (!mflag && fromatty) {
51526049Sminshall 					ointer = interactive;
51626049Sminshall 					interactive = 1;
51726049Sminshall 					if (confirm("Continue with","mput")) {
51826049Sminshall 						mflag++;
51926049Sminshall 					}
52026049Sminshall 					interactive = ointer;
52126049Sminshall 				}
52226049Sminshall 			}
52326049Sminshall 		}
52436421Sbostic 		if (gargs != NULL) {
52513212Ssam 			blkfree(gargs);
52636421Sbostic 			free(gargs);
52736421Sbostic 		}
52811353Ssam 	}
52926049Sminshall 	(void) signal(SIGINT, oldintr);
53026049Sminshall 	mflag = 0;
53111353Ssam }
53211353Ssam 
53337224Skarels reget(argc, argv)
53437224Skarels 	char *argv[];
53537224Skarels {
53637224Skarels 	(void) getit(argc, argv, 1, "r+w");
53737224Skarels }
53836935Skarels 
53937224Skarels get(argc, argv)
54037224Skarels 	char *argv[];
54137224Skarels {
54237224Skarels 	(void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
54337224Skarels }
54437224Skarels 
54511353Ssam /*
54611353Ssam  * Receive one file.
54711353Ssam  */
54837224Skarels getit(argc, argv, restartit, mode)
54910294Ssam 	char *argv[];
55037224Skarels 	char *mode;
55110294Ssam {
55226049Sminshall 	int loc = 0;
55337225Skarels 	char *oldargv1, *oldargv2;
55410294Ssam 
55526049Sminshall 	if (argc == 2) {
55626049Sminshall 		argc++;
55726049Sminshall 		argv[2] = argv[1];
55826049Sminshall 		loc++;
55926049Sminshall 	}
56010294Ssam 	if (argc < 2) {
56126497Sminshall 		(void) strcat(line, " ");
56210294Ssam 		printf("(remote-file) ");
56326497Sminshall 		(void) gets(&line[strlen(line)]);
56410294Ssam 		makeargv();
56510294Ssam 		argc = margc;
56610294Ssam 		argv = margv;
56710294Ssam 	}
56810294Ssam 	if (argc < 2) {
56910294Ssam usage:
57026049Sminshall 		printf("usage: %s remote-file [ local-file ]\n", argv[0]);
57126049Sminshall 		code = -1;
57237224Skarels 		return (0);
57310294Ssam 	}
57410294Ssam 	if (argc < 3) {
57526497Sminshall 		(void) strcat(line, " ");
57610294Ssam 		printf("(local-file) ");
57726497Sminshall 		(void) gets(&line[strlen(line)]);
57810294Ssam 		makeargv();
57910294Ssam 		argc = margc;
58010294Ssam 		argv = margv;
58110294Ssam 	}
58210294Ssam 	if (argc < 3)
58310294Ssam 		goto usage;
58437225Skarels 	oldargv1 = argv[1];
58537225Skarels 	oldargv2 = argv[2];
58626049Sminshall 	if (!globulize(&argv[2])) {
58726049Sminshall 		code = -1;
58837224Skarels 		return (0);
58926049Sminshall 	}
59026049Sminshall 	if (loc && mcase) {
59126049Sminshall 		char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
59226049Sminshall 
59326049Sminshall 		while (*tp && !islower(*tp)) {
59426049Sminshall 			tp++;
59526049Sminshall 		}
59626049Sminshall 		if (!*tp) {
59726049Sminshall 			tp = argv[2];
59826049Sminshall 			tp2 = tmpbuf;
59926049Sminshall 			while ((*tp2 = *tp) != NULL) {
60026049Sminshall 				if (isupper(*tp2)) {
60126049Sminshall 					*tp2 = 'a' + *tp2 - 'A';
60226049Sminshall 				}
60326049Sminshall 				tp++;
60426049Sminshall 				tp2++;
60526049Sminshall 			}
60626049Sminshall 			argv[2] = tmpbuf;
60726049Sminshall 		}
60826049Sminshall 	}
60936940Skarels 	if (loc && ntflag)
61026049Sminshall 		argv[2] = dotrans(argv[2]);
61136940Skarels 	if (loc && mapflag)
61226049Sminshall 		argv[2] = domap(argv[2]);
61337224Skarels 	if (restartit) {
61437224Skarels 		struct stat stbuf;
61537224Skarels 		int ret;
61637224Skarels 
61737224Skarels 		ret = stat(argv[2], &stbuf);
61837224Skarels 		if (restartit == 1) {
61937224Skarels 			if (ret < 0) {
62037224Skarels 				perror(argv[2]);
62137224Skarels 				return (0);
62237224Skarels 			}
62337224Skarels 			restart_point = stbuf.st_size;
62437224Skarels 		} else {
62537224Skarels 			if (ret == 0) {
62637224Skarels 				int overbose;
62737224Skarels 
62837224Skarels 				overbose = verbose;
62937224Skarels 				if (debug == 0)
63037224Skarels 					verbose = -1;
63137224Skarels 				if (command("MDTM %s", argv[1]) == COMPLETE) {
63237224Skarels 					int yy, mo, day, hour, min, sec;
63337224Skarels 					struct tm *tm;
63437224Skarels 					verbose = overbose;
63537224Skarels 					sscanf(reply_string,
63637224Skarels 					    "%*s %04d%02d%02d%02d%02d%02d",
63737224Skarels 					    &yy, &mo, &day, &hour, &min, &sec);
63837224Skarels 					tm = gmtime(&stbuf.st_mtime);
63937224Skarels 					tm->tm_mon++;
64037224Skarels 					if (tm->tm_year > yy%100)
64137224Skarels 						return (1);
64237224Skarels 					else if (tm->tm_year == yy%100) {
64337224Skarels 						if (tm->tm_mon > mo)
64437224Skarels 							return (1);
64537224Skarels 					} else if (tm->tm_mon == mo) {
64637224Skarels 						if (tm->tm_mday > day)
64737224Skarels 							return (1);
64837224Skarels 					} else if (tm->tm_mday == day) {
64937224Skarels 						if (tm->tm_hour > hour)
65037224Skarels 							return (1);
65137224Skarels 					} else if (tm->tm_hour == hour) {
65237224Skarels 						if (tm->tm_min > min)
65337224Skarels 							return (1);
65437224Skarels 					} else if (tm->tm_min == min) {
65537224Skarels 						if (tm->tm_sec > sec)
65637224Skarels 							return (1);
65737224Skarels 					}
65837224Skarels 				} else {
65937224Skarels 					fputs(reply_string, stdout);
66037224Skarels 					verbose = overbose;
66137224Skarels 					return (0);
66237224Skarels 				}
66337224Skarels 			}
66437224Skarels 		}
66537224Skarels 	}
66637224Skarels 
66737225Skarels 	recvrequest("RETR", argv[2], argv[1], mode,
66837225Skarels 	    argv[1] != oldargv1 || argv[2] != oldargv2);
66937224Skarels 	restart_point = 0;
67037224Skarels 	return (0);
67110294Ssam }
67210294Ssam 
67326049Sminshall mabort()
67426049Sminshall {
67526049Sminshall 	int ointer;
67626049Sminshall 	extern jmp_buf jabort;
67726049Sminshall 
67826049Sminshall 	printf("\n");
67926049Sminshall 	(void) fflush(stdout);
68026049Sminshall 	if (mflag && fromatty) {
68126049Sminshall 		ointer = interactive;
68226049Sminshall 		interactive = 1;
68326049Sminshall 		if (confirm("Continue with", mname)) {
68426049Sminshall 			interactive = ointer;
68526049Sminshall 			longjmp(jabort,0);
68626049Sminshall 		}
68726049Sminshall 		interactive = ointer;
68826049Sminshall 	}
68926049Sminshall 	mflag = 0;
69026049Sminshall 	longjmp(jabort,0);
69126049Sminshall }
69226049Sminshall 
69311353Ssam /*
69411353Ssam  * Get multiple files.
69511353Ssam  */
69611353Ssam mget(argc, argv)
69711353Ssam 	char *argv[];
69811353Ssam {
69926049Sminshall 	char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
70026049Sminshall 	int ointer, (*oldintr)(), mabort();
70126049Sminshall 	extern jmp_buf jabort;
70211353Ssam 
70311353Ssam 	if (argc < 2) {
70426497Sminshall 		(void) strcat(line, " ");
70511756Ssam 		printf("(remote-files) ");
70626497Sminshall 		(void) gets(&line[strlen(line)]);
70711353Ssam 		makeargv();
70811353Ssam 		argc = margc;
70911353Ssam 		argv = margv;
71011353Ssam 	}
71111353Ssam 	if (argc < 2) {
71226049Sminshall 		printf("usage:%s remote-files\n", argv[0]);
71326049Sminshall 		code = -1;
71411353Ssam 		return;
71511353Ssam 	}
71626049Sminshall 	mname = argv[0];
71726049Sminshall 	mflag = 1;
71826049Sminshall 	oldintr = signal(SIGINT,mabort);
71926049Sminshall 	(void) setjmp(jabort);
72026497Sminshall 	while ((cp = remglob(argv,proxy)) != NULL) {
72126049Sminshall 		if (*cp == '\0') {
72226049Sminshall 			mflag = 0;
72326049Sminshall 			continue;
72426049Sminshall 		}
72526049Sminshall 		if (mflag && confirm(argv[0], cp)) {
72626049Sminshall 			tp = cp;
72726049Sminshall 			if (mcase) {
72826049Sminshall 				while (*tp && !islower(*tp)) {
72926049Sminshall 					tp++;
73026049Sminshall 				}
73126049Sminshall 				if (!*tp) {
73226049Sminshall 					tp = cp;
73326049Sminshall 					tp2 = tmpbuf;
73426049Sminshall 					while ((*tp2 = *tp) != NULL) {
73526049Sminshall 						if (isupper(*tp2)) {
73626049Sminshall 							*tp2 = 'a' + *tp2 - 'A';
73726049Sminshall 						}
73826049Sminshall 						tp++;
73926049Sminshall 						tp2++;
74026049Sminshall 					}
74126049Sminshall 				}
74226049Sminshall 				tp = tmpbuf;
74326049Sminshall 			}
74426049Sminshall 			if (ntflag) {
74526049Sminshall 				tp = dotrans(tp);
74626049Sminshall 			}
74726049Sminshall 			if (mapflag) {
74826049Sminshall 				tp = domap(tp);
74926049Sminshall 			}
75037225Skarels 			recvrequest("RETR", tp, cp, "w",
75137225Skarels 			    tp != cp || !interactive);
75226049Sminshall 			if (!mflag && fromatty) {
75326049Sminshall 				ointer = interactive;
75426049Sminshall 				interactive = 1;
75526049Sminshall 				if (confirm("Continue with","mget")) {
75626049Sminshall 					mflag++;
75726049Sminshall 				}
75826049Sminshall 				interactive = ointer;
75926049Sminshall 			}
76026049Sminshall 		}
76126049Sminshall 	}
76226049Sminshall 	(void) signal(SIGINT,oldintr);
76326049Sminshall 	mflag = 0;
76411650Ssam }
76511650Ssam 
76611650Ssam char *
76726497Sminshall remglob(argv,doswitch)
76811650Ssam 	char *argv[];
76926497Sminshall 	int doswitch;
77011650Ssam {
77111756Ssam 	char temp[16];
77211650Ssam 	static char buf[MAXPATHLEN];
77311650Ssam 	static FILE *ftemp = NULL;
77411650Ssam 	static char **args;
77513212Ssam 	int oldverbose, oldhash;
77611756Ssam 	char *cp, *mode;
77711650Ssam 
77826049Sminshall 	if (!mflag) {
77926049Sminshall 		if (!doglob) {
78026049Sminshall 			args = NULL;
78126049Sminshall 		}
78226049Sminshall 		else {
78326049Sminshall 			if (ftemp) {
78426497Sminshall 				(void) fclose(ftemp);
78526049Sminshall 				ftemp = NULL;
78626049Sminshall 			}
78726049Sminshall 		}
78826049Sminshall 		return(NULL);
78926049Sminshall 	}
79011650Ssam 	if (!doglob) {
79111756Ssam 		if (args == NULL)
79211650Ssam 			args = argv;
79311650Ssam 		if ((cp = *++args) == NULL)
79411650Ssam 			args = NULL;
79511650Ssam 		return (cp);
79611353Ssam 	}
79711650Ssam 	if (ftemp == NULL) {
79837458Skarels 		(void) strcpy(temp, _PATH_TMP);
79926497Sminshall 		(void) mktemp(temp);
80011650Ssam 		oldverbose = verbose, verbose = 0;
80113212Ssam 		oldhash = hash, hash = 0;
80226049Sminshall 		if (doswitch) {
80326049Sminshall 			pswitch(!proxy);
80426049Sminshall 		}
80511756Ssam 		for (mode = "w"; *++argv != NULL; mode = "a")
80637225Skarels 			recvrequest ("NLST", temp, *argv, mode, 0);
80726049Sminshall 		if (doswitch) {
80826049Sminshall 			pswitch(!proxy);
80926049Sminshall 		}
81013212Ssam 		verbose = oldverbose; hash = oldhash;
81111650Ssam 		ftemp = fopen(temp, "r");
81226497Sminshall 		(void) unlink(temp);
81311650Ssam 		if (ftemp == NULL) {
81411650Ssam 			printf("can't find list of remote files, oops\n");
81511756Ssam 			return (NULL);
81611353Ssam 		}
81711353Ssam 	}
81811650Ssam 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
81926497Sminshall 		(void) fclose(ftemp), ftemp = NULL;
82011650Ssam 		return (NULL);
82111353Ssam 	}
82211650Ssam 	if ((cp = index(buf, '\n')) != NULL)
82311650Ssam 		*cp = '\0';
82411650Ssam 	return (buf);
82511353Ssam }
82611353Ssam 
82710294Ssam char *
82810294Ssam onoff(bool)
82910294Ssam 	int bool;
83010294Ssam {
83110294Ssam 
83210294Ssam 	return (bool ? "on" : "off");
83310294Ssam }
83410294Ssam 
83510294Ssam /*
83610294Ssam  * Show status.
83710294Ssam  */
83826497Sminshall /*ARGSUSED*/
83910294Ssam status(argc, argv)
84010294Ssam 	char *argv[];
84110294Ssam {
84226049Sminshall 	int i;
84310294Ssam 
84410294Ssam 	if (connected)
84510294Ssam 		printf("Connected to %s.\n", hostname);
84610294Ssam 	else
84710294Ssam 		printf("Not connected.\n");
84826049Sminshall 	if (!proxy) {
84926049Sminshall 		pswitch(1);
85026049Sminshall 		if (connected) {
85126049Sminshall 			printf("Connected for proxy commands to %s.\n", hostname);
85226049Sminshall 		}
85326049Sminshall 		else {
85426049Sminshall 			printf("No proxy connection.\n");
85526049Sminshall 		}
85626049Sminshall 		pswitch(0);
85726049Sminshall 	}
85810294Ssam 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
85910294Ssam 		modename, typename, formname, structname);
86011353Ssam 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
86111353Ssam 		onoff(verbose), onoff(bell), onoff(interactive),
86211353Ssam 		onoff(doglob));
86326049Sminshall 	printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
86426049Sminshall 		onoff(runique));
86526049Sminshall 	printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
86626049Sminshall 	if (ntflag) {
86726049Sminshall 		printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
86826049Sminshall 	}
86926049Sminshall 	else {
87026049Sminshall 		printf("Ntrans: off\n");
87126049Sminshall 	}
87226049Sminshall 	if (mapflag) {
87326049Sminshall 		printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
87426049Sminshall 	}
87526049Sminshall 	else {
87626049Sminshall 		printf("Nmap: off\n");
87726049Sminshall 	}
87814143Ssam 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
87914143Ssam 		onoff(hash), onoff(sendport));
88026049Sminshall 	if (macnum > 0) {
88126049Sminshall 		printf("Macros:\n");
88226049Sminshall 		for (i=0; i<macnum; i++) {
88326049Sminshall 			printf("\t%s\n",macros[i].mac_name);
88426049Sminshall 		}
88526049Sminshall 	}
88626049Sminshall 	code = 0;
88710294Ssam }
88810294Ssam 
88910294Ssam /*
89010294Ssam  * Set beep on cmd completed mode.
89110294Ssam  */
89210294Ssam /*VARARGS*/
89310294Ssam setbell()
89410294Ssam {
89510294Ssam 
89610294Ssam 	bell = !bell;
89710294Ssam 	printf("Bell mode %s.\n", onoff(bell));
89826049Sminshall 	code = bell;
89910294Ssam }
90010294Ssam 
90110294Ssam /*
90210294Ssam  * Turn on packet tracing.
90310294Ssam  */
90410294Ssam /*VARARGS*/
90510294Ssam settrace()
90610294Ssam {
90710294Ssam 
90810294Ssam 	trace = !trace;
90910294Ssam 	printf("Packet tracing %s.\n", onoff(trace));
91026049Sminshall 	code = trace;
91110294Ssam }
91210294Ssam 
91310294Ssam /*
91411650Ssam  * Toggle hash mark printing during transfers.
91511650Ssam  */
91611650Ssam /*VARARGS*/
91711650Ssam sethash()
91811650Ssam {
91911650Ssam 
92011650Ssam 	hash = !hash;
92111650Ssam 	printf("Hash mark printing %s", onoff(hash));
92226049Sminshall 	code = hash;
92311650Ssam 	if (hash)
92437224Skarels 		printf(" (%d bytes/hash mark)", 1024);
92511650Ssam 	printf(".\n");
92611650Ssam }
92711650Ssam 
92811650Ssam /*
92910294Ssam  * Turn on printing of server echo's.
93010294Ssam  */
93110294Ssam /*VARARGS*/
93210294Ssam setverbose()
93310294Ssam {
93410294Ssam 
93510294Ssam 	verbose = !verbose;
93610294Ssam 	printf("Verbose mode %s.\n", onoff(verbose));
93726049Sminshall 	code = verbose;
93810294Ssam }
93910294Ssam 
94010294Ssam /*
94111650Ssam  * Toggle PORT cmd use before each data connection.
94211650Ssam  */
94311650Ssam /*VARARGS*/
94411650Ssam setport()
94511650Ssam {
94611650Ssam 
94711650Ssam 	sendport = !sendport;
94811650Ssam 	printf("Use of PORT cmds %s.\n", onoff(sendport));
94926049Sminshall 	code = sendport;
95011650Ssam }
95111650Ssam 
95211650Ssam /*
95310294Ssam  * Turn on interactive prompting
95410294Ssam  * during mget, mput, and mdelete.
95510294Ssam  */
95610294Ssam /*VARARGS*/
95710294Ssam setprompt()
95810294Ssam {
95910294Ssam 
96010294Ssam 	interactive = !interactive;
96110294Ssam 	printf("Interactive mode %s.\n", onoff(interactive));
96226049Sminshall 	code = interactive;
96310294Ssam }
96410294Ssam 
96510294Ssam /*
96611353Ssam  * Toggle metacharacter interpretation
96711353Ssam  * on local file names.
96811353Ssam  */
96911353Ssam /*VARARGS*/
97011353Ssam setglob()
97111353Ssam {
97211353Ssam 
97311353Ssam 	doglob = !doglob;
97411353Ssam 	printf("Globbing %s.\n", onoff(doglob));
97526049Sminshall 	code = doglob;
97611353Ssam }
97711353Ssam 
97811353Ssam /*
97910294Ssam  * Set debugging mode on/off and/or
98010294Ssam  * set level of debugging.
98110294Ssam  */
98211756Ssam /*VARARGS*/
98310294Ssam setdebug(argc, argv)
98410294Ssam 	char *argv[];
98510294Ssam {
98610294Ssam 	int val;
98710294Ssam 
98810294Ssam 	if (argc > 1) {
98910294Ssam 		val = atoi(argv[1]);
99010294Ssam 		if (val < 0) {
99110294Ssam 			printf("%s: bad debugging value.\n", argv[1]);
99226049Sminshall 			code = -1;
99310294Ssam 			return;
99410294Ssam 		}
99510294Ssam 	} else
99610294Ssam 		val = !debug;
99710294Ssam 	debug = val;
99810294Ssam 	if (debug)
99910294Ssam 		options |= SO_DEBUG;
100010294Ssam 	else
100110294Ssam 		options &= ~SO_DEBUG;
100210294Ssam 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
100326049Sminshall 	code = debug > 0;
100410294Ssam }
100510294Ssam 
100610294Ssam /*
100710294Ssam  * Set current working directory
100810294Ssam  * on remote machine.
100910294Ssam  */
101010294Ssam cd(argc, argv)
101110294Ssam 	char *argv[];
101210294Ssam {
101310294Ssam 
101410294Ssam 	if (argc < 2) {
101526497Sminshall 		(void) strcat(line, " ");
101610294Ssam 		printf("(remote-directory) ");
101726497Sminshall 		(void) gets(&line[strlen(line)]);
101810294Ssam 		makeargv();
101910294Ssam 		argc = margc;
102010294Ssam 		argv = margv;
102110294Ssam 	}
102210294Ssam 	if (argc < 2) {
102326049Sminshall 		printf("usage:%s remote-directory\n", argv[0]);
102426049Sminshall 		code = -1;
102510294Ssam 		return;
102610294Ssam 	}
102737224Skarels 	if (command("CWD %s", argv[1]) == ERROR && code == 500) {
102837224Skarels 		if (verbose)
102937224Skarels 			printf("CWD command not recognized, trying XCWD\n");
103037224Skarels 		(void) command("XCWD %s", argv[1]);
103137224Skarels 	}
103210294Ssam }
103310294Ssam 
103410294Ssam /*
103510294Ssam  * Set current working directory
103610294Ssam  * on local machine.
103710294Ssam  */
103810294Ssam lcd(argc, argv)
103910294Ssam 	char *argv[];
104010294Ssam {
104111353Ssam 	char buf[MAXPATHLEN];
104210294Ssam 
104311353Ssam 	if (argc < 2)
104411353Ssam 		argc++, argv[1] = home;
104510294Ssam 	if (argc != 2) {
104626049Sminshall 		printf("usage:%s local-directory\n", argv[0]);
104726049Sminshall 		code = -1;
104810294Ssam 		return;
104910294Ssam 	}
105026049Sminshall 	if (!globulize(&argv[1])) {
105126049Sminshall 		code = -1;
105211353Ssam 		return;
105326049Sminshall 	}
105411353Ssam 	if (chdir(argv[1]) < 0) {
105510294Ssam 		perror(argv[1]);
105626049Sminshall 		code = -1;
105711353Ssam 		return;
105811353Ssam 	}
105911353Ssam 	printf("Local directory now %s\n", getwd(buf));
106026049Sminshall 	code = 0;
106110294Ssam }
106210294Ssam 
106310294Ssam /*
106410294Ssam  * Delete a single file.
106510294Ssam  */
106610294Ssam delete(argc, argv)
106710294Ssam 	char *argv[];
106810294Ssam {
106910294Ssam 
107010294Ssam 	if (argc < 2) {
107126497Sminshall 		(void) strcat(line, " ");
107210294Ssam 		printf("(remote-file) ");
107326497Sminshall 		(void) gets(&line[strlen(line)]);
107410294Ssam 		makeargv();
107510294Ssam 		argc = margc;
107610294Ssam 		argv = margv;
107710294Ssam 	}
107810294Ssam 	if (argc < 2) {
107926049Sminshall 		printf("usage:%s remote-file\n", argv[0]);
108026049Sminshall 		code = -1;
108110294Ssam 		return;
108210294Ssam 	}
108310294Ssam 	(void) command("DELE %s", argv[1]);
108410294Ssam }
108510294Ssam 
108610294Ssam /*
108711650Ssam  * Delete multiple files.
108811650Ssam  */
108911650Ssam mdelete(argc, argv)
109011650Ssam 	char *argv[];
109111650Ssam {
109211650Ssam 	char *cp;
109326049Sminshall 	int ointer, (*oldintr)(), mabort();
109426049Sminshall 	extern jmp_buf jabort;
109511650Ssam 
109611650Ssam 	if (argc < 2) {
109726497Sminshall 		(void) strcat(line, " ");
109811650Ssam 		printf("(remote-files) ");
109926497Sminshall 		(void) gets(&line[strlen(line)]);
110011650Ssam 		makeargv();
110111650Ssam 		argc = margc;
110211650Ssam 		argv = margv;
110311650Ssam 	}
110411650Ssam 	if (argc < 2) {
110526049Sminshall 		printf("usage:%s remote-files\n", argv[0]);
110626049Sminshall 		code = -1;
110711650Ssam 		return;
110811650Ssam 	}
110926049Sminshall 	mname = argv[0];
111026049Sminshall 	mflag = 1;
111126049Sminshall 	oldintr = signal(SIGINT, mabort);
111226049Sminshall 	(void) setjmp(jabort);
111326497Sminshall 	while ((cp = remglob(argv,0)) != NULL) {
111426049Sminshall 		if (*cp == '\0') {
111526049Sminshall 			mflag = 0;
111626049Sminshall 			continue;
111726049Sminshall 		}
111826049Sminshall 		if (mflag && confirm(argv[0], cp)) {
111911650Ssam 			(void) command("DELE %s", cp);
112026049Sminshall 			if (!mflag && fromatty) {
112126049Sminshall 				ointer = interactive;
112226049Sminshall 				interactive = 1;
112326049Sminshall 				if (confirm("Continue with", "mdelete")) {
112426049Sminshall 					mflag++;
112526049Sminshall 				}
112626049Sminshall 				interactive = ointer;
112726049Sminshall 			}
112826049Sminshall 		}
112926049Sminshall 	}
113026049Sminshall 	(void) signal(SIGINT, oldintr);
113126049Sminshall 	mflag = 0;
113211650Ssam }
113311756Ssam 
113411650Ssam /*
113510294Ssam  * Rename a remote file.
113610294Ssam  */
113710294Ssam renamefile(argc, argv)
113810294Ssam 	char *argv[];
113910294Ssam {
114010294Ssam 
114110294Ssam 	if (argc < 2) {
114226497Sminshall 		(void) strcat(line, " ");
114310294Ssam 		printf("(from-name) ");
114426497Sminshall 		(void) gets(&line[strlen(line)]);
114510294Ssam 		makeargv();
114610294Ssam 		argc = margc;
114710294Ssam 		argv = margv;
114810294Ssam 	}
114910294Ssam 	if (argc < 2) {
115010294Ssam usage:
115110294Ssam 		printf("%s from-name to-name\n", argv[0]);
115226049Sminshall 		code = -1;
115310294Ssam 		return;
115410294Ssam 	}
115510294Ssam 	if (argc < 3) {
115626497Sminshall 		(void) strcat(line, " ");
115710294Ssam 		printf("(to-name) ");
115826497Sminshall 		(void) gets(&line[strlen(line)]);
115910294Ssam 		makeargv();
116010294Ssam 		argc = margc;
116110294Ssam 		argv = margv;
116210294Ssam 	}
116310294Ssam 	if (argc < 3)
116410294Ssam 		goto usage;
116510294Ssam 	if (command("RNFR %s", argv[1]) == CONTINUE)
116610294Ssam 		(void) command("RNTO %s", argv[2]);
116710294Ssam }
116810294Ssam 
116910294Ssam /*
117010294Ssam  * Get a directory listing
117110294Ssam  * of remote files.
117210294Ssam  */
117310294Ssam ls(argc, argv)
117410294Ssam 	char *argv[];
117510294Ssam {
117611756Ssam 	char *cmd;
117710294Ssam 
117810294Ssam 	if (argc < 2)
117910294Ssam 		argc++, argv[1] = NULL;
118010294Ssam 	if (argc < 3)
118110294Ssam 		argc++, argv[2] = "-";
118211756Ssam 	if (argc > 3) {
118311756Ssam 		printf("usage: %s remote-directory local-file\n", argv[0]);
118426049Sminshall 		code = -1;
118511756Ssam 		return;
118611756Ssam 	}
118736935Skarels 	cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
118826049Sminshall 	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
118926049Sminshall 		code = -1;
119011353Ssam 		return;
119126049Sminshall 	}
119232344Scsvsj 	if (strcmp(argv[2], "-") && *argv[2] != '|')
119332344Scsvsj 		if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
119432344Scsvsj 			code = -1;
119532344Scsvsj 			return;
119632344Scsvsj 	}
119737225Skarels 	recvrequest(cmd, argv[2], argv[1], "w", 0);
119810294Ssam }
119910294Ssam 
120010294Ssam /*
120111756Ssam  * Get a directory listing
120211756Ssam  * of multiple remote files.
120311756Ssam  */
120411756Ssam mls(argc, argv)
120511756Ssam 	char *argv[];
120611756Ssam {
120726049Sminshall 	char *cmd, mode[1], *dest;
120826049Sminshall 	int ointer, i, (*oldintr)(), mabort();
120926049Sminshall 	extern jmp_buf jabort;
121011756Ssam 
121113212Ssam 	if (argc < 2) {
121226497Sminshall 		(void) strcat(line, " ");
121313212Ssam 		printf("(remote-files) ");
121426497Sminshall 		(void) gets(&line[strlen(line)]);
121513212Ssam 		makeargv();
121613212Ssam 		argc = margc;
121713212Ssam 		argv = margv;
121813212Ssam 	}
121913212Ssam 	if (argc < 3) {
122026497Sminshall 		(void) strcat(line, " ");
122113212Ssam 		printf("(local-file) ");
122226497Sminshall 		(void) gets(&line[strlen(line)]);
122313212Ssam 		makeargv();
122413212Ssam 		argc = margc;
122513212Ssam 		argv = margv;
122613212Ssam 	}
122713212Ssam 	if (argc < 3) {
122826049Sminshall 		printf("usage:%s remote-files local-file\n", argv[0]);
122926049Sminshall 		code = -1;
123013212Ssam 		return;
123113212Ssam 	}
123213212Ssam 	dest = argv[argc - 1];
123313212Ssam 	argv[argc - 1] = NULL;
123426049Sminshall 	if (strcmp(dest, "-") && *dest != '|')
123526049Sminshall 		if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
123626049Sminshall 			code = -1;
123713212Ssam 			return;
123826049Sminshall 	}
123936940Skarels 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
124026049Sminshall 	mname = argv[0];
124126049Sminshall 	mflag = 1;
124226049Sminshall 	oldintr = signal(SIGINT, mabort);
124326049Sminshall 	(void) setjmp(jabort);
124426049Sminshall 	for (i = 1; mflag && i < argc-1; ++i) {
124526049Sminshall 		*mode = (i == 1) ? 'w' : 'a';
124637225Skarels 		recvrequest(cmd, dest, argv[i], mode, 0);
124726049Sminshall 		if (!mflag && fromatty) {
124826049Sminshall 			ointer = interactive;
124926049Sminshall 			interactive = 1;
125026049Sminshall 			if (confirm("Continue with", argv[0])) {
125126049Sminshall 				mflag ++;
125226049Sminshall 			}
125326049Sminshall 			interactive = ointer;
125426049Sminshall 		}
125526049Sminshall 	}
125626049Sminshall 	(void) signal(SIGINT, oldintr);
125726049Sminshall 	mflag = 0;
125811756Ssam }
125911756Ssam 
126011756Ssam /*
126110294Ssam  * Do a shell escape
126210294Ssam  */
126326497Sminshall /*ARGSUSED*/
126410294Ssam shell(argc, argv)
126510294Ssam 	char *argv[];
126610294Ssam {
126726497Sminshall 	int pid, (*old1)(), (*old2)();
126826049Sminshall 	char shellnam[40], *shell, *namep;
126926497Sminshall 	union wait status;
127010294Ssam 
127111756Ssam 	old1 = signal (SIGINT, SIG_IGN);
127211756Ssam 	old2 = signal (SIGQUIT, SIG_IGN);
127311756Ssam 	if ((pid = fork()) == 0) {
127411756Ssam 		for (pid = 3; pid < 20; pid++)
127526497Sminshall 			(void) close(pid);
127626497Sminshall 		(void) signal(SIGINT, SIG_DFL);
127726497Sminshall 		(void) signal(SIGQUIT, SIG_DFL);
127825908Smckusick 		shell = getenv("SHELL");
127925908Smckusick 		if (shell == NULL)
128037458Skarels 			shell = _PATH_BSHELL;
128125908Smckusick 		namep = rindex(shell,'/');
128225908Smckusick 		if (namep == NULL)
128325908Smckusick 			namep = shell;
128426497Sminshall 		(void) strcpy(shellnam,"-");
128526497Sminshall 		(void) strcat(shellnam, ++namep);
128626049Sminshall 		if (strcmp(namep, "sh") != 0)
128726049Sminshall 			shellnam[0] = '+';
128826049Sminshall 		if (debug) {
128926049Sminshall 			printf ("%s\n", shell);
129026497Sminshall 			(void) fflush (stdout);
129111756Ssam 		}
129226049Sminshall 		if (argc > 1) {
129326049Sminshall 			execl(shell,shellnam,"-c",altarg,(char *)0);
129426049Sminshall 		}
129526049Sminshall 		else {
129626049Sminshall 			execl(shell,shellnam,(char *)0);
129726049Sminshall 		}
129825908Smckusick 		perror(shell);
129926049Sminshall 		code = -1;
130011756Ssam 		exit(1);
130126049Sminshall 		}
130211756Ssam 	if (pid > 0)
130311756Ssam 		while (wait(&status) != pid)
130411756Ssam 			;
130526497Sminshall 	(void) signal(SIGINT, old1);
130626497Sminshall 	(void) signal(SIGQUIT, old2);
130726049Sminshall 	if (pid == -1) {
130811756Ssam 		perror("Try again later");
130926049Sminshall 		code = -1;
131026049Sminshall 	}
131126049Sminshall 	else {
131226049Sminshall 		code = 0;
131326049Sminshall 	}
131411756Ssam 	return (0);
131510294Ssam }
131610294Ssam 
131710294Ssam /*
131810294Ssam  * Send new user information (re-login)
131910294Ssam  */
132010294Ssam user(argc, argv)
132110294Ssam 	int argc;
132210294Ssam 	char **argv;
132310294Ssam {
132435658Sbostic 	char acct[80], *getpass();
132526049Sminshall 	int n, aflag = 0;
132610294Ssam 
132710294Ssam 	if (argc < 2) {
132826497Sminshall 		(void) strcat(line, " ");
132910294Ssam 		printf("(username) ");
133026497Sminshall 		(void) gets(&line[strlen(line)]);
133110294Ssam 		makeargv();
133210294Ssam 		argc = margc;
133310294Ssam 		argv = margv;
133410294Ssam 	}
133510294Ssam 	if (argc > 4) {
133610294Ssam 		printf("usage: %s username [password] [account]\n", argv[0]);
133726049Sminshall 		code = -1;
133811756Ssam 		return (0);
133910294Ssam 	}
134010294Ssam 	n = command("USER %s", argv[1]);
134110294Ssam 	if (n == CONTINUE) {
134210294Ssam 		if (argc < 3 )
134335658Sbostic 			argv[2] = getpass("Password: "), argc++;
134410294Ssam 		n = command("PASS %s", argv[2]);
134510294Ssam 	}
134610294Ssam 	if (n == CONTINUE) {
134710294Ssam 		if (argc < 4) {
134810294Ssam 			printf("Account: "); (void) fflush(stdout);
134910294Ssam 			(void) fgets(acct, sizeof(acct) - 1, stdin);
135010294Ssam 			acct[strlen(acct) - 1] = '\0';
135110294Ssam 			argv[3] = acct; argc++;
135210294Ssam 		}
135326049Sminshall 		n = command("ACCT %s", argv[3]);
135426049Sminshall 		aflag++;
135510294Ssam 	}
135610294Ssam 	if (n != COMPLETE) {
135726497Sminshall 		fprintf(stdout, "Login failed.\n");
135810294Ssam 		return (0);
135910294Ssam 	}
136026049Sminshall 	if (!aflag && argc == 4) {
136126049Sminshall 		(void) command("ACCT %s", argv[3]);
136226049Sminshall 	}
136310294Ssam 	return (1);
136410294Ssam }
136510294Ssam 
136610294Ssam /*
136710294Ssam  * Print working directory.
136810294Ssam  */
136910294Ssam /*VARARGS*/
137010294Ssam pwd()
137110294Ssam {
137237224Skarels 	int oldverbose = verbose;
137311756Ssam 
137437224Skarels 	/*
137537224Skarels 	 * If we aren't verbose, this doesn't do anything!
137637224Skarels 	 */
137737224Skarels 	verbose = 1;
137837224Skarels 	if (command("PWD") == ERROR && code == 500) {
137937224Skarels 		printf("PWD command not recognized, trying XPWD\n");
138037224Skarels 		(void) command("XPWD");
138137224Skarels 	}
138237224Skarels 	verbose = oldverbose;
138310294Ssam }
138410294Ssam 
138510294Ssam /*
138610294Ssam  * Make a directory.
138710294Ssam  */
138810294Ssam makedir(argc, argv)
138910294Ssam 	char *argv[];
139010294Ssam {
139110294Ssam 
139210294Ssam 	if (argc < 2) {
139326497Sminshall 		(void) strcat(line, " ");
139410294Ssam 		printf("(directory-name) ");
139526497Sminshall 		(void) gets(&line[strlen(line)]);
139610294Ssam 		makeargv();
139710294Ssam 		argc = margc;
139810294Ssam 		argv = margv;
139910294Ssam 	}
140010294Ssam 	if (argc < 2) {
140126049Sminshall 		printf("usage: %s directory-name\n", argv[0]);
140226049Sminshall 		code = -1;
140310294Ssam 		return;
140410294Ssam 	}
140537224Skarels 	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
140637224Skarels 		if (verbose)
140737224Skarels 			printf("MKD command not recognized, trying XMKD\n");
140837224Skarels 		(void) command("XMKD %s", argv[1]);
140937224Skarels 	}
141010294Ssam }
141110294Ssam 
141210294Ssam /*
141310294Ssam  * Remove a directory.
141410294Ssam  */
141510294Ssam removedir(argc, argv)
141610294Ssam 	char *argv[];
141710294Ssam {
141810294Ssam 
141910294Ssam 	if (argc < 2) {
142026497Sminshall 		(void) strcat(line, " ");
142110294Ssam 		printf("(directory-name) ");
142226497Sminshall 		(void) gets(&line[strlen(line)]);
142310294Ssam 		makeargv();
142410294Ssam 		argc = margc;
142510294Ssam 		argv = margv;
142610294Ssam 	}
142710294Ssam 	if (argc < 2) {
142826049Sminshall 		printf("usage: %s directory-name\n", argv[0]);
142926049Sminshall 		code = -1;
143010294Ssam 		return;
143110294Ssam 	}
143237224Skarels 	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
143337224Skarels 		if (verbose)
143437224Skarels 			printf("RMD command not recognized, trying XRMD\n");
143537224Skarels 		(void) command("XRMD %s", argv[1]);
143637224Skarels 	}
143710294Ssam }
143810294Ssam 
143910294Ssam /*
144010294Ssam  * Send a line, verbatim, to the remote machine.
144110294Ssam  */
144210294Ssam quote(argc, argv)
144310294Ssam 	char *argv[];
144410294Ssam {
144510294Ssam 	int i;
144610294Ssam 	char buf[BUFSIZ];
144710294Ssam 
144810294Ssam 	if (argc < 2) {
144926497Sminshall 		(void) strcat(line, " ");
145010294Ssam 		printf("(command line to send) ");
145126497Sminshall 		(void) gets(&line[strlen(line)]);
145210294Ssam 		makeargv();
145310294Ssam 		argc = margc;
145410294Ssam 		argv = margv;
145510294Ssam 	}
145610294Ssam 	if (argc < 2) {
145710294Ssam 		printf("usage: %s line-to-send\n", argv[0]);
145826049Sminshall 		code = -1;
145910294Ssam 		return;
146010294Ssam 	}
146126497Sminshall 	(void) strcpy(buf, argv[1]);
146210294Ssam 	for (i = 2; i < argc; i++) {
146326497Sminshall 		(void) strcat(buf, " ");
146426497Sminshall 		(void) strcat(buf, argv[i]);
146510294Ssam 	}
146626049Sminshall 	if (command(buf) == PRELIM) {
146726049Sminshall 		while (getreply(0) == PRELIM);
146826049Sminshall 	}
146910294Ssam }
147010294Ssam 
147110294Ssam /*
147237224Skarels  * Send a SITE command to the remote machine.  The line
147337224Skarels  * is sent almost verbatim to the remote machine, the
147437224Skarels  * first argument is changed to SITE.
147537224Skarels  */
147637224Skarels 
147737224Skarels site(argc, argv)
147837224Skarels 	char *argv[];
147937224Skarels {
148037224Skarels 	int i;
148137224Skarels 	char buf[BUFSIZ];
148237224Skarels 
148337224Skarels 	if (argc < 2) {
148437224Skarels 		(void) strcat(line, " ");
148537224Skarels 		printf("(arguments to SITE command) ");
148637224Skarels 		(void) gets(&line[strlen(line)]);
148737224Skarels 		makeargv();
148837224Skarels 		argc = margc;
148937224Skarels 		argv = margv;
149037224Skarels 	}
149137224Skarels 	if (argc < 2) {
149237224Skarels 		printf("usage: %s line-to-send\n", argv[0]);
149337224Skarels 		code = -1;
149437224Skarels 		return;
149537224Skarels 	}
149637224Skarels 	(void) strcpy(buf, "SITE ");
149737224Skarels 	(void) strcat(buf, argv[1]);
149837224Skarels 	for (i = 2; i < argc; i++) {
149937224Skarels 		(void) strcat(buf, " ");
150037224Skarels 		(void) strcat(buf, argv[i]);
150137224Skarels 	}
150237224Skarels 	if (command(buf) == PRELIM) {
150337224Skarels 		while (getreply(0) == PRELIM);
150437224Skarels 	}
150537224Skarels }
150637224Skarels 
150737224Skarels do_chmod(argc, argv)
150837224Skarels 	char *argv[];
150937224Skarels {
151037224Skarels 	if (argc == 2) {
151137224Skarels 		printf("usage: %s mode file-name\n", argv[0]);
151237224Skarels 		code = -1;
151337224Skarels 		return;
151437224Skarels 	}
151537224Skarels 	if (argc < 3) {
151637224Skarels 		(void) strcat(line, " ");
151737224Skarels 		printf("(mode and file-name) ");
151837224Skarels 		(void) gets(&line[strlen(line)]);
151937224Skarels 		makeargv();
152037224Skarels 		argc = margc;
152137224Skarels 		argv = margv;
152237224Skarels 	}
152337224Skarels 	if (argc != 3) {
152437224Skarels 		printf("usage: %s mode file-name\n", argv[0]);
152537224Skarels 		code = -1;
152637224Skarels 		return;
152737224Skarels 	}
152837224Skarels 	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
152937224Skarels }
153037224Skarels 
153137224Skarels do_umask(argc, argv)
153237224Skarels 	char *argv[];
153337224Skarels {
153437224Skarels 	int oldverbose = verbose;
153537224Skarels 
153637224Skarels 	verbose = 1;
153737224Skarels 	(void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
153837224Skarels 	verbose = oldverbose;
153937224Skarels }
154037224Skarels 
154137224Skarels idle(argc, argv)
154237224Skarels 	char *argv[];
154337224Skarels {
154437224Skarels 	int oldverbose = verbose;
154537224Skarels 
154637224Skarels 	verbose = 1;
154737224Skarels 	(void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
154837224Skarels 	verbose = oldverbose;
154937224Skarels }
155037224Skarels 
155137224Skarels /*
155210294Ssam  * Ask the other side for help.
155310294Ssam  */
155410294Ssam rmthelp(argc, argv)
155510294Ssam 	char *argv[];
155610294Ssam {
155710294Ssam 	int oldverbose = verbose;
155810294Ssam 
155910294Ssam 	verbose = 1;
156010294Ssam 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
156110294Ssam 	verbose = oldverbose;
156210294Ssam }
156310294Ssam 
156410294Ssam /*
156510294Ssam  * Terminate session and exit.
156610294Ssam  */
156710294Ssam /*VARARGS*/
156810294Ssam quit()
156910294Ssam {
157010294Ssam 
157118286Sralph 	if (connected)
157218286Sralph 		disconnect();
157326049Sminshall 	pswitch(1);
157426049Sminshall 	if (connected) {
157526049Sminshall 		disconnect();
157626049Sminshall 	}
157710294Ssam 	exit(0);
157810294Ssam }
157910294Ssam 
158010294Ssam /*
158110294Ssam  * Terminate session, but don't exit.
158210294Ssam  */
158310294Ssam disconnect()
158410294Ssam {
158510294Ssam 	extern FILE *cout;
158610294Ssam 	extern int data;
158710294Ssam 
158810294Ssam 	if (!connected)
158910294Ssam 		return;
159010294Ssam 	(void) command("QUIT");
159126049Sminshall 	if (cout) {
159226049Sminshall 		(void) fclose(cout);
159326049Sminshall 	}
159410294Ssam 	cout = NULL;
159510294Ssam 	connected = 0;
159610294Ssam 	data = -1;
159726049Sminshall 	if (!proxy) {
159826049Sminshall 		macnum = 0;
159926049Sminshall 	}
160010294Ssam }
160111353Ssam 
160211650Ssam confirm(cmd, file)
160311353Ssam 	char *cmd, *file;
160411353Ssam {
160511353Ssam 	char line[BUFSIZ];
160611353Ssam 
160711353Ssam 	if (!interactive)
160811650Ssam 		return (1);
160911353Ssam 	printf("%s %s? ", cmd, file);
161026497Sminshall 	(void) fflush(stdout);
161126497Sminshall 	(void) gets(line);
161211650Ssam 	return (*line != 'n' && *line != 'N');
161311353Ssam }
161411353Ssam 
161511353Ssam fatal(msg)
161611353Ssam 	char *msg;
161711353Ssam {
161811353Ssam 
161926497Sminshall 	fprintf(stderr, "ftp: %s\n", msg);
162011353Ssam 	exit(1);
162111353Ssam }
162211353Ssam 
162311353Ssam /*
162411353Ssam  * Glob a local file name specification with
162511353Ssam  * the expectation of a single return value.
162611353Ssam  * Can't control multiple values being expanded
162711353Ssam  * from the expression, we return only the first.
162811353Ssam  */
162911353Ssam globulize(cpp)
163011353Ssam 	char **cpp;
163111353Ssam {
163211353Ssam 	char **globbed;
163311353Ssam 
163411353Ssam 	if (!doglob)
163511353Ssam 		return (1);
163611353Ssam 	globbed = glob(*cpp);
163711353Ssam 	if (globerr != NULL) {
163811353Ssam 		printf("%s: %s\n", *cpp, globerr);
163936421Sbostic 		if (globbed) {
164011353Ssam 			blkfree(globbed);
164136421Sbostic 			free(globbed);
164236421Sbostic 		}
164311353Ssam 		return (0);
164411353Ssam 	}
164511353Ssam 	if (globbed) {
164611353Ssam 		*cpp = *globbed++;
164711353Ssam 		/* don't waste too much memory */
164836421Sbostic 		if (*globbed) {
164911353Ssam 			blkfree(globbed);
165036421Sbostic 			free(globbed);
165136421Sbostic 		}
165211353Ssam 	}
165311353Ssam 	return (1);
165411353Ssam }
165526049Sminshall 
165626049Sminshall account(argc,argv)
165726049Sminshall 	int argc;
165826049Sminshall 	char **argv;
165926049Sminshall {
166035658Sbostic 	char acct[50], *getpass(), *ap;
166126049Sminshall 
166226049Sminshall 	if (argc > 1) {
166326049Sminshall 		++argv;
166426049Sminshall 		--argc;
166526049Sminshall 		(void) strncpy(acct,*argv,49);
166636268Sbostic 		acct[49] = '\0';
166726049Sminshall 		while (argc > 1) {
166826049Sminshall 			--argc;
166926049Sminshall 			++argv;
167026049Sminshall 			(void) strncat(acct,*argv, 49-strlen(acct));
167126049Sminshall 		}
167226049Sminshall 		ap = acct;
167326049Sminshall 	}
167426049Sminshall 	else {
167535658Sbostic 		ap = getpass("Account:");
167626049Sminshall 	}
167726049Sminshall 	(void) command("ACCT %s", ap);
167826049Sminshall }
167926049Sminshall 
168026049Sminshall jmp_buf abortprox;
168126049Sminshall 
168226049Sminshall proxabort()
168326049Sminshall {
168426049Sminshall 	extern int proxy;
168526049Sminshall 
168626049Sminshall 	if (!proxy) {
168726049Sminshall 		pswitch(1);
168826049Sminshall 	}
168926049Sminshall 	if (connected) {
169026049Sminshall 		proxflag = 1;
169126049Sminshall 	}
169226049Sminshall 	else {
169326049Sminshall 		proxflag = 0;
169426049Sminshall 	}
169526049Sminshall 	pswitch(0);
169626049Sminshall 	longjmp(abortprox,1);
169726049Sminshall }
169826049Sminshall 
169926049Sminshall doproxy(argc,argv)
170026049Sminshall 	int argc;
170126049Sminshall 	char *argv[];
170226049Sminshall {
170326049Sminshall 	int (*oldintr)(), proxabort();
170426049Sminshall 	register struct cmd *c;
170526049Sminshall 	struct cmd *getcmd();
170626049Sminshall 	extern struct cmd cmdtab[];
170726049Sminshall 	extern jmp_buf abortprox;
170826049Sminshall 
170926049Sminshall 	if (argc < 2) {
171026497Sminshall 		(void) strcat(line, " ");
171126049Sminshall 		printf("(command) ");
171226497Sminshall 		(void) gets(&line[strlen(line)]);
171326049Sminshall 		makeargv();
171426049Sminshall 		argc = margc;
171526049Sminshall 		argv = margv;
171626049Sminshall 	}
171726049Sminshall 	if (argc < 2) {
171826049Sminshall 		printf("usage:%s command\n", argv[0]);
171926049Sminshall 		code = -1;
172026049Sminshall 		return;
172126049Sminshall 	}
172226049Sminshall 	c = getcmd(argv[1]);
172326049Sminshall 	if (c == (struct cmd *) -1) {
172426049Sminshall 		printf("?Ambiguous command\n");
172526497Sminshall 		(void) fflush(stdout);
172626049Sminshall 		code = -1;
172726049Sminshall 		return;
172826049Sminshall 	}
172926049Sminshall 	if (c == 0) {
173026049Sminshall 		printf("?Invalid command\n");
173126497Sminshall 		(void) fflush(stdout);
173226049Sminshall 		code = -1;
173326049Sminshall 		return;
173426049Sminshall 	}
173526049Sminshall 	if (!c->c_proxy) {
173626049Sminshall 		printf("?Invalid proxy command\n");
173726497Sminshall 		(void) fflush(stdout);
173826049Sminshall 		code = -1;
173926049Sminshall 		return;
174026049Sminshall 	}
174126049Sminshall 	if (setjmp(abortprox)) {
174226049Sminshall 		code = -1;
174326049Sminshall 		return;
174426049Sminshall 	}
174526049Sminshall 	oldintr = signal(SIGINT, proxabort);
174626049Sminshall 	pswitch(1);
174726049Sminshall 	if (c->c_conn && !connected) {
174826049Sminshall 		printf("Not connected\n");
174926497Sminshall 		(void) fflush(stdout);
175026049Sminshall 		pswitch(0);
175126049Sminshall 		(void) signal(SIGINT, oldintr);
175226049Sminshall 		code = -1;
175326049Sminshall 		return;
175426049Sminshall 	}
175526049Sminshall 	(*c->c_handler)(argc-1, argv+1);
175626049Sminshall 	if (connected) {
175726049Sminshall 		proxflag = 1;
175826049Sminshall 	}
175926049Sminshall 	else {
176026049Sminshall 		proxflag = 0;
176126049Sminshall 	}
176226049Sminshall 	pswitch(0);
176326049Sminshall 	(void) signal(SIGINT, oldintr);
176426049Sminshall }
176526049Sminshall 
176626049Sminshall setcase()
176726049Sminshall {
176826049Sminshall 	mcase = !mcase;
176926049Sminshall 	printf("Case mapping %s.\n", onoff(mcase));
177026049Sminshall 	code = mcase;
177126049Sminshall }
177226049Sminshall 
177326049Sminshall setcr()
177426049Sminshall {
177526049Sminshall 	crflag = !crflag;
177626049Sminshall 	printf("Carriage Return stripping %s.\n", onoff(crflag));
177726049Sminshall 	code = crflag;
177826049Sminshall }
177926049Sminshall 
178026049Sminshall setntrans(argc,argv)
178126049Sminshall 	int argc;
178226049Sminshall 	char *argv[];
178326049Sminshall {
178426049Sminshall 	if (argc == 1) {
178526049Sminshall 		ntflag = 0;
178626049Sminshall 		printf("Ntrans off.\n");
178726049Sminshall 		code = ntflag;
178826049Sminshall 		return;
178926049Sminshall 	}
179026049Sminshall 	ntflag++;
179126049Sminshall 	code = ntflag;
179226049Sminshall 	(void) strncpy(ntin, argv[1], 16);
179326049Sminshall 	ntin[16] = '\0';
179426049Sminshall 	if (argc == 2) {
179526049Sminshall 		ntout[0] = '\0';
179626049Sminshall 		return;
179726049Sminshall 	}
179826049Sminshall 	(void) strncpy(ntout, argv[2], 16);
179926049Sminshall 	ntout[16] = '\0';
180026049Sminshall }
180126049Sminshall 
180226049Sminshall char *
180326049Sminshall dotrans(name)
180426049Sminshall 	char *name;
180526049Sminshall {
180626049Sminshall 	static char new[MAXPATHLEN];
180726049Sminshall 	char *cp1, *cp2 = new;
180826049Sminshall 	register int i, ostop, found;
180926049Sminshall 
181026049Sminshall 	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
181126049Sminshall 	for (cp1 = name; *cp1; cp1++) {
181226049Sminshall 		found = 0;
181326049Sminshall 		for (i = 0; *(ntin + i) && i < 16; i++) {
181426049Sminshall 			if (*cp1 == *(ntin + i)) {
181526049Sminshall 				found++;
181626049Sminshall 				if (i < ostop) {
181726049Sminshall 					*cp2++ = *(ntout + i);
181826049Sminshall 				}
181926049Sminshall 				break;
182026049Sminshall 			}
182126049Sminshall 		}
182226049Sminshall 		if (!found) {
182326049Sminshall 			*cp2++ = *cp1;
182426049Sminshall 		}
182526049Sminshall 	}
182626049Sminshall 	*cp2 = '\0';
182726049Sminshall 	return(new);
182826049Sminshall }
182926049Sminshall 
183026049Sminshall setnmap(argc, argv)
183126049Sminshall 	int argc;
183226049Sminshall 	char *argv[];
183326049Sminshall {
183426049Sminshall 	char *cp;
183526049Sminshall 
183626049Sminshall 	if (argc == 1) {
183726049Sminshall 		mapflag = 0;
183826049Sminshall 		printf("Nmap off.\n");
183926049Sminshall 		code = mapflag;
184026049Sminshall 		return;
184126049Sminshall 	}
184226049Sminshall 	if (argc < 3) {
184326497Sminshall 		(void) strcat(line, " ");
184426049Sminshall 		printf("(mapout) ");
184526497Sminshall 		(void) gets(&line[strlen(line)]);
184626049Sminshall 		makeargv();
184726049Sminshall 		argc = margc;
184826049Sminshall 		argv = margv;
184926049Sminshall 	}
185026049Sminshall 	if (argc < 3) {
185126049Sminshall 		printf("Usage: %s [mapin mapout]\n",argv[0]);
185226049Sminshall 		code = -1;
185326049Sminshall 		return;
185426049Sminshall 	}
185526049Sminshall 	mapflag = 1;
185626049Sminshall 	code = 1;
185726049Sminshall 	cp = index(altarg, ' ');
185826049Sminshall 	if (proxy) {
185926049Sminshall 		while(*++cp == ' ');
186026049Sminshall 		altarg = cp;
186126049Sminshall 		cp = index(altarg, ' ');
186226049Sminshall 	}
186326049Sminshall 	*cp = '\0';
186426049Sminshall 	(void) strncpy(mapin, altarg, MAXPATHLEN - 1);
186526049Sminshall 	while (*++cp == ' ');
186626049Sminshall 	(void) strncpy(mapout, cp, MAXPATHLEN - 1);
186726049Sminshall }
186826049Sminshall 
186926049Sminshall char *
187026049Sminshall domap(name)
187126049Sminshall 	char *name;
187226049Sminshall {
187326049Sminshall 	static char new[MAXPATHLEN];
187426049Sminshall 	register char *cp1 = name, *cp2 = mapin;
187526049Sminshall 	char *tp[9], *te[9];
187636689Scsvsj 	int i, toks[9], toknum = 0, match = 1;
187726049Sminshall 
187826049Sminshall 	for (i=0; i < 9; ++i) {
187926049Sminshall 		toks[i] = 0;
188026049Sminshall 	}
188126049Sminshall 	while (match && *cp1 && *cp2) {
188226049Sminshall 		switch (*cp2) {
188326049Sminshall 			case '\\':
188426049Sminshall 				if (*++cp2 != *cp1) {
188526049Sminshall 					match = 0;
188626049Sminshall 				}
188726049Sminshall 				break;
188826049Sminshall 			case '$':
188926049Sminshall 				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
189026049Sminshall 					if (*cp1 != *(++cp2+1)) {
189126049Sminshall 						toks[toknum = *cp2 - '1']++;
189226049Sminshall 						tp[toknum] = cp1;
189326049Sminshall 						while (*++cp1 && *(cp2+1)
189426049Sminshall 							!= *cp1);
189526049Sminshall 						te[toknum] = cp1;
189626049Sminshall 					}
189726049Sminshall 					cp2++;
189826049Sminshall 					break;
189926049Sminshall 				}
190036935Skarels 				/* FALLTHROUGH */
190126049Sminshall 			default:
190226049Sminshall 				if (*cp2 != *cp1) {
190326049Sminshall 					match = 0;
190426049Sminshall 				}
190526049Sminshall 				break;
190626049Sminshall 		}
190736689Scsvsj 		if (match && *cp1) {
190826049Sminshall 			cp1++;
190926049Sminshall 		}
191036689Scsvsj 		if (match && *cp2) {
191126049Sminshall 			cp2++;
191226049Sminshall 		}
191326049Sminshall 	}
191436689Scsvsj 	if (!match && *cp1) /* last token mismatch */
191536689Scsvsj 	{
191636689Scsvsj 		toks[toknum] = 0;
191736689Scsvsj 	}
191826049Sminshall 	cp1 = new;
191926049Sminshall 	*cp1 = '\0';
192026049Sminshall 	cp2 = mapout;
192126049Sminshall 	while (*cp2) {
192226049Sminshall 		match = 0;
192326049Sminshall 		switch (*cp2) {
192426049Sminshall 			case '\\':
192526049Sminshall 				if (*(cp2 + 1)) {
192626049Sminshall 					*cp1++ = *++cp2;
192726049Sminshall 				}
192826049Sminshall 				break;
192926049Sminshall 			case '[':
193026049Sminshall LOOP:
193126049Sminshall 				if (*++cp2 == '$' && isdigit(*(cp2+1))) {
193226049Sminshall 					if (*++cp2 == '0') {
193326049Sminshall 						char *cp3 = name;
193426049Sminshall 
193526049Sminshall 						while (*cp3) {
193626049Sminshall 							*cp1++ = *cp3++;
193726049Sminshall 						}
193826049Sminshall 						match = 1;
193926049Sminshall 					}
194026049Sminshall 					else if (toks[toknum = *cp2 - '1']) {
194126049Sminshall 						char *cp3 = tp[toknum];
194226049Sminshall 
194326049Sminshall 						while (cp3 != te[toknum]) {
194426049Sminshall 							*cp1++ = *cp3++;
194526049Sminshall 						}
194626049Sminshall 						match = 1;
194726049Sminshall 					}
194826049Sminshall 				}
194926049Sminshall 				else {
195026049Sminshall 					while (*cp2 && *cp2 != ',' &&
195126049Sminshall 					    *cp2 != ']') {
195226049Sminshall 						if (*cp2 == '\\') {
195326049Sminshall 							cp2++;
195426049Sminshall 						}
195526049Sminshall 						else if (*cp2 == '$' &&
195626049Sminshall    						        isdigit(*(cp2+1))) {
195726049Sminshall 							if (*++cp2 == '0') {
195826049Sminshall 							   char *cp3 = name;
195926049Sminshall 
196026049Sminshall 							   while (*cp3) {
196126049Sminshall 								*cp1++ = *cp3++;
196226049Sminshall 							   }
196326049Sminshall 							}
196426049Sminshall 							else if (toks[toknum =
196526049Sminshall 							    *cp2 - '1']) {
196626049Sminshall 							   char *cp3=tp[toknum];
196726049Sminshall 
196826049Sminshall 							   while (cp3 !=
196926049Sminshall 								  te[toknum]) {
197026049Sminshall 								*cp1++ = *cp3++;
197126049Sminshall 							   }
197226049Sminshall 							}
197326049Sminshall 						}
197426049Sminshall 						else if (*cp2) {
197526049Sminshall 							*cp1++ = *cp2++;
197626049Sminshall 						}
197726049Sminshall 					}
197826049Sminshall 					if (!*cp2) {
197926049Sminshall 						printf("nmap: unbalanced brackets\n");
198026049Sminshall 						return(name);
198126049Sminshall 					}
198226049Sminshall 					match = 1;
198326049Sminshall 					cp2--;
198426049Sminshall 				}
198526049Sminshall 				if (match) {
198626049Sminshall 					while (*++cp2 && *cp2 != ']') {
198726049Sminshall 					      if (*cp2 == '\\' && *(cp2 + 1)) {
198826049Sminshall 							cp2++;
198926049Sminshall 					      }
199026049Sminshall 					}
199126049Sminshall 					if (!*cp2) {
199226049Sminshall 						printf("nmap: unbalanced brackets\n");
199326049Sminshall 						return(name);
199426049Sminshall 					}
199526049Sminshall 					break;
199626049Sminshall 				}
199726049Sminshall 				switch (*++cp2) {
199826049Sminshall 					case ',':
199926049Sminshall 						goto LOOP;
200026049Sminshall 					case ']':
200126049Sminshall 						break;
200226049Sminshall 					default:
200326049Sminshall 						cp2--;
200426049Sminshall 						goto LOOP;
200526049Sminshall 				}
200626049Sminshall 				break;
200726049Sminshall 			case '$':
200826049Sminshall 				if (isdigit(*(cp2 + 1))) {
200926049Sminshall 					if (*++cp2 == '0') {
201026049Sminshall 						char *cp3 = name;
201126049Sminshall 
201226049Sminshall 						while (*cp3) {
201326049Sminshall 							*cp1++ = *cp3++;
201426049Sminshall 						}
201526049Sminshall 					}
201626049Sminshall 					else if (toks[toknum = *cp2 - '1']) {
201726049Sminshall 						char *cp3 = tp[toknum];
201826049Sminshall 
201926049Sminshall 						while (cp3 != te[toknum]) {
202026049Sminshall 							*cp1++ = *cp3++;
202126049Sminshall 						}
202226049Sminshall 					}
202326049Sminshall 					break;
202426049Sminshall 				}
202526049Sminshall 				/* intentional drop through */
202626049Sminshall 			default:
202726049Sminshall 				*cp1++ = *cp2;
202826049Sminshall 				break;
202926049Sminshall 		}
203026049Sminshall 		cp2++;
203126049Sminshall 	}
203226049Sminshall 	*cp1 = '\0';
203326049Sminshall 	if (!*new) {
203426049Sminshall 		return(name);
203526049Sminshall 	}
203626049Sminshall 	return(new);
203726049Sminshall }
203826049Sminshall 
203926049Sminshall setsunique()
204026049Sminshall {
204126049Sminshall 	sunique = !sunique;
204226049Sminshall 	printf("Store unique %s.\n", onoff(sunique));
204326049Sminshall 	code = sunique;
204426049Sminshall }
204526049Sminshall 
204626049Sminshall setrunique()
204726049Sminshall {
204826049Sminshall 	runique = !runique;
204926049Sminshall 	printf("Receive unique %s.\n", onoff(runique));
205026049Sminshall 	code = runique;
205126049Sminshall }
205226049Sminshall 
205326049Sminshall /* change directory to perent directory */
205426049Sminshall cdup()
205526049Sminshall {
205637224Skarels 	if (command("CDUP") == ERROR && code == 500) {
205737224Skarels 		if (verbose)
205837224Skarels 			printf("CDUP command not recognized, trying XCUP\n");
205937224Skarels 		(void) command("XCUP");
206037224Skarels 	}
206126049Sminshall }
206226049Sminshall 
206337224Skarels /* restart transfer at specific point */
206437224Skarels restart(argc, argv)
206537224Skarels 	int argc;
206637224Skarels 	char *argv[];
206737224Skarels {
206837224Skarels 	extern long atol();
206937224Skarels 	if (argc != 2)
207037224Skarels 		printf("restart: offset not specified\n");
207137224Skarels 	else {
207237224Skarels 		restart_point = atol(argv[1]);
207337224Skarels 		printf("restarting at %ld. %s\n", restart_point,
207437224Skarels 		    "execute get, put or append to initiate transfer");
207537224Skarels 	}
207637224Skarels }
207736935Skarels 
207836935Skarels /* show remote system type */
207936935Skarels syst()
208036935Skarels {
208136935Skarels 	(void) command("SYST");
208236935Skarels }
208336935Skarels 
208426049Sminshall macdef(argc, argv)
208526049Sminshall 	int argc;
208626049Sminshall 	char *argv[];
208726049Sminshall {
208826049Sminshall 	char *tmp;
208926049Sminshall 	int c;
209026049Sminshall 
209126049Sminshall 	if (macnum == 16) {
209226049Sminshall 		printf("Limit of 16 macros have already been defined\n");
209326049Sminshall 		code = -1;
209426049Sminshall 		return;
209526049Sminshall 	}
209626049Sminshall 	if (argc < 2) {
209726497Sminshall 		(void) strcat(line, " ");
209826049Sminshall 		printf("(macro name) ");
209926497Sminshall 		(void) gets(&line[strlen(line)]);
210026049Sminshall 		makeargv();
210126049Sminshall 		argc = margc;
210226049Sminshall 		argv = margv;
210326049Sminshall 	}
210426049Sminshall 	if (argc != 2) {
210526049Sminshall 		printf("Usage: %s macro_name\n",argv[0]);
210626049Sminshall 		code = -1;
210726049Sminshall 		return;
210826049Sminshall 	}
210926049Sminshall 	if (interactive) {
211026049Sminshall 		printf("Enter macro line by line, terminating it with a null line\n");
211126049Sminshall 	}
211226497Sminshall 	(void) strncpy(macros[macnum].mac_name, argv[1], 8);
211326049Sminshall 	if (macnum == 0) {
211426049Sminshall 		macros[macnum].mac_start = macbuf;
211526049Sminshall 	}
211626049Sminshall 	else {
211726049Sminshall 		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
211826049Sminshall 	}
211926049Sminshall 	tmp = macros[macnum].mac_start;
212026049Sminshall 	while (tmp != macbuf+4096) {
212126049Sminshall 		if ((c = getchar()) == EOF) {
212226049Sminshall 			printf("macdef:end of file encountered\n");
212326049Sminshall 			code = -1;
212426049Sminshall 			return;
212526049Sminshall 		}
212626049Sminshall 		if ((*tmp = c) == '\n') {
212726049Sminshall 			if (tmp == macros[macnum].mac_start) {
212826049Sminshall 				macros[macnum++].mac_end = tmp;
212926049Sminshall 				code = 0;
213026049Sminshall 				return;
213126049Sminshall 			}
213226049Sminshall 			if (*(tmp-1) == '\0') {
213326049Sminshall 				macros[macnum++].mac_end = tmp - 1;
213426049Sminshall 				code = 0;
213526049Sminshall 				return;
213626049Sminshall 			}
213726049Sminshall 			*tmp = '\0';
213826049Sminshall 		}
213926049Sminshall 		tmp++;
214026049Sminshall 	}
214126049Sminshall 	while (1) {
214236935Skarels 		while ((c = getchar()) != '\n' && c != EOF)
214336935Skarels 			/* LOOP */;
214426049Sminshall 		if (c == EOF || getchar() == '\n') {
214526049Sminshall 			printf("Macro not defined - 4k buffer exceeded\n");
214626049Sminshall 			code = -1;
214726049Sminshall 			return;
214826049Sminshall 		}
214926049Sminshall 	}
215026049Sminshall }
215136935Skarels 
215236935Skarels /*
215336935Skarels  * get size of file on remote machine
215436935Skarels  */
215536935Skarels sizecmd(argc, argv)
215636935Skarels 	char *argv[];
215736935Skarels {
215836935Skarels 
215936935Skarels 	if (argc < 2) {
216036935Skarels 		(void) strcat(line, " ");
216136935Skarels 		printf("(filename) ");
216236935Skarels 		(void) gets(&line[strlen(line)]);
216336935Skarels 		makeargv();
216436935Skarels 		argc = margc;
216536935Skarels 		argv = margv;
216636935Skarels 	}
216736935Skarels 	if (argc < 2) {
216836935Skarels 		printf("usage:%s filename\n", argv[0]);
216936935Skarels 		code = -1;
217036935Skarels 		return;
217136935Skarels 	}
217236935Skarels 	(void) command("SIZE %s", argv[1]);
217336935Skarels }
217436935Skarels 
217536935Skarels /*
217636935Skarels  * get last modification time of file on remote machine
217736935Skarels  */
217836935Skarels modtime(argc, argv)
217936935Skarels 	char *argv[];
218036935Skarels {
218136935Skarels 	int overbose;
218236935Skarels 
218336935Skarels 	if (argc < 2) {
218436935Skarels 		(void) strcat(line, " ");
218536935Skarels 		printf("(filename) ");
218636935Skarels 		(void) gets(&line[strlen(line)]);
218736935Skarels 		makeargv();
218836935Skarels 		argc = margc;
218936935Skarels 		argv = margv;
219036935Skarels 	}
219136935Skarels 	if (argc < 2) {
219236935Skarels 		printf("usage:%s filename\n", argv[0]);
219336935Skarels 		code = -1;
219436935Skarels 		return;
219536935Skarels 	}
219636940Skarels 	overbose = verbose;
219736940Skarels 	if (debug == 0)
219836940Skarels 		verbose = -1;
219936935Skarels 	if (command("MDTM %s", argv[1]) == COMPLETE) {
220036935Skarels 		int yy, mo, day, hour, min, sec;
220136935Skarels 		sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
220236935Skarels 			&day, &hour, &min, &sec);
220336935Skarels 		/* might want to print this in local time */
220436935Skarels 		printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
220536935Skarels 			mo, day, yy, hour, min, sec);
220636935Skarels 	} else
220736935Skarels 		fputs(reply_string, stdout);
220836935Skarels 	verbose = overbose;
220936935Skarels }
221036935Skarels 
221136935Skarels /*
221237224Skarels  * show status on reomte machine
221336935Skarels  */
221436935Skarels rmtstatus(argc, argv)
221536935Skarels 	char *argv[];
221636935Skarels {
221736935Skarels 	(void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
221836935Skarels }
221937224Skarels 
222037224Skarels /*
222137224Skarels  * get file if modtime is more recent than current file
222237224Skarels  */
222337224Skarels newer(argc, argv)
222437224Skarels 	char *argv[];
222537224Skarels {
222637224Skarels 	if (getit(argc, argv, -1, "w"))
222737224Skarels 		printf("Local file \"%s\" is newer than remote file \"%s\"\n",
222837224Skarels 			argv[1], argv[2]);
222937224Skarels }
2230