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.7 1994/12/15 08:58:44 jtc 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 *tp2 = '\0'; 747 tp = tmpbuf; 748 } 749 if (ntflag) { 750 tp = dotrans(tp); 751 } 752 if (mapflag) { 753 tp = domap(tp); 754 } 755 recvrequest("RETR", tp, cp, "w", 756 tp != cp || !interactive); 757 if (!mflag && fromatty) { 758 ointer = interactive; 759 interactive = 1; 760 if (confirm("Continue with","mget")) { 761 mflag++; 762 } 763 interactive = ointer; 764 } 765 } 766 } 767 (void) signal(SIGINT,oldintr); 768 mflag = 0; 769 } 770 771 char * 772 remglob(argv,doswitch) 773 char *argv[]; 774 int doswitch; 775 { 776 char temp[16]; 777 static char buf[MAXPATHLEN]; 778 static FILE *ftemp = NULL; 779 static char **args; 780 int oldverbose, oldhash; 781 char *cp, *mode; 782 783 if (!mflag) { 784 if (!doglob) { 785 args = NULL; 786 } 787 else { 788 if (ftemp) { 789 (void) fclose(ftemp); 790 ftemp = NULL; 791 } 792 } 793 return (NULL); 794 } 795 if (!doglob) { 796 if (args == NULL) 797 args = argv; 798 if ((cp = *++args) == NULL) 799 args = NULL; 800 return (cp); 801 } 802 if (ftemp == NULL) { 803 (void) strcpy(temp, _PATH_TMP); 804 (void) mktemp(temp); 805 oldverbose = verbose, verbose = 0; 806 oldhash = hash, hash = 0; 807 if (doswitch) { 808 pswitch(!proxy); 809 } 810 for (mode = "w"; *++argv != NULL; mode = "a") 811 recvrequest ("NLST", temp, *argv, mode, 0); 812 if (doswitch) { 813 pswitch(!proxy); 814 } 815 verbose = oldverbose; hash = oldhash; 816 ftemp = fopen(temp, "r"); 817 (void) unlink(temp); 818 if (ftemp == NULL) { 819 printf("can't find list of remote files, oops\n"); 820 return (NULL); 821 } 822 } 823 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 824 (void) fclose(ftemp), ftemp = NULL; 825 return (NULL); 826 } 827 if ((cp = strchr(buf, '\n')) != NULL) 828 *cp = '\0'; 829 return (buf); 830 } 831 832 char * 833 onoff(bool) 834 int bool; 835 { 836 837 return (bool ? "on" : "off"); 838 } 839 840 /* 841 * Show status. 842 */ 843 /*ARGSUSED*/ 844 void 845 status(argc, argv) 846 int argc; 847 char *argv[]; 848 { 849 int i; 850 851 if (connected) 852 printf("Connected to %s.\n", hostname); 853 else 854 printf("Not connected.\n"); 855 if (!proxy) { 856 pswitch(1); 857 if (connected) { 858 printf("Connected for proxy commands to %s.\n", hostname); 859 } 860 else { 861 printf("No proxy connection.\n"); 862 } 863 pswitch(0); 864 } 865 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 866 modename, typename, formname, structname); 867 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 868 onoff(verbose), onoff(bell), onoff(interactive), 869 onoff(doglob)); 870 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 871 onoff(runique)); 872 printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); 873 if (ntflag) { 874 printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); 875 } 876 else { 877 printf("Ntrans: off\n"); 878 } 879 if (mapflag) { 880 printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 881 } 882 else { 883 printf("Nmap: off\n"); 884 } 885 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 886 onoff(hash), onoff(sendport)); 887 if (macnum > 0) { 888 printf("Macros:\n"); 889 for (i=0; i<macnum; i++) { 890 printf("\t%s\n",macros[i].mac_name); 891 } 892 } 893 code = 0; 894 } 895 896 /* 897 * Set beep on cmd completed mode. 898 */ 899 /*VARARGS*/ 900 void 901 setbell(argc, argv) 902 int argc; 903 char *argv[]; 904 { 905 906 bell = !bell; 907 printf("Bell mode %s.\n", onoff(bell)); 908 code = bell; 909 } 910 911 /* 912 * Turn on packet tracing. 913 */ 914 /*VARARGS*/ 915 void 916 settrace(argc, argv) 917 int argc; 918 char *argv[]; 919 { 920 921 trace = !trace; 922 printf("Packet tracing %s.\n", onoff(trace)); 923 code = trace; 924 } 925 926 /* 927 * Toggle hash mark printing during transfers. 928 */ 929 /*VARARGS*/ 930 void 931 sethash(argc, argv) 932 int argc; 933 char *argv[]; 934 { 935 936 hash = !hash; 937 printf("Hash mark printing %s", onoff(hash)); 938 code = hash; 939 if (hash) 940 printf(" (%d bytes/hash mark)", 1024); 941 printf(".\n"); 942 } 943 944 /* 945 * Turn on printing of server echo's. 946 */ 947 /*VARARGS*/ 948 void 949 setverbose(argc, argv) 950 int argc; 951 char *argv[]; 952 { 953 954 verbose = !verbose; 955 printf("Verbose mode %s.\n", onoff(verbose)); 956 code = verbose; 957 } 958 959 /* 960 * Toggle PORT cmd use before each data connection. 961 */ 962 /*VARARGS*/ 963 void 964 setport(argc, argv) 965 int argc; 966 char *argv[]; 967 { 968 969 sendport = !sendport; 970 printf("Use of PORT cmds %s.\n", onoff(sendport)); 971 code = sendport; 972 } 973 974 /* 975 * Turn on interactive prompting 976 * during mget, mput, and mdelete. 977 */ 978 /*VARARGS*/ 979 void 980 setprompt(argc, argv) 981 int argc; 982 char *argv[]; 983 { 984 985 interactive = !interactive; 986 printf("Interactive mode %s.\n", onoff(interactive)); 987 code = interactive; 988 } 989 990 /* 991 * Toggle metacharacter interpretation 992 * on local file names. 993 */ 994 /*VARARGS*/ 995 void 996 setglob(argc, argv) 997 int argc; 998 char *argv[]; 999 { 1000 1001 doglob = !doglob; 1002 printf("Globbing %s.\n", onoff(doglob)); 1003 code = doglob; 1004 } 1005 1006 /* 1007 * Set debugging mode on/off and/or 1008 * set level of debugging. 1009 */ 1010 /*VARARGS*/ 1011 void 1012 setdebug(argc, argv) 1013 int argc; 1014 char *argv[]; 1015 { 1016 int val; 1017 1018 if (argc > 1) { 1019 val = atoi(argv[1]); 1020 if (val < 0) { 1021 printf("%s: bad debugging value.\n", argv[1]); 1022 code = -1; 1023 return; 1024 } 1025 } else 1026 val = !debug; 1027 debug = val; 1028 if (debug) 1029 options |= SO_DEBUG; 1030 else 1031 options &= ~SO_DEBUG; 1032 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 1033 code = debug > 0; 1034 } 1035 1036 /* 1037 * Set current working directory 1038 * on remote machine. 1039 */ 1040 void 1041 cd(argc, argv) 1042 int argc; 1043 char *argv[]; 1044 { 1045 1046 if (argc < 2 && !another(&argc, &argv, "remote-directory")) { 1047 printf("usage: %s remote-directory\n", argv[0]); 1048 code = -1; 1049 return; 1050 } 1051 if (command("CWD %s", argv[1]) == ERROR && code == 500) { 1052 if (verbose) 1053 printf("CWD command not recognized, trying XCWD\n"); 1054 (void) command("XCWD %s", argv[1]); 1055 } 1056 } 1057 1058 /* 1059 * Set current working directory 1060 * on local machine. 1061 */ 1062 void 1063 lcd(argc, argv) 1064 int argc; 1065 char *argv[]; 1066 { 1067 char buf[MAXPATHLEN]; 1068 1069 if (argc < 2) 1070 argc++, argv[1] = home; 1071 if (argc != 2) { 1072 printf("usage: %s local-directory\n", argv[0]); 1073 code = -1; 1074 return; 1075 } 1076 if (!globulize(&argv[1])) { 1077 code = -1; 1078 return; 1079 } 1080 if (chdir(argv[1]) < 0) { 1081 warn("local: %s", argv[1]); 1082 code = -1; 1083 return; 1084 } 1085 if (getwd(buf) != NULL) 1086 printf("Local directory now %s\n", buf); 1087 else 1088 warnx("getwd: %s", buf); 1089 code = 0; 1090 } 1091 1092 /* 1093 * Delete a single file. 1094 */ 1095 void 1096 delete(argc, argv) 1097 int argc; 1098 char *argv[]; 1099 { 1100 1101 if (argc < 2 && !another(&argc, &argv, "remote-file")) { 1102 printf("usage: %s remote-file\n", argv[0]); 1103 code = -1; 1104 return; 1105 } 1106 (void) command("DELE %s", argv[1]); 1107 } 1108 1109 /* 1110 * Delete multiple files. 1111 */ 1112 void 1113 mdelete(argc, argv) 1114 int argc; 1115 char **argv; 1116 { 1117 sig_t oldintr; 1118 int ointer; 1119 char *cp; 1120 1121 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 1122 printf("usage: %s remote-files\n", argv[0]); 1123 code = -1; 1124 return; 1125 } 1126 mname = argv[0]; 1127 mflag = 1; 1128 oldintr = signal(SIGINT, mabort); 1129 (void) setjmp(jabort); 1130 while ((cp = remglob(argv,0)) != NULL) { 1131 if (*cp == '\0') { 1132 mflag = 0; 1133 continue; 1134 } 1135 if (mflag && confirm(argv[0], cp)) { 1136 (void) command("DELE %s", cp); 1137 if (!mflag && fromatty) { 1138 ointer = interactive; 1139 interactive = 1; 1140 if (confirm("Continue with", "mdelete")) { 1141 mflag++; 1142 } 1143 interactive = ointer; 1144 } 1145 } 1146 } 1147 (void) signal(SIGINT, oldintr); 1148 mflag = 0; 1149 } 1150 1151 /* 1152 * Rename a remote file. 1153 */ 1154 void 1155 renamefile(argc, argv) 1156 int argc; 1157 char *argv[]; 1158 { 1159 1160 if (argc < 2 && !another(&argc, &argv, "from-name")) 1161 goto usage; 1162 if (argc < 3 && !another(&argc, &argv, "to-name")) { 1163 usage: 1164 printf("%s from-name to-name\n", argv[0]); 1165 code = -1; 1166 return; 1167 } 1168 if (command("RNFR %s", argv[1]) == CONTINUE) 1169 (void) command("RNTO %s", argv[2]); 1170 } 1171 1172 /* 1173 * Get a directory listing 1174 * of remote files. 1175 */ 1176 void 1177 ls(argc, argv) 1178 int argc; 1179 char *argv[]; 1180 { 1181 char *cmd; 1182 1183 if (argc < 2) 1184 argc++, argv[1] = NULL; 1185 if (argc < 3) 1186 argc++, argv[2] = "-"; 1187 if (argc > 3) { 1188 printf("usage: %s remote-directory local-file\n", argv[0]); 1189 code = -1; 1190 return; 1191 } 1192 cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; 1193 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1194 code = -1; 1195 return; 1196 } 1197 if (strcmp(argv[2], "-") && *argv[2] != '|') 1198 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { 1199 code = -1; 1200 return; 1201 } 1202 recvrequest(cmd, argv[2], argv[1], "w", 0); 1203 } 1204 1205 /* 1206 * Get a directory listing 1207 * of multiple remote files. 1208 */ 1209 void 1210 mls(argc, argv) 1211 int argc; 1212 char **argv; 1213 { 1214 sig_t oldintr; 1215 int ointer, i; 1216 char *cmd, mode[1], *dest; 1217 1218 if (argc < 2 && !another(&argc, &argv, "remote-files")) 1219 goto usage; 1220 if (argc < 3 && !another(&argc, &argv, "local-file")) { 1221 usage: 1222 printf("usage: %s remote-files local-file\n", argv[0]); 1223 code = -1; 1224 return; 1225 } 1226 dest = argv[argc - 1]; 1227 argv[argc - 1] = NULL; 1228 if (strcmp(dest, "-") && *dest != '|') 1229 if (!globulize(&dest) || 1230 !confirm("output to local-file:", dest)) { 1231 code = -1; 1232 return; 1233 } 1234 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 1235 mname = argv[0]; 1236 mflag = 1; 1237 oldintr = signal(SIGINT, mabort); 1238 (void) setjmp(jabort); 1239 for (i = 1; mflag && i < argc-1; ++i) { 1240 *mode = (i == 1) ? 'w' : 'a'; 1241 recvrequest(cmd, dest, argv[i], mode, 0); 1242 if (!mflag && fromatty) { 1243 ointer = interactive; 1244 interactive = 1; 1245 if (confirm("Continue with", argv[0])) { 1246 mflag ++; 1247 } 1248 interactive = ointer; 1249 } 1250 } 1251 (void) signal(SIGINT, oldintr); 1252 mflag = 0; 1253 } 1254 1255 /* 1256 * Do a shell escape 1257 */ 1258 /*ARGSUSED*/ 1259 void 1260 shell(argc, argv) 1261 int argc; 1262 char **argv; 1263 { 1264 pid_t pid; 1265 sig_t old1, old2; 1266 char shellnam[40], *shell, *namep; 1267 union wait status; 1268 1269 old1 = signal (SIGINT, SIG_IGN); 1270 old2 = signal (SIGQUIT, SIG_IGN); 1271 if ((pid = fork()) == 0) { 1272 for (pid = 3; pid < 20; pid++) 1273 (void) close(pid); 1274 (void) signal(SIGINT, SIG_DFL); 1275 (void) signal(SIGQUIT, SIG_DFL); 1276 shell = getenv("SHELL"); 1277 if (shell == NULL) 1278 shell = _PATH_BSHELL; 1279 namep = strrchr(shell,'/'); 1280 if (namep == NULL) 1281 namep = shell; 1282 (void) strcpy(shellnam,"-"); 1283 (void) strcat(shellnam, ++namep); 1284 if (strcmp(namep, "sh") != 0) 1285 shellnam[0] = '+'; 1286 if (debug) { 1287 printf ("%s\n", shell); 1288 (void) fflush (stdout); 1289 } 1290 if (argc > 1) { 1291 execl(shell,shellnam,"-c",altarg,(char *)0); 1292 } 1293 else { 1294 execl(shell,shellnam,(char *)0); 1295 } 1296 warn("%s", shell); 1297 code = -1; 1298 exit(1); 1299 } 1300 if (pid > 0) 1301 while (wait((int *)&status) != pid) 1302 ; 1303 (void) signal(SIGINT, old1); 1304 (void) signal(SIGQUIT, old2); 1305 if (pid == -1) { 1306 warn("%s", "Try again later"); 1307 code = -1; 1308 } 1309 else { 1310 code = 0; 1311 } 1312 } 1313 1314 /* 1315 * Send new user information (re-login) 1316 */ 1317 void 1318 user(argc, argv) 1319 int argc; 1320 char **argv; 1321 { 1322 char acct[80]; 1323 int n, aflag = 0; 1324 1325 if (argc < 2) 1326 (void) another(&argc, &argv, "username"); 1327 if (argc < 2 || argc > 4) { 1328 printf("usage: %s username [password] [account]\n", argv[0]); 1329 code = -1; 1330 return; 1331 } 1332 n = command("USER %s", argv[1]); 1333 if (n == CONTINUE) { 1334 if (argc < 3 ) 1335 argv[2] = getpass("Password: "), argc++; 1336 n = command("PASS %s", argv[2]); 1337 } 1338 if (n == CONTINUE) { 1339 if (argc < 4) { 1340 printf("Account: "); (void) fflush(stdout); 1341 (void) fgets(acct, sizeof(acct) - 1, stdin); 1342 acct[strlen(acct) - 1] = '\0'; 1343 argv[3] = acct; argc++; 1344 } 1345 n = command("ACCT %s", argv[3]); 1346 aflag++; 1347 } 1348 if (n != COMPLETE) { 1349 fprintf(stdout, "Login failed.\n"); 1350 return; 1351 } 1352 if (!aflag && argc == 4) { 1353 (void) command("ACCT %s", argv[3]); 1354 } 1355 } 1356 1357 /* 1358 * Print working directory. 1359 */ 1360 /*VARARGS*/ 1361 void 1362 pwd(argc, argv) 1363 int argc; 1364 char *argv[]; 1365 { 1366 int oldverbose = verbose; 1367 1368 /* 1369 * If we aren't verbose, this doesn't do anything! 1370 */ 1371 verbose = 1; 1372 if (command("PWD") == ERROR && code == 500) { 1373 printf("PWD command not recognized, trying XPWD\n"); 1374 (void) command("XPWD"); 1375 } 1376 verbose = oldverbose; 1377 } 1378 1379 /* 1380 * Make a directory. 1381 */ 1382 void 1383 makedir(argc, argv) 1384 int argc; 1385 char *argv[]; 1386 { 1387 1388 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1389 printf("usage: %s directory-name\n", argv[0]); 1390 code = -1; 1391 return; 1392 } 1393 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1394 if (verbose) 1395 printf("MKD command not recognized, trying XMKD\n"); 1396 (void) command("XMKD %s", argv[1]); 1397 } 1398 } 1399 1400 /* 1401 * Remove a directory. 1402 */ 1403 void 1404 removedir(argc, argv) 1405 int argc; 1406 char *argv[]; 1407 { 1408 1409 if (argc < 2 && !another(&argc, &argv, "directory-name")) { 1410 printf("usage: %s directory-name\n", argv[0]); 1411 code = -1; 1412 return; 1413 } 1414 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1415 if (verbose) 1416 printf("RMD command not recognized, trying XRMD\n"); 1417 (void) command("XRMD %s", argv[1]); 1418 } 1419 } 1420 1421 /* 1422 * Send a line, verbatim, to the remote machine. 1423 */ 1424 void 1425 quote(argc, argv) 1426 int argc; 1427 char *argv[]; 1428 { 1429 1430 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1431 printf("usage: %s line-to-send\n", argv[0]); 1432 code = -1; 1433 return; 1434 } 1435 quote1("", argc, argv); 1436 } 1437 1438 /* 1439 * Send a SITE command to the remote machine. The line 1440 * is sent verbatim to the remote machine, except that the 1441 * word "SITE" is added at the front. 1442 */ 1443 void 1444 site(argc, argv) 1445 int argc; 1446 char *argv[]; 1447 { 1448 1449 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1450 printf("usage: %s line-to-send\n", argv[0]); 1451 code = -1; 1452 return; 1453 } 1454 quote1("SITE ", argc, argv); 1455 } 1456 1457 /* 1458 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1459 * Send the result as a one-line command and get response. 1460 */ 1461 void 1462 quote1(initial, argc, argv) 1463 char *initial; 1464 int argc; 1465 char **argv; 1466 { 1467 int i, len; 1468 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1469 1470 (void) strcpy(buf, initial); 1471 if (argc > 1) { 1472 len = strlen(buf); 1473 len += strlen(strcpy(&buf[len], argv[1])); 1474 for (i = 2; i < argc; i++) { 1475 buf[len++] = ' '; 1476 len += strlen(strcpy(&buf[len], argv[i])); 1477 } 1478 } 1479 if (command(buf) == PRELIM) { 1480 while (getreply(0) == PRELIM) 1481 continue; 1482 } 1483 } 1484 1485 void 1486 do_chmod(argc, argv) 1487 int argc; 1488 char *argv[]; 1489 { 1490 1491 if (argc < 2 && !another(&argc, &argv, "mode")) 1492 goto usage; 1493 if (argc < 3 && !another(&argc, &argv, "file-name")) { 1494 usage: 1495 printf("usage: %s mode file-name\n", argv[0]); 1496 code = -1; 1497 return; 1498 } 1499 (void) command("SITE CHMOD %s %s", argv[1], argv[2]); 1500 } 1501 1502 void 1503 do_umask(argc, argv) 1504 int argc; 1505 char *argv[]; 1506 { 1507 int oldverbose = verbose; 1508 1509 verbose = 1; 1510 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1511 verbose = oldverbose; 1512 } 1513 1514 void 1515 idle(argc, argv) 1516 int argc; 1517 char *argv[]; 1518 { 1519 int oldverbose = verbose; 1520 1521 verbose = 1; 1522 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1523 verbose = oldverbose; 1524 } 1525 1526 /* 1527 * Ask the other side for help. 1528 */ 1529 void 1530 rmthelp(argc, argv) 1531 int argc; 1532 char *argv[]; 1533 { 1534 int oldverbose = verbose; 1535 1536 verbose = 1; 1537 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1538 verbose = oldverbose; 1539 } 1540 1541 /* 1542 * Terminate session and exit. 1543 */ 1544 /*VARARGS*/ 1545 void 1546 quit(argc, argv) 1547 int argc; 1548 char *argv[]; 1549 { 1550 1551 if (connected) 1552 disconnect(0, 0); 1553 pswitch(1); 1554 if (connected) { 1555 disconnect(0, 0); 1556 } 1557 exit(0); 1558 } 1559 1560 /* 1561 * Terminate session, but don't exit. 1562 */ 1563 void 1564 disconnect(argc, argv) 1565 int argc; 1566 char *argv[]; 1567 { 1568 1569 if (!connected) 1570 return; 1571 (void) command("QUIT"); 1572 if (cout) { 1573 (void) fclose(cout); 1574 } 1575 cout = NULL; 1576 connected = 0; 1577 data = -1; 1578 if (!proxy) { 1579 macnum = 0; 1580 } 1581 } 1582 1583 int 1584 confirm(cmd, file) 1585 char *cmd, *file; 1586 { 1587 char line[BUFSIZ]; 1588 1589 if (!interactive) 1590 return (1); 1591 printf("%s %s? ", cmd, file); 1592 (void) fflush(stdout); 1593 if (fgets(line, sizeof line, stdin) == NULL) 1594 return (0); 1595 return (*line != 'n' && *line != 'N'); 1596 } 1597 1598 void 1599 fatal(msg) 1600 char *msg; 1601 { 1602 1603 errx(1, "%s", msg); 1604 } 1605 1606 /* 1607 * Glob a local file name specification with 1608 * the expectation of a single return value. 1609 * Can't control multiple values being expanded 1610 * from the expression, we return only the first. 1611 */ 1612 int 1613 globulize(cpp) 1614 char **cpp; 1615 { 1616 glob_t gl; 1617 int flags; 1618 1619 if (!doglob) 1620 return (1); 1621 1622 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 1623 memset(&gl, 0, sizeof(gl)); 1624 if (glob(*cpp, flags, NULL, &gl) || 1625 gl.gl_pathc == 0) { 1626 warnx("%s: not found", *cpp); 1627 globfree(&gl); 1628 return (0); 1629 } 1630 *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */ 1631 globfree(&gl); 1632 return (1); 1633 } 1634 1635 void 1636 account(argc,argv) 1637 int argc; 1638 char **argv; 1639 { 1640 char acct[50], *ap; 1641 1642 if (argc > 1) { 1643 ++argv; 1644 --argc; 1645 (void) strncpy(acct,*argv,49); 1646 acct[49] = '\0'; 1647 while (argc > 1) { 1648 --argc; 1649 ++argv; 1650 (void) strncat(acct,*argv, 49-strlen(acct)); 1651 } 1652 ap = acct; 1653 } 1654 else { 1655 ap = getpass("Account:"); 1656 } 1657 (void) command("ACCT %s", ap); 1658 } 1659 1660 jmp_buf abortprox; 1661 1662 void 1663 proxabort() 1664 { 1665 1666 if (!proxy) { 1667 pswitch(1); 1668 } 1669 if (connected) { 1670 proxflag = 1; 1671 } 1672 else { 1673 proxflag = 0; 1674 } 1675 pswitch(0); 1676 longjmp(abortprox,1); 1677 } 1678 1679 void 1680 doproxy(argc, argv) 1681 int argc; 1682 char *argv[]; 1683 { 1684 struct cmd *c; 1685 sig_t oldintr; 1686 1687 if (argc < 2 && !another(&argc, &argv, "command")) { 1688 printf("usage: %s command\n", argv[0]); 1689 code = -1; 1690 return; 1691 } 1692 c = getcmd(argv[1]); 1693 if (c == (struct cmd *) -1) { 1694 printf("?Ambiguous command\n"); 1695 (void) fflush(stdout); 1696 code = -1; 1697 return; 1698 } 1699 if (c == 0) { 1700 printf("?Invalid command\n"); 1701 (void) fflush(stdout); 1702 code = -1; 1703 return; 1704 } 1705 if (!c->c_proxy) { 1706 printf("?Invalid proxy command\n"); 1707 (void) fflush(stdout); 1708 code = -1; 1709 return; 1710 } 1711 if (setjmp(abortprox)) { 1712 code = -1; 1713 return; 1714 } 1715 oldintr = signal(SIGINT, proxabort); 1716 pswitch(1); 1717 if (c->c_conn && !connected) { 1718 printf("Not connected\n"); 1719 (void) fflush(stdout); 1720 pswitch(0); 1721 (void) signal(SIGINT, oldintr); 1722 code = -1; 1723 return; 1724 } 1725 (*c->c_handler)(argc-1, argv+1); 1726 if (connected) { 1727 proxflag = 1; 1728 } 1729 else { 1730 proxflag = 0; 1731 } 1732 pswitch(0); 1733 (void) signal(SIGINT, oldintr); 1734 } 1735 1736 void 1737 setcase(argc, argv) 1738 int argc; 1739 char *argv[]; 1740 { 1741 1742 mcase = !mcase; 1743 printf("Case mapping %s.\n", onoff(mcase)); 1744 code = mcase; 1745 } 1746 1747 void 1748 setcr(argc, argv) 1749 int argc; 1750 char *argv[]; 1751 { 1752 1753 crflag = !crflag; 1754 printf("Carriage Return stripping %s.\n", onoff(crflag)); 1755 code = crflag; 1756 } 1757 1758 void 1759 setntrans(argc,argv) 1760 int argc; 1761 char *argv[]; 1762 { 1763 if (argc == 1) { 1764 ntflag = 0; 1765 printf("Ntrans off.\n"); 1766 code = ntflag; 1767 return; 1768 } 1769 ntflag++; 1770 code = ntflag; 1771 (void) strncpy(ntin, argv[1], 16); 1772 ntin[16] = '\0'; 1773 if (argc == 2) { 1774 ntout[0] = '\0'; 1775 return; 1776 } 1777 (void) strncpy(ntout, argv[2], 16); 1778 ntout[16] = '\0'; 1779 } 1780 1781 char * 1782 dotrans(name) 1783 char *name; 1784 { 1785 static char new[MAXPATHLEN]; 1786 char *cp1, *cp2 = new; 1787 int i, ostop, found; 1788 1789 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1790 continue; 1791 for (cp1 = name; *cp1; cp1++) { 1792 found = 0; 1793 for (i = 0; *(ntin + i) && i < 16; i++) { 1794 if (*cp1 == *(ntin + i)) { 1795 found++; 1796 if (i < ostop) { 1797 *cp2++ = *(ntout + i); 1798 } 1799 break; 1800 } 1801 } 1802 if (!found) { 1803 *cp2++ = *cp1; 1804 } 1805 } 1806 *cp2 = '\0'; 1807 return (new); 1808 } 1809 1810 void 1811 setnmap(argc, argv) 1812 int argc; 1813 char *argv[]; 1814 { 1815 char *cp; 1816 1817 if (argc == 1) { 1818 mapflag = 0; 1819 printf("Nmap off.\n"); 1820 code = mapflag; 1821 return; 1822 } 1823 if (argc < 3 && !another(&argc, &argv, "mapout")) { 1824 printf("Usage: %s [mapin mapout]\n",argv[0]); 1825 code = -1; 1826 return; 1827 } 1828 mapflag = 1; 1829 code = 1; 1830 cp = strchr(altarg, ' '); 1831 if (proxy) { 1832 while(*++cp == ' ') 1833 continue; 1834 altarg = cp; 1835 cp = strchr(altarg, ' '); 1836 } 1837 *cp = '\0'; 1838 (void) strncpy(mapin, altarg, MAXPATHLEN - 1); 1839 while (*++cp == ' ') 1840 continue; 1841 (void) strncpy(mapout, cp, MAXPATHLEN - 1); 1842 } 1843 1844 char * 1845 domap(name) 1846 char *name; 1847 { 1848 static char new[MAXPATHLEN]; 1849 char *cp1 = name, *cp2 = mapin; 1850 char *tp[9], *te[9]; 1851 int i, toks[9], toknum = 0, match = 1; 1852 1853 for (i=0; i < 9; ++i) { 1854 toks[i] = 0; 1855 } 1856 while (match && *cp1 && *cp2) { 1857 switch (*cp2) { 1858 case '\\': 1859 if (*++cp2 != *cp1) { 1860 match = 0; 1861 } 1862 break; 1863 case '$': 1864 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1865 if (*cp1 != *(++cp2+1)) { 1866 toks[toknum = *cp2 - '1']++; 1867 tp[toknum] = cp1; 1868 while (*++cp1 && *(cp2+1) 1869 != *cp1); 1870 te[toknum] = cp1; 1871 } 1872 cp2++; 1873 break; 1874 } 1875 /* FALLTHROUGH */ 1876 default: 1877 if (*cp2 != *cp1) { 1878 match = 0; 1879 } 1880 break; 1881 } 1882 if (match && *cp1) { 1883 cp1++; 1884 } 1885 if (match && *cp2) { 1886 cp2++; 1887 } 1888 } 1889 if (!match && *cp1) /* last token mismatch */ 1890 { 1891 toks[toknum] = 0; 1892 } 1893 cp1 = new; 1894 *cp1 = '\0'; 1895 cp2 = mapout; 1896 while (*cp2) { 1897 match = 0; 1898 switch (*cp2) { 1899 case '\\': 1900 if (*(cp2 + 1)) { 1901 *cp1++ = *++cp2; 1902 } 1903 break; 1904 case '[': 1905 LOOP: 1906 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1907 if (*++cp2 == '0') { 1908 char *cp3 = name; 1909 1910 while (*cp3) { 1911 *cp1++ = *cp3++; 1912 } 1913 match = 1; 1914 } 1915 else if (toks[toknum = *cp2 - '1']) { 1916 char *cp3 = tp[toknum]; 1917 1918 while (cp3 != te[toknum]) { 1919 *cp1++ = *cp3++; 1920 } 1921 match = 1; 1922 } 1923 } 1924 else { 1925 while (*cp2 && *cp2 != ',' && 1926 *cp2 != ']') { 1927 if (*cp2 == '\\') { 1928 cp2++; 1929 } 1930 else if (*cp2 == '$' && 1931 isdigit(*(cp2+1))) { 1932 if (*++cp2 == '0') { 1933 char *cp3 = name; 1934 1935 while (*cp3) { 1936 *cp1++ = *cp3++; 1937 } 1938 } 1939 else if (toks[toknum = 1940 *cp2 - '1']) { 1941 char *cp3=tp[toknum]; 1942 1943 while (cp3 != 1944 te[toknum]) { 1945 *cp1++ = *cp3++; 1946 } 1947 } 1948 } 1949 else if (*cp2) { 1950 *cp1++ = *cp2++; 1951 } 1952 } 1953 if (!*cp2) { 1954 printf("nmap: unbalanced brackets\n"); 1955 return (name); 1956 } 1957 match = 1; 1958 cp2--; 1959 } 1960 if (match) { 1961 while (*++cp2 && *cp2 != ']') { 1962 if (*cp2 == '\\' && *(cp2 + 1)) { 1963 cp2++; 1964 } 1965 } 1966 if (!*cp2) { 1967 printf("nmap: unbalanced brackets\n"); 1968 return (name); 1969 } 1970 break; 1971 } 1972 switch (*++cp2) { 1973 case ',': 1974 goto LOOP; 1975 case ']': 1976 break; 1977 default: 1978 cp2--; 1979 goto LOOP; 1980 } 1981 break; 1982 case '$': 1983 if (isdigit(*(cp2 + 1))) { 1984 if (*++cp2 == '0') { 1985 char *cp3 = name; 1986 1987 while (*cp3) { 1988 *cp1++ = *cp3++; 1989 } 1990 } 1991 else if (toks[toknum = *cp2 - '1']) { 1992 char *cp3 = tp[toknum]; 1993 1994 while (cp3 != te[toknum]) { 1995 *cp1++ = *cp3++; 1996 } 1997 } 1998 break; 1999 } 2000 /* intentional drop through */ 2001 default: 2002 *cp1++ = *cp2; 2003 break; 2004 } 2005 cp2++; 2006 } 2007 *cp1 = '\0'; 2008 if (!*new) { 2009 return (name); 2010 } 2011 return (new); 2012 } 2013 2014 void 2015 setpassive(argc, argv) 2016 int argc; 2017 char *argv[]; 2018 { 2019 2020 passivemode = !passivemode; 2021 printf("Passive mode %s.\n", onoff(passivemode)); 2022 code = passivemode; 2023 } 2024 2025 void 2026 setsunique(argc, argv) 2027 int argc; 2028 char *argv[]; 2029 { 2030 2031 sunique = !sunique; 2032 printf("Store unique %s.\n", onoff(sunique)); 2033 code = sunique; 2034 } 2035 2036 void 2037 setrunique(argc, argv) 2038 int argc; 2039 char *argv[]; 2040 { 2041 2042 runique = !runique; 2043 printf("Receive unique %s.\n", onoff(runique)); 2044 code = runique; 2045 } 2046 2047 /* change directory to perent directory */ 2048 void 2049 cdup(argc, argv) 2050 int argc; 2051 char *argv[]; 2052 { 2053 2054 if (command("CDUP") == ERROR && code == 500) { 2055 if (verbose) 2056 printf("CDUP command not recognized, trying XCUP\n"); 2057 (void) command("XCUP"); 2058 } 2059 } 2060 2061 /* restart transfer at specific point */ 2062 void 2063 restart(argc, argv) 2064 int argc; 2065 char *argv[]; 2066 { 2067 2068 if (argc != 2) 2069 printf("restart: offset not specified\n"); 2070 else { 2071 restart_point = atol(argv[1]); 2072 printf("restarting at %qd. %s\n", restart_point, 2073 "execute get, put or append to initiate transfer"); 2074 } 2075 } 2076 2077 /* show remote system type */ 2078 void 2079 syst(argc, argv) 2080 int argc; 2081 char *argv[]; 2082 { 2083 2084 (void) command("SYST"); 2085 } 2086 2087 void 2088 macdef(argc, argv) 2089 int argc; 2090 char *argv[]; 2091 { 2092 char *tmp; 2093 int c; 2094 2095 if (macnum == 16) { 2096 printf("Limit of 16 macros have already been defined\n"); 2097 code = -1; 2098 return; 2099 } 2100 if (argc < 2 && !another(&argc, &argv, "macro name")) { 2101 printf("Usage: %s macro_name\n",argv[0]); 2102 code = -1; 2103 return; 2104 } 2105 if (interactive) { 2106 printf("Enter macro line by line, terminating it with a null line\n"); 2107 } 2108 (void) strncpy(macros[macnum].mac_name, argv[1], 8); 2109 if (macnum == 0) { 2110 macros[macnum].mac_start = macbuf; 2111 } 2112 else { 2113 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2114 } 2115 tmp = macros[macnum].mac_start; 2116 while (tmp != macbuf+4096) { 2117 if ((c = getchar()) == EOF) { 2118 printf("macdef:end of file encountered\n"); 2119 code = -1; 2120 return; 2121 } 2122 if ((*tmp = c) == '\n') { 2123 if (tmp == macros[macnum].mac_start) { 2124 macros[macnum++].mac_end = tmp; 2125 code = 0; 2126 return; 2127 } 2128 if (*(tmp-1) == '\0') { 2129 macros[macnum++].mac_end = tmp - 1; 2130 code = 0; 2131 return; 2132 } 2133 *tmp = '\0'; 2134 } 2135 tmp++; 2136 } 2137 while (1) { 2138 while ((c = getchar()) != '\n' && c != EOF) 2139 /* LOOP */; 2140 if (c == EOF || getchar() == '\n') { 2141 printf("Macro not defined - 4k buffer exceeded\n"); 2142 code = -1; 2143 return; 2144 } 2145 } 2146 } 2147 2148 /* 2149 * get size of file on remote machine 2150 */ 2151 void 2152 sizecmd(argc, argv) 2153 int argc; 2154 char *argv[]; 2155 { 2156 2157 if (argc < 2 && !another(&argc, &argv, "filename")) { 2158 printf("usage: %s filename\n", argv[0]); 2159 code = -1; 2160 return; 2161 } 2162 (void) command("SIZE %s", argv[1]); 2163 } 2164 2165 /* 2166 * get last modification time of file on remote machine 2167 */ 2168 void 2169 modtime(argc, argv) 2170 int argc; 2171 char *argv[]; 2172 { 2173 int overbose; 2174 2175 if (argc < 2 && !another(&argc, &argv, "filename")) { 2176 printf("usage: %s filename\n", argv[0]); 2177 code = -1; 2178 return; 2179 } 2180 overbose = verbose; 2181 if (debug == 0) 2182 verbose = -1; 2183 if (command("MDTM %s", argv[1]) == COMPLETE) { 2184 int yy, mo, day, hour, min, sec; 2185 sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, 2186 &day, &hour, &min, &sec); 2187 /* might want to print this in local time */ 2188 printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], 2189 mo, day, yy, hour, min, sec); 2190 } else 2191 printf("%s\n", reply_string); 2192 verbose = overbose; 2193 } 2194 2195 /* 2196 * show status on reomte machine 2197 */ 2198 void 2199 rmtstatus(argc, argv) 2200 int argc; 2201 char *argv[]; 2202 { 2203 2204 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 2205 } 2206 2207 /* 2208 * get file if modtime is more recent than current file 2209 */ 2210 void 2211 newer(argc, argv) 2212 int argc; 2213 char *argv[]; 2214 { 2215 2216 if (getit(argc, argv, -1, "w")) 2217 printf("Local file \"%s\" is newer than remote file \"%s\"\n", 2218 argv[2], argv[1]); 2219 } 2220