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