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