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