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