110297Ssam #ifndef lint 2*11351Ssam static char sccsid[] = "@(#)main.c 4.4 (Berkeley) 03/01/83"; 310297Ssam #endif 410297Ssam 510297Ssam /* 610297Ssam * FTP User Program -- Command Interface. 710297Ssam */ 810297Ssam #include <sys/types.h> 910297Ssam #include <sys/socket.h> 1010297Ssam #include <sys/ioctl.h> 1110297Ssam 1210297Ssam #include <signal.h> 1310297Ssam #include <stdio.h> 1410297Ssam #include <errno.h> 1510297Ssam #include <ctype.h> 1610297Ssam #include <netdb.h> 1710297Ssam 1810297Ssam #include "ftp.h" 1910297Ssam #include "ftp_var.h" 2010297Ssam 2110297Ssam int intr(); 2210297Ssam int lostpeer(); 2310297Ssam 2410297Ssam main(argc, argv) 2510297Ssam char *argv[]; 2610297Ssam { 2710297Ssam register char *cp; 2810297Ssam int top; 2910297Ssam 3010297Ssam sp = getservbyname("ftp", "tcp"); 3110297Ssam if (sp == 0) { 3210297Ssam fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 3310297Ssam exit(1); 3410297Ssam } 35*11351Ssam doglob = 1; 36*11351Ssam autologin = 1; 3710297Ssam argc--, argv++; 3810297Ssam while (argc > 0 && **argv == '-') { 3910297Ssam for (cp = *argv + 1; *cp; cp++) 4010297Ssam switch (*cp) { 4110297Ssam 4210297Ssam case 'd': 4310297Ssam options |= SO_DEBUG; 4410297Ssam debug++; 4510297Ssam break; 4610297Ssam 4710297Ssam case 'v': 4810297Ssam verbose++; 4910297Ssam break; 5010297Ssam 5110297Ssam case 't': 5210297Ssam trace++; 5310297Ssam break; 5410297Ssam 5510297Ssam case 'i': 5610297Ssam interactive++; 5710297Ssam break; 5810297Ssam 5910297Ssam case 'n': 6010297Ssam autologin = 0; 6110297Ssam break; 6210297Ssam 63*11351Ssam case 'g': 64*11351Ssam doglob = 0; 65*11351Ssam break; 66*11351Ssam 6710297Ssam default: 6810297Ssam fprintf(stderr, 6910297Ssam "ftp: %c: unknown option\n", *cp); 7010297Ssam exit(1); 7110297Ssam } 7210297Ssam argc--, argv++; 7310297Ssam } 7410297Ssam fromatty = isatty(fileno(stdin)); 7510297Ssam /* 7610297Ssam * Set up defaults for FTP. 7710297Ssam */ 7810297Ssam strcpy(typename, "ascii"), type = TYPE_A; 7910297Ssam strcpy(formname, "non-print"), form = FORM_N; 8010297Ssam strcpy(modename, "stream"), mode = MODE_S; 8110297Ssam strcpy(structname, "file"), stru = STRU_F; 8211227Ssam strcpy(bytename, "8"), bytesize = 8; 8310297Ssam if (fromatty) 8410297Ssam verbose++; 8510297Ssam if (argc > 0) { 8610297Ssam if (setjmp(toplevel)) 8710297Ssam exit(0); 8810297Ssam sigset(SIGINT, intr); 8910297Ssam sigset(SIGPIPE, lostpeer); 9010297Ssam setpeer(argc + 1, argv - 1); 9110297Ssam } 9210297Ssam top = setjmp(toplevel) == 0; 9310297Ssam if (top) { 9410297Ssam sigset(SIGINT, intr); 9510297Ssam sigset(SIGPIPE, lostpeer); 9610297Ssam } 9710297Ssam for (;;) { 9810297Ssam cmdscanner(top); 9910297Ssam top = 1; 10010297Ssam } 10110297Ssam } 10210297Ssam 10310297Ssam intr() 10410297Ssam { 10510297Ssam 10610297Ssam longjmp(toplevel, 1); 10710297Ssam } 10810297Ssam 10910297Ssam lostpeer() 11010297Ssam { 11110297Ssam extern FILE *cout; 11210297Ssam extern int data; 11310297Ssam 11410297Ssam if (connected) { 11510297Ssam if (cout != NULL) { 11611239Ssam shutdown(fileno(cout), 1+1); 11710297Ssam fclose(cout); 11810297Ssam cout = NULL; 11910297Ssam } 12010297Ssam if (data >= 0) { 12111239Ssam shutdown(data, 1+1); 12210297Ssam (void) close(data); 12310297Ssam data = -1; 12410297Ssam } 12510297Ssam connected = 0; 12610297Ssam } 12710297Ssam longjmp(toplevel, 1); 12810297Ssam } 12910297Ssam 13010297Ssam char * 13110297Ssam tail(filename) 13210297Ssam char *filename; 13310297Ssam { 13410297Ssam register char *s; 13510297Ssam 13610297Ssam while (*filename) { 13710297Ssam s = rindex(filename, '/'); 13810297Ssam if (s == NULL) 13910297Ssam break; 14010297Ssam if (s[1]) 14110297Ssam return (s + 1); 14210297Ssam *s = '\0'; 14310297Ssam } 14410297Ssam return (filename); 14510297Ssam } 14610297Ssam 14710297Ssam /* 14810297Ssam * Command parser. 14910297Ssam */ 15010297Ssam cmdscanner(top) 15110297Ssam int top; 15210297Ssam { 15310297Ssam register struct cmd *c; 15410297Ssam struct cmd *getcmd(); 15510297Ssam extern struct cmd cmdtab[]; 15610297Ssam extern int help(); 15710297Ssam 15810297Ssam if (!top) 15910297Ssam putchar('\n'); 16010297Ssam for (;;) { 16110297Ssam if (fromatty) { 16210297Ssam printf("ftp> "); 16310297Ssam fflush(stdout); 16410297Ssam } 16510297Ssam if (gets(line) == 0) 16610297Ssam break; 16710297Ssam if (line[0] == 0) 16810297Ssam break; 16910297Ssam makeargv(); 17010297Ssam c = getcmd(margv[0]); 17110297Ssam if (c == (struct cmd *)-1) { 17210297Ssam printf("?Ambiguous command\n"); 17310297Ssam continue; 17410297Ssam } 17510297Ssam if (c == 0) { 17610297Ssam printf("?Invalid command\n"); 17710297Ssam continue; 17810297Ssam } 17910297Ssam (*c->c_handler)(margc, margv); 18010297Ssam if (bell && c->c_bell) 18110297Ssam putchar(CTRL(g)); 18210297Ssam if (c->c_handler != help) 18310297Ssam break; 18410297Ssam } 18510297Ssam longjmp(toplevel, 0); 18610297Ssam } 18710297Ssam 18810297Ssam struct cmd * 18910297Ssam getcmd(name) 19010297Ssam register char *name; 19110297Ssam { 19210297Ssam register char *p, *q; 19310297Ssam register struct cmd *c, *found; 19410297Ssam register int nmatches, longest; 19510297Ssam 19610297Ssam longest = 0; 19710297Ssam nmatches = 0; 19810297Ssam found = 0; 19910297Ssam for (c = cmdtab; p = c->c_name; c++) { 20010297Ssam for (q = name; *q == *p++; q++) 20110297Ssam if (*q == 0) /* exact match? */ 20210297Ssam return (c); 20310297Ssam if (!*q) { /* the name was a prefix */ 20410297Ssam if (q - name > longest) { 20510297Ssam longest = q - name; 20610297Ssam nmatches = 1; 20710297Ssam found = c; 20810297Ssam } else if (q - name == longest) 20910297Ssam nmatches++; 21010297Ssam } 21110297Ssam } 21210297Ssam if (nmatches > 1) 21310297Ssam return ((struct cmd *)-1); 21410297Ssam return (found); 21510297Ssam } 21610297Ssam 21710297Ssam /* 21810297Ssam * Slice a string up into argc/argv. 21910297Ssam */ 22010297Ssam makeargv() 22110297Ssam { 22210297Ssam char **argp; 22310297Ssam char *slurpstring(); 22410297Ssam 22510297Ssam margc = 0; 22610297Ssam argp = margv; 22710297Ssam stringbase = line; /* scan from first of buffer */ 22810297Ssam argbase = argbuf; /* store from first of buffer */ 22910297Ssam while (*argp++ = slurpstring()) 23010297Ssam margc++; 23110297Ssam } 23210297Ssam 23310297Ssam /* 23410297Ssam * Parse string into argbuf; 23510297Ssam * implemented with FSM to 23610297Ssam * handle quoting and strings 23710297Ssam */ 23810297Ssam char * 23910297Ssam slurpstring() 24010297Ssam { 24110297Ssam int got_one = 0; 24210297Ssam register char *sb = stringbase; 24310297Ssam register char *ap = argbase; 24410297Ssam char *tmp = argbase; /* will return this if token found */ 24510297Ssam 24610297Ssam S0: 24710297Ssam switch (*sb) { 24810297Ssam 24910297Ssam case '\0': 25010297Ssam goto OUT; 25110297Ssam 25210297Ssam case ' ': 25310297Ssam case '\t': 25410297Ssam sb++; goto S0; 25510297Ssam 25610297Ssam default: 25710297Ssam goto S1; 25810297Ssam } 25910297Ssam 26010297Ssam S1: 26110297Ssam switch (*sb) { 26210297Ssam 26310297Ssam case ' ': 26410297Ssam case '\t': 26510297Ssam case '\0': 26610297Ssam goto OUT; /* end of token */ 26710297Ssam 26810297Ssam case '\\': 26910297Ssam sb++; goto S2; /* slurp next character */ 27010297Ssam 27110297Ssam case '"': 27210297Ssam sb++; goto S3; /* slurp quoted string */ 27310297Ssam 27410297Ssam default: 27510297Ssam *ap++ = *sb++; /* add character to token */ 27610297Ssam got_one = 1; 27710297Ssam goto S1; 27810297Ssam } 27910297Ssam 28010297Ssam S2: 28110297Ssam switch (*sb) { 28210297Ssam 28310297Ssam case '\0': 28410297Ssam goto OUT; 28510297Ssam 28610297Ssam default: 28710297Ssam *ap++ = *sb++; 28810297Ssam got_one = 1; 28910297Ssam goto S1; 29010297Ssam } 29110297Ssam 29210297Ssam S3: 29310297Ssam switch (*sb) { 29410297Ssam 29510297Ssam case '\0': 29610297Ssam goto OUT; 29710297Ssam 29810297Ssam case '"': 29910297Ssam sb++; goto S1; 30010297Ssam 30110297Ssam default: 30210297Ssam *ap++ = *sb++; 30310297Ssam got_one = 1; 30410297Ssam goto S3; 30510297Ssam } 30610297Ssam 30710297Ssam OUT: 30810297Ssam if (got_one) 30910297Ssam *ap++ = '\0'; 31010297Ssam argbase = ap; /* update storage pointer */ 31110297Ssam stringbase = sb; /* update scan pointer */ 31210297Ssam if (got_one) 31310297Ssam return(tmp); 31410297Ssam return((char *)0); 31510297Ssam } 31610297Ssam 31710297Ssam #define HELPINDENT (sizeof ("directory")) 31810297Ssam 31910297Ssam /* 32010297Ssam * Help command. 32110297Ssam * Call each command handler with argc == 0 and argv[0] == name. 32210297Ssam */ 32310297Ssam help(argc, argv) 32410297Ssam int argc; 32510297Ssam char *argv[]; 32610297Ssam { 32710297Ssam register struct cmd *c; 32810297Ssam 32910297Ssam if (argc == 1) { 33010297Ssam register int i, j, w; 33110297Ssam int columns, width = 0, lines; 33210297Ssam extern int NCMDS; 33310297Ssam 33410297Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 33510297Ssam for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 33610297Ssam int len = strlen(c->c_name); 33710297Ssam 33810297Ssam if (len > width) 33910297Ssam width = len; 34010297Ssam } 34110297Ssam width = (width + 8) &~ 7; 34210297Ssam columns = 80 / width; 34310297Ssam if (columns == 0) 34410297Ssam columns = 1; 34510297Ssam lines = (NCMDS + columns - 1) / columns; 34610297Ssam for (i = 0; i < lines; i++) { 34710297Ssam for (j = 0; j < columns; j++) { 34810297Ssam c = cmdtab + j * lines + i; 34910297Ssam printf("%s", c->c_name); 35010297Ssam if (c + lines >= &cmdtab[NCMDS]) { 35110297Ssam printf("\n"); 35210297Ssam break; 35310297Ssam } 35410297Ssam w = strlen(c->c_name); 35510297Ssam while (w < width) { 35610297Ssam w = (w + 8) &~ 7; 35710297Ssam putchar('\t'); 35810297Ssam } 35910297Ssam } 36010297Ssam } 36110297Ssam return; 36210297Ssam } 36310297Ssam while (--argc > 0) { 36410297Ssam register char *arg; 36510297Ssam arg = *++argv; 36610297Ssam c = getcmd(arg); 36710297Ssam if (c == (struct cmd *)-1) 36810297Ssam printf("?Ambiguous help command %s\n", arg); 36910297Ssam else if (c == (struct cmd *)0) 37010297Ssam printf("?Invalid help command %s\n", arg); 37110297Ssam else 37210297Ssam printf("%-*s\t%s\n", HELPINDENT, 37310297Ssam c->c_name, c->c_help); 37410297Ssam } 37510297Ssam } 37610297Ssam 37710297Ssam /* 37810297Ssam * Call routine with argc, argv set from args (terminated by 0). 37910297Ssam */ 38010297Ssam /* VARARGS2 */ 38110297Ssam call(routine, args) 38210297Ssam int (*routine)(); 38310297Ssam int args; 38410297Ssam { 38510297Ssam register int *argp; 38610297Ssam register int argc; 38710297Ssam 38810297Ssam for (argc = 0, argp = &args; *argp++ != 0; argc++) 38910297Ssam ; 39010297Ssam (*routine)(argc, &args); 39110297Ssam } 392