xref: /openbsd-src/usr.bin/ftp/cmds.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: cmds.c,v 1.85 2023/03/08 04:43:11 guenther Exp $	*/
2bfd817adSflorian /*	$NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $	*/
3bfd817adSflorian 
4bfd817adSflorian /*
5bfd817adSflorian  * Copyright (C) 1997 and 1998 WIDE Project.
6bfd817adSflorian  * All rights reserved.
7bfd817adSflorian  *
8bfd817adSflorian  * Redistribution and use in source and binary forms, with or without
9bfd817adSflorian  * modification, are permitted provided that the following conditions
10bfd817adSflorian  * are met:
11bfd817adSflorian  * 1. Redistributions of source code must retain the above copyright
12bfd817adSflorian  *    notice, this list of conditions and the following disclaimer.
13bfd817adSflorian  * 2. Redistributions in binary form must reproduce the above copyright
14bfd817adSflorian  *    notice, this list of conditions and the following disclaimer in the
15bfd817adSflorian  *    documentation and/or other materials provided with the distribution.
16bfd817adSflorian  * 3. Neither the name of the project nor the names of its contributors
17bfd817adSflorian  *    may be used to endorse or promote products derived from this software
18bfd817adSflorian  *    without specific prior written permission.
19bfd817adSflorian  *
20bfd817adSflorian  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21bfd817adSflorian  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22bfd817adSflorian  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23bfd817adSflorian  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24bfd817adSflorian  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25bfd817adSflorian  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26bfd817adSflorian  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27bfd817adSflorian  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28bfd817adSflorian  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29bfd817adSflorian  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30bfd817adSflorian  * SUCH DAMAGE.
31bfd817adSflorian  */
32bfd817adSflorian 
33bfd817adSflorian /*
34bfd817adSflorian  * Copyright (c) 1985, 1989, 1993, 1994
35bfd817adSflorian  *	The Regents of the University of California.  All rights reserved.
36bfd817adSflorian  *
37bfd817adSflorian  * Redistribution and use in source and binary forms, with or without
38bfd817adSflorian  * modification, are permitted provided that the following conditions
39bfd817adSflorian  * are met:
40bfd817adSflorian  * 1. Redistributions of source code must retain the above copyright
41bfd817adSflorian  *    notice, this list of conditions and the following disclaimer.
42bfd817adSflorian  * 2. Redistributions in binary form must reproduce the above copyright
43bfd817adSflorian  *    notice, this list of conditions and the following disclaimer in the
44bfd817adSflorian  *    documentation and/or other materials provided with the distribution.
45bfd817adSflorian  * 3. Neither the name of the University nor the names of its contributors
46bfd817adSflorian  *    may be used to endorse or promote products derived from this software
47bfd817adSflorian  *    without specific prior written permission.
48bfd817adSflorian  *
49bfd817adSflorian  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50bfd817adSflorian  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51bfd817adSflorian  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52bfd817adSflorian  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53bfd817adSflorian  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54bfd817adSflorian  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55bfd817adSflorian  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56bfd817adSflorian  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57bfd817adSflorian  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58bfd817adSflorian  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59bfd817adSflorian  * SUCH DAMAGE.
60bfd817adSflorian  */
61bfd817adSflorian 
62bfd817adSflorian #ifndef SMALL
63bfd817adSflorian 
64bfd817adSflorian /*
65bfd817adSflorian  * FTP User Program -- Command Routines.
66bfd817adSflorian  */
67bfd817adSflorian #include <sys/types.h>
68bfd817adSflorian #include <sys/socket.h>
69bfd817adSflorian #include <sys/stat.h>
70bfd817adSflorian #include <sys/wait.h>
71bfd817adSflorian #include <arpa/ftp.h>
72bfd817adSflorian 
73bfd817adSflorian #include <ctype.h>
74bfd817adSflorian #include <err.h>
75bfd817adSflorian #include <fnmatch.h>
76bfd817adSflorian #include <glob.h>
77bfd817adSflorian #include <netdb.h>
78bfd817adSflorian #include <stdio.h>
79bfd817adSflorian #include <stdlib.h>
80bfd817adSflorian #include <string.h>
81bfd817adSflorian #include <unistd.h>
82bfd817adSflorian #include <errno.h>
83bfd817adSflorian 
84bfd817adSflorian #include "ftp_var.h"
85bfd817adSflorian #include "pathnames.h"
86bfd817adSflorian #include "cmds.h"
87bfd817adSflorian 
88bfd817adSflorian /*
89bfd817adSflorian  * Set ascii transfer type.
90bfd817adSflorian  */
91bfd817adSflorian void
setascii(int argc,char * argv[])92bfd817adSflorian setascii(int argc, char *argv[])
93bfd817adSflorian {
94bfd817adSflorian 
95bfd817adSflorian 	stype[1] = "ascii";
96bfd817adSflorian 	settype(2, stype);
97bfd817adSflorian }
98bfd817adSflorian 
99bfd817adSflorian /*
100bfd817adSflorian  * Set file transfer mode.
101bfd817adSflorian  */
102bfd817adSflorian void
setftmode(int argc,char * argv[])103bfd817adSflorian setftmode(int argc, char *argv[])
104bfd817adSflorian {
105bfd817adSflorian 
106bfd817adSflorian 	fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
107bfd817adSflorian 	code = -1;
108bfd817adSflorian }
109bfd817adSflorian 
110bfd817adSflorian /*
111bfd817adSflorian  * Set file transfer format.
112bfd817adSflorian  */
113bfd817adSflorian void
setform(int argc,char * argv[])114bfd817adSflorian setform(int argc, char *argv[])
115bfd817adSflorian {
116bfd817adSflorian 
117bfd817adSflorian 	fprintf(ttyout, "We only support %s format, sorry.\n", formname);
118bfd817adSflorian 	code = -1;
119bfd817adSflorian }
120bfd817adSflorian 
121bfd817adSflorian /*
122bfd817adSflorian  * Set file transfer structure.
123bfd817adSflorian  */
124bfd817adSflorian void
setstruct(int argc,char * argv[])125bfd817adSflorian setstruct(int argc, char *argv[])
126bfd817adSflorian {
127bfd817adSflorian 
128bfd817adSflorian 	fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
129bfd817adSflorian 	code = -1;
130bfd817adSflorian }
131bfd817adSflorian 
132bfd817adSflorian void
reput(int argc,char * argv[])133bfd817adSflorian reput(int argc, char *argv[])
134bfd817adSflorian {
135bfd817adSflorian 
136bfd817adSflorian 	(void)putit(argc, argv, 1);
137bfd817adSflorian }
138bfd817adSflorian 
139bfd817adSflorian void
put(int argc,char * argv[])140bfd817adSflorian put(int argc, char *argv[])
141bfd817adSflorian {
142bfd817adSflorian 
143bfd817adSflorian 	(void)putit(argc, argv, 0);
144bfd817adSflorian }
145bfd817adSflorian 
146bfd817adSflorian /*
147bfd817adSflorian  * Send a single file.
148bfd817adSflorian  */
149bfd817adSflorian void
putit(int argc,char * argv[],int restartit)150bfd817adSflorian putit(int argc, char *argv[], int restartit)
151bfd817adSflorian {
152bfd817adSflorian 	char *cmd;
153bfd817adSflorian 	int loc = 0;
154bfd817adSflorian 	char *oldargv1, *oldargv2;
155bfd817adSflorian 
156bfd817adSflorian 	if (argc == 2) {
157bfd817adSflorian 		argc++;
158bfd817adSflorian 		argv[2] = argv[1];
159bfd817adSflorian 		loc++;
160bfd817adSflorian 	}
161bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "local-file"))
162bfd817adSflorian 		goto usage;
163bfd817adSflorian 	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
164bfd817adSflorian usage:
165bfd817adSflorian 		fprintf(ttyout, "usage: %s local-file [remote-file]\n",
166bfd817adSflorian 		    argv[0]);
167bfd817adSflorian 		code = -1;
168bfd817adSflorian 		return;
169bfd817adSflorian 	}
170bfd817adSflorian 	oldargv1 = argv[1];
171bfd817adSflorian 	oldargv2 = argv[2];
172bfd817adSflorian 	if (!globulize(&argv[1])) {
173bfd817adSflorian 		code = -1;
174bfd817adSflorian 		return;
175bfd817adSflorian 	}
176bfd817adSflorian 	/*
177bfd817adSflorian 	 * If "globulize" modifies argv[1], and argv[2] is a copy of
178bfd817adSflorian 	 * the old argv[1], make it a copy of the new argv[1].
179bfd817adSflorian 	 */
180bfd817adSflorian 	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
181bfd817adSflorian 		argv[2] = argv[1];
182bfd817adSflorian 	}
183bfd817adSflorian 	if (restartit == 1) {
184bfd817adSflorian 		if (curtype != type)
185bfd817adSflorian 			changetype(type, 0);
186bfd817adSflorian 		restart_point = remotesize(argv[2], 1);
187bfd817adSflorian 		if (restart_point < 0) {
188bfd817adSflorian 			restart_point = 0;
189bfd817adSflorian 			code = -1;
190bfd817adSflorian 			return;
191bfd817adSflorian 		}
192bfd817adSflorian 	}
193bfd817adSflorian 	if (strcmp(argv[0], "append") == 0) {
194bfd817adSflorian 		restartit = 1;
195bfd817adSflorian 	}
196bfd817adSflorian 	cmd = restartit ? "APPE" : ((sunique) ? "STOU" : "STOR");
197bfd817adSflorian 	if (loc && ntflag) {
198bfd817adSflorian 		argv[2] = dotrans(argv[2]);
199bfd817adSflorian 	}
200bfd817adSflorian 	if (loc && mapflag) {
201bfd817adSflorian 		argv[2] = domap(argv[2]);
202bfd817adSflorian 	}
203bfd817adSflorian 	sendrequest(cmd, argv[1], argv[2],
204bfd817adSflorian 	    argv[1] != oldargv1 || argv[2] != oldargv2);
205bfd817adSflorian 	restart_point = 0;
206bfd817adSflorian 	if (oldargv1 != argv[1])	/* free up after globulize() */
207bfd817adSflorian 		free(argv[1]);
208bfd817adSflorian }
209bfd817adSflorian 
210bfd817adSflorian /*
211bfd817adSflorian  * Send multiple files.
212bfd817adSflorian  */
213bfd817adSflorian void
mput(int argc,char * argv[])214bfd817adSflorian mput(int argc, char *argv[])
215bfd817adSflorian {
216bfd817adSflorian 	extern int optind, optreset;
217bfd817adSflorian 	int ch, i, restartit = 0;
218bfd817adSflorian 	sig_t oldintr;
219bfd817adSflorian 	char *cmd, *tp, *xargv[] = { argv[0], NULL, NULL };
220bfd817adSflorian 	const char *errstr;
221bfd817adSflorian 	static int depth = 0, max_depth = 0;
222bfd817adSflorian 
223bfd817adSflorian 	optind = optreset = 1;
224bfd817adSflorian 
225bfd817adSflorian 	if (depth)
226bfd817adSflorian 		depth++;
227bfd817adSflorian 
228bfd817adSflorian 	while ((ch = getopt(argc, argv, "cd:r")) != -1) {
229bfd817adSflorian 		switch(ch) {
230bfd817adSflorian 		case 'c':
231bfd817adSflorian 			restartit = 1;
232bfd817adSflorian 			break;
233bfd817adSflorian 		case 'd':
234bfd817adSflorian 			max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
235bfd817adSflorian 			if (errstr != NULL) {
236bfd817adSflorian 				fprintf(ttyout, "bad depth value, %s: %s\n",
237bfd817adSflorian 				    errstr, optarg);
238bfd817adSflorian 				code = -1;
239bfd817adSflorian 				return;
240bfd817adSflorian 			}
241bfd817adSflorian 			break;
242bfd817adSflorian 		case 'r':
243bfd817adSflorian 			depth = 1;
244bfd817adSflorian 			break;
245bfd817adSflorian 		default:
246bfd817adSflorian 			goto usage;
247bfd817adSflorian 		}
248bfd817adSflorian 	}
249bfd817adSflorian 
250bfd817adSflorian 	if (argc - optind < 1 && !another(&argc, &argv, "local-files")) {
251bfd817adSflorian usage:
252bfd817adSflorian 		fprintf(ttyout, "usage: %s [-cr] [-d depth] local-files\n",
253bfd817adSflorian 		    argv[0]);
254bfd817adSflorian 		code = -1;
255bfd817adSflorian 		return;
256bfd817adSflorian 	}
257bfd817adSflorian 
258bfd817adSflorian 	argv[optind - 1] = argv[0];
259bfd817adSflorian 	argc -= optind - 1;
260bfd817adSflorian 	argv += optind - 1;
261bfd817adSflorian 
262bfd817adSflorian 	mname = argv[0];
263bfd817adSflorian 	mflag = 1;
264bfd817adSflorian 
265bfd817adSflorian 	oldintr = signal(SIGINT, mabort);
266bfd817adSflorian 	(void)setjmp(jabort);
267bfd817adSflorian 	if (proxy) {
268bfd817adSflorian 		char *cp, *tp2, tmpbuf[PATH_MAX];
269bfd817adSflorian 
270bfd817adSflorian 		while ((cp = remglob(argv, 0, NULL)) != NULL) {
271bfd817adSflorian 			if (*cp == '\0') {
272bfd817adSflorian 				mflag = 0;
273bfd817adSflorian 				continue;
274bfd817adSflorian 			}
275bfd817adSflorian 			if (mflag && confirm(argv[0], cp)) {
276bfd817adSflorian 				tp = cp;
277bfd817adSflorian 				if (mcase) {
278bfd817adSflorian 					while (*tp && !islower((unsigned char)*tp)) {
279bfd817adSflorian 						tp++;
280bfd817adSflorian 					}
281bfd817adSflorian 					if (!*tp) {
282bfd817adSflorian 						tp = cp;
283bfd817adSflorian 						tp2 = tmpbuf;
284bfd817adSflorian 						while ((*tp2 = *tp) != '\0') {
285bfd817adSflorian 							if (isupper((unsigned char)*tp2)) {
286bfd817adSflorian 								*tp2 =
287bfd817adSflorian 								    tolower((unsigned char)*tp2);
288bfd817adSflorian 							}
289bfd817adSflorian 							tp++;
290bfd817adSflorian 							tp2++;
291bfd817adSflorian 						}
292bfd817adSflorian 					}
293bfd817adSflorian 					tp = tmpbuf;
294bfd817adSflorian 				}
295bfd817adSflorian 				if (ntflag) {
296bfd817adSflorian 					tp = dotrans(tp);
297bfd817adSflorian 				}
298bfd817adSflorian 				if (mapflag) {
299bfd817adSflorian 					tp = domap(tp);
300bfd817adSflorian 				}
301bfd817adSflorian 				if (restartit == 1) {
302bfd817adSflorian 					off_t ret;
303bfd817adSflorian 
304bfd817adSflorian 					if (curtype != type)
305bfd817adSflorian 						changetype(type, 0);
306bfd817adSflorian 					ret = remotesize(tp, 0);
307bfd817adSflorian 					restart_point = (ret < 0) ? 0 : ret;
308bfd817adSflorian 				}
309bfd817adSflorian 				cmd = restartit ? "APPE" : ((sunique) ?
310bfd817adSflorian 				    "STOU" : "STOR");
311bfd817adSflorian 				sendrequest(cmd, cp, tp,
312bfd817adSflorian 				    cp != tp || !interactive);
313bfd817adSflorian 				restart_point = 0;
314bfd817adSflorian 				if (!mflag && fromatty) {
315bfd817adSflorian 					if (confirm(argv[0], NULL))
316bfd817adSflorian 						mflag = 1;
317bfd817adSflorian 				}
318bfd817adSflorian 			}
319bfd817adSflorian 		}
320bfd817adSflorian 		(void)signal(SIGINT, oldintr);
321bfd817adSflorian 		mflag = 0;
322bfd817adSflorian 		return;
323bfd817adSflorian 	}
324bfd817adSflorian 
325bfd817adSflorian 	for (i = 1; i < argc; i++) {
326bfd817adSflorian 		char **cpp;
327bfd817adSflorian 		glob_t gl;
328bfd817adSflorian 		int flags;
329bfd817adSflorian 
330bfd817adSflorian 		/* Copy files without word expansion */
331bfd817adSflorian 		if (!doglob) {
332bfd817adSflorian 			if (mflag && confirm(argv[0], argv[i])) {
333bfd817adSflorian 				tp = (ntflag) ? dotrans(argv[i]) : argv[i];
334bfd817adSflorian 				tp = (mapflag) ? domap(tp) : tp;
335bfd817adSflorian 				if (restartit == 1) {
336bfd817adSflorian 					off_t ret;
337bfd817adSflorian 
338bfd817adSflorian 					if (curtype != type)
339bfd817adSflorian 						changetype(type, 0);
340bfd817adSflorian 					ret = remotesize(tp, 0);
341bfd817adSflorian 					restart_point = (ret < 0) ? 0 : ret;
342bfd817adSflorian 				}
343bfd817adSflorian 				cmd = restartit ? "APPE" : ((sunique) ?
344bfd817adSflorian 				    "STOU" : "STOR");
345bfd817adSflorian 				sendrequest(cmd, argv[i], tp,
346bfd817adSflorian 				    tp != argv[i] || !interactive);
347bfd817adSflorian 				restart_point = 0;
348bfd817adSflorian 				if (!mflag && fromatty) {
349bfd817adSflorian 					if (confirm(argv[0], NULL))
350bfd817adSflorian 						mflag = 1;
351bfd817adSflorian 				}
352bfd817adSflorian 			}
353bfd817adSflorian 			continue;
354bfd817adSflorian 		}
355bfd817adSflorian 
356bfd817adSflorian 		/* expanding file names */
357bfd817adSflorian 		memset(&gl, 0, sizeof(gl));
358bfd817adSflorian 		flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
359bfd817adSflorian 		if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
360bfd817adSflorian 			warnx("%s: not found", argv[i]);
361bfd817adSflorian 			globfree(&gl);
362bfd817adSflorian 			continue;
363bfd817adSflorian 		}
364bfd817adSflorian 
365bfd817adSflorian 		/* traverse all expanded file names */
366bfd817adSflorian 		for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
367bfd817adSflorian 			struct stat filestat;
368bfd817adSflorian 
369bfd817adSflorian 			if (!mflag)
370bfd817adSflorian 				continue;
371bfd817adSflorian 			if (stat(*cpp, &filestat) != 0) {
372bfd817adSflorian 				warn("local: %s", *cpp);
373bfd817adSflorian 				continue;
374bfd817adSflorian 			}
375bfd817adSflorian 			if (S_ISDIR(filestat.st_mode) && depth == max_depth)
376bfd817adSflorian 				continue;
377bfd817adSflorian 			if (!confirm(argv[0], *cpp))
378bfd817adSflorian 				continue;
379bfd817adSflorian 
380bfd817adSflorian 			/*
381bfd817adSflorian 			 * If file is a directory then create a new one
382bfd817adSflorian 			 * at the remote machine.
383bfd817adSflorian 			 */
384bfd817adSflorian 			if (S_ISDIR(filestat.st_mode)) {
385bfd817adSflorian 				xargv[1] = *cpp;
386bfd817adSflorian 				makedir(2, xargv);
387bfd817adSflorian 				cd(2, xargv);
388bfd817adSflorian 				if (dirchange != 1) {
389bfd817adSflorian 					warnx("remote: %s", *cpp);
390bfd817adSflorian 					continue;
391bfd817adSflorian 				}
392bfd817adSflorian 
393bfd817adSflorian 				if (chdir(*cpp) != 0) {
394bfd817adSflorian 					warn("local: %s", *cpp);
395bfd817adSflorian 					goto out;
396bfd817adSflorian 				}
397bfd817adSflorian 
398bfd817adSflorian 				/* Copy the whole directory recursively. */
399bfd817adSflorian 				xargv[1] = "*";
400bfd817adSflorian 				mput(2, xargv);
401bfd817adSflorian 
402bfd817adSflorian 				if (chdir("..") != 0) {
403bfd817adSflorian 					mflag = 0;
404bfd817adSflorian 					warn("local: %s", *cpp);
405bfd817adSflorian 					goto out;
406bfd817adSflorian 				}
407bfd817adSflorian 
408bfd817adSflorian  out:
409bfd817adSflorian 				xargv[1] = "..";
410bfd817adSflorian 				cd(2, xargv);
411bfd817adSflorian 				if (dirchange != 1) {
412bfd817adSflorian 					warnx("remote: %s", *cpp);
413bfd817adSflorian 					mflag = 0;
414bfd817adSflorian 				}
415bfd817adSflorian 				continue;
416bfd817adSflorian 			}
417bfd817adSflorian 
418bfd817adSflorian 			tp = (ntflag) ? dotrans(*cpp) : *cpp;
419bfd817adSflorian 			tp = (mapflag) ? domap(tp) : tp;
420bfd817adSflorian 			if (restartit == 1) {
421bfd817adSflorian 				off_t ret;
422bfd817adSflorian 
423bfd817adSflorian 				if (curtype != type)
424bfd817adSflorian 					changetype(type, 0);
425bfd817adSflorian 				ret = remotesize(tp, 0);
426bfd817adSflorian 				restart_point = (ret < 0) ? 0 : ret;
427bfd817adSflorian 			}
428bfd817adSflorian 			cmd = restartit ? "APPE" : ((sunique) ?
429bfd817adSflorian 			    "STOU" : "STOR");
430bfd817adSflorian 			sendrequest(cmd, *cpp, tp,
431bfd817adSflorian 			    *cpp != tp || !interactive);
432bfd817adSflorian 			restart_point = 0;
433bfd817adSflorian 			if (!mflag && fromatty) {
434bfd817adSflorian 				if (confirm(argv[0], NULL))
435bfd817adSflorian 					mflag = 1;
436bfd817adSflorian 			}
437bfd817adSflorian 		}
438bfd817adSflorian 		globfree(&gl);
439bfd817adSflorian 	}
440bfd817adSflorian 
441bfd817adSflorian 	(void)signal(SIGINT, oldintr);
442bfd817adSflorian 
443bfd817adSflorian 	if (depth)
444bfd817adSflorian 		depth--;
445bfd817adSflorian 	if (depth == 0 || mflag == 0)
446bfd817adSflorian 		depth = max_depth = mflag = 0;
447bfd817adSflorian }
448bfd817adSflorian 
449bfd817adSflorian void
reget(int argc,char * argv[])450bfd817adSflorian reget(int argc, char *argv[])
451bfd817adSflorian {
452bfd817adSflorian 
453bfd817adSflorian 	(void)getit(argc, argv, 1, "a+w");
454bfd817adSflorian }
455bfd817adSflorian 
456bfd817adSflorian char *
onoff(int bool)457bfd817adSflorian onoff(int bool)
458bfd817adSflorian {
459bfd817adSflorian 
460bfd817adSflorian 	return (bool ? "on" : "off");
461bfd817adSflorian }
462bfd817adSflorian 
463bfd817adSflorian /*
464bfd817adSflorian  * Show status.
465bfd817adSflorian  */
466bfd817adSflorian void
status(int argc,char * argv[])467bfd817adSflorian status(int argc, char *argv[])
468bfd817adSflorian {
469bfd817adSflorian 	int i;
470bfd817adSflorian 
471bfd817adSflorian 	if (connected)
472bfd817adSflorian 		fprintf(ttyout, "Connected %sto %s.\n",
473bfd817adSflorian 		    connected == -1 ? "and logged in" : "", hostname);
474bfd817adSflorian 	else
475bfd817adSflorian 		fputs("Not connected.\n", ttyout);
476bfd817adSflorian 	if (!proxy) {
477bfd817adSflorian 		pswitch(1);
478bfd817adSflorian 		if (connected) {
479bfd817adSflorian 			fprintf(ttyout, "Connected for proxy commands to %s.\n",
480bfd817adSflorian 			    hostname);
481bfd817adSflorian 		}
482bfd817adSflorian 		else {
483bfd817adSflorian 			fputs("No proxy connection.\n", ttyout);
484bfd817adSflorian 		}
485bfd817adSflorian 		pswitch(0);
486bfd817adSflorian 	}
487bfd817adSflorian 	fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
488bfd817adSflorian 	    *gateserver ? gateserver : "(none)", gateport);
489bfd817adSflorian 	fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode));
490bfd817adSflorian 	fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
491bfd817adSflorian 		modename, typename, formname, structname);
492bfd817adSflorian 	fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
493bfd817adSflorian 		onoff(verbose), onoff(bell), onoff(interactive),
494bfd817adSflorian 		onoff(doglob));
495bfd817adSflorian 	fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique),
496bfd817adSflorian 		onoff(runique));
497bfd817adSflorian 	fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
498bfd817adSflorian 	fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
499bfd817adSflorian 	if (ntflag) {
500bfd817adSflorian 		fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
501bfd817adSflorian 	}
502bfd817adSflorian 	else {
503bfd817adSflorian 		fputs("Ntrans: off.\n", ttyout);
504bfd817adSflorian 	}
505bfd817adSflorian 	if (mapflag) {
506bfd817adSflorian 		fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
507bfd817adSflorian 	}
508bfd817adSflorian 	else {
509bfd817adSflorian 		fputs("Nmap: off.\n", ttyout);
510bfd817adSflorian 	}
511bfd817adSflorian 	fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
512bfd817adSflorian 	    onoff(hash), mark, onoff(progress));
513bfd817adSflorian 	fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport));
514bfd817adSflorian 	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
515bfd817adSflorian 	    epsv4bad ? " (disabled for this connection)" : "");
516bfd817adSflorian 	fprintf(ttyout, "Command line editing: %s.\n", onoff(editing));
517bfd817adSflorian 	if (macnum > 0) {
518bfd817adSflorian 		fputs("Macros:\n", ttyout);
519bfd817adSflorian 		for (i=0; i<macnum; i++) {
520bfd817adSflorian 			fprintf(ttyout, "\t%s\n", macros[i].mac_name);
521bfd817adSflorian 		}
522bfd817adSflorian 	}
523bfd817adSflorian 	code = 0;
524bfd817adSflorian }
525bfd817adSflorian 
526bfd817adSflorian /*
527bfd817adSflorian  * Toggle a variable
528bfd817adSflorian  */
529bfd817adSflorian int
togglevar(int argc,char * argv[],int * var,const char * mesg)530bfd817adSflorian togglevar(int argc, char *argv[], int *var, const char *mesg)
531bfd817adSflorian {
532bfd817adSflorian 	if (argc < 2) {
533bfd817adSflorian 		*var = !*var;
534bfd817adSflorian 	} else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
535bfd817adSflorian 		*var = 1;
536bfd817adSflorian 	} else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
537bfd817adSflorian 		*var = 0;
538bfd817adSflorian 	} else {
539bfd817adSflorian 		fprintf(ttyout, "usage: %s [on | off]\n", argv[0]);
540bfd817adSflorian 		return (-1);
541bfd817adSflorian 	}
542bfd817adSflorian 	if (mesg)
543bfd817adSflorian 		fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
544bfd817adSflorian 	return (*var);
545bfd817adSflorian }
546bfd817adSflorian 
547bfd817adSflorian /*
548bfd817adSflorian  * Set beep on cmd completed mode.
549bfd817adSflorian  */
550bfd817adSflorian void
setbell(int argc,char * argv[])551bfd817adSflorian setbell(int argc, char *argv[])
552bfd817adSflorian {
553bfd817adSflorian 
554bfd817adSflorian 	code = togglevar(argc, argv, &bell, "Bell mode");
555bfd817adSflorian }
556bfd817adSflorian 
557bfd817adSflorian /*
558bfd817adSflorian  * Set command line editing
559bfd817adSflorian  */
560bfd817adSflorian void
setedit(int argc,char * argv[])561bfd817adSflorian setedit(int argc, char *argv[])
562bfd817adSflorian {
563bfd817adSflorian 
564bfd817adSflorian 	code = togglevar(argc, argv, &editing, "Editing mode");
565bfd817adSflorian 	controlediting();
566bfd817adSflorian }
567bfd817adSflorian 
568bfd817adSflorian /*
569bfd817adSflorian  * Toggle use of IPv4 EPSV/EPRT
570bfd817adSflorian  */
571bfd817adSflorian void
setepsv4(int argc,char * argv[])572bfd817adSflorian setepsv4(int argc, char *argv[])
573bfd817adSflorian {
574bfd817adSflorian 
575bfd817adSflorian 	code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4");
576bfd817adSflorian 	epsv4bad = 0;
577bfd817adSflorian }
578bfd817adSflorian 
579bfd817adSflorian /*
580bfd817adSflorian  * Turn on packet tracing.
581bfd817adSflorian  */
582bfd817adSflorian void
settrace(int argc,char * argv[])583bfd817adSflorian settrace(int argc, char *argv[])
584bfd817adSflorian {
585bfd817adSflorian 
586bfd817adSflorian 	code = togglevar(argc, argv, &trace, "Packet tracing");
587bfd817adSflorian }
588bfd817adSflorian 
589bfd817adSflorian /*
590bfd817adSflorian  * Toggle hash mark printing during transfers, or set hash mark bytecount.
591bfd817adSflorian  */
592bfd817adSflorian void
sethash(int argc,char * argv[])593bfd817adSflorian sethash(int argc, char *argv[])
594bfd817adSflorian {
595bfd817adSflorian 	if (argc == 1)
596bfd817adSflorian 		hash = !hash;
597bfd817adSflorian 	else if (argc != 2) {
598bfd817adSflorian 		fprintf(ttyout, "usage: %s [on | off | size]\n", argv[0]);
599bfd817adSflorian 		code = -1;
600bfd817adSflorian 		return;
601bfd817adSflorian 	} else if (strcasecmp(argv[1], "on") == 0)
602bfd817adSflorian 		hash = 1;
603bfd817adSflorian 	else if (strcasecmp(argv[1], "off") == 0)
604bfd817adSflorian 		hash = 0;
605bfd817adSflorian 	else {
606bfd817adSflorian 		int nmark;
607bfd817adSflorian 		const char *errstr;
608bfd817adSflorian 
609bfd817adSflorian 		nmark = strtonum(argv[1], 1, INT_MAX, &errstr);
610bfd817adSflorian 		if (errstr) {
611bfd817adSflorian 			fprintf(ttyout, "bytecount value is %s: %s\n",
612bfd817adSflorian 			    errstr, argv[1]);
613bfd817adSflorian 			code = -1;
614bfd817adSflorian 			return;
615bfd817adSflorian 		}
616bfd817adSflorian 		mark = nmark;
617bfd817adSflorian 		hash = 1;
618bfd817adSflorian 	}
619bfd817adSflorian 	fprintf(ttyout, "Hash mark printing %s", onoff(hash));
620bfd817adSflorian 	if (hash)
621bfd817adSflorian 		fprintf(ttyout, " (%d bytes/hash mark)", mark);
622bfd817adSflorian 	fputs(".\n", ttyout);
623bfd817adSflorian 	code = hash;
624bfd817adSflorian }
625bfd817adSflorian 
626bfd817adSflorian /*
627bfd817adSflorian  * Turn on printing of server echo's.
628bfd817adSflorian  */
629bfd817adSflorian void
setverbose(int argc,char * argv[])630bfd817adSflorian setverbose(int argc, char *argv[])
631bfd817adSflorian {
632bfd817adSflorian 
633bfd817adSflorian 	code = togglevar(argc, argv, &verbose, "Verbose mode");
634bfd817adSflorian }
635bfd817adSflorian 
636bfd817adSflorian /*
637bfd817adSflorian  * Toggle PORT/LPRT cmd use before each data connection.
638bfd817adSflorian  */
639bfd817adSflorian void
setport(int argc,char * argv[])640bfd817adSflorian setport(int argc, char *argv[])
641bfd817adSflorian {
642bfd817adSflorian 
643bfd817adSflorian 	code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
644bfd817adSflorian }
645bfd817adSflorian 
646bfd817adSflorian /*
647bfd817adSflorian  * Toggle transfer progress bar.
648bfd817adSflorian  */
649bfd817adSflorian void
setprogress(int argc,char * argv[])650bfd817adSflorian setprogress(int argc, char *argv[])
651bfd817adSflorian {
652bfd817adSflorian 
653bfd817adSflorian 	code = togglevar(argc, argv, &progress, "Progress bar");
654bfd817adSflorian }
655bfd817adSflorian 
656bfd817adSflorian /*
657bfd817adSflorian  * Turn on interactive prompting during mget, mput, and mdelete.
658bfd817adSflorian  */
659bfd817adSflorian void
setprompt(int argc,char * argv[])660bfd817adSflorian setprompt(int argc, char *argv[])
661bfd817adSflorian {
662bfd817adSflorian 
663bfd817adSflorian 	code = togglevar(argc, argv, &interactive, "Interactive mode");
664bfd817adSflorian }
665bfd817adSflorian 
666bfd817adSflorian /*
667bfd817adSflorian  * Toggle gate-ftp mode, or set gate-ftp server
668bfd817adSflorian  */
669bfd817adSflorian void
setgate(int argc,char * argv[])670bfd817adSflorian setgate(int argc, char *argv[])
671bfd817adSflorian {
672bfd817adSflorian 	static char gsbuf[HOST_NAME_MAX+1];
673bfd817adSflorian 
674bfd817adSflorian 	if (argc > 3) {
675bfd817adSflorian 		fprintf(ttyout, "usage: %s [on | off | host [port]]\n",
676bfd817adSflorian 		    argv[0]);
677bfd817adSflorian 		code = -1;
678bfd817adSflorian 		return;
679bfd817adSflorian 	} else if (argc < 2) {
680bfd817adSflorian 		gatemode = !gatemode;
681bfd817adSflorian 	} else {
682bfd817adSflorian 		if (argc == 2 && strcasecmp(argv[1], "on") == 0)
683bfd817adSflorian 			gatemode = 1;
684bfd817adSflorian 		else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
685bfd817adSflorian 			gatemode = 0;
686bfd817adSflorian 		else {
687bfd817adSflorian 			if (argc == 3) {
688bfd817adSflorian 				gateport = strdup(argv[2]);
689bfd817adSflorian 				if (gateport == NULL)
690bfd817adSflorian 					err(1, NULL);
691bfd817adSflorian 			}
692bfd817adSflorian 			strlcpy(gsbuf, argv[1], sizeof(gsbuf));
693bfd817adSflorian 			gateserver = gsbuf;
694bfd817adSflorian 			gatemode = 1;
695bfd817adSflorian 		}
696bfd817adSflorian 	}
697bfd817adSflorian 	if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
698bfd817adSflorian 		fprintf(ttyout,
699bfd817adSflorian 		    "Disabling gate-ftp mode - no gate-ftp server defined.\n");
700bfd817adSflorian 		gatemode = 0;
701bfd817adSflorian 	} else {
702bfd817adSflorian 		fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
703bfd817adSflorian 		    onoff(gatemode),
704bfd817adSflorian 		    *gateserver ? gateserver : "(none)", gateport);
705bfd817adSflorian 	}
706bfd817adSflorian 	code = gatemode;
707bfd817adSflorian }
708bfd817adSflorian 
709bfd817adSflorian /*
710bfd817adSflorian  * Toggle metacharacter interpretation on local file names.
711bfd817adSflorian  */
712bfd817adSflorian void
setglob(int argc,char * argv[])713bfd817adSflorian setglob(int argc, char *argv[])
714bfd817adSflorian {
715bfd817adSflorian 
716bfd817adSflorian 	code = togglevar(argc, argv, &doglob, "Globbing");
717bfd817adSflorian }
718bfd817adSflorian 
719bfd817adSflorian /*
720bfd817adSflorian  * Toggle preserving modification times on retrieved files.
721bfd817adSflorian  */
722bfd817adSflorian void
setpreserve(int argc,char * argv[])723bfd817adSflorian setpreserve(int argc, char *argv[])
724bfd817adSflorian {
725bfd817adSflorian 
726bfd817adSflorian 	code = togglevar(argc, argv, &preserve, "Preserve modification times");
727bfd817adSflorian }
728bfd817adSflorian 
729bfd817adSflorian /*
730bfd817adSflorian  * Set debugging mode on/off and/or set level of debugging.
731bfd817adSflorian  */
732bfd817adSflorian void
setdebug(int argc,char * argv[])733bfd817adSflorian setdebug(int argc, char *argv[])
734bfd817adSflorian {
735bfd817adSflorian 	if (argc > 2) {
736bfd817adSflorian 		fprintf(ttyout, "usage: %s [on | off | debuglevel]\n", argv[0]);
737bfd817adSflorian 		code = -1;
738bfd817adSflorian 		return;
739bfd817adSflorian 	} else if (argc == 2) {
740bfd817adSflorian 		if (strcasecmp(argv[1], "on") == 0)
741bfd817adSflorian 			debug = 1;
742bfd817adSflorian 		else if (strcasecmp(argv[1], "off") == 0)
743bfd817adSflorian 			debug = 0;
744bfd817adSflorian 		else {
745bfd817adSflorian 			const char *errstr;
746bfd817adSflorian 			int val;
747bfd817adSflorian 
748bfd817adSflorian 			val = strtonum(argv[1], 0, INT_MAX, &errstr);
749bfd817adSflorian 			if (errstr) {
750bfd817adSflorian 				fprintf(ttyout, "debugging value is %s: %s\n",
751bfd817adSflorian 				    errstr, argv[1]);
752bfd817adSflorian 				code = -1;
753bfd817adSflorian 				return;
754bfd817adSflorian 			}
755bfd817adSflorian 			debug = val;
756bfd817adSflorian 		}
757bfd817adSflorian 	} else
758bfd817adSflorian 		debug = !debug;
759bfd817adSflorian 	if (debug)
760bfd817adSflorian 		options |= SO_DEBUG;
761bfd817adSflorian 	else
762bfd817adSflorian 		options &= ~SO_DEBUG;
763bfd817adSflorian 	fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
764bfd817adSflorian 	code = debug > 0;
765bfd817adSflorian }
766bfd817adSflorian 
767bfd817adSflorian /*
768bfd817adSflorian  * Set current working directory on local machine.
769bfd817adSflorian  */
770bfd817adSflorian void
lcd(int argc,char * argv[])771bfd817adSflorian lcd(int argc, char *argv[])
772bfd817adSflorian {
773bfd817adSflorian 	char buf[PATH_MAX];
774bfd817adSflorian 	char *oldargv1;
775bfd817adSflorian 
776bfd817adSflorian 	if (argc < 2)
777bfd817adSflorian 		argc++, argv[1] = home;
778bfd817adSflorian 	if (argc != 2) {
779bfd817adSflorian 		fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
780bfd817adSflorian 		code = -1;
781bfd817adSflorian 		return;
782bfd817adSflorian 	}
783bfd817adSflorian 	oldargv1 = argv[1];
784bfd817adSflorian 	if (!globulize(&argv[1])) {
785bfd817adSflorian 		code = -1;
786bfd817adSflorian 		return;
787bfd817adSflorian 	}
7883aaa63ebSderaadt 	if (chdir(argv[1]) == -1) {
789bfd817adSflorian 		warn("local: %s", argv[1]);
790bfd817adSflorian 		code = -1;
791bfd817adSflorian 	} else {
792bfd817adSflorian 		if (getcwd(buf, sizeof(buf)) != NULL)
793bfd817adSflorian 			fprintf(ttyout, "Local directory now %s\n", buf);
794bfd817adSflorian 		else
795bfd817adSflorian 			warn("getcwd: %s", argv[1]);
796bfd817adSflorian 		code = 0;
797bfd817adSflorian 	}
798bfd817adSflorian 	if (oldargv1 != argv[1])	/* free up after globulize() */
799bfd817adSflorian 		free(argv[1]);
800bfd817adSflorian }
801bfd817adSflorian 
802bfd817adSflorian /*
803bfd817adSflorian  * Delete a single file.
804bfd817adSflorian  */
805bfd817adSflorian void
deletecmd(int argc,char * argv[])806bfd817adSflorian deletecmd(int argc, char *argv[])
807bfd817adSflorian {
808bfd817adSflorian 
809bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
810bfd817adSflorian 		fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
811bfd817adSflorian 		code = -1;
812bfd817adSflorian 		return;
813bfd817adSflorian 	}
814bfd817adSflorian 	(void)command("DELE %s", argv[1]);
815bfd817adSflorian }
816bfd817adSflorian 
817bfd817adSflorian /*
818bfd817adSflorian  * Delete multiple files.
819bfd817adSflorian  */
820bfd817adSflorian void
mdelete(int argc,char * argv[])821bfd817adSflorian mdelete(int argc, char *argv[])
822bfd817adSflorian {
823bfd817adSflorian 	sig_t oldintr;
824bfd817adSflorian 	char *cp;
825bfd817adSflorian 
826bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
827bfd817adSflorian 		fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
828bfd817adSflorian 		code = -1;
829bfd817adSflorian 		return;
830bfd817adSflorian 	}
831bfd817adSflorian 	mname = argv[0];
832bfd817adSflorian 	mflag = 1;
833bfd817adSflorian 	oldintr = signal(SIGINT, mabort);
834bfd817adSflorian 	(void)setjmp(jabort);
835bfd817adSflorian 	while ((cp = remglob(argv, 0, NULL)) != NULL) {
836bfd817adSflorian 		if (*cp == '\0') {
837bfd817adSflorian 			mflag = 0;
838bfd817adSflorian 			continue;
839bfd817adSflorian 		}
840bfd817adSflorian 		if (mflag && confirm(argv[0], cp)) {
841bfd817adSflorian 			(void)command("DELE %s", cp);
842bfd817adSflorian 			if (!mflag && fromatty) {
843bfd817adSflorian 				if (confirm(argv[0], NULL))
844bfd817adSflorian 					mflag = 1;
845bfd817adSflorian 			}
846bfd817adSflorian 		}
847bfd817adSflorian 	}
848bfd817adSflorian 	(void)signal(SIGINT, oldintr);
849bfd817adSflorian 	mflag = 0;
850bfd817adSflorian }
851bfd817adSflorian 
852bfd817adSflorian /*
853bfd817adSflorian  * Rename a remote file.
854bfd817adSflorian  */
855bfd817adSflorian void
renamefile(int argc,char * argv[])856bfd817adSflorian renamefile(int argc, char *argv[])
857bfd817adSflorian {
858bfd817adSflorian 
859bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "from-name"))
860bfd817adSflorian 		goto usage;
861bfd817adSflorian 	if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
862bfd817adSflorian usage:
863bfd817adSflorian 		fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
864bfd817adSflorian 		code = -1;
865bfd817adSflorian 		return;
866bfd817adSflorian 	}
867bfd817adSflorian 	if (command("RNFR %s", argv[1]) == CONTINUE)
868bfd817adSflorian 		(void)command("RNTO %s", argv[2]);
869bfd817adSflorian }
870bfd817adSflorian 
871bfd817adSflorian /*
872bfd817adSflorian  * Get a directory listing of remote files.
873bfd817adSflorian  */
874bfd817adSflorian void
ls(int argc,char * argv[])875bfd817adSflorian ls(int argc, char *argv[])
876bfd817adSflorian {
877bfd817adSflorian 	const char *cmd;
878bfd817adSflorian 	char *oldargv2, *globargv2;
879bfd817adSflorian 
880bfd817adSflorian 	if (argc < 2)
881bfd817adSflorian 		argc++, argv[1] = NULL;
882bfd817adSflorian 	if (argc < 3)
883bfd817adSflorian 		argc++, argv[2] = "-";
884bfd817adSflorian 	if (argc > 3) {
885bfd817adSflorian 		fprintf(ttyout, "usage: %s [remote-directory [local-file]]\n",
886bfd817adSflorian 		    argv[0]);
887bfd817adSflorian 		code = -1;
888bfd817adSflorian 		return;
889bfd817adSflorian 	}
890bfd817adSflorian 	cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
891bfd817adSflorian 	oldargv2 = argv[2];
892bfd817adSflorian 	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
893bfd817adSflorian 		code = -1;
894bfd817adSflorian 		return;
895bfd817adSflorian 	}
896bfd817adSflorian 	globargv2 = argv[2];
897bfd817adSflorian 	if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) ||
898bfd817adSflorian 	    !confirm("output to local-file:", argv[2]))) {
899bfd817adSflorian 		code = -1;
900bfd817adSflorian 		goto freels;
901bfd817adSflorian 	}
902bfd817adSflorian 	recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
903bfd817adSflorian 
904bfd817adSflorian 	/* flush results in case commands are coming from a pipe */
905bfd817adSflorian 	fflush(ttyout);
906bfd817adSflorian freels:
907bfd817adSflorian 	if (argv[2] != globargv2)		/* free up after globulize() */
908bfd817adSflorian 		free(argv[2]);
909bfd817adSflorian 	if (globargv2 != oldargv2)
910bfd817adSflorian 		free(globargv2);
911bfd817adSflorian }
912bfd817adSflorian 
913bfd817adSflorian /*
914bfd817adSflorian  * Get a directory listing of multiple remote files.
915bfd817adSflorian  */
916bfd817adSflorian void
mls(int argc,char * argv[])917bfd817adSflorian mls(int argc, char *argv[])
918bfd817adSflorian {
919bfd817adSflorian 	sig_t oldintr;
920bfd817adSflorian 	int i;
921bfd817adSflorian 	char lmode[1], *dest, *odest;
922bfd817adSflorian 
923bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "remote-files"))
924bfd817adSflorian 		goto usage;
925bfd817adSflorian 	if (argc < 3 && !another(&argc, &argv, "local-file")) {
926bfd817adSflorian usage:
927bfd817adSflorian 		fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
928bfd817adSflorian 		code = -1;
929bfd817adSflorian 		return;
930bfd817adSflorian 	}
931bfd817adSflorian 	odest = dest = argv[argc - 1];
932bfd817adSflorian 	argv[argc - 1] = NULL;
933bfd817adSflorian 	if (strcmp(dest, "-") && *dest != '|')
934bfd817adSflorian 		if (!globulize(&dest) ||
935bfd817adSflorian 		    !confirm("output to local-file:", dest)) {
936bfd817adSflorian 			code = -1;
937bfd817adSflorian 			return;
938bfd817adSflorian 	}
939bfd817adSflorian 	mname = argv[0];
940bfd817adSflorian 	mflag = 1;
941bfd817adSflorian 	oldintr = signal(SIGINT, mabort);
942bfd817adSflorian 	(void)setjmp(jabort);
943bfd817adSflorian 	for (i = 1; mflag && i < argc-1; ++i) {
944bfd817adSflorian 		*lmode = (i == 1) ? 'w' : 'a';
945bfd817adSflorian 		recvrequest("LIST", dest, argv[i], lmode, 0, 0);
946bfd817adSflorian 		if (!mflag && fromatty) {
947bfd817adSflorian 			if (confirm(argv[0], NULL))
948bfd817adSflorian 				mflag ++;
949bfd817adSflorian 		}
950bfd817adSflorian 	}
951bfd817adSflorian 	(void)signal(SIGINT, oldintr);
952bfd817adSflorian 	mflag = 0;
953bfd817adSflorian 	if (dest != odest)			/* free up after globulize() */
954bfd817adSflorian 		free(dest);
955bfd817adSflorian }
956bfd817adSflorian 
957bfd817adSflorian /*
958bfd817adSflorian  * Do a shell escape
959bfd817adSflorian  */
960bfd817adSflorian void
shell(int argc,char * argv[])961bfd817adSflorian shell(int argc, char *argv[])
962bfd817adSflorian {
963bfd817adSflorian 	pid_t pid;
964bfd817adSflorian 	sig_t old1, old2;
965bfd817adSflorian 	char shellnam[PATH_MAX], *shellp, *namep;
966bfd817adSflorian 	int wait_status;
967bfd817adSflorian 
968bfd817adSflorian 	old1 = signal (SIGINT, SIG_IGN);
969bfd817adSflorian 	old2 = signal (SIGQUIT, SIG_IGN);
970bfd817adSflorian 	if ((pid = fork()) == 0) {
971bfd817adSflorian 		(void)closefrom(3);
972bfd817adSflorian 		(void)signal(SIGINT, SIG_DFL);
973bfd817adSflorian 		(void)signal(SIGQUIT, SIG_DFL);
974bfd817adSflorian 		shellp = getenv("SHELL");
975bfd817adSflorian 		if (shellp == NULL || *shellp == '\0')
976bfd817adSflorian 			shellp = _PATH_BSHELL;
977bfd817adSflorian 		namep = strrchr(shellp, '/');
978bfd817adSflorian 		if (namep == NULL)
979bfd817adSflorian 			namep = shellp;
980bfd817adSflorian 		shellnam[0] = '-';
981bfd817adSflorian 		(void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1);
982bfd817adSflorian 		if (strcmp(namep, "sh") != 0)
983bfd817adSflorian 			shellnam[0] = '+';
984bfd817adSflorian 		if (debug) {
985bfd817adSflorian 			fputs(shellp, ttyout);
986bfd817adSflorian 			fputc('\n', ttyout);
987bfd817adSflorian 			(void)fflush(ttyout);
988bfd817adSflorian 		}
989bfd817adSflorian 		if (argc > 1) {
990bfd817adSflorian 			execl(shellp, shellnam, "-c", altarg, (char *)NULL);
991bfd817adSflorian 		}
992bfd817adSflorian 		else {
993bfd817adSflorian 			execl(shellp, shellnam, (char *)NULL);
994bfd817adSflorian 		}
995bfd817adSflorian 		warn("%s", shellp);
996bfd817adSflorian 		code = -1;
997bfd817adSflorian 		exit(1);
998bfd817adSflorian 	}
999bfd817adSflorian 	if (pid > 0)
1000bfd817adSflorian 		while (wait(&wait_status) != pid)
1001bfd817adSflorian 			;
1002bfd817adSflorian 	(void)signal(SIGINT, old1);
1003bfd817adSflorian 	(void)signal(SIGQUIT, old2);
1004bfd817adSflorian 	if (pid == -1) {
1005bfd817adSflorian 		warn("Try again later");
1006bfd817adSflorian 		code = -1;
1007bfd817adSflorian 	}
1008bfd817adSflorian 	else {
1009bfd817adSflorian 		code = 0;
1010bfd817adSflorian 	}
1011bfd817adSflorian }
1012bfd817adSflorian 
1013bfd817adSflorian /*
1014bfd817adSflorian  * Send new user information (re-login)
1015bfd817adSflorian  */
1016bfd817adSflorian void
user(int argc,char * argv[])1017bfd817adSflorian user(int argc, char *argv[])
1018bfd817adSflorian {
1019bfd817adSflorian 	char acctname[80];
1020bfd817adSflorian 	int n, aflag = 0;
1021bfd817adSflorian 
1022bfd817adSflorian 	if (argc < 2)
1023bfd817adSflorian 		(void)another(&argc, &argv, "username");
1024bfd817adSflorian 	if (argc < 2 || argc > 4) {
1025bfd817adSflorian 		fprintf(ttyout, "usage: %s username [password [account]]\n",
1026bfd817adSflorian 		    argv[0]);
1027bfd817adSflorian 		code = -1;
1028bfd817adSflorian 		return;
1029bfd817adSflorian 	}
1030bfd817adSflorian 	n = command("USER %s", argv[1]);
1031bfd817adSflorian 	if (n == CONTINUE) {
1032bfd817adSflorian 		if (argc < 3 )
1033bfd817adSflorian 			argv[2] = getpass("Password:"), argc++;
1034bfd817adSflorian 		n = command("PASS %s", argv[2]);
1035bfd817adSflorian 	}
1036bfd817adSflorian 	if (n == CONTINUE) {
1037bfd817adSflorian 		if (argc < 4) {
1038bfd817adSflorian 			(void)fputs("Account: ", ttyout);
1039bfd817adSflorian 			(void)fflush(ttyout);
1040bfd817adSflorian 			if (fgets(acctname, sizeof(acctname), stdin) == NULL) {
1041bfd817adSflorian 				clearerr(stdin);
1042bfd817adSflorian 				goto fail;
1043bfd817adSflorian 			}
1044bfd817adSflorian 
1045bfd817adSflorian 			acctname[strcspn(acctname, "\n")] = '\0';
1046bfd817adSflorian 
1047bfd817adSflorian 			argv[3] = acctname;
1048bfd817adSflorian 			argc++;
1049bfd817adSflorian 		}
1050bfd817adSflorian 		n = command("ACCT %s", argv[3]);
1051bfd817adSflorian 		aflag++;
1052bfd817adSflorian 	}
1053bfd817adSflorian 	if (n != COMPLETE) {
1054bfd817adSflorian  fail:
1055bfd817adSflorian 		fputs("Login failed.\n", ttyout);
1056bfd817adSflorian 		return;
1057bfd817adSflorian 	}
1058bfd817adSflorian 	if (!aflag && argc == 4) {
1059bfd817adSflorian 		(void)command("ACCT %s", argv[3]);
1060bfd817adSflorian 	}
1061bfd817adSflorian 	connected = -1;
1062bfd817adSflorian }
1063bfd817adSflorian 
1064bfd817adSflorian /*
1065bfd817adSflorian  * Print working directory on remote machine.
1066bfd817adSflorian  */
1067bfd817adSflorian void
pwd(int argc,char * argv[])1068bfd817adSflorian pwd(int argc, char *argv[])
1069bfd817adSflorian {
1070bfd817adSflorian 	int oldverbose = verbose;
1071bfd817adSflorian 
1072bfd817adSflorian 	/*
1073bfd817adSflorian 	 * If we aren't verbose, this doesn't do anything!
1074bfd817adSflorian 	 */
1075bfd817adSflorian 	verbose = 1;
1076bfd817adSflorian 	if (command("PWD") == ERROR && code == 500) {
1077bfd817adSflorian 		fputs("PWD command not recognized, trying XPWD.\n", ttyout);
1078bfd817adSflorian 		(void)command("XPWD");
1079bfd817adSflorian 	}
1080bfd817adSflorian 	verbose = oldverbose;
1081bfd817adSflorian }
1082bfd817adSflorian 
1083bfd817adSflorian /*
1084bfd817adSflorian  * Print working directory on local machine.
1085bfd817adSflorian  */
1086bfd817adSflorian void
lpwd(int argc,char * argv[])1087bfd817adSflorian lpwd(int argc, char *argv[])
1088bfd817adSflorian {
1089bfd817adSflorian 	char buf[PATH_MAX];
1090bfd817adSflorian 
1091bfd817adSflorian 	if (getcwd(buf, sizeof(buf)) != NULL)
1092bfd817adSflorian 		fprintf(ttyout, "Local directory %s\n", buf);
1093bfd817adSflorian 	else
1094bfd817adSflorian 		warn("getcwd");
1095bfd817adSflorian 	code = 0;
1096bfd817adSflorian }
1097bfd817adSflorian 
1098bfd817adSflorian /*
1099bfd817adSflorian  * Make a directory.
1100bfd817adSflorian  */
1101bfd817adSflorian void
makedir(int argc,char * argv[])1102bfd817adSflorian makedir(int argc, char *argv[])
1103bfd817adSflorian {
1104bfd817adSflorian 
1105bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1106bfd817adSflorian 	    argc > 2) {
1107bfd817adSflorian 		fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1108bfd817adSflorian 		code = -1;
1109bfd817adSflorian 		return;
1110bfd817adSflorian 	}
1111bfd817adSflorian 	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1112bfd817adSflorian 		if (verbose)
1113bfd817adSflorian 			fputs("MKD command not recognized, trying XMKD.\n", ttyout);
1114bfd817adSflorian 		(void)command("XMKD %s", argv[1]);
1115bfd817adSflorian 	}
1116bfd817adSflorian }
1117bfd817adSflorian 
1118bfd817adSflorian /*
1119bfd817adSflorian  * Remove a directory.
1120bfd817adSflorian  */
1121bfd817adSflorian void
removedir(int argc,char * argv[])1122bfd817adSflorian removedir(int argc, char *argv[])
1123bfd817adSflorian {
1124bfd817adSflorian 
1125bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1126bfd817adSflorian 	    argc > 2) {
1127bfd817adSflorian 		fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1128bfd817adSflorian 		code = -1;
1129bfd817adSflorian 		return;
1130bfd817adSflorian 	}
1131bfd817adSflorian 	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1132bfd817adSflorian 		if (verbose)
1133bfd817adSflorian 			fputs("RMD command not recognized, trying XRMD.\n", ttyout);
1134bfd817adSflorian 		(void)command("XRMD %s", argv[1]);
1135bfd817adSflorian 	}
1136bfd817adSflorian }
1137bfd817adSflorian 
1138bfd817adSflorian /*
1139bfd817adSflorian  * Send a line, verbatim, to the remote machine.
1140bfd817adSflorian  */
1141bfd817adSflorian void
quote(int argc,char * argv[])1142bfd817adSflorian quote(int argc, char *argv[])
1143bfd817adSflorian {
1144bfd817adSflorian 
1145bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1146bfd817adSflorian 		fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1147bfd817adSflorian 		code = -1;
1148bfd817adSflorian 		return;
1149bfd817adSflorian 	}
1150bfd817adSflorian 	quote1("", argc, argv);
1151bfd817adSflorian }
1152bfd817adSflorian 
1153bfd817adSflorian /*
1154bfd817adSflorian  * Send a SITE command to the remote machine.  The line
1155bfd817adSflorian  * is sent verbatim to the remote machine, except that the
1156bfd817adSflorian  * word "SITE" is added at the front.
1157bfd817adSflorian  */
1158bfd817adSflorian void
site(int argc,char * argv[])1159bfd817adSflorian site(int argc, char *argv[])
1160bfd817adSflorian {
1161bfd817adSflorian 
1162bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1163bfd817adSflorian 		fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1164bfd817adSflorian 		code = -1;
1165bfd817adSflorian 		return;
1166bfd817adSflorian 	}
1167bfd817adSflorian 	quote1("SITE", argc, argv);
1168bfd817adSflorian }
1169bfd817adSflorian 
1170bfd817adSflorian /*
1171bfd817adSflorian  * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1172bfd817adSflorian  * Send the result as a one-line command and get response.
1173bfd817adSflorian  */
1174bfd817adSflorian void
quote1(const char * initial,int argc,char * argv[])1175bfd817adSflorian quote1(const char *initial, int argc, char *argv[])
1176bfd817adSflorian {
1177bfd817adSflorian 	int i, len;
1178bfd817adSflorian 	char buf[BUFSIZ];		/* must be >= sizeof(line) */
1179bfd817adSflorian 
1180bfd817adSflorian 	(void)strlcpy(buf, initial, sizeof(buf));
1181bfd817adSflorian 	if (argc > 1) {
1182bfd817adSflorian 		for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) {
1183bfd817adSflorian 			/* Space for next arg */
1184bfd817adSflorian 			if (len > 1)
1185bfd817adSflorian 				buf[len++] = ' ';
1186bfd817adSflorian 
1187bfd817adSflorian 			/* Sanity check */
1188bfd817adSflorian 			if (len >= sizeof(buf) - 1)
1189bfd817adSflorian 				break;
1190bfd817adSflorian 
1191bfd817adSflorian 			/* Copy next argument, NUL terminate always */
1192bfd817adSflorian 			strlcpy(&buf[len], argv[i], sizeof(buf) - len);
1193bfd817adSflorian 
1194bfd817adSflorian 			/* Update string length */
1195bfd817adSflorian 			len = strlen(buf);
1196bfd817adSflorian 		}
1197bfd817adSflorian 	}
1198bfd817adSflorian 
1199bfd817adSflorian 	/* Make double (triple?) sure the sucker is NUL terminated */
1200bfd817adSflorian 	buf[sizeof(buf) - 1] = '\0';
1201bfd817adSflorian 
1202bfd817adSflorian 	if (command("%s", buf) == PRELIM) {
1203bfd817adSflorian 		while (getreply(0) == PRELIM)
1204bfd817adSflorian 			continue;
1205bfd817adSflorian 	}
1206bfd817adSflorian }
1207bfd817adSflorian 
1208bfd817adSflorian void
do_chmod(int argc,char * argv[])1209bfd817adSflorian do_chmod(int argc, char *argv[])
1210bfd817adSflorian {
1211bfd817adSflorian 
1212bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "mode"))
1213bfd817adSflorian 		goto usage;
1214bfd817adSflorian 	if ((argc < 3 && !another(&argc, &argv, "file")) || argc > 3) {
1215bfd817adSflorian usage:
1216bfd817adSflorian 		fprintf(ttyout, "usage: %s mode file\n", argv[0]);
1217bfd817adSflorian 		code = -1;
1218bfd817adSflorian 		return;
1219bfd817adSflorian 	}
1220bfd817adSflorian 	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1221bfd817adSflorian }
1222bfd817adSflorian 
1223bfd817adSflorian void
do_umask(int argc,char * argv[])1224bfd817adSflorian do_umask(int argc, char *argv[])
1225bfd817adSflorian {
1226bfd817adSflorian 	int oldverbose = verbose;
1227bfd817adSflorian 
1228bfd817adSflorian 	verbose = 1;
1229bfd817adSflorian 	(void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1230bfd817adSflorian 	verbose = oldverbose;
1231bfd817adSflorian }
1232bfd817adSflorian 
1233bfd817adSflorian void
idle(int argc,char * argv[])1234bfd817adSflorian idle(int argc, char *argv[])
1235bfd817adSflorian {
1236bfd817adSflorian 	int oldverbose = verbose;
1237bfd817adSflorian 
1238bfd817adSflorian 	verbose = 1;
1239bfd817adSflorian 	(void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1240bfd817adSflorian 	verbose = oldverbose;
1241bfd817adSflorian }
1242bfd817adSflorian 
1243bfd817adSflorian /*
1244bfd817adSflorian  * Ask the other side for help.
1245bfd817adSflorian  */
1246bfd817adSflorian void
rmthelp(int argc,char * argv[])1247bfd817adSflorian rmthelp(int argc, char *argv[])
1248bfd817adSflorian {
1249bfd817adSflorian 	int oldverbose = verbose;
1250bfd817adSflorian 
1251bfd817adSflorian 	verbose = 1;
1252bfd817adSflorian 	(void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1253bfd817adSflorian 	verbose = oldverbose;
1254bfd817adSflorian }
1255bfd817adSflorian 
1256bfd817adSflorian /*
1257bfd817adSflorian  * Terminate session and exit.
1258bfd817adSflorian  */
1259bfd817adSflorian void
quit(int argc,char * argv[])1260bfd817adSflorian quit(int argc, char *argv[])
1261bfd817adSflorian {
1262bfd817adSflorian 
1263bfd817adSflorian 	if (connected)
1264bfd817adSflorian 		disconnect(0, 0);
1265bfd817adSflorian 	pswitch(1);
1266bfd817adSflorian 	if (connected) {
1267bfd817adSflorian 		disconnect(0, 0);
1268bfd817adSflorian 	}
1269bfd817adSflorian 	exit(0);
1270bfd817adSflorian }
1271bfd817adSflorian 
1272bfd817adSflorian void
account(int argc,char * argv[])1273bfd817adSflorian account(int argc, char *argv[])
1274bfd817adSflorian {
1275bfd817adSflorian 	char *ap;
1276bfd817adSflorian 
1277bfd817adSflorian 	if (argc > 2) {
1278bfd817adSflorian 		fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1279bfd817adSflorian 		code = -1;
1280bfd817adSflorian 		return;
1281bfd817adSflorian 	}
1282bfd817adSflorian 	else if (argc == 2)
1283bfd817adSflorian 		ap = argv[1];
1284bfd817adSflorian 	else
1285bfd817adSflorian 		ap = getpass("Account:");
1286bfd817adSflorian 	(void)command("ACCT %s", ap);
1287bfd817adSflorian }
1288bfd817adSflorian 
1289bfd817adSflorian jmp_buf abortprox;
1290bfd817adSflorian 
1291bfd817adSflorian void
proxabort(int signo)1292bfd817adSflorian proxabort(int signo)
1293bfd817adSflorian {
1294bfd817adSflorian 	int save_errno = errno;
1295bfd817adSflorian 
1296bfd817adSflorian 	alarmtimer(0);
1297bfd817adSflorian 	if (!proxy) {
1298bfd817adSflorian 		pswitch(1);
1299bfd817adSflorian 	}
1300bfd817adSflorian 	if (connected) {
1301bfd817adSflorian 		proxflag = 1;
1302bfd817adSflorian 	}
1303bfd817adSflorian 	else {
1304bfd817adSflorian 		proxflag = 0;
1305bfd817adSflorian 	}
1306bfd817adSflorian 	pswitch(0);
1307bfd817adSflorian 	errno = save_errno;
1308bfd817adSflorian 	longjmp(abortprox, 1);
1309bfd817adSflorian }
1310bfd817adSflorian 
1311bfd817adSflorian void
doproxy(int argc,char * argv[])1312bfd817adSflorian doproxy(int argc, char *argv[])
1313bfd817adSflorian {
1314bfd817adSflorian 	struct cmd *c;
1315bfd817adSflorian 	int cmdpos;
1316bfd817adSflorian 	sig_t oldintr;
1317bfd817adSflorian 
1318bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "command")) {
1319bfd817adSflorian 		fprintf(ttyout, "usage: %s command\n", argv[0]);
1320bfd817adSflorian 		code = -1;
1321bfd817adSflorian 		return;
1322bfd817adSflorian 	}
1323bfd817adSflorian 	c = getcmd(argv[1]);
1324bfd817adSflorian 	if (c == (struct cmd *) -1) {
1325bfd817adSflorian 		fputs("?Ambiguous command.\n", ttyout);
1326bfd817adSflorian 		(void)fflush(ttyout);
1327bfd817adSflorian 		code = -1;
1328bfd817adSflorian 		return;
1329bfd817adSflorian 	}
1330bfd817adSflorian 	if (c == 0) {
1331bfd817adSflorian 		fputs("?Invalid command.\n", ttyout);
1332bfd817adSflorian 		(void)fflush(ttyout);
1333bfd817adSflorian 		code = -1;
1334bfd817adSflorian 		return;
1335bfd817adSflorian 	}
1336bfd817adSflorian 	if (!c->c_proxy) {
1337bfd817adSflorian 		fputs("?Invalid proxy command.\n", ttyout);
1338bfd817adSflorian 		(void)fflush(ttyout);
1339bfd817adSflorian 		code = -1;
1340bfd817adSflorian 		return;
1341bfd817adSflorian 	}
1342bfd817adSflorian 	if (setjmp(abortprox)) {
1343bfd817adSflorian 		code = -1;
1344bfd817adSflorian 		return;
1345bfd817adSflorian 	}
1346bfd817adSflorian 	oldintr = signal(SIGINT, proxabort);
1347bfd817adSflorian 	pswitch(1);
1348bfd817adSflorian 	if (c->c_conn && !connected) {
1349bfd817adSflorian 		fputs("Not connected.\n", ttyout);
1350bfd817adSflorian 		(void)fflush(ttyout);
1351bfd817adSflorian 		pswitch(0);
1352bfd817adSflorian 		(void)signal(SIGINT, oldintr);
1353bfd817adSflorian 		code = -1;
1354bfd817adSflorian 		return;
1355bfd817adSflorian 	}
1356bfd817adSflorian 	cmdpos = strcspn(line, " \t");
1357bfd817adSflorian 	if (cmdpos > 0)		/* remove leading "proxy " from input buffer */
1358bfd817adSflorian 		memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1359bfd817adSflorian 	(*c->c_handler)(argc-1, argv+1);
1360bfd817adSflorian 	if (connected) {
1361bfd817adSflorian 		proxflag = 1;
1362bfd817adSflorian 	}
1363bfd817adSflorian 	else {
1364bfd817adSflorian 		proxflag = 0;
1365bfd817adSflorian 	}
1366bfd817adSflorian 	pswitch(0);
1367bfd817adSflorian 	(void)signal(SIGINT, oldintr);
1368bfd817adSflorian }
1369bfd817adSflorian 
1370bfd817adSflorian void
setcase(int argc,char * argv[])1371bfd817adSflorian setcase(int argc, char *argv[])
1372bfd817adSflorian {
1373bfd817adSflorian 
1374bfd817adSflorian 	code = togglevar(argc, argv, &mcase, "Case mapping");
1375bfd817adSflorian }
1376bfd817adSflorian 
1377bfd817adSflorian void
setcr(int argc,char * argv[])1378bfd817adSflorian setcr(int argc, char *argv[])
1379bfd817adSflorian {
1380bfd817adSflorian 
1381bfd817adSflorian 	code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1382bfd817adSflorian }
1383bfd817adSflorian 
1384bfd817adSflorian void
setntrans(int argc,char * argv[])1385bfd817adSflorian setntrans(int argc, char *argv[])
1386bfd817adSflorian {
1387bfd817adSflorian 	if (argc == 1) {
1388bfd817adSflorian 		ntflag = 0;
1389bfd817adSflorian 		fputs("Ntrans off.\n", ttyout);
1390bfd817adSflorian 		code = ntflag;
1391bfd817adSflorian 		return;
1392bfd817adSflorian 	}
1393bfd817adSflorian 	ntflag++;
1394bfd817adSflorian 	code = ntflag;
1395bfd817adSflorian 	(void)strlcpy(ntin, argv[1], sizeof(ntin));
1396bfd817adSflorian 	if (argc == 2) {
1397bfd817adSflorian 		ntout[0] = '\0';
1398bfd817adSflorian 		return;
1399bfd817adSflorian 	}
1400bfd817adSflorian 	(void)strlcpy(ntout, argv[2], sizeof(ntout));
1401bfd817adSflorian }
1402bfd817adSflorian 
1403bfd817adSflorian void
setnmap(int argc,char * argv[])1404bfd817adSflorian setnmap(int argc, char *argv[])
1405bfd817adSflorian {
1406bfd817adSflorian 	char *cp;
1407bfd817adSflorian 
1408bfd817adSflorian 	if (argc == 1) {
1409bfd817adSflorian 		mapflag = 0;
1410bfd817adSflorian 		fputs("Nmap off.\n", ttyout);
1411bfd817adSflorian 		code = mapflag;
1412bfd817adSflorian 		return;
1413bfd817adSflorian 	}
1414bfd817adSflorian 	if ((argc < 3 && !another(&argc, &argv, "outpattern")) || argc > 3) {
1415bfd817adSflorian 		fprintf(ttyout, "usage: %s [inpattern outpattern]\n", argv[0]);
1416bfd817adSflorian 		code = -1;
1417bfd817adSflorian 		return;
1418bfd817adSflorian 	}
1419bfd817adSflorian 	mapflag = 1;
1420bfd817adSflorian 	code = 1;
1421bfd817adSflorian 	cp = strchr(altarg, ' ');
1422bfd817adSflorian 	if (proxy) {
1423bfd817adSflorian 		while(*++cp == ' ')
1424bfd817adSflorian 			continue;
1425bfd817adSflorian 		altarg = cp;
1426bfd817adSflorian 		cp = strchr(altarg, ' ');
1427bfd817adSflorian 	}
1428bfd817adSflorian 	*cp = '\0';
1429bfd817adSflorian 	(void)strncpy(mapin, altarg, PATH_MAX - 1);
1430bfd817adSflorian 	while (*++cp == ' ')
1431bfd817adSflorian 		continue;
1432bfd817adSflorian 	(void)strncpy(mapout, cp, PATH_MAX - 1);
1433bfd817adSflorian }
1434bfd817adSflorian 
1435bfd817adSflorian void
setpassive(int argc,char * argv[])1436bfd817adSflorian setpassive(int argc, char *argv[])
1437bfd817adSflorian {
1438bfd817adSflorian 
1439bfd817adSflorian 	code = togglevar(argc, argv, &passivemode,
1440bfd817adSflorian 	    verbose ? "Passive mode" : NULL);
1441bfd817adSflorian }
1442bfd817adSflorian 
1443bfd817adSflorian void
setsunique(int argc,char * argv[])1444bfd817adSflorian setsunique(int argc, char *argv[])
1445bfd817adSflorian {
1446bfd817adSflorian 
1447bfd817adSflorian 	code = togglevar(argc, argv, &sunique, "Store unique");
1448bfd817adSflorian }
1449bfd817adSflorian 
1450bfd817adSflorian void
setrunique(int argc,char * argv[])1451bfd817adSflorian setrunique(int argc, char *argv[])
1452bfd817adSflorian {
1453bfd817adSflorian 
1454bfd817adSflorian 	code = togglevar(argc, argv, &runique, "Receive unique");
1455bfd817adSflorian }
1456bfd817adSflorian 
1457bfd817adSflorian /* change directory to parent directory */
1458bfd817adSflorian void
cdup(int argc,char * argv[])1459bfd817adSflorian cdup(int argc, char *argv[])
1460bfd817adSflorian {
1461bfd817adSflorian 	int r;
1462bfd817adSflorian 
1463bfd817adSflorian 	r = command("CDUP");
1464bfd817adSflorian 	if (r == ERROR && code == 500) {
1465bfd817adSflorian 		if (verbose)
1466bfd817adSflorian 			fputs("CDUP command not recognized, trying XCUP.\n", ttyout);
1467bfd817adSflorian 		r = command("XCUP");
1468bfd817adSflorian 	}
1469bfd817adSflorian 	if (r == COMPLETE)
1470bfd817adSflorian 		dirchange = 1;
1471bfd817adSflorian }
1472bfd817adSflorian 
1473bfd817adSflorian /*
1474bfd817adSflorian  * Restart transfer at specific point
1475bfd817adSflorian  */
1476bfd817adSflorian void
restart(int argc,char * argv[])1477bfd817adSflorian restart(int argc, char *argv[])
1478bfd817adSflorian {
1479bfd817adSflorian 	off_t nrestart_point;
1480bfd817adSflorian 	char *ep;
1481bfd817adSflorian 
1482bfd817adSflorian 	if (argc != 2)
1483bfd817adSflorian 		fputs("restart: offset not specified.\n", ttyout);
1484bfd817adSflorian 	else {
1485bfd817adSflorian 		nrestart_point = strtoll(argv[1], &ep, 10);
1486bfd817adSflorian 		if (nrestart_point == LLONG_MAX || *ep != '\0')
1487bfd817adSflorian 			fputs("restart: invalid offset.\n", ttyout);
1488bfd817adSflorian 		else {
1489bfd817adSflorian 			fprintf(ttyout, "Restarting at %lld. Execute get, put "
1490bfd817adSflorian 				"or append to initiate transfer\n",
1491bfd817adSflorian 				(long long)nrestart_point);
1492bfd817adSflorian 			restart_point = nrestart_point;
1493bfd817adSflorian 		}
1494bfd817adSflorian 	}
1495bfd817adSflorian }
1496bfd817adSflorian 
1497bfd817adSflorian /*
1498bfd817adSflorian  * Show remote system type
1499bfd817adSflorian  */
1500bfd817adSflorian void
syst(int argc,char * argv[])1501bfd817adSflorian syst(int argc, char *argv[])
1502bfd817adSflorian {
1503bfd817adSflorian 
1504bfd817adSflorian 	(void)command("SYST");
1505bfd817adSflorian }
1506bfd817adSflorian 
1507bfd817adSflorian void
macdef(int argc,char * argv[])1508bfd817adSflorian macdef(int argc, char *argv[])
1509bfd817adSflorian {
1510bfd817adSflorian 	char *tmp;
1511bfd817adSflorian 	int c;
1512bfd817adSflorian 
1513bfd817adSflorian 	if (macnum == 16) {
1514bfd817adSflorian 		fputs("Limit of 16 macros have already been defined.\n", ttyout);
1515bfd817adSflorian 		code = -1;
1516bfd817adSflorian 		return;
1517bfd817adSflorian 	}
1518bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "macro-name")) || argc > 2) {
1519bfd817adSflorian 		fprintf(ttyout, "usage: %s macro-name\n", argv[0]);
1520bfd817adSflorian 		code = -1;
1521bfd817adSflorian 		return;
1522bfd817adSflorian 	}
1523bfd817adSflorian 	if (interactive)
1524bfd817adSflorian 		fputs(
1525bfd817adSflorian "Enter macro line by line, terminating it with a null line.\n", ttyout);
1526bfd817adSflorian 	(void)strlcpy(macros[macnum].mac_name, argv[1],
1527bfd817adSflorian 	    sizeof(macros[macnum].mac_name));
1528bfd817adSflorian 	if (macnum == 0)
1529bfd817adSflorian 		macros[macnum].mac_start = macbuf;
1530bfd817adSflorian 	else
1531bfd817adSflorian 		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1532bfd817adSflorian 	tmp = macros[macnum].mac_start;
1533bfd817adSflorian 	while (tmp != macbuf+4096) {
1534bfd817adSflorian 		if ((c = getchar()) == EOF) {
1535bfd817adSflorian 			fputs("macdef: end of file encountered.\n", ttyout);
1536bfd817adSflorian 			code = -1;
1537bfd817adSflorian 			return;
1538bfd817adSflorian 		}
1539bfd817adSflorian 		if ((*tmp = c) == '\n') {
1540bfd817adSflorian 			if (tmp == macros[macnum].mac_start) {
1541bfd817adSflorian 				macros[macnum++].mac_end = tmp;
1542bfd817adSflorian 				code = 0;
1543bfd817adSflorian 				return;
1544bfd817adSflorian 			}
1545bfd817adSflorian 			if (*(tmp-1) == '\0') {
1546bfd817adSflorian 				macros[macnum++].mac_end = tmp - 1;
1547bfd817adSflorian 				code = 0;
1548bfd817adSflorian 				return;
1549bfd817adSflorian 			}
1550bfd817adSflorian 			*tmp = '\0';
1551bfd817adSflorian 		}
1552bfd817adSflorian 		tmp++;
1553bfd817adSflorian 	}
1554bfd817adSflorian 	while (1) {
1555bfd817adSflorian 		while ((c = getchar()) != '\n' && c != EOF)
1556bfd817adSflorian 			/* LOOP */;
1557bfd817adSflorian 		if (c == EOF || getchar() == '\n') {
1558bfd817adSflorian 			fputs("Macro not defined - 4K buffer exceeded.\n", ttyout);
1559bfd817adSflorian 			code = -1;
1560bfd817adSflorian 			return;
1561bfd817adSflorian 		}
1562bfd817adSflorian 	}
1563bfd817adSflorian }
1564bfd817adSflorian 
1565bfd817adSflorian /*
1566bfd817adSflorian  * Get size of file on remote machine
1567bfd817adSflorian  */
1568bfd817adSflorian void
sizecmd(int argc,char * argv[])1569bfd817adSflorian sizecmd(int argc, char *argv[])
1570bfd817adSflorian {
1571bfd817adSflorian 	off_t size;
1572bfd817adSflorian 
1573bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1574bfd817adSflorian 		fprintf(ttyout, "usage: %s file\n", argv[0]);
1575bfd817adSflorian 		code = -1;
1576bfd817adSflorian 		return;
1577bfd817adSflorian 	}
1578bfd817adSflorian 	size = remotesize(argv[1], 1);
1579bfd817adSflorian 	if (size != -1)
1580bfd817adSflorian 		fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size);
1581bfd817adSflorian 	code = size;
1582bfd817adSflorian }
1583bfd817adSflorian 
1584bfd817adSflorian /*
1585bfd817adSflorian  * Get last modification time of file on remote machine
1586bfd817adSflorian  */
1587bfd817adSflorian void
modtime(int argc,char * argv[])1588bfd817adSflorian modtime(int argc, char *argv[])
1589bfd817adSflorian {
1590bfd817adSflorian 	time_t mtime;
1591bfd817adSflorian 
1592bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1593bfd817adSflorian 		fprintf(ttyout, "usage: %s file\n", argv[0]);
1594bfd817adSflorian 		code = -1;
1595bfd817adSflorian 		return;
1596bfd817adSflorian 	}
1597bfd817adSflorian 	mtime = remotemodtime(argv[1], 1);
1598bfd817adSflorian 	if (mtime != -1)
1599bfd817adSflorian 		fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
1600bfd817adSflorian 	code = mtime;
1601bfd817adSflorian }
1602bfd817adSflorian 
1603bfd817adSflorian /*
1604bfd817adSflorian  * Show status on remote machine
1605bfd817adSflorian  */
1606bfd817adSflorian void
rmtstatus(int argc,char * argv[])1607bfd817adSflorian rmtstatus(int argc, char *argv[])
1608bfd817adSflorian {
1609bfd817adSflorian 
1610bfd817adSflorian 	(void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
1611bfd817adSflorian }
1612bfd817adSflorian 
1613bfd817adSflorian /*
1614bfd817adSflorian  * Get file if modtime is more recent than current file
1615bfd817adSflorian  */
1616bfd817adSflorian void
newer(int argc,char * argv[])1617bfd817adSflorian newer(int argc, char *argv[])
1618bfd817adSflorian {
1619bfd817adSflorian 
1620bfd817adSflorian 	(void)getit(argc, argv, -1, "w");
1621bfd817adSflorian }
1622bfd817adSflorian 
1623bfd817adSflorian /*
1624bfd817adSflorian  * Display one file through $PAGER (defaults to "more").
1625bfd817adSflorian  */
1626bfd817adSflorian void
page(int argc,char * argv[])1627bfd817adSflorian page(int argc, char *argv[])
1628bfd817adSflorian {
1629bfd817adSflorian 	off_t orestart_point;
1630bfd817adSflorian 	int ohash, overbose;
1631bfd817adSflorian 	char *p, *pager, *oldargv1;
1632bfd817adSflorian 
1633bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1634bfd817adSflorian 		fprintf(ttyout, "usage: %s file\n", argv[0]);
1635bfd817adSflorian 		code = -1;
1636bfd817adSflorian 		return;
1637bfd817adSflorian 	}
1638bfd817adSflorian 	oldargv1 = argv[1];
1639bfd817adSflorian 	if (!globulize(&argv[1])) {
1640bfd817adSflorian 		code = -1;
1641bfd817adSflorian 		return;
1642bfd817adSflorian 	}
1643bfd817adSflorian 	p = getenv("PAGER");
1644bfd817adSflorian 	if (p == NULL || (*p == '\0'))
1645bfd817adSflorian 		p = PAGER;
1646bfd817adSflorian 	if (asprintf(&pager, "|%s", p) == -1)
1647bfd817adSflorian 		errx(1, "Can't allocate memory for $PAGER");
1648bfd817adSflorian 
1649bfd817adSflorian 	orestart_point = restart_point;
1650bfd817adSflorian 	ohash = hash;
1651bfd817adSflorian 	overbose = verbose;
1652bfd817adSflorian 	restart_point = hash = verbose = 0;
1653bfd817adSflorian 	recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
1654bfd817adSflorian 	(void)free(pager);
1655bfd817adSflorian 	restart_point = orestart_point;
1656bfd817adSflorian 	hash = ohash;
1657bfd817adSflorian 	verbose = overbose;
1658bfd817adSflorian 	if (oldargv1 != argv[1])	/* free up after globulize() */
1659bfd817adSflorian 		free(argv[1]);
1660bfd817adSflorian }
1661bfd817adSflorian 
1662bfd817adSflorian #endif /* !SMALL */
1663bfd817adSflorian 
1664