Annotation of src/usr.bin/ftp/cmds.c, Revision 1.6
1.6 ! kstailey 1: /* $OpenBSD: cmds.c,v 1.5 1996/09/28 09:56:54 bitblt 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.6 ! kstailey 41: static char rcsid[] = "$OpenBSD: cmds.c,v 1.5 1996/09/28 09:56:54 bitblt 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.1 deraadt 812: (void) mktemp(temp);
1.5 bitblt 813: /* create a zero-byte version of the file so that
814: * people can't play symlink games.
815: */
816: fd = open (temp, O_CREAT | O_EXCL | O_WRONLY, 600);
817: if (fd < 0) {
818: printf ("temporary file %s already exists\n",temp);
819: close (fd);
820: return NULL;
821: }
822: close (fd);
1.1 deraadt 823: oldverbose = verbose, verbose = 0;
824: oldhash = hash, hash = 0;
825: if (doswitch) {
826: pswitch(!proxy);
827: }
828: for (mode = "w"; *++argv != NULL; mode = "a")
829: recvrequest ("NLST", temp, *argv, mode, 0);
830: if (doswitch) {
831: pswitch(!proxy);
832: }
833: verbose = oldverbose; hash = oldhash;
834: ftemp = fopen(temp, "r");
835: (void) unlink(temp);
836: if (ftemp == NULL) {
837: printf("can't find list of remote files, oops\n");
838: return (NULL);
839: }
840: }
841: if (fgets(buf, sizeof (buf), ftemp) == NULL) {
842: (void) fclose(ftemp), ftemp = NULL;
843: return (NULL);
844: }
845: if ((cp = strchr(buf, '\n')) != NULL)
846: *cp = '\0';
847: return (buf);
848: }
849:
850: char *
851: onoff(bool)
852: int bool;
853: {
854:
855: return (bool ? "on" : "off");
856: }
857:
858: /*
859: * Show status.
860: */
861: /*ARGSUSED*/
862: void
863: status(argc, argv)
864: int argc;
865: char *argv[];
866: {
867: int i;
868:
869: if (connected)
870: printf("Connected to %s.\n", hostname);
871: else
872: printf("Not connected.\n");
873: if (!proxy) {
874: pswitch(1);
875: if (connected) {
876: printf("Connected for proxy commands to %s.\n", hostname);
877: }
878: else {
879: printf("No proxy connection.\n");
880: }
881: pswitch(0);
882: }
883: printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
884: modename, typename, formname, structname);
885: printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
886: onoff(verbose), onoff(bell), onoff(interactive),
887: onoff(doglob));
888: printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
889: onoff(runique));
890: printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
891: if (ntflag) {
892: printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
893: }
894: else {
895: printf("Ntrans: off\n");
896: }
897: if (mapflag) {
898: printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
899: }
900: else {
901: printf("Nmap: off\n");
902: }
1.6 ! kstailey 903: printf("Hash mark printing: %s; Mark count: %d\n", onoff(hash), mark);
! 904: printf("Use of PORT cmds: %s\n", onoff(sendport));
1.1 deraadt 905: if (macnum > 0) {
906: printf("Macros:\n");
907: for (i=0; i<macnum; i++) {
908: printf("\t%s\n",macros[i].mac_name);
909: }
910: }
911: code = 0;
912: }
913:
914: /*
915: * Set beep on cmd completed mode.
916: */
917: /*VARARGS*/
918: void
919: setbell(argc, argv)
920: int argc;
921: char *argv[];
922: {
923:
924: bell = !bell;
925: printf("Bell mode %s.\n", onoff(bell));
926: code = bell;
927: }
928:
929: /*
930: * Turn on packet tracing.
931: */
932: /*VARARGS*/
933: void
934: settrace(argc, argv)
935: int argc;
936: char *argv[];
937: {
938:
939: trace = !trace;
940: printf("Packet tracing %s.\n", onoff(trace));
941: code = trace;
942: }
943:
944: /*
945: * Toggle hash mark printing during transfers.
946: */
947: /*VARARGS*/
948: void
1.6 ! kstailey 949: togglehash()
1.1 deraadt 950: {
951:
952: hash = !hash;
953: printf("Hash mark printing %s", onoff(hash));
954: code = hash;
955: if (hash)
1.6 ! kstailey 956: printf(" (%d bytes/hash mark)", mark);
1.1 deraadt 957: printf(".\n");
958: }
1.6 ! kstailey 959:
! 960: /*
! 961: * Set hash mark bytecount.
! 962: */
! 963: /*VARARGS*/
! 964: void
! 965: sethash(argc, argv)
! 966: int argc;
! 967: char *argv[];
! 968: {
! 969: if (argc == 1)
! 970: togglehash();
! 971: else if (argc != 2) {
! 972: printf("usage: %s [number of bytes].\n", argv[0]);
! 973: } else {
! 974: int nmark = atol(argv[1]);
! 975: if (nmark < 1) {
! 976: printf("A hash mark bytecount of %d %s",
! 977: nmark, "is rather pointless...\n");
! 978: } else {
! 979: mark = nmark;
! 980: printf("Hash mark set to %d bytes/hash mark\n", mark);
! 981: }
! 982: }
! 983: }
! 984:
1.1 deraadt 985:
986: /*
987: * Turn on printing of server echo's.
988: */
989: /*VARARGS*/
990: void
991: setverbose(argc, argv)
992: int argc;
993: char *argv[];
994: {
995:
996: verbose = !verbose;
997: printf("Verbose mode %s.\n", onoff(verbose));
998: code = verbose;
999: }
1000:
1001: /*
1002: * Toggle PORT cmd use before each data connection.
1003: */
1004: /*VARARGS*/
1005: void
1006: setport(argc, argv)
1007: int argc;
1008: char *argv[];
1009: {
1010:
1011: sendport = !sendport;
1012: printf("Use of PORT cmds %s.\n", onoff(sendport));
1013: code = sendport;
1014: }
1015:
1016: /*
1017: * Turn on interactive prompting
1018: * during mget, mput, and mdelete.
1019: */
1020: /*VARARGS*/
1021: void
1022: setprompt(argc, argv)
1023: int argc;
1024: char *argv[];
1025: {
1026:
1027: interactive = !interactive;
1028: printf("Interactive mode %s.\n", onoff(interactive));
1029: code = interactive;
1030: }
1031:
1032: /*
1033: * Toggle metacharacter interpretation
1034: * on local file names.
1035: */
1036: /*VARARGS*/
1037: void
1038: setglob(argc, argv)
1039: int argc;
1040: char *argv[];
1041: {
1042:
1043: doglob = !doglob;
1044: printf("Globbing %s.\n", onoff(doglob));
1045: code = doglob;
1046: }
1047:
1048: /*
1049: * Set debugging mode on/off and/or
1050: * set level of debugging.
1051: */
1052: /*VARARGS*/
1053: void
1054: setdebug(argc, argv)
1055: int argc;
1056: char *argv[];
1057: {
1058: int val;
1059:
1060: if (argc > 1) {
1061: val = atoi(argv[1]);
1062: if (val < 0) {
1063: printf("%s: bad debugging value.\n", argv[1]);
1064: code = -1;
1065: return;
1066: }
1067: } else
1068: val = !debug;
1069: debug = val;
1070: if (debug)
1071: options |= SO_DEBUG;
1072: else
1073: options &= ~SO_DEBUG;
1074: printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
1075: code = debug > 0;
1076: }
1077:
1078: /*
1079: * Set current working directory
1080: * on remote machine.
1081: */
1082: void
1083: cd(argc, argv)
1084: int argc;
1085: char *argv[];
1086: {
1087:
1088: if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
1089: printf("usage: %s remote-directory\n", argv[0]);
1090: code = -1;
1091: return;
1092: }
1093: if (command("CWD %s", argv[1]) == ERROR && code == 500) {
1094: if (verbose)
1095: printf("CWD command not recognized, trying XCWD\n");
1096: (void) command("XCWD %s", argv[1]);
1097: }
1098: }
1099:
1100: /*
1101: * Set current working directory
1102: * on local machine.
1103: */
1104: void
1105: lcd(argc, argv)
1106: int argc;
1107: char *argv[];
1108: {
1109: char buf[MAXPATHLEN];
1110:
1111: if (argc < 2)
1112: argc++, argv[1] = home;
1113: if (argc != 2) {
1114: printf("usage: %s local-directory\n", argv[0]);
1115: code = -1;
1116: return;
1117: }
1118: if (!globulize(&argv[1])) {
1119: code = -1;
1120: return;
1121: }
1122: if (chdir(argv[1]) < 0) {
1123: warn("local: %s", argv[1]);
1124: code = -1;
1125: return;
1126: }
1127: if (getwd(buf) != NULL)
1128: printf("Local directory now %s\n", buf);
1129: else
1130: warnx("getwd: %s", buf);
1131: code = 0;
1132: }
1133:
1134: /*
1135: * Delete a single file.
1136: */
1137: void
1138: delete(argc, argv)
1139: int argc;
1140: char *argv[];
1141: {
1142:
1143: if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1144: printf("usage: %s remote-file\n", argv[0]);
1145: code = -1;
1146: return;
1147: }
1148: (void) command("DELE %s", argv[1]);
1149: }
1150:
1151: /*
1152: * Delete multiple files.
1153: */
1154: void
1155: mdelete(argc, argv)
1156: int argc;
1157: char **argv;
1158: {
1159: sig_t oldintr;
1160: int ointer;
1161: char *cp;
1162:
1163: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1164: printf("usage: %s remote-files\n", argv[0]);
1165: code = -1;
1166: return;
1167: }
1168: mname = argv[0];
1169: mflag = 1;
1170: oldintr = signal(SIGINT, mabort);
1171: (void) setjmp(jabort);
1172: while ((cp = remglob(argv,0)) != NULL) {
1173: if (*cp == '\0') {
1174: mflag = 0;
1175: continue;
1176: }
1177: if (mflag && confirm(argv[0], cp)) {
1178: (void) command("DELE %s", cp);
1179: if (!mflag && fromatty) {
1180: ointer = interactive;
1181: interactive = 1;
1182: if (confirm("Continue with", "mdelete")) {
1183: mflag++;
1184: }
1185: interactive = ointer;
1186: }
1187: }
1188: }
1189: (void) signal(SIGINT, oldintr);
1190: mflag = 0;
1191: }
1192:
1193: /*
1194: * Rename a remote file.
1195: */
1196: void
1197: renamefile(argc, argv)
1198: int argc;
1199: char *argv[];
1200: {
1201:
1202: if (argc < 2 && !another(&argc, &argv, "from-name"))
1203: goto usage;
1204: if (argc < 3 && !another(&argc, &argv, "to-name")) {
1205: usage:
1206: printf("%s from-name to-name\n", argv[0]);
1207: code = -1;
1208: return;
1209: }
1210: if (command("RNFR %s", argv[1]) == CONTINUE)
1211: (void) command("RNTO %s", argv[2]);
1212: }
1213:
1214: /*
1215: * Get a directory listing
1216: * of remote files.
1217: */
1218: void
1219: ls(argc, argv)
1220: int argc;
1221: char *argv[];
1222: {
1223: char *cmd;
1224:
1225: if (argc < 2)
1226: argc++, argv[1] = NULL;
1227: if (argc < 3)
1228: argc++, argv[2] = "-";
1229: if (argc > 3) {
1230: printf("usage: %s remote-directory local-file\n", argv[0]);
1231: code = -1;
1232: return;
1233: }
1234: cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1235: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1236: code = -1;
1237: return;
1238: }
1239: if (strcmp(argv[2], "-") && *argv[2] != '|')
1240: if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1241: code = -1;
1242: return;
1243: }
1244: recvrequest(cmd, argv[2], argv[1], "w", 0);
1.3 downsj 1245:
1246: /* flush results in case commands are coming from a pipe */
1247: fflush(stdout);
1.1 deraadt 1248: }
1249:
1250: /*
1251: * Get a directory listing
1252: * of multiple remote files.
1253: */
1254: void
1255: mls(argc, argv)
1256: int argc;
1257: char **argv;
1258: {
1259: sig_t oldintr;
1260: int ointer, i;
1261: char *cmd, mode[1], *dest;
1262:
1263: if (argc < 2 && !another(&argc, &argv, "remote-files"))
1264: goto usage;
1265: if (argc < 3 && !another(&argc, &argv, "local-file")) {
1266: usage:
1267: printf("usage: %s remote-files local-file\n", argv[0]);
1268: code = -1;
1269: return;
1270: }
1271: dest = argv[argc - 1];
1272: argv[argc - 1] = NULL;
1273: if (strcmp(dest, "-") && *dest != '|')
1274: if (!globulize(&dest) ||
1275: !confirm("output to local-file:", dest)) {
1276: code = -1;
1277: return;
1278: }
1279: cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1280: mname = argv[0];
1281: mflag = 1;
1282: oldintr = signal(SIGINT, mabort);
1283: (void) setjmp(jabort);
1284: for (i = 1; mflag && i < argc-1; ++i) {
1285: *mode = (i == 1) ? 'w' : 'a';
1286: recvrequest(cmd, dest, argv[i], mode, 0);
1287: if (!mflag && fromatty) {
1288: ointer = interactive;
1289: interactive = 1;
1290: if (confirm("Continue with", argv[0])) {
1291: mflag ++;
1292: }
1293: interactive = ointer;
1294: }
1295: }
1296: (void) signal(SIGINT, oldintr);
1297: mflag = 0;
1298: }
1299:
1300: /*
1301: * Do a shell escape
1302: */
1303: /*ARGSUSED*/
1304: void
1305: shell(argc, argv)
1306: int argc;
1307: char **argv;
1308: {
1309: pid_t pid;
1310: sig_t old1, old2;
1311: char shellnam[40], *shell, *namep;
1312: union wait status;
1313:
1314: old1 = signal (SIGINT, SIG_IGN);
1315: old2 = signal (SIGQUIT, SIG_IGN);
1316: if ((pid = fork()) == 0) {
1317: for (pid = 3; pid < 20; pid++)
1318: (void) close(pid);
1319: (void) signal(SIGINT, SIG_DFL);
1320: (void) signal(SIGQUIT, SIG_DFL);
1321: shell = getenv("SHELL");
1322: if (shell == NULL)
1323: shell = _PATH_BSHELL;
1324: namep = strrchr(shell,'/');
1325: if (namep == NULL)
1326: namep = shell;
1327: (void) strcpy(shellnam,"-");
1328: (void) strcat(shellnam, ++namep);
1329: if (strcmp(namep, "sh") != 0)
1330: shellnam[0] = '+';
1331: if (debug) {
1332: printf ("%s\n", shell);
1333: (void) fflush (stdout);
1334: }
1335: if (argc > 1) {
1336: execl(shell,shellnam,"-c",altarg,(char *)0);
1337: }
1338: else {
1339: execl(shell,shellnam,(char *)0);
1340: }
1341: warn("%s", shell);
1342: code = -1;
1343: exit(1);
1344: }
1345: if (pid > 0)
1346: while (wait((int *)&status) != pid)
1347: ;
1348: (void) signal(SIGINT, old1);
1349: (void) signal(SIGQUIT, old2);
1350: if (pid == -1) {
1351: warn("%s", "Try again later");
1352: code = -1;
1353: }
1354: else {
1355: code = 0;
1356: }
1357: }
1358:
1359: /*
1360: * Send new user information (re-login)
1361: */
1362: void
1363: user(argc, argv)
1364: int argc;
1365: char **argv;
1366: {
1367: char acct[80];
1368: int n, aflag = 0;
1369:
1370: if (argc < 2)
1371: (void) another(&argc, &argv, "username");
1372: if (argc < 2 || argc > 4) {
1373: printf("usage: %s username [password] [account]\n", argv[0]);
1374: code = -1;
1375: return;
1376: }
1377: n = command("USER %s", argv[1]);
1378: if (n == CONTINUE) {
1379: if (argc < 3 )
1380: argv[2] = getpass("Password: "), argc++;
1381: n = command("PASS %s", argv[2]);
1382: }
1383: if (n == CONTINUE) {
1384: if (argc < 4) {
1385: printf("Account: "); (void) fflush(stdout);
1386: (void) fgets(acct, sizeof(acct) - 1, stdin);
1387: acct[strlen(acct) - 1] = '\0';
1388: argv[3] = acct; argc++;
1389: }
1390: n = command("ACCT %s", argv[3]);
1391: aflag++;
1392: }
1393: if (n != COMPLETE) {
1394: fprintf(stdout, "Login failed.\n");
1395: return;
1396: }
1397: if (!aflag && argc == 4) {
1398: (void) command("ACCT %s", argv[3]);
1399: }
1400: }
1401:
1402: /*
1403: * Print working directory.
1404: */
1405: /*VARARGS*/
1406: void
1407: pwd(argc, argv)
1408: int argc;
1409: char *argv[];
1410: {
1411: int oldverbose = verbose;
1412:
1413: /*
1414: * If we aren't verbose, this doesn't do anything!
1415: */
1416: verbose = 1;
1417: if (command("PWD") == ERROR && code == 500) {
1418: printf("PWD command not recognized, trying XPWD\n");
1419: (void) command("XPWD");
1420: }
1421: verbose = oldverbose;
1422: }
1423:
1424: /*
1425: * Make a directory.
1426: */
1427: void
1428: makedir(argc, argv)
1429: int argc;
1430: char *argv[];
1431: {
1432:
1433: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1434: printf("usage: %s directory-name\n", argv[0]);
1435: code = -1;
1436: return;
1437: }
1438: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1439: if (verbose)
1440: printf("MKD command not recognized, trying XMKD\n");
1441: (void) command("XMKD %s", argv[1]);
1442: }
1443: }
1444:
1445: /*
1446: * Remove a directory.
1447: */
1448: void
1449: removedir(argc, argv)
1450: int argc;
1451: char *argv[];
1452: {
1453:
1454: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1455: printf("usage: %s directory-name\n", argv[0]);
1456: code = -1;
1457: return;
1458: }
1459: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1460: if (verbose)
1461: printf("RMD command not recognized, trying XRMD\n");
1462: (void) command("XRMD %s", argv[1]);
1463: }
1464: }
1465:
1466: /*
1467: * Send a line, verbatim, to the remote machine.
1468: */
1469: void
1470: quote(argc, argv)
1471: int argc;
1472: char *argv[];
1473: {
1474:
1475: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1476: printf("usage: %s line-to-send\n", argv[0]);
1477: code = -1;
1478: return;
1479: }
1480: quote1("", argc, argv);
1481: }
1482:
1483: /*
1484: * Send a SITE command to the remote machine. The line
1485: * is sent verbatim to the remote machine, except that the
1486: * word "SITE" is added at the front.
1487: */
1488: void
1489: site(argc, argv)
1490: int argc;
1491: char *argv[];
1492: {
1493:
1494: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1495: printf("usage: %s line-to-send\n", argv[0]);
1496: code = -1;
1497: return;
1498: }
1499: quote1("SITE ", argc, argv);
1500: }
1501:
1502: /*
1503: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1504: * Send the result as a one-line command and get response.
1505: */
1506: void
1507: quote1(initial, argc, argv)
1508: char *initial;
1509: int argc;
1510: char **argv;
1511: {
1512: int i, len;
1513: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1514:
1515: (void) strcpy(buf, initial);
1516: if (argc > 1) {
1517: len = strlen(buf);
1518: len += strlen(strcpy(&buf[len], argv[1]));
1519: for (i = 2; i < argc; i++) {
1520: buf[len++] = ' ';
1521: len += strlen(strcpy(&buf[len], argv[i]));
1522: }
1523: }
1524: if (command(buf) == PRELIM) {
1525: while (getreply(0) == PRELIM)
1526: continue;
1527: }
1528: }
1529:
1530: void
1531: do_chmod(argc, argv)
1532: int argc;
1533: char *argv[];
1534: {
1535:
1536: if (argc < 2 && !another(&argc, &argv, "mode"))
1537: goto usage;
1538: if (argc < 3 && !another(&argc, &argv, "file-name")) {
1539: usage:
1540: printf("usage: %s mode file-name\n", argv[0]);
1541: code = -1;
1542: return;
1543: }
1544: (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
1545: }
1546:
1547: void
1548: do_umask(argc, argv)
1549: int argc;
1550: char *argv[];
1551: {
1552: int oldverbose = verbose;
1553:
1554: verbose = 1;
1555: (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1556: verbose = oldverbose;
1557: }
1558:
1559: void
1560: idle(argc, argv)
1561: int argc;
1562: char *argv[];
1563: {
1564: int oldverbose = verbose;
1565:
1566: verbose = 1;
1567: (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1568: verbose = oldverbose;
1569: }
1570:
1571: /*
1572: * Ask the other side for help.
1573: */
1574: void
1575: rmthelp(argc, argv)
1576: int argc;
1577: char *argv[];
1578: {
1579: int oldverbose = verbose;
1580:
1581: verbose = 1;
1582: (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1583: verbose = oldverbose;
1584: }
1585:
1586: /*
1587: * Terminate session and exit.
1588: */
1589: /*VARARGS*/
1590: void
1591: quit(argc, argv)
1592: int argc;
1593: char *argv[];
1594: {
1595:
1596: if (connected)
1597: disconnect(0, 0);
1598: pswitch(1);
1599: if (connected) {
1600: disconnect(0, 0);
1601: }
1602: exit(0);
1603: }
1604:
1605: /*
1606: * Terminate session, but don't exit.
1607: */
1608: void
1609: disconnect(argc, argv)
1610: int argc;
1611: char *argv[];
1612: {
1613:
1614: if (!connected)
1615: return;
1616: (void) command("QUIT");
1617: if (cout) {
1618: (void) fclose(cout);
1619: }
1620: cout = NULL;
1621: connected = 0;
1622: data = -1;
1623: if (!proxy) {
1624: macnum = 0;
1625: }
1626: }
1627:
1628: int
1629: confirm(cmd, file)
1630: char *cmd, *file;
1631: {
1632: char line[BUFSIZ];
1633:
1634: if (!interactive)
1635: return (1);
1636: printf("%s %s? ", cmd, file);
1637: (void) fflush(stdout);
1638: if (fgets(line, sizeof line, stdin) == NULL)
1639: return (0);
1640: return (*line != 'n' && *line != 'N');
1641: }
1642:
1643: void
1644: fatal(msg)
1645: char *msg;
1646: {
1647:
1648: errx(1, "%s", msg);
1649: }
1650:
1651: /*
1652: * Glob a local file name specification with
1653: * the expectation of a single return value.
1654: * Can't control multiple values being expanded
1655: * from the expression, we return only the first.
1656: */
1657: int
1658: globulize(cpp)
1659: char **cpp;
1660: {
1661: glob_t gl;
1662: int flags;
1663:
1664: if (!doglob)
1665: return (1);
1666:
1667: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1668: memset(&gl, 0, sizeof(gl));
1669: if (glob(*cpp, flags, NULL, &gl) ||
1670: gl.gl_pathc == 0) {
1671: warnx("%s: not found", *cpp);
1672: globfree(&gl);
1673: return (0);
1674: }
1675: *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1676: globfree(&gl);
1677: return (1);
1678: }
1679:
1680: void
1681: account(argc,argv)
1682: int argc;
1683: char **argv;
1684: {
1685: char acct[50], *ap;
1686:
1687: if (argc > 1) {
1688: ++argv;
1689: --argc;
1690: (void) strncpy(acct,*argv,49);
1691: acct[49] = '\0';
1692: while (argc > 1) {
1693: --argc;
1694: ++argv;
1695: (void) strncat(acct,*argv, 49-strlen(acct));
1696: }
1697: ap = acct;
1698: }
1699: else {
1700: ap = getpass("Account:");
1701: }
1702: (void) command("ACCT %s", ap);
1703: }
1704:
1705: jmp_buf abortprox;
1706:
1707: void
1708: proxabort()
1709: {
1710:
1711: if (!proxy) {
1712: pswitch(1);
1713: }
1714: if (connected) {
1715: proxflag = 1;
1716: }
1717: else {
1718: proxflag = 0;
1719: }
1720: pswitch(0);
1721: longjmp(abortprox,1);
1722: }
1723:
1724: void
1725: doproxy(argc, argv)
1726: int argc;
1727: char *argv[];
1728: {
1729: struct cmd *c;
1730: sig_t oldintr;
1731:
1732: if (argc < 2 && !another(&argc, &argv, "command")) {
1733: printf("usage: %s command\n", argv[0]);
1734: code = -1;
1735: return;
1736: }
1737: c = getcmd(argv[1]);
1738: if (c == (struct cmd *) -1) {
1739: printf("?Ambiguous command\n");
1740: (void) fflush(stdout);
1741: code = -1;
1742: return;
1743: }
1744: if (c == 0) {
1745: printf("?Invalid command\n");
1746: (void) fflush(stdout);
1747: code = -1;
1748: return;
1749: }
1750: if (!c->c_proxy) {
1751: printf("?Invalid proxy command\n");
1752: (void) fflush(stdout);
1753: code = -1;
1754: return;
1755: }
1756: if (setjmp(abortprox)) {
1757: code = -1;
1758: return;
1759: }
1760: oldintr = signal(SIGINT, proxabort);
1761: pswitch(1);
1762: if (c->c_conn && !connected) {
1763: printf("Not connected\n");
1764: (void) fflush(stdout);
1765: pswitch(0);
1766: (void) signal(SIGINT, oldintr);
1767: code = -1;
1768: return;
1769: }
1770: (*c->c_handler)(argc-1, argv+1);
1771: if (connected) {
1772: proxflag = 1;
1773: }
1774: else {
1775: proxflag = 0;
1776: }
1777: pswitch(0);
1778: (void) signal(SIGINT, oldintr);
1779: }
1780:
1781: void
1782: setcase(argc, argv)
1783: int argc;
1784: char *argv[];
1785: {
1786:
1787: mcase = !mcase;
1788: printf("Case mapping %s.\n", onoff(mcase));
1789: code = mcase;
1790: }
1791:
1792: void
1793: setcr(argc, argv)
1794: int argc;
1795: char *argv[];
1796: {
1797:
1798: crflag = !crflag;
1799: printf("Carriage Return stripping %s.\n", onoff(crflag));
1800: code = crflag;
1801: }
1802:
1803: void
1804: setntrans(argc,argv)
1805: int argc;
1806: char *argv[];
1807: {
1808: if (argc == 1) {
1809: ntflag = 0;
1810: printf("Ntrans off.\n");
1811: code = ntflag;
1812: return;
1813: }
1814: ntflag++;
1815: code = ntflag;
1816: (void) strncpy(ntin, argv[1], 16);
1817: ntin[16] = '\0';
1818: if (argc == 2) {
1819: ntout[0] = '\0';
1820: return;
1821: }
1822: (void) strncpy(ntout, argv[2], 16);
1823: ntout[16] = '\0';
1824: }
1825:
1826: char *
1827: dotrans(name)
1828: char *name;
1829: {
1830: static char new[MAXPATHLEN];
1831: char *cp1, *cp2 = new;
1832: int i, ostop, found;
1833:
1834: for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1835: continue;
1836: for (cp1 = name; *cp1; cp1++) {
1837: found = 0;
1838: for (i = 0; *(ntin + i) && i < 16; i++) {
1839: if (*cp1 == *(ntin + i)) {
1840: found++;
1841: if (i < ostop) {
1842: *cp2++ = *(ntout + i);
1843: }
1844: break;
1845: }
1846: }
1847: if (!found) {
1848: *cp2++ = *cp1;
1849: }
1850: }
1851: *cp2 = '\0';
1852: return (new);
1853: }
1854:
1855: void
1856: setnmap(argc, argv)
1857: int argc;
1858: char *argv[];
1859: {
1860: char *cp;
1861:
1862: if (argc == 1) {
1863: mapflag = 0;
1864: printf("Nmap off.\n");
1865: code = mapflag;
1866: return;
1867: }
1868: if (argc < 3 && !another(&argc, &argv, "mapout")) {
1869: printf("Usage: %s [mapin mapout]\n",argv[0]);
1870: code = -1;
1871: return;
1872: }
1873: mapflag = 1;
1874: code = 1;
1875: cp = strchr(altarg, ' ');
1876: if (proxy) {
1877: while(*++cp == ' ')
1878: continue;
1879: altarg = cp;
1880: cp = strchr(altarg, ' ');
1881: }
1882: *cp = '\0';
1883: (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1884: while (*++cp == ' ')
1885: continue;
1886: (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1887: }
1888:
1889: char *
1890: domap(name)
1891: char *name;
1892: {
1893: static char new[MAXPATHLEN];
1894: char *cp1 = name, *cp2 = mapin;
1895: char *tp[9], *te[9];
1896: int i, toks[9], toknum = 0, match = 1;
1897:
1898: for (i=0; i < 9; ++i) {
1899: toks[i] = 0;
1900: }
1901: while (match && *cp1 && *cp2) {
1902: switch (*cp2) {
1903: case '\\':
1904: if (*++cp2 != *cp1) {
1905: match = 0;
1906: }
1907: break;
1908: case '$':
1909: if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1910: if (*cp1 != *(++cp2+1)) {
1911: toks[toknum = *cp2 - '1']++;
1912: tp[toknum] = cp1;
1913: while (*++cp1 && *(cp2+1)
1914: != *cp1);
1915: te[toknum] = cp1;
1916: }
1917: cp2++;
1918: break;
1919: }
1920: /* FALLTHROUGH */
1921: default:
1922: if (*cp2 != *cp1) {
1923: match = 0;
1924: }
1925: break;
1926: }
1927: if (match && *cp1) {
1928: cp1++;
1929: }
1930: if (match && *cp2) {
1931: cp2++;
1932: }
1933: }
1934: if (!match && *cp1) /* last token mismatch */
1935: {
1936: toks[toknum] = 0;
1937: }
1938: cp1 = new;
1939: *cp1 = '\0';
1940: cp2 = mapout;
1941: while (*cp2) {
1942: match = 0;
1943: switch (*cp2) {
1944: case '\\':
1945: if (*(cp2 + 1)) {
1946: *cp1++ = *++cp2;
1947: }
1948: break;
1949: case '[':
1950: LOOP:
1951: if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1952: if (*++cp2 == '0') {
1953: char *cp3 = name;
1954:
1955: while (*cp3) {
1956: *cp1++ = *cp3++;
1957: }
1958: match = 1;
1959: }
1960: else if (toks[toknum = *cp2 - '1']) {
1961: char *cp3 = tp[toknum];
1962:
1963: while (cp3 != te[toknum]) {
1964: *cp1++ = *cp3++;
1965: }
1966: match = 1;
1967: }
1968: }
1969: else {
1970: while (*cp2 && *cp2 != ',' &&
1971: *cp2 != ']') {
1972: if (*cp2 == '\\') {
1973: cp2++;
1974: }
1975: else if (*cp2 == '$' &&
1976: isdigit(*(cp2+1))) {
1977: if (*++cp2 == '0') {
1978: char *cp3 = name;
1979:
1980: while (*cp3) {
1981: *cp1++ = *cp3++;
1982: }
1983: }
1984: else if (toks[toknum =
1985: *cp2 - '1']) {
1986: char *cp3=tp[toknum];
1987:
1988: while (cp3 !=
1989: te[toknum]) {
1990: *cp1++ = *cp3++;
1991: }
1992: }
1993: }
1994: else if (*cp2) {
1995: *cp1++ = *cp2++;
1996: }
1997: }
1998: if (!*cp2) {
1999: printf("nmap: unbalanced brackets\n");
2000: return (name);
2001: }
2002: match = 1;
2003: cp2--;
2004: }
2005: if (match) {
2006: while (*++cp2 && *cp2 != ']') {
2007: if (*cp2 == '\\' && *(cp2 + 1)) {
2008: cp2++;
2009: }
2010: }
2011: if (!*cp2) {
2012: printf("nmap: unbalanced brackets\n");
2013: return (name);
2014: }
2015: break;
2016: }
2017: switch (*++cp2) {
2018: case ',':
2019: goto LOOP;
2020: case ']':
2021: break;
2022: default:
2023: cp2--;
2024: goto LOOP;
2025: }
2026: break;
2027: case '$':
2028: if (isdigit(*(cp2 + 1))) {
2029: if (*++cp2 == '0') {
2030: char *cp3 = name;
2031:
2032: while (*cp3) {
2033: *cp1++ = *cp3++;
2034: }
2035: }
2036: else if (toks[toknum = *cp2 - '1']) {
2037: char *cp3 = tp[toknum];
2038:
2039: while (cp3 != te[toknum]) {
2040: *cp1++ = *cp3++;
2041: }
2042: }
2043: break;
2044: }
2045: /* intentional drop through */
2046: default:
2047: *cp1++ = *cp2;
2048: break;
2049: }
2050: cp2++;
2051: }
2052: *cp1 = '\0';
2053: if (!*new) {
2054: return (name);
2055: }
2056: return (new);
2057: }
2058:
2059: void
2060: setpassive(argc, argv)
2061: int argc;
2062: char *argv[];
2063: {
2064:
2065: passivemode = !passivemode;
2066: printf("Passive mode %s.\n", onoff(passivemode));
2067: code = passivemode;
2068: }
2069:
2070: void
2071: setsunique(argc, argv)
2072: int argc;
2073: char *argv[];
2074: {
2075:
2076: sunique = !sunique;
2077: printf("Store unique %s.\n", onoff(sunique));
2078: code = sunique;
2079: }
2080:
2081: void
2082: setrunique(argc, argv)
2083: int argc;
2084: char *argv[];
2085: {
2086:
2087: runique = !runique;
2088: printf("Receive unique %s.\n", onoff(runique));
2089: code = runique;
2090: }
2091:
2092: /* change directory to perent directory */
2093: void
2094: cdup(argc, argv)
2095: int argc;
2096: char *argv[];
2097: {
2098:
2099: if (command("CDUP") == ERROR && code == 500) {
2100: if (verbose)
2101: printf("CDUP command not recognized, trying XCUP\n");
2102: (void) command("XCUP");
2103: }
2104: }
2105:
2106: /* restart transfer at specific point */
2107: void
2108: restart(argc, argv)
2109: int argc;
2110: char *argv[];
2111: {
2112:
2113: if (argc != 2)
2114: printf("restart: offset not specified\n");
2115: else {
2116: restart_point = atol(argv[1]);
2117: printf("restarting at %qd. %s\n", restart_point,
2118: "execute get, put or append to initiate transfer");
2119: }
2120: }
2121:
2122: /* show remote system type */
2123: void
2124: syst(argc, argv)
2125: int argc;
2126: char *argv[];
2127: {
2128:
2129: (void) command("SYST");
2130: }
2131:
2132: void
2133: macdef(argc, argv)
2134: int argc;
2135: char *argv[];
2136: {
2137: char *tmp;
2138: int c;
2139:
2140: if (macnum == 16) {
2141: printf("Limit of 16 macros have already been defined\n");
2142: code = -1;
2143: return;
2144: }
2145: if (argc < 2 && !another(&argc, &argv, "macro name")) {
2146: printf("Usage: %s macro_name\n",argv[0]);
2147: code = -1;
2148: return;
2149: }
2150: if (interactive) {
2151: printf("Enter macro line by line, terminating it with a null line\n");
2152: }
2153: (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2154: if (macnum == 0) {
2155: macros[macnum].mac_start = macbuf;
2156: }
2157: else {
2158: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2159: }
2160: tmp = macros[macnum].mac_start;
2161: while (tmp != macbuf+4096) {
2162: if ((c = getchar()) == EOF) {
2163: printf("macdef:end of file encountered\n");
2164: code = -1;
2165: return;
2166: }
2167: if ((*tmp = c) == '\n') {
2168: if (tmp == macros[macnum].mac_start) {
2169: macros[macnum++].mac_end = tmp;
2170: code = 0;
2171: return;
2172: }
2173: if (*(tmp-1) == '\0') {
2174: macros[macnum++].mac_end = tmp - 1;
2175: code = 0;
2176: return;
2177: }
2178: *tmp = '\0';
2179: }
2180: tmp++;
2181: }
2182: while (1) {
2183: while ((c = getchar()) != '\n' && c != EOF)
2184: /* LOOP */;
2185: if (c == EOF || getchar() == '\n') {
2186: printf("Macro not defined - 4k buffer exceeded\n");
2187: code = -1;
2188: return;
2189: }
2190: }
2191: }
2192:
2193: /*
2194: * get size of file on remote machine
2195: */
2196: void
2197: sizecmd(argc, argv)
2198: int argc;
2199: char *argv[];
2200: {
2201:
2202: if (argc < 2 && !another(&argc, &argv, "filename")) {
2203: printf("usage: %s filename\n", argv[0]);
2204: code = -1;
2205: return;
2206: }
2207: (void) command("SIZE %s", argv[1]);
2208: }
2209:
2210: /*
2211: * get last modification time of file on remote machine
2212: */
2213: void
2214: modtime(argc, argv)
2215: int argc;
2216: char *argv[];
2217: {
2218: int overbose;
2219:
2220: if (argc < 2 && !another(&argc, &argv, "filename")) {
2221: printf("usage: %s filename\n", argv[0]);
2222: code = -1;
2223: return;
2224: }
2225: overbose = verbose;
2226: if (debug == 0)
2227: verbose = -1;
2228: if (command("MDTM %s", argv[1]) == COMPLETE) {
2229: int yy, mo, day, hour, min, sec;
2230: sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2231: &day, &hour, &min, &sec);
2232: /* might want to print this in local time */
2233: printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2234: mo, day, yy, hour, min, sec);
2235: } else
2236: printf("%s\n", reply_string);
2237: verbose = overbose;
2238: }
2239:
2240: /*
2241: * show status on reomte machine
2242: */
2243: void
2244: rmtstatus(argc, argv)
2245: int argc;
2246: char *argv[];
2247: {
2248:
2249: (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2250: }
2251:
2252: /*
2253: * get file if modtime is more recent than current file
2254: */
2255: void
2256: newer(argc, argv)
2257: int argc;
2258: char *argv[];
2259: {
2260:
2261: if (getit(argc, argv, -1, "w"))
2262: printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2263: argv[2], argv[1]);
2264: }