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