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