Annotation of src/usr.bin/ftp/cmds.c, Revision 1.16
1.16 ! millert 1: /* $OpenBSD: cmds.c,v 1.15 1997/02/05 04:55:12 millert Exp $ */
! 2: /* $NetBSD: cmds.c,v 1.19 1997/03/13 06:23:11 lukem Exp $ */
1.1 deraadt 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.16 ! millert 41: static char rcsid[] = "$OpenBSD: cmds.c,v 1.15 1997/02/05 04:55:12 millert Exp $";
1.1 deraadt 42: #endif
43: #endif /* not lint */
44:
45: /*
46: * FTP User Program -- Command Routines.
47: */
1.13 millert 48: #include <sys/types.h>
49: #include <sys/socket.h>
50: #include <sys/stat.h>
1.1 deraadt 51: #include <sys/wait.h>
52: #include <arpa/ftp.h>
53:
54: #include <ctype.h>
55: #include <err.h>
56: #include <glob.h>
57: #include <netdb.h>
58: #include <stdio.h>
59: #include <stdlib.h>
60: #include <string.h>
61: #include <unistd.h>
62:
63: #include "ftp_var.h"
64: #include "pathnames.h"
65:
66: jmp_buf jabort;
67: char *mname;
68: char *home = "/";
69:
70: struct types {
71: char *t_name;
72: char *t_mode;
73: int t_type;
74: char *t_arg;
75: } types[] = {
76: { "ascii", "A", TYPE_A, 0 },
77: { "binary", "I", TYPE_I, 0 },
78: { "image", "I", TYPE_I, 0 },
79: { "ebcdic", "E", TYPE_E, 0 },
80: { "tenex", "L", TYPE_L, bytename },
81: { NULL }
82: };
83:
84: /*
85: * Set transfer type.
86: */
87: void
88: settype(argc, argv)
89: int argc;
90: char *argv[];
91: {
92: struct types *p;
93: int comret;
94:
95: if (argc > 2) {
96: char *sep;
97:
98: printf("usage: %s [", argv[0]);
99: sep = " ";
100: for (p = types; p->t_name; p++) {
101: printf("%s%s", sep, p->t_name);
102: sep = " | ";
103: }
1.14 millert 104: puts(" ]");
1.1 deraadt 105: code = -1;
106: return;
107: }
108: if (argc < 2) {
109: printf("Using %s mode to transfer files.\n", typename);
110: code = 0;
111: return;
112: }
113: for (p = types; p->t_name; p++)
114: if (strcmp(argv[1], p->t_name) == 0)
115: break;
116: if (p->t_name == 0) {
1.16 ! millert 117: printf("%s: unknown mode.\n", argv[1]);
1.1 deraadt 118: code = -1;
119: return;
120: }
121: if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
1.15 millert 122: comret = command("TYPE %s %s", p->t_mode, p->t_arg);
1.1 deraadt 123: else
124: comret = command("TYPE %s", p->t_mode);
125: if (comret == COMPLETE) {
1.14 millert 126: (void)strcpy(typename, p->t_name);
1.1 deraadt 127: curtype = type = p->t_type;
128: }
129: }
130:
131: /*
132: * Internal form of settype; changes current type in use with server
133: * without changing our notion of the type for data transfers.
134: * Used to change to and from ascii for listings.
135: */
136: void
137: changetype(newtype, show)
138: int newtype, show;
139: {
140: struct types *p;
141: int comret, oldverbose = verbose;
142:
143: if (newtype == 0)
144: newtype = TYPE_I;
145: if (newtype == curtype)
146: return;
147: if (debug == 0 && show == 0)
148: verbose = 0;
149: for (p = types; p->t_name; p++)
150: if (newtype == p->t_type)
151: break;
152: if (p->t_name == 0) {
1.16 ! millert 153: warnx("internal error: unknown type %d.", newtype);
1.1 deraadt 154: return;
155: }
156: if (newtype == TYPE_L && bytename[0] != '\0')
157: comret = command("TYPE %s %s", p->t_mode, bytename);
158: else
159: comret = command("TYPE %s", p->t_mode);
160: if (comret == COMPLETE)
161: curtype = newtype;
162: verbose = oldverbose;
163: }
164:
165: char *stype[] = {
166: "type",
167: "",
168: 0
169: };
170:
171: /*
172: * Set binary transfer type.
173: */
174: /*VARARGS*/
175: void
176: setbinary(argc, argv)
177: int argc;
1.13 millert 178: char *argv[];
1.1 deraadt 179: {
180:
181: stype[1] = "binary";
182: settype(2, stype);
183: }
184:
185: /*
186: * Set ascii transfer type.
187: */
188: /*VARARGS*/
189: void
190: setascii(argc, argv)
191: int argc;
192: char *argv[];
193: {
194:
195: stype[1] = "ascii";
196: settype(2, stype);
197: }
198:
199: /*
200: * Set tenex transfer type.
201: */
202: /*VARARGS*/
203: void
204: settenex(argc, argv)
205: int argc;
206: char *argv[];
207: {
208:
209: stype[1] = "tenex";
210: settype(2, stype);
211: }
212:
213: /*
214: * Set file transfer mode.
215: */
216: /*ARGSUSED*/
217: void
218: setftmode(argc, argv)
219: int argc;
220: char *argv[];
221: {
222:
223: printf("We only support %s mode, sorry.\n", modename);
224: code = -1;
225: }
226:
227: /*
228: * Set file transfer format.
229: */
230: /*ARGSUSED*/
231: void
232: setform(argc, argv)
233: int argc;
234: char *argv[];
235: {
236:
237: printf("We only support %s format, sorry.\n", formname);
238: code = -1;
239: }
240:
241: /*
242: * Set file transfer structure.
243: */
244: /*ARGSUSED*/
245: void
246: setstruct(argc, argv)
247: int argc;
248: char *argv[];
249: {
250:
251: printf("We only support %s structure, sorry.\n", structname);
252: code = -1;
253: }
254:
255: /*
256: * Send a single file.
257: */
258: void
259: put(argc, argv)
260: int argc;
261: char *argv[];
262: {
263: char *cmd;
264: int loc = 0;
265: char *oldargv1, *oldargv2;
266:
267: if (argc == 2) {
268: argc++;
269: argv[2] = argv[1];
270: loc++;
271: }
272: if (argc < 2 && !another(&argc, &argv, "local-file"))
273: goto usage;
1.13 millert 274: if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
1.1 deraadt 275: usage:
1.13 millert 276: printf("usage: %s local-file [ remote-file ]\n", argv[0]);
1.1 deraadt 277: code = -1;
278: return;
279: }
280: oldargv1 = argv[1];
281: oldargv2 = argv[2];
282: if (!globulize(&argv[1])) {
283: code = -1;
284: return;
285: }
286: /*
287: * If "globulize" modifies argv[1], and argv[2] is a copy of
288: * the old argv[1], make it a copy of the new argv[1].
289: */
290: if (argv[1] != oldargv1 && argv[2] == oldargv1) {
291: argv[2] = argv[1];
292: }
293: cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
294: if (loc && ntflag) {
295: argv[2] = dotrans(argv[2]);
296: }
297: if (loc && mapflag) {
298: argv[2] = domap(argv[2]);
299: }
300: sendrequest(cmd, argv[1], argv[2],
301: argv[1] != oldargv1 || argv[2] != oldargv2);
302: }
303:
304: /*
305: * Send multiple files.
306: */
307: void
308: mput(argc, argv)
309: int argc;
1.13 millert 310: char *argv[];
1.1 deraadt 311: {
312: int i;
313: sig_t oldintr;
314: int ointer;
315: char *tp;
316:
317: if (argc < 2 && !another(&argc, &argv, "local-files")) {
318: printf("usage: %s local-files\n", argv[0]);
319: code = -1;
320: return;
321: }
322: mname = argv[0];
323: mflag = 1;
324: oldintr = signal(SIGINT, mabort);
1.14 millert 325: (void)setjmp(jabort);
1.1 deraadt 326: if (proxy) {
327: char *cp, *tp2, tmpbuf[MAXPATHLEN];
328:
1.16 ! millert 329: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.13 millert 330: if (*cp == '\0') {
1.1 deraadt 331: mflag = 0;
332: continue;
333: }
334: if (mflag && confirm(argv[0], cp)) {
335: tp = cp;
336: if (mcase) {
337: while (*tp && !islower(*tp)) {
338: tp++;
339: }
340: if (!*tp) {
341: tp = cp;
342: tp2 = tmpbuf;
343: while ((*tp2 = *tp) != NULL) {
344: if (isupper(*tp2)) {
345: *tp2 = 'a' + *tp2 - 'A';
346: }
347: tp++;
348: tp2++;
349: }
350: }
351: tp = tmpbuf;
352: }
353: if (ntflag) {
354: tp = dotrans(tp);
355: }
356: if (mapflag) {
357: tp = domap(tp);
358: }
359: sendrequest((sunique) ? "STOU" : "STOR",
360: cp, tp, cp != tp || !interactive);
361: if (!mflag && fromatty) {
362: ointer = interactive;
363: interactive = 1;
1.13 millert 364: if (confirm("Continue with", "mput")) {
1.1 deraadt 365: mflag++;
366: }
367: interactive = ointer;
368: }
369: }
370: }
1.14 millert 371: (void)signal(SIGINT, oldintr);
1.1 deraadt 372: mflag = 0;
373: return;
374: }
375: for (i = 1; i < argc; i++) {
1.13 millert 376: char **cpp;
1.1 deraadt 377: glob_t gl;
378: int flags;
379:
380: if (!doglob) {
381: if (mflag && confirm(argv[0], argv[i])) {
382: tp = (ntflag) ? dotrans(argv[i]) : argv[i];
383: tp = (mapflag) ? domap(tp) : tp;
384: sendrequest((sunique) ? "STOU" : "STOR",
385: argv[i], tp, tp != argv[i] || !interactive);
386: if (!mflag && fromatty) {
387: ointer = interactive;
388: interactive = 1;
1.13 millert 389: if (confirm("Continue with", "mput")) {
1.1 deraadt 390: mflag++;
391: }
392: interactive = ointer;
393: }
394: }
395: continue;
396: }
397:
398: memset(&gl, 0, sizeof(gl));
399: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
400: if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
401: warnx("%s: not found", argv[i]);
402: globfree(&gl);
403: continue;
404: }
405: for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
406: if (mflag && confirm(argv[0], *cpp)) {
407: tp = (ntflag) ? dotrans(*cpp) : *cpp;
408: tp = (mapflag) ? domap(tp) : tp;
409: sendrequest((sunique) ? "STOU" : "STOR",
410: *cpp, tp, *cpp != tp || !interactive);
411: if (!mflag && fromatty) {
412: ointer = interactive;
413: interactive = 1;
1.13 millert 414: if (confirm("Continue with", "mput")) {
1.1 deraadt 415: mflag++;
416: }
417: interactive = ointer;
418: }
419: }
420: }
421: globfree(&gl);
422: }
1.14 millert 423: (void)signal(SIGINT, oldintr);
1.1 deraadt 424: mflag = 0;
425: }
426:
427: void
428: reget(argc, argv)
429: int argc;
430: char *argv[];
431: {
432:
1.14 millert 433: (void)getit(argc, argv, 1, "r+w");
1.1 deraadt 434: }
435:
436: void
437: get(argc, argv)
438: int argc;
439: char *argv[];
440: {
441:
1.14 millert 442: (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
1.1 deraadt 443: }
444:
445: /*
446: * Receive one file.
447: */
448: int
449: getit(argc, argv, restartit, mode)
450: int argc;
451: char *argv[];
452: int restartit;
1.13 millert 453: const char *mode;
1.1 deraadt 454: {
455: int loc = 0;
456: char *oldargv1, *oldargv2;
457:
458: if (argc == 2) {
459: argc++;
460: argv[2] = argv[1];
461: loc++;
462: }
463: if (argc < 2 && !another(&argc, &argv, "remote-file"))
464: goto usage;
1.13 millert 465: if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
1.1 deraadt 466: usage:
467: printf("usage: %s remote-file [ local-file ]\n", argv[0]);
468: code = -1;
469: return (0);
470: }
471: oldargv1 = argv[1];
472: oldargv2 = argv[2];
473: if (!globulize(&argv[2])) {
474: code = -1;
475: return (0);
476: }
477: if (loc && mcase) {
478: char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
479:
480: while (*tp && !islower(*tp)) {
481: tp++;
482: }
483: if (!*tp) {
484: tp = argv[2];
485: tp2 = tmpbuf;
486: while ((*tp2 = *tp) != NULL) {
487: if (isupper(*tp2)) {
488: *tp2 = 'a' + *tp2 - 'A';
489: }
490: tp++;
491: tp2++;
492: }
493: argv[2] = tmpbuf;
494: }
495: }
496: if (loc && ntflag)
497: argv[2] = dotrans(argv[2]);
498: if (loc && mapflag)
499: argv[2] = domap(argv[2]);
500: if (restartit) {
501: struct stat stbuf;
502: int ret;
503:
504: ret = stat(argv[2], &stbuf);
505: if (restartit == 1) {
506: if (ret < 0) {
507: warn("local: %s", argv[2]);
508: return (0);
509: }
510: restart_point = stbuf.st_size;
511: } else {
512: if (ret == 0) {
1.13 millert 513: time_t mtime;
1.1 deraadt 514:
1.13 millert 515: mtime = remotemodtime(argv[1], 0);
516: if (mtime == -1)
1.1 deraadt 517: return (0);
1.13 millert 518: if (stbuf.st_mtime >= mtime)
519: return (1);
1.1 deraadt 520: }
521: }
522: }
523:
524: recvrequest("RETR", argv[2], argv[1], mode,
525: argv[1] != oldargv1 || argv[2] != oldargv2);
526: restart_point = 0;
527: return (0);
528: }
529:
530: /* ARGSUSED */
531: void
532: mabort(signo)
533: int signo;
534: {
1.13 millert 535: int ointer, oconf;
1.1 deraadt 536:
1.13 millert 537: alarmtimer(0);
1.14 millert 538: putchar('\n');
539: (void)fflush(stdout);
1.1 deraadt 540: if (mflag && fromatty) {
541: ointer = interactive;
1.13 millert 542: oconf = confirmrest;
1.1 deraadt 543: interactive = 1;
1.13 millert 544: confirmrest = 0;
1.1 deraadt 545: if (confirm("Continue with", mname)) {
546: interactive = ointer;
1.13 millert 547: confirmrest = oconf;
548: longjmp(jabort, 0);
1.1 deraadt 549: }
550: interactive = ointer;
1.13 millert 551: confirmrest = oconf;
1.1 deraadt 552: }
553: mflag = 0;
1.13 millert 554: longjmp(jabort, 0);
1.1 deraadt 555: }
556:
557: /*
558: * Get multiple files.
559: */
560: void
561: mget(argc, argv)
562: int argc;
1.13 millert 563: char *argv[];
1.1 deraadt 564: {
565: sig_t oldintr;
566: int ch, ointer;
567: char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
568:
569: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
570: printf("usage: %s remote-files\n", argv[0]);
571: code = -1;
572: return;
573: }
574: mname = argv[0];
575: mflag = 1;
576: oldintr = signal(SIGINT, mabort);
1.14 millert 577: (void)setjmp(jabort);
1.16 ! millert 578: while ((cp = remglob(argv, proxy, NULL)) != NULL) {
1.1 deraadt 579: if (*cp == '\0') {
580: mflag = 0;
581: continue;
582: }
583: if (mflag && confirm(argv[0], cp)) {
584: tp = cp;
585: if (mcase) {
1.13 millert 586: for (tp2 = tmpbuf; (ch = *tp++) != NULL; )
1.1 deraadt 587: *tp2++ = isupper(ch) ? tolower(ch) : ch;
588: *tp2 = '\0';
589: tp = tmpbuf;
590: }
591: if (ntflag) {
592: tp = dotrans(tp);
593: }
594: if (mapflag) {
595: tp = domap(tp);
596: }
597: recvrequest("RETR", tp, cp, "w",
598: tp != cp || !interactive);
599: if (!mflag && fromatty) {
600: ointer = interactive;
601: interactive = 1;
1.13 millert 602: if (confirm("Continue with", "mget")) {
1.1 deraadt 603: mflag++;
604: }
605: interactive = ointer;
606: }
607: }
608: }
1.14 millert 609: (void)signal(SIGINT, oldintr);
1.1 deraadt 610: mflag = 0;
611: }
612:
613: char *
614: onoff(bool)
615: int bool;
616: {
617:
618: return (bool ? "on" : "off");
619: }
620:
621: /*
622: * Show status.
623: */
624: /*ARGSUSED*/
625: void
626: status(argc, argv)
627: int argc;
628: char *argv[];
629: {
630: int i;
631:
632: if (connected)
633: printf("Connected to %s.\n", hostname);
634: else
1.14 millert 635: puts("Not connected.");
1.1 deraadt 636: if (!proxy) {
637: pswitch(1);
638: if (connected) {
1.13 millert 639: printf("Connected for proxy commands to %s.\n",
640: hostname);
1.1 deraadt 641: }
642: else {
1.14 millert 643: puts("No proxy connection.");
1.1 deraadt 644: }
645: pswitch(0);
646: }
1.13 millert 647: printf("Passive mode: %s.\n", onoff(passivemode));
1.16 ! millert 648: printf("Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
1.1 deraadt 649: modename, typename, formname, structname);
1.16 ! millert 650: printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
1.1 deraadt 651: onoff(verbose), onoff(bell), onoff(interactive),
652: onoff(doglob));
1.16 ! millert 653: printf("Store unique: %s; Receive unique: %s.\n", onoff(sunique),
1.1 deraadt 654: onoff(runique));
1.16 ! millert 655: printf("Preserve modification times: %s.\n", onoff(preserve));
! 656: printf("Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
1.1 deraadt 657: if (ntflag) {
1.13 millert 658: printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
1.1 deraadt 659: }
660: else {
1.16 ! millert 661: puts("Ntrans: off.");
1.1 deraadt 662: }
663: if (mapflag) {
664: printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
665: }
666: else {
1.16 ! millert 667: puts("Nmap: off.");
1.1 deraadt 668: }
1.16 ! millert 669: printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
1.13 millert 670: onoff(hash), mark, onoff(progress));
1.16 ! millert 671: printf("Use of PORT cmds: %s.\n", onoff(sendport));
1.13 millert 672: #ifndef SMALLFTP
1.16 ! millert 673: printf("Command line editing: %s.\n", onoff(editing));
1.13 millert 674: #endif /* !SMALLFTP */
1.1 deraadt 675: if (macnum > 0) {
1.14 millert 676: puts("Macros:");
1.1 deraadt 677: for (i=0; i<macnum; i++) {
1.13 millert 678: printf("\t%s\n", macros[i].mac_name);
1.1 deraadt 679: }
680: }
681: code = 0;
682: }
683:
684: /*
1.13 millert 685: * Toggle a variable
686: */
687: int
688: togglevar(argc, argv, var, mesg)
689: int argc;
690: char *argv[];
691: int *var;
692: const char *mesg;
693: {
694: if (argc < 2) {
695: *var = !*var;
696: } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
697: *var = 1;
698: } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
699: *var = 0;
700: } else {
701: printf("usage: %s [ on | off ]\n", argv[0]);
1.16 ! millert 702: return (-1);
1.13 millert 703: }
1.15 millert 704: if (mesg)
705: printf("%s %s.\n", mesg, onoff(*var));
1.14 millert 706: return (*var);
1.13 millert 707: }
708:
709: /*
1.1 deraadt 710: * Set beep on cmd completed mode.
711: */
712: /*VARARGS*/
713: void
714: setbell(argc, argv)
715: int argc;
716: char *argv[];
717: {
718:
1.13 millert 719: code = togglevar(argc, argv, &bell, "Bell mode");
1.1 deraadt 720: }
721:
1.13 millert 722: #ifndef SMALLFTP
1.1 deraadt 723: /*
1.13 millert 724: * Set command line editing
1.1 deraadt 725: */
726: /*VARARGS*/
727: void
1.13 millert 728: setedit(argc, argv)
1.1 deraadt 729: int argc;
730: char *argv[];
731: {
732:
1.13 millert 733: code = togglevar(argc, argv, &editing, "Editing mode");
1.1 deraadt 734: }
1.13 millert 735: #endif /* !SMALLFTP */
1.1 deraadt 736:
737: /*
1.13 millert 738: * Turn on packet tracing.
1.1 deraadt 739: */
740: /*VARARGS*/
741: void
1.13 millert 742: settrace(argc, argv)
743: int argc;
744: char *argv[];
1.1 deraadt 745: {
746:
1.13 millert 747: code = togglevar(argc, argv, &trace, "Packet tracing");
1.1 deraadt 748: }
1.6 kstailey 749:
750: /*
1.13 millert 751: * Toggle hash mark printing during transfers, or set hash mark bytecount.
1.6 kstailey 752: */
753: /*VARARGS*/
754: void
755: sethash(argc, argv)
756: int argc;
757: char *argv[];
758: {
759: if (argc == 1)
1.13 millert 760: hash = !hash;
1.6 kstailey 761: else if (argc != 2) {
1.13 millert 762: printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
763: code = -1;
764: return;
765: } else if (strcasecmp(argv[1], "on") == 0)
766: hash = 1;
767: else if (strcasecmp(argv[1], "off") == 0)
768: hash = 0;
769: else {
1.6 kstailey 770: int nmark = atol(argv[1]);
771: if (nmark < 1) {
1.16 ! millert 772: printf("%s: bad bytecount value.\n", argv[1]);
1.13 millert 773: code = -1;
774: return;
1.6 kstailey 775: }
1.13 millert 776: mark = nmark;
777: hash = 1;
1.6 kstailey 778: }
1.13 millert 779: printf("Hash mark printing %s", onoff(hash));
780: if (hash)
781: printf(" (%d bytes/hash mark)", mark);
1.14 millert 782: puts(".");
1.13 millert 783: code = hash;
1.6 kstailey 784: }
785:
1.1 deraadt 786: /*
787: * Turn on printing of server echo's.
788: */
789: /*VARARGS*/
790: void
791: setverbose(argc, argv)
792: int argc;
793: char *argv[];
794: {
795:
1.13 millert 796: code = togglevar(argc, argv, &verbose, "Verbose mode");
1.1 deraadt 797: }
798:
799: /*
800: * Toggle PORT cmd use before each data connection.
801: */
802: /*VARARGS*/
803: void
804: setport(argc, argv)
805: int argc;
806: char *argv[];
807: {
808:
1.13 millert 809: code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
810: }
811:
812: /*
813: * Toggle transfer progress bar.
814: */
815: /*VARARGS*/
816: void
817: setprogress(argc, argv)
818: int argc;
819: char *argv[];
820: {
821:
822: code = togglevar(argc, argv, &progress, "Progress bar");
1.1 deraadt 823: }
824:
825: /*
826: * Turn on interactive prompting
827: * during mget, mput, and mdelete.
828: */
829: /*VARARGS*/
830: void
831: setprompt(argc, argv)
832: int argc;
833: char *argv[];
834: {
835:
1.13 millert 836: code = togglevar(argc, argv, &interactive, "Interactive mode");
1.1 deraadt 837: }
838:
839: /*
840: * Toggle metacharacter interpretation
841: * on local file names.
842: */
843: /*VARARGS*/
844: void
845: setglob(argc, argv)
846: int argc;
847: char *argv[];
848: {
1.13 millert 849:
850: code = togglevar(argc, argv, &doglob, "Globbing");
851: }
852:
853: /*
854: * Toggle preserving modification times on retreived files.
855: */
856: /*VARARGS*/
857: void
858: setpreserve(argc, argv)
859: int argc;
860: char *argv[];
861: {
862:
863: code = togglevar(argc, argv, &preserve, "Preserve modification times");
1.1 deraadt 864: }
865:
866: /*
867: * Set debugging mode on/off and/or
868: * set level of debugging.
869: */
870: /*VARARGS*/
871: void
872: setdebug(argc, argv)
873: int argc;
874: char *argv[];
875: {
876: int val;
877:
1.13 millert 878: if (argc > 2) {
879: printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
880: code = -1;
881: return;
882: } else if (argc == 2) {
883: if (strcasecmp(argv[1], "on") == 0)
884: debug = 1;
885: else if (strcasecmp(argv[1], "off") == 0)
886: debug = 0;
887: else {
888: val = atoi(argv[1]);
889: if (val < 0) {
890: printf("%s: bad debugging value.\n", argv[1]);
891: code = -1;
892: return;
893: }
894: debug = val;
1.1 deraadt 895: }
896: } else
1.13 millert 897: debug = !debug;
1.1 deraadt 898: if (debug)
899: options |= SO_DEBUG;
900: else
901: options &= ~SO_DEBUG;
902: printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
903: code = debug > 0;
904: }
905:
906: /*
907: * Set current working directory
908: * on remote machine.
909: */
1.13 millert 910: void
911: cd(argc, argv)
1.1 deraadt 912: int argc;
913: char *argv[];
914: {
1.13 millert 915: int r;
1.1 deraadt 916:
1.13 millert 917: if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
918: argc > 2) {
1.1 deraadt 919: printf("usage: %s remote-directory\n", argv[0]);
920: code = -1;
1.13 millert 921: return;
1.1 deraadt 922: }
1.13 millert 923: r = command("CWD %s", argv[1]);
924: if (r == ERROR && code == 500) {
925: if (verbose)
1.16 ! millert 926: puts("CWD command not recognized, trying XCWD.");
1.13 millert 927: r = command("XCWD %s", argv[1]);
1.1 deraadt 928: }
1.13 millert 929: if (r == COMPLETE)
930: dirchange = 1;
1.1 deraadt 931: }
932:
933: /*
934: * Set current working directory
935: * on local machine.
936: */
937: void
938: lcd(argc, argv)
939: int argc;
940: char *argv[];
941: {
942: char buf[MAXPATHLEN];
943:
944: if (argc < 2)
945: argc++, argv[1] = home;
946: if (argc != 2) {
947: printf("usage: %s local-directory\n", argv[0]);
948: code = -1;
949: return;
950: }
951: if (!globulize(&argv[1])) {
952: code = -1;
953: return;
954: }
955: if (chdir(argv[1]) < 0) {
956: warn("local: %s", argv[1]);
957: code = -1;
958: return;
959: }
1.11 millert 960: if (getcwd(buf, sizeof(buf)) != NULL)
1.1 deraadt 961: printf("Local directory now %s\n", buf);
962: else
1.13 millert 963: warn("getcwd: %s", argv[1]);
1.1 deraadt 964: code = 0;
965: }
966:
967: /*
968: * Delete a single file.
969: */
970: void
971: delete(argc, argv)
972: int argc;
973: char *argv[];
974: {
975:
1.13 millert 976: if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1.1 deraadt 977: printf("usage: %s remote-file\n", argv[0]);
978: code = -1;
979: return;
980: }
1.14 millert 981: (void)command("DELE %s", argv[1]);
1.1 deraadt 982: }
983:
984: /*
985: * Delete multiple files.
986: */
987: void
988: mdelete(argc, argv)
989: int argc;
1.13 millert 990: char *argv[];
1.1 deraadt 991: {
992: sig_t oldintr;
993: int ointer;
994: char *cp;
995:
996: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
997: printf("usage: %s remote-files\n", argv[0]);
998: code = -1;
999: return;
1000: }
1001: mname = argv[0];
1002: mflag = 1;
1003: oldintr = signal(SIGINT, mabort);
1.14 millert 1004: (void)setjmp(jabort);
1.16 ! millert 1005: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.1 deraadt 1006: if (*cp == '\0') {
1007: mflag = 0;
1008: continue;
1009: }
1010: if (mflag && confirm(argv[0], cp)) {
1.14 millert 1011: (void)command("DELE %s", cp);
1.1 deraadt 1012: if (!mflag && fromatty) {
1013: ointer = interactive;
1014: interactive = 1;
1015: if (confirm("Continue with", "mdelete")) {
1016: mflag++;
1017: }
1018: interactive = ointer;
1019: }
1020: }
1021: }
1.14 millert 1022: (void)signal(SIGINT, oldintr);
1.1 deraadt 1023: mflag = 0;
1024: }
1025:
1026: /*
1027: * Rename a remote file.
1028: */
1029: void
1030: renamefile(argc, argv)
1031: int argc;
1032: char *argv[];
1033: {
1034:
1035: if (argc < 2 && !another(&argc, &argv, "from-name"))
1036: goto usage;
1.13 millert 1037: if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1.1 deraadt 1038: usage:
1.16 ! millert 1039: printf("usage: %s from-name to-name\n", argv[0]);
1.1 deraadt 1040: code = -1;
1041: return;
1042: }
1043: if (command("RNFR %s", argv[1]) == CONTINUE)
1.14 millert 1044: (void)command("RNTO %s", argv[2]);
1.1 deraadt 1045: }
1046:
1047: /*
1048: * Get a directory listing
1049: * of remote files.
1050: */
1051: void
1052: ls(argc, argv)
1053: int argc;
1054: char *argv[];
1055: {
1.13 millert 1056: const char *cmd;
1.1 deraadt 1057:
1058: if (argc < 2)
1059: argc++, argv[1] = NULL;
1060: if (argc < 3)
1061: argc++, argv[2] = "-";
1062: if (argc > 3) {
1063: printf("usage: %s remote-directory local-file\n", argv[0]);
1064: code = -1;
1065: return;
1066: }
1.13 millert 1067: cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
1.1 deraadt 1068: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1069: code = -1;
1070: return;
1071: }
1072: if (strcmp(argv[2], "-") && *argv[2] != '|')
1.13 millert 1073: if (!globulize(&argv[2]) || !confirm("output to local-file:",
1074: argv[2])) {
1.1 deraadt 1075: code = -1;
1076: return;
1077: }
1078: recvrequest(cmd, argv[2], argv[1], "w", 0);
1.3 downsj 1079:
1080: /* flush results in case commands are coming from a pipe */
1081: fflush(stdout);
1.1 deraadt 1082: }
1083:
1084: /*
1085: * Get a directory listing
1086: * of multiple remote files.
1087: */
1088: void
1089: mls(argc, argv)
1090: int argc;
1.13 millert 1091: char *argv[];
1.1 deraadt 1092: {
1093: sig_t oldintr;
1094: int ointer, i;
1.13 millert 1095: const char *cmd;
1096: char mode[1], *dest;
1.1 deraadt 1097:
1098: if (argc < 2 && !another(&argc, &argv, "remote-files"))
1099: goto usage;
1100: if (argc < 3 && !another(&argc, &argv, "local-file")) {
1101: usage:
1102: printf("usage: %s remote-files local-file\n", argv[0]);
1103: code = -1;
1104: return;
1105: }
1106: dest = argv[argc - 1];
1107: argv[argc - 1] = NULL;
1108: if (strcmp(dest, "-") && *dest != '|')
1109: if (!globulize(&dest) ||
1110: !confirm("output to local-file:", dest)) {
1111: code = -1;
1112: return;
1113: }
1.13 millert 1114: cmd = strcmp(argv[0], "mls") == 0 ? "NLST" : "LIST";
1.1 deraadt 1115: mname = argv[0];
1116: mflag = 1;
1117: oldintr = signal(SIGINT, mabort);
1.14 millert 1118: (void)setjmp(jabort);
1.1 deraadt 1119: for (i = 1; mflag && i < argc-1; ++i) {
1120: *mode = (i == 1) ? 'w' : 'a';
1121: recvrequest(cmd, dest, argv[i], mode, 0);
1122: if (!mflag && fromatty) {
1123: ointer = interactive;
1124: interactive = 1;
1125: if (confirm("Continue with", argv[0])) {
1126: mflag ++;
1127: }
1128: interactive = ointer;
1129: }
1130: }
1.14 millert 1131: (void)signal(SIGINT, oldintr);
1.1 deraadt 1132: mflag = 0;
1133: }
1134:
1135: /*
1136: * Do a shell escape
1137: */
1138: /*ARGSUSED*/
1139: void
1140: shell(argc, argv)
1141: int argc;
1.13 millert 1142: char *argv[];
1.1 deraadt 1143: {
1144: pid_t pid;
1145: sig_t old1, old2;
1.13 millert 1146: char shellnam[MAXPATHLEN], *shell, *namep;
1.1 deraadt 1147: union wait status;
1148:
1149: old1 = signal (SIGINT, SIG_IGN);
1150: old2 = signal (SIGQUIT, SIG_IGN);
1151: if ((pid = fork()) == 0) {
1152: for (pid = 3; pid < 20; pid++)
1.14 millert 1153: (void)close(pid);
1154: (void)signal(SIGINT, SIG_DFL);
1155: (void)signal(SIGQUIT, SIG_DFL);
1.1 deraadt 1156: shell = getenv("SHELL");
1157: if (shell == NULL)
1158: shell = _PATH_BSHELL;
1.13 millert 1159: namep = strrchr(shell, '/');
1.1 deraadt 1160: if (namep == NULL)
1161: namep = shell;
1.13 millert 1162: shellnam[0] = '-';
1.14 millert 1163: (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1164: shellnam[sizeof(shellnam) - 1] = '\0';
1.1 deraadt 1165: if (strcmp(namep, "sh") != 0)
1166: shellnam[0] = '+';
1167: if (debug) {
1.14 millert 1168: puts(shell);
1169: (void)fflush(stdout);
1.1 deraadt 1170: }
1171: if (argc > 1) {
1.13 millert 1172: execl(shell, shellnam, "-c", altarg, (char *)0);
1.1 deraadt 1173: }
1174: else {
1.13 millert 1175: execl(shell, shellnam, (char *)0);
1.1 deraadt 1176: }
1177: warn("%s", shell);
1178: code = -1;
1179: exit(1);
1180: }
1181: if (pid > 0)
1182: while (wait((int *)&status) != pid)
1183: ;
1.14 millert 1184: (void)signal(SIGINT, old1);
1185: (void)signal(SIGQUIT, old2);
1.1 deraadt 1186: if (pid == -1) {
1.16 ! millert 1187: warn("Try again later");
1.1 deraadt 1188: code = -1;
1189: }
1190: else {
1191: code = 0;
1192: }
1193: }
1194:
1195: /*
1196: * Send new user information (re-login)
1197: */
1198: void
1199: user(argc, argv)
1200: int argc;
1.13 millert 1201: char *argv[];
1.1 deraadt 1202: {
1203: char acct[80];
1204: int n, aflag = 0;
1205:
1206: if (argc < 2)
1.14 millert 1207: (void)another(&argc, &argv, "username");
1.1 deraadt 1208: if (argc < 2 || argc > 4) {
1209: printf("usage: %s username [password] [account]\n", argv[0]);
1210: code = -1;
1211: return;
1212: }
1213: n = command("USER %s", argv[1]);
1214: if (n == CONTINUE) {
1215: if (argc < 3 )
1216: argv[2] = getpass("Password: "), argc++;
1217: n = command("PASS %s", argv[2]);
1218: }
1219: if (n == CONTINUE) {
1220: if (argc < 4) {
1.14 millert 1221: (void)fputs("Account: ", stdout);
1222: (void)fflush(stdout);
1223: (void)fgets(acct, sizeof(acct) - 1, stdin);
1.1 deraadt 1224: acct[strlen(acct) - 1] = '\0';
1225: argv[3] = acct; argc++;
1226: }
1227: n = command("ACCT %s", argv[3]);
1228: aflag++;
1229: }
1230: if (n != COMPLETE) {
1.14 millert 1231: puts("Login failed.");
1.1 deraadt 1232: return;
1233: }
1234: if (!aflag && argc == 4) {
1.14 millert 1235: (void)command("ACCT %s", argv[3]);
1.1 deraadt 1236: }
1237: }
1238:
1239: /*
1.13 millert 1240: * Print working directory on remote machine.
1.1 deraadt 1241: */
1242: /*VARARGS*/
1243: void
1244: pwd(argc, argv)
1245: int argc;
1246: char *argv[];
1247: {
1248: int oldverbose = verbose;
1249:
1250: /*
1251: * If we aren't verbose, this doesn't do anything!
1252: */
1253: verbose = 1;
1254: if (command("PWD") == ERROR && code == 500) {
1.16 ! millert 1255: puts("PWD command not recognized, trying XPWD.");
1.14 millert 1256: (void)command("XPWD");
1.1 deraadt 1257: }
1258: verbose = oldverbose;
1259: }
1260:
1261: /*
1.13 millert 1262: * Print working directory on local machine.
1263: */
1264: void
1265: lpwd(argc, argv)
1266: int argc;
1267: char *argv[];
1268: {
1269: char buf[MAXPATHLEN];
1270:
1271: if (getcwd(buf, sizeof(buf)) != NULL)
1272: printf("Local directory %s\n", buf);
1273: else
1274: warn("getcwd");
1275: code = 0;
1276: }
1277:
1278: /*
1.1 deraadt 1279: * Make a directory.
1280: */
1281: void
1282: makedir(argc, argv)
1283: int argc;
1284: char *argv[];
1285: {
1286:
1.13 millert 1287: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1288: argc > 2) {
1.1 deraadt 1289: printf("usage: %s directory-name\n", argv[0]);
1290: code = -1;
1291: return;
1292: }
1293: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1294: if (verbose)
1.16 ! millert 1295: puts("MKD command not recognized, trying XMKD.");
1.14 millert 1296: (void)command("XMKD %s", argv[1]);
1.1 deraadt 1297: }
1298: }
1299:
1300: /*
1301: * Remove a directory.
1302: */
1303: void
1304: removedir(argc, argv)
1305: int argc;
1306: char *argv[];
1307: {
1308:
1.13 millert 1309: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1310: argc > 2) {
1.1 deraadt 1311: printf("usage: %s directory-name\n", argv[0]);
1312: code = -1;
1313: return;
1314: }
1315: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1316: if (verbose)
1.16 ! millert 1317: puts("RMD command not recognized, trying XRMD.");
1.14 millert 1318: (void)command("XRMD %s", argv[1]);
1.1 deraadt 1319: }
1320: }
1321:
1322: /*
1323: * Send a line, verbatim, to the remote machine.
1324: */
1325: void
1326: quote(argc, argv)
1327: int argc;
1328: char *argv[];
1329: {
1330:
1331: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1332: printf("usage: %s line-to-send\n", argv[0]);
1333: code = -1;
1334: return;
1335: }
1336: quote1("", argc, argv);
1337: }
1338:
1339: /*
1340: * Send a SITE command to the remote machine. The line
1341: * is sent verbatim to the remote machine, except that the
1342: * word "SITE" is added at the front.
1343: */
1344: void
1345: site(argc, argv)
1346: int argc;
1347: char *argv[];
1348: {
1349:
1350: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1351: printf("usage: %s line-to-send\n", argv[0]);
1352: code = -1;
1353: return;
1354: }
1355: quote1("SITE ", argc, argv);
1356: }
1357:
1358: /*
1359: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1360: * Send the result as a one-line command and get response.
1361: */
1362: void
1363: quote1(initial, argc, argv)
1.13 millert 1364: const char *initial;
1.1 deraadt 1365: int argc;
1.13 millert 1366: char *argv[];
1.1 deraadt 1367: {
1368: int i, len;
1369: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1370:
1.14 millert 1371: (void)strncpy(buf, initial, sizeof(buf) - 1);
1372: buf[sizeof(buf) - 1] = '\0';
1.1 deraadt 1373: if (argc > 1) {
1374: len = strlen(buf);
1.16 ! millert 1375: len += strlen(strncpy(&buf[len], argv[1],
! 1376: sizeof(buf) - len - 1));
1.14 millert 1377: for (i = 2; i < argc && len < sizeof(buf); i++) {
1.1 deraadt 1378: buf[len++] = ' ';
1.13 millert 1379: len += strlen(strncpy(&buf[len], argv[i],
1.14 millert 1380: sizeof(buf) - len) - 1);
1.1 deraadt 1381: }
1382: }
1383: if (command(buf) == PRELIM) {
1384: while (getreply(0) == PRELIM)
1385: continue;
1386: }
1387: }
1388:
1389: void
1390: do_chmod(argc, argv)
1391: int argc;
1392: char *argv[];
1393: {
1394:
1395: if (argc < 2 && !another(&argc, &argv, "mode"))
1396: goto usage;
1.13 millert 1397: if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1.1 deraadt 1398: usage:
1399: printf("usage: %s mode file-name\n", argv[0]);
1400: code = -1;
1401: return;
1402: }
1.14 millert 1403: (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1.1 deraadt 1404: }
1405:
1406: void
1407: do_umask(argc, argv)
1408: int argc;
1409: char *argv[];
1410: {
1411: int oldverbose = verbose;
1412:
1413: verbose = 1;
1.14 millert 1414: (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1.1 deraadt 1415: verbose = oldverbose;
1416: }
1417:
1418: void
1419: idle(argc, argv)
1420: int argc;
1421: char *argv[];
1422: {
1423: int oldverbose = verbose;
1424:
1425: verbose = 1;
1.14 millert 1426: (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1.1 deraadt 1427: verbose = oldverbose;
1428: }
1429:
1430: /*
1431: * Ask the other side for help.
1432: */
1433: void
1434: rmthelp(argc, argv)
1435: int argc;
1436: char *argv[];
1437: {
1438: int oldverbose = verbose;
1439:
1440: verbose = 1;
1.14 millert 1441: (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1.1 deraadt 1442: verbose = oldverbose;
1443: }
1444:
1445: /*
1446: * Terminate session and exit.
1447: */
1448: /*VARARGS*/
1449: void
1450: quit(argc, argv)
1451: int argc;
1452: char *argv[];
1453: {
1454:
1455: if (connected)
1456: disconnect(0, 0);
1457: pswitch(1);
1458: if (connected) {
1459: disconnect(0, 0);
1460: }
1461: exit(0);
1462: }
1463:
1464: /*
1465: * Terminate session, but don't exit.
1466: */
1467: void
1468: disconnect(argc, argv)
1469: int argc;
1470: char *argv[];
1471: {
1472:
1473: if (!connected)
1474: return;
1.14 millert 1475: (void)command("QUIT");
1.1 deraadt 1476: if (cout) {
1.14 millert 1477: (void)fclose(cout);
1.1 deraadt 1478: }
1479: cout = NULL;
1480: connected = 0;
1481: data = -1;
1482: if (!proxy) {
1483: macnum = 0;
1484: }
1485: }
1486:
1487: void
1.13 millert 1488: account(argc, argv)
1.1 deraadt 1489: int argc;
1.13 millert 1490: char *argv[];
1.1 deraadt 1491: {
1.13 millert 1492: char *ap;
1.1 deraadt 1493:
1.13 millert 1494: if (argc > 2) {
1495: printf("usage: %s [password]\n", argv[0]);
1496: code = -1;
1497: return;
1.1 deraadt 1498: }
1.13 millert 1499: else if (argc == 2)
1500: ap = argv[1];
1501: else
1.1 deraadt 1502: ap = getpass("Account:");
1.14 millert 1503: (void)command("ACCT %s", ap);
1.1 deraadt 1504: }
1505:
1506: jmp_buf abortprox;
1507:
1508: void
1.15 millert 1509: proxabort(notused)
1510: int notused;
1.1 deraadt 1511: {
1512:
1.13 millert 1513: alarmtimer(0);
1.1 deraadt 1514: if (!proxy) {
1515: pswitch(1);
1516: }
1517: if (connected) {
1518: proxflag = 1;
1519: }
1520: else {
1521: proxflag = 0;
1522: }
1523: pswitch(0);
1.13 millert 1524: longjmp(abortprox, 1);
1.1 deraadt 1525: }
1526:
1527: void
1528: doproxy(argc, argv)
1529: int argc;
1530: char *argv[];
1531: {
1532: struct cmd *c;
1.13 millert 1533: int cmdpos;
1.1 deraadt 1534: sig_t oldintr;
1535:
1536: if (argc < 2 && !another(&argc, &argv, "command")) {
1537: printf("usage: %s command\n", argv[0]);
1538: code = -1;
1539: return;
1540: }
1541: c = getcmd(argv[1]);
1542: if (c == (struct cmd *) -1) {
1.16 ! millert 1543: puts("?Ambiguous command.");
1.14 millert 1544: (void)fflush(stdout);
1.1 deraadt 1545: code = -1;
1546: return;
1547: }
1548: if (c == 0) {
1.16 ! millert 1549: puts("?Invalid command.");
1.14 millert 1550: (void)fflush(stdout);
1.1 deraadt 1551: code = -1;
1552: return;
1553: }
1554: if (!c->c_proxy) {
1.16 ! millert 1555: puts("?Invalid proxy command.");
1.14 millert 1556: (void)fflush(stdout);
1.1 deraadt 1557: code = -1;
1558: return;
1559: }
1560: if (setjmp(abortprox)) {
1561: code = -1;
1562: return;
1563: }
1564: oldintr = signal(SIGINT, proxabort);
1565: pswitch(1);
1566: if (c->c_conn && !connected) {
1.16 ! millert 1567: puts("Not connected.");
1.14 millert 1568: (void)fflush(stdout);
1.1 deraadt 1569: pswitch(0);
1.14 millert 1570: (void)signal(SIGINT, oldintr);
1.1 deraadt 1571: code = -1;
1572: return;
1573: }
1.13 millert 1574: cmdpos = strcspn(line, " \t");
1575: if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1576: memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1.1 deraadt 1577: (*c->c_handler)(argc-1, argv+1);
1578: if (connected) {
1579: proxflag = 1;
1580: }
1581: else {
1582: proxflag = 0;
1583: }
1584: pswitch(0);
1.14 millert 1585: (void)signal(SIGINT, oldintr);
1.1 deraadt 1586: }
1587:
1588: void
1589: setcase(argc, argv)
1590: int argc;
1591: char *argv[];
1592: {
1593:
1.13 millert 1594: code = togglevar(argc, argv, &mcase, "Case mapping");
1.1 deraadt 1595: }
1596:
1597: void
1598: setcr(argc, argv)
1599: int argc;
1600: char *argv[];
1601: {
1602:
1.13 millert 1603: code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1.1 deraadt 1604: }
1605:
1606: void
1.13 millert 1607: setntrans(argc, argv)
1.1 deraadt 1608: int argc;
1609: char *argv[];
1610: {
1611: if (argc == 1) {
1612: ntflag = 0;
1.14 millert 1613: puts("Ntrans off.");
1.1 deraadt 1614: code = ntflag;
1615: return;
1616: }
1617: ntflag++;
1618: code = ntflag;
1.14 millert 1619: (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1620: ntin[sizeof(ntin) - 1] = '\0';
1.1 deraadt 1621: if (argc == 2) {
1622: ntout[0] = '\0';
1623: return;
1624: }
1.14 millert 1625: (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1626: ntout[sizeof(ntout) - 1] = '\0';
1.1 deraadt 1627: }
1628:
1629: char *
1630: dotrans(name)
1631: char *name;
1632: {
1633: static char new[MAXPATHLEN];
1634: char *cp1, *cp2 = new;
1635: int i, ostop, found;
1636:
1637: for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1638: continue;
1639: for (cp1 = name; *cp1; cp1++) {
1640: found = 0;
1641: for (i = 0; *(ntin + i) && i < 16; i++) {
1642: if (*cp1 == *(ntin + i)) {
1643: found++;
1644: if (i < ostop) {
1645: *cp2++ = *(ntout + i);
1646: }
1647: break;
1648: }
1649: }
1650: if (!found) {
1651: *cp2++ = *cp1;
1652: }
1653: }
1654: *cp2 = '\0';
1655: return (new);
1656: }
1657:
1658: void
1659: setnmap(argc, argv)
1660: int argc;
1661: char *argv[];
1662: {
1663: char *cp;
1664:
1665: if (argc == 1) {
1666: mapflag = 0;
1.14 millert 1667: puts("Nmap off.");
1.1 deraadt 1668: code = mapflag;
1669: return;
1670: }
1.13 millert 1671: if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1.16 ! millert 1672: printf("usage: %s [mapin mapout]\n", argv[0]);
1.1 deraadt 1673: code = -1;
1674: return;
1675: }
1676: mapflag = 1;
1677: code = 1;
1678: cp = strchr(altarg, ' ');
1679: if (proxy) {
1680: while(*++cp == ' ')
1681: continue;
1682: altarg = cp;
1683: cp = strchr(altarg, ' ');
1684: }
1685: *cp = '\0';
1.14 millert 1686: (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1.1 deraadt 1687: while (*++cp == ' ')
1688: continue;
1.14 millert 1689: (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1.1 deraadt 1690: }
1691:
1692: char *
1693: domap(name)
1694: char *name;
1695: {
1696: static char new[MAXPATHLEN];
1697: char *cp1 = name, *cp2 = mapin;
1698: char *tp[9], *te[9];
1699: int i, toks[9], toknum = 0, match = 1;
1700:
1701: for (i=0; i < 9; ++i) {
1702: toks[i] = 0;
1703: }
1704: while (match && *cp1 && *cp2) {
1705: switch (*cp2) {
1706: case '\\':
1707: if (*++cp2 != *cp1) {
1708: match = 0;
1709: }
1710: break;
1711: case '$':
1712: if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1713: if (*cp1 != *(++cp2+1)) {
1714: toks[toknum = *cp2 - '1']++;
1715: tp[toknum] = cp1;
1716: while (*++cp1 && *(cp2+1)
1717: != *cp1);
1718: te[toknum] = cp1;
1719: }
1720: cp2++;
1721: break;
1722: }
1723: /* FALLTHROUGH */
1724: default:
1725: if (*cp2 != *cp1) {
1726: match = 0;
1727: }
1728: break;
1729: }
1730: if (match && *cp1) {
1731: cp1++;
1732: }
1733: if (match && *cp2) {
1734: cp2++;
1735: }
1736: }
1737: if (!match && *cp1) /* last token mismatch */
1738: {
1739: toks[toknum] = 0;
1740: }
1741: cp1 = new;
1742: *cp1 = '\0';
1743: cp2 = mapout;
1744: while (*cp2) {
1745: match = 0;
1746: switch (*cp2) {
1747: case '\\':
1748: if (*(cp2 + 1)) {
1749: *cp1++ = *++cp2;
1750: }
1751: break;
1752: case '[':
1753: LOOP:
1.13 millert 1754: if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1.1 deraadt 1755: if (*++cp2 == '0') {
1756: char *cp3 = name;
1757:
1758: while (*cp3) {
1759: *cp1++ = *cp3++;
1760: }
1761: match = 1;
1762: }
1763: else if (toks[toknum = *cp2 - '1']) {
1764: char *cp3 = tp[toknum];
1765:
1766: while (cp3 != te[toknum]) {
1767: *cp1++ = *cp3++;
1768: }
1769: match = 1;
1770: }
1771: }
1772: else {
1.13 millert 1773: while (*cp2 && *cp2 != ',' &&
1.1 deraadt 1774: *cp2 != ']') {
1775: if (*cp2 == '\\') {
1776: cp2++;
1777: }
1778: else if (*cp2 == '$' &&
1779: isdigit(*(cp2+1))) {
1780: if (*++cp2 == '0') {
1781: char *cp3 = name;
1782:
1783: while (*cp3) {
1784: *cp1++ = *cp3++;
1785: }
1786: }
1787: else if (toks[toknum =
1788: *cp2 - '1']) {
1789: char *cp3=tp[toknum];
1790:
1791: while (cp3 !=
1792: te[toknum]) {
1793: *cp1++ = *cp3++;
1794: }
1795: }
1796: }
1797: else if (*cp2) {
1798: *cp1++ = *cp2++;
1799: }
1800: }
1801: if (!*cp2) {
1.16 ! millert 1802: puts(
! 1803: "nmap: unbalanced brackets.");
1.1 deraadt 1804: return (name);
1805: }
1806: match = 1;
1807: cp2--;
1808: }
1809: if (match) {
1810: while (*++cp2 && *cp2 != ']') {
1811: if (*cp2 == '\\' && *(cp2 + 1)) {
1812: cp2++;
1813: }
1814: }
1815: if (!*cp2) {
1.16 ! millert 1816: puts(
! 1817: "nmap: unbalanced brackets.");
1.1 deraadt 1818: return (name);
1819: }
1820: break;
1821: }
1822: switch (*++cp2) {
1823: case ',':
1824: goto LOOP;
1825: case ']':
1826: break;
1827: default:
1828: cp2--;
1829: goto LOOP;
1830: }
1831: break;
1832: case '$':
1833: if (isdigit(*(cp2 + 1))) {
1834: if (*++cp2 == '0') {
1835: char *cp3 = name;
1836:
1837: while (*cp3) {
1838: *cp1++ = *cp3++;
1839: }
1840: }
1841: else if (toks[toknum = *cp2 - '1']) {
1842: char *cp3 = tp[toknum];
1843:
1844: while (cp3 != te[toknum]) {
1845: *cp1++ = *cp3++;
1846: }
1847: }
1848: break;
1849: }
1850: /* intentional drop through */
1851: default:
1852: *cp1++ = *cp2;
1853: break;
1854: }
1855: cp2++;
1856: }
1857: *cp1 = '\0';
1858: if (!*new) {
1859: return (name);
1860: }
1861: return (new);
1862: }
1863:
1864: void
1865: setpassive(argc, argv)
1866: int argc;
1867: char *argv[];
1868: {
1869:
1.15 millert 1870: code = togglevar(argc, argv, &passivemode,
1871: verbose ? "Passive mode" : NULL);
1.1 deraadt 1872: }
1873:
1874: void
1875: setsunique(argc, argv)
1876: int argc;
1877: char *argv[];
1878: {
1879:
1.13 millert 1880: code = togglevar(argc, argv, &sunique, "Store unique");
1.1 deraadt 1881: }
1882:
1883: void
1884: setrunique(argc, argv)
1885: int argc;
1886: char *argv[];
1887: {
1888:
1.13 millert 1889: code = togglevar(argc, argv, &runique, "Receive unique");
1.1 deraadt 1890: }
1891:
1.13 millert 1892: /* change directory to parent directory */
1.1 deraadt 1893: void
1894: cdup(argc, argv)
1895: int argc;
1896: char *argv[];
1897: {
1.13 millert 1898: int r;
1.1 deraadt 1899:
1.13 millert 1900: r = command("CDUP");
1901: if (r == ERROR && code == 500) {
1.1 deraadt 1902: if (verbose)
1.16 ! millert 1903: puts("CDUP command not recognized, trying XCUP.");
1.13 millert 1904: r = command("XCUP");
1.1 deraadt 1905: }
1.13 millert 1906: if (r == COMPLETE)
1907: dirchange = 1;
1.1 deraadt 1908: }
1909:
1910: /* restart transfer at specific point */
1911: void
1912: restart(argc, argv)
1913: int argc;
1914: char *argv[];
1915: {
1916:
1917: if (argc != 2)
1.16 ! millert 1918: puts("restart: offset not specified.");
1.1 deraadt 1919: else {
1920: restart_point = atol(argv[1]);
1.13 millert 1921: printf("Restarting at %qd. Execute get, put or append to"
1922: "initiate transfer\n", restart_point);
1.1 deraadt 1923: }
1924: }
1925:
1926: /* show remote system type */
1927: void
1928: syst(argc, argv)
1929: int argc;
1930: char *argv[];
1931: {
1932:
1.14 millert 1933: (void)command("SYST");
1.1 deraadt 1934: }
1935:
1936: void
1937: macdef(argc, argv)
1938: int argc;
1939: char *argv[];
1940: {
1941: char *tmp;
1942: int c;
1943:
1944: if (macnum == 16) {
1.16 ! millert 1945: puts("Limit of 16 macros have already been defined.");
1.1 deraadt 1946: code = -1;
1947: return;
1948: }
1.13 millert 1949: if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
1.16 ! millert 1950: printf("usage: %s macro_name\n", argv[0]);
1.1 deraadt 1951: code = -1;
1952: return;
1953: }
1.16 ! millert 1954: if (interactive)
! 1955: puts(
! 1956: "Enter macro line by line, terminating it with a null line.");
1.14 millert 1957: (void)strncpy(macros[macnum].mac_name, argv[1],
1958: sizeof(macros[macnum].mac_name) - 1);
1959: macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
1960: if (macnum == 0)
1.1 deraadt 1961: macros[macnum].mac_start = macbuf;
1.14 millert 1962: else
1.1 deraadt 1963: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1964: tmp = macros[macnum].mac_start;
1965: while (tmp != macbuf+4096) {
1966: if ((c = getchar()) == EOF) {
1.16 ! millert 1967: puts("macdef: end of file encountered.");
1.1 deraadt 1968: code = -1;
1969: return;
1970: }
1971: if ((*tmp = c) == '\n') {
1972: if (tmp == macros[macnum].mac_start) {
1973: macros[macnum++].mac_end = tmp;
1974: code = 0;
1975: return;
1976: }
1977: if (*(tmp-1) == '\0') {
1978: macros[macnum++].mac_end = tmp - 1;
1979: code = 0;
1980: return;
1981: }
1982: *tmp = '\0';
1983: }
1984: tmp++;
1985: }
1986: while (1) {
1987: while ((c = getchar()) != '\n' && c != EOF)
1988: /* LOOP */;
1989: if (c == EOF || getchar() == '\n') {
1.16 ! millert 1990: puts("Macro not defined - 4K buffer exceeded.");
1.1 deraadt 1991: code = -1;
1992: return;
1993: }
1994: }
1995: }
1996:
1997: /*
1998: * get size of file on remote machine
1999: */
2000: void
2001: sizecmd(argc, argv)
2002: int argc;
2003: char *argv[];
2004: {
1.13 millert 2005: off_t size;
1.1 deraadt 2006:
1.13 millert 2007: if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
1.1 deraadt 2008: printf("usage: %s filename\n", argv[0]);
2009: code = -1;
2010: return;
2011: }
1.13 millert 2012: size = remotesize(argv[1], 1);
2013: if (size != -1)
2014: printf("%s\t%qd\n", argv[1], size);
2015: code = size;
1.1 deraadt 2016: }
2017:
2018: /*
2019: * get last modification time of file on remote machine
2020: */
2021: void
2022: modtime(argc, argv)
2023: int argc;
2024: char *argv[];
2025: {
1.13 millert 2026: time_t mtime;
1.1 deraadt 2027:
1.13 millert 2028: if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
1.1 deraadt 2029: printf("usage: %s filename\n", argv[0]);
2030: code = -1;
2031: return;
2032: }
1.13 millert 2033: mtime = remotemodtime(argv[1], 1);
2034: if (mtime != -1)
2035: printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2036: code = mtime;
1.1 deraadt 2037: }
2038:
2039: /*
1.13 millert 2040: * show status on remote machine
1.1 deraadt 2041: */
2042: void
2043: rmtstatus(argc, argv)
2044: int argc;
2045: char *argv[];
2046: {
2047:
1.14 millert 2048: (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
1.1 deraadt 2049: }
2050:
2051: /*
2052: * get file if modtime is more recent than current file
2053: */
2054: void
2055: newer(argc, argv)
2056: int argc;
2057: char *argv[];
2058: {
2059:
2060: if (getit(argc, argv, -1, "w"))
1.16 ! millert 2061: printf("Local file \"%s\" is newer than remote file \"%s\".\n",
1.1 deraadt 2062: argv[2], argv[1]);
1.16 ! millert 2063: }
! 2064:
! 2065: /*
! 2066: * Display one file through $PAGER (defaults to "more").
! 2067: */
! 2068: void
! 2069: page(argc, argv)
! 2070: int argc;
! 2071: char *argv[];
! 2072: {
! 2073: int orestart_point, ohash, overbose;
! 2074: char *p, *pager;
! 2075:
! 2076: if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
! 2077: printf("usage: %s filename\n", argv[0]);
! 2078: code = -1;
! 2079: return;
! 2080: }
! 2081: if (!globulize(&argv[1])) {
! 2082: code = -1;
! 2083: return;
! 2084: }
! 2085: p = getenv("PAGER");
! 2086: if (p == NULL)
! 2087: p = PAGER;
! 2088: if ((pager = malloc(strlen(p) + 2)) == NULL)
! 2089: errx(1, "Can't allocate memory for $PAGER");
! 2090: (void)sprintf(pager, "|%s", p);
! 2091:
! 2092: orestart_point = restart_point;
! 2093: ohash = hash;
! 2094: overbose = verbose;
! 2095: restart_point = hash = verbose = 0;
! 2096: recvrequest("RETR", pager, argv[1], "r+w", 1);
! 2097: (void)free(pager);
! 2098: restart_point = orestart_point;
! 2099: hash = ohash;
! 2100: verbose = overbose;
1.1 deraadt 2101: }