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