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