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.26 (Berkeley) 03/05/91"; 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 else if (tm->tm_year == yy%100) { 629 if (tm->tm_mon > mo) 630 return (1); 631 } else if (tm->tm_mon == mo) { 632 if (tm->tm_mday > day) 633 return (1); 634 } else if (tm->tm_mday == day) { 635 if (tm->tm_hour > hour) 636 return (1); 637 } else if (tm->tm_hour == hour) { 638 if (tm->tm_min > min) 639 return (1); 640 } else if (tm->tm_min == min) { 641 if (tm->tm_sec > sec) 642 return (1); 643 } 644 } else { 645 printf("%s\n", reply_string); 646 verbose = overbose; 647 return (0); 648 } 649 } 650 } 651 } 652 653 recvrequest("RETR", argv[2], argv[1], mode, 654 argv[1] != oldargv1 || argv[2] != oldargv2); 655 restart_point = 0; 656 return (0); 657 } 658 659 void 660 mabort() 661 { 662 int ointer; 663 extern jmp_buf jabort; 664 665 printf("\n"); 666 (void) fflush(stdout); 667 if (mflag && fromatty) { 668 ointer = interactive; 669 interactive = 1; 670 if (confirm("Continue with", mname)) { 671 interactive = ointer; 672 longjmp(jabort,0); 673 } 674 interactive = ointer; 675 } 676 mflag = 0; 677 longjmp(jabort,0); 678 } 679 680 /* 681 * Get multiple files. 682 */ 683 mget(argc, argv) 684 int argc; 685 char **argv; 686 { 687 extern jmp_buf jabort; 688 sig_t oldintr; 689 int ointer; 690 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; 691 void mabort(); 692 693 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 694 printf("usage: %s remote-files\n", argv[0]); 695 code = -1; 696 return; 697 } 698 mname = argv[0]; 699 mflag = 1; 700 oldintr = signal(SIGINT,mabort); 701 (void) setjmp(jabort); 702 while ((cp = remglob(argv,proxy)) != NULL) { 703 if (*cp == '\0') { 704 mflag = 0; 705 continue; 706 } 707 if (mflag && confirm(argv[0], cp)) { 708 tp = cp; 709 if (mcase) { 710 while (*tp && !islower(*tp)) { 711 tp++; 712 } 713 if (!*tp) { 714 tp = cp; 715 tp2 = tmpbuf; 716 while ((*tp2 = *tp) != NULL) { 717 if (isupper(*tp2)) { 718 *tp2 = 'a' + *tp2 - 'A'; 719 } 720 tp++; 721 tp2++; 722 } 723 } 724 tp = tmpbuf; 725 } 726 if (ntflag) { 727 tp = dotrans(tp); 728 } 729 if (mapflag) { 730 tp = domap(tp); 731 } 732 recvrequest("RETR", tp, cp, "w", 733 tp != cp || !interactive); 734 if (!mflag && fromatty) { 735 ointer = interactive; 736 interactive = 1; 737 if (confirm("Continue with","mget")) { 738 mflag++; 739 } 740 interactive = ointer; 741 } 742 } 743 } 744 (void) signal(SIGINT,oldintr); 745 mflag = 0; 746 } 747 748 char * 749 remglob(argv,doswitch) 750 char *argv[]; 751 int doswitch; 752 { 753 char temp[16]; 754 static char buf[MAXPATHLEN]; 755 static FILE *ftemp = NULL; 756 static char **args; 757 int oldverbose, oldhash; 758 char *cp, *mode; 759 760 if (!mflag) { 761 if (!doglob) { 762 args = NULL; 763 } 764 else { 765 if (ftemp) { 766 (void) fclose(ftemp); 767 ftemp = NULL; 768 } 769 } 770 return(NULL); 771 } 772 if (!doglob) { 773 if (args == NULL) 774 args = argv; 775 if ((cp = *++args) == NULL) 776 args = NULL; 777 return (cp); 778 } 779 if (ftemp == NULL) { 780 (void) strcpy(temp, _PATH_TMP); 781 (void) mktemp(temp); 782 oldverbose = verbose, verbose = 0; 783 oldhash = hash, hash = 0; 784 if (doswitch) { 785 pswitch(!proxy); 786 } 787 for (mode = "w"; *++argv != NULL; mode = "a") 788 recvrequest ("NLST", temp, *argv, mode, 0); 789 if (doswitch) { 790 pswitch(!proxy); 791 } 792 verbose = oldverbose; hash = oldhash; 793 ftemp = fopen(temp, "r"); 794 (void) unlink(temp); 795 if (ftemp == NULL) { 796 printf("can't find list of remote files, oops\n"); 797 return (NULL); 798 } 799 } 800 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 801 (void) fclose(ftemp), ftemp = NULL; 802 return (NULL); 803 } 804 if ((cp = index(buf, '\n')) != NULL) 805 *cp = '\0'; 806 return (buf); 807 } 808 809 char * 810 onoff(bool) 811 int bool; 812 { 813 814 return (bool ? "on" : "off"); 815 } 816 817 /* 818 * Show status. 819 */ 820 /*ARGSUSED*/ 821 status(argc, argv) 822 int argc; 823 char *argv[]; 824 { 825 int i; 826 827 if (connected) 828 printf("Connected to %s.\n", hostname); 829 else 830 printf("Not connected.\n"); 831 if (!proxy) { 832 pswitch(1); 833 if (connected) { 834 printf("Connected for proxy commands to %s.\n", hostname); 835 } 836 else { 837 printf("No proxy connection.\n"); 838 } 839 pswitch(0); 840 } 841 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 842 modename, typename, formname, structname); 843 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 844 onoff(verbose), onoff(bell), onoff(interactive), 845 onoff(doglob)); 846 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 847 onoff(runique)); 848 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); 849 if (ntflag) { 850 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); 851 } 852 else { 853 printf("Ntrans: off\n"); 854 } 855 if (mapflag) { 856 printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 857 } 858 else { 859 printf("Nmap: off\n"); 860 } 861 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 862 onoff(hash), onoff(sendport)); 863 if (macnum > 0) { 864 printf("Macros:\n"); 865 for (i=0; i<macnum; i++) { 866 printf("\t%s\n",macros[i].mac_name); 867 } 868 } 869 code = 0; 870 } 871 872 /* 873 * Set beep on cmd completed mode. 874 */ 875 /*VARARGS*/ 876 setbell() 877 { 878 879 bell = !bell; 880 printf("Bell mode %s.\n", onoff(bell)); 881 code = bell; 882 } 883 884 /* 885 * Turn on packet tracing. 886 */ 887 /*VARARGS*/ 888 settrace() 889 { 890 891 trace = !trace; 892 printf("Packet tracing %s.\n", onoff(trace)); 893 code = trace; 894 } 895 896 /* 897 * Toggle hash mark printing during transfers. 898 */ 899 /*VARARGS*/ 900 sethash() 901 { 902 903 hash = !hash; 904 printf("Hash mark printing %s", onoff(hash)); 905 code = hash; 906 if (hash) 907 printf(" (%d bytes/hash mark)", 1024); 908 printf(".\n"); 909 } 910 911 /* 912 * Turn on printing of server echo's. 913 */ 914 /*VARARGS*/ 915 setverbose() 916 { 917 918 verbose = !verbose; 919 printf("Verbose mode %s.\n", onoff(verbose)); 920 code = verbose; 921 } 922 923 /* 924 * Toggle PORT cmd use before each data connection. 925 */ 926 /*VARARGS*/ 927 setport() 928 { 929 930 sendport = !sendport; 931 printf("Use of PORT cmds %s.\n", onoff(sendport)); 932 code = sendport; 933 } 934 935 /* 936 * Turn on interactive prompting 937 * during mget, mput, and mdelete. 938 */ 939 /*VARARGS*/ 940 setprompt() 941 { 942 943 interactive = !interactive; 944 printf("Interactive mode %s.\n", onoff(interactive)); 945 code = interactive; 946 } 947 948 /* 949 * Toggle metacharacter interpretation 950 * on local file names. 951 */ 952 /*VARARGS*/ 953 setglob() 954 { 955 956 doglob = !doglob; 957 printf("Globbing %s.\n", onoff(doglob)); 958 code = doglob; 959 } 960 961 /* 962 * Set debugging mode on/off and/or 963 * set level of debugging. 964 */ 965 /*VARARGS*/ 966 setdebug(argc, argv) 967 int argc; 968 char *argv[]; 969 { 970 int val; 971 972 if (argc > 1) { 973 val = atoi(argv[1]); 974 if (val < 0) { 975 printf("%s: bad debugging value.\n", argv[1]); 976 code = -1; 977 return; 978 } 979 } else 980 val = !debug; 981 debug = val; 982 if (debug) 983 options |= SO_DEBUG; 984 else 985 options &= ~SO_DEBUG; 986 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 987 code = debug > 0; 988 } 989 990 /* 991 * Set current working directory 992 * on remote machine. 993 */ 994 cd(argc, argv) 995 int argc; 996 char *argv[]; 997 { 998 999 if (argc < 2 && !another(&argc, &argv, "remote-directory")) { 1000 printf("usage: %s remote-directory\n", argv[0]); 1001 code = -1; 1002 return; 1003 } 1004 if (command("CWD %s", argv[1]) == ERROR && code == 500) { 1005 if (verbose) 1006 printf("CWD command not recognized, trying XCWD\n"); 1007 (void) command("XCWD %s", argv[1]); 1008 } 1009 } 1010 1011 /* 1012 * Set current working directory 1013 * on local machine. 1014 */ 1015 lcd(argc, argv) 1016 int argc; 1017 char *argv[]; 1018 { 1019 char buf[MAXPATHLEN]; 1020 extern char *getwd(); 1021 1022 if (argc < 2) 1023 argc++, argv[1] = home; 1024 if (argc != 2) { 1025 printf("usage: %s local-directory\n", argv[0]); 1026 code = -1; 1027 return; 1028 } 1029 if (!globulize(&argv[1])) { 1030 code = -1; 1031 return; 1032 } 1033 if (chdir(argv[1]) < 0) { 1034 fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno)); 1035 code = -1; 1036 return; 1037 } 1038 printf("Local directory now %s\n", getwd(buf)); 1039 code = 0; 1040 } 1041 1042 /* 1043 * Delete a single file. 1044 */ 1045 delete(argc, argv) 1046 int argc; 1047 char *argv[]; 1048 { 1049 1050 if (argc < 2 && !another(&argc, &argv, "remote-file")) { 1051 printf("usage: %s remote-file\n", argv[0]); 1052 code = -1; 1053 return; 1054 } 1055 (void) command("DELE %s", argv[1]); 1056 } 1057 1058 /* 1059 * Delete multiple files. 1060 */ 1061 mdelete(argc, argv) 1062 int argc; 1063 char **argv; 1064 { 1065 extern jmp_buf jabort; 1066 sig_t oldintr; 1067 int ointer; 1068 char *cp; 1069 void mabort(); 1070 1071 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 1072 printf("usage: %s remote-files\n", argv[0]); 1073 code = -1; 1074 return; 1075 } 1076 mname = argv[0]; 1077 mflag = 1; 1078 oldintr = signal(SIGINT, mabort); 1079 (void) setjmp(jabort); 1080 while ((cp = remglob(argv,0)) != NULL) { 1081 if (*cp == '\0') { 1082 mflag = 0; 1083 continue; 1084 } 1085 if (mflag && confirm(argv[0], cp)) { 1086 (void) command("DELE %s", cp); 1087 if (!mflag && fromatty) { 1088 ointer = interactive; 1089 interactive = 1; 1090 if (confirm("Continue with", "mdelete")) { 1091 mflag++; 1092 } 1093 interactive = ointer; 1094 } 1095 } 1096 } 1097 (void) signal(SIGINT, oldintr); 1098 mflag = 0; 1099 } 1100 1101 /* 1102 * Rename a remote file. 1103 */ 1104 renamefile(argc, argv) 1105 int argc; 1106 char *argv[]; 1107 { 1108 1109 if (argc < 2 && !another(&argc, &argv, "from-name")) 1110 goto usage; 1111 if (argc < 3 && !another(&argc, &argv, "to-name")) { 1112 usage: 1113 printf("%s from-name to-name\n", argv[0]); 1114 code = -1; 1115 return; 1116 } 1117 if (command("RNFR %s", argv[1]) == CONTINUE) 1118 (void) command("RNTO %s", argv[2]); 1119 } 1120 1121 /* 1122 * Get a directory listing 1123 * of remote files. 1124 */ 1125 ls(argc, argv) 1126 int argc; 1127 char *argv[]; 1128 { 1129 char *cmd; 1130 1131 if (argc < 2) 1132 argc++, argv[1] = NULL; 1133 if (argc < 3) 1134 argc++, argv[2] = "-"; 1135 if (argc > 3) { 1136 printf("usage: %s remote-directory local-file\n", argv[0]); 1137 code = -1; 1138 return; 1139 } 1140 cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; 1141 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1142 code = -1; 1143 return; 1144 } 1145 if (strcmp(argv[2], "-") && *argv[2] != '|') 1146 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { 1147 code = -1; 1148 return; 1149 } 1150 recvrequest(cmd, argv[2], argv[1], "w", 0); 1151 } 1152 1153 /* 1154 * Get a directory listing 1155 * of multiple remote files. 1156 */ 1157 mls(argc, argv) 1158 int argc; 1159 char **argv; 1160 { 1161 extern jmp_buf jabort; 1162 sig_t oldintr; 1163 int ointer, i; 1164 char *cmd, mode[1], *dest; 1165 void mabort(); 1166 1167 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1168 goto usage; 1169 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1170 usage: 1171 printf("usage: %s remote-files local-file\n", argv[0]); 1172 code = -1; 1173 return; 1174 } 1175 dest = argv[argc - 1]; 1176 argv[argc - 1] = NULL; 1177 if (strcmp(dest, "-") && *dest != '|') 1178 if (!globulize(&dest) || 1179 !confirm("output to local-file:", dest)) { 1180 code = -1; 1181 return; 1182 } 1183 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 1184 mname = argv[0]; 1185 mflag = 1; 1186 oldintr = signal(SIGINT, mabort); 1187 (void) setjmp(jabort); 1188 for (i = 1; mflag && i < argc-1; ++i) { 1189 *mode = (i == 1) ? 'w' : 'a'; 1190 recvrequest(cmd, dest, argv[i], mode, 0); 1191 if (!mflag && fromatty) { 1192 ointer = interactive; 1193 interactive = 1; 1194 if (confirm("Continue with", argv[0])) { 1195 mflag ++; 1196 } 1197 interactive = ointer; 1198 } 1199 } 1200 (void) signal(SIGINT, oldintr); 1201 mflag = 0; 1202 } 1203 1204 /* 1205 * Do a shell escape 1206 */ 1207 /*ARGSUSED*/ 1208 shell(argc, argv) 1209 int argc; 1210 char **argv; 1211 { 1212 int pid; 1213 sig_t old1, old2; 1214 char shellnam[40], *shell, *namep; 1215 union wait status; 1216 1217 old1 = signal (SIGINT, SIG_IGN); 1218 old2 = signal (SIGQUIT, SIG_IGN); 1219 if ((pid = fork()) == 0) { 1220 for (pid = 3; pid < 20; pid++) 1221 (void) close(pid); 1222 (void) signal(SIGINT, SIG_DFL); 1223 (void) signal(SIGQUIT, SIG_DFL); 1224 shell = getenv("SHELL"); 1225 if (shell == NULL) 1226 shell = _PATH_BSHELL; 1227 namep = rindex(shell,'/'); 1228 if (namep == NULL) 1229 namep = shell; 1230 (void) strcpy(shellnam,"-"); 1231 (void) strcat(shellnam, ++namep); 1232 if (strcmp(namep, "sh") != 0) 1233 shellnam[0] = '+'; 1234 if (debug) { 1235 printf ("%s\n", shell); 1236 (void) fflush (stdout); 1237 } 1238 if (argc > 1) { 1239 execl(shell,shellnam,"-c",altarg,(char *)0); 1240 } 1241 else { 1242 execl(shell,shellnam,(char *)0); 1243 } 1244 perror(shell); 1245 code = -1; 1246 exit(1); 1247 } 1248 if (pid > 0) 1249 while (wait((int *)&status) != pid) 1250 ; 1251 (void) signal(SIGINT, old1); 1252 (void) signal(SIGQUIT, old2); 1253 if (pid == -1) { 1254 perror("Try again later"); 1255 code = -1; 1256 } 1257 else { 1258 code = 0; 1259 } 1260 return (0); 1261 } 1262 1263 /* 1264 * Send new user information (re-login) 1265 */ 1266 user(argc, argv) 1267 int argc; 1268 char **argv; 1269 { 1270 char acct[80], *getpass(); 1271 int n, aflag = 0; 1272 1273 if (argc < 2) 1274 (void) another(&argc, &argv, "username"); 1275 if (argc < 2 || argc > 4) { 1276 printf("usage: %s username [password] [account]\n", argv[0]); 1277 code = -1; 1278 return (0); 1279 } 1280 n = command("USER %s", argv[1]); 1281 if (n == CONTINUE) { 1282 if (argc < 3 ) 1283 argv[2] = getpass("Password: "), argc++; 1284 n = command("PASS %s", argv[2]); 1285 } 1286 if (n == CONTINUE) { 1287 if (argc < 4) { 1288 printf("Account: "); (void) fflush(stdout); 1289 (void) fgets(acct, sizeof(acct) - 1, stdin); 1290 acct[strlen(acct) - 1] = '\0'; 1291 argv[3] = acct; argc++; 1292 } 1293 n = command("ACCT %s", argv[3]); 1294 aflag++; 1295 } 1296 if (n != COMPLETE) { 1297 fprintf(stdout, "Login failed.\n"); 1298 return (0); 1299 } 1300 if (!aflag && argc == 4) { 1301 (void) command("ACCT %s", argv[3]); 1302 } 1303 return (1); 1304 } 1305 1306 /* 1307 * Print working directory. 1308 */ 1309 /*VARARGS*/ 1310 pwd() 1311 { 1312 int oldverbose = verbose; 1313 1314 /* 1315 * If we aren't verbose, this doesn't do anything! 1316 */ 1317 verbose = 1; 1318 if (command("PWD") == ERROR && code == 500) { 1319 printf("PWD command not recognized, trying XPWD\n"); 1320 (void) command("XPWD"); 1321 } 1322 verbose = oldverbose; 1323 } 1324 1325 /* 1326 * Make a directory. 1327 */ 1328 makedir(argc, argv) 1329 int argc; 1330 char *argv[]; 1331 { 1332 1333 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1334 printf("usage: %s directory-name\n", argv[0]); 1335 code = -1; 1336 return; 1337 } 1338 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1339 if (verbose) 1340 printf("MKD command not recognized, trying XMKD\n"); 1341 (void) command("XMKD %s", argv[1]); 1342 } 1343 } 1344 1345 /* 1346 * Remove a directory. 1347 */ 1348 removedir(argc, argv) 1349 int argc; 1350 char *argv[]; 1351 { 1352 1353 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1354 printf("usage: %s directory-name\n", argv[0]); 1355 code = -1; 1356 return; 1357 } 1358 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1359 if (verbose) 1360 printf("RMD command not recognized, trying XRMD\n"); 1361 (void) command("XRMD %s", argv[1]); 1362 } 1363 } 1364 1365 /* 1366 * Send a line, verbatim, to the remote machine. 1367 */ 1368 quote(argc, argv) 1369 int argc; 1370 char *argv[]; 1371 { 1372 1373 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1374 printf("usage: %s line-to-send\n", argv[0]); 1375 code = -1; 1376 return; 1377 } 1378 quote1("", argc, argv); 1379 } 1380 1381 /* 1382 * Send a SITE command to the remote machine. The line 1383 * is sent verbatim to the remote machine, except that the 1384 * word "SITE" is added at the front. 1385 */ 1386 site(argc, argv) 1387 int argc; 1388 char *argv[]; 1389 { 1390 1391 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1392 printf("usage: %s line-to-send\n", argv[0]); 1393 code = -1; 1394 return; 1395 } 1396 quote1("SITE ", argc, argv); 1397 } 1398 1399 /* 1400 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1401 * Send the result as a one-line command and get response. 1402 */ 1403 quote1(initial, argc, argv) 1404 char *initial; 1405 int argc; 1406 char **argv; 1407 { 1408 register int i, len; 1409 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1410 1411 (void) strcpy(buf, initial); 1412 if (argc > 1) { 1413 len = strlen(buf); 1414 len += strlen(strcpy(&buf[len], argv[1])); 1415 for (i = 2; i < argc; i++) { 1416 buf[len++] = ' '; 1417 len += strlen(strcpy(&buf[len], argv[i])); 1418 } 1419 } 1420 if (command(buf) == PRELIM) { 1421 while (getreply(0) == PRELIM); 1422 } 1423 } 1424 1425 do_chmod(argc, argv) 1426 int argc; 1427 char *argv[]; 1428 { 1429 1430 if (argc < 2 && !another(&argc, &argv, "mode")) 1431 goto usage; 1432 if (argc < 3 && !another(&argc, &argv, "file-name")) { 1433 usage: 1434 printf("usage: %s mode file-name\n", argv[0]); 1435 code = -1; 1436 return; 1437 } 1438 (void) command("SITE CHMOD %s %s", argv[1], argv[2]); 1439 } 1440 1441 do_umask(argc, argv) 1442 int argc; 1443 char *argv[]; 1444 { 1445 int oldverbose = verbose; 1446 1447 verbose = 1; 1448 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1449 verbose = oldverbose; 1450 } 1451 1452 idle(argc, argv) 1453 int argc; 1454 char *argv[]; 1455 { 1456 int oldverbose = verbose; 1457 1458 verbose = 1; 1459 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1460 verbose = oldverbose; 1461 } 1462 1463 /* 1464 * Ask the other side for help. 1465 */ 1466 rmthelp(argc, argv) 1467 int argc; 1468 char *argv[]; 1469 { 1470 int oldverbose = verbose; 1471 1472 verbose = 1; 1473 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1474 verbose = oldverbose; 1475 } 1476 1477 /* 1478 * Terminate session and exit. 1479 */ 1480 /*VARARGS*/ 1481 quit() 1482 { 1483 1484 if (connected) 1485 disconnect(); 1486 pswitch(1); 1487 if (connected) { 1488 disconnect(); 1489 } 1490 exit(0); 1491 } 1492 1493 /* 1494 * Terminate session, but don't exit. 1495 */ 1496 disconnect() 1497 { 1498 extern FILE *cout; 1499 extern int data; 1500 1501 if (!connected) 1502 return; 1503 (void) command("QUIT"); 1504 if (cout) { 1505 (void) fclose(cout); 1506 } 1507 cout = NULL; 1508 connected = 0; 1509 data = -1; 1510 if (!proxy) { 1511 macnum = 0; 1512 } 1513 } 1514 1515 confirm(cmd, file) 1516 char *cmd, *file; 1517 { 1518 char line[BUFSIZ]; 1519 1520 if (!interactive) 1521 return (1); 1522 printf("%s %s? ", cmd, file); 1523 (void) fflush(stdout); 1524 if (fgets(line, sizeof line, stdin) == NULL) 1525 return (0); 1526 return (*line != 'n' && *line != 'N'); 1527 } 1528 1529 fatal(msg) 1530 char *msg; 1531 { 1532 1533 fprintf(stderr, "ftp: %s\n", msg); 1534 exit(1); 1535 } 1536 1537 /* 1538 * Glob a local file name specification with 1539 * the expectation of a single return value. 1540 * Can't control multiple values being expanded 1541 * from the expression, we return only the first. 1542 */ 1543 globulize(cpp) 1544 char **cpp; 1545 { 1546 char **globbed; 1547 1548 if (!doglob) 1549 return (1); 1550 globbed = ftpglob(*cpp); 1551 if (globerr != NULL) { 1552 printf("%s: %s\n", *cpp, globerr); 1553 if (globbed) { 1554 blkfree(globbed); 1555 free((char *)globbed); 1556 } 1557 return (0); 1558 } 1559 if (globbed) { 1560 *cpp = *globbed++; 1561 /* don't waste too much memory */ 1562 if (*globbed) { 1563 blkfree(globbed); 1564 free((char *)globbed); 1565 } 1566 } 1567 return (1); 1568 } 1569 1570 account(argc,argv) 1571 int argc; 1572 char **argv; 1573 { 1574 char acct[50], *getpass(), *ap; 1575 1576 if (argc > 1) { 1577 ++argv; 1578 --argc; 1579 (void) strncpy(acct,*argv,49); 1580 acct[49] = '\0'; 1581 while (argc > 1) { 1582 --argc; 1583 ++argv; 1584 (void) strncat(acct,*argv, 49-strlen(acct)); 1585 } 1586 ap = acct; 1587 } 1588 else { 1589 ap = getpass("Account:"); 1590 } 1591 (void) command("ACCT %s", ap); 1592 } 1593 1594 jmp_buf abortprox; 1595 1596 void 1597 proxabort() 1598 { 1599 extern int proxy; 1600 1601 if (!proxy) { 1602 pswitch(1); 1603 } 1604 if (connected) { 1605 proxflag = 1; 1606 } 1607 else { 1608 proxflag = 0; 1609 } 1610 pswitch(0); 1611 longjmp(abortprox,1); 1612 } 1613 1614 doproxy(argc,argv) 1615 int argc; 1616 char *argv[]; 1617 { 1618 extern struct cmd cmdtab[]; 1619 extern jmp_buf abortprox; 1620 register struct cmd *c; 1621 struct cmd *getcmd(); 1622 sig_t oldintr; 1623 void proxabort(); 1624 1625 if (argc < 2 && !another(&argc, &argv, "command")) { 1626 printf("usage: %s command\n", argv[0]); 1627 code = -1; 1628 return; 1629 } 1630 c = getcmd(argv[1]); 1631 if (c == (struct cmd *) -1) { 1632 printf("?Ambiguous command\n"); 1633 (void) fflush(stdout); 1634 code = -1; 1635 return; 1636 } 1637 if (c == 0) { 1638 printf("?Invalid command\n"); 1639 (void) fflush(stdout); 1640 code = -1; 1641 return; 1642 } 1643 if (!c->c_proxy) { 1644 printf("?Invalid proxy command\n"); 1645 (void) fflush(stdout); 1646 code = -1; 1647 return; 1648 } 1649 if (setjmp(abortprox)) { 1650 code = -1; 1651 return; 1652 } 1653 oldintr = signal(SIGINT, proxabort); 1654 pswitch(1); 1655 if (c->c_conn && !connected) { 1656 printf("Not connected\n"); 1657 (void) fflush(stdout); 1658 pswitch(0); 1659 (void) signal(SIGINT, oldintr); 1660 code = -1; 1661 return; 1662 } 1663 (*c->c_handler)(argc-1, argv+1); 1664 if (connected) { 1665 proxflag = 1; 1666 } 1667 else { 1668 proxflag = 0; 1669 } 1670 pswitch(0); 1671 (void) signal(SIGINT, oldintr); 1672 } 1673 1674 setcase() 1675 { 1676 mcase = !mcase; 1677 printf("Case mapping %s.\n", onoff(mcase)); 1678 code = mcase; 1679 } 1680 1681 setcr() 1682 { 1683 crflag = !crflag; 1684 printf("Carriage Return stripping %s.\n", onoff(crflag)); 1685 code = crflag; 1686 } 1687 1688 setntrans(argc,argv) 1689 int argc; 1690 char *argv[]; 1691 { 1692 if (argc == 1) { 1693 ntflag = 0; 1694 printf("Ntrans off.\n"); 1695 code = ntflag; 1696 return; 1697 } 1698 ntflag++; 1699 code = ntflag; 1700 (void) strncpy(ntin, argv[1], 16); 1701 ntin[16] = '\0'; 1702 if (argc == 2) { 1703 ntout[0] = '\0'; 1704 return; 1705 } 1706 (void) strncpy(ntout, argv[2], 16); 1707 ntout[16] = '\0'; 1708 } 1709 1710 char * 1711 dotrans(name) 1712 char *name; 1713 { 1714 static char new[MAXPATHLEN]; 1715 char *cp1, *cp2 = new; 1716 register int i, ostop, found; 1717 1718 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); 1719 for (cp1 = name; *cp1; cp1++) { 1720 found = 0; 1721 for (i = 0; *(ntin + i) && i < 16; i++) { 1722 if (*cp1 == *(ntin + i)) { 1723 found++; 1724 if (i < ostop) { 1725 *cp2++ = *(ntout + i); 1726 } 1727 break; 1728 } 1729 } 1730 if (!found) { 1731 *cp2++ = *cp1; 1732 } 1733 } 1734 *cp2 = '\0'; 1735 return(new); 1736 } 1737 1738 setnmap(argc, argv) 1739 int argc; 1740 char *argv[]; 1741 { 1742 char *cp; 1743 1744 if (argc == 1) { 1745 mapflag = 0; 1746 printf("Nmap off.\n"); 1747 code = mapflag; 1748 return; 1749 } 1750 if (argc < 3 && !another(&argc, &argv, "mapout")) { 1751 printf("Usage: %s [mapin mapout]\n",argv[0]); 1752 code = -1; 1753 return; 1754 } 1755 mapflag = 1; 1756 code = 1; 1757 cp = index(altarg, ' '); 1758 if (proxy) { 1759 while(*++cp == ' '); 1760 altarg = cp; 1761 cp = index(altarg, ' '); 1762 } 1763 *cp = '\0'; 1764 (void) strncpy(mapin, altarg, MAXPATHLEN - 1); 1765 while (*++cp == ' '); 1766 (void) strncpy(mapout, cp, MAXPATHLEN - 1); 1767 } 1768 1769 char * 1770 domap(name) 1771 char *name; 1772 { 1773 static char new[MAXPATHLEN]; 1774 register char *cp1 = name, *cp2 = mapin; 1775 char *tp[9], *te[9]; 1776 int i, toks[9], toknum = 0, match = 1; 1777 1778 for (i=0; i < 9; ++i) { 1779 toks[i] = 0; 1780 } 1781 while (match && *cp1 && *cp2) { 1782 switch (*cp2) { 1783 case '\\': 1784 if (*++cp2 != *cp1) { 1785 match = 0; 1786 } 1787 break; 1788 case '$': 1789 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1790 if (*cp1 != *(++cp2+1)) { 1791 toks[toknum = *cp2 - '1']++; 1792 tp[toknum] = cp1; 1793 while (*++cp1 && *(cp2+1) 1794 != *cp1); 1795 te[toknum] = cp1; 1796 } 1797 cp2++; 1798 break; 1799 } 1800 /* FALLTHROUGH */ 1801 default: 1802 if (*cp2 != *cp1) { 1803 match = 0; 1804 } 1805 break; 1806 } 1807 if (match && *cp1) { 1808 cp1++; 1809 } 1810 if (match && *cp2) { 1811 cp2++; 1812 } 1813 } 1814 if (!match && *cp1) /* last token mismatch */ 1815 { 1816 toks[toknum] = 0; 1817 } 1818 cp1 = new; 1819 *cp1 = '\0'; 1820 cp2 = mapout; 1821 while (*cp2) { 1822 match = 0; 1823 switch (*cp2) { 1824 case '\\': 1825 if (*(cp2 + 1)) { 1826 *cp1++ = *++cp2; 1827 } 1828 break; 1829 case '[': 1830 LOOP: 1831 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1832 if (*++cp2 == '0') { 1833 char *cp3 = name; 1834 1835 while (*cp3) { 1836 *cp1++ = *cp3++; 1837 } 1838 match = 1; 1839 } 1840 else if (toks[toknum = *cp2 - '1']) { 1841 char *cp3 = tp[toknum]; 1842 1843 while (cp3 != te[toknum]) { 1844 *cp1++ = *cp3++; 1845 } 1846 match = 1; 1847 } 1848 } 1849 else { 1850 while (*cp2 && *cp2 != ',' && 1851 *cp2 != ']') { 1852 if (*cp2 == '\\') { 1853 cp2++; 1854 } 1855 else if (*cp2 == '$' && 1856 isdigit(*(cp2+1))) { 1857 if (*++cp2 == '0') { 1858 char *cp3 = name; 1859 1860 while (*cp3) { 1861 *cp1++ = *cp3++; 1862 } 1863 } 1864 else if (toks[toknum = 1865 *cp2 - '1']) { 1866 char *cp3=tp[toknum]; 1867 1868 while (cp3 != 1869 te[toknum]) { 1870 *cp1++ = *cp3++; 1871 } 1872 } 1873 } 1874 else if (*cp2) { 1875 *cp1++ = *cp2++; 1876 } 1877 } 1878 if (!*cp2) { 1879 printf("nmap: unbalanced brackets\n"); 1880 return(name); 1881 } 1882 match = 1; 1883 cp2--; 1884 } 1885 if (match) { 1886 while (*++cp2 && *cp2 != ']') { 1887 if (*cp2 == '\\' && *(cp2 + 1)) { 1888 cp2++; 1889 } 1890 } 1891 if (!*cp2) { 1892 printf("nmap: unbalanced brackets\n"); 1893 return(name); 1894 } 1895 break; 1896 } 1897 switch (*++cp2) { 1898 case ',': 1899 goto LOOP; 1900 case ']': 1901 break; 1902 default: 1903 cp2--; 1904 goto LOOP; 1905 } 1906 break; 1907 case '$': 1908 if (isdigit(*(cp2 + 1))) { 1909 if (*++cp2 == '0') { 1910 char *cp3 = name; 1911 1912 while (*cp3) { 1913 *cp1++ = *cp3++; 1914 } 1915 } 1916 else if (toks[toknum = *cp2 - '1']) { 1917 char *cp3 = tp[toknum]; 1918 1919 while (cp3 != te[toknum]) { 1920 *cp1++ = *cp3++; 1921 } 1922 } 1923 break; 1924 } 1925 /* intentional drop through */ 1926 default: 1927 *cp1++ = *cp2; 1928 break; 1929 } 1930 cp2++; 1931 } 1932 *cp1 = '\0'; 1933 if (!*new) { 1934 return(name); 1935 } 1936 return(new); 1937 } 1938 1939 setsunique() 1940 { 1941 sunique = !sunique; 1942 printf("Store unique %s.\n", onoff(sunique)); 1943 code = sunique; 1944 } 1945 1946 setrunique() 1947 { 1948 runique = !runique; 1949 printf("Receive unique %s.\n", onoff(runique)); 1950 code = runique; 1951 } 1952 1953 /* change directory to perent directory */ 1954 cdup() 1955 { 1956 if (command("CDUP") == ERROR && code == 500) { 1957 if (verbose) 1958 printf("CDUP command not recognized, trying XCUP\n"); 1959 (void) command("XCUP"); 1960 } 1961 } 1962 1963 /* restart transfer at specific point */ 1964 restart(argc, argv) 1965 int argc; 1966 char *argv[]; 1967 { 1968 extern long atol(); 1969 if (argc != 2) 1970 printf("restart: offset not specified\n"); 1971 else { 1972 restart_point = atol(argv[1]); 1973 printf("restarting at %ld. %s\n", restart_point, 1974 "execute get, put or append to initiate transfer"); 1975 } 1976 } 1977 1978 /* show remote system type */ 1979 syst() 1980 { 1981 (void) command("SYST"); 1982 } 1983 1984 macdef(argc, argv) 1985 int argc; 1986 char *argv[]; 1987 { 1988 char *tmp; 1989 int c; 1990 1991 if (macnum == 16) { 1992 printf("Limit of 16 macros have already been defined\n"); 1993 code = -1; 1994 return; 1995 } 1996 if (argc < 2 && !another(&argc, &argv, "macro name")) { 1997 printf("Usage: %s macro_name\n",argv[0]); 1998 code = -1; 1999 return; 2000 } 2001 if (interactive) { 2002 printf("Enter macro line by line, terminating it with a null line\n"); 2003 } 2004 (void) strncpy(macros[macnum].mac_name, argv[1], 8); 2005 if (macnum == 0) { 2006 macros[macnum].mac_start = macbuf; 2007 } 2008 else { 2009 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2010 } 2011 tmp = macros[macnum].mac_start; 2012 while (tmp != macbuf+4096) { 2013 if ((c = getchar()) == EOF) { 2014 printf("macdef:end of file encountered\n"); 2015 code = -1; 2016 return; 2017 } 2018 if ((*tmp = c) == '\n') { 2019 if (tmp == macros[macnum].mac_start) { 2020 macros[macnum++].mac_end = tmp; 2021 code = 0; 2022 return; 2023 } 2024 if (*(tmp-1) == '\0') { 2025 macros[macnum++].mac_end = tmp - 1; 2026 code = 0; 2027 return; 2028 } 2029 *tmp = '\0'; 2030 } 2031 tmp++; 2032 } 2033 while (1) { 2034 while ((c = getchar()) != '\n' && c != EOF) 2035 /* LOOP */; 2036 if (c == EOF || getchar() == '\n') { 2037 printf("Macro not defined - 4k buffer exceeded\n"); 2038 code = -1; 2039 return; 2040 } 2041 } 2042 } 2043 2044 /* 2045 * get size of file on remote machine 2046 */ 2047 sizecmd(argc, argv) 2048 int argc; 2049 char *argv[]; 2050 { 2051 2052 if (argc < 2 && !another(&argc, &argv, "filename")) { 2053 printf("usage: %s filename\n", argv[0]); 2054 code = -1; 2055 return; 2056 } 2057 (void) command("SIZE %s", argv[1]); 2058 } 2059 2060 /* 2061 * get last modification time of file on remote machine 2062 */ 2063 modtime(argc, argv) 2064 int argc; 2065 char *argv[]; 2066 { 2067 int overbose; 2068 2069 if (argc < 2 && !another(&argc, &argv, "filename")) { 2070 printf("usage: %s filename\n", argv[0]); 2071 code = -1; 2072 return; 2073 } 2074 overbose = verbose; 2075 if (debug == 0) 2076 verbose = -1; 2077 if (command("MDTM %s", argv[1]) == COMPLETE) { 2078 int yy, mo, day, hour, min, sec; 2079 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, 2080 &day, &hour, &min, &sec); 2081 /* might want to print this in local time */ 2082 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], 2083 mo, day, yy, hour, min, sec); 2084 } else 2085 printf("%s\n", reply_string); 2086 verbose = overbose; 2087 } 2088 2089 /* 2090 * show status on reomte machine 2091 */ 2092 rmtstatus(argc, argv) 2093 int argc; 2094 char *argv[]; 2095 { 2096 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 2097 } 2098 2099 /* 2100 * get file if modtime is more recent than current file 2101 */ 2102 newer(argc, argv) 2103 int argc; 2104 char *argv[]; 2105 { 2106 if (getit(argc, argv, -1, "w")) 2107 printf("Local file \"%s\" is newer than remote file \"%s\"\n", 2108 argv[1], argv[2]); 2109 } 2110