1 /* $NetBSD: cmds.c,v 1.103 2004/06/06 01:37:41 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1996-2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 12 * NASA Ames Research Center. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the NetBSD 25 * Foundation, Inc. and its contributors. 26 * 4. Neither the name of The NetBSD Foundation nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /* 44 * Copyright (c) 1985, 1989, 1993, 1994 45 * The Regents of the University of California. All rights reserved. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 */ 71 72 /* 73 * Copyright (C) 1997 and 1998 WIDE Project. 74 * All rights reserved. 75 * 76 * Redistribution and use in source and binary forms, with or without 77 * modification, are permitted provided that the following conditions 78 * are met: 79 * 1. Redistributions of source code must retain the above copyright 80 * notice, this list of conditions and the following disclaimer. 81 * 2. Redistributions in binary form must reproduce the above copyright 82 * notice, this list of conditions and the following disclaimer in the 83 * documentation and/or other materials provided with the distribution. 84 * 3. Neither the name of the project nor the names of its contributors 85 * may be used to endorse or promote products derived from this software 86 * without specific prior written permission. 87 * 88 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 91 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 98 * SUCH DAMAGE. 99 */ 100 101 #include <sys/cdefs.h> 102 #ifndef lint 103 #if 0 104 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; 105 #else 106 __RCSID("$NetBSD: cmds.c,v 1.103 2004/06/06 01:37:41 christos Exp $"); 107 #endif 108 #endif /* not lint */ 109 110 /* 111 * FTP User Program -- Command Routines. 112 */ 113 #include <sys/types.h> 114 #include <sys/socket.h> 115 #include <sys/stat.h> 116 #include <sys/wait.h> 117 #include <arpa/ftp.h> 118 119 #include <ctype.h> 120 #include <err.h> 121 #include <glob.h> 122 #include <limits.h> 123 #include <netdb.h> 124 #include <paths.h> 125 #include <stdio.h> 126 #include <stdlib.h> 127 #include <string.h> 128 #include <time.h> 129 #include <unistd.h> 130 131 #include "ftp_var.h" 132 #include "version.h" 133 134 struct types { 135 char *t_name; 136 char *t_mode; 137 int t_type; 138 char *t_arg; 139 } types[] = { 140 { "ascii", "A", TYPE_A, 0 }, 141 { "binary", "I", TYPE_I, 0 }, 142 { "image", "I", TYPE_I, 0 }, 143 { "ebcdic", "E", TYPE_E, 0 }, 144 { "tenex", "L", TYPE_L, bytename }, 145 { NULL } 146 }; 147 148 sigjmp_buf jabort; 149 char *mname; 150 151 static int confirm(const char *, const char *); 152 153 static int 154 confirm(const char *cmd, const char *file) 155 { 156 char line[BUFSIZ]; 157 158 if (!interactive || confirmrest) 159 return (1); 160 while (1) { 161 fprintf(ttyout, "%s %s [anpqy?]? ", cmd, file); 162 (void)fflush(ttyout); 163 if (fgets(line, sizeof(line), stdin) == NULL) { 164 mflag = 0; 165 fprintf(ttyout, "\nEOF received; %s aborted\n", mname); 166 clearerr(stdin); 167 return (0); 168 } 169 switch (tolower(*line)) { 170 case 'a': 171 confirmrest = 1; 172 fprintf(ttyout, 173 "Prompting off for duration of %s.\n", cmd); 174 break; 175 case 'p': 176 interactive = 0; 177 fputs("Interactive mode: off.\n", ttyout); 178 break; 179 case 'q': 180 mflag = 0; 181 fprintf(ttyout, "%s aborted.\n", mname); 182 /* FALLTHROUGH */ 183 case 'n': 184 return (0); 185 case '?': 186 fprintf(ttyout, 187 " confirmation options:\n" 188 "\ta answer `yes' for the duration of %s\n" 189 "\tn answer `no' for this file\n" 190 "\tp turn off `prompt' mode\n" 191 "\tq stop the current %s\n" 192 "\ty answer `yes' for this file\n" 193 "\t? this help list\n", 194 cmd, cmd); 195 continue; /* back to while(1) */ 196 } 197 return (1); 198 } 199 /* NOTREACHED */ 200 } 201 202 /* 203 * Set transfer type. 204 */ 205 void 206 settype(int argc, char *argv[]) 207 { 208 struct types *p; 209 int comret; 210 211 if (argc == 0 || argc > 2) { 212 char *sep; 213 214 fprintf(ttyout, "usage: %s [", argv[0]); 215 sep = " "; 216 for (p = types; p->t_name; p++) { 217 fprintf(ttyout, "%s%s", sep, p->t_name); 218 sep = " | "; 219 } 220 fputs(" ]\n", ttyout); 221 code = -1; 222 return; 223 } 224 if (argc < 2) { 225 fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 226 code = 0; 227 return; 228 } 229 for (p = types; p->t_name; p++) 230 if (strcmp(argv[1], p->t_name) == 0) 231 break; 232 if (p->t_name == 0) { 233 fprintf(ttyout, "%s: unknown mode.\n", argv[1]); 234 code = -1; 235 return; 236 } 237 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 238 comret = command("TYPE %s %s", p->t_mode, p->t_arg); 239 else 240 comret = command("TYPE %s", p->t_mode); 241 if (comret == COMPLETE) { 242 (void)strlcpy(typename, p->t_name, sizeof(typename)); 243 curtype = type = p->t_type; 244 } 245 } 246 247 /* 248 * Internal form of settype; changes current type in use with server 249 * without changing our notion of the type for data transfers. 250 * Used to change to and from ascii for listings. 251 */ 252 void 253 changetype(int newtype, int show) 254 { 255 struct types *p; 256 int comret, oldverbose = verbose; 257 258 if (newtype == 0) 259 newtype = TYPE_I; 260 if (newtype == curtype) 261 return; 262 if (debug == 0 && show == 0) 263 verbose = 0; 264 for (p = types; p->t_name; p++) 265 if (newtype == p->t_type) 266 break; 267 if (p->t_name == 0) { 268 warnx("internal error: unknown type %d.", newtype); 269 return; 270 } 271 if (newtype == TYPE_L && bytename[0] != '\0') 272 comret = command("TYPE %s %s", p->t_mode, bytename); 273 else 274 comret = command("TYPE %s", p->t_mode); 275 if (comret == COMPLETE) 276 curtype = newtype; 277 verbose = oldverbose; 278 } 279 280 char *stype[] = { 281 "type", 282 "", 283 0 284 }; 285 286 /* 287 * Set binary transfer type. 288 */ 289 /*VARARGS*/ 290 void 291 setbinary(int argc, char *argv[]) 292 { 293 294 if (argc == 0) { 295 fprintf(ttyout, "usage: %s\n", argv[0]); 296 code = -1; 297 return; 298 } 299 stype[1] = "binary"; 300 settype(2, stype); 301 } 302 303 /* 304 * Set ascii transfer type. 305 */ 306 /*VARARGS*/ 307 void 308 setascii(int argc, char *argv[]) 309 { 310 311 if (argc == 0) { 312 fprintf(ttyout, "usage: %s\n", argv[0]); 313 code = -1; 314 return; 315 } 316 stype[1] = "ascii"; 317 settype(2, stype); 318 } 319 320 /* 321 * Set tenex transfer type. 322 */ 323 /*VARARGS*/ 324 void 325 settenex(int argc, char *argv[]) 326 { 327 328 if (argc == 0) { 329 fprintf(ttyout, "usage: %s\n", argv[0]); 330 code = -1; 331 return; 332 } 333 stype[1] = "tenex"; 334 settype(2, stype); 335 } 336 337 /* 338 * Set file transfer mode. 339 */ 340 /*ARGSUSED*/ 341 void 342 setftmode(int argc, char *argv[]) 343 { 344 345 if (argc != 2) { 346 fprintf(ttyout, "usage: %s mode-name\n", argv[0]); 347 code = -1; 348 return; 349 } 350 fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 351 code = -1; 352 } 353 354 /* 355 * Set file transfer format. 356 */ 357 /*ARGSUSED*/ 358 void 359 setform(int argc, char *argv[]) 360 { 361 362 if (argc != 2) { 363 fprintf(ttyout, "usage: %s format\n", argv[0]); 364 code = -1; 365 return; 366 } 367 fprintf(ttyout, "We only support %s format, sorry.\n", formname); 368 code = -1; 369 } 370 371 /* 372 * Set file transfer structure. 373 */ 374 /*ARGSUSED*/ 375 void 376 setstruct(int argc, char *argv[]) 377 { 378 379 if (argc != 2) { 380 fprintf(ttyout, "usage: %s struct-mode\n", argv[0]); 381 code = -1; 382 return; 383 } 384 fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 385 code = -1; 386 } 387 388 /* 389 * Send a single file. 390 */ 391 void 392 put(int argc, char *argv[]) 393 { 394 char *cmd; 395 int loc = 0; 396 char *locfile, *remfile; 397 398 if (argc == 2) { 399 argc++; 400 argv[2] = argv[1]; 401 loc++; 402 } 403 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file"))) 404 goto usage; 405 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 406 usage: 407 fprintf(ttyout, "usage: %s local-file [remote-file]\n", 408 argv[0]); 409 code = -1; 410 return; 411 } 412 if ((locfile = globulize(argv[1])) == NULL) { 413 code = -1; 414 return; 415 } 416 remfile = argv[2]; 417 if (loc) /* If argv[2] is a copy of the old argv[1], update it */ 418 remfile = locfile; 419 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 420 if (loc && ntflag) 421 remfile = dotrans(remfile); 422 if (loc && mapflag) 423 remfile = domap(remfile); 424 sendrequest(cmd, locfile, remfile, 425 locfile != argv[1] || remfile != argv[2]); 426 free(locfile); 427 } 428 429 /* 430 * Send multiple files. 431 */ 432 void 433 mput(int argc, char *argv[]) 434 { 435 int i; 436 sigfunc oldintr; 437 int ointer; 438 char *tp; 439 440 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) { 441 fprintf(ttyout, "usage: %s local-files\n", argv[0]); 442 code = -1; 443 return; 444 } 445 mname = argv[0]; 446 mflag = 1; 447 oldintr = xsignal(SIGINT, mintr); 448 if (sigsetjmp(jabort, 1)) 449 mabort(); 450 if (proxy) { 451 char *cp; 452 453 while ((cp = remglob(argv, 0, NULL)) != NULL) { 454 if (*cp == '\0' || !connected) { 455 mflag = 0; 456 continue; 457 } 458 if (mflag && confirm(argv[0], cp)) { 459 tp = cp; 460 if (mcase) 461 tp = docase(tp); 462 if (ntflag) 463 tp = dotrans(tp); 464 if (mapflag) 465 tp = domap(tp); 466 sendrequest((sunique) ? "STOU" : "STOR", 467 cp, tp, cp != tp || !interactive); 468 if (!mflag && fromatty) { 469 ointer = interactive; 470 interactive = 1; 471 if (confirm("Continue with", "mput")) { 472 mflag++; 473 } 474 interactive = ointer; 475 } 476 } 477 } 478 goto cleanupmput; 479 } 480 for (i = 1; i < argc && connected; i++) { 481 char **cpp; 482 glob_t gl; 483 int flags; 484 485 if (!doglob) { 486 if (mflag && confirm(argv[0], argv[i])) { 487 tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 488 tp = (mapflag) ? domap(tp) : tp; 489 sendrequest((sunique) ? "STOU" : "STOR", 490 argv[i], tp, tp != argv[i] || !interactive); 491 if (!mflag && fromatty) { 492 ointer = interactive; 493 interactive = 1; 494 if (confirm("Continue with", "mput")) { 495 mflag++; 496 } 497 interactive = ointer; 498 } 499 } 500 continue; 501 } 502 503 memset(&gl, 0, sizeof(gl)); 504 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 505 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 506 warnx("%s: not found", argv[i]); 507 globfree(&gl); 508 continue; 509 } 510 for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected; 511 cpp++) { 512 if (mflag && confirm(argv[0], *cpp)) { 513 tp = (ntflag) ? dotrans(*cpp) : *cpp; 514 tp = (mapflag) ? domap(tp) : tp; 515 sendrequest((sunique) ? "STOU" : "STOR", 516 *cpp, tp, *cpp != tp || !interactive); 517 if (!mflag && fromatty) { 518 ointer = interactive; 519 interactive = 1; 520 if (confirm("Continue with", "mput")) { 521 mflag++; 522 } 523 interactive = ointer; 524 } 525 } 526 } 527 globfree(&gl); 528 } 529 cleanupmput: 530 (void)xsignal(SIGINT, oldintr); 531 mflag = 0; 532 } 533 534 void 535 reget(int argc, char *argv[]) 536 { 537 538 (void)getit(argc, argv, 1, "r+"); 539 } 540 541 void 542 get(int argc, char *argv[]) 543 { 544 545 (void)getit(argc, argv, 0, restart_point ? "r+" : "w" ); 546 } 547 548 /* 549 * Receive one file. 550 * If restartit is 1, restart the xfer always. 551 * If restartit is -1, restart the xfer only if the remote file is newer. 552 */ 553 int 554 getit(int argc, char *argv[], int restartit, const char *mode) 555 { 556 int loc, rval; 557 char *remfile, *locfile, *olocfile; 558 559 loc = rval = 0; 560 if (argc == 2) { 561 argc++; 562 argv[2] = argv[1]; 563 loc++; 564 } 565 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file"))) 566 goto usage; 567 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 568 usage: 569 fprintf(ttyout, "usage: %s remote-file [local-file]\n", 570 argv[0]); 571 code = -1; 572 return (0); 573 } 574 remfile = argv[1]; 575 if ((olocfile = globulize(argv[2])) == NULL) { 576 code = -1; 577 return (0); 578 } 579 locfile = olocfile; 580 if (loc && mcase) 581 locfile = docase(locfile); 582 if (loc && ntflag) 583 locfile = dotrans(locfile); 584 if (loc && mapflag) 585 locfile = domap(locfile); 586 if (restartit) { 587 struct stat stbuf; 588 int ret; 589 590 if (! features[FEAT_REST_STREAM]) { 591 fprintf(ttyout, 592 "Restart is not supported by the remote server.\n"); 593 return (0); 594 } 595 ret = stat(locfile, &stbuf); 596 if (restartit == 1) { 597 if (ret < 0) { 598 warn("local: %s", locfile); 599 goto freegetit; 600 } 601 restart_point = stbuf.st_size; 602 } else { 603 if (ret == 0) { 604 time_t mtime; 605 606 mtime = remotemodtime(argv[1], 0); 607 if (mtime == -1) 608 goto freegetit; 609 if (stbuf.st_mtime >= mtime) { 610 rval = 1; 611 goto freegetit; 612 } 613 } 614 } 615 } 616 617 recvrequest("RETR", locfile, remfile, mode, 618 remfile != argv[1] || locfile != argv[2], loc); 619 restart_point = 0; 620 freegetit: 621 (void)free(olocfile); 622 return (rval); 623 } 624 625 /* ARGSUSED */ 626 void 627 mintr(int signo) 628 { 629 630 alarmtimer(0); 631 if (fromatty) 632 write(fileno(ttyout), "\n", 1); 633 siglongjmp(jabort, 1); 634 } 635 636 void 637 mabort(void) 638 { 639 int ointer, oconf; 640 641 if (mflag && fromatty) { 642 ointer = interactive; 643 oconf = confirmrest; 644 interactive = 1; 645 confirmrest = 0; 646 if (confirm("Continue with", mname)) { 647 interactive = ointer; 648 confirmrest = oconf; 649 return; 650 } 651 interactive = ointer; 652 confirmrest = oconf; 653 } 654 mflag = 0; 655 } 656 657 /* 658 * Get multiple files. 659 */ 660 void 661 mget(int argc, char *argv[]) 662 { 663 sigfunc oldintr; 664 int ointer; 665 char *cp, *tp; 666 int restartit; 667 668 if (argc == 0 || 669 (argc == 1 && !another(&argc, &argv, "remote-files"))) { 670 fprintf(ttyout, "usage: %s remote-files\n", argv[0]); 671 code = -1; 672 return; 673 } 674 mname = argv[0]; 675 mflag = 1; 676 restart_point = 0; 677 restartit = 0; 678 if (strcmp(argv[0], "mreget") == 0) { 679 if (! features[FEAT_REST_STREAM]) { 680 fprintf(ttyout, 681 "Restart is not supported by the remote server.\n"); 682 return; 683 } 684 restartit = 1; 685 } 686 oldintr = xsignal(SIGINT, mintr); 687 if (sigsetjmp(jabort, 1)) 688 mabort(); 689 while ((cp = remglob(argv, proxy, NULL)) != NULL) { 690 if (*cp == '\0' || !connected) { 691 mflag = 0; 692 continue; 693 } 694 if (! mflag || !confirm(argv[0], cp)) 695 continue; 696 tp = cp; 697 if (mcase) 698 tp = docase(tp); 699 if (ntflag) 700 tp = dotrans(tp); 701 if (mapflag) 702 tp = domap(tp); 703 if (restartit) { 704 struct stat stbuf; 705 706 if (stat(tp, &stbuf) == 0) 707 restart_point = stbuf.st_size; 708 else 709 warn("stat %s", tp); 710 } 711 recvrequest("RETR", tp, cp, restart_point ? "r+" : "w", 712 tp != cp || !interactive, 1); 713 restart_point = 0; 714 if (!mflag && fromatty) { 715 ointer = interactive; 716 interactive = 1; 717 if (confirm("Continue with", "mget")) 718 mflag++; 719 interactive = ointer; 720 } 721 } 722 (void)xsignal(SIGINT, oldintr); 723 mflag = 0; 724 } 725 726 /* 727 * Read list of filenames from a local file and get those 728 */ 729 void 730 fget(int argc, char *argv[]) 731 { 732 char *buf, *mode; 733 FILE *fp; 734 735 if (argc != 2) { 736 fprintf(ttyout, "usage: %s localfile\n", argv[0]); 737 code = -1; 738 return; 739 } 740 741 fp = fopen(argv[1], "r"); 742 if (fp == NULL) { 743 fprintf(ttyout, "Cannot open source file %s\n", argv[1]); 744 code = -1; 745 return; 746 } 747 748 argv[0] = "get"; 749 mode = restart_point ? "r+" : "w"; 750 751 for (; 752 (buf = fparseln(fp, NULL, NULL, "\0\0\0", 0)) != NULL; 753 free(buf)) { 754 if (buf[0] == '\0') 755 continue; 756 argv[1] = buf; 757 (void)getit(argc, argv, 0, mode); 758 } 759 fclose(fp); 760 } 761 762 char * 763 onoff(int bool) 764 { 765 766 return (bool ? "on" : "off"); 767 } 768 769 /* 770 * Show status. 771 */ 772 /*ARGSUSED*/ 773 void 774 status(int argc, char *argv[]) 775 { 776 int i; 777 778 if (argc == 0) { 779 fprintf(ttyout, "usage: %s\n", argv[0]); 780 code = -1; 781 return; 782 } 783 #ifdef NO_STATUS 784 if (connected) 785 fprintf(ttyout, "Connected %sto %s.\n", 786 connected == -1 ? "and logged in" : "", hostname); 787 else 788 fputs("Not connected.\n", ttyout); 789 if (!proxy) { 790 pswitch(1); 791 if (connected) { 792 fprintf(ttyout, "Connected for proxy commands to %s.\n", 793 hostname); 794 } 795 else { 796 fputs("No proxy connection.\n", ttyout); 797 } 798 pswitch(0); 799 } 800 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 801 *gateserver ? gateserver : "(none)", gateport); 802 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 803 onoff(passivemode), onoff(activefallback)); 804 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 805 modename, typename, formname, structname); 806 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 807 onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); 808 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", 809 onoff(sunique), onoff(runique)); 810 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 811 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), 812 onoff(crflag)); 813 if (ntflag) { 814 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 815 } 816 else { 817 fputs("Ntrans: off.\n", ttyout); 818 } 819 if (mapflag) { 820 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 821 } 822 else { 823 fputs("Nmap: off.\n", ttyout); 824 } 825 fprintf(ttyout, 826 "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 827 onoff(hash), mark, onoff(progress)); 828 fprintf(ttyout, 829 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 830 onoff(rate_get), rate_get, rate_get_incr); 831 fprintf(ttyout, 832 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 833 onoff(rate_put), rate_put, rate_put_incr); 834 fprintf(ttyout, 835 "Socket buffer sizes: send %d, receive %d.\n", 836 sndbuf_size, rcvbuf_size); 837 fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); 838 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 839 epsv4bad ? " (disabled for this connection)" : ""); 840 fprintf(ttyout, "Command line editing: %s.\n", 841 #ifdef NO_EDITCOMPLETE 842 "support not compiled in" 843 #else /* !def NO_EDITCOMPLETE */ 844 onoff(editing) 845 #endif /* !def NO_EDITCOMPLETE */ 846 ); 847 if (macnum > 0) { 848 fputs("Macros:\n", ttyout); 849 for (i=0; i<macnum; i++) { 850 fprintf(ttyout, "\t%s\n", macros[i].mac_name); 851 } 852 } 853 #endif 854 fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION); 855 code = 0; 856 } 857 858 /* 859 * Toggle a variable 860 */ 861 int 862 togglevar(int argc, char *argv[], int *var, const char *mesg) 863 { 864 if (argc == 1) { 865 *var = !*var; 866 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 867 *var = 1; 868 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 869 *var = 0; 870 } else { 871 fprintf(ttyout, "usage: %s [ on | off ]\n", argv[0]); 872 return (-1); 873 } 874 if (mesg) 875 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 876 return (*var); 877 } 878 879 /* 880 * Set beep on cmd completed mode. 881 */ 882 /*VARARGS*/ 883 void 884 setbell(int argc, char *argv[]) 885 { 886 887 code = togglevar(argc, argv, &bell, "Bell mode"); 888 } 889 890 /* 891 * Set command line editing 892 */ 893 /*VARARGS*/ 894 void 895 setedit(int argc, char *argv[]) 896 { 897 898 #ifdef NO_EDITCOMPLETE 899 if (argc == 0) { 900 fprintf(ttyout, "usage: %s\n", argv[0]); 901 code = -1; 902 return; 903 } 904 if (verbose) 905 fputs("Editing support not compiled in; ignoring command.\n", 906 ttyout); 907 #else /* !def NO_EDITCOMPLETE */ 908 code = togglevar(argc, argv, &editing, "Editing mode"); 909 controlediting(); 910 #endif /* !def NO_EDITCOMPLETE */ 911 } 912 913 /* 914 * Turn on packet tracing. 915 */ 916 /*VARARGS*/ 917 void 918 settrace(int argc, char *argv[]) 919 { 920 921 code = togglevar(argc, argv, &trace, "Packet tracing"); 922 } 923 924 /* 925 * Toggle hash mark printing during transfers, or set hash mark bytecount. 926 */ 927 /*VARARGS*/ 928 void 929 sethash(int argc, char *argv[]) 930 { 931 if (argc == 1) 932 hash = !hash; 933 else if (argc != 2) { 934 fprintf(ttyout, "usage: %s [ on | off | bytecount ]\n", 935 argv[0]); 936 code = -1; 937 return; 938 } else if (strcasecmp(argv[1], "on") == 0) 939 hash = 1; 940 else if (strcasecmp(argv[1], "off") == 0) 941 hash = 0; 942 else { 943 int nmark; 944 945 nmark = strsuftoi(argv[1]); 946 if (nmark < 1) { 947 fprintf(ttyout, "mark: bad bytecount value `%s'.\n", 948 argv[1]); 949 code = -1; 950 return; 951 } 952 mark = nmark; 953 hash = 1; 954 } 955 fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 956 if (hash) 957 fprintf(ttyout, " (%d bytes/hash mark)", mark); 958 fputs(".\n", ttyout); 959 if (hash) 960 progress = 0; 961 code = hash; 962 } 963 964 /* 965 * Turn on printing of server echo's. 966 */ 967 /*VARARGS*/ 968 void 969 setverbose(int argc, char *argv[]) 970 { 971 972 code = togglevar(argc, argv, &verbose, "Verbose mode"); 973 } 974 975 /* 976 * Toggle PORT/LPRT cmd use before each data connection. 977 */ 978 /*VARARGS*/ 979 void 980 setport(int argc, char *argv[]) 981 { 982 983 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 984 } 985 986 /* 987 * Toggle transfer progress bar. 988 */ 989 /*VARARGS*/ 990 void 991 setprogress(int argc, char *argv[]) 992 { 993 994 code = togglevar(argc, argv, &progress, "Progress bar"); 995 if (progress) 996 hash = 0; 997 } 998 999 /* 1000 * Turn on interactive prompting during mget, mput, and mdelete. 1001 */ 1002 /*VARARGS*/ 1003 void 1004 setprompt(int argc, char *argv[]) 1005 { 1006 1007 code = togglevar(argc, argv, &interactive, "Interactive mode"); 1008 } 1009 1010 /* 1011 * Toggle gate-ftp mode, or set gate-ftp server 1012 */ 1013 /*VARARGS*/ 1014 void 1015 setgate(int argc, char *argv[]) 1016 { 1017 static char gsbuf[MAXHOSTNAMELEN]; 1018 1019 if (argc == 0 || argc > 3) { 1020 fprintf(ttyout, 1021 "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); 1022 code = -1; 1023 return; 1024 } else if (argc < 2) { 1025 gatemode = !gatemode; 1026 } else { 1027 if (argc == 2 && strcasecmp(argv[1], "on") == 0) 1028 gatemode = 1; 1029 else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 1030 gatemode = 0; 1031 else { 1032 if (argc == 3) 1033 gateport = xstrdup(argv[2]); 1034 (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 1035 gateserver = gsbuf; 1036 gatemode = 1; 1037 } 1038 } 1039 if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 1040 fprintf(ttyout, 1041 "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 1042 gatemode = 0; 1043 } else { 1044 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 1045 onoff(gatemode), *gateserver ? gateserver : "(none)", 1046 gateport); 1047 } 1048 code = gatemode; 1049 } 1050 1051 /* 1052 * Toggle metacharacter interpretation on local file names. 1053 */ 1054 /*VARARGS*/ 1055 void 1056 setglob(int argc, char *argv[]) 1057 { 1058 1059 code = togglevar(argc, argv, &doglob, "Globbing"); 1060 } 1061 1062 /* 1063 * Toggle preserving modification times on retrieved files. 1064 */ 1065 /*VARARGS*/ 1066 void 1067 setpreserve(int argc, char *argv[]) 1068 { 1069 1070 code = togglevar(argc, argv, &preserve, "Preserve modification times"); 1071 } 1072 1073 /* 1074 * Set debugging mode on/off and/or set level of debugging. 1075 */ 1076 /*VARARGS*/ 1077 void 1078 setdebug(int argc, char *argv[]) 1079 { 1080 if (argc == 0 || argc > 2) { 1081 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n", 1082 argv[0]); 1083 code = -1; 1084 return; 1085 } else if (argc == 2) { 1086 if (strcasecmp(argv[1], "on") == 0) 1087 debug = 1; 1088 else if (strcasecmp(argv[1], "off") == 0) 1089 debug = 0; 1090 else { 1091 int val; 1092 1093 val = strsuftoi(argv[1]); 1094 if (val < 0) { 1095 fprintf(ttyout, "%s: bad debugging value.\n", 1096 argv[1]); 1097 code = -1; 1098 return; 1099 } 1100 debug = val; 1101 } 1102 } else 1103 debug = !debug; 1104 if (debug) 1105 options |= SO_DEBUG; 1106 else 1107 options &= ~SO_DEBUG; 1108 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug); 1109 code = debug > 0; 1110 } 1111 1112 /* 1113 * Set current working directory on remote machine. 1114 */ 1115 void 1116 cd(int argc, char *argv[]) 1117 { 1118 int r; 1119 1120 if (argc == 0 || argc > 2 || 1121 (argc == 1 && !another(&argc, &argv, "remote-directory"))) { 1122 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); 1123 code = -1; 1124 return; 1125 } 1126 r = command("CWD %s", argv[1]); 1127 if (r == ERROR && code == 500) { 1128 if (verbose) 1129 fputs("CWD command not recognized, trying XCWD.\n", 1130 ttyout); 1131 r = command("XCWD %s", argv[1]); 1132 } 1133 if (r == COMPLETE) { 1134 dirchange = 1; 1135 updateremotepwd(); 1136 } 1137 } 1138 1139 /* 1140 * Set current working directory on local machine. 1141 */ 1142 void 1143 lcd(int argc, char *argv[]) 1144 { 1145 char buf[MAXPATHLEN]; 1146 char *locdir; 1147 1148 code = -1; 1149 if (argc == 1) { 1150 argc++; 1151 argv[1] = localhome; 1152 } 1153 if (argc != 2) { 1154 fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]); 1155 return; 1156 } 1157 if ((locdir = globulize(argv[1])) == NULL) 1158 return; 1159 if (chdir(locdir) < 0) 1160 warn("local: %s", locdir); 1161 else { 1162 if (getcwd(buf, sizeof(buf)) != NULL) { 1163 fprintf(ttyout, "Local directory now %s\n", buf); 1164 code = 0; 1165 } else 1166 warn("getcwd: %s", locdir); 1167 } 1168 (void)free(locdir); 1169 } 1170 1171 /* 1172 * Delete a single file. 1173 */ 1174 void 1175 delete(int argc, char *argv[]) 1176 { 1177 1178 1179 if (argc == 0 || argc > 2 || 1180 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 1181 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 1182 code = -1; 1183 return; 1184 } 1185 if (command("DELE %s", argv[1]) == COMPLETE) 1186 dirchange = 1; 1187 } 1188 1189 /* 1190 * Delete multiple files. 1191 */ 1192 void 1193 mdelete(int argc, char *argv[]) 1194 { 1195 sigfunc oldintr; 1196 int ointer; 1197 char *cp; 1198 1199 if (argc == 0 || 1200 (argc == 1 && !another(&argc, &argv, "remote-files"))) { 1201 fprintf(ttyout, "usage: %s [remote-files]\n", argv[0]); 1202 code = -1; 1203 return; 1204 } 1205 mname = argv[0]; 1206 mflag = 1; 1207 oldintr = xsignal(SIGINT, mintr); 1208 if (sigsetjmp(jabort, 1)) 1209 mabort(); 1210 while ((cp = remglob(argv, 0, NULL)) != NULL) { 1211 if (*cp == '\0') { 1212 mflag = 0; 1213 continue; 1214 } 1215 if (mflag && confirm(argv[0], cp)) { 1216 if (command("DELE %s", cp) == COMPLETE) 1217 dirchange = 1; 1218 if (!mflag && fromatty) { 1219 ointer = interactive; 1220 interactive = 1; 1221 if (confirm("Continue with", "mdelete")) { 1222 mflag++; 1223 } 1224 interactive = ointer; 1225 } 1226 } 1227 } 1228 (void)xsignal(SIGINT, oldintr); 1229 mflag = 0; 1230 } 1231 1232 /* 1233 * Rename a remote file. 1234 */ 1235 void 1236 renamefile(int argc, char *argv[]) 1237 { 1238 1239 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) 1240 goto usage; 1241 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1242 usage: 1243 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]); 1244 code = -1; 1245 return; 1246 } 1247 if (command("RNFR %s", argv[1]) == CONTINUE && 1248 command("RNTO %s", argv[2]) == COMPLETE) 1249 dirchange = 1; 1250 } 1251 1252 /* 1253 * Get a directory listing of remote files. 1254 * Supports being invoked as: 1255 * cmd runs 1256 * --- ---- 1257 * dir, ls LIST 1258 * mlsd MLSD 1259 * nlist NLST 1260 * pdir, pls LIST |$PAGER 1261 * mmlsd MLSD |$PAGER 1262 */ 1263 void 1264 ls(int argc, char *argv[]) 1265 { 1266 const char *cmd; 1267 char *remdir, *locfile; 1268 int freelocfile, pagecmd, mlsdcmd; 1269 1270 remdir = NULL; 1271 locfile = "-"; 1272 freelocfile = pagecmd = mlsdcmd = 0; 1273 /* 1274 * the only commands that start with `p' are 1275 * the `pager' versions. 1276 */ 1277 if (argv[0][0] == 'p') 1278 pagecmd = 1; 1279 if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { 1280 if (! features[FEAT_MLST]) { 1281 fprintf(ttyout, 1282 "MLSD is not supported by the remote server.\n"); 1283 return; 1284 } 1285 mlsdcmd = 1; 1286 } 1287 if (argc == 0) 1288 goto usage; 1289 1290 if (mlsdcmd) 1291 cmd = "MLSD"; 1292 else if (strcmp(argv[0] + pagecmd, "nlist") == 0) 1293 cmd = "NLST"; 1294 else 1295 cmd = "LIST"; 1296 1297 if (argc > 1) 1298 remdir = argv[1]; 1299 if (argc > 2) 1300 locfile = argv[2]; 1301 if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { 1302 usage: 1303 if (pagecmd || mlsdcmd) 1304 fprintf(ttyout, 1305 "usage: %s [remote-path]\n", argv[0]); 1306 else 1307 fprintf(ttyout, 1308 "usage: %s [remote-path [local-file]]\n", 1309 argv[0]); 1310 code = -1; 1311 goto freels; 1312 } 1313 1314 if (pagecmd) { 1315 char *p; 1316 int len; 1317 1318 p = getoptionvalue("pager"); 1319 if (EMPTYSTRING(p)) 1320 p = DEFAULTPAGER; 1321 len = strlen(p) + 2; 1322 locfile = xmalloc(len); 1323 locfile[0] = '|'; 1324 (void)strlcpy(locfile + 1, p, len - 1); 1325 freelocfile = 1; 1326 } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') { 1327 if ((locfile = globulize(locfile)) == NULL || 1328 !confirm("output to local-file:", locfile)) { 1329 code = -1; 1330 goto freels; 1331 } 1332 freelocfile = 1; 1333 } 1334 recvrequest(cmd, locfile, remdir, "w", 0, 0); 1335 freels: 1336 if (freelocfile && locfile) 1337 (void)free(locfile); 1338 } 1339 1340 /* 1341 * Get a directory listing of multiple remote files. 1342 */ 1343 void 1344 mls(int argc, char *argv[]) 1345 { 1346 sigfunc oldintr; 1347 int ointer, i; 1348 int dolist; 1349 char *mode, *dest, *odest; 1350 1351 if (argc == 0) 1352 goto usage; 1353 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1354 goto usage; 1355 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1356 usage: 1357 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]); 1358 code = -1; 1359 return; 1360 } 1361 odest = dest = argv[argc - 1]; 1362 argv[argc - 1] = NULL; 1363 if (strcmp(dest, "-") && *dest != '|') 1364 if (((dest = globulize(dest)) == NULL) || 1365 !confirm("output to local-file:", dest)) { 1366 code = -1; 1367 return; 1368 } 1369 dolist = strcmp(argv[0], "mls"); 1370 mname = argv[0]; 1371 mflag = 1; 1372 oldintr = xsignal(SIGINT, mintr); 1373 if (sigsetjmp(jabort, 1)) 1374 mabort(); 1375 for (i = 1; mflag && i < argc-1 && connected; i++) { 1376 mode = (i == 1) ? "w" : "a"; 1377 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode, 1378 0, 0); 1379 if (!mflag && fromatty) { 1380 ointer = interactive; 1381 interactive = 1; 1382 if (confirm("Continue with", argv[0])) { 1383 mflag ++; 1384 } 1385 interactive = ointer; 1386 } 1387 } 1388 (void)xsignal(SIGINT, oldintr); 1389 mflag = 0; 1390 if (dest != odest) /* free up after globulize() */ 1391 free(dest); 1392 } 1393 1394 /* 1395 * Do a shell escape 1396 */ 1397 /*ARGSUSED*/ 1398 void 1399 shell(int argc, char *argv[]) 1400 { 1401 pid_t pid; 1402 sigfunc old1; 1403 char shellnam[MAXPATHLEN], *shell, *namep; 1404 int wait_status; 1405 1406 if (argc == 0) { 1407 fprintf(ttyout, "usage: %s [command [args]]\n", argv[0]); 1408 code = -1; 1409 return; 1410 } 1411 old1 = xsignal(SIGINT, SIG_IGN); 1412 if ((pid = fork()) == 0) { 1413 for (pid = 3; pid < 20; pid++) 1414 (void)close(pid); 1415 (void)xsignal(SIGINT, SIG_DFL); 1416 shell = getenv("SHELL"); 1417 if (shell == NULL) 1418 shell = _PATH_BSHELL; 1419 namep = strrchr(shell, '/'); 1420 if (namep == NULL) 1421 namep = shell; 1422 else 1423 namep++; 1424 (void)strlcpy(shellnam, namep, sizeof(shellnam)); 1425 if (debug) { 1426 fputs(shell, ttyout); 1427 putc('\n', ttyout); 1428 } 1429 if (argc > 1) { 1430 execl(shell, shellnam, "-c", altarg, (char *)0); 1431 } 1432 else { 1433 execl(shell, shellnam, (char *)0); 1434 } 1435 warn("%s", shell); 1436 code = -1; 1437 exit(1); 1438 } 1439 if (pid > 0) 1440 while (wait(&wait_status) != pid) 1441 ; 1442 (void)xsignal(SIGINT, old1); 1443 if (pid == -1) { 1444 warn("Try again later"); 1445 code = -1; 1446 } else 1447 code = 0; 1448 } 1449 1450 /* 1451 * Send new user information (re-login) 1452 */ 1453 void 1454 user(int argc, char *argv[]) 1455 { 1456 char acct[80]; 1457 int n, aflag = 0; 1458 1459 if (argc == 0) 1460 goto usage; 1461 if (argc < 2) 1462 (void)another(&argc, &argv, "username"); 1463 if (argc < 2 || argc > 4) { 1464 usage: 1465 fprintf(ttyout, "usage: %s username [password [account]]\n", 1466 argv[0]); 1467 code = -1; 1468 return; 1469 } 1470 n = command("USER %s", argv[1]); 1471 if (n == CONTINUE) { 1472 if (argc < 3) { 1473 argv[2] = getpass("Password: "); 1474 argc++; 1475 } 1476 n = command("PASS %s", argv[2]); 1477 } 1478 if (n == CONTINUE) { 1479 if (argc < 4) { 1480 (void)fputs("Account: ", ttyout); 1481 (void)fflush(ttyout); 1482 if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) { 1483 fprintf(ttyout, 1484 "\nEOF received; login aborted.\n"); 1485 clearerr(stdin); 1486 code = -1; 1487 return; 1488 } 1489 acct[strlen(acct) - 1] = '\0'; 1490 argv[3] = acct; argc++; 1491 } 1492 n = command("ACCT %s", argv[3]); 1493 aflag++; 1494 } 1495 if (n != COMPLETE) { 1496 fputs("Login failed.\n", ttyout); 1497 return; 1498 } 1499 if (!aflag && argc == 4) { 1500 (void)command("ACCT %s", argv[3]); 1501 } 1502 connected = -1; 1503 getremoteinfo(); 1504 } 1505 1506 /* 1507 * Print working directory on remote machine. 1508 */ 1509 /*VARARGS*/ 1510 void 1511 pwd(int argc, char *argv[]) 1512 { 1513 int oldverbose = verbose; 1514 1515 if (argc == 0) { 1516 fprintf(ttyout, "usage: %s\n", argv[0]); 1517 code = -1; 1518 return; 1519 } 1520 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 1521 if (command("PWD") == ERROR && code == 500) { 1522 fputs("PWD command not recognized, trying XPWD.\n", ttyout); 1523 (void)command("XPWD"); 1524 } 1525 verbose = oldverbose; 1526 } 1527 1528 /* 1529 * Print working directory on local machine. 1530 */ 1531 void 1532 lpwd(int argc, char *argv[]) 1533 { 1534 char buf[MAXPATHLEN]; 1535 1536 if (argc == 0) { 1537 fprintf(ttyout, "usage: %s\n", argv[0]); 1538 code = -1; 1539 return; 1540 } 1541 if (getcwd(buf, sizeof(buf)) != NULL) { 1542 fprintf(ttyout, "Local directory %s\n", buf); 1543 code = 0; 1544 } else { 1545 warn("getcwd"); 1546 code = -1; 1547 } 1548 } 1549 1550 /* 1551 * Make a directory. 1552 */ 1553 void 1554 makedir(int argc, char *argv[]) 1555 { 1556 int r; 1557 1558 if (argc == 0 || argc > 2 || 1559 (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1560 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1561 code = -1; 1562 return; 1563 } 1564 r = command("MKD %s", argv[1]); 1565 if (r == ERROR && code == 500) { 1566 if (verbose) 1567 fputs("MKD command not recognized, trying XMKD.\n", 1568 ttyout); 1569 r = command("XMKD %s", argv[1]); 1570 } 1571 if (r == COMPLETE) 1572 dirchange = 1; 1573 } 1574 1575 /* 1576 * Remove a directory. 1577 */ 1578 void 1579 removedir(int argc, char *argv[]) 1580 { 1581 int r; 1582 1583 if (argc == 0 || argc > 2 || 1584 (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1585 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1586 code = -1; 1587 return; 1588 } 1589 r = command("RMD %s", argv[1]); 1590 if (r == ERROR && code == 500) { 1591 if (verbose) 1592 fputs("RMD command not recognized, trying XRMD.\n", 1593 ttyout); 1594 r = command("XRMD %s", argv[1]); 1595 } 1596 if (r == COMPLETE) 1597 dirchange = 1; 1598 } 1599 1600 /* 1601 * Send a line, verbatim, to the remote machine. 1602 */ 1603 void 1604 quote(int argc, char *argv[]) 1605 { 1606 1607 if (argc == 0 || 1608 (argc == 1 && !another(&argc, &argv, "command line to send"))) { 1609 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1610 code = -1; 1611 return; 1612 } 1613 quote1("", argc, argv); 1614 } 1615 1616 /* 1617 * Send a SITE command to the remote machine. The line 1618 * is sent verbatim to the remote machine, except that the 1619 * word "SITE" is added at the front. 1620 */ 1621 void 1622 site(int argc, char *argv[]) 1623 { 1624 1625 if (argc == 0 || 1626 (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ 1627 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1628 code = -1; 1629 return; 1630 } 1631 quote1("SITE ", argc, argv); 1632 } 1633 1634 /* 1635 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1636 * Send the result as a one-line command and get response. 1637 */ 1638 void 1639 quote1(const char *initial, int argc, char *argv[]) 1640 { 1641 int i; 1642 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1643 1644 (void)strlcpy(buf, initial, sizeof(buf)); 1645 for (i = 1; i < argc; i++) { 1646 (void)strlcat(buf, argv[i], sizeof(buf)); 1647 if (i < (argc - 1)) 1648 (void)strlcat(buf, " ", sizeof(buf)); 1649 } 1650 if (command("%s", buf) == PRELIM) { 1651 while (getreply(0) == PRELIM) 1652 continue; 1653 } 1654 dirchange = 1; 1655 } 1656 1657 void 1658 do_chmod(int argc, char *argv[]) 1659 { 1660 1661 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) 1662 goto usage; 1663 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 1664 usage: 1665 fprintf(ttyout, "usage: %s mode remote-file\n", argv[0]); 1666 code = -1; 1667 return; 1668 } 1669 (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1670 } 1671 1672 #define COMMAND_1ARG(argc, argv, cmd) \ 1673 if (argc == 1) \ 1674 command(cmd); \ 1675 else \ 1676 command(cmd " %s", argv[1]) 1677 1678 void 1679 do_umask(int argc, char *argv[]) 1680 { 1681 int oldverbose = verbose; 1682 1683 if (argc == 0) { 1684 fprintf(ttyout, "usage: %s [umask]\n", argv[0]); 1685 code = -1; 1686 return; 1687 } 1688 verbose = 1; 1689 COMMAND_1ARG(argc, argv, "SITE UMASK"); 1690 verbose = oldverbose; 1691 } 1692 1693 void 1694 idlecmd(int argc, char *argv[]) 1695 { 1696 int oldverbose = verbose; 1697 1698 if (argc < 1 || argc > 2) { 1699 fprintf(ttyout, "usage: %s [seconds]\n", argv[0]); 1700 code = -1; 1701 return; 1702 } 1703 verbose = 1; 1704 COMMAND_1ARG(argc, argv, "SITE IDLE"); 1705 verbose = oldverbose; 1706 } 1707 1708 /* 1709 * Ask the other side for help. 1710 */ 1711 void 1712 rmthelp(int argc, char *argv[]) 1713 { 1714 int oldverbose = verbose; 1715 1716 if (argc == 0) { 1717 fprintf(ttyout, "usage: %s\n", argv[0]); 1718 code = -1; 1719 return; 1720 } 1721 verbose = 1; 1722 COMMAND_1ARG(argc, argv, "HELP"); 1723 verbose = oldverbose; 1724 } 1725 1726 /* 1727 * Terminate session and exit. 1728 * May be called with 0, NULL. 1729 */ 1730 /*VARARGS*/ 1731 void 1732 quit(int argc, char *argv[]) 1733 { 1734 1735 /* this may be called with argc == 0, argv == NULL */ 1736 if (argc == 0 && argv != NULL) { 1737 fprintf(ttyout, "usage: %s\n", argv[0]); 1738 code = -1; 1739 return; 1740 } 1741 if (connected) 1742 disconnect(0, NULL); 1743 pswitch(1); 1744 if (connected) 1745 disconnect(0, NULL); 1746 exit(0); 1747 } 1748 1749 /* 1750 * Terminate session, but don't exit. 1751 * May be called with 0, NULL. 1752 */ 1753 void 1754 disconnect(int argc, char *argv[]) 1755 { 1756 1757 /* this may be called with argc == 0, argv == NULL */ 1758 if (argc == 0 && argv != NULL) { 1759 fprintf(ttyout, "usage: %s\n", argv[0]); 1760 code = -1; 1761 return; 1762 } 1763 if (!connected) 1764 return; 1765 (void)command("QUIT"); 1766 cleanuppeer(); 1767 } 1768 1769 void 1770 account(int argc, char *argv[]) 1771 { 1772 char *ap; 1773 1774 if (argc == 0 || argc > 2) { 1775 fprintf(ttyout, "usage: %s [password]\n", argv[0]); 1776 code = -1; 1777 return; 1778 } 1779 else if (argc == 2) 1780 ap = argv[1]; 1781 else 1782 ap = getpass("Account:"); 1783 (void)command("ACCT %s", ap); 1784 } 1785 1786 sigjmp_buf abortprox; 1787 1788 void 1789 proxabort(int notused) 1790 { 1791 1792 alarmtimer(0); 1793 if (!proxy) { 1794 pswitch(1); 1795 } 1796 if (connected) { 1797 proxflag = 1; 1798 } 1799 else { 1800 proxflag = 0; 1801 } 1802 pswitch(0); 1803 siglongjmp(abortprox, 1); 1804 } 1805 1806 void 1807 doproxy(int argc, char *argv[]) 1808 { 1809 struct cmd *c; 1810 int cmdpos; 1811 sigfunc oldintr; 1812 1813 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { 1814 fprintf(ttyout, "usage: %s command\n", argv[0]); 1815 code = -1; 1816 return; 1817 } 1818 c = getcmd(argv[1]); 1819 if (c == (struct cmd *) -1) { 1820 fputs("?Ambiguous command.\n", ttyout); 1821 code = -1; 1822 return; 1823 } 1824 if (c == 0) { 1825 fputs("?Invalid command.\n", ttyout); 1826 code = -1; 1827 return; 1828 } 1829 if (!c->c_proxy) { 1830 fputs("?Invalid proxy command.\n", ttyout); 1831 code = -1; 1832 return; 1833 } 1834 if (sigsetjmp(abortprox, 1)) { 1835 code = -1; 1836 return; 1837 } 1838 oldintr = xsignal(SIGINT, proxabort); 1839 pswitch(1); 1840 if (c->c_conn && !connected) { 1841 fputs("Not connected.\n", ttyout); 1842 pswitch(0); 1843 (void)xsignal(SIGINT, oldintr); 1844 code = -1; 1845 return; 1846 } 1847 cmdpos = strcspn(line, " \t"); 1848 if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1849 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1850 argv[1] = c->c_name; 1851 (*c->c_handler)(argc-1, argv+1); 1852 if (connected) { 1853 proxflag = 1; 1854 } 1855 else { 1856 proxflag = 0; 1857 } 1858 pswitch(0); 1859 (void)xsignal(SIGINT, oldintr); 1860 } 1861 1862 void 1863 setcase(int argc, char *argv[]) 1864 { 1865 1866 code = togglevar(argc, argv, &mcase, "Case mapping"); 1867 } 1868 1869 /* 1870 * convert the given name to lower case if it's all upper case, into 1871 * a static buffer which is returned to the caller 1872 */ 1873 char * 1874 docase(char *name) 1875 { 1876 static char new[MAXPATHLEN]; 1877 int i, dochange; 1878 1879 dochange = 1; 1880 for (i = 0; name[i] != '\0' && i < sizeof(new) - 1; i++) { 1881 new[i] = name[i]; 1882 if (islower((unsigned char)new[i])) 1883 dochange = 0; 1884 } 1885 new[i] = '\0'; 1886 1887 if (dochange) { 1888 for (i = 0; new[i] != '\0'; i++) 1889 if (isupper((unsigned char)new[i])) 1890 new[i] = tolower(new[i]); 1891 } 1892 return (new); 1893 } 1894 1895 void 1896 setcr(int argc, char *argv[]) 1897 { 1898 1899 code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1900 } 1901 1902 void 1903 setntrans(int argc, char *argv[]) 1904 { 1905 1906 if (argc == 0 || argc > 3) { 1907 fprintf(ttyout, "usage: %s [inchars [outchars]]\n", argv[0]); 1908 code = -1; 1909 return; 1910 } 1911 if (argc == 1) { 1912 ntflag = 0; 1913 fputs("Ntrans off.\n", ttyout); 1914 code = ntflag; 1915 return; 1916 } 1917 ntflag++; 1918 code = ntflag; 1919 (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1920 if (argc == 2) { 1921 ntout[0] = '\0'; 1922 return; 1923 } 1924 (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1925 } 1926 1927 char * 1928 dotrans(char *name) 1929 { 1930 static char new[MAXPATHLEN]; 1931 char *cp1, *cp2 = new; 1932 int i, ostop, found; 1933 1934 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1935 continue; 1936 for (cp1 = name; *cp1; cp1++) { 1937 found = 0; 1938 for (i = 0; *(ntin + i) && i < 16; i++) { 1939 if (*cp1 == *(ntin + i)) { 1940 found++; 1941 if (i < ostop) { 1942 *cp2++ = *(ntout + i); 1943 } 1944 break; 1945 } 1946 } 1947 if (!found) { 1948 *cp2++ = *cp1; 1949 } 1950 } 1951 *cp2 = '\0'; 1952 return (new); 1953 } 1954 1955 void 1956 setnmap(int argc, char *argv[]) 1957 { 1958 char *cp; 1959 1960 if (argc == 1) { 1961 mapflag = 0; 1962 fputs("Nmap off.\n", ttyout); 1963 code = mapflag; 1964 return; 1965 } 1966 if (argc == 0 || 1967 (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 1968 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]); 1969 code = -1; 1970 return; 1971 } 1972 mapflag = 1; 1973 code = 1; 1974 cp = strchr(altarg, ' '); 1975 if (proxy) { 1976 while(*++cp == ' ') 1977 continue; 1978 altarg = cp; 1979 cp = strchr(altarg, ' '); 1980 } 1981 *cp = '\0'; 1982 (void)strlcpy(mapin, altarg, MAXPATHLEN); 1983 while (*++cp == ' ') 1984 continue; 1985 (void)strlcpy(mapout, cp, MAXPATHLEN); 1986 } 1987 1988 char * 1989 domap(char *name) 1990 { 1991 static char new[MAXPATHLEN]; 1992 char *cp1 = name, *cp2 = mapin; 1993 char *tp[9], *te[9]; 1994 int i, toks[9], toknum = 0, match = 1; 1995 1996 for (i=0; i < 9; ++i) { 1997 toks[i] = 0; 1998 } 1999 while (match && *cp1 && *cp2) { 2000 switch (*cp2) { 2001 case '\\': 2002 if (*++cp2 != *cp1) { 2003 match = 0; 2004 } 2005 break; 2006 case '$': 2007 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 2008 if (*cp1 != *(++cp2+1)) { 2009 toks[toknum = *cp2 - '1']++; 2010 tp[toknum] = cp1; 2011 while (*++cp1 && *(cp2+1) 2012 != *cp1); 2013 te[toknum] = cp1; 2014 } 2015 cp2++; 2016 break; 2017 } 2018 /* FALLTHROUGH */ 2019 default: 2020 if (*cp2 != *cp1) { 2021 match = 0; 2022 } 2023 break; 2024 } 2025 if (match && *cp1) { 2026 cp1++; 2027 } 2028 if (match && *cp2) { 2029 cp2++; 2030 } 2031 } 2032 if (!match && *cp1) /* last token mismatch */ 2033 { 2034 toks[toknum] = 0; 2035 } 2036 cp1 = new; 2037 *cp1 = '\0'; 2038 cp2 = mapout; 2039 while (*cp2) { 2040 match = 0; 2041 switch (*cp2) { 2042 case '\\': 2043 if (*(cp2 + 1)) { 2044 *cp1++ = *++cp2; 2045 } 2046 break; 2047 case '[': 2048 LOOP: 2049 if (*++cp2 == '$' && 2050 isdigit((unsigned char)*(cp2+1))) { 2051 if (*++cp2 == '0') { 2052 char *cp3 = name; 2053 2054 while (*cp3) { 2055 *cp1++ = *cp3++; 2056 } 2057 match = 1; 2058 } 2059 else if (toks[toknum = *cp2 - '1']) { 2060 char *cp3 = tp[toknum]; 2061 2062 while (cp3 != te[toknum]) { 2063 *cp1++ = *cp3++; 2064 } 2065 match = 1; 2066 } 2067 } 2068 else { 2069 while (*cp2 && *cp2 != ',' && 2070 *cp2 != ']') { 2071 if (*cp2 == '\\') { 2072 cp2++; 2073 } 2074 else if (*cp2 == '$' && 2075 isdigit((unsigned char)*(cp2+1))) { 2076 if (*++cp2 == '0') { 2077 char *cp3 = name; 2078 2079 while (*cp3) { 2080 *cp1++ = *cp3++; 2081 } 2082 } 2083 else if (toks[toknum = 2084 *cp2 - '1']) { 2085 char *cp3=tp[toknum]; 2086 2087 while (cp3 != 2088 te[toknum]) { 2089 *cp1++ = *cp3++; 2090 } 2091 } 2092 } 2093 else if (*cp2) { 2094 *cp1++ = *cp2++; 2095 } 2096 } 2097 if (!*cp2) { 2098 fputs( 2099 "nmap: unbalanced brackets.\n", 2100 ttyout); 2101 return (name); 2102 } 2103 match = 1; 2104 cp2--; 2105 } 2106 if (match) { 2107 while (*++cp2 && *cp2 != ']') { 2108 if (*cp2 == '\\' && *(cp2 + 1)) { 2109 cp2++; 2110 } 2111 } 2112 if (!*cp2) { 2113 fputs( 2114 "nmap: unbalanced brackets.\n", 2115 ttyout); 2116 return (name); 2117 } 2118 break; 2119 } 2120 switch (*++cp2) { 2121 case ',': 2122 goto LOOP; 2123 case ']': 2124 break; 2125 default: 2126 cp2--; 2127 goto LOOP; 2128 } 2129 break; 2130 case '$': 2131 if (isdigit((unsigned char)*(cp2 + 1))) { 2132 if (*++cp2 == '0') { 2133 char *cp3 = name; 2134 2135 while (*cp3) { 2136 *cp1++ = *cp3++; 2137 } 2138 } 2139 else if (toks[toknum = *cp2 - '1']) { 2140 char *cp3 = tp[toknum]; 2141 2142 while (cp3 != te[toknum]) { 2143 *cp1++ = *cp3++; 2144 } 2145 } 2146 break; 2147 } 2148 /* intentional drop through */ 2149 default: 2150 *cp1++ = *cp2; 2151 break; 2152 } 2153 cp2++; 2154 } 2155 *cp1 = '\0'; 2156 if (!*new) { 2157 return (name); 2158 } 2159 return (new); 2160 } 2161 2162 void 2163 setpassive(int argc, char *argv[]) 2164 { 2165 2166 if (argc == 1) { 2167 passivemode = !passivemode; 2168 activefallback = passivemode; 2169 } else if (argc != 2) { 2170 passiveusage: 2171 fprintf(ttyout, "usage: %s [ on | off | auto ]\n", argv[0]); 2172 code = -1; 2173 return; 2174 } else if (strcasecmp(argv[1], "on") == 0) { 2175 passivemode = 1; 2176 activefallback = 0; 2177 } else if (strcasecmp(argv[1], "off") == 0) { 2178 passivemode = 0; 2179 activefallback = 0; 2180 } else if (strcasecmp(argv[1], "auto") == 0) { 2181 passivemode = 1; 2182 activefallback = 1; 2183 } else 2184 goto passiveusage; 2185 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 2186 onoff(passivemode), onoff(activefallback)); 2187 code = passivemode; 2188 } 2189 2190 void 2191 setepsv4(int argc, char *argv[]) 2192 { 2193 2194 code = togglevar(argc, argv, &epsv4, 2195 verbose ? "EPSV/EPRT on IPv4" : NULL); 2196 epsv4bad = 0; 2197 } 2198 2199 void 2200 setsunique(int argc, char *argv[]) 2201 { 2202 2203 code = togglevar(argc, argv, &sunique, "Store unique"); 2204 } 2205 2206 void 2207 setrunique(int argc, char *argv[]) 2208 { 2209 2210 code = togglevar(argc, argv, &runique, "Receive unique"); 2211 } 2212 2213 int 2214 parserate(int argc, char *argv[], int cmdlineopt) 2215 { 2216 int dir, max, incr, showonly; 2217 sigfunc oldusr1, oldusr2; 2218 2219 if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { 2220 usage: 2221 if (cmdlineopt) 2222 fprintf(ttyout, 2223 "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", 2224 argv[0]); 2225 else 2226 fprintf(ttyout, 2227 "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", 2228 argv[0]); 2229 return -1; 2230 } 2231 dir = max = incr = showonly = 0; 2232 #define RATE_GET 1 2233 #define RATE_PUT 2 2234 #define RATE_ALL (RATE_GET | RATE_PUT) 2235 2236 if (strcasecmp(argv[1], "all") == 0) 2237 dir = RATE_ALL; 2238 else if (strcasecmp(argv[1], "get") == 0) 2239 dir = RATE_GET; 2240 else if (strcasecmp(argv[1], "put") == 0) 2241 dir = RATE_PUT; 2242 else 2243 goto usage; 2244 2245 if (argc >= 3) { 2246 if ((max = strsuftoi(argv[2])) < 0) 2247 goto usage; 2248 } else 2249 showonly = 1; 2250 2251 if (argc == 4) { 2252 if ((incr = strsuftoi(argv[3])) <= 0) 2253 goto usage; 2254 } else 2255 incr = DEFAULTINCR; 2256 2257 oldusr1 = xsignal(SIGUSR1, SIG_IGN); 2258 oldusr2 = xsignal(SIGUSR2, SIG_IGN); 2259 if (dir & RATE_GET) { 2260 if (!showonly) { 2261 rate_get = max; 2262 rate_get_incr = incr; 2263 } 2264 if (!cmdlineopt || verbose) 2265 fprintf(ttyout, 2266 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 2267 onoff(rate_get), rate_get, rate_get_incr); 2268 } 2269 if (dir & RATE_PUT) { 2270 if (!showonly) { 2271 rate_put = max; 2272 rate_put_incr = incr; 2273 } 2274 if (!cmdlineopt || verbose) 2275 fprintf(ttyout, 2276 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 2277 onoff(rate_put), rate_put, rate_put_incr); 2278 } 2279 (void)xsignal(SIGUSR1, oldusr1); 2280 (void)xsignal(SIGUSR2, oldusr2); 2281 return 0; 2282 } 2283 2284 void 2285 setrate(int argc, char *argv[]) 2286 { 2287 2288 code = parserate(argc, argv, 0); 2289 } 2290 2291 /* change directory to parent directory */ 2292 void 2293 cdup(int argc, char *argv[]) 2294 { 2295 int r; 2296 2297 if (argc == 0) { 2298 fprintf(ttyout, "usage: %s\n", argv[0]); 2299 code = -1; 2300 return; 2301 } 2302 r = command("CDUP"); 2303 if (r == ERROR && code == 500) { 2304 if (verbose) 2305 fputs("CDUP command not recognized, trying XCUP.\n", 2306 ttyout); 2307 r = command("XCUP"); 2308 } 2309 if (r == COMPLETE) { 2310 dirchange = 1; 2311 updateremotepwd(); 2312 } 2313 } 2314 2315 /* 2316 * Restart transfer at specific point 2317 */ 2318 void 2319 restart(int argc, char *argv[]) 2320 { 2321 2322 if (argc == 0 || argc > 2) { 2323 fprintf(ttyout, "usage: %s [restart-point]\n", argv[0]); 2324 code = -1; 2325 return; 2326 } 2327 if (! features[FEAT_REST_STREAM]) { 2328 fprintf(ttyout, 2329 "Restart is not supported by the remote server.\n"); 2330 return; 2331 } 2332 if (argc == 2) { 2333 off_t rp; 2334 char *ep; 2335 2336 rp = STRTOLL(argv[1], &ep, 10); 2337 if (rp < 0 || *ep != '\0') 2338 fprintf(ttyout, "restart: Invalid offset `%s'\n", 2339 argv[1]); 2340 else 2341 restart_point = rp; 2342 } 2343 if (restart_point == 0) 2344 fputs("No restart point defined.\n", ttyout); 2345 else 2346 fprintf(ttyout, 2347 "Restarting at " LLF " for next get, put or append\n", 2348 (LLT)restart_point); 2349 } 2350 2351 /* 2352 * Show remote system type 2353 */ 2354 void 2355 syst(int argc, char *argv[]) 2356 { 2357 int oldverbose = verbose; 2358 2359 if (argc == 0) { 2360 fprintf(ttyout, "usage: %s\n", argv[0]); 2361 code = -1; 2362 return; 2363 } 2364 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2365 (void)command("SYST"); 2366 verbose = oldverbose; 2367 } 2368 2369 void 2370 macdef(int argc, char *argv[]) 2371 { 2372 char *tmp; 2373 int c; 2374 2375 if (argc == 0) 2376 goto usage; 2377 if (macnum == 16) { 2378 fputs("Limit of 16 macros have already been defined.\n", 2379 ttyout); 2380 code = -1; 2381 return; 2382 } 2383 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2384 usage: 2385 fprintf(ttyout, "usage: %s macro_name\n", argv[0]); 2386 code = -1; 2387 return; 2388 } 2389 if (interactive) 2390 fputs( 2391 "Enter macro line by line, terminating it with a null line.\n", 2392 ttyout); 2393 (void)strlcpy(macros[macnum].mac_name, argv[1], 2394 sizeof(macros[macnum].mac_name)); 2395 if (macnum == 0) 2396 macros[macnum].mac_start = macbuf; 2397 else 2398 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2399 tmp = macros[macnum].mac_start; 2400 while (tmp != macbuf+4096) { 2401 if ((c = getchar()) == EOF) { 2402 fputs("macdef: end of file encountered.\n", ttyout); 2403 code = -1; 2404 return; 2405 } 2406 if ((*tmp = c) == '\n') { 2407 if (tmp == macros[macnum].mac_start) { 2408 macros[macnum++].mac_end = tmp; 2409 code = 0; 2410 return; 2411 } 2412 if (*(tmp-1) == '\0') { 2413 macros[macnum++].mac_end = tmp - 1; 2414 code = 0; 2415 return; 2416 } 2417 *tmp = '\0'; 2418 } 2419 tmp++; 2420 } 2421 while (1) { 2422 while ((c = getchar()) != '\n' && c != EOF) 2423 /* LOOP */; 2424 if (c == EOF || getchar() == '\n') { 2425 fputs("Macro not defined - 4K buffer exceeded.\n", 2426 ttyout); 2427 code = -1; 2428 return; 2429 } 2430 } 2431 } 2432 2433 /* 2434 * Get size of file on remote machine 2435 */ 2436 void 2437 sizecmd(int argc, char *argv[]) 2438 { 2439 off_t size; 2440 2441 if (argc == 0 || argc > 2 || 2442 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2443 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2444 code = -1; 2445 return; 2446 } 2447 size = remotesize(argv[1], 1); 2448 if (size != -1) 2449 fprintf(ttyout, 2450 "%s\t" LLF "\n", argv[1], (LLT)size); 2451 code = (size > 0); 2452 } 2453 2454 /* 2455 * Get last modification time of file on remote machine 2456 */ 2457 void 2458 modtime(int argc, char *argv[]) 2459 { 2460 time_t mtime; 2461 2462 if (argc == 0 || argc > 2 || 2463 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2464 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2465 code = -1; 2466 return; 2467 } 2468 mtime = remotemodtime(argv[1], 1); 2469 if (mtime != -1) 2470 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime))); 2471 code = (mtime > 0); 2472 } 2473 2474 /* 2475 * Show status on remote machine 2476 */ 2477 void 2478 rmtstatus(int argc, char *argv[]) 2479 { 2480 2481 if (argc == 0) { 2482 fprintf(ttyout, "usage: %s [remote-file]\n", argv[0]); 2483 code = -1; 2484 return; 2485 } 2486 COMMAND_1ARG(argc, argv, "STAT"); 2487 } 2488 2489 /* 2490 * Get file if modtime is more recent than current file 2491 */ 2492 void 2493 newer(int argc, char *argv[]) 2494 { 2495 2496 if (getit(argc, argv, -1, "w")) 2497 fprintf(ttyout, 2498 "Local file \"%s\" is newer than remote file \"%s\".\n", 2499 argv[2], argv[1]); 2500 } 2501 2502 /* 2503 * Display one local file through $PAGER. 2504 */ 2505 void 2506 lpage(int argc, char *argv[]) 2507 { 2508 int len; 2509 char *p, *pager, *locfile; 2510 2511 if (argc == 0 || argc > 2 || 2512 (argc == 1 && !another(&argc, &argv, "local-file"))) { 2513 fprintf(ttyout, "usage: %s local-file\n", argv[0]); 2514 code = -1; 2515 return; 2516 } 2517 if ((locfile = globulize(argv[1])) == NULL) { 2518 code = -1; 2519 return; 2520 } 2521 p = getoptionvalue("pager"); 2522 if (EMPTYSTRING(p)) 2523 p = DEFAULTPAGER; 2524 len = strlen(p) + strlen(locfile) + 2; 2525 pager = xmalloc(len); 2526 (void)strlcpy(pager, p, len); 2527 (void)strlcat(pager, " ", len); 2528 (void)strlcat(pager, locfile, len); 2529 system(pager); 2530 code = 0; 2531 (void)free(pager); 2532 (void)free(locfile); 2533 } 2534 2535 /* 2536 * Display one remote file through $PAGER. 2537 */ 2538 void 2539 page(int argc, char *argv[]) 2540 { 2541 int ohash, orestart_point, overbose, len; 2542 char *p, *pager; 2543 2544 if (argc == 0 || argc > 2 || 2545 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2546 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2547 code = -1; 2548 return; 2549 } 2550 p = getoptionvalue("pager"); 2551 if (EMPTYSTRING(p)) 2552 p = DEFAULTPAGER; 2553 len = strlen(p) + 2; 2554 pager = xmalloc(len); 2555 pager[0] = '|'; 2556 (void)strlcpy(pager + 1, p, len - 1); 2557 2558 ohash = hash; 2559 orestart_point = restart_point; 2560 overbose = verbose; 2561 hash = restart_point = verbose = 0; 2562 recvrequest("RETR", pager, argv[1], "r+", 1, 0); 2563 hash = ohash; 2564 restart_point = orestart_point; 2565 verbose = overbose; 2566 (void)free(pager); 2567 } 2568 2569 /* 2570 * Set the socket send or receive buffer size. 2571 */ 2572 void 2573 setxferbuf(int argc, char *argv[]) 2574 { 2575 int size, dir; 2576 2577 if (argc != 2) { 2578 usage: 2579 fprintf(ttyout, "usage: %s size\n", argv[0]); 2580 code = -1; 2581 return; 2582 } 2583 if (strcasecmp(argv[0], "sndbuf") == 0) 2584 dir = RATE_PUT; 2585 else if (strcasecmp(argv[0], "rcvbuf") == 0) 2586 dir = RATE_GET; 2587 else if (strcasecmp(argv[0], "xferbuf") == 0) 2588 dir = RATE_ALL; 2589 else 2590 goto usage; 2591 2592 if ((size = strsuftoi(argv[1])) == -1) 2593 goto usage; 2594 2595 if (size == 0) { 2596 fprintf(ttyout, "%s: size must be positive.\n", argv[0]); 2597 goto usage; 2598 } 2599 2600 if (dir & RATE_PUT) 2601 sndbuf_size = size; 2602 if (dir & RATE_GET) 2603 rcvbuf_size = size; 2604 fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", 2605 sndbuf_size, rcvbuf_size); 2606 code = 0; 2607 } 2608 2609 /* 2610 * Set or display options (defaults are provided by various env vars) 2611 */ 2612 void 2613 setoption(int argc, char *argv[]) 2614 { 2615 struct option *o; 2616 2617 code = -1; 2618 if (argc == 0 || (argc != 1 && argc != 3)) { 2619 fprintf(ttyout, "usage: %s [option value]\n", argv[0]); 2620 return; 2621 } 2622 2623 #define OPTIONINDENT ((int) sizeof("http_proxy")) 2624 if (argc == 1) { 2625 for (o = optiontab; o->name != NULL; o++) { 2626 fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, 2627 o->name, o->value ? o->value : ""); 2628 } 2629 } else { 2630 o = getoption(argv[1]); 2631 if (o == NULL) { 2632 fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2633 return; 2634 } 2635 FREEPTR(o->value); 2636 o->value = xstrdup(argv[2]); 2637 if (verbose) 2638 fprintf(ttyout, "Setting `%s' to `%s'.\n", 2639 o->name, o->value); 2640 } 2641 code = 0; 2642 } 2643 2644 /* 2645 * Unset an option 2646 */ 2647 void 2648 unsetoption(int argc, char *argv[]) 2649 { 2650 struct option *o; 2651 2652 code = -1; 2653 if (argc == 0 || argc != 2) { 2654 fprintf(ttyout, "usage: %s option\n", argv[0]); 2655 return; 2656 } 2657 2658 o = getoption(argv[1]); 2659 if (o == NULL) { 2660 fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2661 return; 2662 } 2663 FREEPTR(o->value); 2664 fprintf(ttyout, "Unsetting `%s'.\n", o->name); 2665 code = 0; 2666 } 2667 2668 /* 2669 * Display features supported by the remote host. 2670 */ 2671 void 2672 feat(int argc, char *argv[]) 2673 { 2674 int oldverbose = verbose; 2675 2676 if (argc == 0) { 2677 fprintf(ttyout, "usage: %s\n", argv[0]); 2678 code = -1; 2679 return; 2680 } 2681 if (! features[FEAT_FEAT]) { 2682 fprintf(ttyout, 2683 "FEAT is not supported by the remote server.\n"); 2684 return; 2685 } 2686 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2687 (void)command("FEAT"); 2688 verbose = oldverbose; 2689 } 2690 2691 void 2692 mlst(int argc, char *argv[]) 2693 { 2694 int oldverbose = verbose; 2695 2696 if (argc < 1 || argc > 2) { 2697 fprintf(ttyout, "usage: %s [remote-path]\n", argv[0]); 2698 code = -1; 2699 return; 2700 } 2701 if (! features[FEAT_MLST]) { 2702 fprintf(ttyout, 2703 "MLST is not supported by the remote server.\n"); 2704 return; 2705 } 2706 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2707 COMMAND_1ARG(argc, argv, "MLST"); 2708 verbose = oldverbose; 2709 } 2710 2711 void 2712 opts(int argc, char *argv[]) 2713 { 2714 int oldverbose = verbose; 2715 2716 if (argc < 2 || argc > 3) { 2717 fprintf(ttyout, "usage: %s command [options]\n", argv[0]); 2718 code = -1; 2719 return; 2720 } 2721 if (! features[FEAT_FEAT]) { 2722 fprintf(ttyout, 2723 "OPTS is not supported by the remote server.\n"); 2724 return; 2725 } 2726 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2727 if (argc == 2) 2728 command("OPTS %s", argv[1]); 2729 else 2730 command("OPTS %s %s", argv[1], argv[2]); 2731 verbose = oldverbose; 2732 } 2733