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