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