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