1 #ifndef lint 2 static char sccsid[] = "@(#)cmds.c 4.4 (Berkeley) 03/23/83"; 3 #endif 4 5 /* 6 * FTP User Program -- Command Routines. 7 */ 8 #include <sys/param.h> 9 #include <sys/socket.h> 10 11 #include <signal.h> 12 #include <stdio.h> 13 #include <errno.h> 14 #include <netdb.h> 15 #include <stat.h> 16 17 #include "ftp.h" 18 #include "ftp_var.h" 19 20 extern char *globerr; 21 extern char **glob(); 22 extern short gflag; 23 24 /* 25 * Connect to peer server and 26 * auto-login, if possible. 27 */ 28 setpeer(argc, argv) 29 int argc; 30 char *argv[]; 31 { 32 struct hostent *host, *hookup(); 33 int port; 34 35 if (connected) { 36 printf("Already connected to %s, use disconnect first.\n", 37 hostname); 38 return; 39 } 40 if (argc < 2) { 41 strcat(line, " "); 42 printf("(to) "); 43 gets(&line[strlen(line)]); 44 makeargv(); 45 argc = margc; 46 argv = margv; 47 } 48 if (argc > 3) { 49 printf("usage: %s host-name [port]\n", argv[0]); 50 return; 51 } 52 port = sp->s_port; 53 if (argc > 2) { 54 port = atoi(argv[2]); 55 if (port <= 0) { 56 printf("%s: bad port number-- %s\n", argv[1], argv[2]); 57 printf ("usage: %s host-name [port]\n", argv[0]); 58 return; 59 } 60 port = htons(port); 61 } 62 host = hookup(argv[1], port); 63 if (host) { 64 connected = 1; 65 if (autologin) 66 login(host); 67 } 68 } 69 70 struct types { 71 char *t_name; 72 char *t_mode; 73 int t_type; 74 char *t_arg; 75 } types[] = { 76 { "ascii", "A", TYPE_A, 0 }, 77 { "binary", "I", TYPE_I, 0 }, 78 { "image", "I", TYPE_I, 0 }, 79 { "ebcdic", "E", TYPE_E, 0 }, 80 { "tenex", "L", TYPE_L, bytename }, 81 0 82 }; 83 84 /* 85 * Set transfer type. 86 */ 87 settype(argc, argv) 88 char *argv[]; 89 { 90 register struct types *p; 91 int comret; 92 93 if (argc > 2) { 94 char *sep; 95 96 printf("usage: %s [", argv[0]); 97 sep = " "; 98 for (p = types; p->t_name; p++) { 99 printf("%s%s", sep, p->t_name); 100 if (*sep == ' ') 101 sep = " | "; 102 } 103 printf(" ]\n"); 104 return; 105 } 106 if (argc < 2) { 107 printf("Using %s mode to transfer files.\n", typename); 108 return; 109 } 110 for (p = types; p->t_name; p++) 111 if (strcmp(argv[1], p->t_name) == 0) 112 break; 113 if (p->t_name == 0) { 114 printf("%s: unknown mode\n", argv[1]); 115 return; 116 } 117 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 118 comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 119 else 120 comret = command("TYPE %s", p->t_mode); 121 if (comret == COMPLETE) { 122 strcpy(typename, p->t_name); 123 type = p->t_type; 124 } 125 } 126 127 /* 128 * Set binary transfer type. 129 */ 130 /*VARARGS*/ 131 setbinary() 132 { 133 134 call(settype, "type", "binary", 0); 135 } 136 137 /* 138 * Set ascii transfer type. 139 */ 140 /*VARARGS*/ 141 setascii() 142 { 143 144 call(settype, "type", "ascii", 0); 145 } 146 147 /* 148 * Set tenex transfer type. 149 */ 150 /*VARARGS*/ 151 settenex() 152 { 153 154 call(settype, "type", "tenex", 0); 155 } 156 157 /* 158 * Set ebcdic transfer type. 159 */ 160 /*VARARGS*/ 161 setebcdic() 162 { 163 164 call(settype, "type", "ebcdic", 0); 165 } 166 167 /* 168 * Set file transfer mode. 169 */ 170 setmode(argc, argv) 171 char *argv[]; 172 { 173 174 printf("We only support %s mode, sorry.\n", modename); 175 } 176 177 /* 178 * Set file transfer format. 179 */ 180 setform(argc, argv) 181 char *argv[]; 182 { 183 184 printf("We only support %s format, sorry.\n", formname); 185 } 186 187 /* 188 * Set file transfer structure. 189 */ 190 setstruct(argc, argv) 191 char *argv[]; 192 { 193 194 printf("We only support %s structure, sorry.\n", structname); 195 } 196 197 /* 198 * Send a single file. 199 */ 200 append(argc, argv) 201 char *argv[]; 202 { 203 204 return (put1("APPE", argc, argv)); 205 } 206 207 put(argc, argv) 208 char *argv[]; 209 { 210 211 return (put1("STOR", argc, argv)); 212 } 213 214 put1(cmd, argc, argv) 215 char *cmd; 216 int argc; 217 char *argv[]; 218 { 219 220 if (argc == 2) 221 argc++, argv[2] = argv[1]; 222 if (argc < 2) { 223 strcat(line, " "); 224 printf("(local-file) "); 225 gets(&line[strlen(line)]); 226 makeargv(); 227 argc = margc; 228 argv = margv; 229 } 230 if (argc < 2) { 231 usage: 232 printf("%s local-file remote-file\n", argv[0]); 233 return; 234 } 235 if (argc < 3) { 236 strcat(line, " "); 237 printf("(remote-file) "); 238 gets(&line[strlen(line)]); 239 makeargv(); 240 argc = margc; 241 argv = margv; 242 } 243 if (argc < 3) 244 goto usage; 245 if (!globulize(&argv[1])) 246 return; 247 sendrequest(cmd, argv[1], argv[2]); 248 } 249 250 /* 251 * Send one or more files. 252 */ 253 mput(argc, argv) 254 char *argv[]; 255 { 256 char **cpp, **gargs = NULL; 257 int i; 258 259 if (argc < 2) { 260 strcat(line, " "); 261 printf("(local-files) "); 262 gets(&line[strlen(line)]); 263 makeargv(); 264 argc = margc; 265 argv = margv; 266 } 267 if (argc < 2) { 268 printf("%s local-files\n", argv[0]); 269 return; 270 } 271 cpp = argv + 1; 272 if (doglob) { 273 gargs = glob(cpp); 274 if (globerr != NULL) { 275 printf("%s\n", globerr); 276 if (gargs) 277 blkfree(gargs); 278 return; 279 } 280 } 281 if (gargs != NULL) 282 cpp = gargs; 283 for (; *cpp != NULL; cpp++) 284 if (confirm(argv[0], *cpp)) 285 sendrequest("STOR", *cpp, *cpp); 286 if (gargs != NULL) 287 blkfree(gargs); 288 } 289 290 /* 291 * Receive one file. 292 */ 293 get(argc, argv) 294 char *argv[]; 295 { 296 297 if (argc == 2) 298 argc++, argv[2] = argv[1]; 299 if (argc < 2) { 300 strcat(line, " "); 301 printf("(remote-file) "); 302 gets(&line[strlen(line)]); 303 makeargv(); 304 argc = margc; 305 argv = margv; 306 } 307 if (argc < 2) { 308 usage: 309 printf("%s remote-file [ local-file ]\n", argv[0]); 310 return; 311 } 312 if (argc < 3) { 313 strcat(line, " "); 314 printf("(local-file) "); 315 gets(&line[strlen(line)]); 316 makeargv(); 317 argc = margc; 318 argv = margv; 319 } 320 if (argc < 3) 321 goto usage; 322 if (!globulize(&argv[2])) 323 return; 324 recvrequest("RETR", argv[2], argv[1], "w"); 325 } 326 327 /* 328 * Get multiple files. 329 */ 330 mget(argc, argv) 331 char *argv[]; 332 { 333 register char *cp; 334 335 if (argc < 2) { 336 strcat(line, " "); 337 printf("(remote-directory) "); 338 gets(&line[strlen(line)]); 339 makeargv(); 340 argc = margc; 341 argv = margv; 342 } 343 if (argc < 2) { 344 printf("%s remote-files\n", argv[0]); 345 return; 346 } 347 while ((cp = remglob(argc, argv)) != NULL) 348 if (confirm(argv[0], cp)) 349 recvrequest("RETR", cp, cp, "w"); 350 } 351 352 char * 353 remglob(argc, argv) 354 char *argv[]; 355 { 356 char temp[16], *cp; 357 static char buf[MAXPATHLEN]; 358 static FILE *ftemp = NULL; 359 static char **args; 360 int oldverbose; 361 362 if (!doglob) { 363 if (argc == NULL) 364 args = argv; 365 if ((cp = *++args) == NULL) 366 args = NULL; 367 return (cp); 368 } 369 if (ftemp == NULL) { 370 strcpy(temp, "/tmp/ftpXXXXXX"); 371 mktemp(temp); 372 oldverbose = verbose, verbose = 0; 373 recvrequest("NLST", temp, argv[1], "w"); 374 verbose = oldverbose; 375 ftemp = fopen(temp, "r"); 376 unlink(temp); 377 if (ftemp == NULL) { 378 printf("can't find list of remote files, oops\n"); 379 return; 380 } 381 } 382 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 383 fclose(ftemp), ftemp = NULL; 384 return (NULL); 385 } 386 if ((cp = index(buf, '\n')) != NULL) 387 *cp = '\0'; 388 return (buf); 389 } 390 391 char * 392 onoff(bool) 393 int bool; 394 { 395 396 return (bool ? "on" : "off"); 397 } 398 399 /* 400 * Show status. 401 */ 402 status(argc, argv) 403 char *argv[]; 404 { 405 406 if (connected) 407 printf("Connected to %s.\n", hostname); 408 else 409 printf("Not connected.\n"); 410 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 411 modename, typename, formname, structname); 412 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 413 onoff(verbose), onoff(bell), onoff(interactive), 414 onoff(doglob)); 415 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 416 onoff(hash), onoff(sendport)); 417 } 418 419 /* 420 * Set beep on cmd completed mode. 421 */ 422 /*VARARGS*/ 423 setbell() 424 { 425 426 bell = !bell; 427 printf("Bell mode %s.\n", onoff(bell)); 428 } 429 430 /* 431 * Turn on packet tracing. 432 */ 433 /*VARARGS*/ 434 settrace() 435 { 436 437 trace = !trace; 438 printf("Packet tracing %s.\n", onoff(trace)); 439 } 440 441 /* 442 * Toggle hash mark printing during transfers. 443 */ 444 /*VARARGS*/ 445 sethash() 446 { 447 448 hash = !hash; 449 printf("Hash mark printing %s", onoff(hash)); 450 if (hash) 451 printf(" (%d bytes/hash mark)", BUFSIZ); 452 printf(".\n"); 453 } 454 455 /* 456 * Turn on printing of server echo's. 457 */ 458 /*VARARGS*/ 459 setverbose() 460 { 461 462 verbose = !verbose; 463 printf("Verbose mode %s.\n", onoff(verbose)); 464 } 465 466 /* 467 * Toggle PORT cmd use before each data connection. 468 */ 469 /*VARARGS*/ 470 setport() 471 { 472 473 sendport = !sendport; 474 printf("Use of PORT cmds %s.\n", onoff(sendport)); 475 } 476 477 /* 478 * Turn on interactive prompting 479 * during mget, mput, and mdelete. 480 */ 481 /*VARARGS*/ 482 setprompt() 483 { 484 485 interactive = !interactive; 486 printf("Interactive mode %s.\n", onoff(interactive)); 487 } 488 489 /* 490 * Toggle metacharacter interpretation 491 * on local file names. 492 */ 493 /*VARARGS*/ 494 setglob() 495 { 496 497 doglob = !doglob; 498 printf("Globbing %s.\n", onoff(doglob)); 499 } 500 501 /* 502 * Set debugging mode on/off and/or 503 * set level of debugging. 504 */ 505 setdebug(argc, argv) 506 char *argv[]; 507 { 508 int val; 509 510 if (argc > 1) { 511 val = atoi(argv[1]); 512 if (val < 0) { 513 printf("%s: bad debugging value.\n", argv[1]); 514 return; 515 } 516 } else 517 val = !debug; 518 debug = val; 519 if (debug) 520 options |= SO_DEBUG; 521 else 522 options &= ~SO_DEBUG; 523 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 524 } 525 526 /* 527 * Set current working directory 528 * on remote machine. 529 */ 530 cd(argc, argv) 531 char *argv[]; 532 { 533 534 if (!connected) { 535 printf("Not connected.\n"); 536 return; 537 } 538 if (argc < 2) { 539 strcat(line, " "); 540 printf("(remote-directory) "); 541 gets(&line[strlen(line)]); 542 makeargv(); 543 argc = margc; 544 argv = margv; 545 } 546 if (argc < 2) { 547 printf("%s remote-directory\n", argv[0]); 548 return; 549 } 550 (void) command("CWD %s", argv[1]); 551 } 552 553 /* 554 * Set current working directory 555 * on local machine. 556 */ 557 lcd(argc, argv) 558 char *argv[]; 559 { 560 char buf[MAXPATHLEN]; 561 extern char *home; 562 563 if (argc < 2) 564 argc++, argv[1] = home; 565 if (argc != 2) { 566 printf("%s local-directory\n", argv[0]); 567 return; 568 } 569 if (!globulize(&argv[1])) 570 return; 571 if (chdir(argv[1]) < 0) { 572 perror(argv[1]); 573 return; 574 } 575 printf("Local directory now %s\n", getwd(buf)); 576 } 577 578 /* 579 * Delete a single file. 580 */ 581 delete(argc, argv) 582 char *argv[]; 583 { 584 585 if (argc < 2) { 586 strcat(line, " "); 587 printf("(remote-file) "); 588 gets(&line[strlen(line)]); 589 makeargv(); 590 argc = margc; 591 argv = margv; 592 } 593 if (argc < 2) { 594 printf("%s remote-file\n", argv[0]); 595 return; 596 } 597 (void) command("DELE %s", argv[1]); 598 } 599 600 /* 601 * Delete multiple files. 602 */ 603 mdelete(argc, argv) 604 char *argv[]; 605 { 606 char *cp; 607 608 if (argc < 2) { 609 strcat(line, " "); 610 printf("(remote-files) "); 611 gets(&line[strlen(line)]); 612 makeargv(); 613 argc = margc; 614 argv = margv; 615 } 616 if (argc < 2) { 617 printf("%s remote-files\n", argv[0]); 618 return; 619 } 620 while ((cp = remglob(argc, argv)) != NULL) 621 if (confirm(argv[0], cp)) 622 (void) command("DELE %s", cp); 623 } 624 /* 625 * Rename a remote file. 626 */ 627 renamefile(argc, argv) 628 char *argv[]; 629 { 630 631 if (argc < 2) { 632 strcat(line, " "); 633 printf("(from-name) "); 634 gets(&line[strlen(line)]); 635 makeargv(); 636 argc = margc; 637 argv = margv; 638 } 639 if (argc < 2) { 640 usage: 641 printf("%s from-name to-name\n", argv[0]); 642 return; 643 } 644 if (argc < 3) { 645 strcat(line, " "); 646 printf("(to-name) "); 647 gets(&line[strlen(line)]); 648 makeargv(); 649 argc = margc; 650 argv = margv; 651 } 652 if (argc < 3) 653 goto usage; 654 if (command("RNFR %s", argv[1]) == CONTINUE) 655 (void) command("RNTO %s", argv[2]); 656 } 657 658 /* 659 * Get a directory listing 660 * of remote files. 661 */ 662 ls(argc, argv) 663 char *argv[]; 664 { 665 char *cmd, *mode; 666 int i; 667 668 if (argc < 2) 669 argc++, argv[1] = NULL; 670 if (argc < 3) 671 argc++, argv[2] = "-"; 672 cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 673 if (strcmp(argv[2], "-") && !globulize(&argv[2])) 674 return; 675 mode = argc > 3 ? "a" : "w"; 676 for (i = 1; i < argc - 1; i++) 677 recvrequest(cmd, argv[argc - 1], argv[i], mode); 678 } 679 680 /* 681 * Do a shell escape 682 */ 683 shell(argc, argv) 684 char *argv[]; 685 { 686 687 printf("Sorry, this function is unimplemented.\n"); 688 } 689 690 /* 691 * Send new user information (re-login) 692 */ 693 user(argc, argv) 694 int argc; 695 char **argv; 696 { 697 char acct[80], *getpass(); 698 int n; 699 700 if (argc < 2) { 701 strcat(line, " "); 702 printf("(username) "); 703 gets(&line[strlen(line)]); 704 makeargv(); 705 argc = margc; 706 argv = margv; 707 } 708 if (argc > 4) { 709 printf("usage: %s username [password] [account]\n", argv[0]); 710 return; 711 } 712 n = command("USER %s", argv[1]); 713 if (n == CONTINUE) { 714 if (argc < 3 ) 715 argv[2] = getpass("Password: "), argc++; 716 n = command("PASS %s", argv[2]); 717 } 718 if (n == CONTINUE) { 719 if (argc < 4) { 720 printf("Account: "); (void) fflush(stdout); 721 (void) fgets(acct, sizeof(acct) - 1, stdin); 722 acct[strlen(acct) - 1] = '\0'; 723 argv[3] = acct; argc++; 724 } 725 n = command("ACCT %s", acct); 726 } 727 if (n != COMPLETE) { 728 fprintf(stderr, "Login failed.\n"); 729 return (0); 730 } 731 return (1); 732 } 733 734 /* 735 * Print working directory. 736 */ 737 /*VARARGS*/ 738 pwd() 739 { 740 if (!connected) { 741 printf("Not connected.\n"); 742 return; 743 } 744 (void) command("XPWD"); 745 } 746 747 /* 748 * Make a directory. 749 */ 750 makedir(argc, argv) 751 char *argv[]; 752 { 753 754 if (argc < 2) { 755 strcat(line, " "); 756 printf("(directory-name) "); 757 gets(&line[strlen(line)]); 758 makeargv(); 759 argc = margc; 760 argv = margv; 761 } 762 if (argc < 2) { 763 printf("%s directory-name\n", argv[0]); 764 return; 765 } 766 (void) command("XMKD %s", argv[1]); 767 } 768 769 /* 770 * Remove a directory. 771 */ 772 removedir(argc, argv) 773 char *argv[]; 774 { 775 776 if (argc < 2) { 777 strcat(line, " "); 778 printf("(directory-name) "); 779 gets(&line[strlen(line)]); 780 makeargv(); 781 argc = margc; 782 argv = margv; 783 } 784 if (argc < 2) { 785 printf("%s directory-name\n", argv[0]); 786 return; 787 } 788 (void) command("XRMD %s", argv[1]); 789 } 790 791 /* 792 * Send a line, verbatim, to the remote machine. 793 */ 794 quote(argc, argv) 795 char *argv[]; 796 { 797 int i; 798 char buf[BUFSIZ]; 799 800 if (argc < 2) { 801 strcat(line, " "); 802 printf("(command line to send) "); 803 gets(&line[strlen(line)]); 804 makeargv(); 805 argc = margc; 806 argv = margv; 807 } 808 if (argc < 2) { 809 printf("usage: %s line-to-send\n", argv[0]); 810 return; 811 } 812 strcpy(buf, argv[1]); 813 for (i = 2; i < argc; i++) { 814 strcat(buf, " "); 815 strcat(buf, argv[i]); 816 } 817 (void) command(buf); 818 } 819 820 /* 821 * Ask the other side for help. 822 */ 823 rmthelp(argc, argv) 824 char *argv[]; 825 { 826 int oldverbose = verbose; 827 828 verbose = 1; 829 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 830 verbose = oldverbose; 831 } 832 833 /* 834 * Terminate session and exit. 835 */ 836 /*VARARGS*/ 837 quit() 838 { 839 840 disconnect(); 841 exit(0); 842 } 843 844 /* 845 * Terminate session, but don't exit. 846 */ 847 disconnect() 848 { 849 extern FILE *cout; 850 extern int data; 851 852 if (!connected) 853 return; 854 (void) command("QUIT"); 855 (void) fclose(cout); 856 cout = NULL; 857 connected = 0; 858 data = -1; 859 } 860 861 confirm(cmd, file) 862 char *cmd, *file; 863 { 864 char line[BUFSIZ]; 865 866 if (!interactive) 867 return (1); 868 printf("%s %s? ", cmd, file); 869 fflush(stdout); 870 gets(line); 871 return (*line != 'n' && *line != 'N'); 872 } 873 874 fatal(msg) 875 char *msg; 876 { 877 878 fprintf(stderr, "ftp: %s\n"); 879 exit(1); 880 } 881 882 /* 883 * Glob a local file name specification with 884 * the expectation of a single return value. 885 * Can't control multiple values being expanded 886 * from the expression, we return only the first. 887 */ 888 globulize(cpp) 889 char **cpp; 890 { 891 char **globbed; 892 893 if (!doglob) 894 return (1); 895 globbed = glob(*cpp); 896 if (globerr != NULL) { 897 printf("%s: %s\n", *cpp, globerr); 898 if (globbed) 899 blkfree(globbed); 900 return (0); 901 } 902 if (globbed) { 903 *cpp = *globbed++; 904 /* don't waste too much memory */ 905 if (*globbed) 906 blkfree(globbed); 907 } 908 return (1); 909 } 910