xref: /openbsd-src/usr.bin/ftp/small.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: small.c,v 1.13 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 /*
63bfd817adSflorian  * FTP User Program -- Command Routines.
64bfd817adSflorian  */
65bfd817adSflorian #include <sys/types.h>
66bfd817adSflorian #include <sys/socket.h>
67bfd817adSflorian #include <sys/stat.h>
68bfd817adSflorian #include <sys/wait.h>
69bfd817adSflorian #include <arpa/ftp.h>
70bfd817adSflorian 
71bfd817adSflorian #include <ctype.h>
72bfd817adSflorian #include <err.h>
73bfd817adSflorian #include <fnmatch.h>
74bfd817adSflorian #include <glob.h>
75bfd817adSflorian #include <netdb.h>
76bfd817adSflorian #include <stdio.h>
77bfd817adSflorian #include <stdlib.h>
78bfd817adSflorian #include <string.h>
79bfd817adSflorian #include <unistd.h>
80bfd817adSflorian #include <errno.h>
81bfd817adSflorian 
82bfd817adSflorian #include "ftp_var.h"
83bfd817adSflorian #include "pathnames.h"
84bfd817adSflorian #include "small.h"
85bfd817adSflorian 
86bfd817adSflorian jmp_buf	jabort;
87bfd817adSflorian char   *mname;
88bfd817adSflorian char   *home = "/";
89bfd817adSflorian 
90bfd817adSflorian struct	types {
91bfd817adSflorian 	char	*t_name;
92bfd817adSflorian 	char	*t_mode;
93bfd817adSflorian 	int	t_type;
94bfd817adSflorian } types[] = {
95bfd817adSflorian 	{ "ascii",	"A",	TYPE_A },
96bfd817adSflorian 	{ "binary",	"I",	TYPE_I },
97bfd817adSflorian 	{ "image",	"I",	TYPE_I },
98bfd817adSflorian 	{ NULL }
99bfd817adSflorian };
100bfd817adSflorian 
101bfd817adSflorian /*
102bfd817adSflorian  * Set transfer type.
103bfd817adSflorian  */
104bfd817adSflorian void
settype(int argc,char * argv[])105bfd817adSflorian settype(int argc, char *argv[])
106bfd817adSflorian {
107bfd817adSflorian 	struct types *p;
108bfd817adSflorian 	int comret;
109bfd817adSflorian 
110bfd817adSflorian 	if (argc > 2) {
111bfd817adSflorian 		char *sep;
112bfd817adSflorian 
113bfd817adSflorian 		fprintf(ttyout, "usage: %s [", argv[0]);
114bfd817adSflorian 		sep = "";
115bfd817adSflorian 		for (p = types; p->t_name; p++) {
116bfd817adSflorian 			fprintf(ttyout, "%s%s", sep, p->t_name);
117bfd817adSflorian 			sep = " | ";
118bfd817adSflorian 		}
119bfd817adSflorian 		fputs("]\n", ttyout);
120bfd817adSflorian 		code = -1;
121bfd817adSflorian 		return;
122bfd817adSflorian 	}
123bfd817adSflorian 	if (argc < 2) {
124bfd817adSflorian 		fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
125bfd817adSflorian 		code = 0;
126bfd817adSflorian 		return;
127bfd817adSflorian 	}
128bfd817adSflorian 	for (p = types; p->t_name; p++)
129bfd817adSflorian 		if (strcmp(argv[1], p->t_name) == 0)
130bfd817adSflorian 			break;
131bfd817adSflorian 	if (p->t_name == 0) {
132bfd817adSflorian 		fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
133bfd817adSflorian 		code = -1;
134bfd817adSflorian 		return;
135bfd817adSflorian 	}
136bfd817adSflorian 	comret = command("TYPE %s", p->t_mode);
137bfd817adSflorian 	if (comret == COMPLETE) {
138bfd817adSflorian 		(void)strlcpy(typename, p->t_name, sizeof typename);
139bfd817adSflorian 		curtype = type = p->t_type;
140bfd817adSflorian 	}
141bfd817adSflorian }
142bfd817adSflorian 
143bfd817adSflorian /*
144bfd817adSflorian  * Internal form of settype; changes current type in use with server
145bfd817adSflorian  * without changing our notion of the type for data transfers.
146bfd817adSflorian  * Used to change to and from ascii for listings.
147bfd817adSflorian  */
148bfd817adSflorian void
changetype(int newtype,int show)149bfd817adSflorian changetype(int newtype, int show)
150bfd817adSflorian {
151bfd817adSflorian 	struct types *p;
152bfd817adSflorian 	int comret, oldverbose = verbose;
153bfd817adSflorian 
154bfd817adSflorian 	if (newtype == 0)
155bfd817adSflorian 		newtype = TYPE_I;
156bfd817adSflorian 	if (newtype == curtype)
157bfd817adSflorian 		return;
158bfd817adSflorian 	if (
159bfd817adSflorian #ifndef SMALL
160bfd817adSflorian 	    !debug &&
161bfd817adSflorian #endif /* !SMALL */
162bfd817adSflorian 	    show == 0)
163bfd817adSflorian 		verbose = 0;
164bfd817adSflorian 	for (p = types; p->t_name; p++)
165bfd817adSflorian 		if (newtype == p->t_type)
166bfd817adSflorian 			break;
167bfd817adSflorian 	if (p->t_name == 0) {
168bfd817adSflorian 		warnx("internal error: unknown type %d.", newtype);
169bfd817adSflorian 		return;
170bfd817adSflorian 	}
171bfd817adSflorian 	if (newtype == TYPE_L && bytename[0] != '\0')
172bfd817adSflorian 		comret = command("TYPE %s %s", p->t_mode, bytename);
173bfd817adSflorian 	else
174bfd817adSflorian 		comret = command("TYPE %s", p->t_mode);
175bfd817adSflorian 	if (comret == COMPLETE)
176bfd817adSflorian 		curtype = newtype;
177bfd817adSflorian 	verbose = oldverbose;
178bfd817adSflorian }
179bfd817adSflorian 
180bfd817adSflorian char *stype[] = {
181bfd817adSflorian 	"type",
182bfd817adSflorian 	"",
183bfd817adSflorian 	0
184bfd817adSflorian };
185bfd817adSflorian 
186bfd817adSflorian /*
187bfd817adSflorian  * Set binary transfer type.
188bfd817adSflorian  */
189bfd817adSflorian void
setbinary(int argc,char * argv[])190bfd817adSflorian setbinary(int argc, char *argv[])
191bfd817adSflorian {
192bfd817adSflorian 
193bfd817adSflorian 	stype[1] = "binary";
194bfd817adSflorian 	settype(2, stype);
195bfd817adSflorian }
196bfd817adSflorian 
197bfd817adSflorian void
get(int argc,char * argv[])198bfd817adSflorian get(int argc, char *argv[])
199bfd817adSflorian {
200bfd817adSflorian 
201bfd817adSflorian 	(void)getit(argc, argv, 0, restart_point ? "a+w" : "w" );
202bfd817adSflorian }
203bfd817adSflorian 
204bfd817adSflorian /*
205bfd817adSflorian  * Receive one file.
206bfd817adSflorian  */
207bfd817adSflorian int
getit(int argc,char * argv[],int restartit,const char * mode)208bfd817adSflorian getit(int argc, char *argv[], int restartit, const char *mode)
209bfd817adSflorian {
210bfd817adSflorian 	int loc = 0;
211bfd817adSflorian 	int rval = 0;
212bfd817adSflorian 	char *oldargv1, *oldargv2, *globargv2;
213bfd817adSflorian 
214bfd817adSflorian 	if (argc == 2) {
215bfd817adSflorian 		argc++;
216bfd817adSflorian 		argv[2] = argv[1];
217bfd817adSflorian 		loc++;
218bfd817adSflorian 	}
219bfd817adSflorian #ifndef SMALL
220bfd817adSflorian 	if (argc < 2 && !another(&argc, &argv, "remote-file"))
221bfd817adSflorian 		goto usage;
222bfd817adSflorian 	if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
223bfd817adSflorian usage:
224bfd817adSflorian 		fprintf(ttyout, "usage: %s remote-file [local-file]\n",
225bfd817adSflorian 		    argv[0]);
226bfd817adSflorian 		code = -1;
227bfd817adSflorian 		return (0);
228bfd817adSflorian 	}
229bfd817adSflorian #endif /* !SMALL */
230bfd817adSflorian 	oldargv1 = argv[1];
231bfd817adSflorian 	oldargv2 = argv[2];
232bfd817adSflorian 	if (!globulize(&argv[2])) {
233bfd817adSflorian 		code = -1;
234bfd817adSflorian 		return (0);
235bfd817adSflorian 	}
236bfd817adSflorian 	globargv2 = argv[2];
237bfd817adSflorian 	if (loc && mcase) {
238bfd817adSflorian 		char *tp = argv[1], *tp2, tmpbuf[PATH_MAX];
239bfd817adSflorian 
240bfd817adSflorian 		while (*tp && !islower((unsigned char)*tp)) {
241bfd817adSflorian 			tp++;
242bfd817adSflorian 		}
243bfd817adSflorian 		if (!*tp) {
244bfd817adSflorian 			tp = argv[2];
245bfd817adSflorian 			tp2 = tmpbuf;
246bfd817adSflorian 			while ((*tp2 = *tp) != '\0') {
247bfd817adSflorian 				if (isupper((unsigned char)*tp2)) {
248bfd817adSflorian 					*tp2 = tolower((unsigned char)*tp2);
249bfd817adSflorian 				}
250bfd817adSflorian 				tp++;
251bfd817adSflorian 				tp2++;
252bfd817adSflorian 			}
253bfd817adSflorian 			argv[2] = tmpbuf;
254bfd817adSflorian 		}
255bfd817adSflorian 	}
256bfd817adSflorian 	if (loc && ntflag)
257bfd817adSflorian 		argv[2] = dotrans(argv[2]);
258bfd817adSflorian 	if (loc && mapflag)
259bfd817adSflorian 		argv[2] = domap(argv[2]);
260bfd817adSflorian #ifndef SMALL
261bfd817adSflorian 	if (restartit) {
262bfd817adSflorian 		struct stat stbuf;
263bfd817adSflorian 		int ret;
264bfd817adSflorian 
265bfd817adSflorian 		ret = stat(argv[2], &stbuf);
266bfd817adSflorian 		if (restartit == 1) {
267bfd817adSflorian 			restart_point = (ret < 0) ? 0 : stbuf.st_size;
268bfd817adSflorian 		} else {
269bfd817adSflorian 			if (ret == 0) {
270bfd817adSflorian 				time_t mtime;
271bfd817adSflorian 
272bfd817adSflorian 				mtime = remotemodtime(argv[1], 0);
273bfd817adSflorian 				if (mtime == -1)
274bfd817adSflorian 					goto freegetit;
275bfd817adSflorian 				if (stbuf.st_mtime >= mtime) {
276bfd817adSflorian 					rval = 1;
277bfd817adSflorian 					fprintf(ttyout,
278bfd817adSflorian 						"Local file \"%s\" is newer "\
279bfd817adSflorian 						"than remote file \"%s\".\n",
280bfd817adSflorian 						argv[2], argv[1]);
281bfd817adSflorian 					goto freegetit;
282bfd817adSflorian 				}
283bfd817adSflorian 			}
284bfd817adSflorian 		}
285bfd817adSflorian 	}
286bfd817adSflorian #endif /* !SMALL */
287bfd817adSflorian 
288bfd817adSflorian 	recvrequest("RETR", argv[2], argv[1], mode,
289bfd817adSflorian 	    argv[1] != oldargv1 || argv[2] != oldargv2 || !interactive, loc);
290bfd817adSflorian 	restart_point = 0;
291bfd817adSflorian #ifndef SMALL
292bfd817adSflorian freegetit:
293bfd817adSflorian #endif
294bfd817adSflorian 	if (oldargv2 != globargv2)	/* free up after globulize() */
295bfd817adSflorian 		free(globargv2);
296bfd817adSflorian 	return (rval);
297bfd817adSflorian }
298bfd817adSflorian 
299bfd817adSflorian /* XXX - Signal race. */
300bfd817adSflorian void
mabort(int signo)301bfd817adSflorian mabort(int signo)
302bfd817adSflorian {
303bfd817adSflorian 	int save_errno = errno;
304bfd817adSflorian 
305bfd817adSflorian 	alarmtimer(0);
306bfd817adSflorian 	(void) write(fileno(ttyout), "\n\r", 2);
307bfd817adSflorian #ifndef SMALL
308bfd817adSflorian 	if (mflag && fromatty) {
309bfd817adSflorian 		/* XXX signal race, crazy unbelievable stdio misuse */
310bfd817adSflorian 		if (confirm(mname, NULL)) {
311bfd817adSflorian 			errno = save_errno;
312bfd817adSflorian 			longjmp(jabort, 1);
313bfd817adSflorian 		}
314bfd817adSflorian 	}
315bfd817adSflorian #endif /* !SMALL */
316bfd817adSflorian 	mflag = 0;
317bfd817adSflorian 	errno = save_errno;
318bfd817adSflorian 	longjmp(jabort, 1);
319bfd817adSflorian }
320bfd817adSflorian 
321bfd817adSflorian /*
322bfd817adSflorian  * Get multiple files.
323bfd817adSflorian  */
324bfd817adSflorian void
mget(int argc,char * argv[])325bfd817adSflorian mget(int argc, char *argv[])
326bfd817adSflorian {
327bfd817adSflorian 	extern int optind, optreset;
328bfd817adSflorian 	sig_t oldintr;
329bfd817adSflorian 	int xargc = 2;
330bfd817adSflorian 	char *cp, localcwd[PATH_MAX], *xargv[] = { argv[0], NULL, NULL };
331bfd817adSflorian 	static int restartit = 0;
332bfd817adSflorian #ifndef SMALL
333bfd817adSflorian 	extern char *optarg;
334bfd817adSflorian 	const char *errstr;
335bfd817adSflorian 	int ch, i = 1;
336bfd817adSflorian 	char type = 0, *dummyargv[] = { argv[0], ".", NULL };
337bfd817adSflorian 	FILE *ftemp = NULL;
338bfd817adSflorian 	static int depth = 0, max_depth = 0;
339bfd817adSflorian 
340bfd817adSflorian 	optind = optreset = 1;
341bfd817adSflorian 
342bfd817adSflorian 	if (depth)
343bfd817adSflorian 		depth++;
344bfd817adSflorian 
345bfd817adSflorian 	while ((ch = getopt(argc, argv, "cd:nr")) != -1) {
346bfd817adSflorian 		switch(ch) {
347bfd817adSflorian 		case 'c':
348bfd817adSflorian 			restartit = 1;
349bfd817adSflorian 			break;
350bfd817adSflorian 		case 'd':
351bfd817adSflorian 			max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
352bfd817adSflorian 			if (errstr != NULL) {
353bfd817adSflorian 				fprintf(ttyout, "bad depth value, %s: %s\n",
354bfd817adSflorian 				    errstr, optarg);
355bfd817adSflorian 				code = -1;
356bfd817adSflorian 				return;
357bfd817adSflorian 			}
358bfd817adSflorian 			break;
359bfd817adSflorian 		case 'n':
360bfd817adSflorian 			restartit = -1;
361bfd817adSflorian 			break;
362bfd817adSflorian 		case 'r':
363bfd817adSflorian 			depth = 1;
364bfd817adSflorian 			break;
365bfd817adSflorian 		default:
366bfd817adSflorian 			goto usage;
367bfd817adSflorian 		}
368bfd817adSflorian 	}
369bfd817adSflorian 
370bfd817adSflorian 	if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) {
371bfd817adSflorian usage:
372bfd817adSflorian 		fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n",
373bfd817adSflorian 		    argv[0]);
374bfd817adSflorian 		code = -1;
375bfd817adSflorian 		return;
376bfd817adSflorian 	}
377bfd817adSflorian 
378bfd817adSflorian 	argv[optind - 1] = argv[0];
379bfd817adSflorian 	argc -= optind - 1;
380bfd817adSflorian 	argv += optind - 1;
381bfd817adSflorian #endif /* !SMALL */
382bfd817adSflorian 
383bfd817adSflorian 	mname = argv[0];
384bfd817adSflorian 	mflag = 1;
385bfd817adSflorian 	if (getcwd(localcwd, sizeof(localcwd)) == NULL)
386bfd817adSflorian 		err(1, "can't get cwd");
387bfd817adSflorian 
388bfd817adSflorian 	oldintr = signal(SIGINT, mabort);
389bfd817adSflorian 	(void)setjmp(jabort);
390bfd817adSflorian 	while ((cp =
391bfd817adSflorian #ifdef SMALL
392bfd817adSflorian 	    remglob(argv, proxy, NULL)) != NULL
393bfd817adSflorian 	    ) {
394bfd817adSflorian #else /* SMALL */
395bfd817adSflorian 	    depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) :
396bfd817adSflorian 	    remglob(argv, proxy, NULL)) != NULL
397bfd817adSflorian 	    || (mflag && depth && ++i < argc)
398bfd817adSflorian 	    ) {
399bfd817adSflorian 		if (cp == NULL)
400bfd817adSflorian 			continue;
401bfd817adSflorian #endif /* SMALL */
402bfd817adSflorian 		if (*cp == '\0') {
403bfd817adSflorian 			mflag = 0;
404bfd817adSflorian 			continue;
405bfd817adSflorian 		}
406bfd817adSflorian 		if (!mflag)
407bfd817adSflorian 			continue;
408bfd817adSflorian #ifndef SMALL
409bfd817adSflorian 		if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0)
410bfd817adSflorian 			continue;
411bfd817adSflorian #endif /* !SMALL */
412bfd817adSflorian 		if (!fileindir(cp, localcwd)) {
413bfd817adSflorian 			fprintf(ttyout, "Skipping non-relative filename `%s'\n",
414bfd817adSflorian 			    cp);
415bfd817adSflorian 			continue;
416bfd817adSflorian 		}
417bfd817adSflorian #ifndef SMALL
418bfd817adSflorian 		if (type == 'd' && depth == max_depth)
419bfd817adSflorian 			continue;
420bfd817adSflorian 		if (!confirm(argv[0], cp))
421bfd817adSflorian 			continue;
422bfd817adSflorian 		if (type == 'd') {
423bfd817adSflorian 			mkdir(cp, 0755);
424bfd817adSflorian 			if (chdir(cp) != 0) {
425bfd817adSflorian 				warn("local: %s", cp);
426bfd817adSflorian 				continue;
427bfd817adSflorian 			}
428bfd817adSflorian 
429bfd817adSflorian 			xargv[1] = cp;
430bfd817adSflorian 			cd(xargc, xargv);
431bfd817adSflorian 			if (dirchange != 1)
432bfd817adSflorian 				goto out;
433bfd817adSflorian 
434bfd817adSflorian 			xargv[1] = "*";
435bfd817adSflorian 			mget(xargc, xargv);
436bfd817adSflorian 
437bfd817adSflorian 			xargv[1] = "..";
438bfd817adSflorian 			cd(xargc, xargv);
439bfd817adSflorian 			if (dirchange != 1) {
440bfd817adSflorian 				mflag = 0;
441bfd817adSflorian 				goto out;
442bfd817adSflorian 			}
443bfd817adSflorian 
444bfd817adSflorian out:
445bfd817adSflorian 			if (chdir("..") != 0) {
446bfd817adSflorian 				warn("local: %s", cp);
447bfd817adSflorian 				mflag = 0;
448bfd817adSflorian 			}
449bfd817adSflorian 			continue;
450bfd817adSflorian 		}
451bfd817adSflorian 		if (type == 's')
452bfd817adSflorian 			/* Currently ignored. */
453bfd817adSflorian 			continue;
454bfd817adSflorian #endif /* !SMALL */
455bfd817adSflorian 		xargv[1] = cp;
456bfd817adSflorian 		(void)getit(xargc, xargv, restartit,
457bfd817adSflorian 		    (restartit == 1 || restart_point) ? "a+w" : "w");
458bfd817adSflorian #ifndef SMALL
459bfd817adSflorian 		if (!mflag && fromatty) {
460bfd817adSflorian 			if (confirm(argv[0], NULL))
461bfd817adSflorian 				mflag = 1;
462bfd817adSflorian 		}
463bfd817adSflorian #endif /* !SMALL */
464bfd817adSflorian 	}
465bfd817adSflorian 	(void)signal(SIGINT, oldintr);
466bfd817adSflorian #ifndef SMALL
467bfd817adSflorian 	if (depth)
468bfd817adSflorian 		depth--;
469bfd817adSflorian 	if (depth == 0 || mflag == 0)
470bfd817adSflorian 		depth = max_depth = mflag = restartit = 0;
471bfd817adSflorian #else /* !SMALL */
472bfd817adSflorian 	mflag = 0;
473bfd817adSflorian #endif /* !SMALL */
474bfd817adSflorian }
475bfd817adSflorian 
476bfd817adSflorian /*
477bfd817adSflorian  * Set current working directory on remote machine.
478bfd817adSflorian  */
479bfd817adSflorian void
480bfd817adSflorian cd(int argc, char *argv[])
481bfd817adSflorian {
482bfd817adSflorian 	int r;
483bfd817adSflorian 
484bfd817adSflorian #ifndef SMALL
485bfd817adSflorian 	if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
486bfd817adSflorian 	    argc > 2) {
487bfd817adSflorian 		fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
488bfd817adSflorian 		code = -1;
489bfd817adSflorian 		return;
490bfd817adSflorian 	}
491bfd817adSflorian #endif /* !SMALL */
492bfd817adSflorian 	r = command("CWD %s", argv[1]);
493bfd817adSflorian 	if (r == ERROR && code == 500) {
494bfd817adSflorian 		if (verbose)
495bfd817adSflorian 			fputs("CWD command not recognized, trying XCWD.\n", ttyout);
496bfd817adSflorian 		r = command("XCWD %s", argv[1]);
497bfd817adSflorian 	}
498bfd817adSflorian 	if (r == ERROR && code == 550) {
499bfd817adSflorian 		dirchange = 0;
500bfd817adSflorian 		return;
501bfd817adSflorian 	}
502bfd817adSflorian 	if (r == COMPLETE)
503bfd817adSflorian 		dirchange = 1;
504bfd817adSflorian }
505bfd817adSflorian 
506bfd817adSflorian /*
507bfd817adSflorian  * Terminate session, but don't exit.
508bfd817adSflorian  */
509bfd817adSflorian void
510bfd817adSflorian disconnect(int argc, char *argv[])
511bfd817adSflorian {
512bfd817adSflorian 
513bfd817adSflorian 	if (!connected)
514bfd817adSflorian 		return;
515bfd817adSflorian 	(void)command("QUIT");
516bfd817adSflorian 	if (cout) {
517bfd817adSflorian 		(void)fclose(cout);
518bfd817adSflorian 	}
519bfd817adSflorian 	cout = NULL;
520bfd817adSflorian 	connected = 0;
521bfd817adSflorian 	data = -1;
522bfd817adSflorian #ifndef SMALL
523bfd817adSflorian 	if (!proxy) {
524bfd817adSflorian 		macnum = 0;
525bfd817adSflorian 	}
526bfd817adSflorian #endif /* !SMALL */
527bfd817adSflorian }
528bfd817adSflorian 
529bfd817adSflorian char *
530bfd817adSflorian dotrans(char *name)
531bfd817adSflorian {
532bfd817adSflorian 	static char new[PATH_MAX];
533bfd817adSflorian 	char *cp1, *cp2 = new;
534bfd817adSflorian 	int i, ostop, found;
535bfd817adSflorian 
536bfd817adSflorian 	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
537bfd817adSflorian 		continue;
538bfd817adSflorian 	for (cp1 = name; *cp1; cp1++) {
539bfd817adSflorian 		found = 0;
540bfd817adSflorian 		for (i = 0; *(ntin + i) && i < 16; i++) {
541bfd817adSflorian 			if (*cp1 == *(ntin + i)) {
542bfd817adSflorian 				found++;
543bfd817adSflorian 				if (i < ostop) {
544bfd817adSflorian 					*cp2++ = *(ntout + i);
545bfd817adSflorian 				}
546bfd817adSflorian 				break;
547bfd817adSflorian 			}
548bfd817adSflorian 		}
549bfd817adSflorian 		if (!found) {
550bfd817adSflorian 			*cp2++ = *cp1;
551bfd817adSflorian 		}
552bfd817adSflorian 	}
553bfd817adSflorian 	*cp2 = '\0';
554bfd817adSflorian 	return (new);
555bfd817adSflorian }
556bfd817adSflorian 
557bfd817adSflorian char *
558bfd817adSflorian domap(char *name)
559bfd817adSflorian {
560bfd817adSflorian 	static char new[PATH_MAX];
561bfd817adSflorian 	char *cp1 = name, *cp2 = mapin;
562bfd817adSflorian 	char *tp[9], *te[9];
563bfd817adSflorian 	int i, toks[9], toknum = 0, match = 1;
564bfd817adSflorian 
565bfd817adSflorian 	for (i=0; i < 9; ++i) {
566bfd817adSflorian 		toks[i] = 0;
567bfd817adSflorian 	}
568bfd817adSflorian 	while (match && *cp1 && *cp2) {
569bfd817adSflorian 		switch (*cp2) {
570bfd817adSflorian 			case '\\':
571bfd817adSflorian 				if (*++cp2 != *cp1) {
572bfd817adSflorian 					match = 0;
573bfd817adSflorian 				}
574bfd817adSflorian 				break;
575bfd817adSflorian 			case '$':
576bfd817adSflorian 				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
577bfd817adSflorian 					if (*cp1 != *(++cp2+1)) {
578bfd817adSflorian 						toks[toknum = *cp2 - '1']++;
579bfd817adSflorian 						tp[toknum] = cp1;
580bfd817adSflorian 						while (*++cp1 && *(cp2+1)
581bfd817adSflorian 							!= *cp1);
582bfd817adSflorian 						te[toknum] = cp1;
583bfd817adSflorian 					}
584bfd817adSflorian 					cp2++;
585bfd817adSflorian 					break;
586bfd817adSflorian 				}
587bfd817adSflorian 				/* FALLTHROUGH */
588bfd817adSflorian 			default:
589bfd817adSflorian 				if (*cp2 != *cp1) {
590bfd817adSflorian 					match = 0;
591bfd817adSflorian 				}
592bfd817adSflorian 				break;
593bfd817adSflorian 		}
594bfd817adSflorian 		if (match && *cp1) {
595bfd817adSflorian 			cp1++;
596bfd817adSflorian 		}
597bfd817adSflorian 		if (match && *cp2) {
598bfd817adSflorian 			cp2++;
599bfd817adSflorian 		}
600bfd817adSflorian 	}
601bfd817adSflorian 	if (!match && *cp1) /* last token mismatch */
602bfd817adSflorian 	{
603bfd817adSflorian 		toks[toknum] = 0;
604bfd817adSflorian 	}
605bfd817adSflorian 	cp1 = new;
606bfd817adSflorian 	*cp1 = '\0';
607bfd817adSflorian 	cp2 = mapout;
608bfd817adSflorian 	while (*cp2) {
609bfd817adSflorian 		match = 0;
610bfd817adSflorian 		switch (*cp2) {
611bfd817adSflorian 			case '\\':
612bfd817adSflorian 				if (*(cp2 + 1)) {
613bfd817adSflorian 					*cp1++ = *++cp2;
614bfd817adSflorian 				}
615bfd817adSflorian 				break;
616bfd817adSflorian 			case '[':
617bfd817adSflorian LOOP:
618bfd817adSflorian 				if (*++cp2 == '$' && isdigit((unsigned char)*(cp2 + 1))) {
619bfd817adSflorian 					if (*++cp2 == '0') {
620bfd817adSflorian 						char *cp3 = name;
621bfd817adSflorian 
622bfd817adSflorian 						while (*cp3) {
623bfd817adSflorian 							*cp1++ = *cp3++;
624bfd817adSflorian 						}
625bfd817adSflorian 						match = 1;
626544013c6Sderaadt 					} else if (toks[toknum = *cp2 - '1']) {
627bfd817adSflorian 						char *cp3 = tp[toknum];
628bfd817adSflorian 
629bfd817adSflorian 						while (cp3 != te[toknum]) {
630bfd817adSflorian 							*cp1++ = *cp3++;
631bfd817adSflorian 						}
632bfd817adSflorian 						match = 1;
633bfd817adSflorian 					}
634544013c6Sderaadt 				} else {
635bfd817adSflorian 					while (*cp2 && *cp2 != ',' &&
636bfd817adSflorian 					    *cp2 != ']') {
637bfd817adSflorian 						if (*cp2 == '\\') {
638bfd817adSflorian 							cp2++;
639544013c6Sderaadt 						} else if (*cp2 == '$' &&
640bfd817adSflorian 						    isdigit((unsigned char)*(cp2 + 1))) {
641bfd817adSflorian 							if (*++cp2 == '0') {
642bfd817adSflorian 							   char *cp3 = name;
643bfd817adSflorian 
644bfd817adSflorian 							   while (*cp3) {
645bfd817adSflorian 								*cp1++ = *cp3++;
646bfd817adSflorian 							   }
647544013c6Sderaadt 							} else if (toks[toknum =
648bfd817adSflorian 							    *cp2 - '1']) {
649bfd817adSflorian 								char *cp3=tp[toknum];
650bfd817adSflorian 
651bfd817adSflorian 								while (cp3 !=
652bfd817adSflorian 								    te[toknum]) {
653bfd817adSflorian 									*cp1++ = *cp3++;
654bfd817adSflorian 								}
655bfd817adSflorian 							}
656544013c6Sderaadt 						} else if (*cp2) {
657bfd817adSflorian 							*cp1++ = *cp2++;
658bfd817adSflorian 						}
659bfd817adSflorian 					}
660bfd817adSflorian 					if (!*cp2) {
661bfd817adSflorian 						fputs(
662bfd817adSflorian "nmap: unbalanced brackets.\n", ttyout);
663bfd817adSflorian 						return (name);
664bfd817adSflorian 					}
665bfd817adSflorian 					match = 1;
666bfd817adSflorian 					cp2--;
667bfd817adSflorian 				}
668bfd817adSflorian 				if (match) {
669bfd817adSflorian 					while (*++cp2 && *cp2 != ']') {
670bfd817adSflorian 						if (*cp2 == '\\' && *(cp2 + 1)) {
671bfd817adSflorian 							cp2++;
672bfd817adSflorian 						}
673bfd817adSflorian 					}
674bfd817adSflorian 					if (!*cp2) {
675bfd817adSflorian 						fputs(
676bfd817adSflorian "nmap: unbalanced brackets.\n", ttyout);
677bfd817adSflorian 						return (name);
678bfd817adSflorian 					}
679bfd817adSflorian 					break;
680bfd817adSflorian 				}
681bfd817adSflorian 				switch (*++cp2) {
682bfd817adSflorian 					case ',':
683bfd817adSflorian 						goto LOOP;
684bfd817adSflorian 					case ']':
685bfd817adSflorian 						break;
686bfd817adSflorian 					default:
687bfd817adSflorian 						cp2--;
688bfd817adSflorian 						goto LOOP;
689bfd817adSflorian 				}
690bfd817adSflorian 				break;
691bfd817adSflorian 			case '$':
692bfd817adSflorian 				if (isdigit((unsigned char)*(cp2 + 1))) {
693bfd817adSflorian 					if (*++cp2 == '0') {
694bfd817adSflorian 						char *cp3 = name;
695bfd817adSflorian 
696bfd817adSflorian 						while (*cp3) {
697bfd817adSflorian 							*cp1++ = *cp3++;
698bfd817adSflorian 						}
699544013c6Sderaadt 					} else if (toks[toknum = *cp2 - '1']) {
700bfd817adSflorian 						char *cp3 = tp[toknum];
701bfd817adSflorian 
702bfd817adSflorian 						while (cp3 != te[toknum]) {
703bfd817adSflorian 							*cp1++ = *cp3++;
704bfd817adSflorian 						}
705bfd817adSflorian 					}
706bfd817adSflorian 					break;
707bfd817adSflorian 				}
708bfd817adSflorian 				/* FALLTHROUGH */
709bfd817adSflorian 			default:
710bfd817adSflorian 				*cp1++ = *cp2;
711bfd817adSflorian 				break;
712bfd817adSflorian 		}
713bfd817adSflorian 		cp2++;
714bfd817adSflorian 	}
715bfd817adSflorian 	*cp1 = '\0';
716bfd817adSflorian 	if (!*new) {
717bfd817adSflorian 		return (name);
718bfd817adSflorian 	}
719bfd817adSflorian 	return (new);
720bfd817adSflorian }
721bfd817adSflorian 
722