Annotation of src/usr.bin/ftp/cmds.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: cmds.c,v 1.8 1995/09/08 01:06:05 tls Exp $ */
2:
3: /*
4: * Copyright (c) 1985, 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: #if 0
38: static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
39: #else
40: static char rcsid[] = "$NetBSD: cmds.c,v 1.8 1995/09/08 01:06:05 tls Exp $";
41: #endif
42: #endif /* not lint */
43:
44: /*
45: * FTP User Program -- Command Routines.
46: */
47: #include <sys/param.h>
48: #include <sys/wait.h>
49: #include <sys/stat.h>
50: #include <sys/socket.h>
51: #include <netinet/in.h>
52: #include <arpa/ftp.h>
53:
54: #include <ctype.h>
55: #include <err.h>
56: #include <glob.h>
57: #include <netdb.h>
58: #include <signal.h>
59: #include <stdio.h>
60: #include <stdlib.h>
61: #include <string.h>
62: #include <time.h>
63: #include <unistd.h>
64:
65: #include "ftp_var.h"
66: #include "pathnames.h"
67:
68: jmp_buf jabort;
69: char *mname;
70: char *home = "/";
71:
72: /*
73: * `Another' gets another argument, and stores the new argc and argv.
74: * It reverts to the top level (via main.c's intr()) on EOF/error.
75: *
76: * Returns false if no new arguments have been added.
77: */
78: int
79: another(pargc, pargv, prompt)
80: int *pargc;
81: char ***pargv;
82: char *prompt;
83: {
84: int len = strlen(line), ret;
85:
86: if (len >= sizeof(line) - 3) {
87: printf("sorry, arguments too long\n");
88: intr();
89: }
90: printf("(%s) ", prompt);
91: line[len++] = ' ';
92: if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
93: intr();
94: len += strlen(&line[len]);
95: if (len > 0 && line[len - 1] == '\n')
96: line[len - 1] = '\0';
97: makeargv();
98: ret = margc > *pargc;
99: *pargc = margc;
100: *pargv = margv;
101: return (ret);
102: }
103:
104: /*
105: * Connect to peer server and
106: * auto-login, if possible.
107: */
108: void
109: setpeer(argc, argv)
110: int argc;
111: char *argv[];
112: {
113: char *host;
114: short port;
115:
116: if (connected) {
117: printf("Already connected to %s, use close first.\n",
118: hostname);
119: code = -1;
120: return;
121: }
122: if (argc < 2)
123: (void) another(&argc, &argv, "to");
124: if (argc < 2 || argc > 3) {
125: printf("usage: %s host-name [port]\n", argv[0]);
126: code = -1;
127: return;
128: }
129: port = sp->s_port;
130: if (argc > 2) {
131: port = atoi(argv[2]);
132: if (port <= 0) {
133: printf("%s: bad port number-- %s\n", argv[1], argv[2]);
134: printf ("usage: %s host-name [port]\n", argv[0]);
135: code = -1;
136: return;
137: }
138: port = htons(port);
139: }
140: host = hookup(argv[1], port);
141: if (host) {
142: int overbose;
143:
144: connected = 1;
145: /*
146: * Set up defaults for FTP.
147: */
148: (void) strcpy(typename, "ascii"), type = TYPE_A;
149: curtype = TYPE_A;
150: (void) strcpy(formname, "non-print"), form = FORM_N;
151: (void) strcpy(modename, "stream"), mode = MODE_S;
152: (void) strcpy(structname, "file"), stru = STRU_F;
153: (void) strcpy(bytename, "8"), bytesize = 8;
154: if (autologin)
155: (void) login(argv[1]);
156:
157: #if defined(unix) && NBBY == 8
158: /*
159: * this ifdef is to keep someone form "porting" this to an incompatible
160: * system and not checking this out. This way they have to think about it.
161: */
162: overbose = verbose;
163: if (debug == 0)
164: verbose = -1;
165: if (command("SYST") == COMPLETE && overbose) {
166: char *cp, c;
167: cp = strchr(reply_string+4, ' ');
168: if (cp == NULL)
169: cp = strchr(reply_string+4, '\r');
170: if (cp) {
171: if (cp[-1] == '.')
172: cp--;
173: c = *cp;
174: *cp = '\0';
175: }
176:
177: printf("Remote system type is %s.\n",
178: reply_string+4);
179: if (cp)
180: *cp = c;
181: }
182: if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
183: if (proxy)
184: unix_proxy = 1;
185: else
186: unix_server = 1;
187: /*
188: * Set type to 0 (not specified by user),
189: * meaning binary by default, but don't bother
190: * telling server. We can use binary
191: * for text files unless changed by the user.
192: */
193: type = 0;
194: (void) strcpy(typename, "binary");
195: if (overbose)
196: printf("Using %s mode to transfer files.\n",
197: typename);
198: } else {
199: if (proxy)
200: unix_proxy = 0;
201: else
202: unix_server = 0;
203: if (overbose &&
204: !strncmp(reply_string, "215 TOPS20", 10))
205: printf(
206: "Remember to set tenex mode when transfering binary files from this machine.\n");
207: }
208: verbose = overbose;
209: #endif /* unix */
210: }
211: }
212:
213: struct types {
214: char *t_name;
215: char *t_mode;
216: int t_type;
217: char *t_arg;
218: } types[] = {
219: { "ascii", "A", TYPE_A, 0 },
220: { "binary", "I", TYPE_I, 0 },
221: { "image", "I", TYPE_I, 0 },
222: { "ebcdic", "E", TYPE_E, 0 },
223: { "tenex", "L", TYPE_L, bytename },
224: { NULL }
225: };
226:
227: /*
228: * Set transfer type.
229: */
230: void
231: settype(argc, argv)
232: int argc;
233: char *argv[];
234: {
235: struct types *p;
236: int comret;
237:
238: if (argc > 2) {
239: char *sep;
240:
241: printf("usage: %s [", argv[0]);
242: sep = " ";
243: for (p = types; p->t_name; p++) {
244: printf("%s%s", sep, p->t_name);
245: sep = " | ";
246: }
247: printf(" ]\n");
248: code = -1;
249: return;
250: }
251: if (argc < 2) {
252: printf("Using %s mode to transfer files.\n", typename);
253: code = 0;
254: return;
255: }
256: for (p = types; p->t_name; p++)
257: if (strcmp(argv[1], p->t_name) == 0)
258: break;
259: if (p->t_name == 0) {
260: printf("%s: unknown mode\n", argv[1]);
261: code = -1;
262: return;
263: }
264: if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
265: comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
266: else
267: comret = command("TYPE %s", p->t_mode);
268: if (comret == COMPLETE) {
269: (void) strcpy(typename, p->t_name);
270: curtype = type = p->t_type;
271: }
272: }
273:
274: /*
275: * Internal form of settype; changes current type in use with server
276: * without changing our notion of the type for data transfers.
277: * Used to change to and from ascii for listings.
278: */
279: void
280: changetype(newtype, show)
281: int newtype, show;
282: {
283: struct types *p;
284: int comret, oldverbose = verbose;
285:
286: if (newtype == 0)
287: newtype = TYPE_I;
288: if (newtype == curtype)
289: return;
290: if (debug == 0 && show == 0)
291: verbose = 0;
292: for (p = types; p->t_name; p++)
293: if (newtype == p->t_type)
294: break;
295: if (p->t_name == 0) {
296: printf("ftp: internal error: unknown type %d\n", newtype);
297: return;
298: }
299: if (newtype == TYPE_L && bytename[0] != '\0')
300: comret = command("TYPE %s %s", p->t_mode, bytename);
301: else
302: comret = command("TYPE %s", p->t_mode);
303: if (comret == COMPLETE)
304: curtype = newtype;
305: verbose = oldverbose;
306: }
307:
308: char *stype[] = {
309: "type",
310: "",
311: 0
312: };
313:
314: /*
315: * Set binary transfer type.
316: */
317: /*VARARGS*/
318: void
319: setbinary(argc, argv)
320: int argc;
321: char **argv;
322: {
323:
324: stype[1] = "binary";
325: settype(2, stype);
326: }
327:
328: /*
329: * Set ascii transfer type.
330: */
331: /*VARARGS*/
332: void
333: setascii(argc, argv)
334: int argc;
335: char *argv[];
336: {
337:
338: stype[1] = "ascii";
339: settype(2, stype);
340: }
341:
342: /*
343: * Set tenex transfer type.
344: */
345: /*VARARGS*/
346: void
347: settenex(argc, argv)
348: int argc;
349: char *argv[];
350: {
351:
352: stype[1] = "tenex";
353: settype(2, stype);
354: }
355:
356: /*
357: * Set file transfer mode.
358: */
359: /*ARGSUSED*/
360: void
361: setftmode(argc, argv)
362: int argc;
363: char *argv[];
364: {
365:
366: printf("We only support %s mode, sorry.\n", modename);
367: code = -1;
368: }
369:
370: /*
371: * Set file transfer format.
372: */
373: /*ARGSUSED*/
374: void
375: setform(argc, argv)
376: int argc;
377: char *argv[];
378: {
379:
380: printf("We only support %s format, sorry.\n", formname);
381: code = -1;
382: }
383:
384: /*
385: * Set file transfer structure.
386: */
387: /*ARGSUSED*/
388: void
389: setstruct(argc, argv)
390: int argc;
391: char *argv[];
392: {
393:
394: printf("We only support %s structure, sorry.\n", structname);
395: code = -1;
396: }
397:
398: /*
399: * Send a single file.
400: */
401: void
402: put(argc, argv)
403: int argc;
404: char *argv[];
405: {
406: char *cmd;
407: int loc = 0;
408: char *oldargv1, *oldargv2;
409:
410: if (argc == 2) {
411: argc++;
412: argv[2] = argv[1];
413: loc++;
414: }
415: if (argc < 2 && !another(&argc, &argv, "local-file"))
416: goto usage;
417: if (argc < 3 && !another(&argc, &argv, "remote-file")) {
418: usage:
419: printf("usage: %s local-file remote-file\n", argv[0]);
420: code = -1;
421: return;
422: }
423: oldargv1 = argv[1];
424: oldargv2 = argv[2];
425: if (!globulize(&argv[1])) {
426: code = -1;
427: return;
428: }
429: /*
430: * If "globulize" modifies argv[1], and argv[2] is a copy of
431: * the old argv[1], make it a copy of the new argv[1].
432: */
433: if (argv[1] != oldargv1 && argv[2] == oldargv1) {
434: argv[2] = argv[1];
435: }
436: cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
437: if (loc && ntflag) {
438: argv[2] = dotrans(argv[2]);
439: }
440: if (loc && mapflag) {
441: argv[2] = domap(argv[2]);
442: }
443: sendrequest(cmd, argv[1], argv[2],
444: argv[1] != oldargv1 || argv[2] != oldargv2);
445: }
446:
447: /*
448: * Send multiple files.
449: */
450: void
451: mput(argc, argv)
452: int argc;
453: char **argv;
454: {
455: int i;
456: sig_t oldintr;
457: int ointer;
458: char *tp;
459:
460: if (argc < 2 && !another(&argc, &argv, "local-files")) {
461: printf("usage: %s local-files\n", argv[0]);
462: code = -1;
463: return;
464: }
465: mname = argv[0];
466: mflag = 1;
467: oldintr = signal(SIGINT, mabort);
468: (void) setjmp(jabort);
469: if (proxy) {
470: char *cp, *tp2, tmpbuf[MAXPATHLEN];
471:
472: while ((cp = remglob(argv,0)) != NULL) {
473: if (*cp == 0) {
474: mflag = 0;
475: continue;
476: }
477: if (mflag && confirm(argv[0], cp)) {
478: tp = cp;
479: if (mcase) {
480: while (*tp && !islower(*tp)) {
481: tp++;
482: }
483: if (!*tp) {
484: tp = cp;
485: tp2 = tmpbuf;
486: while ((*tp2 = *tp) != NULL) {
487: if (isupper(*tp2)) {
488: *tp2 = 'a' + *tp2 - 'A';
489: }
490: tp++;
491: tp2++;
492: }
493: }
494: tp = tmpbuf;
495: }
496: if (ntflag) {
497: tp = dotrans(tp);
498: }
499: if (mapflag) {
500: tp = domap(tp);
501: }
502: sendrequest((sunique) ? "STOU" : "STOR",
503: cp, tp, cp != tp || !interactive);
504: if (!mflag && fromatty) {
505: ointer = interactive;
506: interactive = 1;
507: if (confirm("Continue with","mput")) {
508: mflag++;
509: }
510: interactive = ointer;
511: }
512: }
513: }
514: (void) signal(SIGINT, oldintr);
515: mflag = 0;
516: return;
517: }
518: for (i = 1; i < argc; i++) {
519: char **cpp, **gargs;
520: glob_t gl;
521: int flags;
522:
523: if (!doglob) {
524: if (mflag && confirm(argv[0], argv[i])) {
525: tp = (ntflag) ? dotrans(argv[i]) : argv[i];
526: tp = (mapflag) ? domap(tp) : tp;
527: sendrequest((sunique) ? "STOU" : "STOR",
528: argv[i], tp, tp != argv[i] || !interactive);
529: if (!mflag && fromatty) {
530: ointer = interactive;
531: interactive = 1;
532: if (confirm("Continue with","mput")) {
533: mflag++;
534: }
535: interactive = ointer;
536: }
537: }
538: continue;
539: }
540:
541: memset(&gl, 0, sizeof(gl));
542: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
543: if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
544: warnx("%s: not found", argv[i]);
545: globfree(&gl);
546: continue;
547: }
548: for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
549: if (mflag && confirm(argv[0], *cpp)) {
550: tp = (ntflag) ? dotrans(*cpp) : *cpp;
551: tp = (mapflag) ? domap(tp) : tp;
552: sendrequest((sunique) ? "STOU" : "STOR",
553: *cpp, tp, *cpp != tp || !interactive);
554: if (!mflag && fromatty) {
555: ointer = interactive;
556: interactive = 1;
557: if (confirm("Continue with","mput")) {
558: mflag++;
559: }
560: interactive = ointer;
561: }
562: }
563: }
564: globfree(&gl);
565: }
566: (void) signal(SIGINT, oldintr);
567: mflag = 0;
568: }
569:
570: void
571: reget(argc, argv)
572: int argc;
573: char *argv[];
574: {
575:
576: (void) getit(argc, argv, 1, "r+w");
577: }
578:
579: void
580: get(argc, argv)
581: int argc;
582: char *argv[];
583: {
584:
585: (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
586: }
587:
588: /*
589: * Receive one file.
590: */
591: int
592: getit(argc, argv, restartit, mode)
593: int argc;
594: char *argv[];
595: char *mode;
596: int restartit;
597: {
598: int loc = 0;
599: char *oldargv1, *oldargv2;
600:
601: if (argc == 2) {
602: argc++;
603: argv[2] = argv[1];
604: loc++;
605: }
606: if (argc < 2 && !another(&argc, &argv, "remote-file"))
607: goto usage;
608: if (argc < 3 && !another(&argc, &argv, "local-file")) {
609: usage:
610: printf("usage: %s remote-file [ local-file ]\n", argv[0]);
611: code = -1;
612: return (0);
613: }
614: oldargv1 = argv[1];
615: oldargv2 = argv[2];
616: if (!globulize(&argv[2])) {
617: code = -1;
618: return (0);
619: }
620: if (loc && mcase) {
621: char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
622:
623: while (*tp && !islower(*tp)) {
624: tp++;
625: }
626: if (!*tp) {
627: tp = argv[2];
628: tp2 = tmpbuf;
629: while ((*tp2 = *tp) != NULL) {
630: if (isupper(*tp2)) {
631: *tp2 = 'a' + *tp2 - 'A';
632: }
633: tp++;
634: tp2++;
635: }
636: argv[2] = tmpbuf;
637: }
638: }
639: if (loc && ntflag)
640: argv[2] = dotrans(argv[2]);
641: if (loc && mapflag)
642: argv[2] = domap(argv[2]);
643: if (restartit) {
644: struct stat stbuf;
645: int ret;
646:
647: ret = stat(argv[2], &stbuf);
648: if (restartit == 1) {
649: if (ret < 0) {
650: warn("local: %s", argv[2]);
651: return (0);
652: }
653: restart_point = stbuf.st_size;
654: } else {
655: if (ret == 0) {
656: int overbose;
657:
658: overbose = verbose;
659: if (debug == 0)
660: verbose = -1;
661: if (command("MDTM %s", argv[1]) == COMPLETE) {
662: int yy, mo, day, hour, min, sec;
663: struct tm *tm;
664: verbose = overbose;
665: sscanf(reply_string,
666: "%*s %04d%02d%02d%02d%02d%02d",
667: &yy, &mo, &day, &hour, &min, &sec);
668: tm = gmtime(&stbuf.st_mtime);
669: tm->tm_mon++;
670: if (tm->tm_year > yy%100)
671: return (1);
672: if ((tm->tm_year == yy%100 &&
673: tm->tm_mon > mo) ||
674: (tm->tm_mon == mo &&
675: tm->tm_mday > day) ||
676: (tm->tm_mday == day &&
677: tm->tm_hour > hour) ||
678: (tm->tm_hour == hour &&
679: tm->tm_min > min) ||
680: (tm->tm_min == min &&
681: tm->tm_sec > sec))
682: return (1);
683: } else {
684: printf("%s\n", reply_string);
685: verbose = overbose;
686: return (0);
687: }
688: }
689: }
690: }
691:
692: recvrequest("RETR", argv[2], argv[1], mode,
693: argv[1] != oldargv1 || argv[2] != oldargv2);
694: restart_point = 0;
695: return (0);
696: }
697:
698: /* ARGSUSED */
699: void
700: mabort(signo)
701: int signo;
702: {
703: int ointer;
704:
705: printf("\n");
706: (void) fflush(stdout);
707: if (mflag && fromatty) {
708: ointer = interactive;
709: interactive = 1;
710: if (confirm("Continue with", mname)) {
711: interactive = ointer;
712: longjmp(jabort,0);
713: }
714: interactive = ointer;
715: }
716: mflag = 0;
717: longjmp(jabort,0);
718: }
719:
720: /*
721: * Get multiple files.
722: */
723: void
724: mget(argc, argv)
725: int argc;
726: char **argv;
727: {
728: sig_t oldintr;
729: int ch, ointer;
730: char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
731:
732: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
733: printf("usage: %s remote-files\n", argv[0]);
734: code = -1;
735: return;
736: }
737: mname = argv[0];
738: mflag = 1;
739: oldintr = signal(SIGINT, mabort);
740: (void) setjmp(jabort);
741: while ((cp = remglob(argv,proxy)) != NULL) {
742: if (*cp == '\0') {
743: mflag = 0;
744: continue;
745: }
746: if (mflag && confirm(argv[0], cp)) {
747: tp = cp;
748: if (mcase) {
749: for (tp2 = tmpbuf; ch = *tp++;)
750: *tp2++ = isupper(ch) ? tolower(ch) : ch;
751: *tp2 = '\0';
752: tp = tmpbuf;
753: }
754: if (ntflag) {
755: tp = dotrans(tp);
756: }
757: if (mapflag) {
758: tp = domap(tp);
759: }
760: recvrequest("RETR", tp, cp, "w",
761: tp != cp || !interactive);
762: if (!mflag && fromatty) {
763: ointer = interactive;
764: interactive = 1;
765: if (confirm("Continue with","mget")) {
766: mflag++;
767: }
768: interactive = ointer;
769: }
770: }
771: }
772: (void) signal(SIGINT,oldintr);
773: mflag = 0;
774: }
775:
776: char *
777: remglob(argv,doswitch)
778: char *argv[];
779: int doswitch;
780: {
781: char temp[16];
782: static char buf[MAXPATHLEN];
783: static FILE *ftemp = NULL;
784: static char **args;
785: int oldverbose, oldhash;
786: char *cp, *mode;
787:
788: if (!mflag) {
789: if (!doglob) {
790: args = NULL;
791: }
792: else {
793: if (ftemp) {
794: (void) fclose(ftemp);
795: ftemp = NULL;
796: }
797: }
798: return (NULL);
799: }
800: if (!doglob) {
801: if (args == NULL)
802: args = argv;
803: if ((cp = *++args) == NULL)
804: args = NULL;
805: return (cp);
806: }
807: if (ftemp == NULL) {
808: (void) strcpy(temp, _PATH_TMP);
809: (void) mktemp(temp);
810: oldverbose = verbose, verbose = 0;
811: oldhash = hash, hash = 0;
812: if (doswitch) {
813: pswitch(!proxy);
814: }
815: for (mode = "w"; *++argv != NULL; mode = "a")
816: recvrequest ("NLST", temp, *argv, mode, 0);
817: if (doswitch) {
818: pswitch(!proxy);
819: }
820: verbose = oldverbose; hash = oldhash;
821: ftemp = fopen(temp, "r");
822: (void) unlink(temp);
823: if (ftemp == NULL) {
824: printf("can't find list of remote files, oops\n");
825: return (NULL);
826: }
827: }
828: if (fgets(buf, sizeof (buf), ftemp) == NULL) {
829: (void) fclose(ftemp), ftemp = NULL;
830: return (NULL);
831: }
832: if ((cp = strchr(buf, '\n')) != NULL)
833: *cp = '\0';
834: return (buf);
835: }
836:
837: char *
838: onoff(bool)
839: int bool;
840: {
841:
842: return (bool ? "on" : "off");
843: }
844:
845: /*
846: * Show status.
847: */
848: /*ARGSUSED*/
849: void
850: status(argc, argv)
851: int argc;
852: char *argv[];
853: {
854: int i;
855:
856: if (connected)
857: printf("Connected to %s.\n", hostname);
858: else
859: printf("Not connected.\n");
860: if (!proxy) {
861: pswitch(1);
862: if (connected) {
863: printf("Connected for proxy commands to %s.\n", hostname);
864: }
865: else {
866: printf("No proxy connection.\n");
867: }
868: pswitch(0);
869: }
870: printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
871: modename, typename, formname, structname);
872: printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
873: onoff(verbose), onoff(bell), onoff(interactive),
874: onoff(doglob));
875: printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
876: onoff(runique));
877: printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
878: if (ntflag) {
879: printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
880: }
881: else {
882: printf("Ntrans: off\n");
883: }
884: if (mapflag) {
885: printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
886: }
887: else {
888: printf("Nmap: off\n");
889: }
890: printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
891: onoff(hash), onoff(sendport));
892: if (macnum > 0) {
893: printf("Macros:\n");
894: for (i=0; i<macnum; i++) {
895: printf("\t%s\n",macros[i].mac_name);
896: }
897: }
898: code = 0;
899: }
900:
901: /*
902: * Set beep on cmd completed mode.
903: */
904: /*VARARGS*/
905: void
906: setbell(argc, argv)
907: int argc;
908: char *argv[];
909: {
910:
911: bell = !bell;
912: printf("Bell mode %s.\n", onoff(bell));
913: code = bell;
914: }
915:
916: /*
917: * Turn on packet tracing.
918: */
919: /*VARARGS*/
920: void
921: settrace(argc, argv)
922: int argc;
923: char *argv[];
924: {
925:
926: trace = !trace;
927: printf("Packet tracing %s.\n", onoff(trace));
928: code = trace;
929: }
930:
931: /*
932: * Toggle hash mark printing during transfers.
933: */
934: /*VARARGS*/
935: void
936: sethash(argc, argv)
937: int argc;
938: char *argv[];
939: {
940:
941: hash = !hash;
942: printf("Hash mark printing %s", onoff(hash));
943: code = hash;
944: if (hash)
945: printf(" (%d bytes/hash mark)", 1024);
946: printf(".\n");
947: }
948:
949: /*
950: * Turn on printing of server echo's.
951: */
952: /*VARARGS*/
953: void
954: setverbose(argc, argv)
955: int argc;
956: char *argv[];
957: {
958:
959: verbose = !verbose;
960: printf("Verbose mode %s.\n", onoff(verbose));
961: code = verbose;
962: }
963:
964: /*
965: * Toggle PORT cmd use before each data connection.
966: */
967: /*VARARGS*/
968: void
969: setport(argc, argv)
970: int argc;
971: char *argv[];
972: {
973:
974: sendport = !sendport;
975: printf("Use of PORT cmds %s.\n", onoff(sendport));
976: code = sendport;
977: }
978:
979: /*
980: * Turn on interactive prompting
981: * during mget, mput, and mdelete.
982: */
983: /*VARARGS*/
984: void
985: setprompt(argc, argv)
986: int argc;
987: char *argv[];
988: {
989:
990: interactive = !interactive;
991: printf("Interactive mode %s.\n", onoff(interactive));
992: code = interactive;
993: }
994:
995: /*
996: * Toggle metacharacter interpretation
997: * on local file names.
998: */
999: /*VARARGS*/
1000: void
1001: setglob(argc, argv)
1002: int argc;
1003: char *argv[];
1004: {
1005:
1006: doglob = !doglob;
1007: printf("Globbing %s.\n", onoff(doglob));
1008: code = doglob;
1009: }
1010:
1011: /*
1012: * Set debugging mode on/off and/or
1013: * set level of debugging.
1014: */
1015: /*VARARGS*/
1016: void
1017: setdebug(argc, argv)
1018: int argc;
1019: char *argv[];
1020: {
1021: int val;
1022:
1023: if (argc > 1) {
1024: val = atoi(argv[1]);
1025: if (val < 0) {
1026: printf("%s: bad debugging value.\n", argv[1]);
1027: code = -1;
1028: return;
1029: }
1030: } else
1031: val = !debug;
1032: debug = val;
1033: if (debug)
1034: options |= SO_DEBUG;
1035: else
1036: options &= ~SO_DEBUG;
1037: printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1038: code = debug > 0;
1039: }
1040:
1041: /*
1042: * Set current working directory
1043: * on remote machine.
1044: */
1045: void
1046: cd(argc, argv)
1047: int argc;
1048: char *argv[];
1049: {
1050:
1051: if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1052: printf("usage: %s remote-directory\n", argv[0]);
1053: code = -1;
1054: return;
1055: }
1056: if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1057: if (verbose)
1058: printf("CWD command not recognized, trying XCWD\n");
1059: (void) command("XCWD %s", argv[1]);
1060: }
1061: }
1062:
1063: /*
1064: * Set current working directory
1065: * on local machine.
1066: */
1067: void
1068: lcd(argc, argv)
1069: int argc;
1070: char *argv[];
1071: {
1072: char buf[MAXPATHLEN];
1073:
1074: if (argc < 2)
1075: argc++, argv[1] = home;
1076: if (argc != 2) {
1077: printf("usage: %s local-directory\n", argv[0]);
1078: code = -1;
1079: return;
1080: }
1081: if (!globulize(&argv[1])) {
1082: code = -1;
1083: return;
1084: }
1085: if (chdir(argv[1]) < 0) {
1086: warn("local: %s", argv[1]);
1087: code = -1;
1088: return;
1089: }
1090: if (getwd(buf) != NULL)
1091: printf("Local directory now %s\n", buf);
1092: else
1093: warnx("getwd: %s", buf);
1094: code = 0;
1095: }
1096:
1097: /*
1098: * Delete a single file.
1099: */
1100: void
1101: delete(argc, argv)
1102: int argc;
1103: char *argv[];
1104: {
1105:
1106: if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1107: printf("usage: %s remote-file\n", argv[0]);
1108: code = -1;
1109: return;
1110: }
1111: (void) command("DELE %s", argv[1]);
1112: }
1113:
1114: /*
1115: * Delete multiple files.
1116: */
1117: void
1118: mdelete(argc, argv)
1119: int argc;
1120: char **argv;
1121: {
1122: sig_t oldintr;
1123: int ointer;
1124: char *cp;
1125:
1126: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1127: printf("usage: %s remote-files\n", argv[0]);
1128: code = -1;
1129: return;
1130: }
1131: mname = argv[0];
1132: mflag = 1;
1133: oldintr = signal(SIGINT, mabort);
1134: (void) setjmp(jabort);
1135: while ((cp = remglob(argv,0)) != NULL) {
1136: if (*cp == '\0') {
1137: mflag = 0;
1138: continue;
1139: }
1140: if (mflag && confirm(argv[0], cp)) {
1141: (void) command("DELE %s", cp);
1142: if (!mflag && fromatty) {
1143: ointer = interactive;
1144: interactive = 1;
1145: if (confirm("Continue with", "mdelete")) {
1146: mflag++;
1147: }
1148: interactive = ointer;
1149: }
1150: }
1151: }
1152: (void) signal(SIGINT, oldintr);
1153: mflag = 0;
1154: }
1155:
1156: /*
1157: * Rename a remote file.
1158: */
1159: void
1160: renamefile(argc, argv)
1161: int argc;
1162: char *argv[];
1163: {
1164:
1165: if (argc < 2 && !another(&argc, &argv, "from-name"))
1166: goto usage;
1167: if (argc < 3 && !another(&argc, &argv, "to-name")) {
1168: usage:
1169: printf("%s from-name to-name\n", argv[0]);
1170: code = -1;
1171: return;
1172: }
1173: if (command("RNFR %s", argv[1]) == CONTINUE)
1174: (void) command("RNTO %s", argv[2]);
1175: }
1176:
1177: /*
1178: * Get a directory listing
1179: * of remote files.
1180: */
1181: void
1182: ls(argc, argv)
1183: int argc;
1184: char *argv[];
1185: {
1186: char *cmd;
1187:
1188: if (argc < 2)
1189: argc++, argv[1] = NULL;
1190: if (argc < 3)
1191: argc++, argv[2] = "-";
1192: if (argc > 3) {
1193: printf("usage: %s remote-directory local-file\n", argv[0]);
1194: code = -1;
1195: return;
1196: }
1197: cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1198: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1199: code = -1;
1200: return;
1201: }
1202: if (strcmp(argv[2], "-") && *argv[2] != '|')
1203: if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1204: code = -1;
1205: return;
1206: }
1207: recvrequest(cmd, argv[2], argv[1], "w", 0);
1208: }
1209:
1210: /*
1211: * Get a directory listing
1212: * of multiple remote files.
1213: */
1214: void
1215: mls(argc, argv)
1216: int argc;
1217: char **argv;
1218: {
1219: sig_t oldintr;
1220: int ointer, i;
1221: char *cmd, mode[1], *dest;
1222:
1223: if (argc < 2 && !another(&argc, &argv, "remote-files"))
1224: goto usage;
1225: if (argc < 3 && !another(&argc, &argv, "local-file")) {
1226: usage:
1227: printf("usage: %s remote-files local-file\n", argv[0]);
1228: code = -1;
1229: return;
1230: }
1231: dest = argv[argc - 1];
1232: argv[argc - 1] = NULL;
1233: if (strcmp(dest, "-") && *dest != '|')
1234: if (!globulize(&dest) ||
1235: !confirm("output to local-file:", dest)) {
1236: code = -1;
1237: return;
1238: }
1239: cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1240: mname = argv[0];
1241: mflag = 1;
1242: oldintr = signal(SIGINT, mabort);
1243: (void) setjmp(jabort);
1244: for (i = 1; mflag && i < argc-1; ++i) {
1245: *mode = (i == 1) ? 'w' : 'a';
1246: recvrequest(cmd, dest, argv[i], mode, 0);
1247: if (!mflag && fromatty) {
1248: ointer = interactive;
1249: interactive = 1;
1250: if (confirm("Continue with", argv[0])) {
1251: mflag ++;
1252: }
1253: interactive = ointer;
1254: }
1255: }
1256: (void) signal(SIGINT, oldintr);
1257: mflag = 0;
1258: }
1259:
1260: /*
1261: * Do a shell escape
1262: */
1263: /*ARGSUSED*/
1264: void
1265: shell(argc, argv)
1266: int argc;
1267: char **argv;
1268: {
1269: pid_t pid;
1270: sig_t old1, old2;
1271: char shellnam[40], *shell, *namep;
1272: union wait status;
1273:
1274: old1 = signal (SIGINT, SIG_IGN);
1275: old2 = signal (SIGQUIT, SIG_IGN);
1276: if ((pid = fork()) == 0) {
1277: for (pid = 3; pid < 20; pid++)
1278: (void) close(pid);
1279: (void) signal(SIGINT, SIG_DFL);
1280: (void) signal(SIGQUIT, SIG_DFL);
1281: shell = getenv("SHELL");
1282: if (shell == NULL)
1283: shell = _PATH_BSHELL;
1284: namep = strrchr(shell,'/');
1285: if (namep == NULL)
1286: namep = shell;
1287: (void) strcpy(shellnam,"-");
1288: (void) strcat(shellnam, ++namep);
1289: if (strcmp(namep, "sh") != 0)
1290: shellnam[0] = '+';
1291: if (debug) {
1292: printf ("%s\n", shell);
1293: (void) fflush (stdout);
1294: }
1295: if (argc > 1) {
1296: execl(shell,shellnam,"-c",altarg,(char *)0);
1297: }
1298: else {
1299: execl(shell,shellnam,(char *)0);
1300: }
1301: warn("%s", shell);
1302: code = -1;
1303: exit(1);
1304: }
1305: if (pid > 0)
1306: while (wait((int *)&status) != pid)
1307: ;
1308: (void) signal(SIGINT, old1);
1309: (void) signal(SIGQUIT, old2);
1310: if (pid == -1) {
1311: warn("%s", "Try again later");
1312: code = -1;
1313: }
1314: else {
1315: code = 0;
1316: }
1317: }
1318:
1319: /*
1320: * Send new user information (re-login)
1321: */
1322: void
1323: user(argc, argv)
1324: int argc;
1325: char **argv;
1326: {
1327: char acct[80];
1328: int n, aflag = 0;
1329:
1330: if (argc < 2)
1331: (void) another(&argc, &argv, "username");
1332: if (argc < 2 || argc > 4) {
1333: printf("usage: %s username [password] [account]\n", argv[0]);
1334: code = -1;
1335: return;
1336: }
1337: n = command("USER %s", argv[1]);
1338: if (n == CONTINUE) {
1339: if (argc < 3 )
1340: argv[2] = getpass("Password: "), argc++;
1341: n = command("PASS %s", argv[2]);
1342: }
1343: if (n == CONTINUE) {
1344: if (argc < 4) {
1345: printf("Account: "); (void) fflush(stdout);
1346: (void) fgets(acct, sizeof(acct) - 1, stdin);
1347: acct[strlen(acct) - 1] = '\0';
1348: argv[3] = acct; argc++;
1349: }
1350: n = command("ACCT %s", argv[3]);
1351: aflag++;
1352: }
1353: if (n != COMPLETE) {
1354: fprintf(stdout, "Login failed.\n");
1355: return;
1356: }
1357: if (!aflag && argc == 4) {
1358: (void) command("ACCT %s", argv[3]);
1359: }
1360: }
1361:
1362: /*
1363: * Print working directory.
1364: */
1365: /*VARARGS*/
1366: void
1367: pwd(argc, argv)
1368: int argc;
1369: char *argv[];
1370: {
1371: int oldverbose = verbose;
1372:
1373: /*
1374: * If we aren't verbose, this doesn't do anything!
1375: */
1376: verbose = 1;
1377: if (command("PWD") == ERROR && code == 500) {
1378: printf("PWD command not recognized, trying XPWD\n");
1379: (void) command("XPWD");
1380: }
1381: verbose = oldverbose;
1382: }
1383:
1384: /*
1385: * Make a directory.
1386: */
1387: void
1388: makedir(argc, argv)
1389: int argc;
1390: char *argv[];
1391: {
1392:
1393: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1394: printf("usage: %s directory-name\n", argv[0]);
1395: code = -1;
1396: return;
1397: }
1398: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1399: if (verbose)
1400: printf("MKD command not recognized, trying XMKD\n");
1401: (void) command("XMKD %s", argv[1]);
1402: }
1403: }
1404:
1405: /*
1406: * Remove a directory.
1407: */
1408: void
1409: removedir(argc, argv)
1410: int argc;
1411: char *argv[];
1412: {
1413:
1414: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1415: printf("usage: %s directory-name\n", argv[0]);
1416: code = -1;
1417: return;
1418: }
1419: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1420: if (verbose)
1421: printf("RMD command not recognized, trying XRMD\n");
1422: (void) command("XRMD %s", argv[1]);
1423: }
1424: }
1425:
1426: /*
1427: * Send a line, verbatim, to the remote machine.
1428: */
1429: void
1430: quote(argc, argv)
1431: int argc;
1432: char *argv[];
1433: {
1434:
1435: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1436: printf("usage: %s line-to-send\n", argv[0]);
1437: code = -1;
1438: return;
1439: }
1440: quote1("", argc, argv);
1441: }
1442:
1443: /*
1444: * Send a SITE command to the remote machine. The line
1445: * is sent verbatim to the remote machine, except that the
1446: * word "SITE" is added at the front.
1447: */
1448: void
1449: site(argc, argv)
1450: int argc;
1451: char *argv[];
1452: {
1453:
1454: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1455: printf("usage: %s line-to-send\n", argv[0]);
1456: code = -1;
1457: return;
1458: }
1459: quote1("SITE ", argc, argv);
1460: }
1461:
1462: /*
1463: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1464: * Send the result as a one-line command and get response.
1465: */
1466: void
1467: quote1(initial, argc, argv)
1468: char *initial;
1469: int argc;
1470: char **argv;
1471: {
1472: int i, len;
1473: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1474:
1475: (void) strcpy(buf, initial);
1476: if (argc > 1) {
1477: len = strlen(buf);
1478: len += strlen(strcpy(&buf[len], argv[1]));
1479: for (i = 2; i < argc; i++) {
1480: buf[len++] = ' ';
1481: len += strlen(strcpy(&buf[len], argv[i]));
1482: }
1483: }
1484: if (command(buf) == PRELIM) {
1485: while (getreply(0) == PRELIM)
1486: continue;
1487: }
1488: }
1489:
1490: void
1491: do_chmod(argc, argv)
1492: int argc;
1493: char *argv[];
1494: {
1495:
1496: if (argc < 2 && !another(&argc, &argv, "mode"))
1497: goto usage;
1498: if (argc < 3 && !another(&argc, &argv, "file-name")) {
1499: usage:
1500: printf("usage: %s mode file-name\n", argv[0]);
1501: code = -1;
1502: return;
1503: }
1504: (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
1505: }
1506:
1507: void
1508: do_umask(argc, argv)
1509: int argc;
1510: char *argv[];
1511: {
1512: int oldverbose = verbose;
1513:
1514: verbose = 1;
1515: (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1516: verbose = oldverbose;
1517: }
1518:
1519: void
1520: idle(argc, argv)
1521: int argc;
1522: char *argv[];
1523: {
1524: int oldverbose = verbose;
1525:
1526: verbose = 1;
1527: (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1528: verbose = oldverbose;
1529: }
1530:
1531: /*
1532: * Ask the other side for help.
1533: */
1534: void
1535: rmthelp(argc, argv)
1536: int argc;
1537: char *argv[];
1538: {
1539: int oldverbose = verbose;
1540:
1541: verbose = 1;
1542: (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1543: verbose = oldverbose;
1544: }
1545:
1546: /*
1547: * Terminate session and exit.
1548: */
1549: /*VARARGS*/
1550: void
1551: quit(argc, argv)
1552: int argc;
1553: char *argv[];
1554: {
1555:
1556: if (connected)
1557: disconnect(0, 0);
1558: pswitch(1);
1559: if (connected) {
1560: disconnect(0, 0);
1561: }
1562: exit(0);
1563: }
1564:
1565: /*
1566: * Terminate session, but don't exit.
1567: */
1568: void
1569: disconnect(argc, argv)
1570: int argc;
1571: char *argv[];
1572: {
1573:
1574: if (!connected)
1575: return;
1576: (void) command("QUIT");
1577: if (cout) {
1578: (void) fclose(cout);
1579: }
1580: cout = NULL;
1581: connected = 0;
1582: data = -1;
1583: if (!proxy) {
1584: macnum = 0;
1585: }
1586: }
1587:
1588: int
1589: confirm(cmd, file)
1590: char *cmd, *file;
1591: {
1592: char line[BUFSIZ];
1593:
1594: if (!interactive)
1595: return (1);
1596: printf("%s %s? ", cmd, file);
1597: (void) fflush(stdout);
1598: if (fgets(line, sizeof line, stdin) == NULL)
1599: return (0);
1600: return (*line != 'n' && *line != 'N');
1601: }
1602:
1603: void
1604: fatal(msg)
1605: char *msg;
1606: {
1607:
1608: errx(1, "%s", msg);
1609: }
1610:
1611: /*
1612: * Glob a local file name specification with
1613: * the expectation of a single return value.
1614: * Can't control multiple values being expanded
1615: * from the expression, we return only the first.
1616: */
1617: int
1618: globulize(cpp)
1619: char **cpp;
1620: {
1621: glob_t gl;
1622: int flags;
1623:
1624: if (!doglob)
1625: return (1);
1626:
1627: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1628: memset(&gl, 0, sizeof(gl));
1629: if (glob(*cpp, flags, NULL, &gl) ||
1630: gl.gl_pathc == 0) {
1631: warnx("%s: not found", *cpp);
1632: globfree(&gl);
1633: return (0);
1634: }
1635: *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1636: globfree(&gl);
1637: return (1);
1638: }
1639:
1640: void
1641: account(argc,argv)
1642: int argc;
1643: char **argv;
1644: {
1645: char acct[50], *ap;
1646:
1647: if (argc > 1) {
1648: ++argv;
1649: --argc;
1650: (void) strncpy(acct,*argv,49);
1651: acct[49] = '\0';
1652: while (argc > 1) {
1653: --argc;
1654: ++argv;
1655: (void) strncat(acct,*argv, 49-strlen(acct));
1656: }
1657: ap = acct;
1658: }
1659: else {
1660: ap = getpass("Account:");
1661: }
1662: (void) command("ACCT %s", ap);
1663: }
1664:
1665: jmp_buf abortprox;
1666:
1667: void
1668: proxabort()
1669: {
1670:
1671: if (!proxy) {
1672: pswitch(1);
1673: }
1674: if (connected) {
1675: proxflag = 1;
1676: }
1677: else {
1678: proxflag = 0;
1679: }
1680: pswitch(0);
1681: longjmp(abortprox,1);
1682: }
1683:
1684: void
1685: doproxy(argc, argv)
1686: int argc;
1687: char *argv[];
1688: {
1689: struct cmd *c;
1690: sig_t oldintr;
1691:
1692: if (argc < 2 && !another(&argc, &argv, "command")) {
1693: printf("usage: %s command\n", argv[0]);
1694: code = -1;
1695: return;
1696: }
1697: c = getcmd(argv[1]);
1698: if (c == (struct cmd *) -1) {
1699: printf("?Ambiguous command\n");
1700: (void) fflush(stdout);
1701: code = -1;
1702: return;
1703: }
1704: if (c == 0) {
1705: printf("?Invalid command\n");
1706: (void) fflush(stdout);
1707: code = -1;
1708: return;
1709: }
1710: if (!c->c_proxy) {
1711: printf("?Invalid proxy command\n");
1712: (void) fflush(stdout);
1713: code = -1;
1714: return;
1715: }
1716: if (setjmp(abortprox)) {
1717: code = -1;
1718: return;
1719: }
1720: oldintr = signal(SIGINT, proxabort);
1721: pswitch(1);
1722: if (c->c_conn && !connected) {
1723: printf("Not connected\n");
1724: (void) fflush(stdout);
1725: pswitch(0);
1726: (void) signal(SIGINT, oldintr);
1727: code = -1;
1728: return;
1729: }
1730: (*c->c_handler)(argc-1, argv+1);
1731: if (connected) {
1732: proxflag = 1;
1733: }
1734: else {
1735: proxflag = 0;
1736: }
1737: pswitch(0);
1738: (void) signal(SIGINT, oldintr);
1739: }
1740:
1741: void
1742: setcase(argc, argv)
1743: int argc;
1744: char *argv[];
1745: {
1746:
1747: mcase = !mcase;
1748: printf("Case mapping %s.\n", onoff(mcase));
1749: code = mcase;
1750: }
1751:
1752: void
1753: setcr(argc, argv)
1754: int argc;
1755: char *argv[];
1756: {
1757:
1758: crflag = !crflag;
1759: printf("Carriage Return stripping %s.\n", onoff(crflag));
1760: code = crflag;
1761: }
1762:
1763: void
1764: setntrans(argc,argv)
1765: int argc;
1766: char *argv[];
1767: {
1768: if (argc == 1) {
1769: ntflag = 0;
1770: printf("Ntrans off.\n");
1771: code = ntflag;
1772: return;
1773: }
1774: ntflag++;
1775: code = ntflag;
1776: (void) strncpy(ntin, argv[1], 16);
1777: ntin[16] = '\0';
1778: if (argc == 2) {
1779: ntout[0] = '\0';
1780: return;
1781: }
1782: (void) strncpy(ntout, argv[2], 16);
1783: ntout[16] = '\0';
1784: }
1785:
1786: char *
1787: dotrans(name)
1788: char *name;
1789: {
1790: static char new[MAXPATHLEN];
1791: char *cp1, *cp2 = new;
1792: int i, ostop, found;
1793:
1794: for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1795: continue;
1796: for (cp1 = name; *cp1; cp1++) {
1797: found = 0;
1798: for (i = 0; *(ntin + i) && i < 16; i++) {
1799: if (*cp1 == *(ntin + i)) {
1800: found++;
1801: if (i < ostop) {
1802: *cp2++ = *(ntout + i);
1803: }
1804: break;
1805: }
1806: }
1807: if (!found) {
1808: *cp2++ = *cp1;
1809: }
1810: }
1811: *cp2 = '\0';
1812: return (new);
1813: }
1814:
1815: void
1816: setnmap(argc, argv)
1817: int argc;
1818: char *argv[];
1819: {
1820: char *cp;
1821:
1822: if (argc == 1) {
1823: mapflag = 0;
1824: printf("Nmap off.\n");
1825: code = mapflag;
1826: return;
1827: }
1828: if (argc < 3 && !another(&argc, &argv, "mapout")) {
1829: printf("Usage: %s [mapin mapout]\n",argv[0]);
1830: code = -1;
1831: return;
1832: }
1833: mapflag = 1;
1834: code = 1;
1835: cp = strchr(altarg, ' ');
1836: if (proxy) {
1837: while(*++cp == ' ')
1838: continue;
1839: altarg = cp;
1840: cp = strchr(altarg, ' ');
1841: }
1842: *cp = '\0';
1843: (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1844: while (*++cp == ' ')
1845: continue;
1846: (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1847: }
1848:
1849: char *
1850: domap(name)
1851: char *name;
1852: {
1853: static char new[MAXPATHLEN];
1854: char *cp1 = name, *cp2 = mapin;
1855: char *tp[9], *te[9];
1856: int i, toks[9], toknum = 0, match = 1;
1857:
1858: for (i=0; i < 9; ++i) {
1859: toks[i] = 0;
1860: }
1861: while (match && *cp1 && *cp2) {
1862: switch (*cp2) {
1863: case '\\':
1864: if (*++cp2 != *cp1) {
1865: match = 0;
1866: }
1867: break;
1868: case '$':
1869: if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1870: if (*cp1 != *(++cp2+1)) {
1871: toks[toknum = *cp2 - '1']++;
1872: tp[toknum] = cp1;
1873: while (*++cp1 && *(cp2+1)
1874: != *cp1);
1875: te[toknum] = cp1;
1876: }
1877: cp2++;
1878: break;
1879: }
1880: /* FALLTHROUGH */
1881: default:
1882: if (*cp2 != *cp1) {
1883: match = 0;
1884: }
1885: break;
1886: }
1887: if (match && *cp1) {
1888: cp1++;
1889: }
1890: if (match && *cp2) {
1891: cp2++;
1892: }
1893: }
1894: if (!match && *cp1) /* last token mismatch */
1895: {
1896: toks[toknum] = 0;
1897: }
1898: cp1 = new;
1899: *cp1 = '\0';
1900: cp2 = mapout;
1901: while (*cp2) {
1902: match = 0;
1903: switch (*cp2) {
1904: case '\\':
1905: if (*(cp2 + 1)) {
1906: *cp1++ = *++cp2;
1907: }
1908: break;
1909: case '[':
1910: LOOP:
1911: if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1912: if (*++cp2 == '0') {
1913: char *cp3 = name;
1914:
1915: while (*cp3) {
1916: *cp1++ = *cp3++;
1917: }
1918: match = 1;
1919: }
1920: else if (toks[toknum = *cp2 - '1']) {
1921: char *cp3 = tp[toknum];
1922:
1923: while (cp3 != te[toknum]) {
1924: *cp1++ = *cp3++;
1925: }
1926: match = 1;
1927: }
1928: }
1929: else {
1930: while (*cp2 && *cp2 != ',' &&
1931: *cp2 != ']') {
1932: if (*cp2 == '\\') {
1933: cp2++;
1934: }
1935: else if (*cp2 == '$' &&
1936: isdigit(*(cp2+1))) {
1937: if (*++cp2 == '0') {
1938: char *cp3 = name;
1939:
1940: while (*cp3) {
1941: *cp1++ = *cp3++;
1942: }
1943: }
1944: else if (toks[toknum =
1945: *cp2 - '1']) {
1946: char *cp3=tp[toknum];
1947:
1948: while (cp3 !=
1949: te[toknum]) {
1950: *cp1++ = *cp3++;
1951: }
1952: }
1953: }
1954: else if (*cp2) {
1955: *cp1++ = *cp2++;
1956: }
1957: }
1958: if (!*cp2) {
1959: printf("nmap: unbalanced brackets\n");
1960: return (name);
1961: }
1962: match = 1;
1963: cp2--;
1964: }
1965: if (match) {
1966: while (*++cp2 && *cp2 != ']') {
1967: if (*cp2 == '\\' && *(cp2 + 1)) {
1968: cp2++;
1969: }
1970: }
1971: if (!*cp2) {
1972: printf("nmap: unbalanced brackets\n");
1973: return (name);
1974: }
1975: break;
1976: }
1977: switch (*++cp2) {
1978: case ',':
1979: goto LOOP;
1980: case ']':
1981: break;
1982: default:
1983: cp2--;
1984: goto LOOP;
1985: }
1986: break;
1987: case '$':
1988: if (isdigit(*(cp2 + 1))) {
1989: if (*++cp2 == '0') {
1990: char *cp3 = name;
1991:
1992: while (*cp3) {
1993: *cp1++ = *cp3++;
1994: }
1995: }
1996: else if (toks[toknum = *cp2 - '1']) {
1997: char *cp3 = tp[toknum];
1998:
1999: while (cp3 != te[toknum]) {
2000: *cp1++ = *cp3++;
2001: }
2002: }
2003: break;
2004: }
2005: /* intentional drop through */
2006: default:
2007: *cp1++ = *cp2;
2008: break;
2009: }
2010: cp2++;
2011: }
2012: *cp1 = '\0';
2013: if (!*new) {
2014: return (name);
2015: }
2016: return (new);
2017: }
2018:
2019: void
2020: setpassive(argc, argv)
2021: int argc;
2022: char *argv[];
2023: {
2024:
2025: passivemode = !passivemode;
2026: printf("Passive mode %s.\n", onoff(passivemode));
2027: code = passivemode;
2028: }
2029:
2030: void
2031: setsunique(argc, argv)
2032: int argc;
2033: char *argv[];
2034: {
2035:
2036: sunique = !sunique;
2037: printf("Store unique %s.\n", onoff(sunique));
2038: code = sunique;
2039: }
2040:
2041: void
2042: setrunique(argc, argv)
2043: int argc;
2044: char *argv[];
2045: {
2046:
2047: runique = !runique;
2048: printf("Receive unique %s.\n", onoff(runique));
2049: code = runique;
2050: }
2051:
2052: /* change directory to perent directory */
2053: void
2054: cdup(argc, argv)
2055: int argc;
2056: char *argv[];
2057: {
2058:
2059: if (command("CDUP") == ERROR && code == 500) {
2060: if (verbose)
2061: printf("CDUP command not recognized, trying XCUP\n");
2062: (void) command("XCUP");
2063: }
2064: }
2065:
2066: /* restart transfer at specific point */
2067: void
2068: restart(argc, argv)
2069: int argc;
2070: char *argv[];
2071: {
2072:
2073: if (argc != 2)
2074: printf("restart: offset not specified\n");
2075: else {
2076: restart_point = atol(argv[1]);
2077: printf("restarting at %qd. %s\n", restart_point,
2078: "execute get, put or append to initiate transfer");
2079: }
2080: }
2081:
2082: /* show remote system type */
2083: void
2084: syst(argc, argv)
2085: int argc;
2086: char *argv[];
2087: {
2088:
2089: (void) command("SYST");
2090: }
2091:
2092: void
2093: macdef(argc, argv)
2094: int argc;
2095: char *argv[];
2096: {
2097: char *tmp;
2098: int c;
2099:
2100: if (macnum == 16) {
2101: printf("Limit of 16 macros have already been defined\n");
2102: code = -1;
2103: return;
2104: }
2105: if (argc < 2 && !another(&argc, &argv, "macro name")) {
2106: printf("Usage: %s macro_name\n",argv[0]);
2107: code = -1;
2108: return;
2109: }
2110: if (interactive) {
2111: printf("Enter macro line by line, terminating it with a null line\n");
2112: }
2113: (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2114: if (macnum == 0) {
2115: macros[macnum].mac_start = macbuf;
2116: }
2117: else {
2118: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2119: }
2120: tmp = macros[macnum].mac_start;
2121: while (tmp != macbuf+4096) {
2122: if ((c = getchar()) == EOF) {
2123: printf("macdef:end of file encountered\n");
2124: code = -1;
2125: return;
2126: }
2127: if ((*tmp = c) == '\n') {
2128: if (tmp == macros[macnum].mac_start) {
2129: macros[macnum++].mac_end = tmp;
2130: code = 0;
2131: return;
2132: }
2133: if (*(tmp-1) == '\0') {
2134: macros[macnum++].mac_end = tmp - 1;
2135: code = 0;
2136: return;
2137: }
2138: *tmp = '\0';
2139: }
2140: tmp++;
2141: }
2142: while (1) {
2143: while ((c = getchar()) != '\n' && c != EOF)
2144: /* LOOP */;
2145: if (c == EOF || getchar() == '\n') {
2146: printf("Macro not defined - 4k buffer exceeded\n");
2147: code = -1;
2148: return;
2149: }
2150: }
2151: }
2152:
2153: /*
2154: * get size of file on remote machine
2155: */
2156: void
2157: sizecmd(argc, argv)
2158: int argc;
2159: char *argv[];
2160: {
2161:
2162: if (argc < 2 && !another(&argc, &argv, "filename")) {
2163: printf("usage: %s filename\n", argv[0]);
2164: code = -1;
2165: return;
2166: }
2167: (void) command("SIZE %s", argv[1]);
2168: }
2169:
2170: /*
2171: * get last modification time of file on remote machine
2172: */
2173: void
2174: modtime(argc, argv)
2175: int argc;
2176: char *argv[];
2177: {
2178: int overbose;
2179:
2180: if (argc < 2 && !another(&argc, &argv, "filename")) {
2181: printf("usage: %s filename\n", argv[0]);
2182: code = -1;
2183: return;
2184: }
2185: overbose = verbose;
2186: if (debug == 0)
2187: verbose = -1;
2188: if (command("MDTM %s", argv[1]) == COMPLETE) {
2189: int yy, mo, day, hour, min, sec;
2190: sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2191: &day, &hour, &min, &sec);
2192: /* might want to print this in local time */
2193: printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2194: mo, day, yy, hour, min, sec);
2195: } else
2196: printf("%s\n", reply_string);
2197: verbose = overbose;
2198: }
2199:
2200: /*
2201: * show status on reomte machine
2202: */
2203: void
2204: rmtstatus(argc, argv)
2205: int argc;
2206: char *argv[];
2207: {
2208:
2209: (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2210: }
2211:
2212: /*
2213: * get file if modtime is more recent than current file
2214: */
2215: void
2216: newer(argc, argv)
2217: int argc;
2218: char *argv[];
2219: {
2220:
2221: if (getit(argc, argv, -1, "w"))
2222: printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2223: argv[2], argv[1]);
2224: }