xref: /csrg-svn/usr.bin/ftp/main.c (revision 25802)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)main.c	5.2 (Berkeley) 01/10/86";
15 #endif not lint
16 
17 /*
18  * FTP User Program -- Command Interface.
19  */
20 #include <sys/param.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 
24 #include <arpa/ftp.h>
25 
26 #include <signal.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <netdb.h>
31 #include <pwd.h>
32 
33 #include "ftp_var.h"
34 
35 int	intr();
36 int	lostpeer();
37 extern	char *home;
38 
39 main(argc, argv)
40 	char *argv[];
41 {
42 	register char *cp;
43 	int top;
44 	struct passwd *pw;
45 	char homedir[MAXPATHLEN];
46 
47 	sp = getservbyname("ftp", "tcp");
48 	if (sp == 0) {
49 		fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
50 		exit(1);
51 	}
52 	doglob = 1;
53 	interactive = 1;
54 	autologin = 1;
55 	argc--, argv++;
56 	while (argc > 0 && **argv == '-') {
57 		for (cp = *argv + 1; *cp; cp++)
58 			switch (*cp) {
59 
60 			case 'd':
61 				options |= SO_DEBUG;
62 				debug++;
63 				break;
64 
65 			case 'v':
66 				verbose++;
67 				break;
68 
69 			case 't':
70 				trace++;
71 				break;
72 
73 			case 'i':
74 				interactive = 0;
75 				break;
76 
77 			case 'n':
78 				autologin = 0;
79 				break;
80 
81 			case 'g':
82 				doglob = 0;
83 				break;
84 
85 			default:
86 				fprintf(stderr,
87 				  "ftp: %c: unknown option\n", *cp);
88 				exit(1);
89 			}
90 		argc--, argv++;
91 	}
92 	fromatty = isatty(fileno(stdin));
93 	/*
94 	 * Set up defaults for FTP.
95 	 */
96 	strcpy(typename, "ascii"), type = TYPE_A;
97 	strcpy(formname, "non-print"), form = FORM_N;
98 	strcpy(modename, "stream"), mode = MODE_S;
99 	strcpy(structname, "file"), stru = STRU_F;
100 	strcpy(bytename, "8"), bytesize = 8;
101 	if (fromatty)
102 		verbose++;
103 	/*
104 	 * Set up the home directory in case we're globbing.
105 	 */
106 	pw = getpwnam(getlogin());
107 	if (pw == NULL)
108 		pw = getpwuid(getuid());
109 	if (pw != NULL) {
110 		home = homedir;
111 		strcpy(home, pw->pw_dir);
112 	}
113 	if (argc > 0) {
114 		if (setjmp(toplevel))
115 			exit(0);
116 		signal(SIGINT, intr);
117 		signal(SIGPIPE, lostpeer);
118 		setpeer(argc + 1, argv - 1);
119 	}
120 	top = setjmp(toplevel) == 0;
121 	if (top) {
122 		signal(SIGINT, intr);
123 		signal(SIGPIPE, lostpeer);
124 	}
125 	for (;;) {
126 		cmdscanner(top);
127 		top = 1;
128 	}
129 }
130 
131 intr()
132 {
133 
134 	longjmp(toplevel, 1);
135 }
136 
137 lostpeer()
138 {
139 	extern FILE *cout;
140 	extern int data;
141 
142 	if (connected) {
143 		if (cout != NULL) {
144 			shutdown(fileno(cout), 1+1);
145 			fclose(cout);
146 			cout = NULL;
147 		}
148 		if (data >= 0) {
149 			shutdown(data, 1+1);
150 			(void) close(data);
151 			data = -1;
152 		}
153 		connected = 0;
154 	}
155 	longjmp(toplevel, 1);
156 }
157 
158 char *
159 tail(filename)
160 	char *filename;
161 {
162 	register char *s;
163 
164 	while (*filename) {
165 		s = rindex(filename, '/');
166 		if (s == NULL)
167 			break;
168 		if (s[1])
169 			return (s + 1);
170 		*s = '\0';
171 	}
172 	return (filename);
173 }
174 
175 /*
176  * Command parser.
177  */
178 cmdscanner(top)
179 	int top;
180 {
181 	register struct cmd *c;
182 	struct cmd *getcmd();
183 	extern struct cmd cmdtab[];
184 	extern int help();
185 
186 	if (!top)
187 		putchar('\n');
188 	for (;;) {
189 		if (fromatty) {
190 			printf("ftp> ");
191 			fflush(stdout);
192 		}
193 		if (gets(line) == 0) {
194 			if (feof(stdin))
195 				quit();
196 			break;
197 		}
198 		if (line[0] == 0)
199 			break;
200 		makeargv();
201 		c = getcmd(margv[0]);
202 		if (c == (struct cmd *)-1) {
203 			printf("?Ambiguous command\n");
204 			continue;
205 		}
206 		if (c == 0) {
207 			printf("?Invalid command\n");
208 			continue;
209 		}
210 		if (c->c_conn && !connected) {
211 			printf ("Not connected.\n");
212 			continue;
213 		}
214 		(*c->c_handler)(margc, margv);
215 		if (bell && c->c_bell)
216 			putchar(CTRL(g));
217 		if (c->c_handler != help)
218 			break;
219 	}
220 	longjmp(toplevel, 0);
221 }
222 
223 struct cmd *
224 getcmd(name)
225 	register char *name;
226 {
227 	register char *p, *q;
228 	register struct cmd *c, *found;
229 	register int nmatches, longest;
230 
231 	longest = 0;
232 	nmatches = 0;
233 	found = 0;
234 	for (c = cmdtab; p = c->c_name; c++) {
235 		for (q = name; *q == *p++; q++)
236 			if (*q == 0)		/* exact match? */
237 				return (c);
238 		if (!*q) {			/* the name was a prefix */
239 			if (q - name > longest) {
240 				longest = q - name;
241 				nmatches = 1;
242 				found = c;
243 			} else if (q - name == longest)
244 				nmatches++;
245 		}
246 	}
247 	if (nmatches > 1)
248 		return ((struct cmd *)-1);
249 	return (found);
250 }
251 
252 /*
253  * Slice a string up into argc/argv.
254  */
255 makeargv()
256 {
257 	char **argp;
258 	char *slurpstring();
259 
260 	margc = 0;
261 	argp = margv;
262 	stringbase = line;		/* scan from first of buffer */
263 	argbase = argbuf;		/* store from first of buffer */
264 	while (*argp++ = slurpstring())
265 		margc++;
266 }
267 
268 /*
269  * Parse string into argbuf;
270  * implemented with FSM to
271  * handle quoting and strings
272  */
273 char *
274 slurpstring()
275 {
276 	int got_one = 0;
277 	register char *sb = stringbase;
278 	register char *ap = argbase;
279 	char *tmp = argbase;		/* will return this if token found */
280 
281 	if (*sb == '!') {		/* recognize ! as a token for shell */
282 		stringbase++;
283 		return ("!");
284 	}
285 S0:
286 	switch (*sb) {
287 
288 	case '\0':
289 		goto OUT;
290 
291 	case ' ':
292 	case '\t':
293 		sb++; goto S0;
294 
295 	default:
296 		goto S1;
297 	}
298 
299 S1:
300 	switch (*sb) {
301 
302 	case ' ':
303 	case '\t':
304 	case '\0':
305 		goto OUT;	/* end of token */
306 
307 	case '\\':
308 		sb++; goto S2;	/* slurp next character */
309 
310 	case '"':
311 		sb++; goto S3;	/* slurp quoted string */
312 
313 	default:
314 		*ap++ = *sb++;	/* add character to token */
315 		got_one = 1;
316 		goto S1;
317 	}
318 
319 S2:
320 	switch (*sb) {
321 
322 	case '\0':
323 		goto OUT;
324 
325 	default:
326 		*ap++ = *sb++;
327 		got_one = 1;
328 		goto S1;
329 	}
330 
331 S3:
332 	switch (*sb) {
333 
334 	case '\0':
335 		goto OUT;
336 
337 	case '"':
338 		sb++; goto S1;
339 
340 	default:
341 		*ap++ = *sb++;
342 		got_one = 1;
343 		goto S3;
344 	}
345 
346 OUT:
347 	if (got_one)
348 		*ap++ = '\0';
349 	argbase = ap;			/* update storage pointer */
350 	stringbase = sb;		/* update scan pointer */
351 	if (got_one)
352 		return(tmp);
353 	return((char *)0);
354 }
355 
356 #define HELPINDENT (sizeof ("directory"))
357 
358 /*
359  * Help command.
360  * Call each command handler with argc == 0 and argv[0] == name.
361  */
362 help(argc, argv)
363 	int argc;
364 	char *argv[];
365 {
366 	register struct cmd *c;
367 
368 	if (argc == 1) {
369 		register int i, j, w;
370 		int columns, width = 0, lines;
371 		extern int NCMDS;
372 
373 		printf("Commands may be abbreviated.  Commands are:\n\n");
374 		for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
375 			int len = strlen(c->c_name);
376 
377 			if (len > width)
378 				width = len;
379 		}
380 		width = (width + 8) &~ 7;
381 		columns = 80 / width;
382 		if (columns == 0)
383 			columns = 1;
384 		lines = (NCMDS + columns - 1) / columns;
385 		for (i = 0; i < lines; i++) {
386 			for (j = 0; j < columns; j++) {
387 				c = cmdtab + j * lines + i;
388 				printf("%s", c->c_name);
389 				if (c + lines >= &cmdtab[NCMDS]) {
390 					printf("\n");
391 					break;
392 				}
393 				w = strlen(c->c_name);
394 				while (w < width) {
395 					w = (w + 8) &~ 7;
396 					putchar('\t');
397 				}
398 			}
399 		}
400 		return;
401 	}
402 	while (--argc > 0) {
403 		register char *arg;
404 		arg = *++argv;
405 		c = getcmd(arg);
406 		if (c == (struct cmd *)-1)
407 			printf("?Ambiguous help command %s\n", arg);
408 		else if (c == (struct cmd *)0)
409 			printf("?Invalid help command %s\n", arg);
410 		else
411 			printf("%-*s\t%s\n", HELPINDENT,
412 				c->c_name, c->c_help);
413 	}
414 }
415 
416 /*
417  * Call routine with argc, argv set from args (terminated by 0).
418  */
419 /* VARARGS2 */
420 call(routine, args)
421 	int (*routine)();
422 	int args;
423 {
424 	register int *argp;
425 	register int argc;
426 
427 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
428 		;
429 	(*routine)(argc, &args);
430 }
431