110297Ssam #ifndef lint 2*16735Sralph static char sccsid[] = "@(#)main.c 4.10 (Berkeley) 07/19/84"; 310297Ssam #endif 410297Ssam 510297Ssam /* 610297Ssam * FTP User Program -- Command Interface. 710297Ssam */ 811352Ssam #include <sys/param.h> 910297Ssam #include <sys/socket.h> 1010297Ssam #include <sys/ioctl.h> 1110297Ssam 1212398Ssam #include <arpa/ftp.h> 1312398Ssam 1410297Ssam #include <signal.h> 1510297Ssam #include <stdio.h> 1610297Ssam #include <errno.h> 1710297Ssam #include <ctype.h> 1810297Ssam #include <netdb.h> 1911352Ssam #include <pwd.h> 2010297Ssam 2110297Ssam #include "ftp_var.h" 2210297Ssam 2310297Ssam int intr(); 2410297Ssam int lostpeer(); 2511352Ssam extern char *home; 2610297Ssam 2710297Ssam main(argc, argv) 2810297Ssam char *argv[]; 2910297Ssam { 3010297Ssam register char *cp; 3110297Ssam int top; 3211352Ssam struct passwd *pw; 3311352Ssam char homedir[MAXPATHLEN]; 3410297Ssam 3510297Ssam sp = getservbyname("ftp", "tcp"); 3610297Ssam if (sp == 0) { 3710297Ssam fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 3810297Ssam exit(1); 3910297Ssam } 4011351Ssam doglob = 1; 4111654Ssam interactive = 1; 4211351Ssam autologin = 1; 4310297Ssam argc--, argv++; 4410297Ssam while (argc > 0 && **argv == '-') { 4510297Ssam for (cp = *argv + 1; *cp; cp++) 4610297Ssam switch (*cp) { 4710297Ssam 4810297Ssam case 'd': 4910297Ssam options |= SO_DEBUG; 5010297Ssam debug++; 5110297Ssam break; 5210297Ssam 5310297Ssam case 'v': 5410297Ssam verbose++; 5510297Ssam break; 5610297Ssam 5710297Ssam case 't': 5810297Ssam trace++; 5910297Ssam break; 6010297Ssam 6110297Ssam case 'i': 6211654Ssam interactive = 0; 6310297Ssam break; 6410297Ssam 6510297Ssam case 'n': 6610297Ssam autologin = 0; 6710297Ssam break; 6810297Ssam 6911351Ssam case 'g': 7011351Ssam doglob = 0; 7111351Ssam break; 7211351Ssam 7310297Ssam default: 7410297Ssam fprintf(stderr, 7510297Ssam "ftp: %c: unknown option\n", *cp); 7610297Ssam exit(1); 7710297Ssam } 7810297Ssam argc--, argv++; 7910297Ssam } 8010297Ssam fromatty = isatty(fileno(stdin)); 8110297Ssam /* 8210297Ssam * Set up defaults for FTP. 8310297Ssam */ 8410297Ssam strcpy(typename, "ascii"), type = TYPE_A; 8510297Ssam strcpy(formname, "non-print"), form = FORM_N; 8610297Ssam strcpy(modename, "stream"), mode = MODE_S; 8710297Ssam strcpy(structname, "file"), stru = STRU_F; 8811227Ssam strcpy(bytename, "8"), bytesize = 8; 8910297Ssam if (fromatty) 9010297Ssam verbose++; 9111352Ssam /* 9211352Ssam * Set up the home directory in case we're globbing. 9311352Ssam */ 9411352Ssam pw = getpwnam(getlogin()); 9511352Ssam if (pw == NULL) 9611352Ssam pw = getpwuid(getuid()); 9711352Ssam if (pw != NULL) { 9811352Ssam home = homedir; 9911352Ssam strcpy(home, pw->pw_dir); 10011352Ssam } 10110297Ssam if (argc > 0) { 10210297Ssam if (setjmp(toplevel)) 10310297Ssam exit(0); 10412993Ssam signal(SIGINT, intr); 10512993Ssam signal(SIGPIPE, lostpeer); 10610297Ssam setpeer(argc + 1, argv - 1); 10710297Ssam } 10810297Ssam top = setjmp(toplevel) == 0; 10910297Ssam if (top) { 11012993Ssam signal(SIGINT, intr); 11112993Ssam signal(SIGPIPE, lostpeer); 11210297Ssam } 11310297Ssam for (;;) { 11410297Ssam cmdscanner(top); 11510297Ssam top = 1; 11610297Ssam } 11710297Ssam } 11810297Ssam 11910297Ssam intr() 12010297Ssam { 12110297Ssam 12210297Ssam longjmp(toplevel, 1); 12310297Ssam } 12410297Ssam 12510297Ssam lostpeer() 12610297Ssam { 12710297Ssam extern FILE *cout; 12810297Ssam extern int data; 12910297Ssam 13010297Ssam if (connected) { 13110297Ssam if (cout != NULL) { 13211239Ssam shutdown(fileno(cout), 1+1); 13310297Ssam fclose(cout); 13410297Ssam cout = NULL; 13510297Ssam } 13610297Ssam if (data >= 0) { 13711239Ssam shutdown(data, 1+1); 13810297Ssam (void) close(data); 13910297Ssam data = -1; 14010297Ssam } 14110297Ssam connected = 0; 14210297Ssam } 14310297Ssam longjmp(toplevel, 1); 14410297Ssam } 14510297Ssam 14610297Ssam char * 14710297Ssam tail(filename) 14810297Ssam char *filename; 14910297Ssam { 15010297Ssam register char *s; 15110297Ssam 15210297Ssam while (*filename) { 15310297Ssam s = rindex(filename, '/'); 15410297Ssam if (s == NULL) 15510297Ssam break; 15610297Ssam if (s[1]) 15710297Ssam return (s + 1); 15810297Ssam *s = '\0'; 15910297Ssam } 16010297Ssam return (filename); 16110297Ssam } 16210297Ssam 16310297Ssam /* 16410297Ssam * Command parser. 16510297Ssam */ 16610297Ssam cmdscanner(top) 16710297Ssam int top; 16810297Ssam { 16910297Ssam register struct cmd *c; 17010297Ssam struct cmd *getcmd(); 17110297Ssam extern struct cmd cmdtab[]; 17210297Ssam extern int help(); 17310297Ssam 17410297Ssam if (!top) 17510297Ssam putchar('\n'); 17610297Ssam for (;;) { 17710297Ssam if (fromatty) { 17810297Ssam printf("ftp> "); 17910297Ssam fflush(stdout); 18010297Ssam } 18113968Ssam if (gets(line) == 0) { 18213968Ssam if (feof(stdin)) { 183*16735Sralph if (!fromatty) 184*16735Sralph quit(); 18513968Ssam clearerr(stdin); 18613968Ssam putchar('\n'); 18713968Ssam } 18810297Ssam break; 18913968Ssam } 19010297Ssam if (line[0] == 0) 19110297Ssam break; 19210297Ssam makeargv(); 19310297Ssam c = getcmd(margv[0]); 19410297Ssam if (c == (struct cmd *)-1) { 19510297Ssam printf("?Ambiguous command\n"); 19610297Ssam continue; 19710297Ssam } 19810297Ssam if (c == 0) { 19910297Ssam printf("?Invalid command\n"); 20010297Ssam continue; 20110297Ssam } 20211654Ssam if (c->c_conn && !connected) { 20311654Ssam printf ("Not connected.\n"); 20411654Ssam continue; 20511654Ssam } 20610297Ssam (*c->c_handler)(margc, margv); 20710297Ssam if (bell && c->c_bell) 20810297Ssam putchar(CTRL(g)); 20910297Ssam if (c->c_handler != help) 21010297Ssam break; 21110297Ssam } 21210297Ssam longjmp(toplevel, 0); 21310297Ssam } 21410297Ssam 21510297Ssam struct cmd * 21610297Ssam getcmd(name) 21710297Ssam register char *name; 21810297Ssam { 21910297Ssam register char *p, *q; 22010297Ssam register struct cmd *c, *found; 22110297Ssam register int nmatches, longest; 22210297Ssam 22310297Ssam longest = 0; 22410297Ssam nmatches = 0; 22510297Ssam found = 0; 22610297Ssam for (c = cmdtab; p = c->c_name; c++) { 22710297Ssam for (q = name; *q == *p++; q++) 22810297Ssam if (*q == 0) /* exact match? */ 22910297Ssam return (c); 23010297Ssam if (!*q) { /* the name was a prefix */ 23110297Ssam if (q - name > longest) { 23210297Ssam longest = q - name; 23310297Ssam nmatches = 1; 23410297Ssam found = c; 23510297Ssam } else if (q - name == longest) 23610297Ssam nmatches++; 23710297Ssam } 23810297Ssam } 23910297Ssam if (nmatches > 1) 24010297Ssam return ((struct cmd *)-1); 24110297Ssam return (found); 24210297Ssam } 24310297Ssam 24410297Ssam /* 24510297Ssam * Slice a string up into argc/argv. 24610297Ssam */ 24710297Ssam makeargv() 24810297Ssam { 24910297Ssam char **argp; 25010297Ssam char *slurpstring(); 25110297Ssam 25210297Ssam margc = 0; 25310297Ssam argp = margv; 25410297Ssam stringbase = line; /* scan from first of buffer */ 25510297Ssam argbase = argbuf; /* store from first of buffer */ 25610297Ssam while (*argp++ = slurpstring()) 25710297Ssam margc++; 25810297Ssam } 25910297Ssam 26010297Ssam /* 26110297Ssam * Parse string into argbuf; 26210297Ssam * implemented with FSM to 26310297Ssam * handle quoting and strings 26410297Ssam */ 26510297Ssam char * 26610297Ssam slurpstring() 26710297Ssam { 26810297Ssam int got_one = 0; 26910297Ssam register char *sb = stringbase; 27010297Ssam register char *ap = argbase; 27110297Ssam char *tmp = argbase; /* will return this if token found */ 27210297Ssam 27311654Ssam if (*sb == '!') { /* recognize ! as a token for shell */ 27411654Ssam stringbase++; 27511654Ssam return ("!"); 27611654Ssam } 27710297Ssam S0: 27810297Ssam switch (*sb) { 27910297Ssam 28010297Ssam case '\0': 28110297Ssam goto OUT; 28210297Ssam 28310297Ssam case ' ': 28410297Ssam case '\t': 28510297Ssam sb++; goto S0; 28610297Ssam 28710297Ssam default: 28810297Ssam goto S1; 28910297Ssam } 29010297Ssam 29110297Ssam S1: 29210297Ssam switch (*sb) { 29310297Ssam 29410297Ssam case ' ': 29510297Ssam case '\t': 29610297Ssam case '\0': 29710297Ssam goto OUT; /* end of token */ 29810297Ssam 29910297Ssam case '\\': 30010297Ssam sb++; goto S2; /* slurp next character */ 30110297Ssam 30210297Ssam case '"': 30310297Ssam sb++; goto S3; /* slurp quoted string */ 30410297Ssam 30510297Ssam default: 30610297Ssam *ap++ = *sb++; /* add character to token */ 30710297Ssam got_one = 1; 30810297Ssam goto S1; 30910297Ssam } 31010297Ssam 31110297Ssam S2: 31210297Ssam switch (*sb) { 31310297Ssam 31410297Ssam case '\0': 31510297Ssam goto OUT; 31610297Ssam 31710297Ssam default: 31810297Ssam *ap++ = *sb++; 31910297Ssam got_one = 1; 32010297Ssam goto S1; 32110297Ssam } 32210297Ssam 32310297Ssam S3: 32410297Ssam switch (*sb) { 32510297Ssam 32610297Ssam case '\0': 32710297Ssam goto OUT; 32810297Ssam 32910297Ssam case '"': 33010297Ssam sb++; goto S1; 33110297Ssam 33210297Ssam default: 33310297Ssam *ap++ = *sb++; 33410297Ssam got_one = 1; 33510297Ssam goto S3; 33610297Ssam } 33710297Ssam 33810297Ssam OUT: 33910297Ssam if (got_one) 34010297Ssam *ap++ = '\0'; 34110297Ssam argbase = ap; /* update storage pointer */ 34210297Ssam stringbase = sb; /* update scan pointer */ 34310297Ssam if (got_one) 34410297Ssam return(tmp); 34510297Ssam return((char *)0); 34610297Ssam } 34710297Ssam 34810297Ssam #define HELPINDENT (sizeof ("directory")) 34910297Ssam 35010297Ssam /* 35110297Ssam * Help command. 35210297Ssam * Call each command handler with argc == 0 and argv[0] == name. 35310297Ssam */ 35410297Ssam help(argc, argv) 35510297Ssam int argc; 35610297Ssam char *argv[]; 35710297Ssam { 35810297Ssam register struct cmd *c; 35910297Ssam 36010297Ssam if (argc == 1) { 36110297Ssam register int i, j, w; 36210297Ssam int columns, width = 0, lines; 36310297Ssam extern int NCMDS; 36410297Ssam 36510297Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 36610297Ssam for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 36710297Ssam int len = strlen(c->c_name); 36810297Ssam 36910297Ssam if (len > width) 37010297Ssam width = len; 37110297Ssam } 37210297Ssam width = (width + 8) &~ 7; 37310297Ssam columns = 80 / width; 37410297Ssam if (columns == 0) 37510297Ssam columns = 1; 37610297Ssam lines = (NCMDS + columns - 1) / columns; 37710297Ssam for (i = 0; i < lines; i++) { 37810297Ssam for (j = 0; j < columns; j++) { 37910297Ssam c = cmdtab + j * lines + i; 38010297Ssam printf("%s", c->c_name); 38110297Ssam if (c + lines >= &cmdtab[NCMDS]) { 38210297Ssam printf("\n"); 38310297Ssam break; 38410297Ssam } 38510297Ssam w = strlen(c->c_name); 38610297Ssam while (w < width) { 38710297Ssam w = (w + 8) &~ 7; 38810297Ssam putchar('\t'); 38910297Ssam } 39010297Ssam } 39110297Ssam } 39210297Ssam return; 39310297Ssam } 39410297Ssam while (--argc > 0) { 39510297Ssam register char *arg; 39610297Ssam arg = *++argv; 39710297Ssam c = getcmd(arg); 39810297Ssam if (c == (struct cmd *)-1) 39910297Ssam printf("?Ambiguous help command %s\n", arg); 40010297Ssam else if (c == (struct cmd *)0) 40110297Ssam printf("?Invalid help command %s\n", arg); 40210297Ssam else 40310297Ssam printf("%-*s\t%s\n", HELPINDENT, 40410297Ssam c->c_name, c->c_help); 40510297Ssam } 40610297Ssam } 40710297Ssam 40810297Ssam /* 40910297Ssam * Call routine with argc, argv set from args (terminated by 0). 41010297Ssam */ 41110297Ssam /* VARARGS2 */ 41210297Ssam call(routine, args) 41310297Ssam int (*routine)(); 41410297Ssam int args; 41510297Ssam { 41610297Ssam register int *argp; 41710297Ssam register int argc; 41810297Ssam 41910297Ssam for (argc = 0, argp = &args; *argp++ != 0; argc++) 42010297Ssam ; 42110297Ssam (*routine)(argc, &args); 42210297Ssam } 423