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