|
|
1.1 root 1: #ifndef lint
2: static char RCSid[] = "$Header: main.c,v 2.3 87/03/23 12:29:53 ed Exp $";
3: #endif
4:
5: /*
6: * FTP User Program -- Command Interface.
7: */
8: /* $Log: main.c,v $
9: * Revision 2.3 87/03/23 12:29:53 ed
10: * Added -c switch to allow xnsftp commands to be specified directly
11: * on commandline.
12: *
13: * Revision 2.2 87/01/09 16:51:37 ed
14: * Use FilingSubset, if rejected attempt Filing
15: * Allows user override with -F switch
16: * Maintain FilingSubset mandatory attributes
17: * User niceties: echo file name/type on transfer commands
18: * prompt on delete
19: * guess type which will determine file type implied by content
20: * New commands: (type related) Guess, Whatis
21: * (file transfer) Copy, Move, Rename
22: *
23: * Revision 2.1 86/12/11 06:12:14 jqj
24: * Eliminated form, mode, and struct commands. Started adding support for
25: * more file types.
26: *
27: * Revision 2.0 85/11/21 07:22:49 jqj
28: * 4.3BSD standard release
29: *
30: * Revision 1.1 85/05/27 06:31:05 jqj
31: * Initial revision
32: *
33: * Revision 1.1 85/05/27 06:31:05 jqj
34: * Initial revision
35: *
36: * Based on Berkeley tcp/ftp
37: */
38: #include <sys/param.h>
39: #include <sys/socket.h>
40: #include <sys/ioctl.h>
41:
42: #include <xnscourier/except.h>
43: #include <stdio.h>
44: #include <errno.h>
45: #include <ctype.h>
46: #include <pwd.h>
47:
48: #include "ftp_var.h"
49:
50: int intr();
51: int lostpeer();
52: extern char *home;
53:
54: main(argc, argv)
55: char *argv[];
56: {
57: register char *cp;
58: int top;
59: int continue_flag= 1;
60: struct passwd *pw;
61: char homedir[MAXPATHLEN];
62: char *cmd;
63:
64: doglob = 1;
65: interactive = 1;
66: autologin = 1;
67: argc--, argv++;
68: fromatty = isatty(fileno(stdin));
69: if (fromatty)
70: verbose++;
71: while (argc > 0 && **argv == '-') {
72: for (cp = *argv + 1; *cp; cp++)
73: switch (*cp) {
74:
75: case 'd':
76: debug++;
77: break;
78:
79: case 'v':
80: verbose++;
81: break;
82:
83: case 't':
84: trace++;
85: break;
86:
87: case 'i':
88: interactive = 0;
89: break;
90:
91: case 'n':
92: autologin = 0;
93: break;
94:
95: case 'g':
96: doglob = 0;
97: break;
98:
99: case 'F':
100: usefiling++;
101: break;
102:
103: case 'c':
104: argc--, argv++;
105: cmd= *argv;
106: interactive= verbose= continue_flag= 0;
107: break;
108:
109: default:
110: fprintf(stderr,
111: "xnsftp: %c: unknown option\n", *cp);
112: exit(1);
113: }
114: argc--, argv++;
115: }
116: /*
117: * Set up defaults for FTP.
118: */
119: strcpy(typename, "guess"), typevalue = TYPE_Guess;
120: /*
121: * Set up the home directory in case we're globbing.
122: */
123: pw = getpwnam(getlogin());
124: if (pw == NULL)
125: pw = getpwuid(getuid());
126: if (pw != NULL) {
127: home = homedir;
128: strcpy(home, pw->pw_dir);
129: }
130: signal(SIGINT, intr);
131: signal(SIGPIPE, lostpeer);
132:
133: DURING {
134: if (argc > 0)
135: setpeer(argc + 1, argv - 1);
136: } HANDLER {
137: FilingErrMsg(Exception.Code, Exception.Message);
138: exit(0);
139: } END_HANDLER;
140:
141: if ( cmd ) {
142: continue_flag= cmdfromargv(cmd);
143: }
144:
145: if (continue_flag) {
146: for (;;) {
147: DURING {
148: for (;;)
149: cmdscanner();
150: } HANDLER {
151: FilingErrMsg(Exception.Code, Exception.Message);
152: if (connected != (CourierConnection*)0) {
153: DURING
154: probe(); /* reset alarm */
155: HANDLER { /* can't? Lost peer */
156: connected = (CourierConnection*) 0;
157: } END_HANDLER;
158: }
159: } END_HANDLER;
160: }
161: }
162: }
163:
164: intr()
165: {
166: extern probe();
167:
168: printf("\n");
169: raise(0, (char *)0);
170: }
171:
172: lostpeer()
173: {
174: if (connected != (CourierConnection*)0) {
175: /* CourierClose(connected); */ /* probably won't work */
176: connected = (CourierConnection*) 0;
177: }
178: raise(EPIPE, "lost peer");
179: }
180:
181: char *
182: tail(filename)
183: char *filename;
184: {
185: register char *s;
186:
187: while (*filename) {
188: s = rindex(filename, '/');
189: if (s == NULL)
190: break;
191: if (s[1])
192: return (s + 1);
193: *s = '\0';
194: }
195: return (filename);
196: }
197:
198: /*
199: * Command parser.
200: */
201: cmdscanner()
202: {
203: register struct cmd *c;
204: struct cmd *getcmd();
205: extern struct cmd cmdtab[];
206: extern int help();
207:
208: for (;;) {
209: if (fromatty) {
210: printf("xnsftp> ");
211: fflush(stdout);
212: }
213: if (gets(line) == 0) {
214: if (feof(stdin)) {
215: clearerr(stdin);
216: putchar('\n');
217: }
218: break;
219: }
220: if (line[0] == 0)
221: break;
222: makeargv();
223: c = getcmd(margv[0]);
224: if (c == (struct cmd *)-1) {
225: printf("?Ambiguous command\n");
226: continue;
227: }
228: if (c == 0) {
229: printf("?Invalid command\n");
230: continue;
231: }
232: if (c->c_conn && !connected) {
233: printf ("Not connected.\n");
234: continue;
235: }
236: (*c->c_handler)(margc, margv);
237: if (bell && c->c_bell)
238: putchar(CTRL(g));
239: if (c->c_handler != help)
240: break;
241: }
242: }
243: /*
244: * Execute commands from command line.
245: * command is of form "command1 ; command2 ; command3 ; ..."
246: */
247: cmdfromargv(command)
248: char *command;
249: {
250: register struct cmd *c;
251: struct cmd *getcmd();
252: extern struct cmd cmdtab[];
253: extern int help();
254: int done= 0;
255: char *ptr, *endptr;
256:
257: endptr= command + strlen(command) - 1;
258:
259: for (;;) {
260: if ( done ) break;
261:
262: if ( (ptr= index(command, ';')) == 0 ) {
263: done= 1;
264: } else {
265: if (ptr == endptr)
266: done= 1;
267: *ptr= '\0';
268: }
269:
270: strcpy(line,command);
271: command= ptr + 1;
272:
273: makeargv();
274: c = getcmd(margv[0]);
275: if (c == (struct cmd *)-1) {
276: printf("?Ambiguous command\n");
277: continue;
278: }
279: if (c == 0) {
280: printf("?Invalid command\n");
281: continue;
282: }
283: if (c->c_conn && !connected) {
284: printf ("Not connected.\n");
285: continue;
286: }
287:
288: DURING {
289: (*c->c_handler)(margc, margv);
290: } HANDLER {
291: FilingErrMsg(Exception.Code, Exception.Message);
292: ptr= 0; /* force exit */
293: break;
294: } END_HANDLER;
295:
296: if (bell && c->c_bell)
297: putchar(CTRL(g));
298: if (c->c_handler != help)
299: continue;
300: }
301:
302: if ( ptr == endptr ) /* semi as last character */
303: return(1);
304: else
305: return(0);
306:
307: }
308:
309: struct cmd *
310: getcmd(name)
311: register char *name;
312: {
313: register char *p, *q;
314: register struct cmd *c, *found;
315: register int nmatches, longest;
316:
317: longest = 0;
318: nmatches = 0;
319: found = 0;
320: for (c = cmdtab; p = c->c_name; c++) {
321: for (q = name; *q == *p++; q++)
322: if (*q == 0) /* exact match? */
323: return (c);
324: if (!*q) { /* the name was a prefix */
325: if (q - name > longest) {
326: longest = q - name;
327: nmatches = 1;
328: found = c;
329: } else if (q - name == longest)
330: nmatches++;
331: }
332: }
333: if (nmatches > 1)
334: return ((struct cmd *)-1);
335: return (found);
336: }
337:
338: /*
339: * Slice a string up into argc/argv.
340: */
341: makeargv()
342: {
343: char **argp;
344: char *slurpstring();
345:
346: margc = 0;
347: argp = margv;
348: stringbase = line; /* scan from first of buffer */
349: argbase = argbuf; /* store from first of buffer */
350: while (*argp++ = slurpstring())
351: margc++;
352: }
353:
354: /*
355: * Parse string into argbuf;
356: * implemented with FSM to
357: * handle quoting and strings
358: */
359: char *
360: slurpstring()
361: {
362: int got_one = 0;
363: register char *sb = stringbase;
364: register char *ap = argbase;
365: char *tmp = argbase; /* will return this if token found */
366:
367: if (*sb == '!') { /* recognize ! as a token for shell */
368: stringbase++;
369: return ("!");
370: }
371: S0:
372: switch (*sb) {
373:
374: case '\0':
375: goto OUT;
376:
377: case ' ':
378: case '\t':
379: sb++; goto S0;
380:
381: default:
382: goto S1;
383: }
384:
385: S1:
386: switch (*sb) {
387:
388: case ' ':
389: case '\t':
390: case '\0':
391: goto OUT; /* end of token */
392:
393: case '\\':
394: sb++; goto S2; /* slurp next character */
395:
396: case '"':
397: sb++; goto S3; /* slurp quoted string */
398:
399: default:
400: *ap++ = *sb++; /* add character to token */
401: got_one = 1;
402: goto S1;
403: }
404:
405: S2:
406: switch (*sb) {
407:
408: case '\0':
409: goto OUT;
410:
411: default:
412: *ap++ = *sb++;
413: got_one = 1;
414: goto S1;
415: }
416:
417: S3:
418: switch (*sb) {
419:
420: case '\0':
421: goto OUT;
422:
423: case '"':
424: sb++; goto S1;
425:
426: default:
427: *ap++ = *sb++;
428: got_one = 1;
429: goto S3;
430: }
431:
432: OUT:
433: if (got_one)
434: *ap++ = '\0';
435: argbase = ap; /* update storage pointer */
436: stringbase = sb; /* update scan pointer */
437: if (got_one)
438: return(tmp);
439: return((char *)0);
440: }
441:
442: #define HELPINDENT (sizeof ("directory"))
443:
444: /*
445: * Help command.
446: * Call each command handler with argc == 0 and argv[0] == name.
447: */
448: help(argc, argv)
449: int argc;
450: char *argv[];
451: {
452: register struct cmd *c;
453:
454: if (argc == 1) {
455: register int i, j, w;
456: int columns, width = 0, lines;
457: extern int NCMDS;
458:
459: printf("Commands may be abbreviated. Commands are:\n\n");
460: for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
461: int len = strlen(c->c_name);
462:
463: if (len > width)
464: width = len;
465: }
466: width = (width + 8) &~ 7;
467: columns = 80 / width;
468: if (columns == 0)
469: columns = 1;
470: lines = (NCMDS + columns - 1) / columns;
471: for (i = 0; i < lines; i++) {
472: for (j = 0; j < columns; j++) {
473: c = cmdtab + j * lines + i;
474: printf("%s", c->c_name);
475: if (c + lines >= &cmdtab[NCMDS]) {
476: printf("\n");
477: break;
478: }
479: w = strlen(c->c_name);
480: while (w < width) {
481: w = (w + 8) &~ 7;
482: putchar('\t');
483: }
484: }
485: }
486: return;
487: }
488: while (--argc > 0) {
489: register char *arg;
490: arg = *++argv;
491: c = getcmd(arg);
492: if (c == (struct cmd *)-1)
493: printf("?Ambiguous help command %s\n", arg);
494: else if (c == (struct cmd *)0)
495: printf("?Invalid help command %s\n", arg);
496: else
497: printf("%-*s\t%s\n", HELPINDENT,
498: c->c_name, c->c_help);
499: }
500: }
501:
502: /*
503: * Call routine with argc, argv set from args (terminated by 0).
504: */
505: /* VARARGS2 */
506: call(routine, args)
507: int (*routine)();
508: int args;
509: {
510: register int *argp;
511: register int argc;
512:
513: for (argc = 0, argp = &args; *argp++ != 0; argc++)
514: ;
515: (*routine)(argc, &args);
516: }
517:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.