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