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