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