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