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