1 /* $OpenBSD: cmds.c,v 1.45 2003/06/03 02:56:08 millert Exp $ */ 2 /* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */ 3 4 /* 5 * Copyright (C) 1997 and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1985, 1989, 1993, 1994 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 #ifndef lint 63 #if 0 64 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; 65 #else 66 static char rcsid[] = "$OpenBSD: cmds.c,v 1.45 2003/06/03 02:56:08 millert Exp $"; 67 #endif 68 #endif /* not lint */ 69 70 /* 71 * FTP User Program -- Command Routines. 72 */ 73 #include <sys/types.h> 74 #include <sys/socket.h> 75 #include <sys/stat.h> 76 #include <sys/wait.h> 77 #include <arpa/ftp.h> 78 79 #include <ctype.h> 80 #include <err.h> 81 #include <glob.h> 82 #include <netdb.h> 83 #include <stdio.h> 84 #include <stdlib.h> 85 #include <string.h> 86 #include <unistd.h> 87 88 #include "ftp_var.h" 89 #include "pathnames.h" 90 91 jmp_buf jabort; 92 char *mname; 93 char *home = "/"; 94 95 struct types { 96 char *t_name; 97 char *t_mode; 98 int t_type; 99 char *t_arg; 100 } types[] = { 101 { "ascii", "A", TYPE_A, 0 }, 102 { "binary", "I", TYPE_I, 0 }, 103 { "image", "I", TYPE_I, 0 }, 104 { "ebcdic", "E", TYPE_E, 0 }, 105 { "tenex", "L", TYPE_L, bytename }, 106 { NULL } 107 }; 108 109 /* 110 * Set transfer type. 111 */ 112 void 113 settype(argc, argv) 114 int argc; 115 char *argv[]; 116 { 117 struct types *p; 118 int comret; 119 120 if (argc > 2) { 121 char *sep; 122 123 fprintf(ttyout, "usage: %s [", argv[0]); 124 sep = " "; 125 for (p = types; p->t_name; p++) { 126 fprintf(ttyout, "%s%s", sep, p->t_name); 127 sep = " | "; 128 } 129 fputs(" ]\n", ttyout); 130 code = -1; 131 return; 132 } 133 if (argc < 2) { 134 fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 135 code = 0; 136 return; 137 } 138 for (p = types; p->t_name; p++) 139 if (strcmp(argv[1], p->t_name) == 0) 140 break; 141 if (p->t_name == 0) { 142 fprintf(ttyout, "%s: unknown mode.\n", argv[1]); 143 code = -1; 144 return; 145 } 146 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 147 comret = command("TYPE %s %s", p->t_mode, p->t_arg); 148 else 149 comret = command("TYPE %s", p->t_mode); 150 if (comret == COMPLETE) { 151 (void)strlcpy(typename, p->t_name, sizeof typename); 152 curtype = type = p->t_type; 153 } 154 } 155 156 /* 157 * Internal form of settype; changes current type in use with server 158 * without changing our notion of the type for data transfers. 159 * Used to change to and from ascii for listings. 160 */ 161 void 162 changetype(newtype, show) 163 int newtype, show; 164 { 165 struct types *p; 166 int comret, oldverbose = verbose; 167 168 if (newtype == 0) 169 newtype = TYPE_I; 170 if (newtype == curtype) 171 return; 172 if (debug == 0 && show == 0) 173 verbose = 0; 174 for (p = types; p->t_name; p++) 175 if (newtype == p->t_type) 176 break; 177 if (p->t_name == 0) { 178 warnx("internal error: unknown type %d.", newtype); 179 return; 180 } 181 if (newtype == TYPE_L && bytename[0] != '\0') 182 comret = command("TYPE %s %s", p->t_mode, bytename); 183 else 184 comret = command("TYPE %s", p->t_mode); 185 if (comret == COMPLETE) 186 curtype = newtype; 187 verbose = oldverbose; 188 } 189 190 char *stype[] = { 191 "type", 192 "", 193 0 194 }; 195 196 /* 197 * Set binary transfer type. 198 */ 199 /*VARARGS*/ 200 void 201 setbinary(argc, argv) 202 int argc; 203 char *argv[]; 204 { 205 206 stype[1] = "binary"; 207 settype(2, stype); 208 } 209 210 /* 211 * Set ascii transfer type. 212 */ 213 /*VARARGS*/ 214 void 215 setascii(argc, argv) 216 int argc; 217 char *argv[]; 218 { 219 220 stype[1] = "ascii"; 221 settype(2, stype); 222 } 223 224 /* 225 * Set tenex transfer type. 226 */ 227 /*VARARGS*/ 228 void 229 settenex(argc, argv) 230 int argc; 231 char *argv[]; 232 { 233 234 stype[1] = "tenex"; 235 settype(2, stype); 236 } 237 238 /* 239 * Set file transfer mode. 240 */ 241 /*ARGSUSED*/ 242 void 243 setftmode(argc, argv) 244 int argc; 245 char *argv[]; 246 { 247 248 fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 249 code = -1; 250 } 251 252 /* 253 * Set file transfer format. 254 */ 255 /*ARGSUSED*/ 256 void 257 setform(argc, argv) 258 int argc; 259 char *argv[]; 260 { 261 262 fprintf(ttyout, "We only support %s format, sorry.\n", formname); 263 code = -1; 264 } 265 266 /* 267 * Set file transfer structure. 268 */ 269 /*ARGSUSED*/ 270 void 271 setstruct(argc, argv) 272 int argc; 273 char *argv[]; 274 { 275 276 fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 277 code = -1; 278 } 279 280 /* 281 * Send a single file. 282 */ 283 void 284 put(argc, argv) 285 int argc; 286 char *argv[]; 287 { 288 char *cmd; 289 int loc = 0; 290 char *oldargv1, *oldargv2; 291 292 if (argc == 2) { 293 argc++; 294 argv[2] = argv[1]; 295 loc++; 296 } 297 if (argc < 2 && !another(&argc, &argv, "local-file")) 298 goto usage; 299 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 300 usage: 301 fprintf(ttyout, "usage: %s local-file [ remote-file ]\n", argv[0]); 302 code = -1; 303 return; 304 } 305 oldargv1 = argv[1]; 306 oldargv2 = argv[2]; 307 if (!globulize(&argv[1])) { 308 code = -1; 309 return; 310 } 311 /* 312 * If "globulize" modifies argv[1], and argv[2] is a copy of 313 * the old argv[1], make it a copy of the new argv[1]. 314 */ 315 if (argv[1] != oldargv1 && argv[2] == oldargv1) { 316 argv[2] = argv[1]; 317 } 318 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 319 if (loc && ntflag) { 320 argv[2] = dotrans(argv[2]); 321 } 322 if (loc && mapflag) { 323 argv[2] = domap(argv[2]); 324 } 325 sendrequest(cmd, argv[1], argv[2], 326 argv[1] != oldargv1 || argv[2] != oldargv2); 327 if (oldargv1 != argv[1]) /* free up after globulize() */ 328 free(argv[1]); 329 } 330 331 /* 332 * Send multiple files. 333 */ 334 void 335 mput(argc, argv) 336 int argc; 337 char *argv[]; 338 { 339 int i; 340 sig_t oldintr; 341 int ointer; 342 char *tp; 343 344 if (argc < 2 && !another(&argc, &argv, "local-files")) { 345 fprintf(ttyout, "usage: %s local-files\n", argv[0]); 346 code = -1; 347 return; 348 } 349 mname = argv[0]; 350 mflag = 1; 351 oldintr = signal(SIGINT, mabort); 352 (void)setjmp(jabort); 353 if (proxy) { 354 char *cp, *tp2, tmpbuf[MAXPATHLEN]; 355 356 while ((cp = remglob(argv, 0, NULL)) != NULL) { 357 if (*cp == '\0') { 358 mflag = 0; 359 continue; 360 } 361 if (mflag && confirm(argv[0], cp)) { 362 tp = cp; 363 if (mcase) { 364 while (*tp && !islower(*tp)) { 365 tp++; 366 } 367 if (!*tp) { 368 tp = cp; 369 tp2 = tmpbuf; 370 while ((*tp2 = *tp) != '\0') { 371 if (isupper(*tp2)) { 372 *tp2 = 373 tolower(*tp2); 374 } 375 tp++; 376 tp2++; 377 } 378 } 379 tp = tmpbuf; 380 } 381 if (ntflag) { 382 tp = dotrans(tp); 383 } 384 if (mapflag) { 385 tp = domap(tp); 386 } 387 sendrequest((sunique) ? "STOU" : "STOR", 388 cp, tp, cp != tp || !interactive); 389 if (!mflag && fromatty) { 390 ointer = interactive; 391 interactive = 1; 392 if (confirm("Continue with", "mput")) { 393 mflag++; 394 } 395 interactive = ointer; 396 } 397 } 398 } 399 (void)signal(SIGINT, oldintr); 400 mflag = 0; 401 return; 402 } 403 for (i = 1; i < argc; i++) { 404 char **cpp; 405 glob_t gl; 406 int flags; 407 408 if (!doglob) { 409 if (mflag && confirm(argv[0], argv[i])) { 410 tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 411 tp = (mapflag) ? domap(tp) : tp; 412 sendrequest((sunique) ? "STOU" : "STOR", 413 argv[i], tp, tp != argv[i] || !interactive); 414 if (!mflag && fromatty) { 415 ointer = interactive; 416 interactive = 1; 417 if (confirm("Continue with", "mput")) { 418 mflag++; 419 } 420 interactive = ointer; 421 } 422 } 423 continue; 424 } 425 426 memset(&gl, 0, sizeof(gl)); 427 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 428 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 429 warnx("%s: not found", argv[i]); 430 globfree(&gl); 431 continue; 432 } 433 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { 434 if (mflag && confirm(argv[0], *cpp)) { 435 tp = (ntflag) ? dotrans(*cpp) : *cpp; 436 tp = (mapflag) ? domap(tp) : tp; 437 sendrequest((sunique) ? "STOU" : "STOR", 438 *cpp, tp, *cpp != tp || !interactive); 439 if (!mflag && fromatty) { 440 ointer = interactive; 441 interactive = 1; 442 if (confirm("Continue with", "mput")) { 443 mflag++; 444 } 445 interactive = ointer; 446 } 447 } 448 } 449 globfree(&gl); 450 } 451 (void)signal(SIGINT, oldintr); 452 mflag = 0; 453 } 454 455 void 456 reget(argc, argv) 457 int argc; 458 char *argv[]; 459 { 460 461 (void)getit(argc, argv, 1, "r+w"); 462 } 463 464 void 465 get(argc, argv) 466 int argc; 467 char *argv[]; 468 { 469 470 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" ); 471 } 472 473 /* 474 * Receive one file. 475 */ 476 int 477 getit(argc, argv, restartit, mode) 478 int argc; 479 char *argv[]; 480 int restartit; 481 const char *mode; 482 { 483 int loc = 0; 484 int rval = 0; 485 char *oldargv1, *oldargv2, *globargv2; 486 487 if (argc == 2) { 488 argc++; 489 argv[2] = argv[1]; 490 loc++; 491 } 492 if (argc < 2 && !another(&argc, &argv, "remote-file")) 493 goto usage; 494 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 495 usage: 496 fprintf(ttyout, "usage: %s remote-file [ local-file ]\n", argv[0]); 497 code = -1; 498 return (0); 499 } 500 oldargv1 = argv[1]; 501 oldargv2 = argv[2]; 502 if (!globulize(&argv[2])) { 503 code = -1; 504 return (0); 505 } 506 globargv2 = argv[2]; 507 if (loc && mcase) { 508 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; 509 510 while (*tp && !islower(*tp)) { 511 tp++; 512 } 513 if (!*tp) { 514 tp = argv[2]; 515 tp2 = tmpbuf; 516 while ((*tp2 = *tp) != '\0') { 517 if (isupper(*tp2)) { 518 *tp2 = tolower(*tp2); 519 } 520 tp++; 521 tp2++; 522 } 523 argv[2] = tmpbuf; 524 } 525 } 526 if (loc && ntflag) 527 argv[2] = dotrans(argv[2]); 528 if (loc && mapflag) 529 argv[2] = domap(argv[2]); 530 if (restartit) { 531 struct stat stbuf; 532 int ret; 533 534 ret = stat(argv[2], &stbuf); 535 if (restartit == 1) { 536 if (ret < 0) { 537 warn("local: %s", argv[2]); 538 goto freegetit; 539 } 540 restart_point = stbuf.st_size; 541 } else { 542 if (ret == 0) { 543 time_t mtime; 544 545 mtime = remotemodtime(argv[1], 0); 546 if (mtime == -1) 547 goto freegetit; 548 if (stbuf.st_mtime >= mtime) { 549 rval = 1; 550 goto freegetit; 551 } 552 } 553 } 554 } 555 556 recvrequest("RETR", argv[2], argv[1], mode, 557 argv[1] != oldargv1 || argv[2] != oldargv2, loc); 558 restart_point = 0; 559 freegetit: 560 if (oldargv2 != globargv2) /* free up after globulize() */ 561 free(globargv2); 562 return (rval); 563 } 564 565 /* ARGSUSED */ 566 void 567 mabort(signo) 568 int signo; 569 { 570 int ointer, oconf; 571 572 alarmtimer(0); 573 putc('\n', ttyout); 574 (void)fflush(ttyout); 575 if (mflag && fromatty) { 576 ointer = interactive; 577 oconf = confirmrest; 578 interactive = 1; 579 confirmrest = 0; 580 if (confirm("Continue with", mname)) { 581 interactive = ointer; 582 confirmrest = oconf; 583 longjmp(jabort, 1); 584 } 585 interactive = ointer; 586 confirmrest = oconf; 587 } 588 mflag = 0; 589 longjmp(jabort, 1); 590 } 591 592 /* 593 * Get multiple files. 594 */ 595 void 596 mget(argc, argv) 597 int argc; 598 char *argv[]; 599 { 600 sig_t oldintr; 601 int ch, ointer; 602 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; 603 604 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 605 fprintf(ttyout, "usage: %s remote-files\n", argv[0]); 606 code = -1; 607 return; 608 } 609 mname = argv[0]; 610 mflag = 1; 611 oldintr = signal(SIGINT, mabort); 612 (void)setjmp(jabort); 613 while ((cp = remglob(argv, proxy, NULL)) != NULL) { 614 if (*cp == '\0') { 615 mflag = 0; 616 continue; 617 } 618 if (mflag && confirm(argv[0], cp)) { 619 tp = cp; 620 if (mcase) { 621 for (tp2 = tmpbuf; (ch = *tp++) != 0; ) 622 *tp2++ = isupper(ch) ? tolower(ch) : ch; 623 *tp2 = '\0'; 624 tp = tmpbuf; 625 } 626 if (ntflag) 627 tp = dotrans(tp); 628 if (mapflag) 629 tp = domap(tp); 630 recvrequest("RETR", tp, cp, "w", 631 tp != cp || !interactive, 1); 632 if (!mflag && fromatty) { 633 ointer = interactive; 634 interactive = 1; 635 if (confirm("Continue with", "mget")) { 636 mflag++; 637 } 638 interactive = ointer; 639 } 640 } 641 } 642 (void)signal(SIGINT, oldintr); 643 mflag = 0; 644 } 645 646 char * 647 onoff(bool) 648 int bool; 649 { 650 651 return (bool ? "on" : "off"); 652 } 653 654 /* 655 * Show status. 656 */ 657 /*ARGSUSED*/ 658 void 659 status(argc, argv) 660 int argc; 661 char *argv[]; 662 { 663 int i; 664 665 if (connected) 666 fprintf(ttyout, "Connected %sto %s.\n", 667 connected == -1 ? "and logged in" : "", hostname); 668 else 669 fputs("Not connected.\n", ttyout); 670 if (!proxy) { 671 pswitch(1); 672 if (connected) { 673 fprintf(ttyout, "Connected for proxy commands to %s.\n", 674 hostname); 675 } 676 else { 677 fputs("No proxy connection.\n", ttyout); 678 } 679 pswitch(0); 680 } 681 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 682 *gateserver ? gateserver : "(none)", gateport); 683 fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode)); 684 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 685 modename, typename, formname, structname); 686 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 687 onoff(verbose), onoff(bell), onoff(interactive), 688 onoff(doglob)); 689 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique), 690 onoff(runique)); 691 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 692 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag)); 693 if (ntflag) { 694 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 695 } 696 else { 697 fputs("Ntrans: off.\n", ttyout); 698 } 699 if (mapflag) { 700 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 701 } 702 else { 703 fputs("Nmap: off.\n", ttyout); 704 } 705 fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 706 onoff(hash), mark, onoff(progress)); 707 fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport)); 708 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 709 epsv4bad ? " (disabled for this connection)" : ""); 710 #ifndef SMALL 711 fprintf(ttyout, "Command line editing: %s.\n", onoff(editing)); 712 #endif /* !SMALL */ 713 if (macnum > 0) { 714 fputs("Macros:\n", ttyout); 715 for (i=0; i<macnum; i++) { 716 fprintf(ttyout, "\t%s\n", macros[i].mac_name); 717 } 718 } 719 code = 0; 720 } 721 722 /* 723 * Toggle a variable 724 */ 725 int 726 togglevar(argc, argv, var, mesg) 727 int argc; 728 char *argv[]; 729 int *var; 730 const char *mesg; 731 { 732 if (argc < 2) { 733 *var = !*var; 734 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 735 *var = 1; 736 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 737 *var = 0; 738 } else { 739 fprintf(ttyout, "usage: %s [ on | off ]\n", argv[0]); 740 return (-1); 741 } 742 if (mesg) 743 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 744 return (*var); 745 } 746 747 /* 748 * Set beep on cmd completed mode. 749 */ 750 /*VARARGS*/ 751 void 752 setbell(argc, argv) 753 int argc; 754 char *argv[]; 755 { 756 757 code = togglevar(argc, argv, &bell, "Bell mode"); 758 } 759 760 #ifndef SMALL 761 /* 762 * Set command line editing 763 */ 764 /*VARARGS*/ 765 void 766 setedit(argc, argv) 767 int argc; 768 char *argv[]; 769 { 770 771 code = togglevar(argc, argv, &editing, "Editing mode"); 772 controlediting(); 773 } 774 #endif /* !SMALL */ 775 776 /* 777 * Toggle use of IPv4 EPSV/EPRT 778 */ 779 /*VARARGS*/ 780 void 781 setepsv4(argc, argv) 782 int argc; 783 char *argv[]; 784 { 785 786 code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4"); 787 epsv4bad = 0; 788 } 789 790 /* 791 * Turn on packet tracing. 792 */ 793 /*VARARGS*/ 794 void 795 settrace(argc, argv) 796 int argc; 797 char *argv[]; 798 { 799 800 code = togglevar(argc, argv, &trace, "Packet tracing"); 801 } 802 803 /* 804 * Toggle hash mark printing during transfers, or set hash mark bytecount. 805 */ 806 /*VARARGS*/ 807 void 808 sethash(argc, argv) 809 int argc; 810 char *argv[]; 811 { 812 if (argc == 1) 813 hash = !hash; 814 else if (argc != 2) { 815 fprintf(ttyout, "usage: %s [ on | off | bytecount ]\n", argv[0]); 816 code = -1; 817 return; 818 } else if (strcasecmp(argv[1], "on") == 0) 819 hash = 1; 820 else if (strcasecmp(argv[1], "off") == 0) 821 hash = 0; 822 else { 823 long nmark; 824 char *ep; 825 826 nmark = strtol(argv[1], &ep, 10); 827 if (nmark < 1 || nmark > INT_MAX || *ep != '\0') { 828 fprintf(ttyout, "%s: bad bytecount value.\n", argv[1]); 829 code = -1; 830 return; 831 } 832 mark = nmark; 833 hash = 1; 834 } 835 fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 836 if (hash) 837 fprintf(ttyout, " (%d bytes/hash mark)", mark); 838 fputs(".\n", ttyout); 839 code = hash; 840 } 841 842 /* 843 * Turn on printing of server echo's. 844 */ 845 /*VARARGS*/ 846 void 847 setverbose(argc, argv) 848 int argc; 849 char *argv[]; 850 { 851 852 code = togglevar(argc, argv, &verbose, "Verbose mode"); 853 } 854 855 /* 856 * Toggle PORT/LPRT cmd use before each data connection. 857 */ 858 /*VARARGS*/ 859 void 860 setport(argc, argv) 861 int argc; 862 char *argv[]; 863 { 864 865 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 866 } 867 868 /* 869 * Toggle transfer progress bar. 870 */ 871 /*VARARGS*/ 872 void 873 setprogress(argc, argv) 874 int argc; 875 char *argv[]; 876 { 877 878 code = togglevar(argc, argv, &progress, "Progress bar"); 879 } 880 881 /* 882 * Turn on interactive prompting during mget, mput, and mdelete. 883 */ 884 /*VARARGS*/ 885 void 886 setprompt(argc, argv) 887 int argc; 888 char *argv[]; 889 { 890 891 code = togglevar(argc, argv, &interactive, "Interactive mode"); 892 } 893 894 /* 895 * Toggle gate-ftp mode, or set gate-ftp server 896 */ 897 /*VARARGS*/ 898 void 899 setgate(argc, argv) 900 int argc; 901 char *argv[]; 902 { 903 static char gsbuf[MAXHOSTNAMELEN]; 904 905 if (argc > 3) { 906 fprintf(ttyout, "usage: %s [ on | off | gateserver [ port ] ]\n", 907 argv[0]); 908 code = -1; 909 return; 910 } else if (argc < 2) { 911 gatemode = !gatemode; 912 } else { 913 if (argc == 2 && strcasecmp(argv[1], "on") == 0) 914 gatemode = 1; 915 else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 916 gatemode = 0; 917 else { 918 if (argc == 3) { 919 #if 0 920 char *ep; 921 long port; 922 923 port = strtol(argv[2], &ep, 10); 924 if (port < 0 || port > USHRT_MAX || *ep != '\0') { 925 fprintf(ttyout, 926 "%s: bad gateport value.\n", 927 argv[2]); 928 code = -1; 929 return; 930 } 931 gateport = htons(port); 932 #else 933 gateport = strdup(argv[2]); 934 if (gateport == NULL) 935 err(1, NULL); 936 #endif 937 } 938 strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 939 gateserver = gsbuf; 940 gatemode = 1; 941 } 942 } 943 if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 944 fprintf(ttyout, 945 "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 946 gatemode = 0; 947 } else { 948 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 949 onoff(gatemode), 950 *gateserver ? gateserver : "(none)", gateport); 951 } 952 code = gatemode; 953 } 954 955 /* 956 * Toggle metacharacter interpretation on local file names. 957 */ 958 /*VARARGS*/ 959 void 960 setglob(argc, argv) 961 int argc; 962 char *argv[]; 963 { 964 965 code = togglevar(argc, argv, &doglob, "Globbing"); 966 } 967 968 /* 969 * Toggle preserving modification times on retrieved files. 970 */ 971 /*VARARGS*/ 972 void 973 setpreserve(argc, argv) 974 int argc; 975 char *argv[]; 976 { 977 978 code = togglevar(argc, argv, &preserve, "Preserve modification times"); 979 } 980 981 /* 982 * Set debugging mode on/off and/or set level of debugging. 983 */ 984 /*VARARGS*/ 985 void 986 setdebug(argc, argv) 987 int argc; 988 char *argv[]; 989 { 990 if (argc > 2) { 991 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n", argv[0]); 992 code = -1; 993 return; 994 } else if (argc == 2) { 995 if (strcasecmp(argv[1], "on") == 0) 996 debug = 1; 997 else if (strcasecmp(argv[1], "off") == 0) 998 debug = 0; 999 else { 1000 char *ep; 1001 long val; 1002 1003 val = strtol(argv[1], &ep, 10); 1004 if (val < 0 || val > INT_MAX || *ep != '\0') { 1005 fprintf(ttyout, "%s: bad debugging value.\n", 1006 argv[1]); 1007 code = -1; 1008 return; 1009 } 1010 debug = (int)val; 1011 } 1012 } else 1013 debug = !debug; 1014 if (debug) 1015 options |= SO_DEBUG; 1016 else 1017 options &= ~SO_DEBUG; 1018 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug); 1019 code = debug > 0; 1020 } 1021 1022 /* 1023 * Set current working directory on remote machine. 1024 */ 1025 void 1026 cd(argc, argv) 1027 int argc; 1028 char *argv[]; 1029 { 1030 int r; 1031 1032 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) || 1033 argc > 2) { 1034 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); 1035 code = -1; 1036 return; 1037 } 1038 r = command("CWD %s", argv[1]); 1039 if (r == ERROR && code == 500) { 1040 if (verbose) 1041 fputs("CWD command not recognized, trying XCWD.\n", ttyout); 1042 r = command("XCWD %s", argv[1]); 1043 } 1044 if (r == ERROR && code == 550) { 1045 dirchange = 0; 1046 return; 1047 } 1048 if (r == COMPLETE) 1049 dirchange = 1; 1050 } 1051 1052 /* 1053 * Set current working directory on local machine. 1054 */ 1055 void 1056 lcd(argc, argv) 1057 int argc; 1058 char *argv[]; 1059 { 1060 char buf[MAXPATHLEN]; 1061 char *oldargv1; 1062 1063 if (argc < 2) 1064 argc++, argv[1] = home; 1065 if (argc != 2) { 1066 fprintf(ttyout, "usage: %s local-directory\n", argv[0]); 1067 code = -1; 1068 return; 1069 } 1070 oldargv1 = argv[1]; 1071 if (!globulize(&argv[1])) { 1072 code = -1; 1073 return; 1074 } 1075 if (chdir(argv[1]) < 0) { 1076 warn("local: %s", argv[1]); 1077 code = -1; 1078 } else { 1079 if (getcwd(buf, sizeof(buf)) != NULL) 1080 fprintf(ttyout, "Local directory now %s\n", buf); 1081 else 1082 warn("getcwd: %s", argv[1]); 1083 code = 0; 1084 } 1085 if (oldargv1 != argv[1]) /* free up after globulize() */ 1086 free(argv[1]); 1087 } 1088 1089 /* 1090 * Delete a single file. 1091 */ 1092 void 1093 delete(argc, argv) 1094 int argc; 1095 char *argv[]; 1096 { 1097 1098 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) { 1099 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 1100 code = -1; 1101 return; 1102 } 1103 (void)command("DELE %s", argv[1]); 1104 } 1105 1106 /* 1107 * Delete multiple files. 1108 */ 1109 void 1110 mdelete(argc, argv) 1111 int argc; 1112 char *argv[]; 1113 { 1114 sig_t oldintr; 1115 int ointer; 1116 char *cp; 1117 1118 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 1119 fprintf(ttyout, "usage: %s remote-files\n", argv[0]); 1120 code = -1; 1121 return; 1122 } 1123 mname = argv[0]; 1124 mflag = 1; 1125 oldintr = signal(SIGINT, mabort); 1126 (void)setjmp(jabort); 1127 while ((cp = remglob(argv, 0, NULL)) != NULL) { 1128 if (*cp == '\0') { 1129 mflag = 0; 1130 continue; 1131 } 1132 if (mflag && confirm(argv[0], cp)) { 1133 (void)command("DELE %s", cp); 1134 if (!mflag && fromatty) { 1135 ointer = interactive; 1136 interactive = 1; 1137 if (confirm("Continue with", "mdelete")) { 1138 mflag++; 1139 } 1140 interactive = ointer; 1141 } 1142 } 1143 } 1144 (void)signal(SIGINT, oldintr); 1145 mflag = 0; 1146 } 1147 1148 /* 1149 * Rename a remote file. 1150 */ 1151 void 1152 renamefile(argc, argv) 1153 int argc; 1154 char *argv[]; 1155 { 1156 1157 if (argc < 2 && !another(&argc, &argv, "from-name")) 1158 goto usage; 1159 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1160 usage: 1161 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]); 1162 code = -1; 1163 return; 1164 } 1165 if (command("RNFR %s", argv[1]) == CONTINUE) 1166 (void)command("RNTO %s", argv[2]); 1167 } 1168 1169 /* 1170 * Get a directory listing of remote files. 1171 */ 1172 void 1173 ls(argc, argv) 1174 int argc; 1175 char *argv[]; 1176 { 1177 const char *cmd; 1178 char *oldargv2, *globargv2; 1179 1180 if (argc < 2) 1181 argc++, argv[1] = NULL; 1182 if (argc < 3) 1183 argc++, argv[2] = "-"; 1184 if (argc > 3) { 1185 fprintf(ttyout, "usage: %s remote-directory local-file\n", argv[0]); 1186 code = -1; 1187 return; 1188 } 1189 cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST"; 1190 oldargv2 = argv[2]; 1191 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1192 code = -1; 1193 return; 1194 } 1195 globargv2 = argv[2]; 1196 if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) || 1197 !confirm("output to local-file:", argv[2]))) { 1198 code = -1; 1199 goto freels; 1200 } 1201 recvrequest(cmd, argv[2], argv[1], "w", 0, 0); 1202 1203 /* flush results in case commands are coming from a pipe */ 1204 fflush(ttyout); 1205 freels: 1206 if (argv[2] != globargv2) /* free up after globulize() */ 1207 free(argv[2]); 1208 if (globargv2 != oldargv2) 1209 free(globargv2); 1210 } 1211 1212 /* 1213 * Get a directory listing of multiple remote files. 1214 */ 1215 void 1216 mls(argc, argv) 1217 int argc; 1218 char *argv[]; 1219 { 1220 sig_t oldintr; 1221 int ointer, i; 1222 char mode[1], *dest, *odest; 1223 1224 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1225 goto usage; 1226 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1227 usage: 1228 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]); 1229 code = -1; 1230 return; 1231 } 1232 odest = dest = argv[argc - 1]; 1233 argv[argc - 1] = NULL; 1234 if (strcmp(dest, "-") && *dest != '|') 1235 if (!globulize(&dest) || 1236 !confirm("output to local-file:", dest)) { 1237 code = -1; 1238 return; 1239 } 1240 mname = argv[0]; 1241 mflag = 1; 1242 oldintr = signal(SIGINT, mabort); 1243 (void)setjmp(jabort); 1244 for (i = 1; mflag && i < argc-1; ++i) { 1245 *mode = (i == 1) ? 'w' : 'a'; 1246 recvrequest("LIST", dest, argv[i], mode, 0, 0); 1247 if (!mflag && fromatty) { 1248 ointer = interactive; 1249 interactive = 1; 1250 if (confirm("Continue with", argv[0])) { 1251 mflag ++; 1252 } 1253 interactive = ointer; 1254 } 1255 } 1256 (void)signal(SIGINT, oldintr); 1257 mflag = 0; 1258 if (dest != odest) /* free up after globulize() */ 1259 free(dest); 1260 } 1261 1262 /* 1263 * Do a shell escape 1264 */ 1265 /*ARGSUSED*/ 1266 void 1267 shell(argc, argv) 1268 int argc; 1269 char *argv[]; 1270 { 1271 pid_t pid; 1272 sig_t old1, old2; 1273 char shellnam[MAXPATHLEN], *shell, *namep; 1274 int wait_status; 1275 1276 old1 = signal (SIGINT, SIG_IGN); 1277 old2 = signal (SIGQUIT, SIG_IGN); 1278 if ((pid = fork()) == 0) { 1279 for (pid = 3; pid < 20; pid++) 1280 (void)close(pid); 1281 (void)signal(SIGINT, SIG_DFL); 1282 (void)signal(SIGQUIT, SIG_DFL); 1283 shell = getenv("SHELL"); 1284 if (shell == NULL || *shell == '\0') 1285 shell = _PATH_BSHELL; 1286 namep = strrchr(shell, '/'); 1287 if (namep == NULL) 1288 namep = shell; 1289 shellnam[0] = '-'; 1290 (void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1); 1291 if (strcmp(namep, "sh") != 0) 1292 shellnam[0] = '+'; 1293 if (debug) { 1294 fputs(shell, ttyout); 1295 fputc('\n', ttyout); 1296 (void)fflush(ttyout); 1297 } 1298 if (argc > 1) { 1299 execl(shell, shellnam, "-c", altarg, (char *)0); 1300 } 1301 else { 1302 execl(shell, shellnam, (char *)0); 1303 } 1304 warn("%s", shell); 1305 code = -1; 1306 exit(1); 1307 } 1308 if (pid > 0) 1309 while (wait(&wait_status) != pid) 1310 ; 1311 (void)signal(SIGINT, old1); 1312 (void)signal(SIGQUIT, old2); 1313 if (pid == -1) { 1314 warn("Try again later"); 1315 code = -1; 1316 } 1317 else { 1318 code = 0; 1319 } 1320 } 1321 1322 /* 1323 * Send new user information (re-login) 1324 */ 1325 void 1326 user(argc, argv) 1327 int argc; 1328 char *argv[]; 1329 { 1330 char acct[80]; 1331 int n, aflag = 0; 1332 1333 if (argc < 2) 1334 (void)another(&argc, &argv, "username"); 1335 if (argc < 2 || argc > 4) { 1336 fprintf(ttyout, "usage: %s username [password] [account]\n", argv[0]); 1337 code = -1; 1338 return; 1339 } 1340 n = command("USER %s", argv[1]); 1341 if (n == CONTINUE) { 1342 if (argc < 3 ) 1343 argv[2] = getpass("Password: "), argc++; 1344 n = command("PASS %s", argv[2]); 1345 } 1346 if (n == CONTINUE) { 1347 if (argc < 4) { 1348 (void)fputs("Account: ", ttyout); 1349 (void)fflush(ttyout); 1350 (void)fgets(acct, sizeof(acct) - 1, stdin); 1351 acct[strlen(acct) - 1] = '\0'; 1352 argv[3] = acct; argc++; 1353 } 1354 n = command("ACCT %s", argv[3]); 1355 aflag++; 1356 } 1357 if (n != COMPLETE) { 1358 fputs("Login failed.\n", ttyout); 1359 return; 1360 } 1361 if (!aflag && argc == 4) { 1362 (void)command("ACCT %s", argv[3]); 1363 } 1364 connected = -1; 1365 } 1366 1367 /* 1368 * Print working directory on remote machine. 1369 */ 1370 /*VARARGS*/ 1371 void 1372 pwd(argc, argv) 1373 int argc; 1374 char *argv[]; 1375 { 1376 int oldverbose = verbose; 1377 1378 /* 1379 * If we aren't verbose, this doesn't do anything! 1380 */ 1381 verbose = 1; 1382 if (command("PWD") == ERROR && code == 500) { 1383 fputs("PWD command not recognized, trying XPWD.\n", ttyout); 1384 (void)command("XPWD"); 1385 } 1386 verbose = oldverbose; 1387 } 1388 1389 /* 1390 * Print working directory on local machine. 1391 */ 1392 void 1393 lpwd(argc, argv) 1394 int argc; 1395 char *argv[]; 1396 { 1397 char buf[MAXPATHLEN]; 1398 1399 if (getcwd(buf, sizeof(buf)) != NULL) 1400 fprintf(ttyout, "Local directory %s\n", buf); 1401 else 1402 warn("getcwd"); 1403 code = 0; 1404 } 1405 1406 /* 1407 * Make a directory. 1408 */ 1409 void 1410 makedir(argc, argv) 1411 int argc; 1412 char *argv[]; 1413 { 1414 1415 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1416 argc > 2) { 1417 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1418 code = -1; 1419 return; 1420 } 1421 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1422 if (verbose) 1423 fputs("MKD command not recognized, trying XMKD.\n", ttyout); 1424 (void)command("XMKD %s", argv[1]); 1425 } 1426 } 1427 1428 /* 1429 * Remove a directory. 1430 */ 1431 void 1432 removedir(argc, argv) 1433 int argc; 1434 char *argv[]; 1435 { 1436 1437 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1438 argc > 2) { 1439 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1440 code = -1; 1441 return; 1442 } 1443 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1444 if (verbose) 1445 fputs("RMD command not recognized, trying XRMD.\n", ttyout); 1446 (void)command("XRMD %s", argv[1]); 1447 } 1448 } 1449 1450 /* 1451 * Send a line, verbatim, to the remote machine. 1452 */ 1453 void 1454 quote(argc, argv) 1455 int argc; 1456 char *argv[]; 1457 { 1458 1459 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1460 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1461 code = -1; 1462 return; 1463 } 1464 quote1("", argc, argv); 1465 } 1466 1467 /* 1468 * Send a SITE command to the remote machine. The line 1469 * is sent verbatim to the remote machine, except that the 1470 * word "SITE" is added at the front. 1471 */ 1472 void 1473 site(argc, argv) 1474 int argc; 1475 char *argv[]; 1476 { 1477 1478 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1479 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); 1480 code = -1; 1481 return; 1482 } 1483 quote1("SITE", argc, argv); 1484 } 1485 1486 /* 1487 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1488 * Send the result as a one-line command and get response. 1489 */ 1490 void 1491 quote1(initial, argc, argv) 1492 const char *initial; 1493 int argc; 1494 char *argv[]; 1495 { 1496 int i, len; 1497 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1498 1499 (void)strlcpy(buf, initial, sizeof(buf)); 1500 if (argc > 1) { 1501 for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) { 1502 1503 /* Sanity check */ 1504 if (len >= sizeof(buf) - 1) 1505 break; 1506 1507 /* Space for next arg */ 1508 if (len > 1) 1509 buf[len++] = ' '; 1510 1511 /* Sanity check */ 1512 if (len >= sizeof(buf) - 1) 1513 break; 1514 1515 /* Copy next argument, NUL terminate always */ 1516 strlcpy(&buf[len], argv[i], sizeof(buf) - len); 1517 1518 /* Update string length */ 1519 len = strlen(buf); 1520 } 1521 } 1522 1523 /* Make double (triple?) sure the sucker is NUL terminated */ 1524 buf[sizeof(buf) - 1] = '\0'; 1525 1526 if (command("%s", buf) == PRELIM) { 1527 while (getreply(0) == PRELIM) 1528 continue; 1529 } 1530 } 1531 1532 void 1533 do_chmod(argc, argv) 1534 int argc; 1535 char *argv[]; 1536 { 1537 1538 if (argc < 2 && !another(&argc, &argv, "mode")) 1539 goto usage; 1540 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) { 1541 usage: 1542 fprintf(ttyout, "usage: %s mode file-name\n", argv[0]); 1543 code = -1; 1544 return; 1545 } 1546 (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1547 } 1548 1549 void 1550 do_umask(argc, argv) 1551 int argc; 1552 char *argv[]; 1553 { 1554 int oldverbose = verbose; 1555 1556 verbose = 1; 1557 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1558 verbose = oldverbose; 1559 } 1560 1561 void 1562 idle(argc, argv) 1563 int argc; 1564 char *argv[]; 1565 { 1566 int oldverbose = verbose; 1567 1568 verbose = 1; 1569 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1570 verbose = oldverbose; 1571 } 1572 1573 /* 1574 * Ask the other side for help. 1575 */ 1576 void 1577 rmthelp(argc, argv) 1578 int argc; 1579 char *argv[]; 1580 { 1581 int oldverbose = verbose; 1582 1583 verbose = 1; 1584 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1585 verbose = oldverbose; 1586 } 1587 1588 /* 1589 * Terminate session and exit. 1590 */ 1591 /*VARARGS*/ 1592 void 1593 quit(argc, argv) 1594 int argc; 1595 char *argv[]; 1596 { 1597 1598 if (connected) 1599 disconnect(0, 0); 1600 pswitch(1); 1601 if (connected) { 1602 disconnect(0, 0); 1603 } 1604 exit(0); 1605 } 1606 1607 /* 1608 * Terminate session, but don't exit. 1609 */ 1610 void 1611 disconnect(argc, argv) 1612 int argc; 1613 char *argv[]; 1614 { 1615 1616 if (!connected) 1617 return; 1618 (void)command("QUIT"); 1619 if (cout) { 1620 (void)fclose(cout); 1621 } 1622 cout = NULL; 1623 connected = 0; 1624 data = -1; 1625 if (!proxy) { 1626 macnum = 0; 1627 } 1628 } 1629 1630 void 1631 account(argc, argv) 1632 int argc; 1633 char *argv[]; 1634 { 1635 char *ap; 1636 1637 if (argc > 2) { 1638 fprintf(ttyout, "usage: %s [password]\n", argv[0]); 1639 code = -1; 1640 return; 1641 } 1642 else if (argc == 2) 1643 ap = argv[1]; 1644 else 1645 ap = getpass("Account:"); 1646 (void)command("ACCT %s", ap); 1647 } 1648 1649 jmp_buf abortprox; 1650 1651 void 1652 proxabort(notused) 1653 int notused; 1654 { 1655 1656 alarmtimer(0); 1657 if (!proxy) { 1658 pswitch(1); 1659 } 1660 if (connected) { 1661 proxflag = 1; 1662 } 1663 else { 1664 proxflag = 0; 1665 } 1666 pswitch(0); 1667 longjmp(abortprox, 1); 1668 } 1669 1670 void 1671 doproxy(argc, argv) 1672 int argc; 1673 char *argv[]; 1674 { 1675 struct cmd *c; 1676 int cmdpos; 1677 sig_t oldintr; 1678 1679 if (argc < 2 && !another(&argc, &argv, "command")) { 1680 fprintf(ttyout, "usage: %s command\n", argv[0]); 1681 code = -1; 1682 return; 1683 } 1684 c = getcmd(argv[1]); 1685 if (c == (struct cmd *) -1) { 1686 fputs("?Ambiguous command.\n", ttyout); 1687 (void)fflush(ttyout); 1688 code = -1; 1689 return; 1690 } 1691 if (c == 0) { 1692 fputs("?Invalid command.\n", ttyout); 1693 (void)fflush(ttyout); 1694 code = -1; 1695 return; 1696 } 1697 if (!c->c_proxy) { 1698 fputs("?Invalid proxy command.\n", ttyout); 1699 (void)fflush(ttyout); 1700 code = -1; 1701 return; 1702 } 1703 if (setjmp(abortprox)) { 1704 code = -1; 1705 return; 1706 } 1707 oldintr = signal(SIGINT, proxabort); 1708 pswitch(1); 1709 if (c->c_conn && !connected) { 1710 fputs("Not connected.\n", ttyout); 1711 (void)fflush(ttyout); 1712 pswitch(0); 1713 (void)signal(SIGINT, oldintr); 1714 code = -1; 1715 return; 1716 } 1717 cmdpos = strcspn(line, " \t"); 1718 if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1719 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1720 (*c->c_handler)(argc-1, argv+1); 1721 if (connected) { 1722 proxflag = 1; 1723 } 1724 else { 1725 proxflag = 0; 1726 } 1727 pswitch(0); 1728 (void)signal(SIGINT, oldintr); 1729 } 1730 1731 void 1732 setcase(argc, argv) 1733 int argc; 1734 char *argv[]; 1735 { 1736 1737 code = togglevar(argc, argv, &mcase, "Case mapping"); 1738 } 1739 1740 void 1741 setcr(argc, argv) 1742 int argc; 1743 char *argv[]; 1744 { 1745 1746 code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1747 } 1748 1749 void 1750 setntrans(argc, argv) 1751 int argc; 1752 char *argv[]; 1753 { 1754 if (argc == 1) { 1755 ntflag = 0; 1756 fputs("Ntrans off.\n", ttyout); 1757 code = ntflag; 1758 return; 1759 } 1760 ntflag++; 1761 code = ntflag; 1762 (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1763 if (argc == 2) { 1764 ntout[0] = '\0'; 1765 return; 1766 } 1767 (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1768 } 1769 1770 char * 1771 dotrans(name) 1772 char *name; 1773 { 1774 static char new[MAXPATHLEN]; 1775 char *cp1, *cp2 = new; 1776 int i, ostop, found; 1777 1778 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1779 continue; 1780 for (cp1 = name; *cp1; cp1++) { 1781 found = 0; 1782 for (i = 0; *(ntin + i) && i < 16; i++) { 1783 if (*cp1 == *(ntin + i)) { 1784 found++; 1785 if (i < ostop) { 1786 *cp2++ = *(ntout + i); 1787 } 1788 break; 1789 } 1790 } 1791 if (!found) { 1792 *cp2++ = *cp1; 1793 } 1794 } 1795 *cp2 = '\0'; 1796 return (new); 1797 } 1798 1799 void 1800 setnmap(argc, argv) 1801 int argc; 1802 char *argv[]; 1803 { 1804 char *cp; 1805 1806 if (argc == 1) { 1807 mapflag = 0; 1808 fputs("Nmap off.\n", ttyout); 1809 code = mapflag; 1810 return; 1811 } 1812 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 1813 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]); 1814 code = -1; 1815 return; 1816 } 1817 mapflag = 1; 1818 code = 1; 1819 cp = strchr(altarg, ' '); 1820 if (proxy) { 1821 while(*++cp == ' ') 1822 continue; 1823 altarg = cp; 1824 cp = strchr(altarg, ' '); 1825 } 1826 *cp = '\0'; 1827 (void)strncpy(mapin, altarg, MAXPATHLEN - 1); 1828 while (*++cp == ' ') 1829 continue; 1830 (void)strncpy(mapout, cp, MAXPATHLEN - 1); 1831 } 1832 1833 char * 1834 domap(name) 1835 char *name; 1836 { 1837 static char new[MAXPATHLEN]; 1838 char *cp1 = name, *cp2 = mapin; 1839 char *tp[9], *te[9]; 1840 int i, toks[9], toknum = 0, match = 1; 1841 1842 for (i=0; i < 9; ++i) { 1843 toks[i] = 0; 1844 } 1845 while (match && *cp1 && *cp2) { 1846 switch (*cp2) { 1847 case '\\': 1848 if (*++cp2 != *cp1) { 1849 match = 0; 1850 } 1851 break; 1852 case '$': 1853 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1854 if (*cp1 != *(++cp2+1)) { 1855 toks[toknum = *cp2 - '1']++; 1856 tp[toknum] = cp1; 1857 while (*++cp1 && *(cp2+1) 1858 != *cp1); 1859 te[toknum] = cp1; 1860 } 1861 cp2++; 1862 break; 1863 } 1864 /* FALLTHROUGH */ 1865 default: 1866 if (*cp2 != *cp1) { 1867 match = 0; 1868 } 1869 break; 1870 } 1871 if (match && *cp1) { 1872 cp1++; 1873 } 1874 if (match && *cp2) { 1875 cp2++; 1876 } 1877 } 1878 if (!match && *cp1) /* last token mismatch */ 1879 { 1880 toks[toknum] = 0; 1881 } 1882 cp1 = new; 1883 *cp1 = '\0'; 1884 cp2 = mapout; 1885 while (*cp2) { 1886 match = 0; 1887 switch (*cp2) { 1888 case '\\': 1889 if (*(cp2 + 1)) { 1890 *cp1++ = *++cp2; 1891 } 1892 break; 1893 case '[': 1894 LOOP: 1895 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1896 if (*++cp2 == '0') { 1897 char *cp3 = name; 1898 1899 while (*cp3) { 1900 *cp1++ = *cp3++; 1901 } 1902 match = 1; 1903 } 1904 else if (toks[toknum = *cp2 - '1']) { 1905 char *cp3 = tp[toknum]; 1906 1907 while (cp3 != te[toknum]) { 1908 *cp1++ = *cp3++; 1909 } 1910 match = 1; 1911 } 1912 } 1913 else { 1914 while (*cp2 && *cp2 != ',' && 1915 *cp2 != ']') { 1916 if (*cp2 == '\\') { 1917 cp2++; 1918 } 1919 else if (*cp2 == '$' && 1920 isdigit(*(cp2+1))) { 1921 if (*++cp2 == '0') { 1922 char *cp3 = name; 1923 1924 while (*cp3) { 1925 *cp1++ = *cp3++; 1926 } 1927 } 1928 else if (toks[toknum = 1929 *cp2 - '1']) { 1930 char *cp3=tp[toknum]; 1931 1932 while (cp3 != 1933 te[toknum]) { 1934 *cp1++ = *cp3++; 1935 } 1936 } 1937 } 1938 else if (*cp2) { 1939 *cp1++ = *cp2++; 1940 } 1941 } 1942 if (!*cp2) { 1943 fputs( 1944 "nmap: unbalanced brackets.\n", ttyout); 1945 return (name); 1946 } 1947 match = 1; 1948 cp2--; 1949 } 1950 if (match) { 1951 while (*++cp2 && *cp2 != ']') { 1952 if (*cp2 == '\\' && *(cp2 + 1)) { 1953 cp2++; 1954 } 1955 } 1956 if (!*cp2) { 1957 fputs( 1958 "nmap: unbalanced brackets.\n", ttyout); 1959 return (name); 1960 } 1961 break; 1962 } 1963 switch (*++cp2) { 1964 case ',': 1965 goto LOOP; 1966 case ']': 1967 break; 1968 default: 1969 cp2--; 1970 goto LOOP; 1971 } 1972 break; 1973 case '$': 1974 if (isdigit(*(cp2 + 1))) { 1975 if (*++cp2 == '0') { 1976 char *cp3 = name; 1977 1978 while (*cp3) { 1979 *cp1++ = *cp3++; 1980 } 1981 } 1982 else if (toks[toknum = *cp2 - '1']) { 1983 char *cp3 = tp[toknum]; 1984 1985 while (cp3 != te[toknum]) { 1986 *cp1++ = *cp3++; 1987 } 1988 } 1989 break; 1990 } 1991 /* intentional drop through */ 1992 default: 1993 *cp1++ = *cp2; 1994 break; 1995 } 1996 cp2++; 1997 } 1998 *cp1 = '\0'; 1999 if (!*new) { 2000 return (name); 2001 } 2002 return (new); 2003 } 2004 2005 void 2006 setpassive(argc, argv) 2007 int argc; 2008 char *argv[]; 2009 { 2010 2011 code = togglevar(argc, argv, &passivemode, 2012 verbose ? "Passive mode" : NULL); 2013 } 2014 2015 void 2016 setsunique(argc, argv) 2017 int argc; 2018 char *argv[]; 2019 { 2020 2021 code = togglevar(argc, argv, &sunique, "Store unique"); 2022 } 2023 2024 void 2025 setrunique(argc, argv) 2026 int argc; 2027 char *argv[]; 2028 { 2029 2030 code = togglevar(argc, argv, &runique, "Receive unique"); 2031 } 2032 2033 /* change directory to parent directory */ 2034 void 2035 cdup(argc, argv) 2036 int argc; 2037 char *argv[]; 2038 { 2039 int r; 2040 2041 r = command("CDUP"); 2042 if (r == ERROR && code == 500) { 2043 if (verbose) 2044 fputs("CDUP command not recognized, trying XCUP.\n", ttyout); 2045 r = command("XCUP"); 2046 } 2047 if (r == COMPLETE) 2048 dirchange = 1; 2049 } 2050 2051 /* 2052 * Restart transfer at specific point 2053 */ 2054 void 2055 restart(argc, argv) 2056 int argc; 2057 char *argv[]; 2058 { 2059 quad_t nrestart_point; 2060 char *ep; 2061 2062 if (argc != 2) 2063 fputs("restart: offset not specified.\n", ttyout); 2064 else { 2065 nrestart_point = strtoq(argv[1], &ep, 10); 2066 if (nrestart_point == QUAD_MAX || *ep != '\0') 2067 fputs("restart: invalid offset.\n", ttyout); 2068 else { 2069 fprintf(ttyout, "Restarting at %lld. Execute get, put " 2070 "or append to initiate transfer\n", 2071 (long long)nrestart_point); 2072 restart_point = nrestart_point; 2073 } 2074 } 2075 } 2076 2077 /* 2078 * Show remote system type 2079 */ 2080 void 2081 syst(argc, argv) 2082 int argc; 2083 char *argv[]; 2084 { 2085 2086 (void)command("SYST"); 2087 } 2088 2089 void 2090 macdef(argc, argv) 2091 int argc; 2092 char *argv[]; 2093 { 2094 char *tmp; 2095 int c; 2096 2097 if (macnum == 16) { 2098 fputs("Limit of 16 macros have already been defined.\n", ttyout); 2099 code = -1; 2100 return; 2101 } 2102 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2103 fprintf(ttyout, "usage: %s macro_name\n", argv[0]); 2104 code = -1; 2105 return; 2106 } 2107 if (interactive) 2108 fputs( 2109 "Enter macro line by line, terminating it with a null line.\n", ttyout); 2110 (void)strlcpy(macros[macnum].mac_name, argv[1], 2111 sizeof(macros[macnum].mac_name)); 2112 if (macnum == 0) 2113 macros[macnum].mac_start = macbuf; 2114 else 2115 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2116 tmp = macros[macnum].mac_start; 2117 while (tmp != macbuf+4096) { 2118 if ((c = getchar()) == EOF) { 2119 fputs("macdef: end of file encountered.\n", ttyout); 2120 code = -1; 2121 return; 2122 } 2123 if ((*tmp = c) == '\n') { 2124 if (tmp == macros[macnum].mac_start) { 2125 macros[macnum++].mac_end = tmp; 2126 code = 0; 2127 return; 2128 } 2129 if (*(tmp-1) == '\0') { 2130 macros[macnum++].mac_end = tmp - 1; 2131 code = 0; 2132 return; 2133 } 2134 *tmp = '\0'; 2135 } 2136 tmp++; 2137 } 2138 while (1) { 2139 while ((c = getchar()) != '\n' && c != EOF) 2140 /* LOOP */; 2141 if (c == EOF || getchar() == '\n') { 2142 fputs("Macro not defined - 4K buffer exceeded.\n", ttyout); 2143 code = -1; 2144 return; 2145 } 2146 } 2147 } 2148 2149 /* 2150 * Get size of file on remote machine 2151 */ 2152 void 2153 sizecmd(argc, argv) 2154 int argc; 2155 char *argv[]; 2156 { 2157 off_t size; 2158 2159 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2160 fprintf(ttyout, "usage: %s filename\n", argv[0]); 2161 code = -1; 2162 return; 2163 } 2164 size = remotesize(argv[1], 1); 2165 if (size != -1) 2166 fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size); 2167 code = size; 2168 } 2169 2170 /* 2171 * Get last modification time of file on remote machine 2172 */ 2173 void 2174 modtime(argc, argv) 2175 int argc; 2176 char *argv[]; 2177 { 2178 time_t mtime; 2179 2180 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2181 fprintf(ttyout, "usage: %s filename\n", argv[0]); 2182 code = -1; 2183 return; 2184 } 2185 mtime = remotemodtime(argv[1], 1); 2186 if (mtime != -1) 2187 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime))); 2188 code = mtime; 2189 } 2190 2191 /* 2192 * Show status on remote machine 2193 */ 2194 void 2195 rmtstatus(argc, argv) 2196 int argc; 2197 char *argv[]; 2198 { 2199 2200 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 2201 } 2202 2203 /* 2204 * Get file if modtime is more recent than current file 2205 */ 2206 void 2207 newer(argc, argv) 2208 int argc; 2209 char *argv[]; 2210 { 2211 2212 if (getit(argc, argv, -1, "w")) 2213 fprintf(ttyout, "Local file \"%s\" is newer than remote file \"%s\".\n", 2214 argv[2], argv[1]); 2215 } 2216 2217 /* 2218 * Display one file through $PAGER (defaults to "more"). 2219 */ 2220 void 2221 page(argc, argv) 2222 int argc; 2223 char *argv[]; 2224 { 2225 int orestart_point, ohash, overbose; 2226 char *p, *pager, *oldargv1; 2227 2228 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) { 2229 fprintf(ttyout, "usage: %s filename\n", argv[0]); 2230 code = -1; 2231 return; 2232 } 2233 oldargv1 = argv[1]; 2234 if (!globulize(&argv[1])) { 2235 code = -1; 2236 return; 2237 } 2238 p = getenv("PAGER"); 2239 if (p == NULL || (*p == '\0')) 2240 p = PAGER; 2241 if (asprintf(&pager, "|%s", p) == -1) 2242 errx(1, "Can't allocate memory for $PAGER"); 2243 2244 orestart_point = restart_point; 2245 ohash = hash; 2246 overbose = verbose; 2247 restart_point = hash = verbose = 0; 2248 recvrequest("RETR", pager, argv[1], "r+w", 1, 0); 2249 (void)free(pager); 2250 restart_point = orestart_point; 2251 hash = ohash; 2252 verbose = overbose; 2253 if (oldargv1 != argv[1]) /* free up after globulize() */ 2254 free(argv[1]); 2255 } 2256