Annotation of src/usr.bin/ftp/cmds.c, Revision 1.10
1.10 ! deraadt 1: /* $OpenBSD: cmds.c,v 1.9 1996/12/24 21:22:10 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.10 ! deraadt 41: static char rcsid[] = "$OpenBSD: cmds.c,v 1.9 1996/12/24 21:22:10 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.10 ! deraadt 1078: mcd(argc, argv)
1.1 deraadt 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;
1.10 ! deraadt 1086: return (-1);
1.1 deraadt 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.10 ! deraadt 1099: }
! 1100:
! 1101: void
! 1102: cd(argc, argv)
! 1103: int argc;
! 1104: char *argv[];
! 1105: {
! 1106: mcd(argc, argv);
1.1 deraadt 1107: }
1108:
1109: /*
1110: * Set current working directory
1111: * on local machine.
1112: */
1113: void
1114: lcd(argc, argv)
1115: int argc;
1116: char *argv[];
1117: {
1118: char buf[MAXPATHLEN];
1119:
1120: if (argc < 2)
1121: argc++, argv[1] = home;
1122: if (argc != 2) {
1123: printf("usage: %s local-directory\n", argv[0]);
1124: code = -1;
1125: return;
1126: }
1127: if (!globulize(&argv[1])) {
1128: code = -1;
1129: return;
1130: }
1131: if (chdir(argv[1]) < 0) {
1132: warn("local: %s", argv[1]);
1133: code = -1;
1134: return;
1135: }
1136: if (getwd(buf) != NULL)
1137: printf("Local directory now %s\n", buf);
1138: else
1139: warnx("getwd: %s", buf);
1140: code = 0;
1141: }
1142:
1143: /*
1144: * Delete a single file.
1145: */
1146: void
1147: delete(argc, argv)
1148: int argc;
1149: char *argv[];
1150: {
1151:
1152: if (argc < 2 && !another(&argc, &argv, "remote-file")) {
1153: printf("usage: %s remote-file\n", argv[0]);
1154: code = -1;
1155: return;
1156: }
1157: (void) command("DELE %s", argv[1]);
1158: }
1159:
1160: /*
1161: * Delete multiple files.
1162: */
1163: void
1164: mdelete(argc, argv)
1165: int argc;
1166: char **argv;
1167: {
1168: sig_t oldintr;
1169: int ointer;
1170: char *cp;
1171:
1172: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1173: printf("usage: %s remote-files\n", argv[0]);
1174: code = -1;
1175: return;
1176: }
1177: mname = argv[0];
1178: mflag = 1;
1179: oldintr = signal(SIGINT, mabort);
1180: (void) setjmp(jabort);
1181: while ((cp = remglob(argv,0)) != NULL) {
1182: if (*cp == '\0') {
1183: mflag = 0;
1184: continue;
1185: }
1186: if (mflag && confirm(argv[0], cp)) {
1187: (void) command("DELE %s", cp);
1188: if (!mflag && fromatty) {
1189: ointer = interactive;
1190: interactive = 1;
1191: if (confirm("Continue with", "mdelete")) {
1192: mflag++;
1193: }
1194: interactive = ointer;
1195: }
1196: }
1197: }
1198: (void) signal(SIGINT, oldintr);
1199: mflag = 0;
1200: }
1201:
1202: /*
1203: * Rename a remote file.
1204: */
1205: void
1206: renamefile(argc, argv)
1207: int argc;
1208: char *argv[];
1209: {
1210:
1211: if (argc < 2 && !another(&argc, &argv, "from-name"))
1212: goto usage;
1213: if (argc < 3 && !another(&argc, &argv, "to-name")) {
1214: usage:
1215: printf("%s from-name to-name\n", argv[0]);
1216: code = -1;
1217: return;
1218: }
1219: if (command("RNFR %s", argv[1]) == CONTINUE)
1220: (void) command("RNTO %s", argv[2]);
1221: }
1222:
1223: /*
1224: * Get a directory listing
1225: * of remote files.
1226: */
1227: void
1228: ls(argc, argv)
1229: int argc;
1230: char *argv[];
1231: {
1232: char *cmd;
1233:
1234: if (argc < 2)
1235: argc++, argv[1] = NULL;
1236: if (argc < 3)
1237: argc++, argv[2] = "-";
1238: if (argc > 3) {
1239: printf("usage: %s remote-directory local-file\n", argv[0]);
1240: code = -1;
1241: return;
1242: }
1243: cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1244: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1245: code = -1;
1246: return;
1247: }
1248: if (strcmp(argv[2], "-") && *argv[2] != '|')
1249: if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1250: code = -1;
1251: return;
1252: }
1253: recvrequest(cmd, argv[2], argv[1], "w", 0);
1.3 downsj 1254:
1255: /* flush results in case commands are coming from a pipe */
1256: fflush(stdout);
1.1 deraadt 1257: }
1258:
1259: /*
1260: * Get a directory listing
1261: * of multiple remote files.
1262: */
1263: void
1264: mls(argc, argv)
1265: int argc;
1266: char **argv;
1267: {
1268: sig_t oldintr;
1269: int ointer, i;
1270: char *cmd, mode[1], *dest;
1271:
1272: if (argc < 2 && !another(&argc, &argv, "remote-files"))
1273: goto usage;
1274: if (argc < 3 && !another(&argc, &argv, "local-file")) {
1275: usage:
1276: printf("usage: %s remote-files local-file\n", argv[0]);
1277: code = -1;
1278: return;
1279: }
1280: dest = argv[argc - 1];
1281: argv[argc - 1] = NULL;
1282: if (strcmp(dest, "-") && *dest != '|')
1283: if (!globulize(&dest) ||
1284: !confirm("output to local-file:", dest)) {
1285: code = -1;
1286: return;
1287: }
1288: cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1289: mname = argv[0];
1290: mflag = 1;
1291: oldintr = signal(SIGINT, mabort);
1292: (void) setjmp(jabort);
1293: for (i = 1; mflag && i < argc-1; ++i) {
1294: *mode = (i == 1) ? 'w' : 'a';
1295: recvrequest(cmd, dest, argv[i], mode, 0);
1296: if (!mflag && fromatty) {
1297: ointer = interactive;
1298: interactive = 1;
1299: if (confirm("Continue with", argv[0])) {
1300: mflag ++;
1301: }
1302: interactive = ointer;
1303: }
1304: }
1305: (void) signal(SIGINT, oldintr);
1306: mflag = 0;
1307: }
1308:
1309: /*
1310: * Do a shell escape
1311: */
1312: /*ARGSUSED*/
1313: void
1314: shell(argc, argv)
1315: int argc;
1316: char **argv;
1317: {
1318: pid_t pid;
1319: sig_t old1, old2;
1320: char shellnam[40], *shell, *namep;
1321: union wait status;
1322:
1323: old1 = signal (SIGINT, SIG_IGN);
1324: old2 = signal (SIGQUIT, SIG_IGN);
1325: if ((pid = fork()) == 0) {
1326: for (pid = 3; pid < 20; pid++)
1327: (void) close(pid);
1328: (void) signal(SIGINT, SIG_DFL);
1329: (void) signal(SIGQUIT, SIG_DFL);
1330: shell = getenv("SHELL");
1331: if (shell == NULL)
1332: shell = _PATH_BSHELL;
1333: namep = strrchr(shell,'/');
1334: if (namep == NULL)
1335: namep = shell;
1336: (void) strcpy(shellnam,"-");
1337: (void) strcat(shellnam, ++namep);
1338: if (strcmp(namep, "sh") != 0)
1339: shellnam[0] = '+';
1340: if (debug) {
1341: printf ("%s\n", shell);
1342: (void) fflush (stdout);
1343: }
1344: if (argc > 1) {
1345: execl(shell,shellnam,"-c",altarg,(char *)0);
1346: }
1347: else {
1348: execl(shell,shellnam,(char *)0);
1349: }
1350: warn("%s", shell);
1351: code = -1;
1352: exit(1);
1353: }
1354: if (pid > 0)
1355: while (wait((int *)&status) != pid)
1356: ;
1357: (void) signal(SIGINT, old1);
1358: (void) signal(SIGQUIT, old2);
1359: if (pid == -1) {
1360: warn("%s", "Try again later");
1361: code = -1;
1362: }
1363: else {
1364: code = 0;
1365: }
1366: }
1367:
1368: /*
1369: * Send new user information (re-login)
1370: */
1371: void
1372: user(argc, argv)
1373: int argc;
1374: char **argv;
1375: {
1376: char acct[80];
1377: int n, aflag = 0;
1378:
1379: if (argc < 2)
1380: (void) another(&argc, &argv, "username");
1381: if (argc < 2 || argc > 4) {
1382: printf("usage: %s username [password] [account]\n", argv[0]);
1383: code = -1;
1384: return;
1385: }
1386: n = command("USER %s", argv[1]);
1387: if (n == CONTINUE) {
1388: if (argc < 3 )
1389: argv[2] = getpass("Password: "), argc++;
1390: n = command("PASS %s", argv[2]);
1391: }
1392: if (n == CONTINUE) {
1393: if (argc < 4) {
1394: printf("Account: "); (void) fflush(stdout);
1395: (void) fgets(acct, sizeof(acct) - 1, stdin);
1396: acct[strlen(acct) - 1] = '\0';
1397: argv[3] = acct; argc++;
1398: }
1399: n = command("ACCT %s", argv[3]);
1400: aflag++;
1401: }
1402: if (n != COMPLETE) {
1403: fprintf(stdout, "Login failed.\n");
1404: return;
1405: }
1406: if (!aflag && argc == 4) {
1407: (void) command("ACCT %s", argv[3]);
1408: }
1409: }
1410:
1411: /*
1412: * Print working directory.
1413: */
1414: /*VARARGS*/
1415: void
1416: pwd(argc, argv)
1417: int argc;
1418: char *argv[];
1419: {
1420: int oldverbose = verbose;
1421:
1422: /*
1423: * If we aren't verbose, this doesn't do anything!
1424: */
1425: verbose = 1;
1426: if (command("PWD") == ERROR && code == 500) {
1427: printf("PWD command not recognized, trying XPWD\n");
1428: (void) command("XPWD");
1429: }
1430: verbose = oldverbose;
1431: }
1432:
1433: /*
1434: * Make a directory.
1435: */
1436: void
1437: makedir(argc, argv)
1438: int argc;
1439: char *argv[];
1440: {
1441:
1442: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1443: printf("usage: %s directory-name\n", argv[0]);
1444: code = -1;
1445: return;
1446: }
1447: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1448: if (verbose)
1449: printf("MKD command not recognized, trying XMKD\n");
1450: (void) command("XMKD %s", argv[1]);
1451: }
1452: }
1453:
1454: /*
1455: * Remove a directory.
1456: */
1457: void
1458: removedir(argc, argv)
1459: int argc;
1460: char *argv[];
1461: {
1462:
1463: if (argc < 2 && !another(&argc, &argv, "directory-name")) {
1464: printf("usage: %s directory-name\n", argv[0]);
1465: code = -1;
1466: return;
1467: }
1468: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1469: if (verbose)
1470: printf("RMD command not recognized, trying XRMD\n");
1471: (void) command("XRMD %s", argv[1]);
1472: }
1473: }
1474:
1475: /*
1476: * Send a line, verbatim, to the remote machine.
1477: */
1478: void
1479: quote(argc, argv)
1480: int argc;
1481: char *argv[];
1482: {
1483:
1484: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1485: printf("usage: %s line-to-send\n", argv[0]);
1486: code = -1;
1487: return;
1488: }
1489: quote1("", argc, argv);
1490: }
1491:
1492: /*
1493: * Send a SITE command to the remote machine. The line
1494: * is sent verbatim to the remote machine, except that the
1495: * word "SITE" is added at the front.
1496: */
1497: void
1498: site(argc, argv)
1499: int argc;
1500: char *argv[];
1501: {
1502:
1503: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1504: printf("usage: %s line-to-send\n", argv[0]);
1505: code = -1;
1506: return;
1507: }
1508: quote1("SITE ", argc, argv);
1509: }
1510:
1511: /*
1512: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1513: * Send the result as a one-line command and get response.
1514: */
1515: void
1516: quote1(initial, argc, argv)
1517: char *initial;
1518: int argc;
1519: char **argv;
1520: {
1521: int i, len;
1522: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1523:
1524: (void) strcpy(buf, initial);
1525: if (argc > 1) {
1526: len = strlen(buf);
1527: len += strlen(strcpy(&buf[len], argv[1]));
1528: for (i = 2; i < argc; i++) {
1529: buf[len++] = ' ';
1530: len += strlen(strcpy(&buf[len], argv[i]));
1531: }
1532: }
1533: if (command(buf) == PRELIM) {
1534: while (getreply(0) == PRELIM)
1535: continue;
1536: }
1537: }
1538:
1539: void
1540: do_chmod(argc, argv)
1541: int argc;
1542: char *argv[];
1543: {
1544:
1545: if (argc < 2 && !another(&argc, &argv, "mode"))
1546: goto usage;
1547: if (argc < 3 && !another(&argc, &argv, "file-name")) {
1548: usage:
1549: printf("usage: %s mode file-name\n", argv[0]);
1550: code = -1;
1551: return;
1552: }
1553: (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
1554: }
1555:
1556: void
1557: do_umask(argc, argv)
1558: int argc;
1559: char *argv[];
1560: {
1561: int oldverbose = verbose;
1562:
1563: verbose = 1;
1564: (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1565: verbose = oldverbose;
1566: }
1567:
1568: void
1569: idle(argc, argv)
1570: int argc;
1571: char *argv[];
1572: {
1573: int oldverbose = verbose;
1574:
1575: verbose = 1;
1576: (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1577: verbose = oldverbose;
1578: }
1579:
1580: /*
1581: * Ask the other side for help.
1582: */
1583: void
1584: rmthelp(argc, argv)
1585: int argc;
1586: char *argv[];
1587: {
1588: int oldverbose = verbose;
1589:
1590: verbose = 1;
1591: (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1592: verbose = oldverbose;
1593: }
1594:
1595: /*
1596: * Terminate session and exit.
1597: */
1598: /*VARARGS*/
1599: void
1600: quit(argc, argv)
1601: int argc;
1602: char *argv[];
1603: {
1604:
1605: if (connected)
1606: disconnect(0, 0);
1607: pswitch(1);
1608: if (connected) {
1609: disconnect(0, 0);
1610: }
1611: exit(0);
1612: }
1613:
1614: /*
1615: * Terminate session, but don't exit.
1616: */
1617: void
1618: disconnect(argc, argv)
1619: int argc;
1620: char *argv[];
1621: {
1622:
1623: if (!connected)
1624: return;
1625: (void) command("QUIT");
1626: if (cout) {
1627: (void) fclose(cout);
1628: }
1629: cout = NULL;
1630: connected = 0;
1631: data = -1;
1632: if (!proxy) {
1633: macnum = 0;
1634: }
1635: }
1636:
1637: int
1638: confirm(cmd, file)
1639: char *cmd, *file;
1640: {
1641: char line[BUFSIZ];
1642:
1643: if (!interactive)
1644: return (1);
1645: printf("%s %s? ", cmd, file);
1646: (void) fflush(stdout);
1647: if (fgets(line, sizeof line, stdin) == NULL)
1648: return (0);
1649: return (*line != 'n' && *line != 'N');
1650: }
1651:
1652: void
1653: fatal(msg)
1654: char *msg;
1655: {
1656:
1657: errx(1, "%s", msg);
1658: }
1659:
1660: /*
1661: * Glob a local file name specification with
1662: * the expectation of a single return value.
1663: * Can't control multiple values being expanded
1664: * from the expression, we return only the first.
1665: */
1666: int
1667: globulize(cpp)
1668: char **cpp;
1669: {
1670: glob_t gl;
1671: int flags;
1672:
1673: if (!doglob)
1674: return (1);
1675:
1676: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1677: memset(&gl, 0, sizeof(gl));
1678: if (glob(*cpp, flags, NULL, &gl) ||
1679: gl.gl_pathc == 0) {
1680: warnx("%s: not found", *cpp);
1681: globfree(&gl);
1682: return (0);
1683: }
1684: *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */
1685: globfree(&gl);
1686: return (1);
1687: }
1688:
1689: void
1690: account(argc,argv)
1691: int argc;
1692: char **argv;
1693: {
1694: char acct[50], *ap;
1695:
1696: if (argc > 1) {
1697: ++argv;
1698: --argc;
1699: (void) strncpy(acct,*argv,49);
1700: acct[49] = '\0';
1701: while (argc > 1) {
1702: --argc;
1703: ++argv;
1704: (void) strncat(acct,*argv, 49-strlen(acct));
1705: }
1706: ap = acct;
1707: }
1708: else {
1709: ap = getpass("Account:");
1710: }
1711: (void) command("ACCT %s", ap);
1712: }
1713:
1714: jmp_buf abortprox;
1715:
1716: void
1717: proxabort()
1718: {
1719:
1720: if (!proxy) {
1721: pswitch(1);
1722: }
1723: if (connected) {
1724: proxflag = 1;
1725: }
1726: else {
1727: proxflag = 0;
1728: }
1729: pswitch(0);
1730: longjmp(abortprox,1);
1731: }
1732:
1733: void
1734: doproxy(argc, argv)
1735: int argc;
1736: char *argv[];
1737: {
1738: struct cmd *c;
1739: sig_t oldintr;
1740:
1741: if (argc < 2 && !another(&argc, &argv, "command")) {
1742: printf("usage: %s command\n", argv[0]);
1743: code = -1;
1744: return;
1745: }
1746: c = getcmd(argv[1]);
1747: if (c == (struct cmd *) -1) {
1748: printf("?Ambiguous command\n");
1749: (void) fflush(stdout);
1750: code = -1;
1751: return;
1752: }
1753: if (c == 0) {
1754: printf("?Invalid command\n");
1755: (void) fflush(stdout);
1756: code = -1;
1757: return;
1758: }
1759: if (!c->c_proxy) {
1760: printf("?Invalid proxy command\n");
1761: (void) fflush(stdout);
1762: code = -1;
1763: return;
1764: }
1765: if (setjmp(abortprox)) {
1766: code = -1;
1767: return;
1768: }
1769: oldintr = signal(SIGINT, proxabort);
1770: pswitch(1);
1771: if (c->c_conn && !connected) {
1772: printf("Not connected\n");
1773: (void) fflush(stdout);
1774: pswitch(0);
1775: (void) signal(SIGINT, oldintr);
1776: code = -1;
1777: return;
1778: }
1779: (*c->c_handler)(argc-1, argv+1);
1780: if (connected) {
1781: proxflag = 1;
1782: }
1783: else {
1784: proxflag = 0;
1785: }
1786: pswitch(0);
1787: (void) signal(SIGINT, oldintr);
1788: }
1789:
1790: void
1791: setcase(argc, argv)
1792: int argc;
1793: char *argv[];
1794: {
1795:
1796: mcase = !mcase;
1797: printf("Case mapping %s.\n", onoff(mcase));
1798: code = mcase;
1799: }
1800:
1801: void
1802: setcr(argc, argv)
1803: int argc;
1804: char *argv[];
1805: {
1806:
1807: crflag = !crflag;
1808: printf("Carriage Return stripping %s.\n", onoff(crflag));
1809: code = crflag;
1810: }
1811:
1812: void
1813: setntrans(argc,argv)
1814: int argc;
1815: char *argv[];
1816: {
1817: if (argc == 1) {
1818: ntflag = 0;
1819: printf("Ntrans off.\n");
1820: code = ntflag;
1821: return;
1822: }
1823: ntflag++;
1824: code = ntflag;
1825: (void) strncpy(ntin, argv[1], 16);
1826: ntin[16] = '\0';
1827: if (argc == 2) {
1828: ntout[0] = '\0';
1829: return;
1830: }
1831: (void) strncpy(ntout, argv[2], 16);
1832: ntout[16] = '\0';
1833: }
1834:
1835: char *
1836: dotrans(name)
1837: char *name;
1838: {
1839: static char new[MAXPATHLEN];
1840: char *cp1, *cp2 = new;
1841: int i, ostop, found;
1842:
1843: for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1844: continue;
1845: for (cp1 = name; *cp1; cp1++) {
1846: found = 0;
1847: for (i = 0; *(ntin + i) && i < 16; i++) {
1848: if (*cp1 == *(ntin + i)) {
1849: found++;
1850: if (i < ostop) {
1851: *cp2++ = *(ntout + i);
1852: }
1853: break;
1854: }
1855: }
1856: if (!found) {
1857: *cp2++ = *cp1;
1858: }
1859: }
1860: *cp2 = '\0';
1861: return (new);
1862: }
1863:
1864: void
1865: setnmap(argc, argv)
1866: int argc;
1867: char *argv[];
1868: {
1869: char *cp;
1870:
1871: if (argc == 1) {
1872: mapflag = 0;
1873: printf("Nmap off.\n");
1874: code = mapflag;
1875: return;
1876: }
1877: if (argc < 3 && !another(&argc, &argv, "mapout")) {
1878: printf("Usage: %s [mapin mapout]\n",argv[0]);
1879: code = -1;
1880: return;
1881: }
1882: mapflag = 1;
1883: code = 1;
1884: cp = strchr(altarg, ' ');
1885: if (proxy) {
1886: while(*++cp == ' ')
1887: continue;
1888: altarg = cp;
1889: cp = strchr(altarg, ' ');
1890: }
1891: *cp = '\0';
1892: (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1893: while (*++cp == ' ')
1894: continue;
1895: (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1896: }
1897:
1898: char *
1899: domap(name)
1900: char *name;
1901: {
1902: static char new[MAXPATHLEN];
1903: char *cp1 = name, *cp2 = mapin;
1904: char *tp[9], *te[9];
1905: int i, toks[9], toknum = 0, match = 1;
1906:
1907: for (i=0; i < 9; ++i) {
1908: toks[i] = 0;
1909: }
1910: while (match && *cp1 && *cp2) {
1911: switch (*cp2) {
1912: case '\\':
1913: if (*++cp2 != *cp1) {
1914: match = 0;
1915: }
1916: break;
1917: case '$':
1918: if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1919: if (*cp1 != *(++cp2+1)) {
1920: toks[toknum = *cp2 - '1']++;
1921: tp[toknum] = cp1;
1922: while (*++cp1 && *(cp2+1)
1923: != *cp1);
1924: te[toknum] = cp1;
1925: }
1926: cp2++;
1927: break;
1928: }
1929: /* FALLTHROUGH */
1930: default:
1931: if (*cp2 != *cp1) {
1932: match = 0;
1933: }
1934: break;
1935: }
1936: if (match && *cp1) {
1937: cp1++;
1938: }
1939: if (match && *cp2) {
1940: cp2++;
1941: }
1942: }
1943: if (!match && *cp1) /* last token mismatch */
1944: {
1945: toks[toknum] = 0;
1946: }
1947: cp1 = new;
1948: *cp1 = '\0';
1949: cp2 = mapout;
1950: while (*cp2) {
1951: match = 0;
1952: switch (*cp2) {
1953: case '\\':
1954: if (*(cp2 + 1)) {
1955: *cp1++ = *++cp2;
1956: }
1957: break;
1958: case '[':
1959: LOOP:
1960: if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1961: if (*++cp2 == '0') {
1962: char *cp3 = name;
1963:
1964: while (*cp3) {
1965: *cp1++ = *cp3++;
1966: }
1967: match = 1;
1968: }
1969: else if (toks[toknum = *cp2 - '1']) {
1970: char *cp3 = tp[toknum];
1971:
1972: while (cp3 != te[toknum]) {
1973: *cp1++ = *cp3++;
1974: }
1975: match = 1;
1976: }
1977: }
1978: else {
1979: while (*cp2 && *cp2 != ',' &&
1980: *cp2 != ']') {
1981: if (*cp2 == '\\') {
1982: cp2++;
1983: }
1984: else if (*cp2 == '$' &&
1985: isdigit(*(cp2+1))) {
1986: if (*++cp2 == '0') {
1987: char *cp3 = name;
1988:
1989: while (*cp3) {
1990: *cp1++ = *cp3++;
1991: }
1992: }
1993: else if (toks[toknum =
1994: *cp2 - '1']) {
1995: char *cp3=tp[toknum];
1996:
1997: while (cp3 !=
1998: te[toknum]) {
1999: *cp1++ = *cp3++;
2000: }
2001: }
2002: }
2003: else if (*cp2) {
2004: *cp1++ = *cp2++;
2005: }
2006: }
2007: if (!*cp2) {
2008: printf("nmap: unbalanced brackets\n");
2009: return (name);
2010: }
2011: match = 1;
2012: cp2--;
2013: }
2014: if (match) {
2015: while (*++cp2 && *cp2 != ']') {
2016: if (*cp2 == '\\' && *(cp2 + 1)) {
2017: cp2++;
2018: }
2019: }
2020: if (!*cp2) {
2021: printf("nmap: unbalanced brackets\n");
2022: return (name);
2023: }
2024: break;
2025: }
2026: switch (*++cp2) {
2027: case ',':
2028: goto LOOP;
2029: case ']':
2030: break;
2031: default:
2032: cp2--;
2033: goto LOOP;
2034: }
2035: break;
2036: case '$':
2037: if (isdigit(*(cp2 + 1))) {
2038: if (*++cp2 == '0') {
2039: char *cp3 = name;
2040:
2041: while (*cp3) {
2042: *cp1++ = *cp3++;
2043: }
2044: }
2045: else if (toks[toknum = *cp2 - '1']) {
2046: char *cp3 = tp[toknum];
2047:
2048: while (cp3 != te[toknum]) {
2049: *cp1++ = *cp3++;
2050: }
2051: }
2052: break;
2053: }
2054: /* intentional drop through */
2055: default:
2056: *cp1++ = *cp2;
2057: break;
2058: }
2059: cp2++;
2060: }
2061: *cp1 = '\0';
2062: if (!*new) {
2063: return (name);
2064: }
2065: return (new);
2066: }
2067:
2068: void
2069: setpassive(argc, argv)
2070: int argc;
2071: char *argv[];
2072: {
2073:
2074: passivemode = !passivemode;
2075: printf("Passive mode %s.\n", onoff(passivemode));
2076: code = passivemode;
2077: }
2078:
2079: void
2080: setsunique(argc, argv)
2081: int argc;
2082: char *argv[];
2083: {
2084:
2085: sunique = !sunique;
2086: printf("Store unique %s.\n", onoff(sunique));
2087: code = sunique;
2088: }
2089:
2090: void
2091: setrunique(argc, argv)
2092: int argc;
2093: char *argv[];
2094: {
2095:
2096: runique = !runique;
2097: printf("Receive unique %s.\n", onoff(runique));
2098: code = runique;
2099: }
2100:
2101: /* change directory to perent directory */
2102: void
2103: cdup(argc, argv)
2104: int argc;
2105: char *argv[];
2106: {
2107:
2108: if (command("CDUP") == ERROR && code == 500) {
2109: if (verbose)
2110: printf("CDUP command not recognized, trying XCUP\n");
2111: (void) command("XCUP");
2112: }
2113: }
2114:
2115: /* restart transfer at specific point */
2116: void
2117: restart(argc, argv)
2118: int argc;
2119: char *argv[];
2120: {
2121:
2122: if (argc != 2)
2123: printf("restart: offset not specified\n");
2124: else {
2125: restart_point = atol(argv[1]);
2126: printf("restarting at %qd. %s\n", restart_point,
2127: "execute get, put or append to initiate transfer");
2128: }
2129: }
2130:
2131: /* show remote system type */
2132: void
2133: syst(argc, argv)
2134: int argc;
2135: char *argv[];
2136: {
2137:
2138: (void) command("SYST");
2139: }
2140:
2141: void
2142: macdef(argc, argv)
2143: int argc;
2144: char *argv[];
2145: {
2146: char *tmp;
2147: int c;
2148:
2149: if (macnum == 16) {
2150: printf("Limit of 16 macros have already been defined\n");
2151: code = -1;
2152: return;
2153: }
2154: if (argc < 2 && !another(&argc, &argv, "macro name")) {
2155: printf("Usage: %s macro_name\n",argv[0]);
2156: code = -1;
2157: return;
2158: }
2159: if (interactive) {
2160: printf("Enter macro line by line, terminating it with a null line\n");
2161: }
2162: (void) strncpy(macros[macnum].mac_name, argv[1], 8);
2163: if (macnum == 0) {
2164: macros[macnum].mac_start = macbuf;
2165: }
2166: else {
2167: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2168: }
2169: tmp = macros[macnum].mac_start;
2170: while (tmp != macbuf+4096) {
2171: if ((c = getchar()) == EOF) {
2172: printf("macdef:end of file encountered\n");
2173: code = -1;
2174: return;
2175: }
2176: if ((*tmp = c) == '\n') {
2177: if (tmp == macros[macnum].mac_start) {
2178: macros[macnum++].mac_end = tmp;
2179: code = 0;
2180: return;
2181: }
2182: if (*(tmp-1) == '\0') {
2183: macros[macnum++].mac_end = tmp - 1;
2184: code = 0;
2185: return;
2186: }
2187: *tmp = '\0';
2188: }
2189: tmp++;
2190: }
2191: while (1) {
2192: while ((c = getchar()) != '\n' && c != EOF)
2193: /* LOOP */;
2194: if (c == EOF || getchar() == '\n') {
2195: printf("Macro not defined - 4k buffer exceeded\n");
2196: code = -1;
2197: return;
2198: }
2199: }
2200: }
2201:
2202: /*
2203: * get size of file on remote machine
2204: */
2205: void
2206: sizecmd(argc, argv)
2207: int argc;
2208: char *argv[];
2209: {
2210:
2211: if (argc < 2 && !another(&argc, &argv, "filename")) {
2212: printf("usage: %s filename\n", argv[0]);
2213: code = -1;
2214: return;
2215: }
2216: (void) command("SIZE %s", argv[1]);
2217: }
2218:
2219: /*
2220: * get last modification time of file on remote machine
2221: */
2222: void
2223: modtime(argc, argv)
2224: int argc;
2225: char *argv[];
2226: {
2227: int overbose;
2228:
2229: if (argc < 2 && !another(&argc, &argv, "filename")) {
2230: printf("usage: %s filename\n", argv[0]);
2231: code = -1;
2232: return;
2233: }
2234: overbose = verbose;
2235: if (debug == 0)
2236: verbose = -1;
2237: if (command("MDTM %s", argv[1]) == COMPLETE) {
2238: int yy, mo, day, hour, min, sec;
2239: sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2240: &day, &hour, &min, &sec);
2241: /* might want to print this in local time */
2242: printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2243: mo, day, yy, hour, min, sec);
2244: } else
2245: printf("%s\n", reply_string);
2246: verbose = overbose;
2247: }
2248:
2249: /*
2250: * show status on reomte machine
2251: */
2252: void
2253: rmtstatus(argc, argv)
2254: int argc;
2255: char *argv[];
2256: {
2257:
2258: (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2259: }
2260:
2261: /*
2262: * get file if modtime is more recent than current file
2263: */
2264: void
2265: newer(argc, argv)
2266: int argc;
2267: char *argv[];
2268: {
2269:
2270: if (getit(argc, argv, -1, "w"))
2271: printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2272: argv[2], argv[1]);
2273: }