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