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