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