1: /* 2: * Copyright (c) 1985, 1989 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that the above copyright notice and this paragraph are 7: * duplicated in all such forms and that any documentation, 8: * advertising materials, and other materials related to such 9: * distribution and use acknowledge that the software was developed 10: * by the University of California, Berkeley. The name of the 11: * University may not be used to endorse or promote products derived 12: * from this software without specific prior written permission. 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16: */ 17: 18: #if !defined(lint) && defined(DOSCCS) 19: char copyright[] = 20: "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\ 21: All rights reserved.\n"; 22: 23: static char sccsid[] = "@(#)main.c based on 5.13.1 (2.11BSD) 1997/10/2"; 24: #endif 25: 26: /* 27: * FTP User Program -- Command Interface. 28: */ 29: #include "ftp_var.h" 30: #include <sys/socket.h> 31: #include <sys/ioctl.h> 32: #include <sys/types.h> 33: 34: #include <arpa/ftp.h> 35: 36: #include <signal.h> 37: #include <stdio.h> 38: #include <errno.h> 39: #include <ctype.h> 40: #include <netdb.h> 41: #include <pwd.h> 42: #include <stdlib.h> 43: #include <unistd.h> 44: 45: int intr(); 46: int lostpeer(); 47: extern char *home; 48: 49: main(argc, argv) 50: char *argv[]; 51: { 52: register char *cp; 53: int top; 54: struct passwd *pw = NULL; 55: char homedir[MAXPATHLEN]; 56: 57: sp = getservbyname("ftp", "tcp"); 58: if (sp == 0) { 59: fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 60: exit(1); 61: } 62: doglob = 1; 63: interactive = 1; 64: autologin = 1; 65: argc--, argv++; 66: while (argc > 0 && **argv == '-') { 67: for (cp = *argv + 1; *cp; cp++) 68: switch (*cp) { 69: 70: case 'd': 71: options |= SO_DEBUG; 72: debug++; 73: break; 74: 75: case 'v': 76: verbose++; 77: break; 78: 79: case 't': 80: trace++; 81: break; 82: 83: case 'i': 84: interactive = 0; 85: break; 86: 87: case 'n': 88: autologin = 0; 89: break; 90: 91: case 'g': 92: doglob = 0; 93: break; 94: 95: default: 96: fprintf(stdout, 97: "ftp: %c: unknown option\n", *cp); 98: exit(1); 99: } 100: argc--, argv++; 101: } 102: fromatty = isatty(fileno(stdin)); 103: /* 104: * Set up defaults for FTP. 105: */ 106: (void) strcpy(typename, "ascii"), type = TYPE_A; 107: (void) strcpy(formname, "non-print"), form = FORM_N; 108: (void) strcpy(modename, "stream"), mode = MODE_S; 109: (void) strcpy(structname, "file"), stru = STRU_F; 110: (void) strcpy(bytename, "8"), bytesize = 8; 111: if (fromatty) 112: verbose++; 113: cpend = 0; /* no pending replies */ 114: proxy = 0; /* proxy not active */ 115: crflag = 1; /* strip c.r. on ascii gets */ 116: /* 117: * Set up the home directory in case we're globbing. 118: */ 119: cp = getlogin(); 120: if (cp != NULL) { 121: pw = getpwnam(cp); 122: } 123: if (pw == NULL) 124: pw = getpwuid(getuid()); 125: if (pw != NULL) { 126: home = homedir; 127: (void) strcpy(home, pw->pw_dir); 128: } 129: if (argc > 0) { 130: if (setjmp(toplevel)) 131: exit(0); 132: (void) signal(SIGINT, intr); 133: (void) signal(SIGPIPE, lostpeer); 134: setpeer(argc + 1, argv - 1); 135: } 136: top = setjmp(toplevel) == 0; 137: if (top) { 138: (void) signal(SIGINT, intr); 139: (void) signal(SIGPIPE, lostpeer); 140: } 141: for (;;) { 142: cmdscanner(top); 143: top = 1; 144: } 145: } 146: 147: intr() 148: { 149: 150: longjmp(toplevel, 1); 151: } 152: 153: lostpeer() 154: { 155: extern FILE *cout; 156: extern int data; 157: 158: if (connected) { 159: if (cout != NULL) { 160: (void) shutdown(fileno(cout), 1+1); 161: (void) fclose(cout); 162: cout = NULL; 163: } 164: if (data >= 0) { 165: (void) shutdown(data, 1+1); 166: (void) close(data); 167: data = -1; 168: } 169: connected = 0; 170: } 171: pswitch(1); 172: if (connected) { 173: if (cout != NULL) { 174: (void) shutdown(fileno(cout), 1+1); 175: (void) fclose(cout); 176: cout = NULL; 177: } 178: connected = 0; 179: } 180: proxflag = 0; 181: pswitch(0); 182: } 183: 184: /*char * 185: tail(filename) 186: char *filename; 187: { 188: register char *s; 189: 190: while (*filename) { 191: s = rindex(filename, '/'); 192: if (s == NULL) 193: break; 194: if (s[1]) 195: return (s + 1); 196: *s = '\0'; 197: } 198: return (filename); 199: } 200: */ 201: /* 202: * Command parser. 203: */ 204: cmdscanner(top) 205: int top; 206: { 207: register struct cmd *c; 208: struct cmd *getcmd(); 209: extern int help(); 210: 211: if (!top) 212: (void) putchar('\n'); 213: for (;;) { 214: if (fromatty) { 215: printf("ftp> "); 216: (void) fflush(stdout); 217: } 218: if (gets(line) == 0) { 219: if (feof(stdin) || ferror(stdin)) 220: quit(); 221: break; 222: } 223: if (line[0] == 0) 224: break; 225: makeargv(); 226: if (margc == 0) { 227: continue; 228: } 229: c = getcmd(margv[0]); 230: if (c == (struct cmd *)-1) { 231: printf("?Ambiguous command\n"); 232: continue; 233: } 234: if (c == 0) { 235: printf("?Invalid command\n"); 236: continue; 237: } 238: if (c->c_conn && !connected) { 239: printf ("Not connected.\n"); 240: continue; 241: } 242: (*c->c_handler)(margc, margv); 243: if (bell && c->c_bell) 244: (void) putchar('\007'); 245: if (c->c_handler != help) 246: break; 247: } 248: (void) signal(SIGINT, intr); 249: (void) signal(SIGPIPE, lostpeer); 250: } 251: 252: struct cmd * 253: getcmd(name) 254: register char *name; 255: { 256: extern struct cmd cmdtab[]; 257: register char *p, *q; 258: register struct cmd *c, *found; 259: register int nmatches, longest; 260: 261: longest = 0; 262: nmatches = 0; 263: found = 0; 264: for (c = cmdtab; p = c->c_name; c++) { 265: for (q = name; *q == *p++; q++) 266: if (*q == 0) /* exact match? */ 267: return (c); 268: if (!*q) { /* the name was a prefix */ 269: if (q - name > longest) { 270: longest = q - name; 271: nmatches = 1; 272: found = c; 273: } else if (q - name == longest) 274: nmatches++; 275: } 276: } 277: if (nmatches > 1) 278: return ((struct cmd *)-1); 279: return (found); 280: } 281: 282: /* 283: * Slice a string up into argc/argv. 284: */ 285: 286: int slrflag; 287: 288: makeargv() 289: { 290: char **argp; 291: char *slurpstring(); 292: 293: margc = 0; 294: argp = margv; 295: stringbase = line; /* scan from first of buffer */ 296: argbase = argbuf; /* store from first of buffer */ 297: slrflag = 0; 298: while (*argp++ = slurpstring()) 299: margc++; 300: } 301: 302: /* 303: * Parse string into argbuf; 304: * implemented with FSM to 305: * handle quoting and strings 306: */ 307: char * 308: slurpstring() 309: { 310: int got_one = 0; 311: register char *sb = stringbase; 312: register char *ap = argbase; 313: char *tmp = argbase; /* will return this if token found */ 314: 315: if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 316: switch (slrflag) { /* and $ as token for macro invoke */ 317: case 0: 318: slrflag++; 319: stringbase++; 320: return ((*sb == '!') ? "!" : "$"); 321: /* NOTREACHED */ 322: case 1: 323: slrflag++; 324: altarg = stringbase; 325: break; 326: default: 327: break; 328: } 329: } 330: 331: S0: 332: switch (*sb) { 333: 334: case '\0': 335: goto OUT; 336: 337: case ' ': 338: case '\t': 339: sb++; goto S0; 340: 341: default: 342: switch (slrflag) { 343: case 0: 344: slrflag++; 345: break; 346: case 1: 347: slrflag++; 348: altarg = sb; 349: break; 350: default: 351: break; 352: } 353: goto S1; 354: } 355: 356: S1: 357: switch (*sb) { 358: 359: case ' ': 360: case '\t': 361: case '\0': 362: goto OUT; /* end of token */ 363: 364: case '\\': 365: sb++; goto S2; /* slurp next character */ 366: 367: case '"': 368: sb++; goto S3; /* slurp quoted string */ 369: 370: default: 371: *ap++ = *sb++; /* add character to token */ 372: got_one = 1; 373: goto S1; 374: } 375: 376: S2: 377: switch (*sb) { 378: 379: case '\0': 380: goto OUT; 381: 382: default: 383: *ap++ = *sb++; 384: got_one = 1; 385: goto S1; 386: } 387: 388: S3: 389: switch (*sb) { 390: 391: case '\0': 392: goto OUT; 393: 394: case '"': 395: sb++; goto S1; 396: 397: default: 398: *ap++ = *sb++; 399: got_one = 1; 400: goto S3; 401: } 402: 403: OUT: 404: if (got_one) 405: *ap++ = '\0'; 406: argbase = ap; /* update storage pointer */ 407: stringbase = sb; /* update scan pointer */ 408: if (got_one) { 409: return(tmp); 410: } 411: switch (slrflag) { 412: case 0: 413: slrflag++; 414: break; 415: case 1: 416: slrflag++; 417: altarg = (char *) 0; 418: break; 419: default: 420: break; 421: } 422: return((char *)0); 423: } 424: 425: #define HELPINDENT (sizeof ("directory")) 426: 427: /* 428: * Help command. 429: * Call each command handler with argc == 0 and argv[0] == name. 430: */ 431: help(argc, argv) 432: int argc; 433: char *argv[]; 434: { 435: extern struct cmd cmdtab[]; 436: register struct cmd *c; 437: 438: if (argc == 1) { 439: register int i, j, w, k; 440: int columns, width = 0, lines; 441: extern int NCMDS; 442: 443: printf("Commands may be abbreviated. Commands are:\n\n"); 444: for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 445: int len = strlen(c->c_name); 446: 447: if (len > width) 448: width = len; 449: } 450: width = (width + 8) &~ 7; 451: columns = 80 / width; 452: if (columns == 0) 453: columns = 1; 454: lines = (NCMDS + columns - 1) / columns; 455: for (i = 0; i < lines; i++) { 456: for (j = 0; j < columns; j++) { 457: c = cmdtab + j * lines + i; 458: if (c->c_name && (!proxy || c->c_proxy)) { 459: printf("%s", c->c_name); 460: } 461: else if (c->c_name) { 462: for (k=0; k < strlen(c->c_name); k++) { 463: (void) putchar(' '); 464: } 465: } 466: if (c + lines >= &cmdtab[NCMDS]) { 467: printf("\n"); 468: break; 469: } 470: w = strlen(c->c_name); 471: while (w < width) { 472: w = (w + 8) &~ 7; 473: (void) putchar('\t'); 474: } 475: } 476: } 477: return; 478: } 479: while (--argc > 0) { 480: register char *arg; 481: arg = *++argv; 482: c = getcmd(arg); 483: if (c == (struct cmd *)-1) 484: printf("?Ambiguous help command %s\n", arg); 485: else if (c == (struct cmd *)0) 486: printf("?Invalid help command %s\n", arg); 487: else 488: printf("%-*s\t%s\n", HELPINDENT, 489: c->c_name, c->c_help); 490: } 491: }