1 /* $NetBSD: cmds.c,v 1.102 2003/08/07 11:13:52 agc 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.102 2003/08/07 11:13:52 agc 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 if (connected) 784 fprintf(ttyout, "Connected %sto %s.\n", 785 connected == -1 ? "and logged in" : "", hostname); 786 else 787 fputs("Not connected.\n", ttyout); 788 if (!proxy) { 789 pswitch(1); 790 if (connected) { 791 fprintf(ttyout, "Connected for proxy commands to %s.\n", 792 hostname); 793 } 794 else { 795 fputs("No proxy connection.\n", ttyout); 796 } 797 pswitch(0); 798 } 799 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 800 *gateserver ? gateserver : "(none)", gateport); 801 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 802 onoff(passivemode), onoff(activefallback)); 803 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 804 modename, typename, formname, structname); 805 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 806 onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); 807 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", 808 onoff(sunique), onoff(runique)); 809 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 810 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), 811 onoff(crflag)); 812 if (ntflag) { 813 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 814 } 815 else { 816 fputs("Ntrans: off.\n", ttyout); 817 } 818 if (mapflag) { 819 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 820 } 821 else { 822 fputs("Nmap: off.\n", ttyout); 823 } 824 fprintf(ttyout, 825 "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 826 onoff(hash), mark, onoff(progress)); 827 fprintf(ttyout, 828 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 829 onoff(rate_get), rate_get, rate_get_incr); 830 fprintf(ttyout, 831 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 832 onoff(rate_put), rate_put, rate_put_incr); 833 fprintf(ttyout, 834 "Socket buffer sizes: send %d, receive %d.\n", 835 sndbuf_size, rcvbuf_size); 836 fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); 837 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 838 epsv4bad ? " (disabled for this connection)" : ""); 839 fprintf(ttyout, "Command line editing: %s.\n", 840 #ifdef NO_EDITCOMPLETE 841 "support not compiled in" 842 #else /* !def NO_EDITCOMPLETE */ 843 onoff(editing) 844 #endif /* !def NO_EDITCOMPLETE */ 845 ); 846 fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION); 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 code = 0; 854 } 855 856 /* 857 * Toggle a variable 858 */ 859 int 860 togglevar(int argc, char *argv[], int *var, const char *mesg) 861 { 862 if (argc == 1) { 863 *var = !*var; 864 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 865 *var = 1; 866 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 867 *var = 0; 868 } else { 869 fprintf(ttyout, "usage: %s [ on | off ]\n", argv[0]); 870 return (-1); 871 } 872 if (mesg) 873 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 874 return (*var); 875 } 876 877 /* 878 * Set beep on cmd completed mode. 879 */ 880 /*VARARGS*/ 881 void 882 setbell(int argc, char *argv[]) 883 { 884 885 code = togglevar(argc, argv, &bell, "Bell mode"); 886 } 887 888 /* 889 * Set command line editing 890 */ 891 /*VARARGS*/ 892 void 893 setedit(int argc, char *argv[]) 894 { 895 896 #ifdef NO_EDITCOMPLETE 897 if (argc == 0) { 898 fprintf(ttyout, "usage: %s\n", argv[0]); 899 code = -1; 900 return; 901 } 902 if (verbose) 903 fputs("Editing support not compiled in; ignoring command.\n", 904 ttyout); 905 #else /* !def NO_EDITCOMPLETE */ 906 code = togglevar(argc, argv, &editing, "Editing mode"); 907 controlediting(); 908 #endif /* !def NO_EDITCOMPLETE */ 909 } 910 911 /* 912 * Turn on packet tracing. 913 */ 914 /*VARARGS*/ 915 void 916 settrace(int argc, char *argv[]) 917 { 918 919 code = togglevar(argc, argv, &trace, "Packet tracing"); 920 } 921 922 /* 923 * Toggle hash mark printing during transfers, or set hash mark bytecount. 924 */ 925 /*VARARGS*/ 926 void 927 sethash(int argc, char *argv[]) 928 { 929 if (argc == 1) 930 hash = !hash; 931 else if (argc != 2) { 932 fprintf(ttyout, "usage: %s [ on | off | bytecount ]\n", 933 argv[0]); 934 code = -1; 935 return; 936 } else if (strcasecmp(argv[1], "on") == 0) 937 hash = 1; 938 else if (strcasecmp(argv[1], "off") == 0) 939 hash = 0; 940 else { 941 int nmark; 942 943 nmark = strsuftoi(argv[1]); 944 if (nmark < 1) { 945 fprintf(ttyout, "mark: bad bytecount value `%s'.\n", 946 argv[1]); 947 code = -1; 948 return; 949 } 950 mark = nmark; 951 hash = 1; 952 } 953 fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 954 if (hash) 955 fprintf(ttyout, " (%d bytes/hash mark)", mark); 956 fputs(".\n", ttyout); 957 if (hash) 958 progress = 0; 959 code = hash; 960 } 961 962 /* 963 * Turn on printing of server echo's. 964 */ 965 /*VARARGS*/ 966 void 967 setverbose(int argc, char *argv[]) 968 { 969 970 code = togglevar(argc, argv, &verbose, "Verbose mode"); 971 } 972 973 /* 974 * Toggle PORT/LPRT cmd use before each data connection. 975 */ 976 /*VARARGS*/ 977 void 978 setport(int argc, char *argv[]) 979 { 980 981 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 982 } 983 984 /* 985 * Toggle transfer progress bar. 986 */ 987 /*VARARGS*/ 988 void 989 setprogress(int argc, char *argv[]) 990 { 991 992 code = togglevar(argc, argv, &progress, "Progress bar"); 993 if (progress) 994 hash = 0; 995 } 996 997 /* 998 * Turn on interactive prompting during mget, mput, and mdelete. 999 */ 1000 /*VARARGS*/ 1001 void 1002 setprompt(int argc, char *argv[]) 1003 { 1004 1005 code = togglevar(argc, argv, &interactive, "Interactive mode"); 1006 } 1007 1008 /* 1009 * Toggle gate-ftp mode, or set gate-ftp server 1010 */ 1011 /*VARARGS*/ 1012 void 1013 setgate(int argc, char *argv[]) 1014 { 1015 static char gsbuf[MAXHOSTNAMELEN]; 1016 1017 if (argc == 0 || argc > 3) { 1018 fprintf(ttyout, 1019 "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); 1020 code = -1; 1021 return; 1022 } else if (argc < 2) { 1023 gatemode = !gatemode; 1024 } else { 1025 if (argc == 2 && strcasecmp(argv[1], "on") == 0) 1026 gatemode = 1; 1027 else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 1028 gatemode = 0; 1029 else { 1030 if (argc == 3) 1031 gateport = xstrdup(argv[2]); 1032 (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 1033 gateserver = gsbuf; 1034 gatemode = 1; 1035 } 1036 } 1037 if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 1038 fprintf(ttyout, 1039 "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 1040 gatemode = 0; 1041 } else { 1042 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 1043 onoff(gatemode), *gateserver ? gateserver : "(none)", 1044 gateport); 1045 } 1046 code = gatemode; 1047 } 1048 1049 /* 1050 * Toggle metacharacter interpretation on local file names. 1051 */ 1052 /*VARARGS*/ 1053 void 1054 setglob(int argc, char *argv[]) 1055 { 1056 1057 code = togglevar(argc, argv, &doglob, "Globbing"); 1058 } 1059 1060 /* 1061 * Toggle preserving modification times on retrieved files. 1062 */ 1063 /*VARARGS*/ 1064 void 1065 setpreserve(int argc, char *argv[]) 1066 { 1067 1068 code = togglevar(argc, argv, &preserve, "Preserve modification times"); 1069 } 1070 1071 /* 1072 * Set debugging mode on/off and/or set level of debugging. 1073 */ 1074 /*VARARGS*/ 1075 void 1076 setdebug(int argc, char *argv[]) 1077 { 1078 if (argc == 0 || argc > 2) { 1079 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n", 1080 argv[0]); 1081 code = -1; 1082 return; 1083 } else if (argc == 2) { 1084 if (strcasecmp(argv[1], "on") == 0) 1085 debug = 1; 1086 else if (strcasecmp(argv[1], "off") == 0) 1087 debug = 0; 1088 else { 1089 int val; 1090 1091 val = strsuftoi(argv[1]); 1092 if (val < 0) { 1093 fprintf(ttyout, "%s: bad debugging value.\n", 1094 argv[1]); 1095 code = -1; 1096 return; 1097 } 1098 debug = val; 1099 } 1100 } else 1101 debug = !debug; 1102 if (debug) 1103 options |= SO_DEBUG; 1104 else 1105 options &= ~SO_DEBUG; 1106 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug); 1107 code = debug > 0; 1108 } 1109 1110 /* 1111 * Set current working directory on remote machine. 1112 */ 1113 void 1114 cd(int argc, char *argv[]) 1115 { 1116 int r; 1117 1118 if (argc == 0 || argc > 2 || 1119 (argc == 1 && !another(&argc, &argv, "remote-directory"))) { 1120 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); 1121 code = -1; 1122 return; 1123 } 1124 r = command("CWD %s", argv[1]); 1125 if (r == ERROR && code == 500) { 1126 if (verbose) 1127 fputs("CWD command not recognized, trying XCWD.\n", 1128 ttyout); 1129 r = command("XCWD %s", argv[1]); 1130 } 1131 if (r == COMPLETE) { 1132 dirchange = 1; 1133 updateremotepwd(); 1134 } 1135 } 1136 1137 /* 1138 * Set current working directory on local machine. 1139 */ 1140 void 1141 lcd(int argc, char *argv[]) 1142 { 1143 char buf[MAXPATHLEN]; 1144 char *locdir; 1145 1146 code = -1; 1147 if (argc == 1) { 1148 argc++; 1149 argv[1] = localhome; 1150 } 1151 if (argc != 2) { 1152 fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]); 1153 return; 1154 } 1155 if ((locdir = globulize(argv[1])) == NULL) 1156 return; 1157 if (chdir(locdir) < 0) 1158 warn("local: %s", locdir); 1159 else { 1160 if (getcwd(buf, sizeof(buf)) != NULL) { 1161 fprintf(ttyout, "Local directory now %s\n", buf); 1162 code = 0; 1163 } else 1164 warn("getcwd: %s", locdir); 1165 } 1166 (void)free(locdir); 1167 } 1168 1169 /* 1170 * Delete a single file. 1171 */ 1172 void 1173 delete(int argc, char *argv[]) 1174 { 1175 1176 1177 if (argc == 0 || argc > 2 || 1178 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 1179 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 1180 code = -1; 1181 return; 1182 } 1183 if (command("DELE %s", argv[1]) == COMPLETE) 1184 dirchange = 1; 1185 } 1186 1187 /* 1188 * Delete multiple files. 1189 */ 1190 void 1191 mdelete(int argc, char *argv[]) 1192 { 1193 sigfunc oldintr; 1194 int ointer; 1195 char *cp; 1196 1197 if (argc == 0 || 1198 (argc == 1 && !another(&argc, &argv, "remote-files"))) { 1199 fprintf(ttyout, "usage: %s [remote-files]\n", argv[0]); 1200 code = -1; 1201 return; 1202 } 1203 mname = argv[0]; 1204 mflag = 1; 1205 oldintr = xsignal(SIGINT, mintr); 1206 if (sigsetjmp(jabort, 1)) 1207 mabort(); 1208 while ((cp = remglob(argv, 0, NULL)) != NULL) { 1209 if (*cp == '\0') { 1210 mflag = 0; 1211 continue; 1212 } 1213 if (mflag && confirm(argv[0], cp)) { 1214 if (command("DELE %s", cp) == COMPLETE) 1215 dirchange = 1; 1216 if (!mflag && fromatty) { 1217 ointer = interactive; 1218 interactive = 1; 1219 if (confirm("Continue with", "mdelete")) { 1220 mflag++; 1221 } 1222 interactive = ointer; 1223 } 1224 } 1225 } 1226 (void)xsignal(SIGINT, oldintr); 1227 mflag = 0; 1228 } 1229 1230 /* 1231 * Rename a remote file. 1232 */ 1233 void 1234 renamefile(int argc, char *argv[]) 1235 { 1236 1237 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) 1238 goto usage; 1239 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1240 usage: 1241 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]); 1242 code = -1; 1243 return; 1244 } 1245 if (command("RNFR %s", argv[1]) == CONTINUE && 1246 command("RNTO %s", argv[2]) == COMPLETE) 1247 dirchange = 1; 1248 } 1249 1250 /* 1251 * Get a directory listing of remote files. 1252 * Supports being invoked as: 1253 * cmd runs 1254 * --- ---- 1255 * dir, ls LIST 1256 * mlsd MLSD 1257 * nlist NLST 1258 * pdir, pls LIST |$PAGER 1259 * mmlsd MLSD |$PAGER 1260 */ 1261 void 1262 ls(int argc, char *argv[]) 1263 { 1264 const char *cmd; 1265 char *remdir, *locfile; 1266 int freelocfile, pagecmd, mlsdcmd; 1267 1268 remdir = NULL; 1269 locfile = "-"; 1270 freelocfile = pagecmd = mlsdcmd = 0; 1271 /* 1272 * the only commands that start with `p' are 1273 * the `pager' versions. 1274 */ 1275 if (argv[0][0] == 'p') 1276 pagecmd = 1; 1277 if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { 1278 if (! features[FEAT_MLST]) { 1279 fprintf(ttyout, 1280 "MLSD is not supported by the remote server.\n"); 1281 return; 1282 } 1283 mlsdcmd = 1; 1284 } 1285 if (argc == 0) 1286 goto usage; 1287 1288 if (mlsdcmd) 1289 cmd = "MLSD"; 1290 else if (strcmp(argv[0] + pagecmd, "nlist") == 0) 1291 cmd = "NLST"; 1292 else 1293 cmd = "LIST"; 1294 1295 if (argc > 1) 1296 remdir = argv[1]; 1297 if (argc > 2) 1298 locfile = argv[2]; 1299 if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { 1300 usage: 1301 if (pagecmd || mlsdcmd) 1302 fprintf(ttyout, 1303 "usage: %s [remote-path]\n", argv[0]); 1304 else 1305 fprintf(ttyout, 1306 "usage: %s [remote-path [local-file]]\n", 1307 argv[0]); 1308 code = -1; 1309 goto freels; 1310 } 1311 1312 if (pagecmd) { 1313 char *p; 1314 int len; 1315 1316 p = getoptionvalue("pager"); 1317 if (EMPTYSTRING(p)) 1318 p = DEFAULTPAGER; 1319 len = strlen(p) + 2; 1320 locfile = xmalloc(len); 1321 locfile[0] = '|'; 1322 (void)strlcpy(locfile + 1, p, len - 1); 1323 freelocfile = 1; 1324 } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') { 1325 if ((locfile = globulize(locfile)) == NULL || 1326 !confirm("output to local-file:", locfile)) { 1327 code = -1; 1328 goto freels; 1329 } 1330 freelocfile = 1; 1331 } 1332 recvrequest(cmd, locfile, remdir, "w", 0, 0); 1333 freels: 1334 if (freelocfile && locfile) 1335 (void)free(locfile); 1336 } 1337 1338 /* 1339 * Get a directory listing of multiple remote files. 1340 */ 1341 void 1342 mls(int argc, char *argv[]) 1343 { 1344 sigfunc oldintr; 1345 int ointer, i; 1346 int dolist; 1347 char *mode, *dest, *odest; 1348 1349 if (argc == 0) 1350 goto usage; 1351 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1352 goto usage; 1353 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1354 usage: 1355 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]); 1356 code = -1; 1357 return; 1358 } 1359 odest = dest = argv[argc - 1]; 1360 argv[argc - 1] = NULL; 1361 if (strcmp(dest, "-") && *dest != '|') 1362 if (((dest = globulize(dest)) == NULL) || 1363 !confirm("output to local-file:", dest)) { 1364 code = -1; 1365 return; 1366 } 1367 dolist = strcmp(argv[0], "mls"); 1368 mname = argv[0]; 1369 mflag = 1; 1370 oldintr = xsignal(SIGINT, mintr); 1371 if (sigsetjmp(jabort, 1)) 1372 mabort(); 1373 for (i = 1; mflag && i < argc-1 && connected; i++) { 1374 mode = (i == 1) ? "w" : "a"; 1375 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode, 1376 0, 0); 1377 if (!mflag && fromatty) { 1378 ointer = interactive; 1379 interactive = 1; 1380 if (confirm("Continue with", argv[0])) { 1381 mflag ++; 1382 } 1383 interactive = ointer; 1384 } 1385 } 1386 (void)xsignal(SIGINT, oldintr); 1387 mflag = 0; 1388 if (dest != odest) /* free up after globulize() */ 1389 free(dest); 1390 } 1391 1392 /* 1393 * Do a shell escape 1394 */ 1395 /*ARGSUSED*/ 1396 void 1397 shell(int argc, char *argv[]) 1398 { 1399 pid_t pid; 1400 sigfunc old1; 1401 char shellnam[MAXPATHLEN], *shell, *namep; 1402 int wait_status; 1403 1404 if (argc == 0) { 1405 fprintf(ttyout, "usage: %s [command [args]]\n", argv[0]); 1406 code = -1; 1407 return; 1408 } 1409 old1 = xsignal(SIGINT, SIG_IGN); 1410 if ((pid = fork()) == 0) { 1411 for (pid = 3; pid < 20; pid++) 1412 (void)close(pid); 1413 (void)xsignal(SIGINT, SIG_DFL); 1414 shell = getenv("SHELL"); 1415 if (shell == NULL) 1416 shell = _PATH_BSHELL; 1417 namep = strrchr(shell, '/'); 1418 if (namep == NULL) 1419 namep = shell; 1420 else 1421 namep++; 1422 (void)strlcpy(shellnam, namep, sizeof(shellnam)); 1423 if (debug) { 1424 fputs(shell, ttyout); 1425 putc('\n', ttyout); 1426 } 1427 if (argc > 1) { 1428 execl(shell, shellnam, "-c", altarg, (char *)0); 1429 } 1430 else { 1431 execl(shell, shellnam, (char *)0); 1432 } 1433 warn("%s", shell); 1434 code = -1; 1435 exit(1); 1436 } 1437 if (pid > 0) 1438 while (wait(&wait_status) != pid) 1439 ; 1440 (void)xsignal(SIGINT, old1); 1441 if (pid == -1) { 1442 warn("Try again later"); 1443 code = -1; 1444 } else 1445 code = 0; 1446 } 1447 1448 /* 1449 * Send new user information (re-login) 1450 */ 1451 void 1452 user(int argc, char *argv[]) 1453 { 1454 char acct[80]; 1455 int n, aflag = 0; 1456 1457 if (argc == 0) 1458 goto usage; 1459 if (argc < 2) 1460 (void)another(&argc, &argv, "username"); 1461 if (argc < 2 || argc > 4) { 1462 usage: 1463 fprintf(ttyout, "usage: %s username [password [account]]\n", 1464 argv[0]); 1465 code = -1; 1466 return; 1467 } 1468 n = command("USER %s", argv[1]); 1469 if (n == CONTINUE) { 1470 if (argc < 3) { 1471 argv[2] = getpass("Password: "); 1472 argc++; 1473 } 1474 n = command("PASS %s", argv[2]); 1475 } 1476 if (n == CONTINUE) { 1477 if (argc < 4) { 1478 (void)fputs("Account: ", ttyout); 1479 (void)fflush(ttyout); 1480 if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) { 1481 fprintf(ttyout, 1482 "\nEOF received; login aborted.\n"); 1483 clearerr(stdin); 1484 code = -1; 1485 return; 1486 } 1487 acct[strlen(acct) - 1] = '\0'; 1488 argv[3] = acct; argc++; 1489 } 1490 n = command("ACCT %s", argv[3]); 1491 aflag++; 1492 } 1493 if (n != COMPLETE) { 1494 fputs("Login failed.\n", ttyout); 1495 return; 1496 } 1497 if (!aflag && argc == 4) { 1498 (void)command("ACCT %s", argv[3]); 1499 } 1500 connected = -1; 1501 getremoteinfo(); 1502 } 1503 1504 /* 1505 * Print working directory on remote machine. 1506 */ 1507 /*VARARGS*/ 1508 void 1509 pwd(int argc, char *argv[]) 1510 { 1511 int oldverbose = verbose; 1512 1513 if (argc == 0) { 1514 fprintf(ttyout, "usage: %s\n", argv[0]); 1515 code = -1; 1516 return; 1517 } 1518 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 1519 if (command("PWD") == ERROR && code == 500) { 1520 fputs("PWD command not recognized, trying XPWD.\n", ttyout); 1521 (void)command("XPWD"); 1522 } 1523 verbose = oldverbose; 1524 } 1525 1526 /* 1527 * Print working directory on local machine. 1528 */ 1529 void 1530 lpwd(int argc, char *argv[]) 1531 { 1532 char buf[MAXPATHLEN]; 1533 1534 if (argc == 0) { 1535 fprintf(ttyout, "usage: %s\n", argv[0]); 1536 code = -1; 1537 return; 1538 } 1539 if (getcwd(buf, sizeof(buf)) != NULL) { 1540 fprintf(ttyout, "Local directory %s\n", buf); 1541 code = 0; 1542 } else { 1543 warn("getcwd"); 1544 code = -1; 1545 } 1546 } 1547 1548 /* 1549 * Make a directory. 1550 */ 1551 void 1552 makedir(int argc, char *argv[]) 1553 { 1554 int r; 1555 1556 if (argc == 0 || argc > 2 || 1557 (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1558 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1559 code = -1; 1560 return; 1561 } 1562 r = command("MKD %s", argv[1]); 1563 if (r == ERROR && code == 500) { 1564 if (verbose) 1565 fputs("MKD command not recognized, trying XMKD.\n", 1566 ttyout); 1567 r = command("XMKD %s", argv[1]); 1568 } 1569 if (r == COMPLETE) 1570 dirchange = 1; 1571 } 1572 1573 /* 1574 * Remove a directory. 1575 */ 1576 void 1577 removedir(int argc, char *argv[]) 1578 { 1579 int r; 1580 1581 if (argc == 0 || argc > 2 || 1582 (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1583 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1584 code = -1; 1585 return; 1586 } 1587 r = command("RMD %s", argv[1]); 1588 if (r == ERROR && code == 500) { 1589 if (verbose) 1590 fputs("RMD command not recognized, trying XRMD.\n", 1591 ttyout); 1592 r = command("XRMD %s", argv[1]); 1593 } 1594 if (r == COMPLETE) 1595 dirchange = 1; 1596 } 1597 1598 /* 1599 * Send a line, verbatim, to the remote machine. 1600 */ 1601 void 1602 quote(int argc, char *argv[]) 1603 { 1604 1605 if (argc == 0 || 1606 (argc == 1 && !another(&argc, &argv, "command line to send"))) { 1607 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1608 code = -1; 1609 return; 1610 } 1611 quote1("", argc, argv); 1612 } 1613 1614 /* 1615 * Send a SITE command to the remote machine. The line 1616 * is sent verbatim to the remote machine, except that the 1617 * word "SITE" is added at the front. 1618 */ 1619 void 1620 site(int argc, char *argv[]) 1621 { 1622 1623 if (argc == 0 || 1624 (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ 1625 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1626 code = -1; 1627 return; 1628 } 1629 quote1("SITE ", argc, argv); 1630 } 1631 1632 /* 1633 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1634 * Send the result as a one-line command and get response. 1635 */ 1636 void 1637 quote1(const char *initial, int argc, char *argv[]) 1638 { 1639 int i; 1640 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1641 1642 (void)strlcpy(buf, initial, sizeof(buf)); 1643 for (i = 1; i < argc; i++) { 1644 (void)strlcat(buf, argv[i], sizeof(buf)); 1645 if (i < (argc - 1)) 1646 (void)strlcat(buf, " ", sizeof(buf)); 1647 } 1648 if (command("%s", buf) == PRELIM) { 1649 while (getreply(0) == PRELIM) 1650 continue; 1651 } 1652 dirchange = 1; 1653 } 1654 1655 void 1656 do_chmod(int argc, char *argv[]) 1657 { 1658 1659 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) 1660 goto usage; 1661 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 1662 usage: 1663 fprintf(ttyout, "usage: %s mode remote-file\n", argv[0]); 1664 code = -1; 1665 return; 1666 } 1667 (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1668 } 1669 1670 #define COMMAND_1ARG(argc, argv, cmd) \ 1671 if (argc == 1) \ 1672 command(cmd); \ 1673 else \ 1674 command(cmd " %s", argv[1]) 1675 1676 void 1677 do_umask(int argc, char *argv[]) 1678 { 1679 int oldverbose = verbose; 1680 1681 if (argc == 0) { 1682 fprintf(ttyout, "usage: %s [umask]\n", argv[0]); 1683 code = -1; 1684 return; 1685 } 1686 verbose = 1; 1687 COMMAND_1ARG(argc, argv, "SITE UMASK"); 1688 verbose = oldverbose; 1689 } 1690 1691 void 1692 idlecmd(int argc, char *argv[]) 1693 { 1694 int oldverbose = verbose; 1695 1696 if (argc < 1 || argc > 2) { 1697 fprintf(ttyout, "usage: %s [seconds]\n", argv[0]); 1698 code = -1; 1699 return; 1700 } 1701 verbose = 1; 1702 COMMAND_1ARG(argc, argv, "SITE IDLE"); 1703 verbose = oldverbose; 1704 } 1705 1706 /* 1707 * Ask the other side for help. 1708 */ 1709 void 1710 rmthelp(int argc, char *argv[]) 1711 { 1712 int oldverbose = verbose; 1713 1714 if (argc == 0) { 1715 fprintf(ttyout, "usage: %s\n", argv[0]); 1716 code = -1; 1717 return; 1718 } 1719 verbose = 1; 1720 COMMAND_1ARG(argc, argv, "HELP"); 1721 verbose = oldverbose; 1722 } 1723 1724 /* 1725 * Terminate session and exit. 1726 * May be called with 0, NULL. 1727 */ 1728 /*VARARGS*/ 1729 void 1730 quit(int argc, char *argv[]) 1731 { 1732 1733 /* this may be called with argc == 0, argv == NULL */ 1734 if (argc == 0 && argv != NULL) { 1735 fprintf(ttyout, "usage: %s\n", argv[0]); 1736 code = -1; 1737 return; 1738 } 1739 if (connected) 1740 disconnect(0, NULL); 1741 pswitch(1); 1742 if (connected) 1743 disconnect(0, NULL); 1744 exit(0); 1745 } 1746 1747 /* 1748 * Terminate session, but don't exit. 1749 * May be called with 0, NULL. 1750 */ 1751 void 1752 disconnect(int argc, char *argv[]) 1753 { 1754 1755 /* this may be called with argc == 0, argv == NULL */ 1756 if (argc == 0 && argv != NULL) { 1757 fprintf(ttyout, "usage: %s\n", argv[0]); 1758 code = -1; 1759 return; 1760 } 1761 if (!connected) 1762 return; 1763 (void)command("QUIT"); 1764 cleanuppeer(); 1765 } 1766 1767 void 1768 account(int argc, char *argv[]) 1769 { 1770 char *ap; 1771 1772 if (argc == 0 || argc > 2) { 1773 fprintf(ttyout, "usage: %s [password]\n", argv[0]); 1774 code = -1; 1775 return; 1776 } 1777 else if (argc == 2) 1778 ap = argv[1]; 1779 else 1780 ap = getpass("Account:"); 1781 (void)command("ACCT %s", ap); 1782 } 1783 1784 sigjmp_buf abortprox; 1785 1786 void 1787 proxabort(int notused) 1788 { 1789 1790 alarmtimer(0); 1791 if (!proxy) { 1792 pswitch(1); 1793 } 1794 if (connected) { 1795 proxflag = 1; 1796 } 1797 else { 1798 proxflag = 0; 1799 } 1800 pswitch(0); 1801 siglongjmp(abortprox, 1); 1802 } 1803 1804 void 1805 doproxy(int argc, char *argv[]) 1806 { 1807 struct cmd *c; 1808 int cmdpos; 1809 sigfunc oldintr; 1810 1811 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { 1812 fprintf(ttyout, "usage: %s command\n", argv[0]); 1813 code = -1; 1814 return; 1815 } 1816 c = getcmd(argv[1]); 1817 if (c == (struct cmd *) -1) { 1818 fputs("?Ambiguous command.\n", ttyout); 1819 code = -1; 1820 return; 1821 } 1822 if (c == 0) { 1823 fputs("?Invalid command.\n", ttyout); 1824 code = -1; 1825 return; 1826 } 1827 if (!c->c_proxy) { 1828 fputs("?Invalid proxy command.\n", ttyout); 1829 code = -1; 1830 return; 1831 } 1832 if (sigsetjmp(abortprox, 1)) { 1833 code = -1; 1834 return; 1835 } 1836 oldintr = xsignal(SIGINT, proxabort); 1837 pswitch(1); 1838 if (c->c_conn && !connected) { 1839 fputs("Not connected.\n", ttyout); 1840 pswitch(0); 1841 (void)xsignal(SIGINT, oldintr); 1842 code = -1; 1843 return; 1844 } 1845 cmdpos = strcspn(line, " \t"); 1846 if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1847 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1848 argv[1] = c->c_name; 1849 (*c->c_handler)(argc-1, argv+1); 1850 if (connected) { 1851 proxflag = 1; 1852 } 1853 else { 1854 proxflag = 0; 1855 } 1856 pswitch(0); 1857 (void)xsignal(SIGINT, oldintr); 1858 } 1859 1860 void 1861 setcase(int argc, char *argv[]) 1862 { 1863 1864 code = togglevar(argc, argv, &mcase, "Case mapping"); 1865 } 1866 1867 /* 1868 * convert the given name to lower case if it's all upper case, into 1869 * a static buffer which is returned to the caller 1870 */ 1871 char * 1872 docase(char *name) 1873 { 1874 static char new[MAXPATHLEN]; 1875 int i, dochange; 1876 1877 dochange = 1; 1878 for (i = 0; name[i] != '\0' && i < sizeof(new) - 1; i++) { 1879 new[i] = name[i]; 1880 if (islower((unsigned char)new[i])) 1881 dochange = 0; 1882 } 1883 new[i] = '\0'; 1884 1885 if (dochange) { 1886 for (i = 0; new[i] != '\0'; i++) 1887 if (isupper((unsigned char)new[i])) 1888 new[i] = tolower(new[i]); 1889 } 1890 return (new); 1891 } 1892 1893 void 1894 setcr(int argc, char *argv[]) 1895 { 1896 1897 code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1898 } 1899 1900 void 1901 setntrans(int argc, char *argv[]) 1902 { 1903 1904 if (argc == 0 || argc > 3) { 1905 fprintf(ttyout, "usage: %s [inchars [outchars]]\n", argv[0]); 1906 code = -1; 1907 return; 1908 } 1909 if (argc == 1) { 1910 ntflag = 0; 1911 fputs("Ntrans off.\n", ttyout); 1912 code = ntflag; 1913 return; 1914 } 1915 ntflag++; 1916 code = ntflag; 1917 (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1918 if (argc == 2) { 1919 ntout[0] = '\0'; 1920 return; 1921 } 1922 (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1923 } 1924 1925 char * 1926 dotrans(char *name) 1927 { 1928 static char new[MAXPATHLEN]; 1929 char *cp1, *cp2 = new; 1930 int i, ostop, found; 1931 1932 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1933 continue; 1934 for (cp1 = name; *cp1; cp1++) { 1935 found = 0; 1936 for (i = 0; *(ntin + i) && i < 16; i++) { 1937 if (*cp1 == *(ntin + i)) { 1938 found++; 1939 if (i < ostop) { 1940 *cp2++ = *(ntout + i); 1941 } 1942 break; 1943 } 1944 } 1945 if (!found) { 1946 *cp2++ = *cp1; 1947 } 1948 } 1949 *cp2 = '\0'; 1950 return (new); 1951 } 1952 1953 void 1954 setnmap(int argc, char *argv[]) 1955 { 1956 char *cp; 1957 1958 if (argc == 1) { 1959 mapflag = 0; 1960 fputs("Nmap off.\n", ttyout); 1961 code = mapflag; 1962 return; 1963 } 1964 if (argc == 0 || 1965 (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 1966 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]); 1967 code = -1; 1968 return; 1969 } 1970 mapflag = 1; 1971 code = 1; 1972 cp = strchr(altarg, ' '); 1973 if (proxy) { 1974 while(*++cp == ' ') 1975 continue; 1976 altarg = cp; 1977 cp = strchr(altarg, ' '); 1978 } 1979 *cp = '\0'; 1980 (void)strlcpy(mapin, altarg, MAXPATHLEN); 1981 while (*++cp == ' ') 1982 continue; 1983 (void)strlcpy(mapout, cp, MAXPATHLEN); 1984 } 1985 1986 char * 1987 domap(char *name) 1988 { 1989 static char new[MAXPATHLEN]; 1990 char *cp1 = name, *cp2 = mapin; 1991 char *tp[9], *te[9]; 1992 int i, toks[9], toknum = 0, match = 1; 1993 1994 for (i=0; i < 9; ++i) { 1995 toks[i] = 0; 1996 } 1997 while (match && *cp1 && *cp2) { 1998 switch (*cp2) { 1999 case '\\': 2000 if (*++cp2 != *cp1) { 2001 match = 0; 2002 } 2003 break; 2004 case '$': 2005 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 2006 if (*cp1 != *(++cp2+1)) { 2007 toks[toknum = *cp2 - '1']++; 2008 tp[toknum] = cp1; 2009 while (*++cp1 && *(cp2+1) 2010 != *cp1); 2011 te[toknum] = cp1; 2012 } 2013 cp2++; 2014 break; 2015 } 2016 /* FALLTHROUGH */ 2017 default: 2018 if (*cp2 != *cp1) { 2019 match = 0; 2020 } 2021 break; 2022 } 2023 if (match && *cp1) { 2024 cp1++; 2025 } 2026 if (match && *cp2) { 2027 cp2++; 2028 } 2029 } 2030 if (!match && *cp1) /* last token mismatch */ 2031 { 2032 toks[toknum] = 0; 2033 } 2034 cp1 = new; 2035 *cp1 = '\0'; 2036 cp2 = mapout; 2037 while (*cp2) { 2038 match = 0; 2039 switch (*cp2) { 2040 case '\\': 2041 if (*(cp2 + 1)) { 2042 *cp1++ = *++cp2; 2043 } 2044 break; 2045 case '[': 2046 LOOP: 2047 if (*++cp2 == '$' && 2048 isdigit((unsigned char)*(cp2+1))) { 2049 if (*++cp2 == '0') { 2050 char *cp3 = name; 2051 2052 while (*cp3) { 2053 *cp1++ = *cp3++; 2054 } 2055 match = 1; 2056 } 2057 else if (toks[toknum = *cp2 - '1']) { 2058 char *cp3 = tp[toknum]; 2059 2060 while (cp3 != te[toknum]) { 2061 *cp1++ = *cp3++; 2062 } 2063 match = 1; 2064 } 2065 } 2066 else { 2067 while (*cp2 && *cp2 != ',' && 2068 *cp2 != ']') { 2069 if (*cp2 == '\\') { 2070 cp2++; 2071 } 2072 else if (*cp2 == '$' && 2073 isdigit((unsigned char)*(cp2+1))) { 2074 if (*++cp2 == '0') { 2075 char *cp3 = name; 2076 2077 while (*cp3) { 2078 *cp1++ = *cp3++; 2079 } 2080 } 2081 else if (toks[toknum = 2082 *cp2 - '1']) { 2083 char *cp3=tp[toknum]; 2084 2085 while (cp3 != 2086 te[toknum]) { 2087 *cp1++ = *cp3++; 2088 } 2089 } 2090 } 2091 else if (*cp2) { 2092 *cp1++ = *cp2++; 2093 } 2094 } 2095 if (!*cp2) { 2096 fputs( 2097 "nmap: unbalanced brackets.\n", 2098 ttyout); 2099 return (name); 2100 } 2101 match = 1; 2102 cp2--; 2103 } 2104 if (match) { 2105 while (*++cp2 && *cp2 != ']') { 2106 if (*cp2 == '\\' && *(cp2 + 1)) { 2107 cp2++; 2108 } 2109 } 2110 if (!*cp2) { 2111 fputs( 2112 "nmap: unbalanced brackets.\n", 2113 ttyout); 2114 return (name); 2115 } 2116 break; 2117 } 2118 switch (*++cp2) { 2119 case ',': 2120 goto LOOP; 2121 case ']': 2122 break; 2123 default: 2124 cp2--; 2125 goto LOOP; 2126 } 2127 break; 2128 case '$': 2129 if (isdigit((unsigned char)*(cp2 + 1))) { 2130 if (*++cp2 == '0') { 2131 char *cp3 = name; 2132 2133 while (*cp3) { 2134 *cp1++ = *cp3++; 2135 } 2136 } 2137 else if (toks[toknum = *cp2 - '1']) { 2138 char *cp3 = tp[toknum]; 2139 2140 while (cp3 != te[toknum]) { 2141 *cp1++ = *cp3++; 2142 } 2143 } 2144 break; 2145 } 2146 /* intentional drop through */ 2147 default: 2148 *cp1++ = *cp2; 2149 break; 2150 } 2151 cp2++; 2152 } 2153 *cp1 = '\0'; 2154 if (!*new) { 2155 return (name); 2156 } 2157 return (new); 2158 } 2159 2160 void 2161 setpassive(int argc, char *argv[]) 2162 { 2163 2164 if (argc == 1) { 2165 passivemode = !passivemode; 2166 activefallback = passivemode; 2167 } else if (argc != 2) { 2168 passiveusage: 2169 fprintf(ttyout, "usage: %s [ on | off | auto ]\n", argv[0]); 2170 code = -1; 2171 return; 2172 } else if (strcasecmp(argv[1], "on") == 0) { 2173 passivemode = 1; 2174 activefallback = 0; 2175 } else if (strcasecmp(argv[1], "off") == 0) { 2176 passivemode = 0; 2177 activefallback = 0; 2178 } else if (strcasecmp(argv[1], "auto") == 0) { 2179 passivemode = 1; 2180 activefallback = 1; 2181 } else 2182 goto passiveusage; 2183 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 2184 onoff(passivemode), onoff(activefallback)); 2185 code = passivemode; 2186 } 2187 2188 void 2189 setepsv4(int argc, char *argv[]) 2190 { 2191 2192 code = togglevar(argc, argv, &epsv4, 2193 verbose ? "EPSV/EPRT on IPv4" : NULL); 2194 epsv4bad = 0; 2195 } 2196 2197 void 2198 setsunique(int argc, char *argv[]) 2199 { 2200 2201 code = togglevar(argc, argv, &sunique, "Store unique"); 2202 } 2203 2204 void 2205 setrunique(int argc, char *argv[]) 2206 { 2207 2208 code = togglevar(argc, argv, &runique, "Receive unique"); 2209 } 2210 2211 int 2212 parserate(int argc, char *argv[], int cmdlineopt) 2213 { 2214 int dir, max, incr, showonly; 2215 sigfunc oldusr1, oldusr2; 2216 2217 if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { 2218 usage: 2219 if (cmdlineopt) 2220 fprintf(ttyout, 2221 "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", 2222 argv[0]); 2223 else 2224 fprintf(ttyout, 2225 "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", 2226 argv[0]); 2227 return -1; 2228 } 2229 dir = max = incr = showonly = 0; 2230 #define RATE_GET 1 2231 #define RATE_PUT 2 2232 #define RATE_ALL (RATE_GET | RATE_PUT) 2233 2234 if (strcasecmp(argv[1], "all") == 0) 2235 dir = RATE_ALL; 2236 else if (strcasecmp(argv[1], "get") == 0) 2237 dir = RATE_GET; 2238 else if (strcasecmp(argv[1], "put") == 0) 2239 dir = RATE_PUT; 2240 else 2241 goto usage; 2242 2243 if (argc >= 3) { 2244 if ((max = strsuftoi(argv[2])) < 0) 2245 goto usage; 2246 } else 2247 showonly = 1; 2248 2249 if (argc == 4) { 2250 if ((incr = strsuftoi(argv[3])) <= 0) 2251 goto usage; 2252 } else 2253 incr = DEFAULTINCR; 2254 2255 oldusr1 = xsignal(SIGUSR1, SIG_IGN); 2256 oldusr2 = xsignal(SIGUSR2, SIG_IGN); 2257 if (dir & RATE_GET) { 2258 if (!showonly) { 2259 rate_get = max; 2260 rate_get_incr = incr; 2261 } 2262 if (!cmdlineopt || verbose) 2263 fprintf(ttyout, 2264 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 2265 onoff(rate_get), rate_get, rate_get_incr); 2266 } 2267 if (dir & RATE_PUT) { 2268 if (!showonly) { 2269 rate_put = max; 2270 rate_put_incr = incr; 2271 } 2272 if (!cmdlineopt || verbose) 2273 fprintf(ttyout, 2274 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 2275 onoff(rate_put), rate_put, rate_put_incr); 2276 } 2277 (void)xsignal(SIGUSR1, oldusr1); 2278 (void)xsignal(SIGUSR2, oldusr2); 2279 return 0; 2280 } 2281 2282 void 2283 setrate(int argc, char *argv[]) 2284 { 2285 2286 code = parserate(argc, argv, 0); 2287 } 2288 2289 /* change directory to parent directory */ 2290 void 2291 cdup(int argc, char *argv[]) 2292 { 2293 int r; 2294 2295 if (argc == 0) { 2296 fprintf(ttyout, "usage: %s\n", argv[0]); 2297 code = -1; 2298 return; 2299 } 2300 r = command("CDUP"); 2301 if (r == ERROR && code == 500) { 2302 if (verbose) 2303 fputs("CDUP command not recognized, trying XCUP.\n", 2304 ttyout); 2305 r = command("XCUP"); 2306 } 2307 if (r == COMPLETE) { 2308 dirchange = 1; 2309 updateremotepwd(); 2310 } 2311 } 2312 2313 /* 2314 * Restart transfer at specific point 2315 */ 2316 void 2317 restart(int argc, char *argv[]) 2318 { 2319 2320 if (argc == 0 || argc > 2) { 2321 fprintf(ttyout, "usage: %s [restart-point]\n", argv[0]); 2322 code = -1; 2323 return; 2324 } 2325 if (! features[FEAT_REST_STREAM]) { 2326 fprintf(ttyout, 2327 "Restart is not supported by the remote server.\n"); 2328 return; 2329 } 2330 if (argc == 2) { 2331 off_t rp; 2332 char *ep; 2333 2334 rp = STRTOLL(argv[1], &ep, 10); 2335 if (rp < 0 || *ep != '\0') 2336 fprintf(ttyout, "restart: Invalid offset `%s'\n", 2337 argv[1]); 2338 else 2339 restart_point = rp; 2340 } 2341 if (restart_point == 0) 2342 fputs("No restart point defined.\n", ttyout); 2343 else 2344 fprintf(ttyout, 2345 "Restarting at " LLF " for next get, put or append\n", 2346 (LLT)restart_point); 2347 } 2348 2349 /* 2350 * Show remote system type 2351 */ 2352 void 2353 syst(int argc, char *argv[]) 2354 { 2355 int oldverbose = verbose; 2356 2357 if (argc == 0) { 2358 fprintf(ttyout, "usage: %s\n", argv[0]); 2359 code = -1; 2360 return; 2361 } 2362 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2363 (void)command("SYST"); 2364 verbose = oldverbose; 2365 } 2366 2367 void 2368 macdef(int argc, char *argv[]) 2369 { 2370 char *tmp; 2371 int c; 2372 2373 if (argc == 0) 2374 goto usage; 2375 if (macnum == 16) { 2376 fputs("Limit of 16 macros have already been defined.\n", 2377 ttyout); 2378 code = -1; 2379 return; 2380 } 2381 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2382 usage: 2383 fprintf(ttyout, "usage: %s macro_name\n", argv[0]); 2384 code = -1; 2385 return; 2386 } 2387 if (interactive) 2388 fputs( 2389 "Enter macro line by line, terminating it with a null line.\n", 2390 ttyout); 2391 (void)strlcpy(macros[macnum].mac_name, argv[1], 2392 sizeof(macros[macnum].mac_name)); 2393 if (macnum == 0) 2394 macros[macnum].mac_start = macbuf; 2395 else 2396 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2397 tmp = macros[macnum].mac_start; 2398 while (tmp != macbuf+4096) { 2399 if ((c = getchar()) == EOF) { 2400 fputs("macdef: end of file encountered.\n", ttyout); 2401 code = -1; 2402 return; 2403 } 2404 if ((*tmp = c) == '\n') { 2405 if (tmp == macros[macnum].mac_start) { 2406 macros[macnum++].mac_end = tmp; 2407 code = 0; 2408 return; 2409 } 2410 if (*(tmp-1) == '\0') { 2411 macros[macnum++].mac_end = tmp - 1; 2412 code = 0; 2413 return; 2414 } 2415 *tmp = '\0'; 2416 } 2417 tmp++; 2418 } 2419 while (1) { 2420 while ((c = getchar()) != '\n' && c != EOF) 2421 /* LOOP */; 2422 if (c == EOF || getchar() == '\n') { 2423 fputs("Macro not defined - 4K buffer exceeded.\n", 2424 ttyout); 2425 code = -1; 2426 return; 2427 } 2428 } 2429 } 2430 2431 /* 2432 * Get size of file on remote machine 2433 */ 2434 void 2435 sizecmd(int argc, char *argv[]) 2436 { 2437 off_t size; 2438 2439 if (argc == 0 || argc > 2 || 2440 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2441 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2442 code = -1; 2443 return; 2444 } 2445 size = remotesize(argv[1], 1); 2446 if (size != -1) 2447 fprintf(ttyout, 2448 "%s\t" LLF "\n", argv[1], (LLT)size); 2449 code = (size > 0); 2450 } 2451 2452 /* 2453 * Get last modification time of file on remote machine 2454 */ 2455 void 2456 modtime(int argc, char *argv[]) 2457 { 2458 time_t mtime; 2459 2460 if (argc == 0 || argc > 2 || 2461 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2462 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2463 code = -1; 2464 return; 2465 } 2466 mtime = remotemodtime(argv[1], 1); 2467 if (mtime != -1) 2468 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime))); 2469 code = (mtime > 0); 2470 } 2471 2472 /* 2473 * Show status on remote machine 2474 */ 2475 void 2476 rmtstatus(int argc, char *argv[]) 2477 { 2478 2479 if (argc == 0) { 2480 fprintf(ttyout, "usage: %s [remote-file]\n", argv[0]); 2481 code = -1; 2482 return; 2483 } 2484 COMMAND_1ARG(argc, argv, "STAT"); 2485 } 2486 2487 /* 2488 * Get file if modtime is more recent than current file 2489 */ 2490 void 2491 newer(int argc, char *argv[]) 2492 { 2493 2494 if (getit(argc, argv, -1, "w")) 2495 fprintf(ttyout, 2496 "Local file \"%s\" is newer than remote file \"%s\".\n", 2497 argv[2], argv[1]); 2498 } 2499 2500 /* 2501 * Display one local file through $PAGER. 2502 */ 2503 void 2504 lpage(int argc, char *argv[]) 2505 { 2506 int len; 2507 char *p, *pager, *locfile; 2508 2509 if (argc == 0 || argc > 2 || 2510 (argc == 1 && !another(&argc, &argv, "local-file"))) { 2511 fprintf(ttyout, "usage: %s local-file\n", argv[0]); 2512 code = -1; 2513 return; 2514 } 2515 if ((locfile = globulize(argv[1])) == NULL) { 2516 code = -1; 2517 return; 2518 } 2519 p = getoptionvalue("pager"); 2520 if (EMPTYSTRING(p)) 2521 p = DEFAULTPAGER; 2522 len = strlen(p) + strlen(locfile) + 2; 2523 pager = xmalloc(len); 2524 (void)strlcpy(pager, p, len); 2525 (void)strlcat(pager, " ", len); 2526 (void)strlcat(pager, locfile, len); 2527 system(pager); 2528 code = 0; 2529 (void)free(pager); 2530 (void)free(locfile); 2531 } 2532 2533 /* 2534 * Display one remote file through $PAGER. 2535 */ 2536 void 2537 page(int argc, char *argv[]) 2538 { 2539 int ohash, orestart_point, overbose, len; 2540 char *p, *pager; 2541 2542 if (argc == 0 || argc > 2 || 2543 (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2544 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 2545 code = -1; 2546 return; 2547 } 2548 p = getoptionvalue("pager"); 2549 if (EMPTYSTRING(p)) 2550 p = DEFAULTPAGER; 2551 len = strlen(p) + 2; 2552 pager = xmalloc(len); 2553 pager[0] = '|'; 2554 (void)strlcpy(pager + 1, p, len - 1); 2555 2556 ohash = hash; 2557 orestart_point = restart_point; 2558 overbose = verbose; 2559 hash = restart_point = verbose = 0; 2560 recvrequest("RETR", pager, argv[1], "r+", 1, 0); 2561 hash = ohash; 2562 restart_point = orestart_point; 2563 verbose = overbose; 2564 (void)free(pager); 2565 } 2566 2567 /* 2568 * Set the socket send or receive buffer size. 2569 */ 2570 void 2571 setxferbuf(int argc, char *argv[]) 2572 { 2573 int size, dir; 2574 2575 if (argc != 2) { 2576 usage: 2577 fprintf(ttyout, "usage: %s size\n", argv[0]); 2578 code = -1; 2579 return; 2580 } 2581 if (strcasecmp(argv[0], "sndbuf") == 0) 2582 dir = RATE_PUT; 2583 else if (strcasecmp(argv[0], "rcvbuf") == 0) 2584 dir = RATE_GET; 2585 else if (strcasecmp(argv[0], "xferbuf") == 0) 2586 dir = RATE_ALL; 2587 else 2588 goto usage; 2589 2590 if ((size = strsuftoi(argv[1])) == -1) 2591 goto usage; 2592 2593 if (size == 0) { 2594 fprintf(ttyout, "%s: size must be positive.\n", argv[0]); 2595 goto usage; 2596 } 2597 2598 if (dir & RATE_PUT) 2599 sndbuf_size = size; 2600 if (dir & RATE_GET) 2601 rcvbuf_size = size; 2602 fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", 2603 sndbuf_size, rcvbuf_size); 2604 code = 0; 2605 } 2606 2607 /* 2608 * Set or display options (defaults are provided by various env vars) 2609 */ 2610 void 2611 setoption(int argc, char *argv[]) 2612 { 2613 struct option *o; 2614 2615 code = -1; 2616 if (argc == 0 || (argc != 1 && argc != 3)) { 2617 fprintf(ttyout, "usage: %s [option value]\n", argv[0]); 2618 return; 2619 } 2620 2621 #define OPTIONINDENT ((int) sizeof("http_proxy")) 2622 if (argc == 1) { 2623 for (o = optiontab; o->name != NULL; o++) { 2624 fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, 2625 o->name, o->value ? o->value : ""); 2626 } 2627 } else { 2628 o = getoption(argv[1]); 2629 if (o == NULL) { 2630 fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2631 return; 2632 } 2633 FREEPTR(o->value); 2634 o->value = xstrdup(argv[2]); 2635 if (verbose) 2636 fprintf(ttyout, "Setting `%s' to `%s'.\n", 2637 o->name, o->value); 2638 } 2639 code = 0; 2640 } 2641 2642 /* 2643 * Unset an option 2644 */ 2645 void 2646 unsetoption(int argc, char *argv[]) 2647 { 2648 struct option *o; 2649 2650 code = -1; 2651 if (argc == 0 || argc != 2) { 2652 fprintf(ttyout, "usage: %s option\n", argv[0]); 2653 return; 2654 } 2655 2656 o = getoption(argv[1]); 2657 if (o == NULL) { 2658 fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2659 return; 2660 } 2661 FREEPTR(o->value); 2662 fprintf(ttyout, "Unsetting `%s'.\n", o->name); 2663 code = 0; 2664 } 2665 2666 /* 2667 * Display features supported by the remote host. 2668 */ 2669 void 2670 feat(int argc, char *argv[]) 2671 { 2672 int oldverbose = verbose; 2673 2674 if (argc == 0) { 2675 fprintf(ttyout, "usage: %s\n", argv[0]); 2676 code = -1; 2677 return; 2678 } 2679 if (! features[FEAT_FEAT]) { 2680 fprintf(ttyout, 2681 "FEAT is not supported by the remote server.\n"); 2682 return; 2683 } 2684 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2685 (void)command("FEAT"); 2686 verbose = oldverbose; 2687 } 2688 2689 void 2690 mlst(int argc, char *argv[]) 2691 { 2692 int oldverbose = verbose; 2693 2694 if (argc < 1 || argc > 2) { 2695 fprintf(ttyout, "usage: %s [remote-path]\n", argv[0]); 2696 code = -1; 2697 return; 2698 } 2699 if (! features[FEAT_MLST]) { 2700 fprintf(ttyout, 2701 "MLST is not supported by the remote server.\n"); 2702 return; 2703 } 2704 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2705 COMMAND_1ARG(argc, argv, "MLST"); 2706 verbose = oldverbose; 2707 } 2708 2709 void 2710 opts(int argc, char *argv[]) 2711 { 2712 int oldverbose = verbose; 2713 2714 if (argc < 2 || argc > 3) { 2715 fprintf(ttyout, "usage: %s command [options]\n", argv[0]); 2716 code = -1; 2717 return; 2718 } 2719 if (! features[FEAT_FEAT]) { 2720 fprintf(ttyout, 2721 "OPTS is not supported by the remote server.\n"); 2722 return; 2723 } 2724 verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2725 if (argc == 2) 2726 command("OPTS %s", argv[1]); 2727 else 2728 command("OPTS %s %s", argv[1], argv[2]); 2729 verbose = oldverbose; 2730 } 2731