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