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