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