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