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