|
|
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.