xref: /freebsd/contrib/tnftp/src/cmds.c (revision 91019ea7d45385dd73bc853691375c169bd5941d)
1cc361f65SGavin Atkinson /*	$NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $	*/
2cc361f65SGavin Atkinson /*	from	NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp	*/
3f982db4aSGavin Atkinson 
4f982db4aSGavin Atkinson /*-
5cc361f65SGavin Atkinson  * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
6f982db4aSGavin Atkinson  * All rights reserved.
7f982db4aSGavin Atkinson  *
8f982db4aSGavin Atkinson  * This code is derived from software contributed to The NetBSD Foundation
9f982db4aSGavin Atkinson  * by Luke Mewburn.
10f982db4aSGavin Atkinson  *
11f982db4aSGavin Atkinson  * This code is derived from software contributed to The NetBSD Foundation
12f982db4aSGavin Atkinson  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
13f982db4aSGavin Atkinson  * NASA Ames Research Center.
14f982db4aSGavin Atkinson  *
15f982db4aSGavin Atkinson  * Redistribution and use in source and binary forms, with or without
16f982db4aSGavin Atkinson  * modification, are permitted provided that the following conditions
17f982db4aSGavin Atkinson  * are met:
18f982db4aSGavin Atkinson  * 1. Redistributions of source code must retain the above copyright
19f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer.
20f982db4aSGavin Atkinson  * 2. Redistributions in binary form must reproduce the above copyright
21f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer in the
22f982db4aSGavin Atkinson  *    documentation and/or other materials provided with the distribution.
23f982db4aSGavin Atkinson  *
24f982db4aSGavin Atkinson  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25f982db4aSGavin Atkinson  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26f982db4aSGavin Atkinson  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27f982db4aSGavin Atkinson  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28f982db4aSGavin Atkinson  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29f982db4aSGavin Atkinson  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30f982db4aSGavin Atkinson  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31f982db4aSGavin Atkinson  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32f982db4aSGavin Atkinson  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33f982db4aSGavin Atkinson  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34f982db4aSGavin Atkinson  * POSSIBILITY OF SUCH DAMAGE.
35f982db4aSGavin Atkinson  */
36f982db4aSGavin Atkinson 
37f982db4aSGavin Atkinson /*
38f982db4aSGavin Atkinson  * Copyright (c) 1985, 1989, 1993, 1994
39f982db4aSGavin Atkinson  *	The Regents of the University of California.  All rights reserved.
40f982db4aSGavin Atkinson  *
41f982db4aSGavin Atkinson  * Redistribution and use in source and binary forms, with or without
42f982db4aSGavin Atkinson  * modification, are permitted provided that the following conditions
43f982db4aSGavin Atkinson  * are met:
44f982db4aSGavin Atkinson  * 1. Redistributions of source code must retain the above copyright
45f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer.
46f982db4aSGavin Atkinson  * 2. Redistributions in binary form must reproduce the above copyright
47f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer in the
48f982db4aSGavin Atkinson  *    documentation and/or other materials provided with the distribution.
49f982db4aSGavin Atkinson  * 3. Neither the name of the University nor the names of its contributors
50f982db4aSGavin Atkinson  *    may be used to endorse or promote products derived from this software
51f982db4aSGavin Atkinson  *    without specific prior written permission.
52f982db4aSGavin Atkinson  *
53f982db4aSGavin Atkinson  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54f982db4aSGavin Atkinson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55f982db4aSGavin Atkinson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56f982db4aSGavin Atkinson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57f982db4aSGavin Atkinson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58f982db4aSGavin Atkinson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59f982db4aSGavin Atkinson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60f982db4aSGavin Atkinson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61f982db4aSGavin Atkinson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62f982db4aSGavin Atkinson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63f982db4aSGavin Atkinson  * SUCH DAMAGE.
64f982db4aSGavin Atkinson  */
65f982db4aSGavin Atkinson 
66f982db4aSGavin Atkinson /*
67f982db4aSGavin Atkinson  * Copyright (C) 1997 and 1998 WIDE Project.
68f982db4aSGavin Atkinson  * All rights reserved.
69f982db4aSGavin Atkinson  *
70f982db4aSGavin Atkinson  * Redistribution and use in source and binary forms, with or without
71f982db4aSGavin Atkinson  * modification, are permitted provided that the following conditions
72f982db4aSGavin Atkinson  * are met:
73f982db4aSGavin Atkinson  * 1. Redistributions of source code must retain the above copyright
74f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer.
75f982db4aSGavin Atkinson  * 2. Redistributions in binary form must reproduce the above copyright
76f982db4aSGavin Atkinson  *    notice, this list of conditions and the following disclaimer in the
77f982db4aSGavin Atkinson  *    documentation and/or other materials provided with the distribution.
78f982db4aSGavin Atkinson  * 3. Neither the name of the project nor the names of its contributors
79f982db4aSGavin Atkinson  *    may be used to endorse or promote products derived from this software
80f982db4aSGavin Atkinson  *    without specific prior written permission.
81f982db4aSGavin Atkinson  *
82f982db4aSGavin Atkinson  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
83f982db4aSGavin Atkinson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84f982db4aSGavin Atkinson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85f982db4aSGavin Atkinson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
86f982db4aSGavin Atkinson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87f982db4aSGavin Atkinson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88f982db4aSGavin Atkinson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89f982db4aSGavin Atkinson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90f982db4aSGavin Atkinson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91f982db4aSGavin Atkinson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
92f982db4aSGavin Atkinson  * SUCH DAMAGE.
93f982db4aSGavin Atkinson  */
94f982db4aSGavin Atkinson 
95cc361f65SGavin Atkinson #include "tnftp.h"
96cc361f65SGavin Atkinson 
97cc361f65SGavin Atkinson #if 0	/* tnftp */
98cc361f65SGavin Atkinson 
99f982db4aSGavin Atkinson #include <sys/cdefs.h>
100f982db4aSGavin Atkinson #ifndef lint
101f982db4aSGavin Atkinson #if 0
102f982db4aSGavin Atkinson static char sccsid[] = "@(#)cmds.c	8.6 (Berkeley) 10/9/94";
103f982db4aSGavin Atkinson #else
104cc361f65SGavin Atkinson __RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp  ");
105f982db4aSGavin Atkinson #endif
106f982db4aSGavin Atkinson #endif /* not lint */
107f982db4aSGavin Atkinson 
108f982db4aSGavin Atkinson /*
109f982db4aSGavin Atkinson  * FTP User Program -- Command Routines.
110f982db4aSGavin Atkinson  */
111f982db4aSGavin Atkinson #include <sys/types.h>
112f982db4aSGavin Atkinson #include <sys/socket.h>
113f982db4aSGavin Atkinson #include <sys/stat.h>
114f982db4aSGavin Atkinson #include <sys/wait.h>
115f982db4aSGavin Atkinson #include <arpa/ftp.h>
116f982db4aSGavin Atkinson 
117f982db4aSGavin Atkinson #include <ctype.h>
118f982db4aSGavin Atkinson #include <err.h>
119f982db4aSGavin Atkinson #include <glob.h>
120f982db4aSGavin Atkinson #include <limits.h>
121f982db4aSGavin Atkinson #include <netdb.h>
122f982db4aSGavin Atkinson #include <paths.h>
123cc361f65SGavin Atkinson #include <stddef.h>
124f982db4aSGavin Atkinson #include <stdio.h>
125f982db4aSGavin Atkinson #include <stdlib.h>
126f982db4aSGavin Atkinson #include <string.h>
127f982db4aSGavin Atkinson #include <time.h>
128f982db4aSGavin Atkinson #include <unistd.h>
129cc361f65SGavin Atkinson 
130cc361f65SGavin Atkinson #endif	/* tnftp */
131f982db4aSGavin Atkinson 
132f982db4aSGavin Atkinson #include "ftp_var.h"
133f982db4aSGavin Atkinson #include "version.h"
134f982db4aSGavin Atkinson 
135cc361f65SGavin Atkinson static struct types {
136cc361f65SGavin Atkinson 	const char	*t_name;
137cc361f65SGavin Atkinson 	const char	*t_mode;
138f982db4aSGavin Atkinson 	int		t_type;
139cc361f65SGavin Atkinson 	const char	*t_arg;
140f982db4aSGavin Atkinson } types[] = {
141f982db4aSGavin Atkinson 	{ "ascii",	"A",	TYPE_A,	0 },
142f982db4aSGavin Atkinson 	{ "binary",	"I",	TYPE_I,	0 },
143f982db4aSGavin Atkinson 	{ "image",	"I",	TYPE_I,	0 },
144f982db4aSGavin Atkinson 	{ "ebcdic",	"E",	TYPE_E,	0 },
145f982db4aSGavin Atkinson 	{ "tenex",	"L",	TYPE_L,	bytename },
146cc361f65SGavin Atkinson 	{ NULL,		NULL,	0, NULL }
147f982db4aSGavin Atkinson };
148f982db4aSGavin Atkinson 
149cc361f65SGavin Atkinson static sigjmp_buf	 jabort;
150f982db4aSGavin Atkinson 
151f982db4aSGavin Atkinson static int	confirm(const char *, const char *);
152cc361f65SGavin Atkinson static void	mintr(int);
153cc361f65SGavin Atkinson static void	mabort(const char *);
154cc361f65SGavin Atkinson static void	set_type(const char *);
155f982db4aSGavin Atkinson 
156f982db4aSGavin Atkinson static const char *doprocess(char *, size_t, const char *, int, int, int);
157f982db4aSGavin Atkinson static const char *domap(char *, size_t, const char *);
158f982db4aSGavin Atkinson static const char *docase(char *, size_t, const char *);
159f982db4aSGavin Atkinson static const char *dotrans(char *, size_t, const char *);
160f982db4aSGavin Atkinson 
161cc361f65SGavin Atkinson /*
162cc361f65SGavin Atkinson  * Confirm if "cmd" is to be performed upon "file".
163cc361f65SGavin Atkinson  * If "file" is NULL, generate a "Continue with" prompt instead.
164cc361f65SGavin Atkinson  */
165f982db4aSGavin Atkinson static int
confirm(const char * cmd,const char * file)166f982db4aSGavin Atkinson confirm(const char *cmd, const char *file)
167f982db4aSGavin Atkinson {
168cc361f65SGavin Atkinson 	const char *errormsg;
169cc361f65SGavin Atkinson 	char cline[BUFSIZ];
170cc361f65SGavin Atkinson 	const char *promptleft, *promptright;
171f982db4aSGavin Atkinson 
172f982db4aSGavin Atkinson 	if (!interactive || confirmrest)
173f982db4aSGavin Atkinson 		return (1);
174cc361f65SGavin Atkinson 	if (file == NULL) {
175cc361f65SGavin Atkinson 		promptleft = "Continue with";
176cc361f65SGavin Atkinson 		promptright = cmd;
177cc361f65SGavin Atkinson 	} else {
178cc361f65SGavin Atkinson 		promptleft = cmd;
179cc361f65SGavin Atkinson 		promptright = file;
180cc361f65SGavin Atkinson 	}
181f982db4aSGavin Atkinson 	while (1) {
182cc361f65SGavin Atkinson 		fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright);
183f982db4aSGavin Atkinson 		(void)fflush(ttyout);
184cc361f65SGavin Atkinson 		if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) {
185f982db4aSGavin Atkinson 			mflag = 0;
186cc361f65SGavin Atkinson 			fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd);
187f982db4aSGavin Atkinson 			return (0);
188f982db4aSGavin Atkinson 		}
189cc361f65SGavin Atkinson 		switch (tolower((unsigned char)*cline)) {
190f982db4aSGavin Atkinson 			case 'a':
191f982db4aSGavin Atkinson 				confirmrest = 1;
192f982db4aSGavin Atkinson 				fprintf(ttyout,
193f982db4aSGavin Atkinson 				    "Prompting off for duration of %s.\n", cmd);
194f982db4aSGavin Atkinson 				break;
195f982db4aSGavin Atkinson 			case 'p':
196f982db4aSGavin Atkinson 				interactive = 0;
197f982db4aSGavin Atkinson 				fputs("Interactive mode: off.\n", ttyout);
198f982db4aSGavin Atkinson 				break;
199f982db4aSGavin Atkinson 			case 'q':
200f982db4aSGavin Atkinson 				mflag = 0;
201cc361f65SGavin Atkinson 				fprintf(ttyout, "%s aborted.\n", cmd);
202f982db4aSGavin Atkinson 				/* FALLTHROUGH */
203f982db4aSGavin Atkinson 			case 'n':
204f982db4aSGavin Atkinson 				return (0);
205f982db4aSGavin Atkinson 			case '?':
206f982db4aSGavin Atkinson 				fprintf(ttyout,
207f982db4aSGavin Atkinson 				    "  confirmation options:\n"
208f982db4aSGavin Atkinson 				    "\ta  answer `yes' for the duration of %s\n"
209f982db4aSGavin Atkinson 				    "\tn  answer `no' for this file\n"
210f982db4aSGavin Atkinson 				    "\tp  turn off `prompt' mode\n"
211f982db4aSGavin Atkinson 				    "\tq  stop the current %s\n"
212f982db4aSGavin Atkinson 				    "\ty  answer `yes' for this file\n"
213f982db4aSGavin Atkinson 				    "\t?  this help list\n",
214f982db4aSGavin Atkinson 				    cmd, cmd);
215f982db4aSGavin Atkinson 				continue;	/* back to while(1) */
216f982db4aSGavin Atkinson 		}
217f982db4aSGavin Atkinson 		return (1);
218f982db4aSGavin Atkinson 	}
219f982db4aSGavin Atkinson 	/* NOTREACHED */
220f982db4aSGavin Atkinson }
221f982db4aSGavin Atkinson 
222f982db4aSGavin Atkinson /*
223f982db4aSGavin Atkinson  * Set transfer type.
224f982db4aSGavin Atkinson  */
225f982db4aSGavin Atkinson void
settype(int argc,char * argv[])226f982db4aSGavin Atkinson settype(int argc, char *argv[])
227f982db4aSGavin Atkinson {
228f982db4aSGavin Atkinson 	struct types *p;
229f982db4aSGavin Atkinson 
230f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2) {
231cc361f65SGavin Atkinson 		const char *sep;
232f982db4aSGavin Atkinson 
233cc361f65SGavin Atkinson 		UPRINTF("usage: %s [", argv[0]);
234f982db4aSGavin Atkinson 		sep = " ";
235f982db4aSGavin Atkinson 		for (p = types; p->t_name; p++) {
236f982db4aSGavin Atkinson 			fprintf(ttyout, "%s%s", sep, p->t_name);
237f982db4aSGavin Atkinson 			sep = " | ";
238f982db4aSGavin Atkinson 		}
239f982db4aSGavin Atkinson 		fputs(" ]\n", ttyout);
240f982db4aSGavin Atkinson 		code = -1;
241f982db4aSGavin Atkinson 		return;
242f982db4aSGavin Atkinson 	}
243f982db4aSGavin Atkinson 	if (argc < 2) {
244f982db4aSGavin Atkinson 		fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
245f982db4aSGavin Atkinson 		code = 0;
246f982db4aSGavin Atkinson 		return;
247f982db4aSGavin Atkinson 	}
248cc361f65SGavin Atkinson 	set_type(argv[1]);
249cc361f65SGavin Atkinson }
250cc361f65SGavin Atkinson 
251cc361f65SGavin Atkinson void
set_type(const char * ttype)252cc361f65SGavin Atkinson set_type(const char *ttype)
253cc361f65SGavin Atkinson {
254cc361f65SGavin Atkinson 	struct types *p;
255cc361f65SGavin Atkinson 	int comret;
256cc361f65SGavin Atkinson 
257f982db4aSGavin Atkinson 	for (p = types; p->t_name; p++)
258cc361f65SGavin Atkinson 		if (strcmp(ttype, p->t_name) == 0)
259f982db4aSGavin Atkinson 			break;
260f982db4aSGavin Atkinson 	if (p->t_name == 0) {
261cc361f65SGavin Atkinson 		fprintf(ttyout, "%s: unknown mode.\n", ttype);
262f982db4aSGavin Atkinson 		code = -1;
263f982db4aSGavin Atkinson 		return;
264f982db4aSGavin Atkinson 	}
265f982db4aSGavin Atkinson 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
266f982db4aSGavin Atkinson 		comret = command("TYPE %s %s", p->t_mode, p->t_arg);
267f982db4aSGavin Atkinson 	else
268f982db4aSGavin Atkinson 		comret = command("TYPE %s", p->t_mode);
269f982db4aSGavin Atkinson 	if (comret == COMPLETE) {
270f982db4aSGavin Atkinson 		(void)strlcpy(typename, p->t_name, sizeof(typename));
271f982db4aSGavin Atkinson 		curtype = type = p->t_type;
272f982db4aSGavin Atkinson 	}
273f982db4aSGavin Atkinson }
274f982db4aSGavin Atkinson 
275f982db4aSGavin Atkinson /*
276f982db4aSGavin Atkinson  * Internal form of settype; changes current type in use with server
277f982db4aSGavin Atkinson  * without changing our notion of the type for data transfers.
278f982db4aSGavin Atkinson  * Used to change to and from ascii for listings.
279f982db4aSGavin Atkinson  */
280f982db4aSGavin Atkinson void
changetype(int newtype,int show)281f982db4aSGavin Atkinson changetype(int newtype, int show)
282f982db4aSGavin Atkinson {
283f982db4aSGavin Atkinson 	struct types *p;
284f982db4aSGavin Atkinson 	int comret, oldverbose = verbose;
285f982db4aSGavin Atkinson 
286f982db4aSGavin Atkinson 	if (newtype == 0)
287f982db4aSGavin Atkinson 		newtype = TYPE_I;
288f982db4aSGavin Atkinson 	if (newtype == curtype)
289f982db4aSGavin Atkinson 		return;
290cc361f65SGavin Atkinson 	if (ftp_debug == 0 && show == 0)
291f982db4aSGavin Atkinson 		verbose = 0;
292f982db4aSGavin Atkinson 	for (p = types; p->t_name; p++)
293f982db4aSGavin Atkinson 		if (newtype == p->t_type)
294f982db4aSGavin Atkinson 			break;
295f982db4aSGavin Atkinson 	if (p->t_name == 0) {
296cc361f65SGavin Atkinson 		errx(1, "changetype: unknown type %d", newtype);
297f982db4aSGavin Atkinson 	}
298f982db4aSGavin Atkinson 	if (newtype == TYPE_L && bytename[0] != '\0')
299f982db4aSGavin Atkinson 		comret = command("TYPE %s %s", p->t_mode, bytename);
300f982db4aSGavin Atkinson 	else
301f982db4aSGavin Atkinson 		comret = command("TYPE %s", p->t_mode);
302f982db4aSGavin Atkinson 	if (comret == COMPLETE)
303f982db4aSGavin Atkinson 		curtype = newtype;
304f982db4aSGavin Atkinson 	verbose = oldverbose;
305f982db4aSGavin Atkinson }
306f982db4aSGavin Atkinson 
307f982db4aSGavin Atkinson /*
308f982db4aSGavin Atkinson  * Set binary transfer type.
309f982db4aSGavin Atkinson  */
310f982db4aSGavin Atkinson /*VARARGS*/
311f982db4aSGavin Atkinson void
setbinary(int argc,char * argv[])312f982db4aSGavin Atkinson setbinary(int argc, char *argv[])
313f982db4aSGavin Atkinson {
314f982db4aSGavin Atkinson 
315f982db4aSGavin Atkinson 	if (argc == 0) {
316cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
317f982db4aSGavin Atkinson 		code = -1;
318f982db4aSGavin Atkinson 		return;
319f982db4aSGavin Atkinson 	}
320cc361f65SGavin Atkinson 	set_type("binary");
321f982db4aSGavin Atkinson }
322f982db4aSGavin Atkinson 
323f982db4aSGavin Atkinson /*
324f982db4aSGavin Atkinson  * Set ascii transfer type.
325f982db4aSGavin Atkinson  */
326f982db4aSGavin Atkinson /*VARARGS*/
327f982db4aSGavin Atkinson void
setascii(int argc,char * argv[])328f982db4aSGavin Atkinson setascii(int argc, char *argv[])
329f982db4aSGavin Atkinson {
330f982db4aSGavin Atkinson 
331f982db4aSGavin Atkinson 	if (argc == 0) {
332cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
333f982db4aSGavin Atkinson 		code = -1;
334f982db4aSGavin Atkinson 		return;
335f982db4aSGavin Atkinson 	}
336cc361f65SGavin Atkinson 	set_type("ascii");
337f982db4aSGavin Atkinson }
338f982db4aSGavin Atkinson 
339f982db4aSGavin Atkinson /*
340f982db4aSGavin Atkinson  * Set tenex transfer type.
341f982db4aSGavin Atkinson  */
342f982db4aSGavin Atkinson /*VARARGS*/
343f982db4aSGavin Atkinson void
settenex(int argc,char * argv[])344f982db4aSGavin Atkinson settenex(int argc, char *argv[])
345f982db4aSGavin Atkinson {
346f982db4aSGavin Atkinson 
347f982db4aSGavin Atkinson 	if (argc == 0) {
348cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
349f982db4aSGavin Atkinson 		code = -1;
350f982db4aSGavin Atkinson 		return;
351f982db4aSGavin Atkinson 	}
352cc361f65SGavin Atkinson 	set_type("tenex");
353f982db4aSGavin Atkinson }
354f982db4aSGavin Atkinson 
355f982db4aSGavin Atkinson /*
356f982db4aSGavin Atkinson  * Set file transfer mode.
357f982db4aSGavin Atkinson  */
358f982db4aSGavin Atkinson /*ARGSUSED*/
359f982db4aSGavin Atkinson void
setftmode(int argc,char * argv[])360f982db4aSGavin Atkinson setftmode(int argc, char *argv[])
361f982db4aSGavin Atkinson {
362f982db4aSGavin Atkinson 
363f982db4aSGavin Atkinson 	if (argc != 2) {
364cc361f65SGavin Atkinson 		UPRINTF("usage: %s mode-name\n", argv[0]);
365f982db4aSGavin Atkinson 		code = -1;
366f982db4aSGavin Atkinson 		return;
367f982db4aSGavin Atkinson 	}
368f982db4aSGavin Atkinson 	fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
369f982db4aSGavin Atkinson 	code = -1;
370f982db4aSGavin Atkinson }
371f982db4aSGavin Atkinson 
372f982db4aSGavin Atkinson /*
373f982db4aSGavin Atkinson  * Set file transfer format.
374f982db4aSGavin Atkinson  */
375f982db4aSGavin Atkinson /*ARGSUSED*/
376f982db4aSGavin Atkinson void
setform(int argc,char * argv[])377f982db4aSGavin Atkinson setform(int argc, char *argv[])
378f982db4aSGavin Atkinson {
379f982db4aSGavin Atkinson 
380f982db4aSGavin Atkinson 	if (argc != 2) {
381cc361f65SGavin Atkinson 		UPRINTF("usage: %s format\n", argv[0]);
382f982db4aSGavin Atkinson 		code = -1;
383f982db4aSGavin Atkinson 		return;
384f982db4aSGavin Atkinson 	}
385f982db4aSGavin Atkinson 	fprintf(ttyout, "We only support %s format, sorry.\n", formname);
386f982db4aSGavin Atkinson 	code = -1;
387f982db4aSGavin Atkinson }
388f982db4aSGavin Atkinson 
389f982db4aSGavin Atkinson /*
390f982db4aSGavin Atkinson  * Set file transfer structure.
391f982db4aSGavin Atkinson  */
392f982db4aSGavin Atkinson /*ARGSUSED*/
393f982db4aSGavin Atkinson void
setstruct(int argc,char * argv[])394f982db4aSGavin Atkinson setstruct(int argc, char *argv[])
395f982db4aSGavin Atkinson {
396f982db4aSGavin Atkinson 
397f982db4aSGavin Atkinson 	if (argc != 2) {
398cc361f65SGavin Atkinson 		UPRINTF("usage: %s struct-mode\n", argv[0]);
399f982db4aSGavin Atkinson 		code = -1;
400f982db4aSGavin Atkinson 		return;
401f982db4aSGavin Atkinson 	}
402f982db4aSGavin Atkinson 	fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
403f982db4aSGavin Atkinson 	code = -1;
404f982db4aSGavin Atkinson }
405f982db4aSGavin Atkinson 
406f982db4aSGavin Atkinson /*
407f982db4aSGavin Atkinson  * Send a single file.
408f982db4aSGavin Atkinson  */
409f982db4aSGavin Atkinson void
put(int argc,char * argv[])410f982db4aSGavin Atkinson put(int argc, char *argv[])
411f982db4aSGavin Atkinson {
412f982db4aSGavin Atkinson 	char buf[MAXPATHLEN];
413cc361f65SGavin Atkinson 	const char *cmd;
414f982db4aSGavin Atkinson 	int loc = 0;
415f982db4aSGavin Atkinson 	char *locfile;
416f982db4aSGavin Atkinson 	const char *remfile;
417f982db4aSGavin Atkinson 
418f982db4aSGavin Atkinson 	if (argc == 2) {
419f982db4aSGavin Atkinson 		argc++;
420f982db4aSGavin Atkinson 		argv[2] = argv[1];
421f982db4aSGavin Atkinson 		loc++;
422f982db4aSGavin Atkinson 	}
423f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file")))
424f982db4aSGavin Atkinson 		goto usage;
425f982db4aSGavin Atkinson 	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
426f982db4aSGavin Atkinson  usage:
427cc361f65SGavin Atkinson 		UPRINTF("usage: %s local-file [remote-file]\n", argv[0]);
428f982db4aSGavin Atkinson 		code = -1;
429f982db4aSGavin Atkinson 		return;
430f982db4aSGavin Atkinson 	}
431f982db4aSGavin Atkinson 	if ((locfile = globulize(argv[1])) == NULL) {
432f982db4aSGavin Atkinson 		code = -1;
433f982db4aSGavin Atkinson 		return;
434f982db4aSGavin Atkinson 	}
435f982db4aSGavin Atkinson 	remfile = argv[2];
436f982db4aSGavin Atkinson 	if (loc)	/* If argv[2] is a copy of the old argv[1], update it */
437f982db4aSGavin Atkinson 		remfile = locfile;
438f982db4aSGavin Atkinson 	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
439f982db4aSGavin Atkinson 	remfile = doprocess(buf, sizeof(buf), remfile,
440f982db4aSGavin Atkinson 		0, loc && ntflag, loc && mapflag);
441f982db4aSGavin Atkinson 	sendrequest(cmd, locfile, remfile,
442f982db4aSGavin Atkinson 	    locfile != argv[1] || remfile != argv[2]);
443f982db4aSGavin Atkinson 	free(locfile);
444f982db4aSGavin Atkinson }
445f982db4aSGavin Atkinson 
446f982db4aSGavin Atkinson static const char *
doprocess(char * dst,size_t dlen,const char * src,int casef,int transf,int mapf)447f982db4aSGavin Atkinson doprocess(char *dst, size_t dlen, const char *src,
448f982db4aSGavin Atkinson     int casef, int transf, int mapf)
449f982db4aSGavin Atkinson {
450f982db4aSGavin Atkinson 	if (casef)
451f982db4aSGavin Atkinson 		src = docase(dst, dlen, src);
452f982db4aSGavin Atkinson 	if (transf)
453f982db4aSGavin Atkinson 		src = dotrans(dst, dlen, src);
454f982db4aSGavin Atkinson 	if (mapf)
455f982db4aSGavin Atkinson 		src = domap(dst, dlen, src);
456f982db4aSGavin Atkinson 	return src;
457f982db4aSGavin Atkinson }
458f982db4aSGavin Atkinson 
459f982db4aSGavin Atkinson /*
460f982db4aSGavin Atkinson  * Send multiple files.
461f982db4aSGavin Atkinson  */
462f982db4aSGavin Atkinson void
mput(int argc,char * argv[])463f982db4aSGavin Atkinson mput(int argc, char *argv[])
464f982db4aSGavin Atkinson {
465f982db4aSGavin Atkinson 	int i;
466f982db4aSGavin Atkinson 	sigfunc oldintr;
467f982db4aSGavin Atkinson 	int ointer;
468f982db4aSGavin Atkinson 	const char *tp;
469f982db4aSGavin Atkinson 
470f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) {
471cc361f65SGavin Atkinson 		UPRINTF("usage: %s local-files\n", argv[0]);
472f982db4aSGavin Atkinson 		code = -1;
473f982db4aSGavin Atkinson 		return;
474f982db4aSGavin Atkinson 	}
475f982db4aSGavin Atkinson 	mflag = 1;
476f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, mintr);
477f982db4aSGavin Atkinson 	if (sigsetjmp(jabort, 1))
478cc361f65SGavin Atkinson 		mabort(argv[0]);
479f982db4aSGavin Atkinson 	if (proxy) {
480f982db4aSGavin Atkinson 		char *cp;
481f982db4aSGavin Atkinson 
482f982db4aSGavin Atkinson 		while ((cp = remglob(argv, 0, NULL)) != NULL) {
483f982db4aSGavin Atkinson 			if (*cp == '\0' || !connected) {
484f982db4aSGavin Atkinson 				mflag = 0;
485f982db4aSGavin Atkinson 				continue;
486f982db4aSGavin Atkinson 			}
487f982db4aSGavin Atkinson 			if (mflag && confirm(argv[0], cp)) {
488f982db4aSGavin Atkinson 				char buf[MAXPATHLEN];
489f982db4aSGavin Atkinson 				tp = doprocess(buf, sizeof(buf), cp,
490f982db4aSGavin Atkinson 				    mcase, ntflag, mapflag);
491f982db4aSGavin Atkinson 				sendrequest((sunique) ? "STOU" : "STOR",
492f982db4aSGavin Atkinson 				    cp, tp, cp != tp || !interactive);
493f982db4aSGavin Atkinson 				if (!mflag && fromatty) {
494f982db4aSGavin Atkinson 					ointer = interactive;
495f982db4aSGavin Atkinson 					interactive = 1;
496cc361f65SGavin Atkinson 					if (confirm(argv[0], NULL)) {
497f982db4aSGavin Atkinson 						mflag++;
498f982db4aSGavin Atkinson 					}
499f982db4aSGavin Atkinson 					interactive = ointer;
500f982db4aSGavin Atkinson 				}
501f982db4aSGavin Atkinson 			}
502f982db4aSGavin Atkinson 		}
503f982db4aSGavin Atkinson 		goto cleanupmput;
504f982db4aSGavin Atkinson 	}
505f982db4aSGavin Atkinson 	for (i = 1; i < argc && connected; i++) {
506f982db4aSGavin Atkinson 		char **cpp;
507f982db4aSGavin Atkinson 		glob_t gl;
508f982db4aSGavin Atkinson 		int flags;
509f982db4aSGavin Atkinson 
510f982db4aSGavin Atkinson 		if (!doglob) {
511f982db4aSGavin Atkinson 			if (mflag && confirm(argv[0], argv[i])) {
512f982db4aSGavin Atkinson 				char buf[MAXPATHLEN];
513f982db4aSGavin Atkinson 				tp = doprocess(buf, sizeof(buf), argv[i],
514f982db4aSGavin Atkinson 					0, ntflag, mapflag);
515f982db4aSGavin Atkinson 				sendrequest((sunique) ? "STOU" : "STOR",
516f982db4aSGavin Atkinson 				    argv[i], tp, tp != argv[i] || !interactive);
517f982db4aSGavin Atkinson 				if (!mflag && fromatty) {
518f982db4aSGavin Atkinson 					ointer = interactive;
519f982db4aSGavin Atkinson 					interactive = 1;
520cc361f65SGavin Atkinson 					if (confirm(argv[0], NULL)) {
521f982db4aSGavin Atkinson 						mflag++;
522f982db4aSGavin Atkinson 					}
523f982db4aSGavin Atkinson 					interactive = ointer;
524f982db4aSGavin Atkinson 				}
525f982db4aSGavin Atkinson 			}
526f982db4aSGavin Atkinson 			continue;
527f982db4aSGavin Atkinson 		}
528f982db4aSGavin Atkinson 
529f982db4aSGavin Atkinson 		memset(&gl, 0, sizeof(gl));
530f982db4aSGavin Atkinson 		flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
531f982db4aSGavin Atkinson 		if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
532cc361f65SGavin Atkinson 			warnx("Glob pattern `%s' not found", argv[i]);
533f982db4aSGavin Atkinson 			globfree(&gl);
534f982db4aSGavin Atkinson 			continue;
535f982db4aSGavin Atkinson 		}
536f982db4aSGavin Atkinson 		for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected;
537f982db4aSGavin Atkinson 		    cpp++) {
538f982db4aSGavin Atkinson 			if (mflag && confirm(argv[0], *cpp)) {
539f982db4aSGavin Atkinson 				char buf[MAXPATHLEN];
540f982db4aSGavin Atkinson 				tp = *cpp;
541f982db4aSGavin Atkinson 				tp = doprocess(buf, sizeof(buf), *cpp,
542f982db4aSGavin Atkinson 				    0, ntflag, mapflag);
543f982db4aSGavin Atkinson 				sendrequest((sunique) ? "STOU" : "STOR",
544f982db4aSGavin Atkinson 				    *cpp, tp, *cpp != tp || !interactive);
545f982db4aSGavin Atkinson 				if (!mflag && fromatty) {
546f982db4aSGavin Atkinson 					ointer = interactive;
547f982db4aSGavin Atkinson 					interactive = 1;
548cc361f65SGavin Atkinson 					if (confirm(argv[0], NULL)) {
549f982db4aSGavin Atkinson 						mflag++;
550f982db4aSGavin Atkinson 					}
551f982db4aSGavin Atkinson 					interactive = ointer;
552f982db4aSGavin Atkinson 				}
553f982db4aSGavin Atkinson 			}
554f982db4aSGavin Atkinson 		}
555f982db4aSGavin Atkinson 		globfree(&gl);
556f982db4aSGavin Atkinson 	}
557f982db4aSGavin Atkinson  cleanupmput:
558f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
559f982db4aSGavin Atkinson 	mflag = 0;
560f982db4aSGavin Atkinson }
561f982db4aSGavin Atkinson 
562f982db4aSGavin Atkinson void
reget(int argc,char * argv[])563f982db4aSGavin Atkinson reget(int argc, char *argv[])
564f982db4aSGavin Atkinson {
565f982db4aSGavin Atkinson 
566f982db4aSGavin Atkinson 	(void)getit(argc, argv, 1, "r+");
567f982db4aSGavin Atkinson }
568f982db4aSGavin Atkinson 
569f982db4aSGavin Atkinson void
get(int argc,char * argv[])570f982db4aSGavin Atkinson get(int argc, char *argv[])
571f982db4aSGavin Atkinson {
572f982db4aSGavin Atkinson 
573f982db4aSGavin Atkinson 	(void)getit(argc, argv, 0, restart_point ? "r+" : "w" );
574f982db4aSGavin Atkinson }
575f982db4aSGavin Atkinson 
576f982db4aSGavin Atkinson /*
577f982db4aSGavin Atkinson  * Receive one file.
578f982db4aSGavin Atkinson  * If restartit is  1, restart the xfer always.
579f982db4aSGavin Atkinson  * If restartit is -1, restart the xfer only if the remote file is newer.
580f982db4aSGavin Atkinson  */
581f982db4aSGavin Atkinson int
getit(int argc,char * argv[],int restartit,const char * gmode)582cc361f65SGavin Atkinson getit(int argc, char *argv[], int restartit, const char *gmode)
583f982db4aSGavin Atkinson {
584f982db4aSGavin Atkinson 	int	loc, rval;
585f982db4aSGavin Atkinson 	char	*remfile, *olocfile;
586f982db4aSGavin Atkinson 	const char *locfile;
587f982db4aSGavin Atkinson 	char	buf[MAXPATHLEN];
588f982db4aSGavin Atkinson 
589f982db4aSGavin Atkinson 	loc = rval = 0;
590f982db4aSGavin Atkinson 	if (argc == 2) {
591f982db4aSGavin Atkinson 		argc++;
592f982db4aSGavin Atkinson 		argv[2] = argv[1];
593f982db4aSGavin Atkinson 		loc++;
594f982db4aSGavin Atkinson 	}
595f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file")))
596f982db4aSGavin Atkinson 		goto usage;
597f982db4aSGavin Atkinson 	if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
598f982db4aSGavin Atkinson  usage:
599cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-file [local-file]\n", argv[0]);
600f982db4aSGavin Atkinson 		code = -1;
601f982db4aSGavin Atkinson 		return (0);
602f982db4aSGavin Atkinson 	}
603f982db4aSGavin Atkinson 	remfile = argv[1];
604f982db4aSGavin Atkinson 	if ((olocfile = globulize(argv[2])) == NULL) {
605f982db4aSGavin Atkinson 		code = -1;
606f982db4aSGavin Atkinson 		return (0);
607f982db4aSGavin Atkinson 	}
608f982db4aSGavin Atkinson 	locfile = doprocess(buf, sizeof(buf), olocfile,
609f982db4aSGavin Atkinson 		loc && mcase, loc && ntflag, loc && mapflag);
610f982db4aSGavin Atkinson 	if (restartit) {
611f982db4aSGavin Atkinson 		struct stat stbuf;
612f982db4aSGavin Atkinson 		int ret;
613f982db4aSGavin Atkinson 
614f982db4aSGavin Atkinson 		if (! features[FEAT_REST_STREAM]) {
615f982db4aSGavin Atkinson 			fprintf(ttyout,
616f982db4aSGavin Atkinson 			    "Restart is not supported by the remote server.\n");
617f982db4aSGavin Atkinson 			return (0);
618f982db4aSGavin Atkinson 		}
619f982db4aSGavin Atkinson 		ret = stat(locfile, &stbuf);
620f982db4aSGavin Atkinson 		if (restartit == 1) {
621f982db4aSGavin Atkinson 			if (ret < 0) {
622cc361f65SGavin Atkinson 				warn("Can't stat `%s'", locfile);
623f982db4aSGavin Atkinson 				goto freegetit;
624f982db4aSGavin Atkinson 			}
625f982db4aSGavin Atkinson 			restart_point = stbuf.st_size;
626f982db4aSGavin Atkinson 		} else {
627f982db4aSGavin Atkinson 			if (ret == 0) {
628f982db4aSGavin Atkinson 				time_t mtime;
629f982db4aSGavin Atkinson 
630f982db4aSGavin Atkinson 				mtime = remotemodtime(argv[1], 0);
631f982db4aSGavin Atkinson 				if (mtime == -1)
632f982db4aSGavin Atkinson 					goto freegetit;
633f982db4aSGavin Atkinson 				if (stbuf.st_mtime >= mtime) {
634f982db4aSGavin Atkinson 					rval = 1;
635f982db4aSGavin Atkinson 					goto freegetit;
636f982db4aSGavin Atkinson 				}
637f982db4aSGavin Atkinson 			}
638f982db4aSGavin Atkinson 		}
639f982db4aSGavin Atkinson 	}
640f982db4aSGavin Atkinson 
641cc361f65SGavin Atkinson 	recvrequest("RETR", locfile, remfile, gmode,
642f982db4aSGavin Atkinson 	    remfile != argv[1] || locfile != argv[2], loc);
643f982db4aSGavin Atkinson 	restart_point = 0;
644f982db4aSGavin Atkinson  freegetit:
645f982db4aSGavin Atkinson 	(void)free(olocfile);
646f982db4aSGavin Atkinson 	return (rval);
647f982db4aSGavin Atkinson }
648f982db4aSGavin Atkinson 
649f982db4aSGavin Atkinson /* ARGSUSED */
650cc361f65SGavin Atkinson static void
mintr(int signo)651f982db4aSGavin Atkinson mintr(int signo)
652f982db4aSGavin Atkinson {
653f982db4aSGavin Atkinson 
654f982db4aSGavin Atkinson 	alarmtimer(0);
655f982db4aSGavin Atkinson 	if (fromatty)
656f982db4aSGavin Atkinson 		write(fileno(ttyout), "\n", 1);
657f982db4aSGavin Atkinson 	siglongjmp(jabort, 1);
658f982db4aSGavin Atkinson }
659f982db4aSGavin Atkinson 
660cc361f65SGavin Atkinson static void
mabort(const char * cmd)661cc361f65SGavin Atkinson mabort(const char *cmd)
662f982db4aSGavin Atkinson {
663f982db4aSGavin Atkinson 	int ointer, oconf;
664f982db4aSGavin Atkinson 
665f982db4aSGavin Atkinson 	if (mflag && fromatty) {
666f982db4aSGavin Atkinson 		ointer = interactive;
667f982db4aSGavin Atkinson 		oconf = confirmrest;
668f982db4aSGavin Atkinson 		interactive = 1;
669f982db4aSGavin Atkinson 		confirmrest = 0;
670cc361f65SGavin Atkinson 		if (confirm(cmd, NULL)) {
671f982db4aSGavin Atkinson 			interactive = ointer;
672f982db4aSGavin Atkinson 			confirmrest = oconf;
673f982db4aSGavin Atkinson 			return;
674f982db4aSGavin Atkinson 		}
675f982db4aSGavin Atkinson 		interactive = ointer;
676f982db4aSGavin Atkinson 		confirmrest = oconf;
677f982db4aSGavin Atkinson 	}
678f982db4aSGavin Atkinson 	mflag = 0;
679f982db4aSGavin Atkinson }
680f982db4aSGavin Atkinson 
681f982db4aSGavin Atkinson /*
682f982db4aSGavin Atkinson  * Get multiple files.
683f982db4aSGavin Atkinson  */
684f982db4aSGavin Atkinson void
mget(int argc,char * argv[])685f982db4aSGavin Atkinson mget(int argc, char *argv[])
686f982db4aSGavin Atkinson {
687f982db4aSGavin Atkinson 	sigfunc oldintr;
688f982db4aSGavin Atkinson 	int ointer;
689f982db4aSGavin Atkinson 	char *cp;
690f982db4aSGavin Atkinson 	const char *tp;
691cc361f65SGavin Atkinson 	int volatile restartit;
692f982db4aSGavin Atkinson 
693f982db4aSGavin Atkinson 	if (argc == 0 ||
694f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-files"))) {
695cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-files\n", argv[0]);
696f982db4aSGavin Atkinson 		code = -1;
697f982db4aSGavin Atkinson 		return;
698f982db4aSGavin Atkinson 	}
699f982db4aSGavin Atkinson 	mflag = 1;
700f982db4aSGavin Atkinson 	restart_point = 0;
701f982db4aSGavin Atkinson 	restartit = 0;
702f982db4aSGavin Atkinson 	if (strcmp(argv[0], "mreget") == 0) {
703f982db4aSGavin Atkinson 		if (! features[FEAT_REST_STREAM]) {
704f982db4aSGavin Atkinson 			fprintf(ttyout,
705f982db4aSGavin Atkinson 		    "Restart is not supported by the remote server.\n");
706f982db4aSGavin Atkinson 			return;
707f982db4aSGavin Atkinson 		}
708f982db4aSGavin Atkinson 		restartit = 1;
709f982db4aSGavin Atkinson 	}
710f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, mintr);
711f982db4aSGavin Atkinson 	if (sigsetjmp(jabort, 1))
712cc361f65SGavin Atkinson 		mabort(argv[0]);
713f982db4aSGavin Atkinson 	while ((cp = remglob(argv, proxy, NULL)) != NULL) {
714f982db4aSGavin Atkinson 		char buf[MAXPATHLEN];
715f982db4aSGavin Atkinson 		if (*cp == '\0' || !connected) {
716f982db4aSGavin Atkinson 			mflag = 0;
717f982db4aSGavin Atkinson 			continue;
718f982db4aSGavin Atkinson 		}
719f982db4aSGavin Atkinson 		if (! mflag)
720f982db4aSGavin Atkinson 			continue;
721f982db4aSGavin Atkinson 		if (! fileindir(cp, localcwd)) {
722f982db4aSGavin Atkinson 			fprintf(ttyout, "Skipping non-relative filename `%s'\n",
723f982db4aSGavin Atkinson 			    cp);
724f982db4aSGavin Atkinson 			continue;
725f982db4aSGavin Atkinson 		}
726f982db4aSGavin Atkinson 		if (!confirm(argv[0], cp))
727f982db4aSGavin Atkinson 			continue;
728f982db4aSGavin Atkinson 		tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag);
729f982db4aSGavin Atkinson 		if (restartit) {
730f982db4aSGavin Atkinson 			struct stat stbuf;
731f982db4aSGavin Atkinson 
732f982db4aSGavin Atkinson 			if (stat(tp, &stbuf) == 0)
733f982db4aSGavin Atkinson 				restart_point = stbuf.st_size;
734f982db4aSGavin Atkinson 			else
735cc361f65SGavin Atkinson 				warn("Can't stat `%s'", tp);
736f982db4aSGavin Atkinson 		}
737f982db4aSGavin Atkinson 		recvrequest("RETR", tp, cp, restart_point ? "r+" : "w",
738f982db4aSGavin Atkinson 		    tp != cp || !interactive, 1);
739f982db4aSGavin Atkinson 		restart_point = 0;
740f982db4aSGavin Atkinson 		if (!mflag && fromatty) {
741f982db4aSGavin Atkinson 			ointer = interactive;
742f982db4aSGavin Atkinson 			interactive = 1;
743cc361f65SGavin Atkinson 			if (confirm(argv[0], NULL))
744f982db4aSGavin Atkinson 				mflag++;
745f982db4aSGavin Atkinson 			interactive = ointer;
746f982db4aSGavin Atkinson 		}
747f982db4aSGavin Atkinson 	}
748f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
749f982db4aSGavin Atkinson 	mflag = 0;
750f982db4aSGavin Atkinson }
751f982db4aSGavin Atkinson 
752f982db4aSGavin Atkinson /*
753f982db4aSGavin Atkinson  * Read list of filenames from a local file and get those
754f982db4aSGavin Atkinson  */
755f982db4aSGavin Atkinson void
fget(int argc,char * argv[])756f982db4aSGavin Atkinson fget(int argc, char *argv[])
757f982db4aSGavin Atkinson {
758cc361f65SGavin Atkinson 	const char *gmode;
759f982db4aSGavin Atkinson 	FILE	*fp;
760cc361f65SGavin Atkinson 	char	buf[MAXPATHLEN], cmdbuf[MAX_C_NAME];
761f982db4aSGavin Atkinson 
762f982db4aSGavin Atkinson 	if (argc != 2) {
763cc361f65SGavin Atkinson 		UPRINTF("usage: %s localfile\n", argv[0]);
764f982db4aSGavin Atkinson 		code = -1;
765f982db4aSGavin Atkinson 		return;
766f982db4aSGavin Atkinson 	}
767f982db4aSGavin Atkinson 
768f982db4aSGavin Atkinson 	fp = fopen(argv[1], "r");
769f982db4aSGavin Atkinson 	if (fp == NULL) {
770cc361f65SGavin Atkinson 		fprintf(ttyout, "Can't open source file %s\n", argv[1]);
771f982db4aSGavin Atkinson 		code = -1;
772f982db4aSGavin Atkinson 		return;
773f982db4aSGavin Atkinson 	}
774f982db4aSGavin Atkinson 
775cc361f65SGavin Atkinson 	(void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
776cc361f65SGavin Atkinson 	argv[0] = cmdbuf;
777cc361f65SGavin Atkinson 	gmode = restart_point ? "r+" : "w";
778f982db4aSGavin Atkinson 
779cc361f65SGavin Atkinson 	while (get_line(fp, buf, sizeof(buf), NULL) >= 0) {
780f982db4aSGavin Atkinson 		if (buf[0] == '\0')
781f982db4aSGavin Atkinson 			continue;
782f982db4aSGavin Atkinson 		argv[1] = buf;
783cc361f65SGavin Atkinson 		(void)getit(argc, argv, 0, gmode);
784f982db4aSGavin Atkinson 	}
785f982db4aSGavin Atkinson 	fclose(fp);
786f982db4aSGavin Atkinson }
787f982db4aSGavin Atkinson 
788cc361f65SGavin Atkinson const char *
onoff(int val)789cc361f65SGavin Atkinson onoff(int val)
790f982db4aSGavin Atkinson {
791f982db4aSGavin Atkinson 
792cc361f65SGavin Atkinson 	return (val ? "on" : "off");
793f982db4aSGavin Atkinson }
794f982db4aSGavin Atkinson 
795f982db4aSGavin Atkinson /*
796f982db4aSGavin Atkinson  * Show status.
797f982db4aSGavin Atkinson  */
798f982db4aSGavin Atkinson /*ARGSUSED*/
799f982db4aSGavin Atkinson void
status(int argc,char * argv[])800f982db4aSGavin Atkinson status(int argc, char *argv[])
801f982db4aSGavin Atkinson {
802f982db4aSGavin Atkinson 
803f982db4aSGavin Atkinson 	if (argc == 0) {
804cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
805f982db4aSGavin Atkinson 		code = -1;
806f982db4aSGavin Atkinson 		return;
807f982db4aSGavin Atkinson 	}
808f982db4aSGavin Atkinson #ifndef NO_STATUS
809f982db4aSGavin Atkinson 	if (connected)
810f982db4aSGavin Atkinson 		fprintf(ttyout, "Connected %sto %s.\n",
811f982db4aSGavin Atkinson 		    connected == -1 ? "and logged in" : "", hostname);
812f982db4aSGavin Atkinson 	else
813f982db4aSGavin Atkinson 		fputs("Not connected.\n", ttyout);
814f982db4aSGavin Atkinson 	if (!proxy) {
815f982db4aSGavin Atkinson 		pswitch(1);
816f982db4aSGavin Atkinson 		if (connected) {
817f982db4aSGavin Atkinson 			fprintf(ttyout, "Connected for proxy commands to %s.\n",
818f982db4aSGavin Atkinson 			    hostname);
819f982db4aSGavin Atkinson 		}
820f982db4aSGavin Atkinson 		else {
821f982db4aSGavin Atkinson 			fputs("No proxy connection.\n", ttyout);
822f982db4aSGavin Atkinson 		}
823f982db4aSGavin Atkinson 		pswitch(0);
824f982db4aSGavin Atkinson 	}
825f982db4aSGavin Atkinson 	fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
826f982db4aSGavin Atkinson 	    *gateserver ? gateserver : "(none)", gateport);
827f982db4aSGavin Atkinson 	fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
828f982db4aSGavin Atkinson 	    onoff(passivemode), onoff(activefallback));
829f982db4aSGavin Atkinson 	fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
830f982db4aSGavin Atkinson 	    modename, typename, formname, structname);
831f982db4aSGavin Atkinson 	fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
832f982db4aSGavin Atkinson 	    onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob));
833f982db4aSGavin Atkinson 	fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n",
834f982db4aSGavin Atkinson 	    onoff(sunique), onoff(runique));
835f982db4aSGavin Atkinson 	fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
836f982db4aSGavin Atkinson 	fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase),
837f982db4aSGavin Atkinson 	    onoff(crflag));
838f982db4aSGavin Atkinson 	if (ntflag) {
839f982db4aSGavin Atkinson 		fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
840f982db4aSGavin Atkinson 	}
841f982db4aSGavin Atkinson 	else {
842f982db4aSGavin Atkinson 		fputs("Ntrans: off.\n", ttyout);
843f982db4aSGavin Atkinson 	}
844f982db4aSGavin Atkinson 	if (mapflag) {
845f982db4aSGavin Atkinson 		fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
846f982db4aSGavin Atkinson 	}
847f982db4aSGavin Atkinson 	else {
848f982db4aSGavin Atkinson 		fputs("Nmap: off.\n", ttyout);
849f982db4aSGavin Atkinson 	}
850f982db4aSGavin Atkinson 	fprintf(ttyout,
851f982db4aSGavin Atkinson 	    "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
852f982db4aSGavin Atkinson 	    onoff(hash), mark, onoff(progress));
853f982db4aSGavin Atkinson 	fprintf(ttyout,
854f982db4aSGavin Atkinson 	    "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
855f982db4aSGavin Atkinson 	    onoff(rate_get), rate_get, rate_get_incr);
856f982db4aSGavin Atkinson 	fprintf(ttyout,
857f982db4aSGavin Atkinson 	    "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
858f982db4aSGavin Atkinson 	    onoff(rate_put), rate_put, rate_put_incr);
859f982db4aSGavin Atkinson 	fprintf(ttyout,
860f982db4aSGavin Atkinson 	    "Socket buffer sizes: send %d, receive %d.\n",
861f982db4aSGavin Atkinson 	    sndbuf_size, rcvbuf_size);
862f982db4aSGavin Atkinson 	fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport));
863f982db4aSGavin Atkinson 	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
864f982db4aSGavin Atkinson 	    epsv4bad ? " (disabled for this connection)" : "");
865cc361f65SGavin Atkinson 	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6),
866cc361f65SGavin Atkinson 	    epsv6bad ? " (disabled for this connection)" : "");
867f982db4aSGavin Atkinson 	fprintf(ttyout, "Command line editing: %s.\n",
868f982db4aSGavin Atkinson #ifdef NO_EDITCOMPLETE
869f982db4aSGavin Atkinson 	    "support not compiled in"
870f982db4aSGavin Atkinson #else	/* !def NO_EDITCOMPLETE */
871f982db4aSGavin Atkinson 	    onoff(editing)
872f982db4aSGavin Atkinson #endif	/* !def NO_EDITCOMPLETE */
873f982db4aSGavin Atkinson 	    );
874f982db4aSGavin Atkinson 	if (macnum > 0) {
875f982db4aSGavin Atkinson 		int i;
876f982db4aSGavin Atkinson 
877f982db4aSGavin Atkinson 		fputs("Macros:\n", ttyout);
878f982db4aSGavin Atkinson 		for (i=0; i<macnum; i++) {
879f982db4aSGavin Atkinson 			fprintf(ttyout, "\t%s\n", macros[i].mac_name);
880f982db4aSGavin Atkinson 		}
881f982db4aSGavin Atkinson 	}
882f982db4aSGavin Atkinson #endif /* !def NO_STATUS */
883f982db4aSGavin Atkinson 	fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION);
884f982db4aSGavin Atkinson 	code = 0;
885f982db4aSGavin Atkinson }
886f982db4aSGavin Atkinson 
887f982db4aSGavin Atkinson /*
888f982db4aSGavin Atkinson  * Toggle a variable
889f982db4aSGavin Atkinson  */
890f982db4aSGavin Atkinson int
togglevar(int argc,char * argv[],int * var,const char * mesg)891f982db4aSGavin Atkinson togglevar(int argc, char *argv[], int *var, const char *mesg)
892f982db4aSGavin Atkinson {
893f982db4aSGavin Atkinson 	if (argc == 1) {
894f982db4aSGavin Atkinson 		*var = !*var;
895f982db4aSGavin Atkinson 	} else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
896f982db4aSGavin Atkinson 		*var = 1;
897f982db4aSGavin Atkinson 	} else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
898f982db4aSGavin Atkinson 		*var = 0;
899f982db4aSGavin Atkinson 	} else {
900cc361f65SGavin Atkinson 		UPRINTF("usage: %s [ on | off ]\n", argv[0]);
901f982db4aSGavin Atkinson 		return (-1);
902f982db4aSGavin Atkinson 	}
903f982db4aSGavin Atkinson 	if (mesg)
904f982db4aSGavin Atkinson 		fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
905f982db4aSGavin Atkinson 	return (*var);
906f982db4aSGavin Atkinson }
907f982db4aSGavin Atkinson 
908f982db4aSGavin Atkinson /*
909f982db4aSGavin Atkinson  * Set beep on cmd completed mode.
910f982db4aSGavin Atkinson  */
911f982db4aSGavin Atkinson /*VARARGS*/
912f982db4aSGavin Atkinson void
setbell(int argc,char * argv[])913f982db4aSGavin Atkinson setbell(int argc, char *argv[])
914f982db4aSGavin Atkinson {
915f982db4aSGavin Atkinson 
916f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &bell, "Bell mode");
917f982db4aSGavin Atkinson }
918f982db4aSGavin Atkinson 
919f982db4aSGavin Atkinson /*
920f982db4aSGavin Atkinson  * Set command line editing
921f982db4aSGavin Atkinson  */
922f982db4aSGavin Atkinson /*VARARGS*/
923f982db4aSGavin Atkinson void
setedit(int argc,char * argv[])924f982db4aSGavin Atkinson setedit(int argc, char *argv[])
925f982db4aSGavin Atkinson {
926f982db4aSGavin Atkinson 
927f982db4aSGavin Atkinson #ifdef NO_EDITCOMPLETE
928f982db4aSGavin Atkinson 	if (argc == 0) {
929cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
930f982db4aSGavin Atkinson 		code = -1;
931f982db4aSGavin Atkinson 		return;
932f982db4aSGavin Atkinson 	}
933f982db4aSGavin Atkinson 	if (verbose)
934f982db4aSGavin Atkinson 		fputs("Editing support not compiled in; ignoring command.\n",
935f982db4aSGavin Atkinson 		    ttyout);
936f982db4aSGavin Atkinson #else	/* !def NO_EDITCOMPLETE */
937f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &editing, "Editing mode");
938f982db4aSGavin Atkinson 	controlediting();
939f982db4aSGavin Atkinson #endif	/* !def NO_EDITCOMPLETE */
940f982db4aSGavin Atkinson }
941f982db4aSGavin Atkinson 
942f982db4aSGavin Atkinson /*
943f982db4aSGavin Atkinson  * Turn on packet tracing.
944f982db4aSGavin Atkinson  */
945f982db4aSGavin Atkinson /*VARARGS*/
946f982db4aSGavin Atkinson void
settrace(int argc,char * argv[])947f982db4aSGavin Atkinson settrace(int argc, char *argv[])
948f982db4aSGavin Atkinson {
949f982db4aSGavin Atkinson 
950f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &trace, "Packet tracing");
951f982db4aSGavin Atkinson }
952f982db4aSGavin Atkinson 
953f982db4aSGavin Atkinson /*
954f982db4aSGavin Atkinson  * Toggle hash mark printing during transfers, or set hash mark bytecount.
955f982db4aSGavin Atkinson  */
956f982db4aSGavin Atkinson /*VARARGS*/
957f982db4aSGavin Atkinson void
sethash(int argc,char * argv[])958f982db4aSGavin Atkinson sethash(int argc, char *argv[])
959f982db4aSGavin Atkinson {
960f982db4aSGavin Atkinson 	if (argc == 1)
961f982db4aSGavin Atkinson 		hash = !hash;
962f982db4aSGavin Atkinson 	else if (argc != 2) {
963cc361f65SGavin Atkinson 		UPRINTF("usage: %s [ on | off | bytecount ]\n",
964f982db4aSGavin Atkinson 		    argv[0]);
965f982db4aSGavin Atkinson 		code = -1;
966f982db4aSGavin Atkinson 		return;
967f982db4aSGavin Atkinson 	} else if (strcasecmp(argv[1], "on") == 0)
968f982db4aSGavin Atkinson 		hash = 1;
969f982db4aSGavin Atkinson 	else if (strcasecmp(argv[1], "off") == 0)
970f982db4aSGavin Atkinson 		hash = 0;
971f982db4aSGavin Atkinson 	else {
972f982db4aSGavin Atkinson 		int nmark;
973f982db4aSGavin Atkinson 
974f982db4aSGavin Atkinson 		nmark = strsuftoi(argv[1]);
975f982db4aSGavin Atkinson 		if (nmark < 1) {
976f982db4aSGavin Atkinson 			fprintf(ttyout, "mark: bad bytecount value `%s'.\n",
977f982db4aSGavin Atkinson 			    argv[1]);
978f982db4aSGavin Atkinson 			code = -1;
979f982db4aSGavin Atkinson 			return;
980f982db4aSGavin Atkinson 		}
981f982db4aSGavin Atkinson 		mark = nmark;
982f982db4aSGavin Atkinson 		hash = 1;
983f982db4aSGavin Atkinson 	}
984f982db4aSGavin Atkinson 	fprintf(ttyout, "Hash mark printing %s", onoff(hash));
985f982db4aSGavin Atkinson 	if (hash)
986f982db4aSGavin Atkinson 		fprintf(ttyout, " (%d bytes/hash mark)", mark);
987f982db4aSGavin Atkinson 	fputs(".\n", ttyout);
988f982db4aSGavin Atkinson 	if (hash)
989f982db4aSGavin Atkinson 		progress = 0;
990f982db4aSGavin Atkinson 	code = hash;
991f982db4aSGavin Atkinson }
992f982db4aSGavin Atkinson 
993f982db4aSGavin Atkinson /*
994f982db4aSGavin Atkinson  * Turn on printing of server echo's.
995f982db4aSGavin Atkinson  */
996f982db4aSGavin Atkinson /*VARARGS*/
997f982db4aSGavin Atkinson void
setverbose(int argc,char * argv[])998f982db4aSGavin Atkinson setverbose(int argc, char *argv[])
999f982db4aSGavin Atkinson {
1000f982db4aSGavin Atkinson 
1001f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &verbose, "Verbose mode");
1002f982db4aSGavin Atkinson }
1003f982db4aSGavin Atkinson 
1004f982db4aSGavin Atkinson /*
1005f982db4aSGavin Atkinson  * Toggle PORT/LPRT cmd use before each data connection.
1006f982db4aSGavin Atkinson  */
1007f982db4aSGavin Atkinson /*VARARGS*/
1008f982db4aSGavin Atkinson void
setport(int argc,char * argv[])1009f982db4aSGavin Atkinson setport(int argc, char *argv[])
1010f982db4aSGavin Atkinson {
1011f982db4aSGavin Atkinson 
1012f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
1013f982db4aSGavin Atkinson }
1014f982db4aSGavin Atkinson 
1015f982db4aSGavin Atkinson /*
1016f982db4aSGavin Atkinson  * Toggle transfer progress bar.
1017f982db4aSGavin Atkinson  */
1018f982db4aSGavin Atkinson /*VARARGS*/
1019f982db4aSGavin Atkinson void
setprogress(int argc,char * argv[])1020f982db4aSGavin Atkinson setprogress(int argc, char *argv[])
1021f982db4aSGavin Atkinson {
1022f982db4aSGavin Atkinson 
1023f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &progress, "Progress bar");
1024f982db4aSGavin Atkinson 	if (progress)
1025f982db4aSGavin Atkinson 		hash = 0;
1026f982db4aSGavin Atkinson }
1027f982db4aSGavin Atkinson 
1028f982db4aSGavin Atkinson /*
1029f982db4aSGavin Atkinson  * Turn on interactive prompting during mget, mput, and mdelete.
1030f982db4aSGavin Atkinson  */
1031f982db4aSGavin Atkinson /*VARARGS*/
1032f982db4aSGavin Atkinson void
setprompt(int argc,char * argv[])1033f982db4aSGavin Atkinson setprompt(int argc, char *argv[])
1034f982db4aSGavin Atkinson {
1035f982db4aSGavin Atkinson 
1036f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &interactive, "Interactive mode");
1037f982db4aSGavin Atkinson }
1038f982db4aSGavin Atkinson 
1039f982db4aSGavin Atkinson /*
1040f982db4aSGavin Atkinson  * Toggle gate-ftp mode, or set gate-ftp server
1041f982db4aSGavin Atkinson  */
1042f982db4aSGavin Atkinson /*VARARGS*/
1043f982db4aSGavin Atkinson void
setgate(int argc,char * argv[])1044f982db4aSGavin Atkinson setgate(int argc, char *argv[])
1045f982db4aSGavin Atkinson {
1046f982db4aSGavin Atkinson 	static char gsbuf[MAXHOSTNAMELEN];
1047f982db4aSGavin Atkinson 
1048f982db4aSGavin Atkinson 	if (argc == 0 || argc > 3) {
1049cc361f65SGavin Atkinson 		UPRINTF(
1050f982db4aSGavin Atkinson 		    "usage: %s [ on | off | gateserver [port] ]\n", argv[0]);
1051f982db4aSGavin Atkinson 		code = -1;
1052f982db4aSGavin Atkinson 		return;
1053f982db4aSGavin Atkinson 	} else if (argc < 2) {
1054f982db4aSGavin Atkinson 		gatemode = !gatemode;
1055f982db4aSGavin Atkinson 	} else {
1056f982db4aSGavin Atkinson 		if (argc == 2 && strcasecmp(argv[1], "on") == 0)
1057f982db4aSGavin Atkinson 			gatemode = 1;
1058f982db4aSGavin Atkinson 		else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
1059f982db4aSGavin Atkinson 			gatemode = 0;
1060f982db4aSGavin Atkinson 		else {
1061f982db4aSGavin Atkinson 			if (argc == 3)
1062cc361f65SGavin Atkinson 				gateport = ftp_strdup(argv[2]);
1063f982db4aSGavin Atkinson 			(void)strlcpy(gsbuf, argv[1], sizeof(gsbuf));
1064f982db4aSGavin Atkinson 			gateserver = gsbuf;
1065f982db4aSGavin Atkinson 			gatemode = 1;
1066f982db4aSGavin Atkinson 		}
1067f982db4aSGavin Atkinson 	}
1068f982db4aSGavin Atkinson 	if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
1069f982db4aSGavin Atkinson 		fprintf(ttyout,
1070f982db4aSGavin Atkinson 		    "Disabling gate-ftp mode - no gate-ftp server defined.\n");
1071f982db4aSGavin Atkinson 		gatemode = 0;
1072f982db4aSGavin Atkinson 	} else {
1073f982db4aSGavin Atkinson 		fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
1074f982db4aSGavin Atkinson 		    onoff(gatemode), *gateserver ? gateserver : "(none)",
1075f982db4aSGavin Atkinson 		    gateport);
1076f982db4aSGavin Atkinson 	}
1077f982db4aSGavin Atkinson 	code = gatemode;
1078f982db4aSGavin Atkinson }
1079f982db4aSGavin Atkinson 
1080f982db4aSGavin Atkinson /*
1081f982db4aSGavin Atkinson  * Toggle metacharacter interpretation on local file names.
1082f982db4aSGavin Atkinson  */
1083f982db4aSGavin Atkinson /*VARARGS*/
1084f982db4aSGavin Atkinson void
setglob(int argc,char * argv[])1085f982db4aSGavin Atkinson setglob(int argc, char *argv[])
1086f982db4aSGavin Atkinson {
1087f982db4aSGavin Atkinson 
1088f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &doglob, "Globbing");
1089f982db4aSGavin Atkinson }
1090f982db4aSGavin Atkinson 
1091f982db4aSGavin Atkinson /*
1092f982db4aSGavin Atkinson  * Toggle preserving modification times on retrieved files.
1093f982db4aSGavin Atkinson  */
1094f982db4aSGavin Atkinson /*VARARGS*/
1095f982db4aSGavin Atkinson void
setpreserve(int argc,char * argv[])1096f982db4aSGavin Atkinson setpreserve(int argc, char *argv[])
1097f982db4aSGavin Atkinson {
1098f982db4aSGavin Atkinson 
1099f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &preserve, "Preserve modification times");
1100f982db4aSGavin Atkinson }
1101f982db4aSGavin Atkinson 
1102f982db4aSGavin Atkinson /*
1103f982db4aSGavin Atkinson  * Set debugging mode on/off and/or set level of debugging.
1104f982db4aSGavin Atkinson  */
1105f982db4aSGavin Atkinson /*VARARGS*/
1106f982db4aSGavin Atkinson void
setdebug(int argc,char * argv[])1107f982db4aSGavin Atkinson setdebug(int argc, char *argv[])
1108f982db4aSGavin Atkinson {
1109f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2) {
1110cc361f65SGavin Atkinson 		UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]);
1111f982db4aSGavin Atkinson 		code = -1;
1112f982db4aSGavin Atkinson 		return;
1113f982db4aSGavin Atkinson 	} else if (argc == 2) {
1114f982db4aSGavin Atkinson 		if (strcasecmp(argv[1], "on") == 0)
1115cc361f65SGavin Atkinson 			ftp_debug = 1;
1116f982db4aSGavin Atkinson 		else if (strcasecmp(argv[1], "off") == 0)
1117cc361f65SGavin Atkinson 			ftp_debug = 0;
1118f982db4aSGavin Atkinson 		else {
1119f982db4aSGavin Atkinson 			int val;
1120f982db4aSGavin Atkinson 
1121f982db4aSGavin Atkinson 			val = strsuftoi(argv[1]);
1122f982db4aSGavin Atkinson 			if (val < 0) {
1123f982db4aSGavin Atkinson 				fprintf(ttyout, "%s: bad debugging value.\n",
1124f982db4aSGavin Atkinson 				    argv[1]);
1125f982db4aSGavin Atkinson 				code = -1;
1126f982db4aSGavin Atkinson 				return;
1127f982db4aSGavin Atkinson 			}
1128cc361f65SGavin Atkinson 			ftp_debug = val;
1129f982db4aSGavin Atkinson 		}
1130f982db4aSGavin Atkinson 	} else
1131cc361f65SGavin Atkinson 		ftp_debug = !ftp_debug;
1132cc361f65SGavin Atkinson 	if (ftp_debug)
1133f982db4aSGavin Atkinson 		options |= SO_DEBUG;
1134f982db4aSGavin Atkinson 	else
1135f982db4aSGavin Atkinson 		options &= ~SO_DEBUG;
1136cc361f65SGavin Atkinson 	fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug);
1137cc361f65SGavin Atkinson 	code = ftp_debug > 0;
1138f982db4aSGavin Atkinson }
1139f982db4aSGavin Atkinson 
1140f982db4aSGavin Atkinson /*
1141f982db4aSGavin Atkinson  * Set current working directory on remote machine.
1142f982db4aSGavin Atkinson  */
1143f982db4aSGavin Atkinson void
cd(int argc,char * argv[])1144f982db4aSGavin Atkinson cd(int argc, char *argv[])
1145f982db4aSGavin Atkinson {
1146f982db4aSGavin Atkinson 	int r;
1147f982db4aSGavin Atkinson 
1148f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
1149f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-directory"))) {
1150cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-directory\n", argv[0]);
1151f982db4aSGavin Atkinson 		code = -1;
1152f982db4aSGavin Atkinson 		return;
1153f982db4aSGavin Atkinson 	}
1154f982db4aSGavin Atkinson 	r = command("CWD %s", argv[1]);
1155f982db4aSGavin Atkinson 	if (r == ERROR && code == 500) {
1156f982db4aSGavin Atkinson 		if (verbose)
1157f982db4aSGavin Atkinson 			fputs("CWD command not recognized, trying XCWD.\n",
1158f982db4aSGavin Atkinson 			    ttyout);
1159f982db4aSGavin Atkinson 		r = command("XCWD %s", argv[1]);
1160f982db4aSGavin Atkinson 	}
1161f982db4aSGavin Atkinson 	if (r == COMPLETE) {
1162f982db4aSGavin Atkinson 		dirchange = 1;
1163f982db4aSGavin Atkinson 		updateremotecwd();
1164f982db4aSGavin Atkinson 	}
1165f982db4aSGavin Atkinson }
1166f982db4aSGavin Atkinson 
1167f982db4aSGavin Atkinson /*
1168f982db4aSGavin Atkinson  * Set current working directory on local machine.
1169f982db4aSGavin Atkinson  */
1170f982db4aSGavin Atkinson void
lcd(int argc,char * argv[])1171f982db4aSGavin Atkinson lcd(int argc, char *argv[])
1172f982db4aSGavin Atkinson {
1173f982db4aSGavin Atkinson 	char *locdir;
1174f982db4aSGavin Atkinson 
1175f982db4aSGavin Atkinson 	code = -1;
1176f982db4aSGavin Atkinson 	if (argc == 1) {
1177f982db4aSGavin Atkinson 		argc++;
1178f982db4aSGavin Atkinson 		argv[1] = localhome;
1179f982db4aSGavin Atkinson 	}
1180f982db4aSGavin Atkinson 	if (argc != 2) {
1181cc361f65SGavin Atkinson 		UPRINTF("usage: %s [local-directory]\n", argv[0]);
1182f982db4aSGavin Atkinson 		return;
1183f982db4aSGavin Atkinson 	}
1184f982db4aSGavin Atkinson 	if ((locdir = globulize(argv[1])) == NULL)
1185f982db4aSGavin Atkinson 		return;
1186f982db4aSGavin Atkinson 	if (chdir(locdir) == -1)
1187cc361f65SGavin Atkinson 		warn("Can't chdir `%s'", locdir);
1188f982db4aSGavin Atkinson 	else {
1189f982db4aSGavin Atkinson 		updatelocalcwd();
1190f982db4aSGavin Atkinson 		if (localcwd[0]) {
1191f982db4aSGavin Atkinson 			fprintf(ttyout, "Local directory now: %s\n", localcwd);
1192f982db4aSGavin Atkinson 			code = 0;
1193f982db4aSGavin Atkinson 		} else {
1194f982db4aSGavin Atkinson 			fprintf(ttyout, "Unable to determine local directory\n");
1195f982db4aSGavin Atkinson 		}
1196f982db4aSGavin Atkinson 	}
1197f982db4aSGavin Atkinson 	(void)free(locdir);
1198f982db4aSGavin Atkinson }
1199f982db4aSGavin Atkinson 
1200f982db4aSGavin Atkinson /*
1201f982db4aSGavin Atkinson  * Delete a single file.
1202f982db4aSGavin Atkinson  */
1203f982db4aSGavin Atkinson void
delete(int argc,char * argv[])1204f982db4aSGavin Atkinson delete(int argc, char *argv[])
1205f982db4aSGavin Atkinson {
1206f982db4aSGavin Atkinson 
1207f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
1208f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
1209cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-file\n", argv[0]);
1210f982db4aSGavin Atkinson 		code = -1;
1211f982db4aSGavin Atkinson 		return;
1212f982db4aSGavin Atkinson 	}
1213f982db4aSGavin Atkinson 	if (command("DELE %s", argv[1]) == COMPLETE)
1214f982db4aSGavin Atkinson 		dirchange = 1;
1215f982db4aSGavin Atkinson }
1216f982db4aSGavin Atkinson 
1217f982db4aSGavin Atkinson /*
1218f982db4aSGavin Atkinson  * Delete multiple files.
1219f982db4aSGavin Atkinson  */
1220f982db4aSGavin Atkinson void
mdelete(int argc,char * argv[])1221f982db4aSGavin Atkinson mdelete(int argc, char *argv[])
1222f982db4aSGavin Atkinson {
1223f982db4aSGavin Atkinson 	sigfunc oldintr;
1224f982db4aSGavin Atkinson 	int ointer;
1225f982db4aSGavin Atkinson 	char *cp;
1226f982db4aSGavin Atkinson 
1227f982db4aSGavin Atkinson 	if (argc == 0 ||
1228f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-files"))) {
1229cc361f65SGavin Atkinson 		UPRINTF("usage: %s [remote-files]\n", argv[0]);
1230f982db4aSGavin Atkinson 		code = -1;
1231f982db4aSGavin Atkinson 		return;
1232f982db4aSGavin Atkinson 	}
1233f982db4aSGavin Atkinson 	mflag = 1;
1234f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, mintr);
1235f982db4aSGavin Atkinson 	if (sigsetjmp(jabort, 1))
1236cc361f65SGavin Atkinson 		mabort(argv[0]);
1237f982db4aSGavin Atkinson 	while ((cp = remglob(argv, 0, NULL)) != NULL) {
1238f982db4aSGavin Atkinson 		if (*cp == '\0') {
1239f982db4aSGavin Atkinson 			mflag = 0;
1240f982db4aSGavin Atkinson 			continue;
1241f982db4aSGavin Atkinson 		}
1242f982db4aSGavin Atkinson 		if (mflag && confirm(argv[0], cp)) {
1243f982db4aSGavin Atkinson 			if (command("DELE %s", cp) == COMPLETE)
1244f982db4aSGavin Atkinson 				dirchange = 1;
1245f982db4aSGavin Atkinson 			if (!mflag && fromatty) {
1246f982db4aSGavin Atkinson 				ointer = interactive;
1247f982db4aSGavin Atkinson 				interactive = 1;
1248cc361f65SGavin Atkinson 				if (confirm(argv[0], NULL)) {
1249f982db4aSGavin Atkinson 					mflag++;
1250f982db4aSGavin Atkinson 				}
1251f982db4aSGavin Atkinson 				interactive = ointer;
1252f982db4aSGavin Atkinson 			}
1253f982db4aSGavin Atkinson 		}
1254f982db4aSGavin Atkinson 	}
1255f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
1256f982db4aSGavin Atkinson 	mflag = 0;
1257f982db4aSGavin Atkinson }
1258f982db4aSGavin Atkinson 
1259f982db4aSGavin Atkinson /*
1260f982db4aSGavin Atkinson  * Rename a remote file.
1261f982db4aSGavin Atkinson  */
1262f982db4aSGavin Atkinson void
renamefile(int argc,char * argv[])1263f982db4aSGavin Atkinson renamefile(int argc, char *argv[])
1264f982db4aSGavin Atkinson {
1265f982db4aSGavin Atkinson 
1266f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name")))
1267f982db4aSGavin Atkinson 		goto usage;
1268f982db4aSGavin Atkinson 	if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1269f982db4aSGavin Atkinson  usage:
1270cc361f65SGavin Atkinson 		UPRINTF("usage: %s from-name to-name\n", argv[0]);
1271f982db4aSGavin Atkinson 		code = -1;
1272f982db4aSGavin Atkinson 		return;
1273f982db4aSGavin Atkinson 	}
1274f982db4aSGavin Atkinson 	if (command("RNFR %s", argv[1]) == CONTINUE &&
1275f982db4aSGavin Atkinson 	    command("RNTO %s", argv[2]) == COMPLETE)
1276f982db4aSGavin Atkinson 		dirchange = 1;
1277f982db4aSGavin Atkinson }
1278f982db4aSGavin Atkinson 
1279f982db4aSGavin Atkinson /*
1280f982db4aSGavin Atkinson  * Get a directory listing of remote files.
1281f982db4aSGavin Atkinson  * Supports being invoked as:
1282f982db4aSGavin Atkinson  *	cmd		runs
1283f982db4aSGavin Atkinson  *	---		----
1284f982db4aSGavin Atkinson  *	dir, ls		LIST
1285f982db4aSGavin Atkinson  *	mlsd		MLSD
1286f982db4aSGavin Atkinson  *	nlist		NLST
1287f982db4aSGavin Atkinson  *	pdir, pls	LIST |$PAGER
1288cc361f65SGavin Atkinson  *	pmlsd		MLSD |$PAGER
1289f982db4aSGavin Atkinson  */
1290f982db4aSGavin Atkinson void
ls(int argc,char * argv[])1291f982db4aSGavin Atkinson ls(int argc, char *argv[])
1292f982db4aSGavin Atkinson {
1293f982db4aSGavin Atkinson 	const char *cmd;
1294cc361f65SGavin Atkinson 	char *remdir, *locbuf;
1295cc361f65SGavin Atkinson 	const char *locfile;
1296cc361f65SGavin Atkinson 	int pagecmd, mlsdcmd;
1297f982db4aSGavin Atkinson 
1298f982db4aSGavin Atkinson 	remdir = NULL;
1299cc361f65SGavin Atkinson 	locbuf = NULL;
1300f982db4aSGavin Atkinson 	locfile = "-";
1301cc361f65SGavin Atkinson 	pagecmd = mlsdcmd = 0;
1302f982db4aSGavin Atkinson 			/*
1303f982db4aSGavin Atkinson 			 * the only commands that start with `p' are
1304f982db4aSGavin Atkinson 			 * the `pager' versions.
1305f982db4aSGavin Atkinson 			 */
1306f982db4aSGavin Atkinson 	if (argv[0][0] == 'p')
1307f982db4aSGavin Atkinson 		pagecmd = 1;
1308f982db4aSGavin Atkinson 	if (strcmp(argv[0] + pagecmd , "mlsd") == 0) {
1309f982db4aSGavin Atkinson 		if (! features[FEAT_MLST]) {
1310f982db4aSGavin Atkinson 			fprintf(ttyout,
1311f982db4aSGavin Atkinson 			   "MLSD is not supported by the remote server.\n");
1312f982db4aSGavin Atkinson 			return;
1313f982db4aSGavin Atkinson 		}
1314f982db4aSGavin Atkinson 		mlsdcmd = 1;
1315f982db4aSGavin Atkinson 	}
1316f982db4aSGavin Atkinson 	if (argc == 0)
1317f982db4aSGavin Atkinson 		goto usage;
1318f982db4aSGavin Atkinson 
1319f982db4aSGavin Atkinson 	if (mlsdcmd)
1320f982db4aSGavin Atkinson 		cmd = "MLSD";
1321f982db4aSGavin Atkinson 	else if (strcmp(argv[0] + pagecmd, "nlist") == 0)
1322f982db4aSGavin Atkinson 		cmd = "NLST";
1323f982db4aSGavin Atkinson 	else
1324f982db4aSGavin Atkinson 		cmd = "LIST";
1325f982db4aSGavin Atkinson 
1326f982db4aSGavin Atkinson 	if (argc > 1)
1327f982db4aSGavin Atkinson 		remdir = argv[1];
1328f982db4aSGavin Atkinson 	if (argc > 2)
1329f982db4aSGavin Atkinson 		locfile = argv[2];
1330f982db4aSGavin Atkinson 	if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) {
1331f982db4aSGavin Atkinson  usage:
1332f982db4aSGavin Atkinson 		if (pagecmd || mlsdcmd)
1333cc361f65SGavin Atkinson 			UPRINTF("usage: %s [remote-path]\n", argv[0]);
1334f982db4aSGavin Atkinson 		else
1335cc361f65SGavin Atkinson 			UPRINTF("usage: %s [remote-path [local-file]]\n",
1336f982db4aSGavin Atkinson 			    argv[0]);
1337f982db4aSGavin Atkinson 		code = -1;
1338f982db4aSGavin Atkinson 		goto freels;
1339f982db4aSGavin Atkinson 	}
1340f982db4aSGavin Atkinson 
1341f982db4aSGavin Atkinson 	if (pagecmd) {
1342cc361f65SGavin Atkinson 		const char *p;
1343cc361f65SGavin Atkinson 		size_t len;
1344f982db4aSGavin Atkinson 
1345f982db4aSGavin Atkinson 		p = getoptionvalue("pager");
1346f982db4aSGavin Atkinson 		if (EMPTYSTRING(p))
1347f982db4aSGavin Atkinson 			p = DEFAULTPAGER;
1348f982db4aSGavin Atkinson 		len = strlen(p) + 2;
1349cc361f65SGavin Atkinson 		locbuf = ftp_malloc(len);
1350cc361f65SGavin Atkinson 		locbuf[0] = '|';
1351cc361f65SGavin Atkinson 		(void)strlcpy(locbuf + 1, p, len - 1);
1352cc361f65SGavin Atkinson 		locfile = locbuf;
1353f982db4aSGavin Atkinson 	} else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
1354cc361f65SGavin Atkinson 		if ((locbuf = globulize(locfile)) == NULL ||
1355cc361f65SGavin Atkinson 		    !confirm("output to local-file:", locbuf)) {
1356f982db4aSGavin Atkinson 			code = -1;
1357f982db4aSGavin Atkinson 			goto freels;
1358f982db4aSGavin Atkinson 		}
1359cc361f65SGavin Atkinson 		locfile = locbuf;
1360f982db4aSGavin Atkinson 	}
1361f982db4aSGavin Atkinson 	recvrequest(cmd, locfile, remdir, "w", 0, 0);
1362f982db4aSGavin Atkinson  freels:
1363cc361f65SGavin Atkinson 	if (locbuf)
1364cc361f65SGavin Atkinson 		(void)free(locbuf);
1365f982db4aSGavin Atkinson }
1366f982db4aSGavin Atkinson 
1367f982db4aSGavin Atkinson /*
1368f982db4aSGavin Atkinson  * Get a directory listing of multiple remote files.
1369f982db4aSGavin Atkinson  */
1370f982db4aSGavin Atkinson void
mls(int argc,char * argv[])1371f982db4aSGavin Atkinson mls(int argc, char *argv[])
1372f982db4aSGavin Atkinson {
1373f982db4aSGavin Atkinson 	sigfunc oldintr;
1374f982db4aSGavin Atkinson 	int ointer, i;
1375cc361f65SGavin Atkinson 	int volatile dolist;
1376cc361f65SGavin Atkinson 	char * volatile dest, *odest;
1377cc361f65SGavin Atkinson 	const char *lmode;
1378f982db4aSGavin Atkinson 
1379f982db4aSGavin Atkinson 	if (argc == 0)
1380f982db4aSGavin Atkinson 		goto usage;
1381f982db4aSGavin Atkinson 	if (argc < 2 && !another(&argc, &argv, "remote-files"))
1382f982db4aSGavin Atkinson 		goto usage;
1383f982db4aSGavin Atkinson 	if (argc < 3 && !another(&argc, &argv, "local-file")) {
1384f982db4aSGavin Atkinson  usage:
1385cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-files local-file\n", argv[0]);
1386f982db4aSGavin Atkinson 		code = -1;
1387f982db4aSGavin Atkinson 		return;
1388f982db4aSGavin Atkinson 	}
1389f982db4aSGavin Atkinson 	odest = dest = argv[argc - 1];
1390f982db4aSGavin Atkinson 	argv[argc - 1] = NULL;
1391f982db4aSGavin Atkinson 	if (strcmp(dest, "-") && *dest != '|')
1392f982db4aSGavin Atkinson 		if (((dest = globulize(dest)) == NULL) ||
1393f982db4aSGavin Atkinson 		    !confirm("output to local-file:", dest)) {
1394f982db4aSGavin Atkinson 			code = -1;
1395f982db4aSGavin Atkinson 			return;
1396f982db4aSGavin Atkinson 	}
1397f982db4aSGavin Atkinson 	dolist = strcmp(argv[0], "mls");
1398f982db4aSGavin Atkinson 	mflag = 1;
1399f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, mintr);
1400f982db4aSGavin Atkinson 	if (sigsetjmp(jabort, 1))
1401cc361f65SGavin Atkinson 		mabort(argv[0]);
1402f982db4aSGavin Atkinson 	for (i = 1; mflag && i < argc-1 && connected; i++) {
1403cc361f65SGavin Atkinson 		lmode = (i == 1) ? "w" : "a";
1404cc361f65SGavin Atkinson 		recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode,
1405f982db4aSGavin Atkinson 		    0, 0);
1406f982db4aSGavin Atkinson 		if (!mflag && fromatty) {
1407f982db4aSGavin Atkinson 			ointer = interactive;
1408f982db4aSGavin Atkinson 			interactive = 1;
1409cc361f65SGavin Atkinson 			if (confirm(argv[0], NULL)) {
1410f982db4aSGavin Atkinson 				mflag++;
1411f982db4aSGavin Atkinson 			}
1412f982db4aSGavin Atkinson 			interactive = ointer;
1413f982db4aSGavin Atkinson 		}
1414f982db4aSGavin Atkinson 	}
1415f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
1416f982db4aSGavin Atkinson 	mflag = 0;
1417f982db4aSGavin Atkinson 	if (dest != odest)			/* free up after globulize() */
1418f982db4aSGavin Atkinson 		free(dest);
1419f982db4aSGavin Atkinson }
1420f982db4aSGavin Atkinson 
1421f982db4aSGavin Atkinson /*
1422f982db4aSGavin Atkinson  * Do a shell escape
1423f982db4aSGavin Atkinson  */
1424f982db4aSGavin Atkinson /*ARGSUSED*/
1425f982db4aSGavin Atkinson void
shell(int argc,char * argv[])1426f982db4aSGavin Atkinson shell(int argc, char *argv[])
1427f982db4aSGavin Atkinson {
1428f982db4aSGavin Atkinson 	pid_t pid;
1429f982db4aSGavin Atkinson 	sigfunc oldintr;
1430cc361f65SGavin Atkinson 	char shellnam[MAXPATHLEN];
1431cc361f65SGavin Atkinson 	const char *shellp, *namep;
1432f982db4aSGavin Atkinson 	int wait_status;
1433f982db4aSGavin Atkinson 
1434f982db4aSGavin Atkinson 	if (argc == 0) {
1435cc361f65SGavin Atkinson 		UPRINTF("usage: %s [command [args]]\n", argv[0]);
1436f982db4aSGavin Atkinson 		code = -1;
1437f982db4aSGavin Atkinson 		return;
1438f982db4aSGavin Atkinson 	}
1439f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, SIG_IGN);
1440f982db4aSGavin Atkinson 	if ((pid = fork()) == 0) {
1441d54cfbd1SPedro F. Giffuni 		(void)closefrom(3);
1442f982db4aSGavin Atkinson 		(void)xsignal(SIGINT, SIG_DFL);
1443cc361f65SGavin Atkinson 		shellp = getenv("SHELL");
1444cc361f65SGavin Atkinson 		if (shellp == NULL)
1445cc361f65SGavin Atkinson 			shellp = _PATH_BSHELL;
1446cc361f65SGavin Atkinson 		namep = strrchr(shellp, '/');
1447f982db4aSGavin Atkinson 		if (namep == NULL)
1448cc361f65SGavin Atkinson 			namep = shellp;
1449f982db4aSGavin Atkinson 		else
1450f982db4aSGavin Atkinson 			namep++;
1451f982db4aSGavin Atkinson 		(void)strlcpy(shellnam, namep, sizeof(shellnam));
1452cc361f65SGavin Atkinson 		if (ftp_debug) {
1453cc361f65SGavin Atkinson 			fputs(shellp, ttyout);
1454f982db4aSGavin Atkinson 			putc('\n', ttyout);
1455f982db4aSGavin Atkinson 		}
1456f982db4aSGavin Atkinson 		if (argc > 1) {
1457cc361f65SGavin Atkinson 			execl(shellp, shellnam, "-c", altarg, (char *)0);
1458f982db4aSGavin Atkinson 		}
1459f982db4aSGavin Atkinson 		else {
1460cc361f65SGavin Atkinson 			execl(shellp, shellnam, (char *)0);
1461f982db4aSGavin Atkinson 		}
1462cc361f65SGavin Atkinson 		warn("Can't execute `%s'", shellp);
1463f982db4aSGavin Atkinson 		code = -1;
1464f982db4aSGavin Atkinson 		exit(1);
1465f982db4aSGavin Atkinson 	}
1466f982db4aSGavin Atkinson 	if (pid > 0)
1467f982db4aSGavin Atkinson 		while (wait(&wait_status) != pid)
1468f982db4aSGavin Atkinson 			;
1469f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
1470f982db4aSGavin Atkinson 	if (pid == -1) {
1471cc361f65SGavin Atkinson 		warn("Can't fork a subshell; try again later");
1472f982db4aSGavin Atkinson 		code = -1;
1473f982db4aSGavin Atkinson 	} else
1474f982db4aSGavin Atkinson 		code = 0;
1475f982db4aSGavin Atkinson }
1476f982db4aSGavin Atkinson 
1477f982db4aSGavin Atkinson /*
1478f982db4aSGavin Atkinson  * Send new user information (re-login)
1479f982db4aSGavin Atkinson  */
1480f982db4aSGavin Atkinson void
user(int argc,char * argv[])1481f982db4aSGavin Atkinson user(int argc, char *argv[])
1482f982db4aSGavin Atkinson {
1483cc361f65SGavin Atkinson 	char *password;
1484cc361f65SGavin Atkinson 	char emptypass[] = "";
1485f982db4aSGavin Atkinson 	int n, aflag = 0;
1486f982db4aSGavin Atkinson 
1487f982db4aSGavin Atkinson 	if (argc == 0)
1488f982db4aSGavin Atkinson 		goto usage;
1489f982db4aSGavin Atkinson 	if (argc < 2)
1490f982db4aSGavin Atkinson 		(void)another(&argc, &argv, "username");
1491f982db4aSGavin Atkinson 	if (argc < 2 || argc > 4) {
1492f982db4aSGavin Atkinson  usage:
1493cc361f65SGavin Atkinson 		UPRINTF("usage: %s username [password [account]]\n",
1494f982db4aSGavin Atkinson 		    argv[0]);
1495f982db4aSGavin Atkinson 		code = -1;
1496f982db4aSGavin Atkinson 		return;
1497f982db4aSGavin Atkinson 	}
1498f982db4aSGavin Atkinson 	n = command("USER %s", argv[1]);
1499f982db4aSGavin Atkinson 	if (n == CONTINUE) {
1500f982db4aSGavin Atkinson 		if (argc < 3) {
1501cc361f65SGavin Atkinson 			password = getpass("Password: ");
1502cc361f65SGavin Atkinson 			if (password == NULL)
1503cc361f65SGavin Atkinson 				password = emptypass;
1504cc361f65SGavin Atkinson 		} else {
1505cc361f65SGavin Atkinson 			password = argv[2];
1506f982db4aSGavin Atkinson 		}
1507cc361f65SGavin Atkinson 		n = command("PASS %s", password);
1508cc361f65SGavin Atkinson 		memset(password, 0, strlen(password));
1509f982db4aSGavin Atkinson 	}
1510f982db4aSGavin Atkinson 	if (n == CONTINUE) {
1511f982db4aSGavin Atkinson 		aflag++;
1512cc361f65SGavin Atkinson 		if (argc < 4) {
1513cc361f65SGavin Atkinson 			password = getpass("Account: ");
1514cc361f65SGavin Atkinson 			if (password == NULL)
1515cc361f65SGavin Atkinson 				password = emptypass;
1516cc361f65SGavin Atkinson 		} else {
1517cc361f65SGavin Atkinson 			password = argv[3];
1518cc361f65SGavin Atkinson 		}
1519cc361f65SGavin Atkinson 		n = command("ACCT %s", password);
1520cc361f65SGavin Atkinson 		memset(password, 0, strlen(password));
1521f982db4aSGavin Atkinson 	}
1522f982db4aSGavin Atkinson 	if (n != COMPLETE) {
1523f982db4aSGavin Atkinson 		fputs("Login failed.\n", ttyout);
1524f982db4aSGavin Atkinson 		return;
1525f982db4aSGavin Atkinson 	}
1526f982db4aSGavin Atkinson 	if (!aflag && argc == 4) {
1527cc361f65SGavin Atkinson 		password = argv[3];
1528cc361f65SGavin Atkinson 		(void)command("ACCT %s", password);
1529cc361f65SGavin Atkinson 		memset(password, 0, strlen(password));
1530f982db4aSGavin Atkinson 	}
1531f982db4aSGavin Atkinson 	connected = -1;
1532f982db4aSGavin Atkinson 	getremoteinfo();
1533f982db4aSGavin Atkinson }
1534f982db4aSGavin Atkinson 
1535f982db4aSGavin Atkinson /*
1536f982db4aSGavin Atkinson  * Print working directory on remote machine.
1537f982db4aSGavin Atkinson  */
1538f982db4aSGavin Atkinson /*VARARGS*/
1539f982db4aSGavin Atkinson void
pwd(int argc,char * argv[])1540f982db4aSGavin Atkinson pwd(int argc, char *argv[])
1541f982db4aSGavin Atkinson {
1542f982db4aSGavin Atkinson 
1543f982db4aSGavin Atkinson 	code = -1;
1544f982db4aSGavin Atkinson 	if (argc != 1) {
1545cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
1546f982db4aSGavin Atkinson 		return;
1547f982db4aSGavin Atkinson 	}
1548f982db4aSGavin Atkinson 	if (! remotecwd[0])
1549f982db4aSGavin Atkinson 		updateremotecwd();
1550f982db4aSGavin Atkinson 	if (! remotecwd[0])
1551f982db4aSGavin Atkinson 		fprintf(ttyout, "Unable to determine remote directory\n");
1552f982db4aSGavin Atkinson 	else {
1553f982db4aSGavin Atkinson 		fprintf(ttyout, "Remote directory: %s\n", remotecwd);
1554f982db4aSGavin Atkinson 		code = 0;
1555f982db4aSGavin Atkinson 	}
1556f982db4aSGavin Atkinson }
1557f982db4aSGavin Atkinson 
1558f982db4aSGavin Atkinson /*
1559f982db4aSGavin Atkinson  * Print working directory on local machine.
1560f982db4aSGavin Atkinson  */
1561f982db4aSGavin Atkinson void
lpwd(int argc,char * argv[])1562f982db4aSGavin Atkinson lpwd(int argc, char *argv[])
1563f982db4aSGavin Atkinson {
1564f982db4aSGavin Atkinson 
1565f982db4aSGavin Atkinson 	code = -1;
1566f982db4aSGavin Atkinson 	if (argc != 1) {
1567cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
1568f982db4aSGavin Atkinson 		return;
1569f982db4aSGavin Atkinson 	}
1570f982db4aSGavin Atkinson 	if (! localcwd[0])
1571f982db4aSGavin Atkinson 		updatelocalcwd();
1572f982db4aSGavin Atkinson 	if (! localcwd[0])
1573f982db4aSGavin Atkinson 		fprintf(ttyout, "Unable to determine local directory\n");
1574f982db4aSGavin Atkinson 	else {
1575f982db4aSGavin Atkinson 		fprintf(ttyout, "Local directory: %s\n", localcwd);
1576f982db4aSGavin Atkinson 		code = 0;
1577f982db4aSGavin Atkinson 	}
1578f982db4aSGavin Atkinson }
1579f982db4aSGavin Atkinson 
1580f982db4aSGavin Atkinson /*
1581f982db4aSGavin Atkinson  * Make a directory.
1582f982db4aSGavin Atkinson  */
1583f982db4aSGavin Atkinson void
makedir(int argc,char * argv[])1584f982db4aSGavin Atkinson makedir(int argc, char *argv[])
1585f982db4aSGavin Atkinson {
1586f982db4aSGavin Atkinson 	int r;
1587f982db4aSGavin Atkinson 
1588f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
1589f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "directory-name"))) {
1590cc361f65SGavin Atkinson 		UPRINTF("usage: %s directory-name\n", argv[0]);
1591f982db4aSGavin Atkinson 		code = -1;
1592f982db4aSGavin Atkinson 		return;
1593f982db4aSGavin Atkinson 	}
1594f982db4aSGavin Atkinson 	r = command("MKD %s", argv[1]);
1595f982db4aSGavin Atkinson 	if (r == ERROR && code == 500) {
1596f982db4aSGavin Atkinson 		if (verbose)
1597f982db4aSGavin Atkinson 			fputs("MKD command not recognized, trying XMKD.\n",
1598f982db4aSGavin Atkinson 			    ttyout);
1599f982db4aSGavin Atkinson 		r = command("XMKD %s", argv[1]);
1600f982db4aSGavin Atkinson 	}
1601f982db4aSGavin Atkinson 	if (r == COMPLETE)
1602f982db4aSGavin Atkinson 		dirchange = 1;
1603f982db4aSGavin Atkinson }
1604f982db4aSGavin Atkinson 
1605f982db4aSGavin Atkinson /*
1606f982db4aSGavin Atkinson  * Remove a directory.
1607f982db4aSGavin Atkinson  */
1608f982db4aSGavin Atkinson void
removedir(int argc,char * argv[])1609f982db4aSGavin Atkinson removedir(int argc, char *argv[])
1610f982db4aSGavin Atkinson {
1611f982db4aSGavin Atkinson 	int r;
1612f982db4aSGavin Atkinson 
1613f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
1614f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "directory-name"))) {
1615cc361f65SGavin Atkinson 		UPRINTF("usage: %s directory-name\n", argv[0]);
1616f982db4aSGavin Atkinson 		code = -1;
1617f982db4aSGavin Atkinson 		return;
1618f982db4aSGavin Atkinson 	}
1619f982db4aSGavin Atkinson 	r = command("RMD %s", argv[1]);
1620f982db4aSGavin Atkinson 	if (r == ERROR && code == 500) {
1621f982db4aSGavin Atkinson 		if (verbose)
1622f982db4aSGavin Atkinson 			fputs("RMD command not recognized, trying XRMD.\n",
1623f982db4aSGavin Atkinson 			    ttyout);
1624f982db4aSGavin Atkinson 		r = command("XRMD %s", argv[1]);
1625f982db4aSGavin Atkinson 	}
1626f982db4aSGavin Atkinson 	if (r == COMPLETE)
1627f982db4aSGavin Atkinson 		dirchange = 1;
1628f982db4aSGavin Atkinson }
1629f982db4aSGavin Atkinson 
1630f982db4aSGavin Atkinson /*
1631f982db4aSGavin Atkinson  * Send a line, verbatim, to the remote machine.
1632f982db4aSGavin Atkinson  */
1633f982db4aSGavin Atkinson void
quote(int argc,char * argv[])1634f982db4aSGavin Atkinson quote(int argc, char *argv[])
1635f982db4aSGavin Atkinson {
1636f982db4aSGavin Atkinson 
1637f982db4aSGavin Atkinson 	if (argc == 0 ||
1638f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "command line to send"))) {
1639cc361f65SGavin Atkinson 		UPRINTF("usage: %s line-to-send\n", argv[0]);
1640f982db4aSGavin Atkinson 		code = -1;
1641f982db4aSGavin Atkinson 		return;
1642f982db4aSGavin Atkinson 	}
1643f982db4aSGavin Atkinson 	quote1("", argc, argv);
1644f982db4aSGavin Atkinson }
1645f982db4aSGavin Atkinson 
1646f982db4aSGavin Atkinson /*
1647f982db4aSGavin Atkinson  * Send a SITE command to the remote machine.  The line
1648f982db4aSGavin Atkinson  * is sent verbatim to the remote machine, except that the
1649f982db4aSGavin Atkinson  * word "SITE" is added at the front.
1650f982db4aSGavin Atkinson  */
1651f982db4aSGavin Atkinson void
site(int argc,char * argv[])1652f982db4aSGavin Atkinson site(int argc, char *argv[])
1653f982db4aSGavin Atkinson {
1654f982db4aSGavin Atkinson 
1655f982db4aSGavin Atkinson 	if (argc == 0 ||
1656f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){
1657cc361f65SGavin Atkinson 		UPRINTF("usage: %s line-to-send\n", argv[0]);
1658f982db4aSGavin Atkinson 		code = -1;
1659f982db4aSGavin Atkinson 		return;
1660f982db4aSGavin Atkinson 	}
1661f982db4aSGavin Atkinson 	quote1("SITE ", argc, argv);
1662f982db4aSGavin Atkinson }
1663f982db4aSGavin Atkinson 
1664f982db4aSGavin Atkinson /*
1665f982db4aSGavin Atkinson  * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1666f982db4aSGavin Atkinson  * Send the result as a one-line command and get response.
1667f982db4aSGavin Atkinson  */
1668f982db4aSGavin Atkinson void
quote1(const char * initial,int argc,char * argv[])1669f982db4aSGavin Atkinson quote1(const char *initial, int argc, char *argv[])
1670f982db4aSGavin Atkinson {
1671f982db4aSGavin Atkinson 	int i;
1672f982db4aSGavin Atkinson 	char buf[BUFSIZ];		/* must be >= sizeof(line) */
1673f982db4aSGavin Atkinson 
1674f982db4aSGavin Atkinson 	(void)strlcpy(buf, initial, sizeof(buf));
1675f982db4aSGavin Atkinson 	for (i = 1; i < argc; i++) {
1676f982db4aSGavin Atkinson 		(void)strlcat(buf, argv[i], sizeof(buf));
1677f982db4aSGavin Atkinson 		if (i < (argc - 1))
1678f982db4aSGavin Atkinson 			(void)strlcat(buf, " ", sizeof(buf));
1679f982db4aSGavin Atkinson 	}
1680f982db4aSGavin Atkinson 	if (command("%s", buf) == PRELIM) {
1681f982db4aSGavin Atkinson 		while (getreply(0) == PRELIM)
1682f982db4aSGavin Atkinson 			continue;
1683f982db4aSGavin Atkinson 	}
1684f982db4aSGavin Atkinson 	dirchange = 1;
1685f982db4aSGavin Atkinson }
1686f982db4aSGavin Atkinson 
1687f982db4aSGavin Atkinson void
do_chmod(int argc,char * argv[])1688f982db4aSGavin Atkinson do_chmod(int argc, char *argv[])
1689f982db4aSGavin Atkinson {
1690f982db4aSGavin Atkinson 
1691f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode")))
1692f982db4aSGavin Atkinson 		goto usage;
1693f982db4aSGavin Atkinson 	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
1694f982db4aSGavin Atkinson  usage:
1695cc361f65SGavin Atkinson 		UPRINTF("usage: %s mode remote-file\n", argv[0]);
1696f982db4aSGavin Atkinson 		code = -1;
1697f982db4aSGavin Atkinson 		return;
1698f982db4aSGavin Atkinson 	}
1699f982db4aSGavin Atkinson 	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1700f982db4aSGavin Atkinson }
1701f982db4aSGavin Atkinson 
1702f982db4aSGavin Atkinson #define COMMAND_1ARG(argc, argv, cmd)			\
1703f982db4aSGavin Atkinson 	if (argc == 1)					\
1704f982db4aSGavin Atkinson 		command(cmd);				\
1705f982db4aSGavin Atkinson 	else						\
1706f982db4aSGavin Atkinson 		command(cmd " %s", argv[1])
1707f982db4aSGavin Atkinson 
1708f982db4aSGavin Atkinson void
do_umask(int argc,char * argv[])1709f982db4aSGavin Atkinson do_umask(int argc, char *argv[])
1710f982db4aSGavin Atkinson {
1711f982db4aSGavin Atkinson 	int oldverbose = verbose;
1712f982db4aSGavin Atkinson 
1713f982db4aSGavin Atkinson 	if (argc == 0) {
1714cc361f65SGavin Atkinson 		UPRINTF("usage: %s [umask]\n", argv[0]);
1715f982db4aSGavin Atkinson 		code = -1;
1716f982db4aSGavin Atkinson 		return;
1717f982db4aSGavin Atkinson 	}
1718f982db4aSGavin Atkinson 	verbose = 1;
1719f982db4aSGavin Atkinson 	COMMAND_1ARG(argc, argv, "SITE UMASK");
1720f982db4aSGavin Atkinson 	verbose = oldverbose;
1721f982db4aSGavin Atkinson }
1722f982db4aSGavin Atkinson 
1723f982db4aSGavin Atkinson void
idlecmd(int argc,char * argv[])1724f982db4aSGavin Atkinson idlecmd(int argc, char *argv[])
1725f982db4aSGavin Atkinson {
1726f982db4aSGavin Atkinson 	int oldverbose = verbose;
1727f982db4aSGavin Atkinson 
1728f982db4aSGavin Atkinson 	if (argc < 1 || argc > 2) {
1729cc361f65SGavin Atkinson 		UPRINTF("usage: %s [seconds]\n", argv[0]);
1730f982db4aSGavin Atkinson 		code = -1;
1731f982db4aSGavin Atkinson 		return;
1732f982db4aSGavin Atkinson 	}
1733f982db4aSGavin Atkinson 	verbose = 1;
1734f982db4aSGavin Atkinson 	COMMAND_1ARG(argc, argv, "SITE IDLE");
1735f982db4aSGavin Atkinson 	verbose = oldverbose;
1736f982db4aSGavin Atkinson }
1737f982db4aSGavin Atkinson 
1738f982db4aSGavin Atkinson /*
1739f982db4aSGavin Atkinson  * Ask the other side for help.
1740f982db4aSGavin Atkinson  */
1741f982db4aSGavin Atkinson void
rmthelp(int argc,char * argv[])1742f982db4aSGavin Atkinson rmthelp(int argc, char *argv[])
1743f982db4aSGavin Atkinson {
1744f982db4aSGavin Atkinson 	int oldverbose = verbose;
1745f982db4aSGavin Atkinson 
1746f982db4aSGavin Atkinson 	if (argc == 0) {
1747cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
1748f982db4aSGavin Atkinson 		code = -1;
1749f982db4aSGavin Atkinson 		return;
1750f982db4aSGavin Atkinson 	}
1751f982db4aSGavin Atkinson 	verbose = 1;
1752f982db4aSGavin Atkinson 	COMMAND_1ARG(argc, argv, "HELP");
1753f982db4aSGavin Atkinson 	verbose = oldverbose;
1754f982db4aSGavin Atkinson }
1755f982db4aSGavin Atkinson 
1756f982db4aSGavin Atkinson /*
1757f982db4aSGavin Atkinson  * Terminate session and exit.
1758f982db4aSGavin Atkinson  * May be called with 0, NULL.
1759f982db4aSGavin Atkinson  */
1760f982db4aSGavin Atkinson /*VARARGS*/
1761f982db4aSGavin Atkinson void
quit(int argc,char * argv[])1762f982db4aSGavin Atkinson quit(int argc, char *argv[])
1763f982db4aSGavin Atkinson {
1764f982db4aSGavin Atkinson 
1765f982db4aSGavin Atkinson 			/* this may be called with argc == 0, argv == NULL */
1766f982db4aSGavin Atkinson 	if (argc == 0 && argv != NULL) {
1767cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
1768f982db4aSGavin Atkinson 		code = -1;
1769f982db4aSGavin Atkinson 		return;
1770f982db4aSGavin Atkinson 	}
1771f982db4aSGavin Atkinson 	if (connected)
1772f982db4aSGavin Atkinson 		disconnect(0, NULL);
1773f982db4aSGavin Atkinson 	pswitch(1);
1774f982db4aSGavin Atkinson 	if (connected)
1775f982db4aSGavin Atkinson 		disconnect(0, NULL);
1776f982db4aSGavin Atkinson 	exit(0);
1777f982db4aSGavin Atkinson }
1778f982db4aSGavin Atkinson 
1779f982db4aSGavin Atkinson /*
1780f982db4aSGavin Atkinson  * Terminate session, but don't exit.
1781f982db4aSGavin Atkinson  * May be called with 0, NULL.
1782f982db4aSGavin Atkinson  */
1783f982db4aSGavin Atkinson void
disconnect(int argc,char * argv[])1784f982db4aSGavin Atkinson disconnect(int argc, char *argv[])
1785f982db4aSGavin Atkinson {
1786f982db4aSGavin Atkinson 
1787f982db4aSGavin Atkinson 			/* this may be called with argc == 0, argv == NULL */
1788f982db4aSGavin Atkinson 	if (argc == 0 && argv != NULL) {
1789cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
1790f982db4aSGavin Atkinson 		code = -1;
1791f982db4aSGavin Atkinson 		return;
1792f982db4aSGavin Atkinson 	}
1793f982db4aSGavin Atkinson 	if (!connected)
1794f982db4aSGavin Atkinson 		return;
1795f982db4aSGavin Atkinson 	(void)command("QUIT");
1796f982db4aSGavin Atkinson 	cleanuppeer();
1797f982db4aSGavin Atkinson }
1798f982db4aSGavin Atkinson 
1799f982db4aSGavin Atkinson void
account(int argc,char * argv[])1800f982db4aSGavin Atkinson account(int argc, char *argv[])
1801f982db4aSGavin Atkinson {
1802f982db4aSGavin Atkinson 	char *ap;
1803cc361f65SGavin Atkinson 	char emptypass[] = "";
1804f982db4aSGavin Atkinson 
1805f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2) {
1806cc361f65SGavin Atkinson 		UPRINTF("usage: %s [password]\n", argv[0]);
1807f982db4aSGavin Atkinson 		code = -1;
1808f982db4aSGavin Atkinson 		return;
1809f982db4aSGavin Atkinson 	}
1810f982db4aSGavin Atkinson 	else if (argc == 2)
1811f982db4aSGavin Atkinson 		ap = argv[1];
1812cc361f65SGavin Atkinson 	else {
1813f982db4aSGavin Atkinson 		ap = getpass("Account:");
1814cc361f65SGavin Atkinson 		if (ap == NULL)
1815cc361f65SGavin Atkinson 			ap = emptypass;
1816cc361f65SGavin Atkinson 	}
1817f982db4aSGavin Atkinson 	(void)command("ACCT %s", ap);
1818cc361f65SGavin Atkinson 	memset(ap, 0, strlen(ap));
1819f982db4aSGavin Atkinson }
1820f982db4aSGavin Atkinson 
1821f982db4aSGavin Atkinson sigjmp_buf abortprox;
1822f982db4aSGavin Atkinson 
1823f982db4aSGavin Atkinson void
proxabort(int notused)1824f982db4aSGavin Atkinson proxabort(int notused)
1825f982db4aSGavin Atkinson {
1826f982db4aSGavin Atkinson 
1827f982db4aSGavin Atkinson 	sigint_raised = 1;
1828f982db4aSGavin Atkinson 	alarmtimer(0);
1829f982db4aSGavin Atkinson 	if (!proxy) {
1830f982db4aSGavin Atkinson 		pswitch(1);
1831f982db4aSGavin Atkinson 	}
1832f982db4aSGavin Atkinson 	if (connected) {
1833f982db4aSGavin Atkinson 		proxflag = 1;
1834f982db4aSGavin Atkinson 	}
1835f982db4aSGavin Atkinson 	else {
1836f982db4aSGavin Atkinson 		proxflag = 0;
1837f982db4aSGavin Atkinson 	}
1838f982db4aSGavin Atkinson 	pswitch(0);
1839f982db4aSGavin Atkinson 	siglongjmp(abortprox, 1);
1840f982db4aSGavin Atkinson }
1841f982db4aSGavin Atkinson 
1842f982db4aSGavin Atkinson void
doproxy(int argc,char * argv[])1843f982db4aSGavin Atkinson doproxy(int argc, char *argv[])
1844f982db4aSGavin Atkinson {
1845f982db4aSGavin Atkinson 	struct cmd *c;
1846f982db4aSGavin Atkinson 	int cmdpos;
1847f982db4aSGavin Atkinson 	sigfunc oldintr;
1848cc361f65SGavin Atkinson 	char cmdbuf[MAX_C_NAME];
1849f982db4aSGavin Atkinson 
1850f982db4aSGavin Atkinson 	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) {
1851cc361f65SGavin Atkinson 		UPRINTF("usage: %s command\n", argv[0]);
1852f982db4aSGavin Atkinson 		code = -1;
1853f982db4aSGavin Atkinson 		return;
1854f982db4aSGavin Atkinson 	}
1855f982db4aSGavin Atkinson 	c = getcmd(argv[1]);
1856f982db4aSGavin Atkinson 	if (c == (struct cmd *) -1) {
1857f982db4aSGavin Atkinson 		fputs("?Ambiguous command.\n", ttyout);
1858f982db4aSGavin Atkinson 		code = -1;
1859f982db4aSGavin Atkinson 		return;
1860f982db4aSGavin Atkinson 	}
1861f982db4aSGavin Atkinson 	if (c == 0) {
1862f982db4aSGavin Atkinson 		fputs("?Invalid command.\n", ttyout);
1863f982db4aSGavin Atkinson 		code = -1;
1864f982db4aSGavin Atkinson 		return;
1865f982db4aSGavin Atkinson 	}
1866f982db4aSGavin Atkinson 	if (!c->c_proxy) {
1867f982db4aSGavin Atkinson 		fputs("?Invalid proxy command.\n", ttyout);
1868f982db4aSGavin Atkinson 		code = -1;
1869f982db4aSGavin Atkinson 		return;
1870f982db4aSGavin Atkinson 	}
1871f982db4aSGavin Atkinson 	if (sigsetjmp(abortprox, 1)) {
1872f982db4aSGavin Atkinson 		code = -1;
1873f982db4aSGavin Atkinson 		return;
1874f982db4aSGavin Atkinson 	}
1875f982db4aSGavin Atkinson 	oldintr = xsignal(SIGINT, proxabort);
1876f982db4aSGavin Atkinson 	pswitch(1);
1877f982db4aSGavin Atkinson 	if (c->c_conn && !connected) {
1878f982db4aSGavin Atkinson 		fputs("Not connected.\n", ttyout);
1879f982db4aSGavin Atkinson 		pswitch(0);
1880f982db4aSGavin Atkinson 		(void)xsignal(SIGINT, oldintr);
1881f982db4aSGavin Atkinson 		code = -1;
1882f982db4aSGavin Atkinson 		return;
1883f982db4aSGavin Atkinson 	}
1884f982db4aSGavin Atkinson 	cmdpos = strcspn(line, " \t");
1885f982db4aSGavin Atkinson 	if (cmdpos > 0)		/* remove leading "proxy " from input buffer */
1886f982db4aSGavin Atkinson 		memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1887cc361f65SGavin Atkinson 	(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
1888cc361f65SGavin Atkinson 	argv[1] = cmdbuf;
1889f982db4aSGavin Atkinson 	(*c->c_handler)(argc-1, argv+1);
1890f982db4aSGavin Atkinson 	if (connected) {
1891f982db4aSGavin Atkinson 		proxflag = 1;
1892f982db4aSGavin Atkinson 	}
1893f982db4aSGavin Atkinson 	else {
1894f982db4aSGavin Atkinson 		proxflag = 0;
1895f982db4aSGavin Atkinson 	}
1896f982db4aSGavin Atkinson 	pswitch(0);
1897f982db4aSGavin Atkinson 	(void)xsignal(SIGINT, oldintr);
1898f982db4aSGavin Atkinson }
1899f982db4aSGavin Atkinson 
1900f982db4aSGavin Atkinson void
setcase(int argc,char * argv[])1901f982db4aSGavin Atkinson setcase(int argc, char *argv[])
1902f982db4aSGavin Atkinson {
1903f982db4aSGavin Atkinson 
1904f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &mcase, "Case mapping");
1905f982db4aSGavin Atkinson }
1906f982db4aSGavin Atkinson 
1907f982db4aSGavin Atkinson /*
1908f982db4aSGavin Atkinson  * convert the given name to lower case if it's all upper case, into
1909f982db4aSGavin Atkinson  * a static buffer which is returned to the caller
1910f982db4aSGavin Atkinson  */
1911f982db4aSGavin Atkinson static const char *
docase(char * dst,size_t dlen,const char * src)1912f982db4aSGavin Atkinson docase(char *dst, size_t dlen, const char *src)
1913f982db4aSGavin Atkinson {
1914f982db4aSGavin Atkinson 	size_t i;
1915f982db4aSGavin Atkinson 	int dochange = 1;
1916f982db4aSGavin Atkinson 
1917f982db4aSGavin Atkinson 	for (i = 0; src[i] != '\0' && i < dlen - 1; i++) {
1918f982db4aSGavin Atkinson 		dst[i] = src[i];
1919f982db4aSGavin Atkinson 		if (islower((unsigned char)dst[i]))
1920f982db4aSGavin Atkinson 			dochange = 0;
1921f982db4aSGavin Atkinson 	}
1922f982db4aSGavin Atkinson 	dst[i] = '\0';
1923f982db4aSGavin Atkinson 
1924f982db4aSGavin Atkinson 	if (dochange) {
1925f982db4aSGavin Atkinson 		for (i = 0; dst[i] != '\0'; i++)
1926f982db4aSGavin Atkinson 			if (isupper((unsigned char)dst[i]))
1927f982db4aSGavin Atkinson 				dst[i] = tolower((unsigned char)dst[i]);
1928f982db4aSGavin Atkinson 	}
1929f982db4aSGavin Atkinson 	return dst;
1930f982db4aSGavin Atkinson }
1931f982db4aSGavin Atkinson 
1932f982db4aSGavin Atkinson void
setcr(int argc,char * argv[])1933f982db4aSGavin Atkinson setcr(int argc, char *argv[])
1934f982db4aSGavin Atkinson {
1935f982db4aSGavin Atkinson 
1936f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1937f982db4aSGavin Atkinson }
1938f982db4aSGavin Atkinson 
1939f982db4aSGavin Atkinson void
setntrans(int argc,char * argv[])1940f982db4aSGavin Atkinson setntrans(int argc, char *argv[])
1941f982db4aSGavin Atkinson {
1942f982db4aSGavin Atkinson 
1943f982db4aSGavin Atkinson 	if (argc == 0 || argc > 3) {
1944cc361f65SGavin Atkinson 		UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]);
1945f982db4aSGavin Atkinson 		code = -1;
1946f982db4aSGavin Atkinson 		return;
1947f982db4aSGavin Atkinson 	}
1948f982db4aSGavin Atkinson 	if (argc == 1) {
1949f982db4aSGavin Atkinson 		ntflag = 0;
1950f982db4aSGavin Atkinson 		fputs("Ntrans off.\n", ttyout);
1951f982db4aSGavin Atkinson 		code = ntflag;
1952f982db4aSGavin Atkinson 		return;
1953f982db4aSGavin Atkinson 	}
1954f982db4aSGavin Atkinson 	ntflag++;
1955f982db4aSGavin Atkinson 	code = ntflag;
1956f982db4aSGavin Atkinson 	(void)strlcpy(ntin, argv[1], sizeof(ntin));
1957f982db4aSGavin Atkinson 	if (argc == 2) {
1958f982db4aSGavin Atkinson 		ntout[0] = '\0';
1959f982db4aSGavin Atkinson 		return;
1960f982db4aSGavin Atkinson 	}
1961f982db4aSGavin Atkinson 	(void)strlcpy(ntout, argv[2], sizeof(ntout));
1962f982db4aSGavin Atkinson }
1963f982db4aSGavin Atkinson 
1964f982db4aSGavin Atkinson static const char *
dotrans(char * dst,size_t dlen,const char * src)1965f982db4aSGavin Atkinson dotrans(char *dst, size_t dlen, const char *src)
1966f982db4aSGavin Atkinson {
1967f982db4aSGavin Atkinson 	const char *cp1;
1968f982db4aSGavin Atkinson 	char *cp2 = dst;
1969f982db4aSGavin Atkinson 	size_t i, ostop;
1970f982db4aSGavin Atkinson 
1971f982db4aSGavin Atkinson 	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1972f982db4aSGavin Atkinson 		continue;
1973f982db4aSGavin Atkinson 	for (cp1 = src; *cp1; cp1++) {
1974f982db4aSGavin Atkinson 		int found = 0;
1975f982db4aSGavin Atkinson 		for (i = 0; *(ntin + i) && i < 16; i++) {
1976f982db4aSGavin Atkinson 			if (*cp1 == *(ntin + i)) {
1977f982db4aSGavin Atkinson 				found++;
1978f982db4aSGavin Atkinson 				if (i < ostop) {
1979f982db4aSGavin Atkinson 					*cp2++ = *(ntout + i);
1980cc361f65SGavin Atkinson 					if (cp2 - dst >= (ptrdiff_t)(dlen - 1))
1981f982db4aSGavin Atkinson 						goto out;
1982f982db4aSGavin Atkinson 				}
1983f982db4aSGavin Atkinson 				break;
1984f982db4aSGavin Atkinson 			}
1985f982db4aSGavin Atkinson 		}
1986f982db4aSGavin Atkinson 		if (!found) {
1987f982db4aSGavin Atkinson 			*cp2++ = *cp1;
1988f982db4aSGavin Atkinson 		}
1989f982db4aSGavin Atkinson 	}
1990f982db4aSGavin Atkinson out:
1991f982db4aSGavin Atkinson 	*cp2 = '\0';
1992f982db4aSGavin Atkinson 	return dst;
1993f982db4aSGavin Atkinson }
1994f982db4aSGavin Atkinson 
1995f982db4aSGavin Atkinson void
setnmap(int argc,char * argv[])1996f982db4aSGavin Atkinson setnmap(int argc, char *argv[])
1997f982db4aSGavin Atkinson {
1998f982db4aSGavin Atkinson 	char *cp;
1999f982db4aSGavin Atkinson 
2000f982db4aSGavin Atkinson 	if (argc == 1) {
2001f982db4aSGavin Atkinson 		mapflag = 0;
2002f982db4aSGavin Atkinson 		fputs("Nmap off.\n", ttyout);
2003f982db4aSGavin Atkinson 		code = mapflag;
2004f982db4aSGavin Atkinson 		return;
2005f982db4aSGavin Atkinson 	}
2006f982db4aSGavin Atkinson 	if (argc == 0 ||
2007f982db4aSGavin Atkinson 	    (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
2008cc361f65SGavin Atkinson 		UPRINTF("usage: %s [mapin mapout]\n", argv[0]);
2009f982db4aSGavin Atkinson 		code = -1;
2010f982db4aSGavin Atkinson 		return;
2011f982db4aSGavin Atkinson 	}
2012f982db4aSGavin Atkinson 	mapflag = 1;
2013f982db4aSGavin Atkinson 	code = 1;
2014f982db4aSGavin Atkinson 	cp = strchr(altarg, ' ');
2015f982db4aSGavin Atkinson 	if (proxy) {
2016f982db4aSGavin Atkinson 		while(*++cp == ' ')
2017f982db4aSGavin Atkinson 			continue;
2018f982db4aSGavin Atkinson 		altarg = cp;
2019f982db4aSGavin Atkinson 		cp = strchr(altarg, ' ');
2020f982db4aSGavin Atkinson 	}
2021f982db4aSGavin Atkinson 	*cp = '\0';
2022f982db4aSGavin Atkinson 	(void)strlcpy(mapin, altarg, MAXPATHLEN);
2023f982db4aSGavin Atkinson 	while (*++cp == ' ')
2024f982db4aSGavin Atkinson 		continue;
2025f982db4aSGavin Atkinson 	(void)strlcpy(mapout, cp, MAXPATHLEN);
2026f982db4aSGavin Atkinson }
2027f982db4aSGavin Atkinson 
2028f982db4aSGavin Atkinson static const char *
domap(char * dst,size_t dlen,const char * src)2029f982db4aSGavin Atkinson domap(char *dst, size_t dlen, const char *src)
2030f982db4aSGavin Atkinson {
2031f982db4aSGavin Atkinson 	const char *cp1 = src;
2032f982db4aSGavin Atkinson 	char *cp2 = mapin;
2033f982db4aSGavin Atkinson 	const char *tp[9], *te[9];
2034f982db4aSGavin Atkinson 	int i, toks[9], toknum = 0, match = 1;
2035f982db4aSGavin Atkinson 
2036f982db4aSGavin Atkinson 	for (i=0; i < 9; ++i) {
2037f982db4aSGavin Atkinson 		toks[i] = 0;
2038f982db4aSGavin Atkinson 	}
2039f982db4aSGavin Atkinson 	while (match && *cp1 && *cp2) {
2040f982db4aSGavin Atkinson 		switch (*cp2) {
2041f982db4aSGavin Atkinson 			case '\\':
2042f982db4aSGavin Atkinson 				if (*++cp2 != *cp1) {
2043f982db4aSGavin Atkinson 					match = 0;
2044f982db4aSGavin Atkinson 				}
2045f982db4aSGavin Atkinson 				break;
2046f982db4aSGavin Atkinson 			case '$':
2047f982db4aSGavin Atkinson 				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
2048f982db4aSGavin Atkinson 					if (*cp1 != *(++cp2+1)) {
2049f982db4aSGavin Atkinson 						toks[toknum = *cp2 - '1']++;
2050f982db4aSGavin Atkinson 						tp[toknum] = cp1;
2051f982db4aSGavin Atkinson 						while (*++cp1 && *(cp2+1)
2052f982db4aSGavin Atkinson 							!= *cp1);
2053f982db4aSGavin Atkinson 						te[toknum] = cp1;
2054f982db4aSGavin Atkinson 					}
2055f982db4aSGavin Atkinson 					cp2++;
2056f982db4aSGavin Atkinson 					break;
2057f982db4aSGavin Atkinson 				}
2058f982db4aSGavin Atkinson 				/* FALLTHROUGH */
2059f982db4aSGavin Atkinson 			default:
2060f982db4aSGavin Atkinson 				if (*cp2 != *cp1) {
2061f982db4aSGavin Atkinson 					match = 0;
2062f982db4aSGavin Atkinson 				}
2063f982db4aSGavin Atkinson 				break;
2064f982db4aSGavin Atkinson 		}
2065f982db4aSGavin Atkinson 		if (match && *cp1) {
2066f982db4aSGavin Atkinson 			cp1++;
2067f982db4aSGavin Atkinson 		}
2068f982db4aSGavin Atkinson 		if (match && *cp2) {
2069f982db4aSGavin Atkinson 			cp2++;
2070f982db4aSGavin Atkinson 		}
2071f982db4aSGavin Atkinson 	}
2072f982db4aSGavin Atkinson 	if (!match && *cp1) /* last token mismatch */
2073f982db4aSGavin Atkinson 	{
2074f982db4aSGavin Atkinson 		toks[toknum] = 0;
2075f982db4aSGavin Atkinson 	}
2076f982db4aSGavin Atkinson 	cp2 = dst;
2077f982db4aSGavin Atkinson 	*cp2 = '\0';
2078f982db4aSGavin Atkinson 	cp1 = mapout;
2079f982db4aSGavin Atkinson 	while (*cp1) {
2080f982db4aSGavin Atkinson 		match = 0;
2081f982db4aSGavin Atkinson 		switch (*cp1) {
2082f982db4aSGavin Atkinson 			case '\\':
2083f982db4aSGavin Atkinson 				if (*(cp1 + 1)) {
2084f982db4aSGavin Atkinson 					*cp2++ = *++cp1;
2085f982db4aSGavin Atkinson 				}
2086f982db4aSGavin Atkinson 				break;
2087f982db4aSGavin Atkinson 			case '[':
2088f982db4aSGavin Atkinson LOOP:
2089f982db4aSGavin Atkinson 				if (*++cp1 == '$' &&
2090f982db4aSGavin Atkinson 				    isdigit((unsigned char)*(cp1+1))) {
2091f982db4aSGavin Atkinson 					if (*++cp1 == '0') {
2092f982db4aSGavin Atkinson 						const char *cp3 = src;
2093f982db4aSGavin Atkinson 
2094f982db4aSGavin Atkinson 						while (*cp3) {
2095f982db4aSGavin Atkinson 							*cp2++ = *cp3++;
2096f982db4aSGavin Atkinson 						}
2097f982db4aSGavin Atkinson 						match = 1;
2098f982db4aSGavin Atkinson 					}
2099f982db4aSGavin Atkinson 					else if (toks[toknum = *cp1 - '1']) {
2100f982db4aSGavin Atkinson 						const char *cp3 = tp[toknum];
2101f982db4aSGavin Atkinson 
2102f982db4aSGavin Atkinson 						while (cp3 != te[toknum]) {
2103f982db4aSGavin Atkinson 							*cp2++ = *cp3++;
2104f982db4aSGavin Atkinson 						}
2105f982db4aSGavin Atkinson 						match = 1;
2106f982db4aSGavin Atkinson 					}
2107f982db4aSGavin Atkinson 				}
2108f982db4aSGavin Atkinson 				else {
2109f982db4aSGavin Atkinson 					while (*cp1 && *cp1 != ',' &&
2110f982db4aSGavin Atkinson 					    *cp1 != ']') {
2111f982db4aSGavin Atkinson 						if (*cp1 == '\\') {
2112f982db4aSGavin Atkinson 							cp1++;
2113f982db4aSGavin Atkinson 						}
2114f982db4aSGavin Atkinson 						else if (*cp1 == '$' &&
2115f982db4aSGavin Atkinson 						    isdigit((unsigned char)*(cp1+1))) {
2116f982db4aSGavin Atkinson 							if (*++cp1 == '0') {
2117f982db4aSGavin Atkinson 							   const char *cp3 = src;
2118f982db4aSGavin Atkinson 
2119f982db4aSGavin Atkinson 							   while (*cp3) {
2120f982db4aSGavin Atkinson 								*cp2++ = *cp3++;
2121f982db4aSGavin Atkinson 							   }
2122f982db4aSGavin Atkinson 							}
2123f982db4aSGavin Atkinson 							else if (toks[toknum =
2124f982db4aSGavin Atkinson 							    *cp1 - '1']) {
2125f982db4aSGavin Atkinson 							   const char *cp3=tp[toknum];
2126f982db4aSGavin Atkinson 
2127f982db4aSGavin Atkinson 							   while (cp3 !=
2128f982db4aSGavin Atkinson 								  te[toknum]) {
2129f982db4aSGavin Atkinson 								*cp2++ = *cp3++;
2130f982db4aSGavin Atkinson 							   }
2131f982db4aSGavin Atkinson 							}
2132f982db4aSGavin Atkinson 						}
2133f982db4aSGavin Atkinson 						else if (*cp1) {
2134f982db4aSGavin Atkinson 							*cp2++ = *cp1++;
2135f982db4aSGavin Atkinson 						}
2136f982db4aSGavin Atkinson 					}
2137f982db4aSGavin Atkinson 					if (!*cp1) {
2138f982db4aSGavin Atkinson 						fputs(
2139f982db4aSGavin Atkinson 						"nmap: unbalanced brackets.\n",
2140f982db4aSGavin Atkinson 						    ttyout);
2141f982db4aSGavin Atkinson 						return (src);
2142f982db4aSGavin Atkinson 					}
2143f982db4aSGavin Atkinson 					match = 1;
2144f982db4aSGavin Atkinson 					cp1--;
2145f982db4aSGavin Atkinson 				}
2146f982db4aSGavin Atkinson 				if (match) {
2147f982db4aSGavin Atkinson 					while (*++cp1 && *cp1 != ']') {
2148f982db4aSGavin Atkinson 					      if (*cp1 == '\\' && *(cp1 + 1)) {
2149f982db4aSGavin Atkinson 							cp1++;
2150f982db4aSGavin Atkinson 					      }
2151f982db4aSGavin Atkinson 					}
2152f982db4aSGavin Atkinson 					if (!*cp1) {
2153f982db4aSGavin Atkinson 						fputs(
2154f982db4aSGavin Atkinson 						"nmap: unbalanced brackets.\n",
2155f982db4aSGavin Atkinson 						    ttyout);
2156f982db4aSGavin Atkinson 						return (src);
2157f982db4aSGavin Atkinson 					}
2158f982db4aSGavin Atkinson 					break;
2159f982db4aSGavin Atkinson 				}
2160f982db4aSGavin Atkinson 				switch (*++cp1) {
2161f982db4aSGavin Atkinson 					case ',':
2162f982db4aSGavin Atkinson 						goto LOOP;
2163f982db4aSGavin Atkinson 					case ']':
2164f982db4aSGavin Atkinson 						break;
2165f982db4aSGavin Atkinson 					default:
2166f982db4aSGavin Atkinson 						cp1--;
2167f982db4aSGavin Atkinson 						goto LOOP;
2168f982db4aSGavin Atkinson 				}
2169f982db4aSGavin Atkinson 				break;
2170f982db4aSGavin Atkinson 			case '$':
2171f982db4aSGavin Atkinson 				if (isdigit((unsigned char)*(cp1 + 1))) {
2172f982db4aSGavin Atkinson 					if (*++cp1 == '0') {
2173f982db4aSGavin Atkinson 						const char *cp3 = src;
2174f982db4aSGavin Atkinson 
2175f982db4aSGavin Atkinson 						while (*cp3) {
2176f982db4aSGavin Atkinson 							*cp2++ = *cp3++;
2177f982db4aSGavin Atkinson 						}
2178f982db4aSGavin Atkinson 					}
2179f982db4aSGavin Atkinson 					else if (toks[toknum = *cp1 - '1']) {
2180f982db4aSGavin Atkinson 						const char *cp3 = tp[toknum];
2181f982db4aSGavin Atkinson 
2182f982db4aSGavin Atkinson 						while (cp3 != te[toknum]) {
2183f982db4aSGavin Atkinson 							*cp2++ = *cp3++;
2184f982db4aSGavin Atkinson 						}
2185f982db4aSGavin Atkinson 					}
2186f982db4aSGavin Atkinson 					break;
2187f982db4aSGavin Atkinson 				}
2188f982db4aSGavin Atkinson 				/* intentional drop through */
2189f982db4aSGavin Atkinson 			default:
2190f982db4aSGavin Atkinson 				*cp2++ = *cp1;
2191f982db4aSGavin Atkinson 				break;
2192f982db4aSGavin Atkinson 		}
2193f982db4aSGavin Atkinson 		cp1++;
2194f982db4aSGavin Atkinson 	}
2195f982db4aSGavin Atkinson 	*cp2 = '\0';
2196f982db4aSGavin Atkinson 	return *dst ? dst : src;
2197f982db4aSGavin Atkinson }
2198f982db4aSGavin Atkinson 
2199f982db4aSGavin Atkinson void
setpassive(int argc,char * argv[])2200f982db4aSGavin Atkinson setpassive(int argc, char *argv[])
2201f982db4aSGavin Atkinson {
2202f982db4aSGavin Atkinson 
2203f982db4aSGavin Atkinson 	if (argc == 1) {
2204f982db4aSGavin Atkinson 		passivemode = !passivemode;
2205f982db4aSGavin Atkinson 		activefallback = passivemode;
2206f982db4aSGavin Atkinson 	} else if (argc != 2) {
2207f982db4aSGavin Atkinson  passiveusage:
2208cc361f65SGavin Atkinson 		UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]);
2209f982db4aSGavin Atkinson 		code = -1;
2210f982db4aSGavin Atkinson 		return;
2211f982db4aSGavin Atkinson 	} else if (strcasecmp(argv[1], "on") == 0) {
2212f982db4aSGavin Atkinson 		passivemode = 1;
2213f982db4aSGavin Atkinson 		activefallback = 0;
2214f982db4aSGavin Atkinson 	} else if (strcasecmp(argv[1], "off") == 0) {
2215f982db4aSGavin Atkinson 		passivemode = 0;
2216f982db4aSGavin Atkinson 		activefallback = 0;
2217f982db4aSGavin Atkinson 	} else if (strcasecmp(argv[1], "auto") == 0) {
2218f982db4aSGavin Atkinson 		passivemode = 1;
2219f982db4aSGavin Atkinson 		activefallback = 1;
2220f982db4aSGavin Atkinson 	} else
2221f982db4aSGavin Atkinson 		goto passiveusage;
2222f982db4aSGavin Atkinson 	fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
2223f982db4aSGavin Atkinson 	    onoff(passivemode), onoff(activefallback));
2224f982db4aSGavin Atkinson 	code = passivemode;
2225f982db4aSGavin Atkinson }
2226f982db4aSGavin Atkinson 
2227cc361f65SGavin Atkinson 
2228f982db4aSGavin Atkinson void
setepsv4(int argc,char * argv[])2229f982db4aSGavin Atkinson setepsv4(int argc, char *argv[])
2230f982db4aSGavin Atkinson {
2231f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &epsv4,
2232f982db4aSGavin Atkinson 	    verbose ? "EPSV/EPRT on IPv4" : NULL);
2233f982db4aSGavin Atkinson 	epsv4bad = 0;
2234f982db4aSGavin Atkinson }
2235f982db4aSGavin Atkinson 
2236f982db4aSGavin Atkinson void
setepsv6(int argc,char * argv[])2237cc361f65SGavin Atkinson setepsv6(int argc, char *argv[])
2238cc361f65SGavin Atkinson {
2239cc361f65SGavin Atkinson 	code = togglevar(argc, argv, &epsv6,
2240cc361f65SGavin Atkinson 	    verbose ? "EPSV/EPRT on IPv6" : NULL);
2241cc361f65SGavin Atkinson 	epsv6bad = 0;
2242cc361f65SGavin Atkinson }
2243cc361f65SGavin Atkinson 
2244cc361f65SGavin Atkinson void
setepsv(int argc,char * argv[])2245cc361f65SGavin Atkinson setepsv(int argc, char*argv[])
2246cc361f65SGavin Atkinson {
2247cc361f65SGavin Atkinson 	setepsv4(argc,argv);
2248cc361f65SGavin Atkinson 	setepsv6(argc,argv);
2249cc361f65SGavin Atkinson }
2250cc361f65SGavin Atkinson 
2251cc361f65SGavin Atkinson void
setsunique(int argc,char * argv[])2252f982db4aSGavin Atkinson setsunique(int argc, char *argv[])
2253f982db4aSGavin Atkinson {
2254f982db4aSGavin Atkinson 
2255f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &sunique, "Store unique");
2256f982db4aSGavin Atkinson }
2257f982db4aSGavin Atkinson 
2258f982db4aSGavin Atkinson void
setrunique(int argc,char * argv[])2259f982db4aSGavin Atkinson setrunique(int argc, char *argv[])
2260f982db4aSGavin Atkinson {
2261f982db4aSGavin Atkinson 
2262f982db4aSGavin Atkinson 	code = togglevar(argc, argv, &runique, "Receive unique");
2263f982db4aSGavin Atkinson }
2264f982db4aSGavin Atkinson 
2265f982db4aSGavin Atkinson int
parserate(int argc,char * argv[],int cmdlineopt)2266f982db4aSGavin Atkinson parserate(int argc, char *argv[], int cmdlineopt)
2267f982db4aSGavin Atkinson {
2268f982db4aSGavin Atkinson 	int dir, max, incr, showonly;
2269f982db4aSGavin Atkinson 	sigfunc oldusr1, oldusr2;
2270f982db4aSGavin Atkinson 
2271f982db4aSGavin Atkinson 	if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) {
2272f982db4aSGavin Atkinson  usage:
2273f982db4aSGavin Atkinson 		if (cmdlineopt)
2274cc361f65SGavin Atkinson 			UPRINTF(
2275f982db4aSGavin Atkinson 	"usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n",
2276f982db4aSGavin Atkinson 			    argv[0]);
2277f982db4aSGavin Atkinson 		else
2278cc361f65SGavin Atkinson 			UPRINTF(
2279f982db4aSGavin Atkinson 	"usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n",
2280f982db4aSGavin Atkinson 			    argv[0]);
2281f982db4aSGavin Atkinson 		return -1;
2282f982db4aSGavin Atkinson 	}
2283f982db4aSGavin Atkinson 	dir = max = incr = showonly = 0;
2284f982db4aSGavin Atkinson #define	RATE_GET	1
2285f982db4aSGavin Atkinson #define	RATE_PUT	2
2286f982db4aSGavin Atkinson #define	RATE_ALL	(RATE_GET | RATE_PUT)
2287f982db4aSGavin Atkinson 
2288f982db4aSGavin Atkinson 	if (strcasecmp(argv[1], "all") == 0)
2289f982db4aSGavin Atkinson 		dir = RATE_ALL;
2290f982db4aSGavin Atkinson 	else if (strcasecmp(argv[1], "get") == 0)
2291f982db4aSGavin Atkinson 		dir = RATE_GET;
2292f982db4aSGavin Atkinson 	else if (strcasecmp(argv[1], "put") == 0)
2293f982db4aSGavin Atkinson 		dir = RATE_PUT;
2294f982db4aSGavin Atkinson 	else
2295f982db4aSGavin Atkinson 		goto usage;
2296f982db4aSGavin Atkinson 
2297f982db4aSGavin Atkinson 	if (argc >= 3) {
2298f982db4aSGavin Atkinson 		if ((max = strsuftoi(argv[2])) < 0)
2299f982db4aSGavin Atkinson 			goto usage;
2300f982db4aSGavin Atkinson 	} else
2301f982db4aSGavin Atkinson 		showonly = 1;
2302f982db4aSGavin Atkinson 
2303f982db4aSGavin Atkinson 	if (argc == 4) {
2304f982db4aSGavin Atkinson 		if ((incr = strsuftoi(argv[3])) <= 0)
2305f982db4aSGavin Atkinson 			goto usage;
2306f982db4aSGavin Atkinson 	} else
2307f982db4aSGavin Atkinson 		incr = DEFAULTINCR;
2308f982db4aSGavin Atkinson 
2309f982db4aSGavin Atkinson 	oldusr1 = xsignal(SIGUSR1, SIG_IGN);
2310f982db4aSGavin Atkinson 	oldusr2 = xsignal(SIGUSR2, SIG_IGN);
2311f982db4aSGavin Atkinson 	if (dir & RATE_GET) {
2312f982db4aSGavin Atkinson 		if (!showonly) {
2313f982db4aSGavin Atkinson 			rate_get = max;
2314f982db4aSGavin Atkinson 			rate_get_incr = incr;
2315f982db4aSGavin Atkinson 		}
2316f982db4aSGavin Atkinson 		if (!cmdlineopt || verbose)
2317f982db4aSGavin Atkinson 			fprintf(ttyout,
2318f982db4aSGavin Atkinson 		"Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
2319f982db4aSGavin Atkinson 			    onoff(rate_get), rate_get, rate_get_incr);
2320f982db4aSGavin Atkinson 	}
2321f982db4aSGavin Atkinson 	if (dir & RATE_PUT) {
2322f982db4aSGavin Atkinson 		if (!showonly) {
2323f982db4aSGavin Atkinson 			rate_put = max;
2324f982db4aSGavin Atkinson 			rate_put_incr = incr;
2325f982db4aSGavin Atkinson 		}
2326f982db4aSGavin Atkinson 		if (!cmdlineopt || verbose)
2327f982db4aSGavin Atkinson 			fprintf(ttyout,
2328f982db4aSGavin Atkinson 		"Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
2329f982db4aSGavin Atkinson 			    onoff(rate_put), rate_put, rate_put_incr);
2330f982db4aSGavin Atkinson 	}
2331f982db4aSGavin Atkinson 	(void)xsignal(SIGUSR1, oldusr1);
2332f982db4aSGavin Atkinson 	(void)xsignal(SIGUSR2, oldusr2);
2333f982db4aSGavin Atkinson 	return 0;
2334f982db4aSGavin Atkinson }
2335f982db4aSGavin Atkinson 
2336f982db4aSGavin Atkinson void
setrate(int argc,char * argv[])2337f982db4aSGavin Atkinson setrate(int argc, char *argv[])
2338f982db4aSGavin Atkinson {
2339f982db4aSGavin Atkinson 
2340f982db4aSGavin Atkinson 	code = parserate(argc, argv, 0);
2341f982db4aSGavin Atkinson }
2342f982db4aSGavin Atkinson 
2343f982db4aSGavin Atkinson /* change directory to parent directory */
2344f982db4aSGavin Atkinson void
cdup(int argc,char * argv[])2345f982db4aSGavin Atkinson cdup(int argc, char *argv[])
2346f982db4aSGavin Atkinson {
2347f982db4aSGavin Atkinson 	int r;
2348f982db4aSGavin Atkinson 
2349f982db4aSGavin Atkinson 	if (argc == 0) {
2350cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
2351f982db4aSGavin Atkinson 		code = -1;
2352f982db4aSGavin Atkinson 		return;
2353f982db4aSGavin Atkinson 	}
2354f982db4aSGavin Atkinson 	r = command("CDUP");
2355f982db4aSGavin Atkinson 	if (r == ERROR && code == 500) {
2356f982db4aSGavin Atkinson 		if (verbose)
2357f982db4aSGavin Atkinson 			fputs("CDUP command not recognized, trying XCUP.\n",
2358f982db4aSGavin Atkinson 			    ttyout);
2359f982db4aSGavin Atkinson 		r = command("XCUP");
2360f982db4aSGavin Atkinson 	}
2361f982db4aSGavin Atkinson 	if (r == COMPLETE) {
2362f982db4aSGavin Atkinson 		dirchange = 1;
2363f982db4aSGavin Atkinson 		updateremotecwd();
2364f982db4aSGavin Atkinson 	}
2365f982db4aSGavin Atkinson }
2366f982db4aSGavin Atkinson 
2367f982db4aSGavin Atkinson /*
2368f982db4aSGavin Atkinson  * Restart transfer at specific point
2369f982db4aSGavin Atkinson  */
2370f982db4aSGavin Atkinson void
restart(int argc,char * argv[])2371f982db4aSGavin Atkinson restart(int argc, char *argv[])
2372f982db4aSGavin Atkinson {
2373f982db4aSGavin Atkinson 
2374f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2) {
2375cc361f65SGavin Atkinson 		UPRINTF("usage: %s [restart-point]\n", argv[0]);
2376f982db4aSGavin Atkinson 		code = -1;
2377f982db4aSGavin Atkinson 		return;
2378f982db4aSGavin Atkinson 	}
2379f982db4aSGavin Atkinson 	if (! features[FEAT_REST_STREAM]) {
2380f982db4aSGavin Atkinson 		fprintf(ttyout,
2381f982db4aSGavin Atkinson 		    "Restart is not supported by the remote server.\n");
2382f982db4aSGavin Atkinson 		return;
2383f982db4aSGavin Atkinson 	}
2384f982db4aSGavin Atkinson 	if (argc == 2) {
2385f982db4aSGavin Atkinson 		off_t rp;
2386f982db4aSGavin Atkinson 		char *ep;
2387f982db4aSGavin Atkinson 
2388f982db4aSGavin Atkinson 		rp = STRTOLL(argv[1], &ep, 10);
2389f982db4aSGavin Atkinson 		if (rp < 0 || *ep != '\0')
2390f982db4aSGavin Atkinson 			fprintf(ttyout, "restart: Invalid offset `%s'\n",
2391f982db4aSGavin Atkinson 			    argv[1]);
2392f982db4aSGavin Atkinson 		else
2393f982db4aSGavin Atkinson 			restart_point = rp;
2394f982db4aSGavin Atkinson 	}
2395f982db4aSGavin Atkinson 	if (restart_point == 0)
2396f982db4aSGavin Atkinson 		fputs("No restart point defined.\n", ttyout);
2397f982db4aSGavin Atkinson 	else
2398f982db4aSGavin Atkinson 		fprintf(ttyout,
2399f982db4aSGavin Atkinson 		    "Restarting at " LLF " for next get, put or append\n",
2400f982db4aSGavin Atkinson 		    (LLT)restart_point);
2401f982db4aSGavin Atkinson }
2402f982db4aSGavin Atkinson 
2403f982db4aSGavin Atkinson /*
2404f982db4aSGavin Atkinson  * Show remote system type
2405f982db4aSGavin Atkinson  */
2406f982db4aSGavin Atkinson void
syst(int argc,char * argv[])2407f982db4aSGavin Atkinson syst(int argc, char *argv[])
2408f982db4aSGavin Atkinson {
2409f982db4aSGavin Atkinson 	int oldverbose = verbose;
2410f982db4aSGavin Atkinson 
2411f982db4aSGavin Atkinson 	if (argc == 0) {
2412cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
2413f982db4aSGavin Atkinson 		code = -1;
2414f982db4aSGavin Atkinson 		return;
2415f982db4aSGavin Atkinson 	}
2416f982db4aSGavin Atkinson 	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
2417f982db4aSGavin Atkinson 	(void)command("SYST");
2418f982db4aSGavin Atkinson 	verbose = oldverbose;
2419f982db4aSGavin Atkinson }
2420f982db4aSGavin Atkinson 
2421f982db4aSGavin Atkinson void
macdef(int argc,char * argv[])2422f982db4aSGavin Atkinson macdef(int argc, char *argv[])
2423f982db4aSGavin Atkinson {
2424f982db4aSGavin Atkinson 	char *tmp;
2425f982db4aSGavin Atkinson 	int c;
2426f982db4aSGavin Atkinson 
2427f982db4aSGavin Atkinson 	if (argc == 0)
2428f982db4aSGavin Atkinson 		goto usage;
2429f982db4aSGavin Atkinson 	if (macnum == 16) {
2430f982db4aSGavin Atkinson 		fputs("Limit of 16 macros have already been defined.\n",
2431f982db4aSGavin Atkinson 		    ttyout);
2432f982db4aSGavin Atkinson 		code = -1;
2433f982db4aSGavin Atkinson 		return;
2434f982db4aSGavin Atkinson 	}
2435f982db4aSGavin Atkinson 	if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2436f982db4aSGavin Atkinson  usage:
2437cc361f65SGavin Atkinson 		UPRINTF("usage: %s macro_name\n", argv[0]);
2438f982db4aSGavin Atkinson 		code = -1;
2439f982db4aSGavin Atkinson 		return;
2440f982db4aSGavin Atkinson 	}
2441f982db4aSGavin Atkinson 	if (interactive)
2442f982db4aSGavin Atkinson 		fputs(
2443f982db4aSGavin Atkinson 		"Enter macro line by line, terminating it with a null line.\n",
2444f982db4aSGavin Atkinson 		    ttyout);
2445f982db4aSGavin Atkinson 	(void)strlcpy(macros[macnum].mac_name, argv[1],
2446f982db4aSGavin Atkinson 	    sizeof(macros[macnum].mac_name));
2447f982db4aSGavin Atkinson 	if (macnum == 0)
2448f982db4aSGavin Atkinson 		macros[macnum].mac_start = macbuf;
2449f982db4aSGavin Atkinson 	else
2450f982db4aSGavin Atkinson 		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2451f982db4aSGavin Atkinson 	tmp = macros[macnum].mac_start;
2452f982db4aSGavin Atkinson 	while (tmp != macbuf+4096) {
2453f982db4aSGavin Atkinson 		if ((c = getchar()) == EOF) {
2454f982db4aSGavin Atkinson 			fputs("macdef: end of file encountered.\n", ttyout);
2455f982db4aSGavin Atkinson 			code = -1;
2456f982db4aSGavin Atkinson 			return;
2457f982db4aSGavin Atkinson 		}
2458f982db4aSGavin Atkinson 		if ((*tmp = c) == '\n') {
2459f982db4aSGavin Atkinson 			if (tmp == macros[macnum].mac_start) {
2460f982db4aSGavin Atkinson 				macros[macnum++].mac_end = tmp;
2461f982db4aSGavin Atkinson 				code = 0;
2462f982db4aSGavin Atkinson 				return;
2463f982db4aSGavin Atkinson 			}
2464f982db4aSGavin Atkinson 			if (*(tmp-1) == '\0') {
2465f982db4aSGavin Atkinson 				macros[macnum++].mac_end = tmp - 1;
2466f982db4aSGavin Atkinson 				code = 0;
2467f982db4aSGavin Atkinson 				return;
2468f982db4aSGavin Atkinson 			}
2469f982db4aSGavin Atkinson 			*tmp = '\0';
2470f982db4aSGavin Atkinson 		}
2471f982db4aSGavin Atkinson 		tmp++;
2472f982db4aSGavin Atkinson 	}
2473f982db4aSGavin Atkinson 	while (1) {
2474f982db4aSGavin Atkinson 		while ((c = getchar()) != '\n' && c != EOF)
2475f982db4aSGavin Atkinson 			/* LOOP */;
2476f982db4aSGavin Atkinson 		if (c == EOF || getchar() == '\n') {
2477f982db4aSGavin Atkinson 			fputs("Macro not defined - 4K buffer exceeded.\n",
2478f982db4aSGavin Atkinson 			    ttyout);
2479f982db4aSGavin Atkinson 			code = -1;
2480f982db4aSGavin Atkinson 			return;
2481f982db4aSGavin Atkinson 		}
2482f982db4aSGavin Atkinson 	}
2483f982db4aSGavin Atkinson }
2484f982db4aSGavin Atkinson 
2485f982db4aSGavin Atkinson /*
2486f982db4aSGavin Atkinson  * Get size of file on remote machine
2487f982db4aSGavin Atkinson  */
2488f982db4aSGavin Atkinson void
sizecmd(int argc,char * argv[])2489f982db4aSGavin Atkinson sizecmd(int argc, char *argv[])
2490f982db4aSGavin Atkinson {
2491f982db4aSGavin Atkinson 	off_t size;
2492f982db4aSGavin Atkinson 
2493f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
2494f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2495cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-file\n", argv[0]);
2496f982db4aSGavin Atkinson 		code = -1;
2497f982db4aSGavin Atkinson 		return;
2498f982db4aSGavin Atkinson 	}
2499f982db4aSGavin Atkinson 	size = remotesize(argv[1], 1);
2500f982db4aSGavin Atkinson 	if (size != -1)
2501f982db4aSGavin Atkinson 		fprintf(ttyout,
2502f982db4aSGavin Atkinson 		    "%s\t" LLF "\n", argv[1], (LLT)size);
2503f982db4aSGavin Atkinson 	code = (size > 0);
2504f982db4aSGavin Atkinson }
2505f982db4aSGavin Atkinson 
2506f982db4aSGavin Atkinson /*
2507f982db4aSGavin Atkinson  * Get last modification time of file on remote machine
2508f982db4aSGavin Atkinson  */
2509f982db4aSGavin Atkinson void
modtime(int argc,char * argv[])2510f982db4aSGavin Atkinson modtime(int argc, char *argv[])
2511f982db4aSGavin Atkinson {
2512f982db4aSGavin Atkinson 	time_t mtime;
2513f982db4aSGavin Atkinson 
2514f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
2515f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2516cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-file\n", argv[0]);
2517f982db4aSGavin Atkinson 		code = -1;
2518f982db4aSGavin Atkinson 		return;
2519f982db4aSGavin Atkinson 	}
2520f982db4aSGavin Atkinson 	mtime = remotemodtime(argv[1], 1);
2521f982db4aSGavin Atkinson 	if (mtime != -1)
2522cc361f65SGavin Atkinson 		fprintf(ttyout, "%s\t%s", argv[1],
2523cc361f65SGavin Atkinson 		    rfc2822time(localtime(&mtime)));
2524f982db4aSGavin Atkinson 	code = (mtime > 0);
2525f982db4aSGavin Atkinson }
2526f982db4aSGavin Atkinson 
2527f982db4aSGavin Atkinson /*
2528f982db4aSGavin Atkinson  * Show status on remote machine
2529f982db4aSGavin Atkinson  */
2530f982db4aSGavin Atkinson void
rmtstatus(int argc,char * argv[])2531f982db4aSGavin Atkinson rmtstatus(int argc, char *argv[])
2532f982db4aSGavin Atkinson {
2533f982db4aSGavin Atkinson 
2534f982db4aSGavin Atkinson 	if (argc == 0) {
2535cc361f65SGavin Atkinson 		UPRINTF("usage: %s [remote-file]\n", argv[0]);
2536f982db4aSGavin Atkinson 		code = -1;
2537f982db4aSGavin Atkinson 		return;
2538f982db4aSGavin Atkinson 	}
2539f982db4aSGavin Atkinson 	COMMAND_1ARG(argc, argv, "STAT");
2540f982db4aSGavin Atkinson }
2541f982db4aSGavin Atkinson 
2542f982db4aSGavin Atkinson /*
2543f982db4aSGavin Atkinson  * Get file if modtime is more recent than current file
2544f982db4aSGavin Atkinson  */
2545f982db4aSGavin Atkinson void
newer(int argc,char * argv[])2546f982db4aSGavin Atkinson newer(int argc, char *argv[])
2547f982db4aSGavin Atkinson {
2548f982db4aSGavin Atkinson 
2549f982db4aSGavin Atkinson 	if (getit(argc, argv, -1, "w"))
2550f982db4aSGavin Atkinson 		fprintf(ttyout,
2551f982db4aSGavin Atkinson 		    "Local file \"%s\" is newer than remote file \"%s\".\n",
2552f982db4aSGavin Atkinson 		    argv[2], argv[1]);
2553f982db4aSGavin Atkinson }
2554f982db4aSGavin Atkinson 
2555f982db4aSGavin Atkinson /*
2556f982db4aSGavin Atkinson  * Display one local file through $PAGER.
2557f982db4aSGavin Atkinson  */
2558f982db4aSGavin Atkinson void
lpage(int argc,char * argv[])2559f982db4aSGavin Atkinson lpage(int argc, char *argv[])
2560f982db4aSGavin Atkinson {
2561cc361f65SGavin Atkinson 	size_t len;
2562cc361f65SGavin Atkinson 	const char *p;
2563cc361f65SGavin Atkinson 	char *pager, *locfile;
2564f982db4aSGavin Atkinson 
2565f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
2566f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "local-file"))) {
2567cc361f65SGavin Atkinson 		UPRINTF("usage: %s local-file\n", argv[0]);
2568f982db4aSGavin Atkinson 		code = -1;
2569f982db4aSGavin Atkinson 		return;
2570f982db4aSGavin Atkinson 	}
2571f982db4aSGavin Atkinson 	if ((locfile = globulize(argv[1])) == NULL) {
2572f982db4aSGavin Atkinson 		code = -1;
2573f982db4aSGavin Atkinson 		return;
2574f982db4aSGavin Atkinson 	}
2575f982db4aSGavin Atkinson 	p = getoptionvalue("pager");
2576f982db4aSGavin Atkinson 	if (EMPTYSTRING(p))
2577f982db4aSGavin Atkinson 		p = DEFAULTPAGER;
2578f982db4aSGavin Atkinson 	len = strlen(p) + strlen(locfile) + 2;
2579cc361f65SGavin Atkinson 	pager = ftp_malloc(len);
2580f982db4aSGavin Atkinson 	(void)strlcpy(pager, p,		len);
2581f982db4aSGavin Atkinson 	(void)strlcat(pager, " ",	len);
2582f982db4aSGavin Atkinson 	(void)strlcat(pager, locfile,	len);
2583f982db4aSGavin Atkinson 	system(pager);
2584f982db4aSGavin Atkinson 	code = 0;
2585f982db4aSGavin Atkinson 	(void)free(pager);
2586f982db4aSGavin Atkinson 	(void)free(locfile);
2587f982db4aSGavin Atkinson }
2588f982db4aSGavin Atkinson 
2589f982db4aSGavin Atkinson /*
2590f982db4aSGavin Atkinson  * Display one remote file through $PAGER.
2591f982db4aSGavin Atkinson  */
2592f982db4aSGavin Atkinson void
page(int argc,char * argv[])2593f982db4aSGavin Atkinson page(int argc, char *argv[])
2594f982db4aSGavin Atkinson {
2595cc361f65SGavin Atkinson 	int ohash, orestart_point, overbose;
2596cc361f65SGavin Atkinson 	size_t len;
2597cc361f65SGavin Atkinson 	const char *p;
2598cc361f65SGavin Atkinson 	char *pager;
2599f982db4aSGavin Atkinson 
2600f982db4aSGavin Atkinson 	if (argc == 0 || argc > 2 ||
2601f982db4aSGavin Atkinson 	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2602cc361f65SGavin Atkinson 		UPRINTF("usage: %s remote-file\n", argv[0]);
2603f982db4aSGavin Atkinson 		code = -1;
2604f982db4aSGavin Atkinson 		return;
2605f982db4aSGavin Atkinson 	}
2606f982db4aSGavin Atkinson 	p = getoptionvalue("pager");
2607f982db4aSGavin Atkinson 	if (EMPTYSTRING(p))
2608f982db4aSGavin Atkinson 		p = DEFAULTPAGER;
2609f982db4aSGavin Atkinson 	len = strlen(p) + 2;
2610cc361f65SGavin Atkinson 	pager = ftp_malloc(len);
2611f982db4aSGavin Atkinson 	pager[0] = '|';
2612f982db4aSGavin Atkinson 	(void)strlcpy(pager + 1, p, len - 1);
2613f982db4aSGavin Atkinson 
2614f982db4aSGavin Atkinson 	ohash = hash;
2615f982db4aSGavin Atkinson 	orestart_point = restart_point;
2616f982db4aSGavin Atkinson 	overbose = verbose;
2617f982db4aSGavin Atkinson 	hash = restart_point = verbose = 0;
2618f982db4aSGavin Atkinson 	recvrequest("RETR", pager, argv[1], "r+", 1, 0);
2619f982db4aSGavin Atkinson 	hash = ohash;
2620f982db4aSGavin Atkinson 	restart_point = orestart_point;
2621f982db4aSGavin Atkinson 	verbose = overbose;
2622f982db4aSGavin Atkinson 	(void)free(pager);
2623f982db4aSGavin Atkinson }
2624f982db4aSGavin Atkinson 
2625f982db4aSGavin Atkinson /*
2626f982db4aSGavin Atkinson  * Set the socket send or receive buffer size.
2627f982db4aSGavin Atkinson  */
2628f982db4aSGavin Atkinson void
setxferbuf(int argc,char * argv[])2629f982db4aSGavin Atkinson setxferbuf(int argc, char *argv[])
2630f982db4aSGavin Atkinson {
2631f982db4aSGavin Atkinson 	int size, dir;
2632f982db4aSGavin Atkinson 
2633f982db4aSGavin Atkinson 	if (argc != 2) {
2634f982db4aSGavin Atkinson  usage:
2635cc361f65SGavin Atkinson 		UPRINTF("usage: %s size\n", argv[0]);
2636f982db4aSGavin Atkinson 		code = -1;
2637f982db4aSGavin Atkinson 		return;
2638f982db4aSGavin Atkinson 	}
2639f982db4aSGavin Atkinson 	if (strcasecmp(argv[0], "sndbuf") == 0)
2640f982db4aSGavin Atkinson 		dir = RATE_PUT;
2641f982db4aSGavin Atkinson 	else if (strcasecmp(argv[0], "rcvbuf") == 0)
2642f982db4aSGavin Atkinson 		dir = RATE_GET;
2643f982db4aSGavin Atkinson 	else if (strcasecmp(argv[0], "xferbuf") == 0)
2644f982db4aSGavin Atkinson 		dir = RATE_ALL;
2645f982db4aSGavin Atkinson 	else
2646f982db4aSGavin Atkinson 		goto usage;
2647f982db4aSGavin Atkinson 
2648f982db4aSGavin Atkinson 	if ((size = strsuftoi(argv[1])) == -1)
2649f982db4aSGavin Atkinson 		goto usage;
2650f982db4aSGavin Atkinson 
2651f982db4aSGavin Atkinson 	if (size == 0) {
2652f982db4aSGavin Atkinson 		fprintf(ttyout, "%s: size must be positive.\n", argv[0]);
2653f982db4aSGavin Atkinson 		goto usage;
2654f982db4aSGavin Atkinson 	}
2655f982db4aSGavin Atkinson 
2656*43092b7dSHiroki Sato 	if (dir & RATE_PUT) {
2657f982db4aSGavin Atkinson 		sndbuf_size = size;
2658*43092b7dSHiroki Sato 		auto_sndbuf = 0;
2659*43092b7dSHiroki Sato 	}
2660*43092b7dSHiroki Sato 	if (dir & RATE_GET) {
2661f982db4aSGavin Atkinson 		rcvbuf_size = size;
2662*43092b7dSHiroki Sato 		auto_rcvbuf = 0;
2663*43092b7dSHiroki Sato 	}
2664f982db4aSGavin Atkinson 	fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n",
2665f982db4aSGavin Atkinson 	    sndbuf_size, rcvbuf_size);
2666f982db4aSGavin Atkinson 	code = 0;
2667f982db4aSGavin Atkinson }
2668f982db4aSGavin Atkinson 
2669f982db4aSGavin Atkinson /*
2670f982db4aSGavin Atkinson  * Set or display options (defaults are provided by various env vars)
2671f982db4aSGavin Atkinson  */
2672f982db4aSGavin Atkinson void
setoption(int argc,char * argv[])2673f982db4aSGavin Atkinson setoption(int argc, char *argv[])
2674f982db4aSGavin Atkinson {
2675f982db4aSGavin Atkinson 	struct option *o;
2676f982db4aSGavin Atkinson 
2677f982db4aSGavin Atkinson 	code = -1;
2678f982db4aSGavin Atkinson 	if (argc == 0 || (argc != 1 && argc != 3)) {
2679cc361f65SGavin Atkinson 		UPRINTF("usage: %s [option value]\n", argv[0]);
2680f982db4aSGavin Atkinson 		return;
2681f982db4aSGavin Atkinson 	}
2682f982db4aSGavin Atkinson 
2683f982db4aSGavin Atkinson #define	OPTIONINDENT ((int) sizeof("http_proxy"))
2684f982db4aSGavin Atkinson 	if (argc == 1) {
2685f982db4aSGavin Atkinson 		for (o = optiontab; o->name != NULL; o++) {
2686f982db4aSGavin Atkinson 			fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT,
2687f982db4aSGavin Atkinson 			    o->name, o->value ? o->value : "");
2688f982db4aSGavin Atkinson 		}
2689f982db4aSGavin Atkinson 	} else {
2690cc361f65SGavin Atkinson 		set_option(argv[1], argv[2], 1);
2691cc361f65SGavin Atkinson 	}
2692cc361f65SGavin Atkinson 	code = 0;
2693cc361f65SGavin Atkinson }
2694cc361f65SGavin Atkinson 
2695cc361f65SGavin Atkinson void
set_option(const char * option,const char * value,int doverbose)2696cc361f65SGavin Atkinson set_option(const char * option, const char * value, int doverbose)
2697cc361f65SGavin Atkinson {
2698cc361f65SGavin Atkinson 	struct option *o;
2699cc361f65SGavin Atkinson 
2700cc361f65SGavin Atkinson 	o = getoption(option);
2701f982db4aSGavin Atkinson 	if (o == NULL) {
2702cc361f65SGavin Atkinson 		fprintf(ttyout, "No such option `%s'.\n", option);
2703f982db4aSGavin Atkinson 		return;
2704f982db4aSGavin Atkinson 	}
2705f982db4aSGavin Atkinson 	FREEPTR(o->value);
2706cc361f65SGavin Atkinson 	o->value = ftp_strdup(value);
2707cc361f65SGavin Atkinson 	if (verbose && doverbose)
2708f982db4aSGavin Atkinson 		fprintf(ttyout, "Setting `%s' to `%s'.\n",
2709f982db4aSGavin Atkinson 		    o->name, o->value);
2710f982db4aSGavin Atkinson }
2711f982db4aSGavin Atkinson 
2712f982db4aSGavin Atkinson /*
2713f982db4aSGavin Atkinson  * Unset an option
2714f982db4aSGavin Atkinson  */
2715f982db4aSGavin Atkinson void
unsetoption(int argc,char * argv[])2716f982db4aSGavin Atkinson unsetoption(int argc, char *argv[])
2717f982db4aSGavin Atkinson {
2718f982db4aSGavin Atkinson 	struct option *o;
2719f982db4aSGavin Atkinson 
2720f982db4aSGavin Atkinson 	code = -1;
2721f982db4aSGavin Atkinson 	if (argc == 0 || argc != 2) {
2722cc361f65SGavin Atkinson 		UPRINTF("usage: %s option\n", argv[0]);
2723f982db4aSGavin Atkinson 		return;
2724f982db4aSGavin Atkinson 	}
2725f982db4aSGavin Atkinson 
2726f982db4aSGavin Atkinson 	o = getoption(argv[1]);
2727f982db4aSGavin Atkinson 	if (o == NULL) {
2728f982db4aSGavin Atkinson 		fprintf(ttyout, "No such option `%s'.\n", argv[1]);
2729f982db4aSGavin Atkinson 		return;
2730f982db4aSGavin Atkinson 	}
2731f982db4aSGavin Atkinson 	FREEPTR(o->value);
2732f982db4aSGavin Atkinson 	fprintf(ttyout, "Unsetting `%s'.\n", o->name);
2733f982db4aSGavin Atkinson 	code = 0;
2734f982db4aSGavin Atkinson }
2735f982db4aSGavin Atkinson 
2736f982db4aSGavin Atkinson /*
2737f982db4aSGavin Atkinson  * Display features supported by the remote host.
2738f982db4aSGavin Atkinson  */
2739f982db4aSGavin Atkinson void
feat(int argc,char * argv[])2740f982db4aSGavin Atkinson feat(int argc, char *argv[])
2741f982db4aSGavin Atkinson {
2742f982db4aSGavin Atkinson 	int oldverbose = verbose;
2743f982db4aSGavin Atkinson 
2744f982db4aSGavin Atkinson 	if (argc == 0) {
2745cc361f65SGavin Atkinson 		UPRINTF("usage: %s\n", argv[0]);
2746f982db4aSGavin Atkinson 		code = -1;
2747f982db4aSGavin Atkinson 		return;
2748f982db4aSGavin Atkinson 	}
2749f982db4aSGavin Atkinson 	if (! features[FEAT_FEAT]) {
2750f982db4aSGavin Atkinson 		fprintf(ttyout,
2751f982db4aSGavin Atkinson 		    "FEAT is not supported by the remote server.\n");
2752f982db4aSGavin Atkinson 		return;
2753f982db4aSGavin Atkinson 	}
2754f982db4aSGavin Atkinson 	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
2755f982db4aSGavin Atkinson 	(void)command("FEAT");
2756f982db4aSGavin Atkinson 	verbose = oldverbose;
2757f982db4aSGavin Atkinson }
2758f982db4aSGavin Atkinson 
2759f982db4aSGavin Atkinson void
mlst(int argc,char * argv[])2760f982db4aSGavin Atkinson mlst(int argc, char *argv[])
2761f982db4aSGavin Atkinson {
2762f982db4aSGavin Atkinson 	int oldverbose = verbose;
2763f982db4aSGavin Atkinson 
2764f982db4aSGavin Atkinson 	if (argc < 1 || argc > 2) {
2765cc361f65SGavin Atkinson 		UPRINTF("usage: %s [remote-path]\n", argv[0]);
2766f982db4aSGavin Atkinson 		code = -1;
2767f982db4aSGavin Atkinson 		return;
2768f982db4aSGavin Atkinson 	}
2769f982db4aSGavin Atkinson 	if (! features[FEAT_MLST]) {
2770f982db4aSGavin Atkinson 		fprintf(ttyout,
2771f982db4aSGavin Atkinson 		    "MLST is not supported by the remote server.\n");
2772f982db4aSGavin Atkinson 		return;
2773f982db4aSGavin Atkinson 	}
2774f982db4aSGavin Atkinson 	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
2775f982db4aSGavin Atkinson 	COMMAND_1ARG(argc, argv, "MLST");
2776f982db4aSGavin Atkinson 	verbose = oldverbose;
2777f982db4aSGavin Atkinson }
2778f982db4aSGavin Atkinson 
2779f982db4aSGavin Atkinson void
opts(int argc,char * argv[])2780f982db4aSGavin Atkinson opts(int argc, char *argv[])
2781f982db4aSGavin Atkinson {
2782f982db4aSGavin Atkinson 	int oldverbose = verbose;
2783f982db4aSGavin Atkinson 
2784f982db4aSGavin Atkinson 	if (argc < 2 || argc > 3) {
2785cc361f65SGavin Atkinson 		UPRINTF("usage: %s command [options]\n", argv[0]);
2786f982db4aSGavin Atkinson 		code = -1;
2787f982db4aSGavin Atkinson 		return;
2788f982db4aSGavin Atkinson 	}
2789f982db4aSGavin Atkinson 	if (! features[FEAT_FEAT]) {
2790f982db4aSGavin Atkinson 		fprintf(ttyout,
2791f982db4aSGavin Atkinson 		    "OPTS is not supported by the remote server.\n");
2792f982db4aSGavin Atkinson 		return;
2793f982db4aSGavin Atkinson 	}
2794f982db4aSGavin Atkinson 	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
2795f982db4aSGavin Atkinson 	if (argc == 2)
2796f982db4aSGavin Atkinson 		command("OPTS %s", argv[1]);
2797f982db4aSGavin Atkinson 	else
2798f982db4aSGavin Atkinson 		command("OPTS %s %s", argv[1], argv[2]);
2799f982db4aSGavin Atkinson 	verbose = oldverbose;
2800f982db4aSGavin Atkinson }
2801