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.6 (Berkeley) 10/09/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 (ch) { 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 passivemode = 0; /* passive mode not active */ 96 crflag = 1; /* strip c.r. on ascii gets */ 97 sendport = -1; /* not using ports */ 98 /* 99 * Set up the home directory in case we're globbing. 100 */ 101 cp = getlogin(); 102 if (cp != NULL) { 103 pw = getpwnam(cp); 104 } 105 if (pw == NULL) 106 pw = getpwuid(getuid()); 107 if (pw != NULL) { 108 home = homedir; 109 (void) strcpy(home, pw->pw_dir); 110 } 111 if (argc > 0) { 112 char *xargv[5]; 113 extern char *__progname; 114 115 if (setjmp(toplevel)) 116 exit(0); 117 (void) signal(SIGINT, intr); 118 (void) signal(SIGPIPE, lostpeer); 119 xargv[0] = __progname; 120 xargv[1] = argv[0]; 121 xargv[2] = argv[1]; 122 xargv[3] = argv[2]; 123 xargv[4] = NULL; 124 setpeer(argc+1, xargv); 125 } 126 top = setjmp(toplevel) == 0; 127 if (top) { 128 (void) signal(SIGINT, intr); 129 (void) signal(SIGPIPE, lostpeer); 130 } 131 for (;;) { 132 cmdscanner(top); 133 top = 1; 134 } 135 } 136 137 void 138 intr() 139 { 140 141 longjmp(toplevel, 1); 142 } 143 144 void 145 lostpeer() 146 { 147 148 if (connected) { 149 if (cout != NULL) { 150 (void) shutdown(fileno(cout), 1+1); 151 (void) fclose(cout); 152 cout = NULL; 153 } 154 if (data >= 0) { 155 (void) shutdown(data, 1+1); 156 (void) close(data); 157 data = -1; 158 } 159 connected = 0; 160 } 161 pswitch(1); 162 if (connected) { 163 if (cout != NULL) { 164 (void) shutdown(fileno(cout), 1+1); 165 (void) fclose(cout); 166 cout = NULL; 167 } 168 connected = 0; 169 } 170 proxflag = 0; 171 pswitch(0); 172 } 173 174 /* 175 char * 176 tail(filename) 177 char *filename; 178 { 179 char *s; 180 181 while (*filename) { 182 s = strrchr(filename, '/'); 183 if (s == NULL) 184 break; 185 if (s[1]) 186 return (s + 1); 187 *s = '\0'; 188 } 189 return (filename); 190 } 191 */ 192 193 /* 194 * Command parser. 195 */ 196 void 197 cmdscanner(top) 198 int top; 199 { 200 struct cmd *c; 201 int l; 202 203 if (!top) 204 (void) putchar('\n'); 205 for (;;) { 206 if (fromatty) { 207 printf("ftp> "); 208 (void) fflush(stdout); 209 } 210 if (fgets(line, sizeof line, stdin) == NULL) 211 quit(0, 0); 212 l = strlen(line); 213 if (l == 0) 214 break; 215 if (line[--l] == '\n') { 216 if (l == 0) 217 break; 218 line[l] = '\0'; 219 } else if (l == sizeof(line) - 2) { 220 printf("sorry, input line too long\n"); 221 while ((l = getchar()) != '\n' && l != EOF) 222 /* void */; 223 break; 224 } /* else it was a line without a newline */ 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 char *name; 255 { 256 char *p, *q; 257 struct cmd *c, *found; 258 int nmatches, longest; 259 260 longest = 0; 261 nmatches = 0; 262 found = 0; 263 for (c = cmdtab; p = c->c_name; c++) { 264 for (q = name; *q == *p++; q++) 265 if (*q == 0) /* exact match? */ 266 return (c); 267 if (!*q) { /* the name was a prefix */ 268 if (q - name > longest) { 269 longest = q - name; 270 nmatches = 1; 271 found = c; 272 } else if (q - name == longest) 273 nmatches++; 274 } 275 } 276 if (nmatches > 1) 277 return ((struct cmd *)-1); 278 return (found); 279 } 280 281 /* 282 * Slice a string up into argc/argv. 283 */ 284 285 int slrflag; 286 287 void 288 makeargv() 289 { 290 char **argp; 291 292 margc = 0; 293 argp = margv; 294 stringbase = line; /* scan from first of buffer */ 295 argbase = argbuf; /* store from first of buffer */ 296 slrflag = 0; 297 while (*argp++ = slurpstring()) 298 margc++; 299 } 300 301 /* 302 * Parse string into argbuf; 303 * implemented with FSM to 304 * handle quoting and strings 305 */ 306 char * 307 slurpstring() 308 { 309 int got_one = 0; 310 char *sb = stringbase; 311 char *ap = argbase; 312 char *tmp = argbase; /* will return this if token found */ 313 314 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 315 switch (slrflag) { /* and $ as token for macro invoke */ 316 case 0: 317 slrflag++; 318 stringbase++; 319 return ((*sb == '!') ? "!" : "$"); 320 /* NOTREACHED */ 321 case 1: 322 slrflag++; 323 altarg = stringbase; 324 break; 325 default: 326 break; 327 } 328 } 329 330 S0: 331 switch (*sb) { 332 333 case '\0': 334 goto OUT; 335 336 case ' ': 337 case '\t': 338 sb++; goto S0; 339 340 default: 341 switch (slrflag) { 342 case 0: 343 slrflag++; 344 break; 345 case 1: 346 slrflag++; 347 altarg = sb; 348 break; 349 default: 350 break; 351 } 352 goto S1; 353 } 354 355 S1: 356 switch (*sb) { 357 358 case ' ': 359 case '\t': 360 case '\0': 361 goto OUT; /* end of token */ 362 363 case '\\': 364 sb++; goto S2; /* slurp next character */ 365 366 case '"': 367 sb++; goto S3; /* slurp quoted string */ 368 369 default: 370 *ap++ = *sb++; /* add character to token */ 371 got_one = 1; 372 goto S1; 373 } 374 375 S2: 376 switch (*sb) { 377 378 case '\0': 379 goto OUT; 380 381 default: 382 *ap++ = *sb++; 383 got_one = 1; 384 goto S1; 385 } 386 387 S3: 388 switch (*sb) { 389 390 case '\0': 391 goto OUT; 392 393 case '"': 394 sb++; goto S1; 395 396 default: 397 *ap++ = *sb++; 398 got_one = 1; 399 goto S3; 400 } 401 402 OUT: 403 if (got_one) 404 *ap++ = '\0'; 405 argbase = ap; /* update storage pointer */ 406 stringbase = sb; /* update scan pointer */ 407 if (got_one) { 408 return (tmp); 409 } 410 switch (slrflag) { 411 case 0: 412 slrflag++; 413 break; 414 case 1: 415 slrflag++; 416 altarg = (char *) 0; 417 break; 418 default: 419 break; 420 } 421 return ((char *)0); 422 } 423 424 #define HELPINDENT ((int) sizeof ("directory")) 425 426 /* 427 * Help command. 428 * Call each command handler with argc == 0 and argv[0] == name. 429 */ 430 void 431 help(argc, argv) 432 int argc; 433 char *argv[]; 434 { 435 struct cmd *c; 436 437 if (argc == 1) { 438 int i, j, w, k; 439 int columns, width = 0, lines; 440 441 printf("Commands may be abbreviated. Commands are:\n\n"); 442 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 443 int len = strlen(c->c_name); 444 445 if (len > width) 446 width = len; 447 } 448 width = (width + 8) &~ 7; 449 columns = 80 / width; 450 if (columns == 0) 451 columns = 1; 452 lines = (NCMDS + columns - 1) / columns; 453 for (i = 0; i < lines; i++) { 454 for (j = 0; j < columns; j++) { 455 c = cmdtab + j * lines + i; 456 if (c->c_name && (!proxy || c->c_proxy)) { 457 printf("%s", c->c_name); 458 } 459 else if (c->c_name) { 460 for (k=0; k < strlen(c->c_name); k++) { 461 (void) putchar(' '); 462 } 463 } 464 if (c + lines >= &cmdtab[NCMDS]) { 465 printf("\n"); 466 break; 467 } 468 w = strlen(c->c_name); 469 while (w < width) { 470 w = (w + 8) &~ 7; 471 (void) putchar('\t'); 472 } 473 } 474 } 475 return; 476 } 477 while (--argc > 0) { 478 char *arg; 479 arg = *++argv; 480 c = getcmd(arg); 481 if (c == (struct cmd *)-1) 482 printf("?Ambiguous help command %s\n", arg); 483 else if (c == (struct cmd *)0) 484 printf("?Invalid help command %s\n", arg); 485 else 486 printf("%-*s\t%s\n", HELPINDENT, 487 c->c_name, c->c_help); 488 } 489 } 490