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