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