1 /* 2 * Copyright (c) 1985, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)cmds.c 5.29 (Berkeley) 07/06/92"; 10 #endif /* not lint */ 11 12 /* 13 * FTP User Program -- Command Routines. 14 */ 15 #include <sys/param.h> 16 #include <sys/wait.h> 17 #include <sys/stat.h> 18 #include <sys/socket.h> 19 20 #include <arpa/ftp.h> 21 22 #include <signal.h> 23 #include <stdio.h> 24 #include <errno.h> 25 #include <netdb.h> 26 #include <ctype.h> 27 #include <time.h> 28 #include <netinet/in.h> 29 30 #include "ftp_var.h" 31 #include "pathnames.h" 32 33 extern char *globerr; 34 extern char **ftpglob(); 35 extern char *home; 36 extern char *remglob(); 37 extern char *getenv(); 38 extern char *index(); 39 extern char *rindex(); 40 extern char *strerror(); 41 extern int errno; 42 extern off_t restart_point; 43 extern char reply_string[]; 44 45 char *mname; 46 jmp_buf jabort; 47 char *dotrans(), *domap(); 48 49 /* 50 * `Another' gets another argument, and stores the new argc and argv. 51 * It reverts to the top level (via main.c's intr()) on EOF/error. 52 * 53 * Returns false if no new arguments have been added. 54 */ 55 another(pargc, pargv, prompt) 56 int *pargc; 57 char ***pargv; 58 char *prompt; 59 { 60 int len = strlen(line), ret; 61 extern sig_t intr(); 62 63 if (len >= sizeof(line) - 3) { 64 printf("sorry, arguments too long\n"); 65 intr(); 66 } 67 printf("(%s) ", prompt); 68 line[len++] = ' '; 69 if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) 70 intr(); 71 len += strlen(&line[len]); 72 if (len > 0 && line[len - 1] == '\n') 73 line[len - 1] = '\0'; 74 makeargv(); 75 ret = margc > *pargc; 76 *pargc = margc; 77 *pargv = margv; 78 return (ret); 79 } 80 81 /* 82 * Connect to peer server and 83 * auto-login, if possible. 84 */ 85 setpeer(argc, argv) 86 int argc; 87 char *argv[]; 88 { 89 char *host, *hookup(); 90 short port; 91 92 if (connected) { 93 printf("Already connected to %s, use close first.\n", 94 hostname); 95 code = -1; 96 return; 97 } 98 if (argc < 2) 99 (void) another(&argc, &argv, "to"); 100 if (argc < 2 || argc > 3) { 101 printf("usage: %s host-name [port]\n", argv[0]); 102 code = -1; 103 return; 104 } 105 port = sp->s_port; 106 if (argc > 2) { 107 port = atoi(argv[2]); 108 if (port <= 0) { 109 printf("%s: bad port number-- %s\n", argv[1], argv[2]); 110 printf ("usage: %s host-name [port]\n", argv[0]); 111 code = -1; 112 return; 113 } 114 port = htons(port); 115 } 116 host = hookup(argv[1], port); 117 if (host) { 118 int overbose; 119 120 connected = 1; 121 /* 122 * Set up defaults for FTP. 123 */ 124 (void) strcpy(typename, "ascii"), type = TYPE_A; 125 curtype = TYPE_A; 126 (void) strcpy(formname, "non-print"), form = FORM_N; 127 (void) strcpy(modename, "stream"), mode = MODE_S; 128 (void) strcpy(structname, "file"), stru = STRU_F; 129 (void) strcpy(bytename, "8"), bytesize = 8; 130 if (autologin) 131 (void) login(argv[1]); 132 133 #if defined(unix) && NBBY == 8 134 /* 135 * this ifdef is to keep someone form "porting" this to an incompatible 136 * system and not checking this out. This way they have to think about it. 137 */ 138 overbose = verbose; 139 if (debug == 0) 140 verbose = -1; 141 if (command("SYST") == COMPLETE && overbose) { 142 register char *cp, c; 143 cp = index(reply_string+4, ' '); 144 if (cp == NULL) 145 cp = index(reply_string+4, '\r'); 146 if (cp) { 147 if (cp[-1] == '.') 148 cp--; 149 c = *cp; 150 *cp = '\0'; 151 } 152 153 printf("Remote system type is %s.\n", 154 reply_string+4); 155 if (cp) 156 *cp = c; 157 } 158 if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { 159 if (proxy) 160 unix_proxy = 1; 161 else 162 unix_server = 1; 163 /* 164 * Set type to 0 (not specified by user), 165 * meaning binary by default, but don't bother 166 * telling server. We can use binary 167 * for text files unless changed by the user. 168 */ 169 type = 0; 170 (void) strcpy(typename, "binary"); 171 if (overbose) 172 printf("Using %s mode to transfer files.\n", 173 typename); 174 } else { 175 if (proxy) 176 unix_proxy = 0; 177 else 178 unix_server = 0; 179 if (overbose && 180 !strncmp(reply_string, "215 TOPS20", 10)) 181 printf( 182 "Remember to set tenex mode when transfering binary files from this machine.\n"); 183 } 184 verbose = overbose; 185 #endif /* unix */ 186 } 187 } 188 189 struct types { 190 char *t_name; 191 char *t_mode; 192 int t_type; 193 char *t_arg; 194 } types[] = { 195 { "ascii", "A", TYPE_A, 0 }, 196 { "binary", "I", TYPE_I, 0 }, 197 { "image", "I", TYPE_I, 0 }, 198 { "ebcdic", "E", TYPE_E, 0 }, 199 { "tenex", "L", TYPE_L, bytename }, 200 0 201 }; 202 203 /* 204 * Set transfer type. 205 */ 206 settype(argc, argv) 207 int argc; 208 char *argv[]; 209 { 210 register struct types *p; 211 int comret; 212 213 if (argc > 2) { 214 char *sep; 215 216 printf("usage: %s [", argv[0]); 217 sep = " "; 218 for (p = types; p->t_name; p++) { 219 printf("%s%s", sep, p->t_name); 220 sep = " | "; 221 } 222 printf(" ]\n"); 223 code = -1; 224 return; 225 } 226 if (argc < 2) { 227 printf("Using %s mode to transfer files.\n", typename); 228 code = 0; 229 return; 230 } 231 for (p = types; p->t_name; p++) 232 if (strcmp(argv[1], p->t_name) == 0) 233 break; 234 if (p->t_name == 0) { 235 printf("%s: unknown mode\n", argv[1]); 236 code = -1; 237 return; 238 } 239 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 240 comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 241 else 242 comret = command("TYPE %s", p->t_mode); 243 if (comret == COMPLETE) { 244 (void) strcpy(typename, p->t_name); 245 curtype = type = p->t_type; 246 } 247 } 248 249 /* 250 * Internal form of settype; changes current type in use with server 251 * without changing our notion of the type for data transfers. 252 * Used to change to and from ascii for listings. 253 */ 254 changetype(newtype, show) 255 int newtype, show; 256 { 257 register struct types *p; 258 int comret, oldverbose = verbose; 259 260 if (newtype == 0) 261 newtype = TYPE_I; 262 if (newtype == curtype) 263 return; 264 if (debug == 0 && show == 0) 265 verbose = 0; 266 for (p = types; p->t_name; p++) 267 if (newtype == p->t_type) 268 break; 269 if (p->t_name == 0) { 270 printf("ftp: internal error: unknown type %d\n", newtype); 271 return; 272 } 273 if (newtype == TYPE_L && bytename[0] != '\0') 274 comret = command("TYPE %s %s", p->t_mode, bytename); 275 else 276 comret = command("TYPE %s", p->t_mode); 277 if (comret == COMPLETE) 278 curtype = newtype; 279 verbose = oldverbose; 280 } 281 282 char *stype[] = { 283 "type", 284 "", 285 0 286 }; 287 288 /* 289 * Set binary transfer type. 290 */ 291 /*VARARGS*/ 292 setbinary() 293 { 294 stype[1] = "binary"; 295 settype(2, stype); 296 } 297 298 /* 299 * Set ascii transfer type. 300 */ 301 /*VARARGS*/ 302 setascii() 303 { 304 stype[1] = "ascii"; 305 settype(2, stype); 306 } 307 308 /* 309 * Set tenex transfer type. 310 */ 311 /*VARARGS*/ 312 settenex() 313 { 314 stype[1] = "tenex"; 315 settype(2, stype); 316 } 317 318 /* 319 * Set file transfer mode. 320 */ 321 /*ARGSUSED*/ 322 setmode(argc, argv) 323 int argc; 324 char *argv[]; 325 { 326 327 printf("We only support %s mode, sorry.\n", modename); 328 code = -1; 329 } 330 331 /* 332 * Set file transfer format. 333 */ 334 /*ARGSUSED*/ 335 setform(argc, argv) 336 int argc; 337 char *argv[]; 338 { 339 340 printf("We only support %s format, sorry.\n", formname); 341 code = -1; 342 } 343 344 /* 345 * Set file transfer structure. 346 */ 347 /*ARGSUSED*/ 348 setstruct(argc, argv) 349 int argc; 350 char *argv[]; 351 { 352 353 printf("We only support %s structure, sorry.\n", structname); 354 code = -1; 355 } 356 357 /* 358 * Send a single file. 359 */ 360 put(argc, argv) 361 int argc; 362 char *argv[]; 363 { 364 char *cmd; 365 int loc = 0; 366 char *oldargv1, *oldargv2; 367 368 if (argc == 2) { 369 argc++; 370 argv[2] = argv[1]; 371 loc++; 372 } 373 if (argc < 2 && !another(&argc, &argv, "local-file")) 374 goto usage; 375 if (argc < 3 && !another(&argc, &argv, "remote-file")) { 376 usage: 377 printf("usage: %s local-file remote-file\n", argv[0]); 378 code = -1; 379 return; 380 } 381 oldargv1 = argv[1]; 382 oldargv2 = argv[2]; 383 if (!globulize(&argv[1])) { 384 code = -1; 385 return; 386 } 387 /* 388 * If "globulize" modifies argv[1], and argv[2] is a copy of 389 * the old argv[1], make it a copy of the new argv[1]. 390 */ 391 if (argv[1] != oldargv1 && argv[2] == oldargv1) { 392 argv[2] = argv[1]; 393 } 394 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 395 if (loc && ntflag) { 396 argv[2] = dotrans(argv[2]); 397 } 398 if (loc && mapflag) { 399 argv[2] = domap(argv[2]); 400 } 401 sendrequest(cmd, argv[1], argv[2], 402 argv[1] != oldargv1 || argv[2] != oldargv2); 403 } 404 405 /* 406 * Send multiple files. 407 */ 408 mput(argc, argv) 409 int argc; 410 char **argv; 411 { 412 extern jmp_buf jabort; 413 register int i; 414 sig_t oldintr; 415 int ointer; 416 char *tp; 417 void mabort(); 418 419 if (argc < 2 && !another(&argc, &argv, "local-files")) { 420 printf("usage: %s local-files\n", argv[0]); 421 code = -1; 422 return; 423 } 424 mname = argv[0]; 425 mflag = 1; 426 oldintr = signal(SIGINT, mabort); 427 (void) setjmp(jabort); 428 if (proxy) { 429 char *cp, *tp2, tmpbuf[MAXPATHLEN]; 430 431 while ((cp = remglob(argv,0)) != NULL) { 432 if (*cp == 0) { 433 mflag = 0; 434 continue; 435 } 436 if (mflag && confirm(argv[0], cp)) { 437 tp = cp; 438 if (mcase) { 439 while (*tp && !islower(*tp)) { 440 tp++; 441 } 442 if (!*tp) { 443 tp = cp; 444 tp2 = tmpbuf; 445 while ((*tp2 = *tp) != NULL) { 446 if (isupper(*tp2)) { 447 *tp2 = 'a' + *tp2 - 'A'; 448 } 449 tp++; 450 tp2++; 451 } 452 } 453 tp = tmpbuf; 454 } 455 if (ntflag) { 456 tp = dotrans(tp); 457 } 458 if (mapflag) { 459 tp = domap(tp); 460 } 461 sendrequest((sunique) ? "STOU" : "STOR", 462 cp, tp, cp != tp || !interactive); 463 if (!mflag && fromatty) { 464 ointer = interactive; 465 interactive = 1; 466 if (confirm("Continue with","mput")) { 467 mflag++; 468 } 469 interactive = ointer; 470 } 471 } 472 } 473 (void) signal(SIGINT, oldintr); 474 mflag = 0; 475 return; 476 } 477 for (i = 1; i < argc; i++) { 478 register char **cpp, **gargs; 479 480 if (!doglob) { 481 if (mflag && confirm(argv[0], argv[i])) { 482 tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 483 tp = (mapflag) ? domap(tp) : tp; 484 sendrequest((sunique) ? "STOU" : "STOR", 485 argv[i], tp, tp != argv[i] || !interactive); 486 if (!mflag && fromatty) { 487 ointer = interactive; 488 interactive = 1; 489 if (confirm("Continue with","mput")) { 490 mflag++; 491 } 492 interactive = ointer; 493 } 494 } 495 continue; 496 } 497 gargs = ftpglob(argv[i]); 498 if (globerr != NULL) { 499 printf("%s\n", globerr); 500 if (gargs) { 501 blkfree(gargs); 502 free((char *)gargs); 503 } 504 continue; 505 } 506 for (cpp = gargs; cpp && *cpp != NULL; cpp++) { 507 if (mflag && confirm(argv[0], *cpp)) { 508 tp = (ntflag) ? dotrans(*cpp) : *cpp; 509 tp = (mapflag) ? domap(tp) : tp; 510 sendrequest((sunique) ? "STOU" : "STOR", 511 *cpp, tp, *cpp != tp || !interactive); 512 if (!mflag && fromatty) { 513 ointer = interactive; 514 interactive = 1; 515 if (confirm("Continue with","mput")) { 516 mflag++; 517 } 518 interactive = ointer; 519 } 520 } 521 } 522 if (gargs != NULL) { 523 blkfree(gargs); 524 free((char *)gargs); 525 } 526 } 527 (void) signal(SIGINT, oldintr); 528 mflag = 0; 529 } 530 531 reget(argc, argv) 532 int argc; 533 char *argv[]; 534 { 535 (void) getit(argc, argv, 1, "r+w"); 536 } 537 538 get(argc, argv) 539 int argc; 540 char *argv[]; 541 { 542 (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" ); 543 } 544 545 /* 546 * Receive one file. 547 */ 548 getit(argc, argv, restartit, mode) 549 int argc; 550 char *argv[]; 551 char *mode; 552 { 553 int loc = 0; 554 char *oldargv1, *oldargv2; 555 556 if (argc == 2) { 557 argc++; 558 argv[2] = argv[1]; 559 loc++; 560 } 561 if (argc < 2 && !another(&argc, &argv, "remote-file")) 562 goto usage; 563 if (argc < 3 && !another(&argc, &argv, "local-file")) { 564 usage: 565 printf("usage: %s remote-file [ local-file ]\n", argv[0]); 566 code = -1; 567 return (0); 568 } 569 oldargv1 = argv[1]; 570 oldargv2 = argv[2]; 571 if (!globulize(&argv[2])) { 572 code = -1; 573 return (0); 574 } 575 if (loc && mcase) { 576 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; 577 578 while (*tp && !islower(*tp)) { 579 tp++; 580 } 581 if (!*tp) { 582 tp = argv[2]; 583 tp2 = tmpbuf; 584 while ((*tp2 = *tp) != NULL) { 585 if (isupper(*tp2)) { 586 *tp2 = 'a' + *tp2 - 'A'; 587 } 588 tp++; 589 tp2++; 590 } 591 argv[2] = tmpbuf; 592 } 593 } 594 if (loc && ntflag) 595 argv[2] = dotrans(argv[2]); 596 if (loc && mapflag) 597 argv[2] = domap(argv[2]); 598 if (restartit) { 599 struct stat stbuf; 600 int ret; 601 602 ret = stat(argv[2], &stbuf); 603 if (restartit == 1) { 604 if (ret < 0) { 605 fprintf(stderr, "local: %s: %s\n", argv[2], 606 strerror(errno)); 607 return (0); 608 } 609 restart_point = stbuf.st_size; 610 } else { 611 if (ret == 0) { 612 int overbose; 613 614 overbose = verbose; 615 if (debug == 0) 616 verbose = -1; 617 if (command("MDTM %s", argv[1]) == COMPLETE) { 618 int yy, mo, day, hour, min, sec; 619 struct tm *tm; 620 verbose = overbose; 621 sscanf(reply_string, 622 "%*s %04d%02d%02d%02d%02d%02d", 623 &yy, &mo, &day, &hour, &min, &sec); 624 tm = gmtime(&stbuf.st_mtime); 625 tm->tm_mon++; 626 if (tm->tm_year > yy%100) 627 return (1); 628 if ((tm->tm_year == yy%100 && 629 tm->tm_mon > mo) || 630 (tm->tm_mon == mo && 631 tm->tm_mday > day) || 632 (tm->tm_mday == day && 633 tm->tm_hour > hour) || 634 (tm->tm_hour == hour && 635 tm->tm_min > min) || 636 (tm->tm_min == min && 637 tm->tm_sec > sec)) 638 return (1); 639 } else { 640 printf("%s\n", reply_string); 641 verbose = overbose; 642 return (0); 643 } 644 } 645 } 646 } 647 648 recvrequest("RETR", argv[2], argv[1], mode, 649 argv[1] != oldargv1 || argv[2] != oldargv2); 650 restart_point = 0; 651 return (0); 652 } 653 654 void 655 mabort() 656 { 657 int ointer; 658 extern jmp_buf jabort; 659 660 printf("\n"); 661 (void) fflush(stdout); 662 if (mflag && fromatty) { 663 ointer = interactive; 664 interactive = 1; 665 if (confirm("Continue with", mname)) { 666 interactive = ointer; 667 longjmp(jabort,0); 668 } 669 interactive = ointer; 670 } 671 mflag = 0; 672 longjmp(jabort,0); 673 } 674 675 /* 676 * Get multiple files. 677 */ 678 mget(argc, argv) 679 int argc; 680 char **argv; 681 { 682 extern jmp_buf jabort; 683 sig_t oldintr; 684 int ch, ointer; 685 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; 686 void mabort(); 687 688 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 689 printf("usage: %s remote-files\n", argv[0]); 690 code = -1; 691 return; 692 } 693 mname = argv[0]; 694 mflag = 1; 695 oldintr = signal(SIGINT,mabort); 696 (void) setjmp(jabort); 697 while ((cp = remglob(argv,proxy)) != NULL) { 698 if (*cp == '\0') { 699 mflag = 0; 700 continue; 701 } 702 if (mflag && confirm(argv[0], cp)) { 703 tp = cp; 704 if (mcase) { 705 for (tp2 = tmpbuf; ch = *tp++;) 706 *tp2++ = isupper(ch) ? tolower(ch) : ch; 707 tp = tmpbuf; 708 } 709 if (ntflag) { 710 tp = dotrans(tp); 711 } 712 if (mapflag) { 713 tp = domap(tp); 714 } 715 recvrequest("RETR", tp, cp, "w", 716 tp != cp || !interactive); 717 if (!mflag && fromatty) { 718 ointer = interactive; 719 interactive = 1; 720 if (confirm("Continue with","mget")) { 721 mflag++; 722 } 723 interactive = ointer; 724 } 725 } 726 } 727 (void) signal(SIGINT,oldintr); 728 mflag = 0; 729 } 730 731 char * 732 remglob(argv,doswitch) 733 char *argv[]; 734 int doswitch; 735 { 736 char temp[16]; 737 static char buf[MAXPATHLEN]; 738 static FILE *ftemp = NULL; 739 static char **args; 740 int oldverbose, oldhash; 741 char *cp, *mode; 742 743 if (!mflag) { 744 if (!doglob) { 745 args = NULL; 746 } 747 else { 748 if (ftemp) { 749 (void) fclose(ftemp); 750 ftemp = NULL; 751 } 752 } 753 return(NULL); 754 } 755 if (!doglob) { 756 if (args == NULL) 757 args = argv; 758 if ((cp = *++args) == NULL) 759 args = NULL; 760 return (cp); 761 } 762 if (ftemp == NULL) { 763 (void) strcpy(temp, _PATH_TMP); 764 (void) mktemp(temp); 765 oldverbose = verbose, verbose = 0; 766 oldhash = hash, hash = 0; 767 if (doswitch) { 768 pswitch(!proxy); 769 } 770 for (mode = "w"; *++argv != NULL; mode = "a") 771 recvrequest ("NLST", temp, *argv, mode, 0); 772 if (doswitch) { 773 pswitch(!proxy); 774 } 775 verbose = oldverbose; hash = oldhash; 776 ftemp = fopen(temp, "r"); 777 (void) unlink(temp); 778 if (ftemp == NULL) { 779 printf("can't find list of remote files, oops\n"); 780 return (NULL); 781 } 782 } 783 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 784 (void) fclose(ftemp), ftemp = NULL; 785 return (NULL); 786 } 787 if ((cp = index(buf, '\n')) != NULL) 788 *cp = '\0'; 789 return (buf); 790 } 791 792 char * 793 onoff(bool) 794 int bool; 795 { 796 797 return (bool ? "on" : "off"); 798 } 799 800 /* 801 * Show status. 802 */ 803 /*ARGSUSED*/ 804 status(argc, argv) 805 int argc; 806 char *argv[]; 807 { 808 int i; 809 810 if (connected) 811 printf("Connected to %s.\n", hostname); 812 else 813 printf("Not connected.\n"); 814 if (!proxy) { 815 pswitch(1); 816 if (connected) { 817 printf("Connected for proxy commands to %s.\n", hostname); 818 } 819 else { 820 printf("No proxy connection.\n"); 821 } 822 pswitch(0); 823 } 824 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 825 modename, typename, formname, structname); 826 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 827 onoff(verbose), onoff(bell), onoff(interactive), 828 onoff(doglob)); 829 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 830 onoff(runique)); 831 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); 832 if (ntflag) { 833 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); 834 } 835 else { 836 printf("Ntrans: off\n"); 837 } 838 if (mapflag) { 839 printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 840 } 841 else { 842 printf("Nmap: off\n"); 843 } 844 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 845 onoff(hash), onoff(sendport)); 846 if (macnum > 0) { 847 printf("Macros:\n"); 848 for (i=0; i<macnum; i++) { 849 printf("\t%s\n",macros[i].mac_name); 850 } 851 } 852 code = 0; 853 } 854 855 /* 856 * Set beep on cmd completed mode. 857 */ 858 /*VARARGS*/ 859 setbell() 860 { 861 862 bell = !bell; 863 printf("Bell mode %s.\n", onoff(bell)); 864 code = bell; 865 } 866 867 /* 868 * Turn on packet tracing. 869 */ 870 /*VARARGS*/ 871 settrace() 872 { 873 874 trace = !trace; 875 printf("Packet tracing %s.\n", onoff(trace)); 876 code = trace; 877 } 878 879 /* 880 * Toggle hash mark printing during transfers. 881 */ 882 /*VARARGS*/ 883 sethash() 884 { 885 886 hash = !hash; 887 printf("Hash mark printing %s", onoff(hash)); 888 code = hash; 889 if (hash) 890 printf(" (%d bytes/hash mark)", 1024); 891 printf(".\n"); 892 } 893 894 /* 895 * Turn on printing of server echo's. 896 */ 897 /*VARARGS*/ 898 setverbose() 899 { 900 901 verbose = !verbose; 902 printf("Verbose mode %s.\n", onoff(verbose)); 903 code = verbose; 904 } 905 906 /* 907 * Toggle PORT cmd use before each data connection. 908 */ 909 /*VARARGS*/ 910 setport() 911 { 912 913 sendport = !sendport; 914 printf("Use of PORT cmds %s.\n", onoff(sendport)); 915 code = sendport; 916 } 917 918 /* 919 * Turn on interactive prompting 920 * during mget, mput, and mdelete. 921 */ 922 /*VARARGS*/ 923 setprompt() 924 { 925 926 interactive = !interactive; 927 printf("Interactive mode %s.\n", onoff(interactive)); 928 code = interactive; 929 } 930 931 /* 932 * Toggle metacharacter interpretation 933 * on local file names. 934 */ 935 /*VARARGS*/ 936 setglob() 937 { 938 939 doglob = !doglob; 940 printf("Globbing %s.\n", onoff(doglob)); 941 code = doglob; 942 } 943 944 /* 945 * Set debugging mode on/off and/or 946 * set level of debugging. 947 */ 948 /*VARARGS*/ 949 setdebug(argc, argv) 950 int argc; 951 char *argv[]; 952 { 953 int val; 954 955 if (argc > 1) { 956 val = atoi(argv[1]); 957 if (val < 0) { 958 printf("%s: bad debugging value.\n", argv[1]); 959 code = -1; 960 return; 961 } 962 } else 963 val = !debug; 964 debug = val; 965 if (debug) 966 options |= SO_DEBUG; 967 else 968 options &= ~SO_DEBUG; 969 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 970 code = debug > 0; 971 } 972 973 /* 974 * Set current working directory 975 * on remote machine. 976 */ 977 cd(argc, argv) 978 int argc; 979 char *argv[]; 980 { 981 982 if (argc < 2 && !another(&argc, &argv, "remote-directory")) { 983 printf("usage: %s remote-directory\n", argv[0]); 984 code = -1; 985 return; 986 } 987 if (command("CWD %s", argv[1]) == ERROR && code == 500) { 988 if (verbose) 989 printf("CWD command not recognized, trying XCWD\n"); 990 (void) command("XCWD %s", argv[1]); 991 } 992 } 993 994 /* 995 * Set current working directory 996 * on local machine. 997 */ 998 lcd(argc, argv) 999 int argc; 1000 char *argv[]; 1001 { 1002 char buf[MAXPATHLEN]; 1003 extern char *getwd(); 1004 1005 if (argc < 2) 1006 argc++, argv[1] = home; 1007 if (argc != 2) { 1008 printf("usage: %s local-directory\n", argv[0]); 1009 code = -1; 1010 return; 1011 } 1012 if (!globulize(&argv[1])) { 1013 code = -1; 1014 return; 1015 } 1016 if (chdir(argv[1]) < 0) { 1017 fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno)); 1018 code = -1; 1019 return; 1020 } 1021 printf("Local directory now %s\n", getwd(buf)); 1022 code = 0; 1023 } 1024 1025 /* 1026 * Delete a single file. 1027 */ 1028 delete(argc, argv) 1029 int argc; 1030 char *argv[]; 1031 { 1032 1033 if (argc < 2 && !another(&argc, &argv, "remote-file")) { 1034 printf("usage: %s remote-file\n", argv[0]); 1035 code = -1; 1036 return; 1037 } 1038 (void) command("DELE %s", argv[1]); 1039 } 1040 1041 /* 1042 * Delete multiple files. 1043 */ 1044 mdelete(argc, argv) 1045 int argc; 1046 char **argv; 1047 { 1048 extern jmp_buf jabort; 1049 sig_t oldintr; 1050 int ointer; 1051 char *cp; 1052 void mabort(); 1053 1054 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 1055 printf("usage: %s remote-files\n", argv[0]); 1056 code = -1; 1057 return; 1058 } 1059 mname = argv[0]; 1060 mflag = 1; 1061 oldintr = signal(SIGINT, mabort); 1062 (void) setjmp(jabort); 1063 while ((cp = remglob(argv,0)) != NULL) { 1064 if (*cp == '\0') { 1065 mflag = 0; 1066 continue; 1067 } 1068 if (mflag && confirm(argv[0], cp)) { 1069 (void) command("DELE %s", cp); 1070 if (!mflag && fromatty) { 1071 ointer = interactive; 1072 interactive = 1; 1073 if (confirm("Continue with", "mdelete")) { 1074 mflag++; 1075 } 1076 interactive = ointer; 1077 } 1078 } 1079 } 1080 (void) signal(SIGINT, oldintr); 1081 mflag = 0; 1082 } 1083 1084 /* 1085 * Rename a remote file. 1086 */ 1087 renamefile(argc, argv) 1088 int argc; 1089 char *argv[]; 1090 { 1091 1092 if (argc < 2 && !another(&argc, &argv, "from-name")) 1093 goto usage; 1094 if (argc < 3 && !another(&argc, &argv, "to-name")) { 1095 usage: 1096 printf("%s from-name to-name\n", argv[0]); 1097 code = -1; 1098 return; 1099 } 1100 if (command("RNFR %s", argv[1]) == CONTINUE) 1101 (void) command("RNTO %s", argv[2]); 1102 } 1103 1104 /* 1105 * Get a directory listing 1106 * of remote files. 1107 */ 1108 ls(argc, argv) 1109 int argc; 1110 char *argv[]; 1111 { 1112 char *cmd; 1113 1114 if (argc < 2) 1115 argc++, argv[1] = NULL; 1116 if (argc < 3) 1117 argc++, argv[2] = "-"; 1118 if (argc > 3) { 1119 printf("usage: %s remote-directory local-file\n", argv[0]); 1120 code = -1; 1121 return; 1122 } 1123 cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; 1124 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1125 code = -1; 1126 return; 1127 } 1128 if (strcmp(argv[2], "-") && *argv[2] != '|') 1129 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { 1130 code = -1; 1131 return; 1132 } 1133 recvrequest(cmd, argv[2], argv[1], "w", 0); 1134 } 1135 1136 /* 1137 * Get a directory listing 1138 * of multiple remote files. 1139 */ 1140 mls(argc, argv) 1141 int argc; 1142 char **argv; 1143 { 1144 extern jmp_buf jabort; 1145 sig_t oldintr; 1146 int ointer, i; 1147 char *cmd, mode[1], *dest; 1148 void mabort(); 1149 1150 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1151 goto usage; 1152 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1153 usage: 1154 printf("usage: %s remote-files local-file\n", argv[0]); 1155 code = -1; 1156 return; 1157 } 1158 dest = argv[argc - 1]; 1159 argv[argc - 1] = NULL; 1160 if (strcmp(dest, "-") && *dest != '|') 1161 if (!globulize(&dest) || 1162 !confirm("output to local-file:", dest)) { 1163 code = -1; 1164 return; 1165 } 1166 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 1167 mname = argv[0]; 1168 mflag = 1; 1169 oldintr = signal(SIGINT, mabort); 1170 (void) setjmp(jabort); 1171 for (i = 1; mflag && i < argc-1; ++i) { 1172 *mode = (i == 1) ? 'w' : 'a'; 1173 recvrequest(cmd, dest, argv[i], mode, 0); 1174 if (!mflag && fromatty) { 1175 ointer = interactive; 1176 interactive = 1; 1177 if (confirm("Continue with", argv[0])) { 1178 mflag ++; 1179 } 1180 interactive = ointer; 1181 } 1182 } 1183 (void) signal(SIGINT, oldintr); 1184 mflag = 0; 1185 } 1186 1187 /* 1188 * Do a shell escape 1189 */ 1190 /*ARGSUSED*/ 1191 shell(argc, argv) 1192 int argc; 1193 char **argv; 1194 { 1195 int pid; 1196 sig_t old1, old2; 1197 char shellnam[40], *shell, *namep; 1198 union wait status; 1199 1200 old1 = signal (SIGINT, SIG_IGN); 1201 old2 = signal (SIGQUIT, SIG_IGN); 1202 if ((pid = fork()) == 0) { 1203 for (pid = 3; pid < 20; pid++) 1204 (void) close(pid); 1205 (void) signal(SIGINT, SIG_DFL); 1206 (void) signal(SIGQUIT, SIG_DFL); 1207 shell = getenv("SHELL"); 1208 if (shell == NULL) 1209 shell = _PATH_BSHELL; 1210 namep = rindex(shell,'/'); 1211 if (namep == NULL) 1212 namep = shell; 1213 (void) strcpy(shellnam,"-"); 1214 (void) strcat(shellnam, ++namep); 1215 if (strcmp(namep, "sh") != 0) 1216 shellnam[0] = '+'; 1217 if (debug) { 1218 printf ("%s\n", shell); 1219 (void) fflush (stdout); 1220 } 1221 if (argc > 1) { 1222 execl(shell,shellnam,"-c",altarg,(char *)0); 1223 } 1224 else { 1225 execl(shell,shellnam,(char *)0); 1226 } 1227 perror(shell); 1228 code = -1; 1229 exit(1); 1230 } 1231 if (pid > 0) 1232 while (wait((int *)&status) != pid) 1233 ; 1234 (void) signal(SIGINT, old1); 1235 (void) signal(SIGQUIT, old2); 1236 if (pid == -1) { 1237 perror("Try again later"); 1238 code = -1; 1239 } 1240 else { 1241 code = 0; 1242 } 1243 return (0); 1244 } 1245 1246 /* 1247 * Send new user information (re-login) 1248 */ 1249 user(argc, argv) 1250 int argc; 1251 char **argv; 1252 { 1253 char acct[80], *getpass(); 1254 int n, aflag = 0; 1255 1256 if (argc < 2) 1257 (void) another(&argc, &argv, "username"); 1258 if (argc < 2 || argc > 4) { 1259 printf("usage: %s username [password] [account]\n", argv[0]); 1260 code = -1; 1261 return (0); 1262 } 1263 n = command("USER %s", argv[1]); 1264 if (n == CONTINUE) { 1265 if (argc < 3 ) 1266 argv[2] = getpass("Password: "), argc++; 1267 n = command("PASS %s", argv[2]); 1268 } 1269 if (n == CONTINUE) { 1270 if (argc < 4) { 1271 printf("Account: "); (void) fflush(stdout); 1272 (void) fgets(acct, sizeof(acct) - 1, stdin); 1273 acct[strlen(acct) - 1] = '\0'; 1274 argv[3] = acct; argc++; 1275 } 1276 n = command("ACCT %s", argv[3]); 1277 aflag++; 1278 } 1279 if (n != COMPLETE) { 1280 fprintf(stdout, "Login failed.\n"); 1281 return (0); 1282 } 1283 if (!aflag && argc == 4) { 1284 (void) command("ACCT %s", argv[3]); 1285 } 1286 return (1); 1287 } 1288 1289 /* 1290 * Print working directory. 1291 */ 1292 /*VARARGS*/ 1293 pwd() 1294 { 1295 int oldverbose = verbose; 1296 1297 /* 1298 * If we aren't verbose, this doesn't do anything! 1299 */ 1300 verbose = 1; 1301 if (command("PWD") == ERROR && code == 500) { 1302 printf("PWD command not recognized, trying XPWD\n"); 1303 (void) command("XPWD"); 1304 } 1305 verbose = oldverbose; 1306 } 1307 1308 /* 1309 * Make a directory. 1310 */ 1311 makedir(argc, argv) 1312 int argc; 1313 char *argv[]; 1314 { 1315 1316 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1317 printf("usage: %s directory-name\n", argv[0]); 1318 code = -1; 1319 return; 1320 } 1321 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1322 if (verbose) 1323 printf("MKD command not recognized, trying XMKD\n"); 1324 (void) command("XMKD %s", argv[1]); 1325 } 1326 } 1327 1328 /* 1329 * Remove a directory. 1330 */ 1331 removedir(argc, argv) 1332 int argc; 1333 char *argv[]; 1334 { 1335 1336 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1337 printf("usage: %s directory-name\n", argv[0]); 1338 code = -1; 1339 return; 1340 } 1341 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1342 if (verbose) 1343 printf("RMD command not recognized, trying XRMD\n"); 1344 (void) command("XRMD %s", argv[1]); 1345 } 1346 } 1347 1348 /* 1349 * Send a line, verbatim, to the remote machine. 1350 */ 1351 quote(argc, argv) 1352 int argc; 1353 char *argv[]; 1354 { 1355 1356 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1357 printf("usage: %s line-to-send\n", argv[0]); 1358 code = -1; 1359 return; 1360 } 1361 quote1("", argc, argv); 1362 } 1363 1364 /* 1365 * Send a SITE command to the remote machine. The line 1366 * is sent verbatim to the remote machine, except that the 1367 * word "SITE" is added at the front. 1368 */ 1369 site(argc, argv) 1370 int argc; 1371 char *argv[]; 1372 { 1373 1374 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1375 printf("usage: %s line-to-send\n", argv[0]); 1376 code = -1; 1377 return; 1378 } 1379 quote1("SITE ", argc, argv); 1380 } 1381 1382 /* 1383 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1384 * Send the result as a one-line command and get response. 1385 */ 1386 quote1(initial, argc, argv) 1387 char *initial; 1388 int argc; 1389 char **argv; 1390 { 1391 register int i, len; 1392 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1393 1394 (void) strcpy(buf, initial); 1395 if (argc > 1) { 1396 len = strlen(buf); 1397 len += strlen(strcpy(&buf[len], argv[1])); 1398 for (i = 2; i < argc; i++) { 1399 buf[len++] = ' '; 1400 len += strlen(strcpy(&buf[len], argv[i])); 1401 } 1402 } 1403 if (command(buf) == PRELIM) { 1404 while (getreply(0) == PRELIM); 1405 } 1406 } 1407 1408 do_chmod(argc, argv) 1409 int argc; 1410 char *argv[]; 1411 { 1412 1413 if (argc < 2 && !another(&argc, &argv, "mode")) 1414 goto usage; 1415 if (argc < 3 && !another(&argc, &argv, "file-name")) { 1416 usage: 1417 printf("usage: %s mode file-name\n", argv[0]); 1418 code = -1; 1419 return; 1420 } 1421 (void) command("SITE CHMOD %s %s", argv[1], argv[2]); 1422 } 1423 1424 do_umask(argc, argv) 1425 int argc; 1426 char *argv[]; 1427 { 1428 int oldverbose = verbose; 1429 1430 verbose = 1; 1431 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1432 verbose = oldverbose; 1433 } 1434 1435 idle(argc, argv) 1436 int argc; 1437 char *argv[]; 1438 { 1439 int oldverbose = verbose; 1440 1441 verbose = 1; 1442 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1443 verbose = oldverbose; 1444 } 1445 1446 /* 1447 * Ask the other side for help. 1448 */ 1449 rmthelp(argc, argv) 1450 int argc; 1451 char *argv[]; 1452 { 1453 int oldverbose = verbose; 1454 1455 verbose = 1; 1456 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1457 verbose = oldverbose; 1458 } 1459 1460 /* 1461 * Terminate session and exit. 1462 */ 1463 /*VARARGS*/ 1464 quit() 1465 { 1466 1467 if (connected) 1468 disconnect(); 1469 pswitch(1); 1470 if (connected) { 1471 disconnect(); 1472 } 1473 exit(0); 1474 } 1475 1476 /* 1477 * Terminate session, but don't exit. 1478 */ 1479 disconnect() 1480 { 1481 extern FILE *cout; 1482 extern int data; 1483 1484 if (!connected) 1485 return; 1486 (void) command("QUIT"); 1487 if (cout) { 1488 (void) fclose(cout); 1489 } 1490 cout = NULL; 1491 connected = 0; 1492 data = -1; 1493 if (!proxy) { 1494 macnum = 0; 1495 } 1496 } 1497 1498 confirm(cmd, file) 1499 char *cmd, *file; 1500 { 1501 char line[BUFSIZ]; 1502 1503 if (!interactive) 1504 return (1); 1505 printf("%s %s? ", cmd, file); 1506 (void) fflush(stdout); 1507 if (fgets(line, sizeof line, stdin) == NULL) 1508 return (0); 1509 return (*line != 'n' && *line != 'N'); 1510 } 1511 1512 fatal(msg) 1513 char *msg; 1514 { 1515 1516 fprintf(stderr, "ftp: %s\n", msg); 1517 exit(1); 1518 } 1519 1520 /* 1521 * Glob a local file name specification with 1522 * the expectation of a single return value. 1523 * Can't control multiple values being expanded 1524 * from the expression, we return only the first. 1525 */ 1526 globulize(cpp) 1527 char **cpp; 1528 { 1529 char **globbed; 1530 1531 if (!doglob) 1532 return (1); 1533 globbed = ftpglob(*cpp); 1534 if (globerr != NULL) { 1535 printf("%s: %s\n", *cpp, globerr); 1536 if (globbed) { 1537 blkfree(globbed); 1538 free((char *)globbed); 1539 } 1540 return (0); 1541 } 1542 if (globbed) { 1543 *cpp = *globbed++; 1544 /* don't waste too much memory */ 1545 if (*globbed) { 1546 blkfree(*globbed); 1547 free((char *)*globbed); 1548 } 1549 } 1550 return (1); 1551 } 1552 1553 account(argc,argv) 1554 int argc; 1555 char **argv; 1556 { 1557 char acct[50], *getpass(), *ap; 1558 1559 if (argc > 1) { 1560 ++argv; 1561 --argc; 1562 (void) strncpy(acct,*argv,49); 1563 acct[49] = '\0'; 1564 while (argc > 1) { 1565 --argc; 1566 ++argv; 1567 (void) strncat(acct,*argv, 49-strlen(acct)); 1568 } 1569 ap = acct; 1570 } 1571 else { 1572 ap = getpass("Account:"); 1573 } 1574 (void) command("ACCT %s", ap); 1575 } 1576 1577 jmp_buf abortprox; 1578 1579 void 1580 proxabort() 1581 { 1582 extern int proxy; 1583 1584 if (!proxy) { 1585 pswitch(1); 1586 } 1587 if (connected) { 1588 proxflag = 1; 1589 } 1590 else { 1591 proxflag = 0; 1592 } 1593 pswitch(0); 1594 longjmp(abortprox,1); 1595 } 1596 1597 doproxy(argc,argv) 1598 int argc; 1599 char *argv[]; 1600 { 1601 extern struct cmd cmdtab[]; 1602 extern jmp_buf abortprox; 1603 register struct cmd *c; 1604 struct cmd *getcmd(); 1605 sig_t oldintr; 1606 void proxabort(); 1607 1608 if (argc < 2 && !another(&argc, &argv, "command")) { 1609 printf("usage: %s command\n", argv[0]); 1610 code = -1; 1611 return; 1612 } 1613 c = getcmd(argv[1]); 1614 if (c == (struct cmd *) -1) { 1615 printf("?Ambiguous command\n"); 1616 (void) fflush(stdout); 1617 code = -1; 1618 return; 1619 } 1620 if (c == 0) { 1621 printf("?Invalid command\n"); 1622 (void) fflush(stdout); 1623 code = -1; 1624 return; 1625 } 1626 if (!c->c_proxy) { 1627 printf("?Invalid proxy command\n"); 1628 (void) fflush(stdout); 1629 code = -1; 1630 return; 1631 } 1632 if (setjmp(abortprox)) { 1633 code = -1; 1634 return; 1635 } 1636 oldintr = signal(SIGINT, proxabort); 1637 pswitch(1); 1638 if (c->c_conn && !connected) { 1639 printf("Not connected\n"); 1640 (void) fflush(stdout); 1641 pswitch(0); 1642 (void) signal(SIGINT, oldintr); 1643 code = -1; 1644 return; 1645 } 1646 (*c->c_handler)(argc-1, argv+1); 1647 if (connected) { 1648 proxflag = 1; 1649 } 1650 else { 1651 proxflag = 0; 1652 } 1653 pswitch(0); 1654 (void) signal(SIGINT, oldintr); 1655 } 1656 1657 setcase() 1658 { 1659 mcase = !mcase; 1660 printf("Case mapping %s.\n", onoff(mcase)); 1661 code = mcase; 1662 } 1663 1664 setcr() 1665 { 1666 crflag = !crflag; 1667 printf("Carriage Return stripping %s.\n", onoff(crflag)); 1668 code = crflag; 1669 } 1670 1671 setntrans(argc,argv) 1672 int argc; 1673 char *argv[]; 1674 { 1675 if (argc == 1) { 1676 ntflag = 0; 1677 printf("Ntrans off.\n"); 1678 code = ntflag; 1679 return; 1680 } 1681 ntflag++; 1682 code = ntflag; 1683 (void) strncpy(ntin, argv[1], 16); 1684 ntin[16] = '\0'; 1685 if (argc == 2) { 1686 ntout[0] = '\0'; 1687 return; 1688 } 1689 (void) strncpy(ntout, argv[2], 16); 1690 ntout[16] = '\0'; 1691 } 1692 1693 char * 1694 dotrans(name) 1695 char *name; 1696 { 1697 static char new[MAXPATHLEN]; 1698 char *cp1, *cp2 = new; 1699 register int i, ostop, found; 1700 1701 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); 1702 for (cp1 = name; *cp1; cp1++) { 1703 found = 0; 1704 for (i = 0; *(ntin + i) && i < 16; i++) { 1705 if (*cp1 == *(ntin + i)) { 1706 found++; 1707 if (i < ostop) { 1708 *cp2++ = *(ntout + i); 1709 } 1710 break; 1711 } 1712 } 1713 if (!found) { 1714 *cp2++ = *cp1; 1715 } 1716 } 1717 *cp2 = '\0'; 1718 return(new); 1719 } 1720 1721 setnmap(argc, argv) 1722 int argc; 1723 char *argv[]; 1724 { 1725 char *cp; 1726 1727 if (argc == 1) { 1728 mapflag = 0; 1729 printf("Nmap off.\n"); 1730 code = mapflag; 1731 return; 1732 } 1733 if (argc < 3 && !another(&argc, &argv, "mapout")) { 1734 printf("Usage: %s [mapin mapout]\n",argv[0]); 1735 code = -1; 1736 return; 1737 } 1738 mapflag = 1; 1739 code = 1; 1740 cp = index(altarg, ' '); 1741 if (proxy) { 1742 while(*++cp == ' '); 1743 altarg = cp; 1744 cp = index(altarg, ' '); 1745 } 1746 *cp = '\0'; 1747 (void) strncpy(mapin, altarg, MAXPATHLEN - 1); 1748 while (*++cp == ' '); 1749 (void) strncpy(mapout, cp, MAXPATHLEN - 1); 1750 } 1751 1752 char * 1753 domap(name) 1754 char *name; 1755 { 1756 static char new[MAXPATHLEN]; 1757 register char *cp1 = name, *cp2 = mapin; 1758 char *tp[9], *te[9]; 1759 int i, toks[9], toknum = 0, match = 1; 1760 1761 for (i=0; i < 9; ++i) { 1762 toks[i] = 0; 1763 } 1764 while (match && *cp1 && *cp2) { 1765 switch (*cp2) { 1766 case '\\': 1767 if (*++cp2 != *cp1) { 1768 match = 0; 1769 } 1770 break; 1771 case '$': 1772 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1773 if (*cp1 != *(++cp2+1)) { 1774 toks[toknum = *cp2 - '1']++; 1775 tp[toknum] = cp1; 1776 while (*++cp1 && *(cp2+1) 1777 != *cp1); 1778 te[toknum] = cp1; 1779 } 1780 cp2++; 1781 break; 1782 } 1783 /* FALLTHROUGH */ 1784 default: 1785 if (*cp2 != *cp1) { 1786 match = 0; 1787 } 1788 break; 1789 } 1790 if (match && *cp1) { 1791 cp1++; 1792 } 1793 if (match && *cp2) { 1794 cp2++; 1795 } 1796 } 1797 if (!match && *cp1) /* last token mismatch */ 1798 { 1799 toks[toknum] = 0; 1800 } 1801 cp1 = new; 1802 *cp1 = '\0'; 1803 cp2 = mapout; 1804 while (*cp2) { 1805 match = 0; 1806 switch (*cp2) { 1807 case '\\': 1808 if (*(cp2 + 1)) { 1809 *cp1++ = *++cp2; 1810 } 1811 break; 1812 case '[': 1813 LOOP: 1814 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1815 if (*++cp2 == '0') { 1816 char *cp3 = name; 1817 1818 while (*cp3) { 1819 *cp1++ = *cp3++; 1820 } 1821 match = 1; 1822 } 1823 else if (toks[toknum = *cp2 - '1']) { 1824 char *cp3 = tp[toknum]; 1825 1826 while (cp3 != te[toknum]) { 1827 *cp1++ = *cp3++; 1828 } 1829 match = 1; 1830 } 1831 } 1832 else { 1833 while (*cp2 && *cp2 != ',' && 1834 *cp2 != ']') { 1835 if (*cp2 == '\\') { 1836 cp2++; 1837 } 1838 else if (*cp2 == '$' && 1839 isdigit(*(cp2+1))) { 1840 if (*++cp2 == '0') { 1841 char *cp3 = name; 1842 1843 while (*cp3) { 1844 *cp1++ = *cp3++; 1845 } 1846 } 1847 else if (toks[toknum = 1848 *cp2 - '1']) { 1849 char *cp3=tp[toknum]; 1850 1851 while (cp3 != 1852 te[toknum]) { 1853 *cp1++ = *cp3++; 1854 } 1855 } 1856 } 1857 else if (*cp2) { 1858 *cp1++ = *cp2++; 1859 } 1860 } 1861 if (!*cp2) { 1862 printf("nmap: unbalanced brackets\n"); 1863 return(name); 1864 } 1865 match = 1; 1866 cp2--; 1867 } 1868 if (match) { 1869 while (*++cp2 && *cp2 != ']') { 1870 if (*cp2 == '\\' && *(cp2 + 1)) { 1871 cp2++; 1872 } 1873 } 1874 if (!*cp2) { 1875 printf("nmap: unbalanced brackets\n"); 1876 return(name); 1877 } 1878 break; 1879 } 1880 switch (*++cp2) { 1881 case ',': 1882 goto LOOP; 1883 case ']': 1884 break; 1885 default: 1886 cp2--; 1887 goto LOOP; 1888 } 1889 break; 1890 case '$': 1891 if (isdigit(*(cp2 + 1))) { 1892 if (*++cp2 == '0') { 1893 char *cp3 = name; 1894 1895 while (*cp3) { 1896 *cp1++ = *cp3++; 1897 } 1898 } 1899 else if (toks[toknum = *cp2 - '1']) { 1900 char *cp3 = tp[toknum]; 1901 1902 while (cp3 != te[toknum]) { 1903 *cp1++ = *cp3++; 1904 } 1905 } 1906 break; 1907 } 1908 /* intentional drop through */ 1909 default: 1910 *cp1++ = *cp2; 1911 break; 1912 } 1913 cp2++; 1914 } 1915 *cp1 = '\0'; 1916 if (!*new) { 1917 return(name); 1918 } 1919 return(new); 1920 } 1921 1922 setsunique() 1923 { 1924 sunique = !sunique; 1925 printf("Store unique %s.\n", onoff(sunique)); 1926 code = sunique; 1927 } 1928 1929 setrunique() 1930 { 1931 runique = !runique; 1932 printf("Receive unique %s.\n", onoff(runique)); 1933 code = runique; 1934 } 1935 1936 /* change directory to perent directory */ 1937 cdup() 1938 { 1939 if (command("CDUP") == ERROR && code == 500) { 1940 if (verbose) 1941 printf("CDUP command not recognized, trying XCUP\n"); 1942 (void) command("XCUP"); 1943 } 1944 } 1945 1946 /* restart transfer at specific point */ 1947 restart(argc, argv) 1948 int argc; 1949 char *argv[]; 1950 { 1951 extern long atol(); 1952 if (argc != 2) 1953 printf("restart: offset not specified\n"); 1954 else { 1955 restart_point = atol(argv[1]); 1956 printf("restarting at %ld. %s\n", restart_point, 1957 "execute get, put or append to initiate transfer"); 1958 } 1959 } 1960 1961 /* show remote system type */ 1962 syst() 1963 { 1964 (void) command("SYST"); 1965 } 1966 1967 macdef(argc, argv) 1968 int argc; 1969 char *argv[]; 1970 { 1971 char *tmp; 1972 int c; 1973 1974 if (macnum == 16) { 1975 printf("Limit of 16 macros have already been defined\n"); 1976 code = -1; 1977 return; 1978 } 1979 if (argc < 2 && !another(&argc, &argv, "macro name")) { 1980 printf("Usage: %s macro_name\n",argv[0]); 1981 code = -1; 1982 return; 1983 } 1984 if (interactive) { 1985 printf("Enter macro line by line, terminating it with a null line\n"); 1986 } 1987 (void) strncpy(macros[macnum].mac_name, argv[1], 8); 1988 if (macnum == 0) { 1989 macros[macnum].mac_start = macbuf; 1990 } 1991 else { 1992 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 1993 } 1994 tmp = macros[macnum].mac_start; 1995 while (tmp != macbuf+4096) { 1996 if ((c = getchar()) == EOF) { 1997 printf("macdef:end of file encountered\n"); 1998 code = -1; 1999 return; 2000 } 2001 if ((*tmp = c) == '\n') { 2002 if (tmp == macros[macnum].mac_start) { 2003 macros[macnum++].mac_end = tmp; 2004 code = 0; 2005 return; 2006 } 2007 if (*(tmp-1) == '\0') { 2008 macros[macnum++].mac_end = tmp - 1; 2009 code = 0; 2010 return; 2011 } 2012 *tmp = '\0'; 2013 } 2014 tmp++; 2015 } 2016 while (1) { 2017 while ((c = getchar()) != '\n' && c != EOF) 2018 /* LOOP */; 2019 if (c == EOF || getchar() == '\n') { 2020 printf("Macro not defined - 4k buffer exceeded\n"); 2021 code = -1; 2022 return; 2023 } 2024 } 2025 } 2026 2027 /* 2028 * get size of file on remote machine 2029 */ 2030 sizecmd(argc, argv) 2031 int argc; 2032 char *argv[]; 2033 { 2034 2035 if (argc < 2 && !another(&argc, &argv, "filename")) { 2036 printf("usage: %s filename\n", argv[0]); 2037 code = -1; 2038 return; 2039 } 2040 (void) command("SIZE %s", argv[1]); 2041 } 2042 2043 /* 2044 * get last modification time of file on remote machine 2045 */ 2046 modtime(argc, argv) 2047 int argc; 2048 char *argv[]; 2049 { 2050 int overbose; 2051 2052 if (argc < 2 && !another(&argc, &argv, "filename")) { 2053 printf("usage: %s filename\n", argv[0]); 2054 code = -1; 2055 return; 2056 } 2057 overbose = verbose; 2058 if (debug == 0) 2059 verbose = -1; 2060 if (command("MDTM %s", argv[1]) == COMPLETE) { 2061 int yy, mo, day, hour, min, sec; 2062 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, 2063 &day, &hour, &min, &sec); 2064 /* might want to print this in local time */ 2065 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], 2066 mo, day, yy, hour, min, sec); 2067 } else 2068 printf("%s\n", reply_string); 2069 verbose = overbose; 2070 } 2071 2072 /* 2073 * show status on reomte machine 2074 */ 2075 rmtstatus(argc, argv) 2076 int argc; 2077 char *argv[]; 2078 { 2079 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 2080 } 2081 2082 /* 2083 * get file if modtime is more recent than current file 2084 */ 2085 newer(argc, argv) 2086 int argc; 2087 char *argv[]; 2088 { 2089 if (getit(argc, argv, -1, "w")) 2090 printf("Local file \"%s\" is newer than remote file \"%s\"\n", 2091 argv[2], argv[1]); 2092 } 2093