1 /* $NetBSD: cmds.c,v 1.30 1997/09/26 15:22: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.30 1997/09/26 15:22: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 = atol(argv[1]); 785 if (nmark < 1) { 786 printf("%s: bad bytecount value.\n", argv[1]); 787 code = -1; 788 return; 789 } 790 mark = nmark; 791 hash = 1; 792 } 793 printf("Hash mark printing %s", onoff(hash)); 794 if (hash) 795 printf(" (%d bytes/hash mark)", mark); 796 puts("."); 797 code = hash; 798 } 799 800 /* 801 * Turn on printing of server echo's. 802 */ 803 /*VARARGS*/ 804 void 805 setverbose(argc, argv) 806 int argc; 807 char *argv[]; 808 { 809 810 code = togglevar(argc, argv, &verbose, "Verbose mode"); 811 } 812 813 /* 814 * Toggle PORT cmd use before each data connection. 815 */ 816 /*VARARGS*/ 817 void 818 setport(argc, argv) 819 int argc; 820 char *argv[]; 821 { 822 823 code = togglevar(argc, argv, &sendport, "Use of PORT cmds"); 824 } 825 826 /* 827 * Toggle transfer progress bar. 828 */ 829 /*VARARGS*/ 830 void 831 setprogress(argc, argv) 832 int argc; 833 char *argv[]; 834 { 835 836 code = togglevar(argc, argv, &progress, "Progress bar"); 837 } 838 839 /* 840 * Turn on interactive prompting during mget, mput, and mdelete. 841 */ 842 /*VARARGS*/ 843 void 844 setprompt(argc, argv) 845 int argc; 846 char *argv[]; 847 { 848 849 code = togglevar(argc, argv, &interactive, "Interactive mode"); 850 } 851 852 /* 853 * Toggle gate-ftp mode, or set gate-ftp server 854 */ 855 /*VARARGS*/ 856 void 857 setgate(argc, argv) 858 int argc; 859 char *argv[]; 860 { 861 static char gsbuf[MAXHOSTNAMELEN]; 862 863 if (argc > 3) { 864 printf("usage: %s [ on | off | gateserver [ port ] ]\n", 865 argv[0]); 866 code = -1; 867 return; 868 } else if (argc < 2) { 869 gatemode = !gatemode; 870 } else { 871 if (argc == 2 && strcasecmp(argv[1], "on") == 0) 872 gatemode = 1; 873 else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 874 gatemode = 0; 875 else { 876 if (argc == 3) { 877 char *ep; 878 long port; 879 880 port = strtol(argv[2], &ep, 10); 881 if (port < 0 || port > 0xffff || *ep != '\0') { 882 printf("%s: bad gateport value.\n", 883 argv[2]); 884 code = -1; 885 return; 886 } 887 gateport = htons(port); 888 } 889 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1); 890 gsbuf[sizeof(gsbuf) - 1] = '\0'; 891 gateserver = gsbuf; 892 gatemode = 1; 893 } 894 } 895 if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 896 printf( 897 "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 898 gatemode = 0; 899 } else { 900 printf("Gate ftp: %s, server %s, port %d.\n", onoff(gatemode), 901 *gateserver ? gateserver : "(none)", ntohs(gateport)); 902 } 903 code = gatemode; 904 } 905 906 /* 907 * Toggle metacharacter interpretation on local file names. 908 */ 909 /*VARARGS*/ 910 void 911 setglob(argc, argv) 912 int argc; 913 char *argv[]; 914 { 915 916 code = togglevar(argc, argv, &doglob, "Globbing"); 917 } 918 919 /* 920 * Toggle preserving modification times on retreived files. 921 */ 922 /*VARARGS*/ 923 void 924 setpreserve(argc, argv) 925 int argc; 926 char *argv[]; 927 { 928 929 code = togglevar(argc, argv, &preserve, "Preserve modification times"); 930 } 931 932 /* 933 * Set debugging mode on/off and/or set level of debugging. 934 */ 935 /*VARARGS*/ 936 void 937 setdebug(argc, argv) 938 int argc; 939 char *argv[]; 940 { 941 if (argc > 2) { 942 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]); 943 code = -1; 944 return; 945 } else if (argc == 2) { 946 if (strcasecmp(argv[1], "on") == 0) 947 debug = 1; 948 else if (strcasecmp(argv[1], "off") == 0) 949 debug = 0; 950 else { 951 char *ep; 952 long val; 953 954 val = strtol(argv[1], &ep, 10); 955 if (val < 0 || val > INT_MAX || *ep != '\0') { 956 printf("%s: bad debugging value.\n", argv[1]); 957 code = -1; 958 return; 959 } 960 debug = (int)val; 961 } 962 } else 963 debug = !debug; 964 if (debug) 965 options |= SO_DEBUG; 966 else 967 options &= ~SO_DEBUG; 968 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 969 code = debug > 0; 970 } 971 972 /* 973 * Set current working directory on remote machine. 974 */ 975 void 976 cd(argc, argv) 977 int argc; 978 char *argv[]; 979 { 980 int r; 981 982 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) || 983 argc > 2) { 984 printf("usage: %s remote-directory\n", argv[0]); 985 code = -1; 986 return; 987 } 988 r = command("CWD %s", argv[1]); 989 if (r == ERROR && code == 500) { 990 if (verbose) 991 puts("CWD command not recognized, trying XCWD."); 992 r = command("XCWD %s", argv[1]); 993 } 994 if (r == COMPLETE) 995 dirchange = 1; 996 } 997 998 /* 999 * Set current working directory on local machine. 1000 */ 1001 void 1002 lcd(argc, argv) 1003 int argc; 1004 char *argv[]; 1005 { 1006 char buf[MAXPATHLEN]; 1007 char *oldargv1; 1008 1009 if (argc < 2) 1010 argc++, argv[1] = home; 1011 if (argc != 2) { 1012 printf("usage: %s local-directory\n", argv[0]); 1013 code = -1; 1014 return; 1015 } 1016 oldargv1 = argv[1]; 1017 if (!globulize(&argv[1])) { 1018 code = -1; 1019 return; 1020 } 1021 if (chdir(argv[1]) < 0) { 1022 warn("local: %s", argv[1]); 1023 code = -1; 1024 } else { 1025 if (getcwd(buf, sizeof(buf)) != NULL) 1026 printf("Local directory now %s\n", buf); 1027 else 1028 warn("getcwd: %s", argv[1]); 1029 code = 0; 1030 } 1031 if (oldargv1 != argv[1]) /* free up after globulize() */ 1032 free(argv[1]); 1033 } 1034 1035 /* 1036 * Delete a single file. 1037 */ 1038 void 1039 delete(argc, argv) 1040 int argc; 1041 char *argv[]; 1042 { 1043 1044 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) { 1045 printf("usage: %s remote-file\n", argv[0]); 1046 code = -1; 1047 return; 1048 } 1049 (void)command("DELE %s", argv[1]); 1050 } 1051 1052 /* 1053 * Delete multiple files. 1054 */ 1055 void 1056 mdelete(argc, argv) 1057 int argc; 1058 char *argv[]; 1059 { 1060 sig_t oldintr; 1061 int ointer; 1062 char *cp; 1063 1064 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 1065 printf("usage: %s remote-files\n", argv[0]); 1066 code = -1; 1067 return; 1068 } 1069 mname = argv[0]; 1070 mflag = 1; 1071 oldintr = signal(SIGINT, mabort); 1072 (void)setjmp(jabort); 1073 while ((cp = remglob(argv, 0, NULL)) != NULL) { 1074 if (*cp == '\0') { 1075 mflag = 0; 1076 continue; 1077 } 1078 if (mflag && confirm(argv[0], cp)) { 1079 (void)command("DELE %s", cp); 1080 if (!mflag && fromatty) { 1081 ointer = interactive; 1082 interactive = 1; 1083 if (confirm("Continue with", "mdelete")) { 1084 mflag++; 1085 } 1086 interactive = ointer; 1087 } 1088 } 1089 } 1090 (void)signal(SIGINT, oldintr); 1091 mflag = 0; 1092 } 1093 1094 /* 1095 * Rename a remote file. 1096 */ 1097 void 1098 renamefile(argc, argv) 1099 int argc; 1100 char *argv[]; 1101 { 1102 1103 if (argc < 2 && !another(&argc, &argv, "from-name")) 1104 goto usage; 1105 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1106 usage: 1107 printf("usage: %s from-name to-name\n", argv[0]); 1108 code = -1; 1109 return; 1110 } 1111 if (command("RNFR %s", argv[1]) == CONTINUE) 1112 (void)command("RNTO %s", argv[2]); 1113 } 1114 1115 /* 1116 * Get a directory listing of remote files. 1117 */ 1118 void 1119 ls(argc, argv) 1120 int argc; 1121 char *argv[]; 1122 { 1123 const char *cmd; 1124 char *oldargv2, *globargv2; 1125 1126 if (argc < 2) 1127 argc++, argv[1] = NULL; 1128 if (argc < 3) 1129 argc++, argv[2] = "-"; 1130 if (argc > 3) { 1131 printf("usage: %s remote-directory local-file\n", argv[0]); 1132 code = -1; 1133 return; 1134 } 1135 cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST"; 1136 oldargv2 = argv[2]; 1137 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1138 code = -1; 1139 return; 1140 } 1141 globargv2 = argv[2]; 1142 if (strcmp(argv[2], "-") && *argv[2] != '|') 1143 if (!globulize(&argv[2]) || !confirm("output to local-file:", 1144 argv[2])) { 1145 code = -1; 1146 goto freels; 1147 } 1148 recvrequest(cmd, argv[2], argv[1], "w", 0, 0); 1149 1150 /* flush results in case commands are coming from a pipe */ 1151 fflush(stdout); 1152 freels: 1153 if (argv[2] != globargv2) /* free up after globulize() */ 1154 free(argv[2]); 1155 if (globargv2 != oldargv2) 1156 free(globargv2); 1157 } 1158 1159 /* 1160 * Get a directory listing of multiple remote files. 1161 */ 1162 void 1163 mls(argc, argv) 1164 int argc; 1165 char *argv[]; 1166 { 1167 sig_t oldintr; 1168 int ointer, i; 1169 int dolist; 1170 char mode[1], *dest, *odest; 1171 1172 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1173 goto usage; 1174 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1175 usage: 1176 printf("usage: %s remote-files local-file\n", argv[0]); 1177 code = -1; 1178 return; 1179 } 1180 odest = dest = argv[argc - 1]; 1181 argv[argc - 1] = NULL; 1182 if (strcmp(dest, "-") && *dest != '|') 1183 if (!globulize(&dest) || 1184 !confirm("output to local-file:", dest)) { 1185 code = -1; 1186 return; 1187 } 1188 dolist = strcmp(argv[0], "mls"); 1189 mname = argv[0]; 1190 mflag = 1; 1191 oldintr = signal(SIGINT, mabort); 1192 (void)setjmp(jabort); 1193 for (i = 1; mflag && i < argc-1; ++i) { 1194 *mode = (i == 1) ? 'w' : 'a'; 1195 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode, 1196 0, 0); 1197 if (!mflag && fromatty) { 1198 ointer = interactive; 1199 interactive = 1; 1200 if (confirm("Continue with", argv[0])) { 1201 mflag ++; 1202 } 1203 interactive = ointer; 1204 } 1205 } 1206 (void)signal(SIGINT, oldintr); 1207 mflag = 0; 1208 if (dest != odest) /* free up after globulize() */ 1209 free(dest); 1210 } 1211 1212 /* 1213 * Do a shell escape 1214 */ 1215 /*ARGSUSED*/ 1216 void 1217 shell(argc, argv) 1218 int argc; 1219 char *argv[]; 1220 { 1221 pid_t pid; 1222 sig_t old1, old2; 1223 char shellnam[MAXPATHLEN], *shell, *namep; 1224 int wait_status; 1225 1226 old1 = signal (SIGINT, SIG_IGN); 1227 old2 = signal (SIGQUIT, SIG_IGN); 1228 if ((pid = fork()) == 0) { 1229 for (pid = 3; pid < 20; pid++) 1230 (void)close(pid); 1231 (void)signal(SIGINT, SIG_DFL); 1232 (void)signal(SIGQUIT, SIG_DFL); 1233 shell = getenv("SHELL"); 1234 if (shell == NULL) 1235 shell = _PATH_BSHELL; 1236 namep = strrchr(shell, '/'); 1237 if (namep == NULL) 1238 namep = shell; 1239 shellnam[0] = '-'; 1240 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2); 1241 shellnam[sizeof(shellnam) - 1] = '\0'; 1242 if (strcmp(namep, "sh") != 0) 1243 shellnam[0] = '+'; 1244 if (debug) { 1245 puts(shell); 1246 (void)fflush(stdout); 1247 } 1248 if (argc > 1) { 1249 execl(shell, shellnam, "-c", altarg, (char *)0); 1250 } 1251 else { 1252 execl(shell, shellnam, (char *)0); 1253 } 1254 warn("%s", shell); 1255 code = -1; 1256 exit(1); 1257 } 1258 if (pid > 0) 1259 while (wait(&wait_status) != pid) 1260 ; 1261 (void)signal(SIGINT, old1); 1262 (void)signal(SIGQUIT, old2); 1263 if (pid == -1) { 1264 warn("Try again later"); 1265 code = -1; 1266 } 1267 else { 1268 code = 0; 1269 } 1270 } 1271 1272 /* 1273 * Send new user information (re-login) 1274 */ 1275 void 1276 user(argc, argv) 1277 int argc; 1278 char *argv[]; 1279 { 1280 char acct[80]; 1281 int n, aflag = 0; 1282 1283 if (argc < 2) 1284 (void)another(&argc, &argv, "username"); 1285 if (argc < 2 || argc > 4) { 1286 printf("usage: %s username [password] [account]\n", argv[0]); 1287 code = -1; 1288 return; 1289 } 1290 n = command("USER %s", argv[1]); 1291 if (n == CONTINUE) { 1292 if (argc < 3 ) 1293 argv[2] = getpass("Password: "), argc++; 1294 n = command("PASS %s", argv[2]); 1295 } 1296 if (n == CONTINUE) { 1297 if (argc < 4) { 1298 (void)fputs("Account: ", stdout); 1299 (void)fflush(stdout); 1300 (void)fgets(acct, sizeof(acct) - 1, stdin); 1301 acct[strlen(acct) - 1] = '\0'; 1302 argv[3] = acct; argc++; 1303 } 1304 n = command("ACCT %s", argv[3]); 1305 aflag++; 1306 } 1307 if (n != COMPLETE) { 1308 puts("Login failed."); 1309 return; 1310 } 1311 if (!aflag && argc == 4) { 1312 (void)command("ACCT %s", argv[3]); 1313 } 1314 connected = -1; 1315 } 1316 1317 /* 1318 * Print working directory on remote machine. 1319 */ 1320 /*VARARGS*/ 1321 void 1322 pwd(argc, argv) 1323 int argc; 1324 char *argv[]; 1325 { 1326 int oldverbose = verbose; 1327 1328 /* 1329 * If we aren't verbose, this doesn't do anything! 1330 */ 1331 verbose = 1; 1332 if (command("PWD") == ERROR && code == 500) { 1333 puts("PWD command not recognized, trying XPWD."); 1334 (void)command("XPWD"); 1335 } 1336 verbose = oldverbose; 1337 } 1338 1339 /* 1340 * Print working directory on local machine. 1341 */ 1342 void 1343 lpwd(argc, argv) 1344 int argc; 1345 char *argv[]; 1346 { 1347 char buf[MAXPATHLEN]; 1348 1349 if (getcwd(buf, sizeof(buf)) != NULL) 1350 printf("Local directory %s\n", buf); 1351 else 1352 warn("getcwd"); 1353 code = 0; 1354 } 1355 1356 /* 1357 * Make a directory. 1358 */ 1359 void 1360 makedir(argc, argv) 1361 int argc; 1362 char *argv[]; 1363 { 1364 1365 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1366 argc > 2) { 1367 printf("usage: %s directory-name\n", argv[0]); 1368 code = -1; 1369 return; 1370 } 1371 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1372 if (verbose) 1373 puts("MKD command not recognized, trying XMKD."); 1374 (void)command("XMKD %s", argv[1]); 1375 } 1376 } 1377 1378 /* 1379 * Remove a directory. 1380 */ 1381 void 1382 removedir(argc, argv) 1383 int argc; 1384 char *argv[]; 1385 { 1386 1387 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1388 argc > 2) { 1389 printf("usage: %s directory-name\n", argv[0]); 1390 code = -1; 1391 return; 1392 } 1393 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1394 if (verbose) 1395 puts("RMD command not recognized, trying XRMD."); 1396 (void)command("XRMD %s", argv[1]); 1397 } 1398 } 1399 1400 /* 1401 * Send a line, verbatim, to the remote machine. 1402 */ 1403 void 1404 quote(argc, argv) 1405 int argc; 1406 char *argv[]; 1407 { 1408 1409 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1410 printf("usage: %s line-to-send\n", argv[0]); 1411 code = -1; 1412 return; 1413 } 1414 quote1("", argc, argv); 1415 } 1416 1417 /* 1418 * Send a SITE command to the remote machine. The line 1419 * is sent verbatim to the remote machine, except that the 1420 * word "SITE" is added at the front. 1421 */ 1422 void 1423 site(argc, argv) 1424 int argc; 1425 char *argv[]; 1426 { 1427 1428 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1429 printf("usage: %s line-to-send\n", argv[0]); 1430 code = -1; 1431 return; 1432 } 1433 quote1("SITE ", argc, argv); 1434 } 1435 1436 /* 1437 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1438 * Send the result as a one-line command and get response. 1439 */ 1440 void 1441 quote1(initial, argc, argv) 1442 const char *initial; 1443 int argc; 1444 char *argv[]; 1445 { 1446 int i, len; 1447 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1448 1449 (void)strncpy(buf, initial, sizeof(buf) - 1); 1450 buf[sizeof(buf) - 1] = '\0'; 1451 if (argc > 1) { 1452 len = strlen(buf); 1453 len += strlen(strncpy(&buf[len], argv[1], 1454 sizeof(buf) - len - 1)); 1455 for (i = 2; i < argc && len < sizeof(buf); i++) { 1456 buf[len++] = ' '; 1457 len += strlen(strncpy(&buf[len], argv[i], 1458 sizeof(buf) - len) - 1); 1459 } 1460 } 1461 if (command(buf) == PRELIM) { 1462 while (getreply(0) == PRELIM) 1463 continue; 1464 } 1465 } 1466 1467 void 1468 do_chmod(argc, argv) 1469 int argc; 1470 char *argv[]; 1471 { 1472 1473 if (argc < 2 && !another(&argc, &argv, "mode")) 1474 goto usage; 1475 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) { 1476 usage: 1477 printf("usage: %s mode file-name\n", argv[0]); 1478 code = -1; 1479 return; 1480 } 1481 (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1482 } 1483 1484 void 1485 do_umask(argc, argv) 1486 int argc; 1487 char *argv[]; 1488 { 1489 int oldverbose = verbose; 1490 1491 verbose = 1; 1492 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1493 verbose = oldverbose; 1494 } 1495 1496 void 1497 idle(argc, argv) 1498 int argc; 1499 char *argv[]; 1500 { 1501 int oldverbose = verbose; 1502 1503 verbose = 1; 1504 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1505 verbose = oldverbose; 1506 } 1507 1508 /* 1509 * Ask the other side for help. 1510 */ 1511 void 1512 rmthelp(argc, argv) 1513 int argc; 1514 char *argv[]; 1515 { 1516 int oldverbose = verbose; 1517 1518 verbose = 1; 1519 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1520 verbose = oldverbose; 1521 } 1522 1523 /* 1524 * Terminate session and exit. 1525 */ 1526 /*VARARGS*/ 1527 void 1528 quit(argc, argv) 1529 int argc; 1530 char *argv[]; 1531 { 1532 1533 if (connected) 1534 disconnect(0, 0); 1535 pswitch(1); 1536 if (connected) { 1537 disconnect(0, 0); 1538 } 1539 exit(0); 1540 } 1541 1542 /* 1543 * Terminate session, but don't exit. 1544 */ 1545 void 1546 disconnect(argc, argv) 1547 int argc; 1548 char *argv[]; 1549 { 1550 1551 if (!connected) 1552 return; 1553 (void)command("QUIT"); 1554 if (cout) { 1555 (void)fclose(cout); 1556 } 1557 cout = NULL; 1558 connected = 0; 1559 data = -1; 1560 if (!proxy) { 1561 macnum = 0; 1562 } 1563 } 1564 1565 void 1566 account(argc, argv) 1567 int argc; 1568 char *argv[]; 1569 { 1570 char *ap; 1571 1572 if (argc > 2) { 1573 printf("usage: %s [password]\n", argv[0]); 1574 code = -1; 1575 return; 1576 } 1577 else if (argc == 2) 1578 ap = argv[1]; 1579 else 1580 ap = getpass("Account:"); 1581 (void)command("ACCT %s", ap); 1582 } 1583 1584 jmp_buf abortprox; 1585 1586 void 1587 proxabort(notused) 1588 int notused; 1589 { 1590 1591 alarmtimer(0); 1592 if (!proxy) { 1593 pswitch(1); 1594 } 1595 if (connected) { 1596 proxflag = 1; 1597 } 1598 else { 1599 proxflag = 0; 1600 } 1601 pswitch(0); 1602 longjmp(abortprox, 1); 1603 } 1604 1605 void 1606 doproxy(argc, argv) 1607 int argc; 1608 char *argv[]; 1609 { 1610 struct cmd *c; 1611 int cmdpos; 1612 sig_t oldintr; 1613 1614 if (argc < 2 && !another(&argc, &argv, "command")) { 1615 printf("usage: %s command\n", argv[0]); 1616 code = -1; 1617 return; 1618 } 1619 c = getcmd(argv[1]); 1620 if (c == (struct cmd *) -1) { 1621 puts("?Ambiguous command."); 1622 (void)fflush(stdout); 1623 code = -1; 1624 return; 1625 } 1626 if (c == 0) { 1627 puts("?Invalid command."); 1628 (void)fflush(stdout); 1629 code = -1; 1630 return; 1631 } 1632 if (!c->c_proxy) { 1633 puts("?Invalid proxy command."); 1634 (void)fflush(stdout); 1635 code = -1; 1636 return; 1637 } 1638 if (setjmp(abortprox)) { 1639 code = -1; 1640 return; 1641 } 1642 oldintr = signal(SIGINT, proxabort); 1643 pswitch(1); 1644 if (c->c_conn && !connected) { 1645 puts("Not connected."); 1646 (void)fflush(stdout); 1647 pswitch(0); 1648 (void)signal(SIGINT, oldintr); 1649 code = -1; 1650 return; 1651 } 1652 cmdpos = strcspn(line, " \t"); 1653 if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1654 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1655 (*c->c_handler)(argc-1, argv+1); 1656 if (connected) { 1657 proxflag = 1; 1658 } 1659 else { 1660 proxflag = 0; 1661 } 1662 pswitch(0); 1663 (void)signal(SIGINT, oldintr); 1664 } 1665 1666 void 1667 setcase(argc, argv) 1668 int argc; 1669 char *argv[]; 1670 { 1671 1672 code = togglevar(argc, argv, &mcase, "Case mapping"); 1673 } 1674 1675 void 1676 setcr(argc, argv) 1677 int argc; 1678 char *argv[]; 1679 { 1680 1681 code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1682 } 1683 1684 void 1685 setntrans(argc, argv) 1686 int argc; 1687 char *argv[]; 1688 { 1689 if (argc == 1) { 1690 ntflag = 0; 1691 puts("Ntrans off."); 1692 code = ntflag; 1693 return; 1694 } 1695 ntflag++; 1696 code = ntflag; 1697 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1); 1698 ntin[sizeof(ntin) - 1] = '\0'; 1699 if (argc == 2) { 1700 ntout[0] = '\0'; 1701 return; 1702 } 1703 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1); 1704 ntout[sizeof(ntout) - 1] = '\0'; 1705 } 1706 1707 char * 1708 dotrans(name) 1709 char *name; 1710 { 1711 static char new[MAXPATHLEN]; 1712 char *cp1, *cp2 = new; 1713 int i, ostop, found; 1714 1715 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1716 continue; 1717 for (cp1 = name; *cp1; cp1++) { 1718 found = 0; 1719 for (i = 0; *(ntin + i) && i < 16; i++) { 1720 if (*cp1 == *(ntin + i)) { 1721 found++; 1722 if (i < ostop) { 1723 *cp2++ = *(ntout + i); 1724 } 1725 break; 1726 } 1727 } 1728 if (!found) { 1729 *cp2++ = *cp1; 1730 } 1731 } 1732 *cp2 = '\0'; 1733 return (new); 1734 } 1735 1736 void 1737 setnmap(argc, argv) 1738 int argc; 1739 char *argv[]; 1740 { 1741 char *cp; 1742 1743 if (argc == 1) { 1744 mapflag = 0; 1745 puts("Nmap off."); 1746 code = mapflag; 1747 return; 1748 } 1749 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 1750 printf("usage: %s [mapin mapout]\n", argv[0]); 1751 code = -1; 1752 return; 1753 } 1754 mapflag = 1; 1755 code = 1; 1756 cp = strchr(altarg, ' '); 1757 if (proxy) { 1758 while(*++cp == ' ') 1759 continue; 1760 altarg = cp; 1761 cp = strchr(altarg, ' '); 1762 } 1763 *cp = '\0'; 1764 (void)strncpy(mapin, altarg, MAXPATHLEN - 1); 1765 while (*++cp == ' ') 1766 continue; 1767 (void)strncpy(mapout, cp, MAXPATHLEN - 1); 1768 } 1769 1770 char * 1771 domap(name) 1772 char *name; 1773 { 1774 static char new[MAXPATHLEN]; 1775 char *cp1 = name, *cp2 = mapin; 1776 char *tp[9], *te[9]; 1777 int i, toks[9], toknum = 0, match = 1; 1778 1779 for (i=0; i < 9; ++i) { 1780 toks[i] = 0; 1781 } 1782 while (match && *cp1 && *cp2) { 1783 switch (*cp2) { 1784 case '\\': 1785 if (*++cp2 != *cp1) { 1786 match = 0; 1787 } 1788 break; 1789 case '$': 1790 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1791 if (*cp1 != *(++cp2+1)) { 1792 toks[toknum = *cp2 - '1']++; 1793 tp[toknum] = cp1; 1794 while (*++cp1 && *(cp2+1) 1795 != *cp1); 1796 te[toknum] = cp1; 1797 } 1798 cp2++; 1799 break; 1800 } 1801 /* FALLTHROUGH */ 1802 default: 1803 if (*cp2 != *cp1) { 1804 match = 0; 1805 } 1806 break; 1807 } 1808 if (match && *cp1) { 1809 cp1++; 1810 } 1811 if (match && *cp2) { 1812 cp2++; 1813 } 1814 } 1815 if (!match && *cp1) /* last token mismatch */ 1816 { 1817 toks[toknum] = 0; 1818 } 1819 cp1 = new; 1820 *cp1 = '\0'; 1821 cp2 = mapout; 1822 while (*cp2) { 1823 match = 0; 1824 switch (*cp2) { 1825 case '\\': 1826 if (*(cp2 + 1)) { 1827 *cp1++ = *++cp2; 1828 } 1829 break; 1830 case '[': 1831 LOOP: 1832 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1833 if (*++cp2 == '0') { 1834 char *cp3 = name; 1835 1836 while (*cp3) { 1837 *cp1++ = *cp3++; 1838 } 1839 match = 1; 1840 } 1841 else if (toks[toknum = *cp2 - '1']) { 1842 char *cp3 = tp[toknum]; 1843 1844 while (cp3 != te[toknum]) { 1845 *cp1++ = *cp3++; 1846 } 1847 match = 1; 1848 } 1849 } 1850 else { 1851 while (*cp2 && *cp2 != ',' && 1852 *cp2 != ']') { 1853 if (*cp2 == '\\') { 1854 cp2++; 1855 } 1856 else if (*cp2 == '$' && 1857 isdigit(*(cp2+1))) { 1858 if (*++cp2 == '0') { 1859 char *cp3 = name; 1860 1861 while (*cp3) { 1862 *cp1++ = *cp3++; 1863 } 1864 } 1865 else if (toks[toknum = 1866 *cp2 - '1']) { 1867 char *cp3=tp[toknum]; 1868 1869 while (cp3 != 1870 te[toknum]) { 1871 *cp1++ = *cp3++; 1872 } 1873 } 1874 } 1875 else if (*cp2) { 1876 *cp1++ = *cp2++; 1877 } 1878 } 1879 if (!*cp2) { 1880 puts( 1881 "nmap: unbalanced brackets."); 1882 return (name); 1883 } 1884 match = 1; 1885 cp2--; 1886 } 1887 if (match) { 1888 while (*++cp2 && *cp2 != ']') { 1889 if (*cp2 == '\\' && *(cp2 + 1)) { 1890 cp2++; 1891 } 1892 } 1893 if (!*cp2) { 1894 puts( 1895 "nmap: unbalanced brackets."); 1896 return (name); 1897 } 1898 break; 1899 } 1900 switch (*++cp2) { 1901 case ',': 1902 goto LOOP; 1903 case ']': 1904 break; 1905 default: 1906 cp2--; 1907 goto LOOP; 1908 } 1909 break; 1910 case '$': 1911 if (isdigit(*(cp2 + 1))) { 1912 if (*++cp2 == '0') { 1913 char *cp3 = name; 1914 1915 while (*cp3) { 1916 *cp1++ = *cp3++; 1917 } 1918 } 1919 else if (toks[toknum = *cp2 - '1']) { 1920 char *cp3 = tp[toknum]; 1921 1922 while (cp3 != te[toknum]) { 1923 *cp1++ = *cp3++; 1924 } 1925 } 1926 break; 1927 } 1928 /* intentional drop through */ 1929 default: 1930 *cp1++ = *cp2; 1931 break; 1932 } 1933 cp2++; 1934 } 1935 *cp1 = '\0'; 1936 if (!*new) { 1937 return (name); 1938 } 1939 return (new); 1940 } 1941 1942 void 1943 setpassive(argc, argv) 1944 int argc; 1945 char *argv[]; 1946 { 1947 1948 code = togglevar(argc, argv, &passivemode, 1949 verbose ? "Passive mode" : NULL); 1950 } 1951 1952 void 1953 setsunique(argc, argv) 1954 int argc; 1955 char *argv[]; 1956 { 1957 1958 code = togglevar(argc, argv, &sunique, "Store unique"); 1959 } 1960 1961 void 1962 setrunique(argc, argv) 1963 int argc; 1964 char *argv[]; 1965 { 1966 1967 code = togglevar(argc, argv, &runique, "Receive unique"); 1968 } 1969 1970 /* change directory to parent directory */ 1971 void 1972 cdup(argc, argv) 1973 int argc; 1974 char *argv[]; 1975 { 1976 int r; 1977 1978 r = command("CDUP"); 1979 if (r == ERROR && code == 500) { 1980 if (verbose) 1981 puts("CDUP command not recognized, trying XCUP."); 1982 r = command("XCUP"); 1983 } 1984 if (r == COMPLETE) 1985 dirchange = 1; 1986 } 1987 1988 /* 1989 * Restart transfer at specific point 1990 */ 1991 void 1992 restart(argc, argv) 1993 int argc; 1994 char *argv[]; 1995 { 1996 1997 if (argc != 2) 1998 puts("restart: offset not specified."); 1999 else { 2000 restart_point = atol(argv[1]); 2001 printf("Restarting at %qd. Execute get, put or append to " 2002 "initiate transfer\n", (long long)restart_point); 2003 } 2004 } 2005 2006 /* 2007 * Show remote system type 2008 */ 2009 void 2010 syst(argc, argv) 2011 int argc; 2012 char *argv[]; 2013 { 2014 2015 (void)command("SYST"); 2016 } 2017 2018 void 2019 macdef(argc, argv) 2020 int argc; 2021 char *argv[]; 2022 { 2023 char *tmp; 2024 int c; 2025 2026 if (macnum == 16) { 2027 puts("Limit of 16 macros have already been defined."); 2028 code = -1; 2029 return; 2030 } 2031 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2032 printf("usage: %s macro_name\n", argv[0]); 2033 code = -1; 2034 return; 2035 } 2036 if (interactive) 2037 puts( 2038 "Enter macro line by line, terminating it with a null line."); 2039 (void)strncpy(macros[macnum].mac_name, argv[1], 2040 sizeof(macros[macnum].mac_name) - 1); 2041 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0'; 2042 if (macnum == 0) 2043 macros[macnum].mac_start = macbuf; 2044 else 2045 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2046 tmp = macros[macnum].mac_start; 2047 while (tmp != macbuf+4096) { 2048 if ((c = getchar()) == EOF) { 2049 puts("macdef: end of file encountered."); 2050 code = -1; 2051 return; 2052 } 2053 if ((*tmp = c) == '\n') { 2054 if (tmp == macros[macnum].mac_start) { 2055 macros[macnum++].mac_end = tmp; 2056 code = 0; 2057 return; 2058 } 2059 if (*(tmp-1) == '\0') { 2060 macros[macnum++].mac_end = tmp - 1; 2061 code = 0; 2062 return; 2063 } 2064 *tmp = '\0'; 2065 } 2066 tmp++; 2067 } 2068 while (1) { 2069 while ((c = getchar()) != '\n' && c != EOF) 2070 /* LOOP */; 2071 if (c == EOF || getchar() == '\n') { 2072 puts("Macro not defined - 4K buffer exceeded."); 2073 code = -1; 2074 return; 2075 } 2076 } 2077 } 2078 2079 /* 2080 * Get size of file on remote machine 2081 */ 2082 void 2083 sizecmd(argc, argv) 2084 int argc; 2085 char *argv[]; 2086 { 2087 off_t size; 2088 2089 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2090 printf("usage: %s filename\n", argv[0]); 2091 code = -1; 2092 return; 2093 } 2094 size = remotesize(argv[1], 1); 2095 if (size != -1) 2096 printf("%s\t%qd\n", argv[1], (long long)size); 2097 code = size; 2098 } 2099 2100 /* 2101 * Get last modification time of file on remote machine 2102 */ 2103 void 2104 modtime(argc, argv) 2105 int argc; 2106 char *argv[]; 2107 { 2108 time_t mtime; 2109 2110 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2111 printf("usage: %s filename\n", argv[0]); 2112 code = -1; 2113 return; 2114 } 2115 mtime = remotemodtime(argv[1], 1); 2116 if (mtime != -1) 2117 printf("%s\t%s", argv[1], asctime(localtime(&mtime))); 2118 code = mtime; 2119 } 2120 2121 /* 2122 * Show status on remote machine 2123 */ 2124 void 2125 rmtstatus(argc, argv) 2126 int argc; 2127 char *argv[]; 2128 { 2129 2130 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 2131 } 2132 2133 /* 2134 * Get file if modtime is more recent than current file 2135 */ 2136 void 2137 newer(argc, argv) 2138 int argc; 2139 char *argv[]; 2140 { 2141 2142 if (getit(argc, argv, -1, "w")) 2143 printf("Local file \"%s\" is newer than remote file \"%s\".\n", 2144 argv[2], argv[1]); 2145 } 2146 2147 /* 2148 * Display one file through $PAGER (defaults to "more"). 2149 */ 2150 void 2151 page(argc, argv) 2152 int argc; 2153 char *argv[]; 2154 { 2155 int orestart_point, ohash, overbose; 2156 char *p, *pager, *oldargv1; 2157 2158 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2159 printf("usage: %s filename\n", argv[0]); 2160 code = -1; 2161 return; 2162 } 2163 oldargv1 = argv[1]; 2164 if (!globulize(&argv[1])) { 2165 code = -1; 2166 return; 2167 } 2168 p = getenv("PAGER"); 2169 if (p == NULL) 2170 p = PAGER; 2171 if ((pager = malloc(strlen(p) + 2)) == NULL) 2172 errx(1, "Can't allocate memory for $PAGER"); 2173 (void)sprintf(pager, "|%s", p); 2174 2175 orestart_point = restart_point; 2176 ohash = hash; 2177 overbose = verbose; 2178 restart_point = hash = verbose = 0; 2179 recvrequest("RETR", pager, argv[1], "r+w", 1, 0); 2180 (void)free(pager); 2181 restart_point = orestart_point; 2182 hash = ohash; 2183 verbose = overbose; 2184 if (oldargv1 != argv[1]) /* free up after globulize() */ 2185 free(argv[1]); 2186 } 2187