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