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