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