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