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.6 (Berkeley) 10/06/87"; 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 if (strcmp(argv[2], "-") && *argv[2] != '|') 996 if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { 997 code = -1; 998 return; 999 } 1000 recvrequest(cmd, argv[2], argv[1], "w"); 1001 } 1002 1003 /* 1004 * Get a directory listing 1005 * of multiple remote files. 1006 */ 1007 mls(argc, argv) 1008 char *argv[]; 1009 { 1010 char *cmd, mode[1], *dest; 1011 int ointer, i, (*oldintr)(), mabort(); 1012 extern jmp_buf jabort; 1013 1014 if (argc < 2) { 1015 (void) strcat(line, " "); 1016 printf("(remote-files) "); 1017 (void) gets(&line[strlen(line)]); 1018 makeargv(); 1019 argc = margc; 1020 argv = margv; 1021 } 1022 if (argc < 3) { 1023 (void) strcat(line, " "); 1024 printf("(local-file) "); 1025 (void) gets(&line[strlen(line)]); 1026 makeargv(); 1027 argc = margc; 1028 argv = margv; 1029 } 1030 if (argc < 3) { 1031 printf("usage:%s remote-files local-file\n", argv[0]); 1032 code = -1; 1033 return; 1034 } 1035 dest = argv[argc - 1]; 1036 argv[argc - 1] = NULL; 1037 if (strcmp(dest, "-") && *dest != '|') 1038 if (!globulize(&dest) || !confirm("output to local-file:", dest)) { 1039 code = -1; 1040 return; 1041 } 1042 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 1043 mname = argv[0]; 1044 mflag = 1; 1045 oldintr = signal(SIGINT, mabort); 1046 (void) setjmp(jabort); 1047 for (i = 1; mflag && i < argc-1; ++i) { 1048 *mode = (i == 1) ? 'w' : 'a'; 1049 recvrequest(cmd, dest, argv[i], mode); 1050 if (!mflag && fromatty) { 1051 ointer = interactive; 1052 interactive = 1; 1053 if (confirm("Continue with", argv[0])) { 1054 mflag ++; 1055 } 1056 interactive = ointer; 1057 } 1058 } 1059 (void) signal(SIGINT, oldintr); 1060 mflag = 0; 1061 } 1062 1063 /* 1064 * Do a shell escape 1065 */ 1066 /*ARGSUSED*/ 1067 shell(argc, argv) 1068 char *argv[]; 1069 { 1070 int pid, (*old1)(), (*old2)(); 1071 char shellnam[40], *shell, *namep; 1072 union wait status; 1073 1074 old1 = signal (SIGINT, SIG_IGN); 1075 old2 = signal (SIGQUIT, SIG_IGN); 1076 if ((pid = fork()) == 0) { 1077 for (pid = 3; pid < 20; pid++) 1078 (void) close(pid); 1079 (void) signal(SIGINT, SIG_DFL); 1080 (void) signal(SIGQUIT, SIG_DFL); 1081 shell = getenv("SHELL"); 1082 if (shell == NULL) 1083 shell = "/bin/sh"; 1084 namep = rindex(shell,'/'); 1085 if (namep == NULL) 1086 namep = shell; 1087 (void) strcpy(shellnam,"-"); 1088 (void) strcat(shellnam, ++namep); 1089 if (strcmp(namep, "sh") != 0) 1090 shellnam[0] = '+'; 1091 if (debug) { 1092 printf ("%s\n", shell); 1093 (void) fflush (stdout); 1094 } 1095 if (argc > 1) { 1096 execl(shell,shellnam,"-c",altarg,(char *)0); 1097 } 1098 else { 1099 execl(shell,shellnam,(char *)0); 1100 } 1101 perror(shell); 1102 code = -1; 1103 exit(1); 1104 } 1105 if (pid > 0) 1106 while (wait(&status) != pid) 1107 ; 1108 (void) signal(SIGINT, old1); 1109 (void) signal(SIGQUIT, old2); 1110 if (pid == -1) { 1111 perror("Try again later"); 1112 code = -1; 1113 } 1114 else { 1115 code = 0; 1116 } 1117 return (0); 1118 } 1119 1120 /* 1121 * Send new user information (re-login) 1122 */ 1123 user(argc, argv) 1124 int argc; 1125 char **argv; 1126 { 1127 char acct[80], *mygetpass(); 1128 int n, aflag = 0; 1129 1130 if (argc < 2) { 1131 (void) strcat(line, " "); 1132 printf("(username) "); 1133 (void) gets(&line[strlen(line)]); 1134 makeargv(); 1135 argc = margc; 1136 argv = margv; 1137 } 1138 if (argc > 4) { 1139 printf("usage: %s username [password] [account]\n", argv[0]); 1140 code = -1; 1141 return (0); 1142 } 1143 n = command("USER %s", argv[1]); 1144 if (n == CONTINUE) { 1145 if (argc < 3 ) 1146 argv[2] = mygetpass("Password: "), argc++; 1147 n = command("PASS %s", argv[2]); 1148 } 1149 if (n == CONTINUE) { 1150 if (argc < 4) { 1151 printf("Account: "); (void) fflush(stdout); 1152 (void) fgets(acct, sizeof(acct) - 1, stdin); 1153 acct[strlen(acct) - 1] = '\0'; 1154 argv[3] = acct; argc++; 1155 } 1156 n = command("ACCT %s", argv[3]); 1157 aflag++; 1158 } 1159 if (n != COMPLETE) { 1160 fprintf(stdout, "Login failed.\n"); 1161 return (0); 1162 } 1163 if (!aflag && argc == 4) { 1164 (void) command("ACCT %s", argv[3]); 1165 } 1166 return (1); 1167 } 1168 1169 /* 1170 * Print working directory. 1171 */ 1172 /*VARARGS*/ 1173 pwd() 1174 { 1175 1176 (void) command("PWD"); 1177 } 1178 1179 /* 1180 * Make a directory. 1181 */ 1182 makedir(argc, argv) 1183 char *argv[]; 1184 { 1185 1186 if (argc < 2) { 1187 (void) strcat(line, " "); 1188 printf("(directory-name) "); 1189 (void) gets(&line[strlen(line)]); 1190 makeargv(); 1191 argc = margc; 1192 argv = margv; 1193 } 1194 if (argc < 2) { 1195 printf("usage: %s directory-name\n", argv[0]); 1196 code = -1; 1197 return; 1198 } 1199 (void) command("MKD %s", argv[1]); 1200 } 1201 1202 /* 1203 * Remove a directory. 1204 */ 1205 removedir(argc, argv) 1206 char *argv[]; 1207 { 1208 1209 if (argc < 2) { 1210 (void) strcat(line, " "); 1211 printf("(directory-name) "); 1212 (void) gets(&line[strlen(line)]); 1213 makeargv(); 1214 argc = margc; 1215 argv = margv; 1216 } 1217 if (argc < 2) { 1218 printf("usage: %s directory-name\n", argv[0]); 1219 code = -1; 1220 return; 1221 } 1222 (void) command("RMD %s", argv[1]); 1223 } 1224 1225 /* 1226 * Send a line, verbatim, to the remote machine. 1227 */ 1228 quote(argc, argv) 1229 char *argv[]; 1230 { 1231 int i; 1232 char buf[BUFSIZ]; 1233 1234 if (argc < 2) { 1235 (void) strcat(line, " "); 1236 printf("(command line to send) "); 1237 (void) gets(&line[strlen(line)]); 1238 makeargv(); 1239 argc = margc; 1240 argv = margv; 1241 } 1242 if (argc < 2) { 1243 printf("usage: %s line-to-send\n", argv[0]); 1244 code = -1; 1245 return; 1246 } 1247 (void) strcpy(buf, argv[1]); 1248 for (i = 2; i < argc; i++) { 1249 (void) strcat(buf, " "); 1250 (void) strcat(buf, argv[i]); 1251 } 1252 if (command(buf) == PRELIM) { 1253 while (getreply(0) == PRELIM); 1254 } 1255 } 1256 1257 /* 1258 * Ask the other side for help. 1259 */ 1260 rmthelp(argc, argv) 1261 char *argv[]; 1262 { 1263 int oldverbose = verbose; 1264 1265 verbose = 1; 1266 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1267 verbose = oldverbose; 1268 } 1269 1270 /* 1271 * Terminate session and exit. 1272 */ 1273 /*VARARGS*/ 1274 quit() 1275 { 1276 1277 if (connected) 1278 disconnect(); 1279 pswitch(1); 1280 if (connected) { 1281 disconnect(); 1282 } 1283 exit(0); 1284 } 1285 1286 /* 1287 * Terminate session, but don't exit. 1288 */ 1289 disconnect() 1290 { 1291 extern FILE *cout; 1292 extern int data; 1293 1294 if (!connected) 1295 return; 1296 (void) command("QUIT"); 1297 if (cout) { 1298 (void) fclose(cout); 1299 } 1300 cout = NULL; 1301 connected = 0; 1302 data = -1; 1303 if (!proxy) { 1304 macnum = 0; 1305 } 1306 } 1307 1308 confirm(cmd, file) 1309 char *cmd, *file; 1310 { 1311 char line[BUFSIZ]; 1312 1313 if (!interactive) 1314 return (1); 1315 printf("%s %s? ", cmd, file); 1316 (void) fflush(stdout); 1317 (void) gets(line); 1318 return (*line != 'n' && *line != 'N'); 1319 } 1320 1321 fatal(msg) 1322 char *msg; 1323 { 1324 1325 fprintf(stderr, "ftp: %s\n", msg); 1326 exit(1); 1327 } 1328 1329 /* 1330 * Glob a local file name specification with 1331 * the expectation of a single return value. 1332 * Can't control multiple values being expanded 1333 * from the expression, we return only the first. 1334 */ 1335 globulize(cpp) 1336 char **cpp; 1337 { 1338 char **globbed; 1339 1340 if (!doglob) 1341 return (1); 1342 globbed = glob(*cpp); 1343 if (globerr != NULL) { 1344 printf("%s: %s\n", *cpp, globerr); 1345 if (globbed) 1346 blkfree(globbed); 1347 return (0); 1348 } 1349 if (globbed) { 1350 *cpp = *globbed++; 1351 /* don't waste too much memory */ 1352 if (*globbed) 1353 blkfree(globbed); 1354 } 1355 return (1); 1356 } 1357 1358 account(argc,argv) 1359 1360 int argc; 1361 char **argv; 1362 { 1363 char acct[50], *mygetpass(), *ap; 1364 1365 if (argc > 1) { 1366 ++argv; 1367 --argc; 1368 (void) strncpy(acct,*argv,49); 1369 acct[50] = '\0'; 1370 while (argc > 1) { 1371 --argc; 1372 ++argv; 1373 (void) strncat(acct,*argv, 49-strlen(acct)); 1374 } 1375 ap = acct; 1376 } 1377 else { 1378 ap = mygetpass("Account:"); 1379 } 1380 (void) command("ACCT %s", ap); 1381 } 1382 1383 jmp_buf abortprox; 1384 1385 proxabort() 1386 { 1387 extern int proxy; 1388 1389 if (!proxy) { 1390 pswitch(1); 1391 } 1392 if (connected) { 1393 proxflag = 1; 1394 } 1395 else { 1396 proxflag = 0; 1397 } 1398 pswitch(0); 1399 longjmp(abortprox,1); 1400 } 1401 1402 doproxy(argc,argv) 1403 int argc; 1404 char *argv[]; 1405 { 1406 int (*oldintr)(), proxabort(); 1407 register struct cmd *c; 1408 struct cmd *getcmd(); 1409 extern struct cmd cmdtab[]; 1410 extern jmp_buf abortprox; 1411 1412 if (argc < 2) { 1413 (void) strcat(line, " "); 1414 printf("(command) "); 1415 (void) gets(&line[strlen(line)]); 1416 makeargv(); 1417 argc = margc; 1418 argv = margv; 1419 } 1420 if (argc < 2) { 1421 printf("usage:%s command\n", argv[0]); 1422 code = -1; 1423 return; 1424 } 1425 c = getcmd(argv[1]); 1426 if (c == (struct cmd *) -1) { 1427 printf("?Ambiguous command\n"); 1428 (void) fflush(stdout); 1429 code = -1; 1430 return; 1431 } 1432 if (c == 0) { 1433 printf("?Invalid command\n"); 1434 (void) fflush(stdout); 1435 code = -1; 1436 return; 1437 } 1438 if (!c->c_proxy) { 1439 printf("?Invalid proxy command\n"); 1440 (void) fflush(stdout); 1441 code = -1; 1442 return; 1443 } 1444 if (setjmp(abortprox)) { 1445 code = -1; 1446 return; 1447 } 1448 oldintr = signal(SIGINT, proxabort); 1449 pswitch(1); 1450 if (c->c_conn && !connected) { 1451 printf("Not connected\n"); 1452 (void) fflush(stdout); 1453 pswitch(0); 1454 (void) signal(SIGINT, oldintr); 1455 code = -1; 1456 return; 1457 } 1458 (*c->c_handler)(argc-1, argv+1); 1459 if (connected) { 1460 proxflag = 1; 1461 } 1462 else { 1463 proxflag = 0; 1464 } 1465 pswitch(0); 1466 (void) signal(SIGINT, oldintr); 1467 } 1468 1469 setcase() 1470 { 1471 mcase = !mcase; 1472 printf("Case mapping %s.\n", onoff(mcase)); 1473 code = mcase; 1474 } 1475 1476 setcr() 1477 { 1478 crflag = !crflag; 1479 printf("Carriage Return stripping %s.\n", onoff(crflag)); 1480 code = crflag; 1481 } 1482 1483 setntrans(argc,argv) 1484 int argc; 1485 char *argv[]; 1486 { 1487 if (argc == 1) { 1488 ntflag = 0; 1489 printf("Ntrans off.\n"); 1490 code = ntflag; 1491 return; 1492 } 1493 ntflag++; 1494 code = ntflag; 1495 (void) strncpy(ntin, argv[1], 16); 1496 ntin[16] = '\0'; 1497 if (argc == 2) { 1498 ntout[0] = '\0'; 1499 return; 1500 } 1501 (void) strncpy(ntout, argv[2], 16); 1502 ntout[16] = '\0'; 1503 } 1504 1505 char * 1506 dotrans(name) 1507 char *name; 1508 { 1509 static char new[MAXPATHLEN]; 1510 char *cp1, *cp2 = new; 1511 register int i, ostop, found; 1512 1513 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); 1514 for (cp1 = name; *cp1; cp1++) { 1515 found = 0; 1516 for (i = 0; *(ntin + i) && i < 16; i++) { 1517 if (*cp1 == *(ntin + i)) { 1518 found++; 1519 if (i < ostop) { 1520 *cp2++ = *(ntout + i); 1521 } 1522 break; 1523 } 1524 } 1525 if (!found) { 1526 *cp2++ = *cp1; 1527 } 1528 } 1529 *cp2 = '\0'; 1530 return(new); 1531 } 1532 1533 setnmap(argc, argv) 1534 int argc; 1535 char *argv[]; 1536 { 1537 char *cp; 1538 1539 if (argc == 1) { 1540 mapflag = 0; 1541 printf("Nmap off.\n"); 1542 code = mapflag; 1543 return; 1544 } 1545 if (argc < 3) { 1546 (void) strcat(line, " "); 1547 printf("(mapout) "); 1548 (void) gets(&line[strlen(line)]); 1549 makeargv(); 1550 argc = margc; 1551 argv = margv; 1552 } 1553 if (argc < 3) { 1554 printf("Usage: %s [mapin mapout]\n",argv[0]); 1555 code = -1; 1556 return; 1557 } 1558 mapflag = 1; 1559 code = 1; 1560 cp = index(altarg, ' '); 1561 if (proxy) { 1562 while(*++cp == ' '); 1563 altarg = cp; 1564 cp = index(altarg, ' '); 1565 } 1566 *cp = '\0'; 1567 (void) strncpy(mapin, altarg, MAXPATHLEN - 1); 1568 while (*++cp == ' '); 1569 (void) strncpy(mapout, cp, MAXPATHLEN - 1); 1570 } 1571 1572 char * 1573 domap(name) 1574 char *name; 1575 { 1576 static char new[MAXPATHLEN]; 1577 register char *cp1 = name, *cp2 = mapin; 1578 char *tp[9], *te[9]; 1579 int i, toks[9], toknum, match = 1; 1580 1581 for (i=0; i < 9; ++i) { 1582 toks[i] = 0; 1583 } 1584 while (match && *cp1 && *cp2) { 1585 switch (*cp2) { 1586 case '\\': 1587 if (*++cp2 != *cp1) { 1588 match = 0; 1589 } 1590 break; 1591 case '$': 1592 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 1593 if (*cp1 != *(++cp2+1)) { 1594 toks[toknum = *cp2 - '1']++; 1595 tp[toknum] = cp1; 1596 while (*++cp1 && *(cp2+1) 1597 != *cp1); 1598 te[toknum] = cp1; 1599 } 1600 cp2++; 1601 break; 1602 } 1603 /* intentional drop through */ 1604 default: 1605 if (*cp2 != *cp1) { 1606 match = 0; 1607 } 1608 break; 1609 } 1610 if (*cp1) { 1611 cp1++; 1612 } 1613 if (*cp2) { 1614 cp2++; 1615 } 1616 } 1617 cp1 = new; 1618 *cp1 = '\0'; 1619 cp2 = mapout; 1620 while (*cp2) { 1621 match = 0; 1622 switch (*cp2) { 1623 case '\\': 1624 if (*(cp2 + 1)) { 1625 *cp1++ = *++cp2; 1626 } 1627 break; 1628 case '[': 1629 LOOP: 1630 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 1631 if (*++cp2 == '0') { 1632 char *cp3 = name; 1633 1634 while (*cp3) { 1635 *cp1++ = *cp3++; 1636 } 1637 match = 1; 1638 } 1639 else if (toks[toknum = *cp2 - '1']) { 1640 char *cp3 = tp[toknum]; 1641 1642 while (cp3 != te[toknum]) { 1643 *cp1++ = *cp3++; 1644 } 1645 match = 1; 1646 } 1647 } 1648 else { 1649 while (*cp2 && *cp2 != ',' && 1650 *cp2 != ']') { 1651 if (*cp2 == '\\') { 1652 cp2++; 1653 } 1654 else if (*cp2 == '$' && 1655 isdigit(*(cp2+1))) { 1656 if (*++cp2 == '0') { 1657 char *cp3 = name; 1658 1659 while (*cp3) { 1660 *cp1++ = *cp3++; 1661 } 1662 } 1663 else if (toks[toknum = 1664 *cp2 - '1']) { 1665 char *cp3=tp[toknum]; 1666 1667 while (cp3 != 1668 te[toknum]) { 1669 *cp1++ = *cp3++; 1670 } 1671 } 1672 } 1673 else if (*cp2) { 1674 *cp1++ = *cp2++; 1675 } 1676 } 1677 if (!*cp2) { 1678 printf("nmap: unbalanced brackets\n"); 1679 return(name); 1680 } 1681 match = 1; 1682 cp2--; 1683 } 1684 if (match) { 1685 while (*++cp2 && *cp2 != ']') { 1686 if (*cp2 == '\\' && *(cp2 + 1)) { 1687 cp2++; 1688 } 1689 } 1690 if (!*cp2) { 1691 printf("nmap: unbalanced brackets\n"); 1692 return(name); 1693 } 1694 break; 1695 } 1696 switch (*++cp2) { 1697 case ',': 1698 goto LOOP; 1699 case ']': 1700 break; 1701 default: 1702 cp2--; 1703 goto LOOP; 1704 } 1705 break; 1706 case '$': 1707 if (isdigit(*(cp2 + 1))) { 1708 if (*++cp2 == '0') { 1709 char *cp3 = name; 1710 1711 while (*cp3) { 1712 *cp1++ = *cp3++; 1713 } 1714 } 1715 else if (toks[toknum = *cp2 - '1']) { 1716 char *cp3 = tp[toknum]; 1717 1718 while (cp3 != te[toknum]) { 1719 *cp1++ = *cp3++; 1720 } 1721 } 1722 break; 1723 } 1724 /* intentional drop through */ 1725 default: 1726 *cp1++ = *cp2; 1727 break; 1728 } 1729 cp2++; 1730 } 1731 *cp1 = '\0'; 1732 if (!*new) { 1733 return(name); 1734 } 1735 return(new); 1736 } 1737 1738 setsunique() 1739 { 1740 sunique = !sunique; 1741 printf("Store unique %s.\n", onoff(sunique)); 1742 code = sunique; 1743 } 1744 1745 setrunique() 1746 { 1747 runique = !runique; 1748 printf("Receive unique %s.\n", onoff(runique)); 1749 code = runique; 1750 } 1751 1752 /* change directory to perent directory */ 1753 cdup() 1754 { 1755 (void) command("CDUP"); 1756 } 1757 1758 macdef(argc, argv) 1759 int argc; 1760 char *argv[]; 1761 { 1762 char *tmp; 1763 int c; 1764 1765 if (macnum == 16) { 1766 printf("Limit of 16 macros have already been defined\n"); 1767 code = -1; 1768 return; 1769 } 1770 if (argc < 2) { 1771 (void) strcat(line, " "); 1772 printf("(macro name) "); 1773 (void) gets(&line[strlen(line)]); 1774 makeargv(); 1775 argc = margc; 1776 argv = margv; 1777 } 1778 if (argc != 2) { 1779 printf("Usage: %s macro_name\n",argv[0]); 1780 code = -1; 1781 return; 1782 } 1783 if (interactive) { 1784 printf("Enter macro line by line, terminating it with a null line\n"); 1785 } 1786 (void) strncpy(macros[macnum].mac_name, argv[1], 8); 1787 if (macnum == 0) { 1788 macros[macnum].mac_start = macbuf; 1789 } 1790 else { 1791 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 1792 } 1793 tmp = macros[macnum].mac_start; 1794 while (tmp != macbuf+4096) { 1795 if ((c = getchar()) == EOF) { 1796 printf("macdef:end of file encountered\n"); 1797 code = -1; 1798 return; 1799 } 1800 if ((*tmp = c) == '\n') { 1801 if (tmp == macros[macnum].mac_start) { 1802 macros[macnum++].mac_end = tmp; 1803 code = 0; 1804 return; 1805 } 1806 if (*(tmp-1) == '\0') { 1807 macros[macnum++].mac_end = tmp - 1; 1808 code = 0; 1809 return; 1810 } 1811 *tmp = '\0'; 1812 } 1813 tmp++; 1814 } 1815 while (1) { 1816 while ((c = getchar()) != '\n' && c != EOF); 1817 if (c == EOF || getchar() == '\n') { 1818 printf("Macro not defined - 4k buffer exceeded\n"); 1819 code = -1; 1820 return; 1821 } 1822 } 1823 } 1824