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