cmds.c revision 1.62 1 /* $NetBSD: cmds.c,v 1.62 1999/09/27 23:09:42 lukem Exp $ */
2
3 /*
4 * Copyright (C) 1997 and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
38 * NASA Ames Research Center.
39 *
40 * This code is derived from software contributed to The NetBSD Foundation
41 * by Luke Mewburn.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the NetBSD
54 * Foundation, Inc. and its contributors.
55 * 4. Neither the name of The NetBSD Foundation nor the names of its
56 * contributors may be used to endorse or promote products derived
57 * from this software without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69 * POSSIBILITY OF SUCH DAMAGE.
70 */
71
72 /*
73 * Copyright (c) 1985, 1989, 1993, 1994
74 * The Regents of the University of California. All rights reserved.
75 *
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions
78 * are met:
79 * 1. Redistributions of source code must retain the above copyright
80 * notice, this list of conditions and the following disclaimer.
81 * 2. Redistributions in binary form must reproduce the above copyright
82 * notice, this list of conditions and the following disclaimer in the
83 * documentation and/or other materials provided with the distribution.
84 * 3. All advertising materials mentioning features or use of this software
85 * must display the following acknowledgement:
86 * This product includes software developed by the University of
87 * California, Berkeley and its contributors.
88 * 4. Neither the name of the University nor the names of its contributors
89 * may be used to endorse or promote products derived from this software
90 * without specific prior written permission.
91 *
92 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
96 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102 * SUCH DAMAGE.
103 */
104
105 #include <sys/cdefs.h>
106 #ifndef lint
107 #if 0
108 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
109 #else
110 __RCSID("$NetBSD: cmds.c,v 1.62 1999/09/27 23:09:42 lukem Exp $");
111 #endif
112 #endif /* not lint */
113
114 /*
115 * FTP User Program -- Command Routines.
116 */
117 #include <sys/types.h>
118 #include <sys/socket.h>
119 #include <sys/stat.h>
120 #include <sys/wait.h>
121 #include <arpa/ftp.h>
122
123 #include <ctype.h>
124 #include <err.h>
125 #include <glob.h>
126 #include <limits.h>
127 #include <netdb.h>
128 #include <stdio.h>
129 #include <stdlib.h>
130 #include <string.h>
131 #include <time.h>
132 #include <unistd.h>
133
134 #include "ftp_var.h"
135 #include "pathnames.h"
136
137 jmp_buf jabort;
138 char *mname;
139 char *home = "/";
140
141 struct types {
142 char *t_name;
143 char *t_mode;
144 int t_type;
145 char *t_arg;
146 } types[] = {
147 { "ascii", "A", TYPE_A, 0 },
148 { "binary", "I", TYPE_I, 0 },
149 { "image", "I", TYPE_I, 0 },
150 { "ebcdic", "E", TYPE_E, 0 },
151 { "tenex", "L", TYPE_L, bytename },
152 { NULL }
153 };
154
155 /*
156 * Set transfer type.
157 */
158 void
159 settype(argc, argv)
160 int argc;
161 char *argv[];
162 {
163 struct types *p;
164 int comret;
165
166 if (argc > 2) {
167 char *sep;
168
169 fprintf(ttyout, "usage: %s [", argv[0]);
170 sep = " ";
171 for (p = types; p->t_name; p++) {
172 fprintf(ttyout, "%s%s", sep, p->t_name);
173 sep = " | ";
174 }
175 fputs(" ]\n", ttyout);
176 code = -1;
177 return;
178 }
179 if (argc < 2) {
180 fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
181 code = 0;
182 return;
183 }
184 for (p = types; p->t_name; p++)
185 if (strcmp(argv[1], p->t_name) == 0)
186 break;
187 if (p->t_name == 0) {
188 fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
189 code = -1;
190 return;
191 }
192 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
193 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
194 else
195 comret = command("TYPE %s", p->t_mode);
196 if (comret == COMPLETE) {
197 (void)strcpy(typename, p->t_name);
198 curtype = type = p->t_type;
199 }
200 }
201
202 /*
203 * Internal form of settype; changes current type in use with server
204 * without changing our notion of the type for data transfers.
205 * Used to change to and from ascii for listings.
206 */
207 void
208 changetype(newtype, show)
209 int newtype, show;
210 {
211 struct types *p;
212 int comret, oldverbose = verbose;
213
214 if (newtype == 0)
215 newtype = TYPE_I;
216 if (newtype == curtype)
217 return;
218 if (debug == 0 && show == 0)
219 verbose = 0;
220 for (p = types; p->t_name; p++)
221 if (newtype == p->t_type)
222 break;
223 if (p->t_name == 0) {
224 warnx("internal error: unknown type %d.", newtype);
225 return;
226 }
227 if (newtype == TYPE_L && bytename[0] != '\0')
228 comret = command("TYPE %s %s", p->t_mode, bytename);
229 else
230 comret = command("TYPE %s", p->t_mode);
231 if (comret == COMPLETE)
232 curtype = newtype;
233 verbose = oldverbose;
234 }
235
236 char *stype[] = {
237 "type",
238 "",
239 0
240 };
241
242 /*
243 * Set binary transfer type.
244 */
245 /*VARARGS*/
246 void
247 setbinary(argc, argv)
248 int argc;
249 char *argv[];
250 {
251
252 stype[1] = "binary";
253 settype(2, stype);
254 }
255
256 /*
257 * Set ascii transfer type.
258 */
259 /*VARARGS*/
260 void
261 setascii(argc, argv)
262 int argc;
263 char *argv[];
264 {
265
266 stype[1] = "ascii";
267 settype(2, stype);
268 }
269
270 /*
271 * Set tenex transfer type.
272 */
273 /*VARARGS*/
274 void
275 settenex(argc, argv)
276 int argc;
277 char *argv[];
278 {
279
280 stype[1] = "tenex";
281 settype(2, stype);
282 }
283
284 /*
285 * Set file transfer mode.
286 */
287 /*ARGSUSED*/
288 void
289 setftmode(argc, argv)
290 int argc;
291 char *argv[];
292 {
293
294 fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
295 code = -1;
296 }
297
298 /*
299 * Set file transfer format.
300 */
301 /*ARGSUSED*/
302 void
303 setform(argc, argv)
304 int argc;
305 char *argv[];
306 {
307
308 fprintf(ttyout, "We only support %s format, sorry.\n", formname);
309 code = -1;
310 }
311
312 /*
313 * Set file transfer structure.
314 */
315 /*ARGSUSED*/
316 void
317 setstruct(argc, argv)
318 int argc;
319 char *argv[];
320 {
321
322 fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
323 code = -1;
324 }
325
326 /*
327 * Send a single file.
328 */
329 void
330 put(argc, argv)
331 int argc;
332 char *argv[];
333 {
334 char *cmd;
335 int loc = 0;
336 char *oldargv1, *oldargv2;
337
338 if (argc == 2) {
339 argc++;
340 argv[2] = argv[1];
341 loc++;
342 }
343 if (argc < 2 && !another(&argc, &argv, "local-file"))
344 goto usage;
345 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
346 usage:
347 fprintf(ttyout, "usage: %s local-file [ remote-file ]\n",
348 argv[0]);
349 code = -1;
350 return;
351 }
352 oldargv1 = argv[1];
353 oldargv2 = argv[2];
354 if (!globulize(&argv[1])) {
355 code = -1;
356 return;
357 }
358 /*
359 * If "globulize" modifies argv[1], and argv[2] is a copy of
360 * the old argv[1], make it a copy of the new argv[1].
361 */
362 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
363 argv[2] = argv[1];
364 }
365 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
366 if (loc && ntflag) {
367 argv[2] = dotrans(argv[2]);
368 }
369 if (loc && mapflag) {
370 argv[2] = domap(argv[2]);
371 }
372 sendrequest(cmd, argv[1], argv[2],
373 argv[1] != oldargv1 || argv[2] != oldargv2);
374 if (oldargv1 != argv[1]) /* free up after globulize() */
375 free(argv[1]);
376 }
377
378 /*
379 * Send multiple files.
380 */
381 void
382 mput(argc, argv)
383 int argc;
384 char *argv[];
385 {
386 int i;
387 sig_t oldintr;
388 int ointer;
389 char *tp;
390
391 if (argc < 2 && !another(&argc, &argv, "local-files")) {
392 fprintf(ttyout, "usage: %s local-files\n", argv[0]);
393 code = -1;
394 return;
395 }
396 mname = argv[0];
397 mflag = 1;
398 oldintr = xsignal(SIGINT, mabort);
399 (void)setjmp(jabort);
400 if (proxy) {
401 char *cp, *tp2, tmpbuf[MAXPATHLEN];
402
403 while ((cp = remglob(argv, 0, NULL)) != NULL) {
404 if (*cp == '\0') {
405 mflag = 0;
406 continue;
407 }
408 if (mflag && confirm(argv[0], cp)) {
409 tp = cp;
410 if (mcase) {
411 while (*tp &&
412 !islower((unsigned char)*tp)) {
413 tp++;
414 }
415 if (!*tp) {
416 tp = cp;
417 tp2 = tmpbuf;
418 while ((*tp2 = *tp) != '\0') {
419 if (isupper((unsigned char)*tp2)) {
420 *tp2 =
421 tolower(*tp2);
422 }
423 tp++;
424 tp2++;
425 }
426 }
427 tp = tmpbuf;
428 }
429 if (ntflag) {
430 tp = dotrans(tp);
431 }
432 if (mapflag) {
433 tp = domap(tp);
434 }
435 sendrequest((sunique) ? "STOU" : "STOR",
436 cp, tp, cp != tp || !interactive);
437 if (!mflag && fromatty) {
438 ointer = interactive;
439 interactive = 1;
440 if (confirm("Continue with", "mput")) {
441 mflag++;
442 }
443 interactive = ointer;
444 }
445 }
446 }
447 (void)xsignal(SIGINT, oldintr);
448 mflag = 0;
449 return;
450 }
451 for (i = 1; i < argc; i++) {
452 char **cpp;
453 glob_t gl;
454 int flags;
455
456 if (!doglob) {
457 if (mflag && confirm(argv[0], argv[i])) {
458 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
459 tp = (mapflag) ? domap(tp) : tp;
460 sendrequest((sunique) ? "STOU" : "STOR",
461 argv[i], tp, tp != argv[i] || !interactive);
462 if (!mflag && fromatty) {
463 ointer = interactive;
464 interactive = 1;
465 if (confirm("Continue with", "mput")) {
466 mflag++;
467 }
468 interactive = ointer;
469 }
470 }
471 continue;
472 }
473
474 memset(&gl, 0, sizeof(gl));
475 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
476 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
477 warnx("%s: not found", argv[i]);
478 globfree(&gl);
479 continue;
480 }
481 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
482 if (mflag && confirm(argv[0], *cpp)) {
483 tp = (ntflag) ? dotrans(*cpp) : *cpp;
484 tp = (mapflag) ? domap(tp) : tp;
485 sendrequest((sunique) ? "STOU" : "STOR",
486 *cpp, tp, *cpp != tp || !interactive);
487 if (!mflag && fromatty) {
488 ointer = interactive;
489 interactive = 1;
490 if (confirm("Continue with", "mput")) {
491 mflag++;
492 }
493 interactive = ointer;
494 }
495 }
496 }
497 globfree(&gl);
498 }
499 (void)xsignal(SIGINT, oldintr);
500 mflag = 0;
501 }
502
503 void
504 reget(argc, argv)
505 int argc;
506 char *argv[];
507 {
508
509 (void)getit(argc, argv, 1, "r+w");
510 }
511
512 void
513 get(argc, argv)
514 int argc;
515 char *argv[];
516 {
517
518 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
519 }
520
521 /*
522 * Receive one file.
523 */
524 int
525 getit(argc, argv, restartit, mode)
526 int argc;
527 char *argv[];
528 int restartit;
529 const char *mode;
530 {
531 int loc = 0;
532 int rval = 0;
533 char *oldargv1, *oldargv2, *globargv2;
534
535 if (argc == 2) {
536 argc++;
537 argv[2] = argv[1];
538 loc++;
539 }
540 if (argc < 2 && !another(&argc, &argv, "remote-file"))
541 goto usage;
542 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
543 usage:
544 fprintf(ttyout, "usage: %s remote-file [ local-file ]\n",
545 argv[0]);
546 code = -1;
547 return (0);
548 }
549 oldargv1 = argv[1];
550 oldargv2 = argv[2];
551 if (!globulize(&argv[2])) {
552 code = -1;
553 return (0);
554 }
555 globargv2 = argv[2];
556 if (loc && mcase) {
557 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
558
559 while (*tp && !islower((unsigned char)*tp)) {
560 tp++;
561 }
562 if (!*tp) {
563 tp = argv[2];
564 tp2 = tmpbuf;
565 while ((*tp2 = *tp) != '\0') {
566 if (isupper((unsigned char)*tp2)) {
567 *tp2 = tolower(*tp2);
568 }
569 tp++;
570 tp2++;
571 }
572 argv[2] = tmpbuf;
573 }
574 }
575 if (loc && ntflag)
576 argv[2] = dotrans(argv[2]);
577 if (loc && mapflag)
578 argv[2] = domap(argv[2]);
579 if (restartit) {
580 struct stat stbuf;
581 int ret;
582
583 ret = stat(argv[2], &stbuf);
584 if (restartit == 1) {
585 if (ret < 0) {
586 warn("local: %s", argv[2]);
587 goto freegetit;
588 }
589 restart_point = stbuf.st_size;
590 } else {
591 if (ret == 0) {
592 time_t mtime;
593
594 mtime = remotemodtime(argv[1], 0);
595 if (mtime == -1)
596 goto freegetit;
597 if (stbuf.st_mtime >= mtime) {
598 rval = 1;
599 goto freegetit;
600 }
601 }
602 }
603 }
604
605 recvrequest("RETR", argv[2], argv[1], mode,
606 argv[1] != oldargv1 || argv[2] != oldargv2, loc);
607 restart_point = 0;
608 freegetit:
609 if (oldargv2 != globargv2) /* free up after globulize() */
610 free(globargv2);
611 return (rval);
612 }
613
614 /* ARGSUSED */
615 void
616 mabort(signo)
617 int signo;
618 {
619 int ointer, oconf;
620
621 alarmtimer(0);
622 putc('\n', ttyout);
623 if (mflag && fromatty) {
624 ointer = interactive;
625 oconf = confirmrest;
626 interactive = 1;
627 confirmrest = 0;
628 if (confirm("Continue with", mname)) {
629 interactive = ointer;
630 confirmrest = oconf;
631 longjmp(jabort, 0);
632 }
633 interactive = ointer;
634 confirmrest = oconf;
635 }
636 mflag = 0;
637 longjmp(jabort, 0);
638 }
639
640 /*
641 * Get multiple files.
642 */
643 void
644 mget(argc, argv)
645 int argc;
646 char *argv[];
647 {
648 sig_t oldintr;
649 int ch, ointer;
650 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
651
652 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
653 fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
654 code = -1;
655 return;
656 }
657 mname = argv[0];
658 mflag = 1;
659 oldintr = xsignal(SIGINT, mabort);
660 (void)setjmp(jabort);
661 while ((cp = remglob(argv, proxy, NULL)) != NULL) {
662 if (*cp == '\0') {
663 mflag = 0;
664 continue;
665 }
666 if (mflag && confirm(argv[0], cp)) {
667 tp = cp;
668 if (mcase) {
669 for (tp2 = tmpbuf; (ch = *tp++) != 0; )
670 *tp2++ = isupper(ch) ? tolower(ch) : ch;
671 *tp2 = '\0';
672 tp = tmpbuf;
673 }
674 if (ntflag) {
675 tp = dotrans(tp);
676 }
677 if (mapflag) {
678 tp = domap(tp);
679 }
680 recvrequest("RETR", tp, cp, "w",
681 tp != cp || !interactive, 1);
682 if (!mflag && fromatty) {
683 ointer = interactive;
684 interactive = 1;
685 if (confirm("Continue with", "mget")) {
686 mflag++;
687 }
688 interactive = ointer;
689 }
690 }
691 }
692 (void)xsignal(SIGINT, oldintr);
693 mflag = 0;
694 }
695
696 char *
697 onoff(bool)
698 int bool;
699 {
700
701 return (bool ? "on" : "off");
702 }
703
704 /*
705 * Show status.
706 */
707 /*ARGSUSED*/
708 void
709 status(argc, argv)
710 int argc;
711 char *argv[];
712 {
713 int i;
714
715 if (connected)
716 fprintf(ttyout, "Connected %sto %s.\n",
717 connected == -1 ? "and logged in" : "", hostname);
718 else
719 fputs("Not connected.\n", ttyout);
720 if (!proxy) {
721 pswitch(1);
722 if (connected) {
723 fprintf(ttyout, "Connected for proxy commands to %s.\n",
724 hostname);
725 }
726 else {
727 fputs("No proxy connection.\n", ttyout);
728 }
729 pswitch(0);
730 }
731 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
732 *gateserver ? gateserver : "(none)", gateport);
733 fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode));
734 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
735 modename, typename, formname, structname);
736 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
737 onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob));
738 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n",
739 onoff(sunique), onoff(runique));
740 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
741 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase),
742 onoff(crflag));
743 if (ntflag) {
744 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
745 }
746 else {
747 fputs("Ntrans: off.\n", ttyout);
748 }
749 if (mapflag) {
750 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
751 }
752 else {
753 fputs("Nmap: off.\n", ttyout);
754 }
755 fprintf(ttyout,
756 "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
757 onoff(hash), mark, onoff(progress));
758 fprintf(ttyout,
759 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
760 onoff(rate_get), rate_get, rate_get_incr);
761 fprintf(ttyout,
762 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
763 onoff(rate_put), rate_put, rate_put_incr);
764 fprintf(ttyout,
765 "Socket buffer sizes: send %d, receive %d.\n",
766 sndbuf_size, rcvbuf_size);
767 fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport));
768 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s.\n", onoff(epsv4));
769 #ifndef NO_EDITCOMPLETE
770 fprintf(ttyout, "Command line editing: %s.\n", onoff(editing));
771 #endif /* !NO_EDITCOMPLETE */
772 if (macnum > 0) {
773 fputs("Macros:\n", ttyout);
774 for (i=0; i<macnum; i++) {
775 fprintf(ttyout, "\t%s\n", macros[i].mac_name);
776 }
777 }
778 code = 0;
779 }
780
781 /*
782 * Toggle a variable
783 */
784 int
785 togglevar(argc, argv, var, mesg)
786 int argc;
787 char *argv[];
788 int *var;
789 const char *mesg;
790 {
791 if (argc < 2) {
792 *var = !*var;
793 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
794 *var = 1;
795 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
796 *var = 0;
797 } else {
798 fprintf(ttyout, "usage: %s [ on | off ]\n", argv[0]);
799 return (-1);
800 }
801 if (mesg)
802 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
803 return (*var);
804 }
805
806 /*
807 * Set beep on cmd completed mode.
808 */
809 /*VARARGS*/
810 void
811 setbell(argc, argv)
812 int argc;
813 char *argv[];
814 {
815
816 code = togglevar(argc, argv, &bell, "Bell mode");
817 }
818
819 #ifndef NO_EDITCOMPLETE
820 /*
821 * Set command line editing
822 */
823 /*VARARGS*/
824 void
825 setedit(argc, argv)
826 int argc;
827 char *argv[];
828 {
829
830 code = togglevar(argc, argv, &editing, "Editing mode");
831 controlediting();
832 }
833 #endif /* !NO_EDITCOMPLETE */
834
835 /*
836 * Turn on packet tracing.
837 */
838 /*VARARGS*/
839 void
840 settrace(argc, argv)
841 int argc;
842 char *argv[];
843 {
844
845 code = togglevar(argc, argv, &trace, "Packet tracing");
846 }
847
848 /*
849 * Toggle hash mark printing during transfers, or set hash mark bytecount.
850 */
851 /*VARARGS*/
852 void
853 sethash(argc, argv)
854 int argc;
855 char *argv[];
856 {
857 if (argc == 1)
858 hash = !hash;
859 else if (argc != 2) {
860 fprintf(ttyout, "usage: %s [ on | off | bytecount ]\n",
861 argv[0]);
862 code = -1;
863 return;
864 } else if (strcasecmp(argv[1], "on") == 0)
865 hash = 1;
866 else if (strcasecmp(argv[1], "off") == 0)
867 hash = 0;
868 else {
869 int nmark;
870
871 nmark = strsuftoi(argv[1]);
872 if (nmark < 1) {
873 fprintf(ttyout, "mark: bad bytecount value `%s'.\n",
874 argv[1]);
875 code = -1;
876 return;
877 }
878 mark = nmark;
879 hash = 1;
880 }
881 fprintf(ttyout, "Hash mark printing %s", onoff(hash));
882 if (hash)
883 fprintf(ttyout, " (%d bytes/hash mark)", mark);
884 fputs(".\n", ttyout);
885 if (hash)
886 progress = 0;
887 code = hash;
888 }
889
890 /*
891 * Turn on printing of server echo's.
892 */
893 /*VARARGS*/
894 void
895 setverbose(argc, argv)
896 int argc;
897 char *argv[];
898 {
899
900 code = togglevar(argc, argv, &verbose, "Verbose mode");
901 }
902
903 /*
904 * Toggle PORT/LPRT cmd use before each data connection.
905 */
906 /*VARARGS*/
907 void
908 setport(argc, argv)
909 int argc;
910 char *argv[];
911 {
912
913 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
914 }
915
916 /*
917 * Toggle transfer progress bar.
918 */
919 /*VARARGS*/
920 void
921 setprogress(argc, argv)
922 int argc;
923 char *argv[];
924 {
925
926 code = togglevar(argc, argv, &progress, "Progress bar");
927 if (progress)
928 hash = 0;
929 }
930
931 /*
932 * Turn on interactive prompting during mget, mput, and mdelete.
933 */
934 /*VARARGS*/
935 void
936 setprompt(argc, argv)
937 int argc;
938 char *argv[];
939 {
940
941 code = togglevar(argc, argv, &interactive, "Interactive mode");
942 }
943
944 /*
945 * Toggle gate-ftp mode, or set gate-ftp server
946 */
947 /*VARARGS*/
948 void
949 setgate(argc, argv)
950 int argc;
951 char *argv[];
952 {
953 static char gsbuf[MAXHOSTNAMELEN];
954
955 if (argc > 3) {
956 fprintf(ttyout,
957 "usage: %s [ on | off | gateserver [ port ] ]\n", argv[0]);
958 code = -1;
959 return;
960 } else if (argc < 2) {
961 gatemode = !gatemode;
962 } else {
963 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
964 gatemode = 1;
965 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
966 gatemode = 0;
967 else {
968 if (argc == 3)
969 gateport = strdup(argv[2]);
970 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
971 gsbuf[sizeof(gsbuf) - 1] = '\0';
972 gateserver = gsbuf;
973 gatemode = 1;
974 }
975 }
976 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
977 fprintf(ttyout,
978 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
979 gatemode = 0;
980 } else {
981 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
982 onoff(gatemode), *gateserver ? gateserver : "(none)",
983 gateport);
984 }
985 code = gatemode;
986 }
987
988 /*
989 * Toggle metacharacter interpretation on local file names.
990 */
991 /*VARARGS*/
992 void
993 setglob(argc, argv)
994 int argc;
995 char *argv[];
996 {
997
998 code = togglevar(argc, argv, &doglob, "Globbing");
999 }
1000
1001 /*
1002 * Toggle preserving modification times on retrieved files.
1003 */
1004 /*VARARGS*/
1005 void
1006 setpreserve(argc, argv)
1007 int argc;
1008 char *argv[];
1009 {
1010
1011 code = togglevar(argc, argv, &preserve, "Preserve modification times");
1012 }
1013
1014 /*
1015 * Set debugging mode on/off and/or set level of debugging.
1016 */
1017 /*VARARGS*/
1018 void
1019 setdebug(argc, argv)
1020 int argc;
1021 char *argv[];
1022 {
1023 if (argc > 2) {
1024 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n",
1025 argv[0]);
1026 code = -1;
1027 return;
1028 } else if (argc == 2) {
1029 if (strcasecmp(argv[1], "on") == 0)
1030 debug = 1;
1031 else if (strcasecmp(argv[1], "off") == 0)
1032 debug = 0;
1033 else {
1034 int val;
1035
1036 val = strsuftoi(argv[1]);
1037 if (val < 0) {
1038 fprintf(ttyout, "%s: bad debugging value.\n",
1039 argv[1]);
1040 code = -1;
1041 return;
1042 }
1043 debug = val;
1044 }
1045 } else
1046 debug = !debug;
1047 if (debug)
1048 options |= SO_DEBUG;
1049 else
1050 options &= ~SO_DEBUG;
1051 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
1052 code = debug > 0;
1053 }
1054
1055 /*
1056 * Set current working directory on remote machine.
1057 */
1058 void
1059 cd(argc, argv)
1060 int argc;
1061 char *argv[];
1062 {
1063 int r;
1064
1065 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
1066 argc > 2) {
1067 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
1068 code = -1;
1069 return;
1070 }
1071 r = command("CWD %s", argv[1]);
1072 if (r == ERROR && code == 500) {
1073 if (verbose)
1074 fputs("CWD command not recognized, trying XCWD.\n",
1075 ttyout);
1076 r = command("XCWD %s", argv[1]);
1077 }
1078 if (r == COMPLETE)
1079 dirchange = 1;
1080 }
1081
1082 /*
1083 * Set current working directory on local machine.
1084 */
1085 void
1086 lcd(argc, argv)
1087 int argc;
1088 char *argv[];
1089 {
1090 char buf[MAXPATHLEN];
1091 char *oldargv1;
1092
1093 if (argc < 2)
1094 argc++, argv[1] = home;
1095 if (argc != 2) {
1096 fprintf(ttyout, "usage: %s local-directory\n", argv[0]);
1097 code = -1;
1098 return;
1099 }
1100 oldargv1 = argv[1];
1101 if (!globulize(&argv[1])) {
1102 code = -1;
1103 return;
1104 }
1105 if (chdir(argv[1]) < 0) {
1106 warn("local: %s", argv[1]);
1107 code = -1;
1108 } else {
1109 if (getcwd(buf, sizeof(buf)) != NULL)
1110 fprintf(ttyout, "Local directory now %s\n", buf);
1111 else
1112 warn("getcwd: %s", argv[1]);
1113 code = 0;
1114 }
1115 if (oldargv1 != argv[1]) /* free up after globulize() */
1116 free(argv[1]);
1117 }
1118
1119 /*
1120 * Delete a single file.
1121 */
1122 void
1123 delete(argc, argv)
1124 int argc;
1125 char *argv[];
1126 {
1127
1128 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1129 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
1130 code = -1;
1131 return;
1132 }
1133 (void)command("DELE %s", argv[1]);
1134 }
1135
1136 /*
1137 * Delete multiple files.
1138 */
1139 void
1140 mdelete(argc, argv)
1141 int argc;
1142 char *argv[];
1143 {
1144 sig_t oldintr;
1145 int ointer;
1146 char *cp;
1147
1148 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1149 fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
1150 code = -1;
1151 return;
1152 }
1153 mname = argv[0];
1154 mflag = 1;
1155 oldintr = xsignal(SIGINT, mabort);
1156 (void)setjmp(jabort);
1157 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1158 if (*cp == '\0') {
1159 mflag = 0;
1160 continue;
1161 }
1162 if (mflag && confirm(argv[0], cp)) {
1163 (void)command("DELE %s", cp);
1164 if (!mflag && fromatty) {
1165 ointer = interactive;
1166 interactive = 1;
1167 if (confirm("Continue with", "mdelete")) {
1168 mflag++;
1169 }
1170 interactive = ointer;
1171 }
1172 }
1173 }
1174 (void)xsignal(SIGINT, oldintr);
1175 mflag = 0;
1176 }
1177
1178 /*
1179 * Rename a remote file.
1180 */
1181 void
1182 renamefile(argc, argv)
1183 int argc;
1184 char *argv[];
1185 {
1186
1187 if (argc < 2 && !another(&argc, &argv, "from-name"))
1188 goto usage;
1189 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1190 usage:
1191 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
1192 code = -1;
1193 return;
1194 }
1195 if (command("RNFR %s", argv[1]) == CONTINUE)
1196 (void)command("RNTO %s", argv[2]);
1197 }
1198
1199 /*
1200 * Get a directory listing of remote files.
1201 */
1202 void
1203 ls(argc, argv)
1204 int argc;
1205 char *argv[];
1206 {
1207 const char *cmd;
1208 char *oldargv2, *globargv2;
1209
1210 if (argc < 2)
1211 argc++, argv[1] = NULL;
1212 if (argc < 3)
1213 argc++, argv[2] = "-";
1214 if (argc > 3) {
1215 fprintf(ttyout, "usage: %s remote-directory local-file\n",
1216 argv[0]);
1217 code = -1;
1218 return;
1219 }
1220 cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
1221 oldargv2 = argv[2];
1222 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1223 code = -1;
1224 return;
1225 }
1226 globargv2 = argv[2];
1227 if (strcmp(argv[2], "-") && *argv[2] != '|')
1228 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1229 argv[2])) {
1230 code = -1;
1231 goto freels;
1232 }
1233 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1234 freels:
1235 if (argv[2] != globargv2) /* free up after globulize() */
1236 free(argv[2]);
1237 if (globargv2 != oldargv2)
1238 free(globargv2);
1239 }
1240
1241 /*
1242 * Get a directory listing of multiple remote files.
1243 */
1244 void
1245 mls(argc, argv)
1246 int argc;
1247 char *argv[];
1248 {
1249 sig_t oldintr;
1250 int ointer, i;
1251 int dolist;
1252 char mode[1], *dest, *odest;
1253
1254 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1255 goto usage;
1256 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1257 usage:
1258 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
1259 code = -1;
1260 return;
1261 }
1262 odest = dest = argv[argc - 1];
1263 argv[argc - 1] = NULL;
1264 if (strcmp(dest, "-") && *dest != '|')
1265 if (!globulize(&dest) ||
1266 !confirm("output to local-file:", dest)) {
1267 code = -1;
1268 return;
1269 }
1270 dolist = strcmp(argv[0], "mls");
1271 mname = argv[0];
1272 mflag = 1;
1273 oldintr = xsignal(SIGINT, mabort);
1274 (void)setjmp(jabort);
1275 for (i = 1; mflag && i < argc-1; ++i) {
1276 *mode = (i == 1) ? 'w' : 'a';
1277 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1278 0, 0);
1279 if (!mflag && fromatty) {
1280 ointer = interactive;
1281 interactive = 1;
1282 if (confirm("Continue with", argv[0])) {
1283 mflag ++;
1284 }
1285 interactive = ointer;
1286 }
1287 }
1288 (void)xsignal(SIGINT, oldintr);
1289 mflag = 0;
1290 if (dest != odest) /* free up after globulize() */
1291 free(dest);
1292 }
1293
1294 /*
1295 * Do a shell escape
1296 */
1297 /*ARGSUSED*/
1298 void
1299 shell(argc, argv)
1300 int argc;
1301 char *argv[];
1302 {
1303 pid_t pid;
1304 sig_t old1, old2;
1305 char shellnam[MAXPATHLEN], *shell, *namep;
1306 int wait_status;
1307
1308 old1 = xsignal(SIGINT, SIG_IGN);
1309 old2 = xsignal(SIGQUIT, SIG_IGN);
1310 if ((pid = fork()) == 0) {
1311 for (pid = 3; pid < 20; pid++)
1312 (void)close(pid);
1313 (void)xsignal(SIGINT, SIG_DFL);
1314 (void)xsignal(SIGQUIT, SIG_DFL);
1315 shell = getenv("SHELL");
1316 if (shell == NULL)
1317 shell = _PATH_BSHELL;
1318 namep = strrchr(shell, '/');
1319 if (namep == NULL)
1320 namep = shell;
1321 shellnam[0] = '-';
1322 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1323 shellnam[sizeof(shellnam) - 1] = '\0';
1324 if (strcmp(namep, "sh") != 0)
1325 shellnam[0] = '+';
1326 if (debug) {
1327 fputs(shell, ttyout);
1328 putc('\n', ttyout);
1329 }
1330 if (argc > 1) {
1331 execl(shell, shellnam, "-c", altarg, (char *)0);
1332 }
1333 else {
1334 execl(shell, shellnam, (char *)0);
1335 }
1336 warn("%s", shell);
1337 code = -1;
1338 exit(1);
1339 }
1340 if (pid > 0)
1341 while (wait(&wait_status) != pid)
1342 ;
1343 (void)xsignal(SIGINT, old1);
1344 (void)xsignal(SIGQUIT, old2);
1345 if (pid == -1) {
1346 warn("Try again later");
1347 code = -1;
1348 }
1349 else {
1350 code = 0;
1351 }
1352 }
1353
1354 /*
1355 * Send new user information (re-login)
1356 */
1357 void
1358 user(argc, argv)
1359 int argc;
1360 char *argv[];
1361 {
1362 char acct[80];
1363 int n, aflag = 0;
1364
1365 if (argc < 2)
1366 (void)another(&argc, &argv, "username");
1367 if (argc < 2 || argc > 4) {
1368 fprintf(ttyout, "usage: %s username [password] [account]\n",
1369 argv[0]);
1370 code = -1;
1371 return;
1372 }
1373 n = command("USER %s", argv[1]);
1374 if (n == CONTINUE) {
1375 if (argc < 3) {
1376 argv[2] = getpass("Password: ");
1377 argc++;
1378 }
1379 n = command("PASS %s", argv[2]);
1380 }
1381 if (n == CONTINUE) {
1382 if (argc < 4) {
1383 (void)fputs("Account: ", ttyout);
1384 (void)fflush(ttyout);
1385 if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) {
1386 fprintf(ttyout,
1387 "\nEOF received; login aborted.\n");
1388 code = -1;
1389 return;
1390 }
1391 acct[strlen(acct) - 1] = '\0';
1392 argv[3] = acct; argc++;
1393 }
1394 n = command("ACCT %s", argv[3]);
1395 aflag++;
1396 }
1397 if (n != COMPLETE) {
1398 fputs("Login failed.\n", ttyout);
1399 return;
1400 }
1401 if (!aflag && argc == 4) {
1402 (void)command("ACCT %s", argv[3]);
1403 }
1404 connected = -1;
1405 }
1406
1407 /*
1408 * Print working directory on remote machine.
1409 */
1410 /*VARARGS*/
1411 void
1412 pwd(argc, argv)
1413 int argc;
1414 char *argv[];
1415 {
1416 int oldverbose = verbose;
1417
1418 /*
1419 * If we aren't verbose, this doesn't do anything!
1420 */
1421 verbose = 1;
1422 if (command("PWD") == ERROR && code == 500) {
1423 fputs("PWD command not recognized, trying XPWD.\n", ttyout);
1424 (void)command("XPWD");
1425 }
1426 verbose = oldverbose;
1427 }
1428
1429 /*
1430 * Print working directory on local machine.
1431 */
1432 void
1433 lpwd(argc, argv)
1434 int argc;
1435 char *argv[];
1436 {
1437 char buf[MAXPATHLEN];
1438
1439 if (getcwd(buf, sizeof(buf)) != NULL)
1440 fprintf(ttyout, "Local directory %s\n", buf);
1441 else
1442 warn("getcwd");
1443 code = 0;
1444 }
1445
1446 /*
1447 * Make a directory.
1448 */
1449 void
1450 makedir(argc, argv)
1451 int argc;
1452 char *argv[];
1453 {
1454
1455 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1456 argc > 2) {
1457 fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1458 code = -1;
1459 return;
1460 }
1461 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1462 if (verbose)
1463 fputs("MKD command not recognized, trying XMKD.\n",
1464 ttyout);
1465 (void)command("XMKD %s", argv[1]);
1466 }
1467 }
1468
1469 /*
1470 * Remove a directory.
1471 */
1472 void
1473 removedir(argc, argv)
1474 int argc;
1475 char *argv[];
1476 {
1477
1478 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1479 argc > 2) {
1480 fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1481 code = -1;
1482 return;
1483 }
1484 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1485 if (verbose)
1486 fputs("RMD command not recognized, trying XRMD.\n",
1487 ttyout);
1488 (void)command("XRMD %s", argv[1]);
1489 }
1490 }
1491
1492 /*
1493 * Send a line, verbatim, to the remote machine.
1494 */
1495 void
1496 quote(argc, argv)
1497 int argc;
1498 char *argv[];
1499 {
1500
1501 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1502 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]);
1503 code = -1;
1504 return;
1505 }
1506 quote1("", argc, argv);
1507 }
1508
1509 /*
1510 * Send a SITE command to the remote machine. The line
1511 * is sent verbatim to the remote machine, except that the
1512 * word "SITE" is added at the front.
1513 */
1514 void
1515 site(argc, argv)
1516 int argc;
1517 char *argv[];
1518 {
1519
1520 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1521 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]);
1522 code = -1;
1523 return;
1524 }
1525 quote1("SITE ", argc, argv);
1526 }
1527
1528 /*
1529 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1530 * Send the result as a one-line command and get response.
1531 */
1532 void
1533 quote1(initial, argc, argv)
1534 const char *initial;
1535 int argc;
1536 char *argv[];
1537 {
1538 int i, len;
1539 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1540
1541 (void)strncpy(buf, initial, sizeof(buf) - 1);
1542 buf[sizeof(buf) - 1] = '\0';
1543 if (argc > 1) {
1544 len = strlen(buf);
1545 len += strlen(strncpy(&buf[len], argv[1],
1546 sizeof(buf) - len - 1));
1547 for (i = 2; i < argc && len < sizeof(buf); i++) {
1548 buf[len++] = ' ';
1549 len += strlen(strncpy(&buf[len], argv[i],
1550 sizeof(buf) - len) - 1);
1551 }
1552 }
1553 /* Ensure buf is NUL terminated */
1554 buf[sizeof(buf) - 1] = '\0';
1555 if (command("%s", buf) == PRELIM) {
1556 while (getreply(0) == PRELIM)
1557 continue;
1558 }
1559 }
1560
1561 void
1562 do_chmod(argc, argv)
1563 int argc;
1564 char *argv[];
1565 {
1566
1567 if (argc < 2 && !another(&argc, &argv, "mode"))
1568 goto usage;
1569 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1570 usage:
1571 fprintf(ttyout, "usage: %s mode file-name\n", argv[0]);
1572 code = -1;
1573 return;
1574 }
1575 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1576 }
1577
1578 void
1579 do_umask(argc, argv)
1580 int argc;
1581 char *argv[];
1582 {
1583 int oldverbose = verbose;
1584
1585 verbose = 1;
1586 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1587 verbose = oldverbose;
1588 }
1589
1590 void
1591 idlecmd(argc, argv)
1592 int argc;
1593 char *argv[];
1594 {
1595 int oldverbose = verbose;
1596
1597 verbose = 1;
1598 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1599 verbose = oldverbose;
1600 }
1601
1602 /*
1603 * Ask the other side for help.
1604 */
1605 void
1606 rmthelp(argc, argv)
1607 int argc;
1608 char *argv[];
1609 {
1610 int oldverbose = verbose;
1611
1612 verbose = 1;
1613 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1614 verbose = oldverbose;
1615 }
1616
1617 /*
1618 * Terminate session and exit.
1619 */
1620 /*VARARGS*/
1621 void
1622 quit(argc, argv)
1623 int argc;
1624 char *argv[];
1625 {
1626
1627 if (connected)
1628 disconnect(0, 0);
1629 pswitch(1);
1630 if (connected) {
1631 disconnect(0, 0);
1632 }
1633 exit(0);
1634 }
1635
1636 /*
1637 * Terminate session, but don't exit.
1638 */
1639 void
1640 disconnect(argc, argv)
1641 int argc;
1642 char *argv[];
1643 {
1644
1645 if (!connected)
1646 return;
1647 (void)command("QUIT");
1648 if (cout) {
1649 (void)fclose(cout);
1650 }
1651 cout = NULL;
1652 connected = 0;
1653 data = -1;
1654 if (!proxy) {
1655 macnum = 0;
1656 }
1657 }
1658
1659 void
1660 account(argc, argv)
1661 int argc;
1662 char *argv[];
1663 {
1664 char *ap;
1665
1666 if (argc > 2) {
1667 fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1668 code = -1;
1669 return;
1670 }
1671 else if (argc == 2)
1672 ap = argv[1];
1673 else
1674 ap = getpass("Account:");
1675 (void)command("ACCT %s", ap);
1676 }
1677
1678 jmp_buf abortprox;
1679
1680 void
1681 proxabort(notused)
1682 int notused;
1683 {
1684
1685 alarmtimer(0);
1686 if (!proxy) {
1687 pswitch(1);
1688 }
1689 if (connected) {
1690 proxflag = 1;
1691 }
1692 else {
1693 proxflag = 0;
1694 }
1695 pswitch(0);
1696 longjmp(abortprox, 1);
1697 }
1698
1699 void
1700 doproxy(argc, argv)
1701 int argc;
1702 char *argv[];
1703 {
1704 struct cmd *c;
1705 int cmdpos;
1706 sig_t oldintr;
1707
1708 if (argc < 2 && !another(&argc, &argv, "command")) {
1709 fprintf(ttyout, "usage: %s command\n", argv[0]);
1710 code = -1;
1711 return;
1712 }
1713 c = getcmd(argv[1]);
1714 if (c == (struct cmd *) -1) {
1715 fputs("?Ambiguous command.\n", ttyout);
1716 code = -1;
1717 return;
1718 }
1719 if (c == 0) {
1720 fputs("?Invalid command.\n", ttyout);
1721 code = -1;
1722 return;
1723 }
1724 if (!c->c_proxy) {
1725 fputs("?Invalid proxy command.\n", ttyout);
1726 code = -1;
1727 return;
1728 }
1729 if (setjmp(abortprox)) {
1730 code = -1;
1731 return;
1732 }
1733 oldintr = xsignal(SIGINT, proxabort);
1734 pswitch(1);
1735 if (c->c_conn && !connected) {
1736 fputs("Not connected.\n", ttyout);
1737 pswitch(0);
1738 (void)xsignal(SIGINT, oldintr);
1739 code = -1;
1740 return;
1741 }
1742 cmdpos = strcspn(line, " \t");
1743 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1744 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1745 (*c->c_handler)(argc-1, argv+1);
1746 if (connected) {
1747 proxflag = 1;
1748 }
1749 else {
1750 proxflag = 0;
1751 }
1752 pswitch(0);
1753 (void)xsignal(SIGINT, oldintr);
1754 }
1755
1756 void
1757 setcase(argc, argv)
1758 int argc;
1759 char *argv[];
1760 {
1761
1762 code = togglevar(argc, argv, &mcase, "Case mapping");
1763 }
1764
1765 void
1766 setcr(argc, argv)
1767 int argc;
1768 char *argv[];
1769 {
1770
1771 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1772 }
1773
1774 void
1775 setntrans(argc, argv)
1776 int argc;
1777 char *argv[];
1778 {
1779 if (argc == 1) {
1780 ntflag = 0;
1781 fputs("Ntrans off.\n", ttyout);
1782 code = ntflag;
1783 return;
1784 }
1785 ntflag++;
1786 code = ntflag;
1787 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1788 ntin[sizeof(ntin) - 1] = '\0';
1789 if (argc == 2) {
1790 ntout[0] = '\0';
1791 return;
1792 }
1793 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1794 ntout[sizeof(ntout) - 1] = '\0';
1795 }
1796
1797 char *
1798 dotrans(name)
1799 char *name;
1800 {
1801 static char new[MAXPATHLEN];
1802 char *cp1, *cp2 = new;
1803 int i, ostop, found;
1804
1805 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1806 continue;
1807 for (cp1 = name; *cp1; cp1++) {
1808 found = 0;
1809 for (i = 0; *(ntin + i) && i < 16; i++) {
1810 if (*cp1 == *(ntin + i)) {
1811 found++;
1812 if (i < ostop) {
1813 *cp2++ = *(ntout + i);
1814 }
1815 break;
1816 }
1817 }
1818 if (!found) {
1819 *cp2++ = *cp1;
1820 }
1821 }
1822 *cp2 = '\0';
1823 return (new);
1824 }
1825
1826 void
1827 setnmap(argc, argv)
1828 int argc;
1829 char *argv[];
1830 {
1831 char *cp;
1832
1833 if (argc == 1) {
1834 mapflag = 0;
1835 fputs("Nmap off.\n", ttyout);
1836 code = mapflag;
1837 return;
1838 }
1839 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1840 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]);
1841 code = -1;
1842 return;
1843 }
1844 mapflag = 1;
1845 code = 1;
1846 cp = strchr(altarg, ' ');
1847 if (proxy) {
1848 while(*++cp == ' ')
1849 continue;
1850 altarg = cp;
1851 cp = strchr(altarg, ' ');
1852 }
1853 *cp = '\0';
1854 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1855 while (*++cp == ' ')
1856 continue;
1857 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1858 }
1859
1860 char *
1861 domap(name)
1862 char *name;
1863 {
1864 static char new[MAXPATHLEN];
1865 char *cp1 = name, *cp2 = mapin;
1866 char *tp[9], *te[9];
1867 int i, toks[9], toknum = 0, match = 1;
1868
1869 for (i=0; i < 9; ++i) {
1870 toks[i] = 0;
1871 }
1872 while (match && *cp1 && *cp2) {
1873 switch (*cp2) {
1874 case '\\':
1875 if (*++cp2 != *cp1) {
1876 match = 0;
1877 }
1878 break;
1879 case '$':
1880 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1881 if (*cp1 != *(++cp2+1)) {
1882 toks[toknum = *cp2 - '1']++;
1883 tp[toknum] = cp1;
1884 while (*++cp1 && *(cp2+1)
1885 != *cp1);
1886 te[toknum] = cp1;
1887 }
1888 cp2++;
1889 break;
1890 }
1891 /* FALLTHROUGH */
1892 default:
1893 if (*cp2 != *cp1) {
1894 match = 0;
1895 }
1896 break;
1897 }
1898 if (match && *cp1) {
1899 cp1++;
1900 }
1901 if (match && *cp2) {
1902 cp2++;
1903 }
1904 }
1905 if (!match && *cp1) /* last token mismatch */
1906 {
1907 toks[toknum] = 0;
1908 }
1909 cp1 = new;
1910 *cp1 = '\0';
1911 cp2 = mapout;
1912 while (*cp2) {
1913 match = 0;
1914 switch (*cp2) {
1915 case '\\':
1916 if (*(cp2 + 1)) {
1917 *cp1++ = *++cp2;
1918 }
1919 break;
1920 case '[':
1921 LOOP:
1922 if (*++cp2 == '$' &&
1923 isdigit((unsigned char)*(cp2+1))) {
1924 if (*++cp2 == '0') {
1925 char *cp3 = name;
1926
1927 while (*cp3) {
1928 *cp1++ = *cp3++;
1929 }
1930 match = 1;
1931 }
1932 else if (toks[toknum = *cp2 - '1']) {
1933 char *cp3 = tp[toknum];
1934
1935 while (cp3 != te[toknum]) {
1936 *cp1++ = *cp3++;
1937 }
1938 match = 1;
1939 }
1940 }
1941 else {
1942 while (*cp2 && *cp2 != ',' &&
1943 *cp2 != ']') {
1944 if (*cp2 == '\\') {
1945 cp2++;
1946 }
1947 else if (*cp2 == '$' &&
1948 isdigit((unsigned char)*(cp2+1))) {
1949 if (*++cp2 == '0') {
1950 char *cp3 = name;
1951
1952 while (*cp3) {
1953 *cp1++ = *cp3++;
1954 }
1955 }
1956 else if (toks[toknum =
1957 *cp2 - '1']) {
1958 char *cp3=tp[toknum];
1959
1960 while (cp3 !=
1961 te[toknum]) {
1962 *cp1++ = *cp3++;
1963 }
1964 }
1965 }
1966 else if (*cp2) {
1967 *cp1++ = *cp2++;
1968 }
1969 }
1970 if (!*cp2) {
1971 fputs(
1972 "nmap: unbalanced brackets.\n",
1973 ttyout);
1974 return (name);
1975 }
1976 match = 1;
1977 cp2--;
1978 }
1979 if (match) {
1980 while (*++cp2 && *cp2 != ']') {
1981 if (*cp2 == '\\' && *(cp2 + 1)) {
1982 cp2++;
1983 }
1984 }
1985 if (!*cp2) {
1986 fputs(
1987 "nmap: unbalanced brackets.\n",
1988 ttyout);
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((unsigned char)*(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 code = togglevar(argc, argv, &passivemode,
2042 verbose ? "Passive mode" : NULL);
2043 }
2044
2045 void
2046 setsunique(argc, argv)
2047 int argc;
2048 char *argv[];
2049 {
2050
2051 code = togglevar(argc, argv, &sunique, "Store unique");
2052 }
2053
2054 void
2055 setrunique(argc, argv)
2056 int argc;
2057 char *argv[];
2058 {
2059
2060 code = togglevar(argc, argv, &runique, "Receive unique");
2061 }
2062
2063 int
2064 parserate(argc, argv, cmdlineopt)
2065 int argc;
2066 char *argv[];
2067 int cmdlineopt;
2068 {
2069 int dir, max, incr, showonly;
2070 sig_t oldusr1, oldusr2;
2071
2072 if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) {
2073 usage:
2074 if (cmdlineopt)
2075 fprintf(ttyout,
2076 "usage: %s (all|get|put),maximum[,increment]]\n",
2077 argv[0]);
2078 else
2079 fprintf(ttyout,
2080 "usage: %s (all|get|put) [maximum [increment]]\n",
2081 argv[0]);
2082 return -1;
2083 }
2084 dir = max = incr = showonly = 0;
2085 #define RATE_GET 1
2086 #define RATE_PUT 2
2087 #define RATE_ALL (RATE_GET | RATE_PUT)
2088
2089 if (strcasecmp(argv[1], "all") == 0)
2090 dir = RATE_ALL;
2091 else if (strcasecmp(argv[1], "get") == 0)
2092 dir = RATE_GET;
2093 else if (strcasecmp(argv[1], "put") == 0)
2094 dir = RATE_PUT;
2095 else
2096 goto usage;
2097
2098 if (argc >= 3) {
2099 if ((max = strsuftoi(argv[2])) < 0)
2100 goto usage;
2101 } else
2102 showonly = 1;
2103
2104 if (argc == 4) {
2105 if ((incr = strsuftoi(argv[3])) <= 0)
2106 goto usage;
2107 } else
2108 incr = DEFAULTINCR;
2109
2110 oldusr1 = xsignal(SIGUSR1, SIG_IGN);
2111 oldusr2 = xsignal(SIGUSR2, SIG_IGN);
2112 if (dir & RATE_GET) {
2113 if (!showonly) {
2114 rate_get = max;
2115 rate_get_incr = incr;
2116 }
2117 if (!cmdlineopt || verbose)
2118 fprintf(ttyout,
2119 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
2120 onoff(rate_get), rate_get, rate_get_incr);
2121 }
2122 if (dir & RATE_PUT) {
2123 if (!showonly) {
2124 rate_put = max;
2125 rate_put_incr = incr;
2126 }
2127 if (!cmdlineopt || verbose)
2128 fprintf(ttyout,
2129 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
2130 onoff(rate_put), rate_put, rate_put_incr);
2131 }
2132 (void)xsignal(SIGUSR1, oldusr1);
2133 (void)xsignal(SIGUSR2, oldusr2);
2134 return 0;
2135 }
2136
2137 void
2138 setrate(argc, argv)
2139 int argc;
2140 char *argv[];
2141 {
2142
2143 code = parserate(argc, argv, 0);
2144 }
2145
2146 /* change directory to parent directory */
2147 void
2148 cdup(argc, argv)
2149 int argc;
2150 char *argv[];
2151 {
2152 int r;
2153
2154 r = command("CDUP");
2155 if (r == ERROR && code == 500) {
2156 if (verbose)
2157 fputs("CDUP command not recognized, trying XCUP.\n",
2158 ttyout);
2159 r = command("XCUP");
2160 }
2161 if (r == COMPLETE)
2162 dirchange = 1;
2163 }
2164
2165 /*
2166 * Restart transfer at specific point
2167 */
2168 void
2169 restart(argc, argv)
2170 int argc;
2171 char *argv[];
2172 {
2173
2174 if (argc > 2) {
2175 fprintf(ttyout, "usage: %s [restart_point]\n", argv[0]);
2176 code = -1;
2177 return;
2178 }
2179 if (argc == 2) {
2180 off_t rp;
2181 char *ep;
2182
2183 #ifndef NO_QUAD
2184 rp = strtoq(argv[1], &ep, 10);
2185 #else
2186 rp = strtol(argv[1], &ep, 10);
2187 #endif
2188 if (rp < 0 || *ep != '\0')
2189 fprintf(ttyout, "restart: Invalid offset `%s'\n",
2190 argv[1]);
2191 else
2192 restart_point = rp;
2193 }
2194 if (restart_point == 0)
2195 fputs("No restart point defined.\n", ttyout);
2196 else
2197 fprintf(ttyout,
2198 #ifndef NO_QUAD
2199 "Restarting at %lld for next get, put or append\n",
2200 (long long)restart_point);
2201 #else
2202 "Restarting at %ld for next get, put or append\n",
2203 (long)restart_point);
2204 #endif
2205 }
2206
2207 /*
2208 * Show remote system type
2209 */
2210 void
2211 syst(argc, argv)
2212 int argc;
2213 char *argv[];
2214 {
2215
2216 (void)command("SYST");
2217 }
2218
2219 void
2220 macdef(argc, argv)
2221 int argc;
2222 char *argv[];
2223 {
2224 char *tmp;
2225 int c;
2226
2227 if (macnum == 16) {
2228 fputs("Limit of 16 macros have already been defined.\n",
2229 ttyout);
2230 code = -1;
2231 return;
2232 }
2233 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2234 fprintf(ttyout, "usage: %s macro_name\n", argv[0]);
2235 code = -1;
2236 return;
2237 }
2238 if (interactive)
2239 fputs(
2240 "Enter macro line by line, terminating it with a null line.\n",
2241 ttyout);
2242 (void)strncpy(macros[macnum].mac_name, argv[1],
2243 sizeof(macros[macnum].mac_name) - 1);
2244 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
2245 if (macnum == 0)
2246 macros[macnum].mac_start = macbuf;
2247 else
2248 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2249 tmp = macros[macnum].mac_start;
2250 while (tmp != macbuf+4096) {
2251 if ((c = getchar()) == EOF) {
2252 fputs("macdef: end of file encountered.\n", ttyout);
2253 code = -1;
2254 return;
2255 }
2256 if ((*tmp = c) == '\n') {
2257 if (tmp == macros[macnum].mac_start) {
2258 macros[macnum++].mac_end = tmp;
2259 code = 0;
2260 return;
2261 }
2262 if (*(tmp-1) == '\0') {
2263 macros[macnum++].mac_end = tmp - 1;
2264 code = 0;
2265 return;
2266 }
2267 *tmp = '\0';
2268 }
2269 tmp++;
2270 }
2271 while (1) {
2272 while ((c = getchar()) != '\n' && c != EOF)
2273 /* LOOP */;
2274 if (c == EOF || getchar() == '\n') {
2275 fputs("Macro not defined - 4K buffer exceeded.\n",
2276 ttyout);
2277 code = -1;
2278 return;
2279 }
2280 }
2281 }
2282
2283 /*
2284 * Get size of file on remote machine
2285 */
2286 void
2287 sizecmd(argc, argv)
2288 int argc;
2289 char *argv[];
2290 {
2291 off_t size;
2292
2293 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2294 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2295 code = -1;
2296 return;
2297 }
2298 size = remotesize(argv[1], 1);
2299 if (size != -1)
2300 fprintf(ttyout,
2301 #ifndef NO_QUAD
2302 "%s\t%lld\n", argv[1], (long long)size);
2303 #else
2304 "%s\t%ld\n", argv[1], (long)size);
2305 #endif
2306 code = size;
2307 }
2308
2309 /*
2310 * Get last modification time of file on remote machine
2311 */
2312 void
2313 modtime(argc, argv)
2314 int argc;
2315 char *argv[];
2316 {
2317 time_t mtime;
2318
2319 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2320 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2321 code = -1;
2322 return;
2323 }
2324 mtime = remotemodtime(argv[1], 1);
2325 if (mtime != -1)
2326 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
2327 code = mtime;
2328 }
2329
2330 /*
2331 * Show status on remote machine
2332 */
2333 void
2334 rmtstatus(argc, argv)
2335 int argc;
2336 char *argv[];
2337 {
2338
2339 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2340 }
2341
2342 /*
2343 * Get file if modtime is more recent than current file
2344 */
2345 void
2346 newer(argc, argv)
2347 int argc;
2348 char *argv[];
2349 {
2350
2351 if (getit(argc, argv, -1, "w"))
2352 fprintf(ttyout,
2353 "Local file \"%s\" is newer than remote file \"%s\".\n",
2354 argv[2], argv[1]);
2355 }
2356
2357 /*
2358 * Display one file through $PAGER (defaults to "more").
2359 */
2360 void
2361 page(argc, argv)
2362 int argc;
2363 char *argv[];
2364 {
2365 int ohash, orestart_point, overbose, len;
2366 char *p, *pager, *oldargv1;
2367
2368 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2369 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2370 code = -1;
2371 return;
2372 }
2373 oldargv1 = argv[1];
2374 if (!globulize(&argv[1])) {
2375 code = -1;
2376 return;
2377 }
2378 p = getenv("PAGER");
2379 if (p == NULL || p[0] == '\0')
2380 p = PAGER;
2381 len = strlen(p) + 2;
2382 pager = xmalloc(len);
2383 pager[0] = '|';
2384 strlcpy(pager + 1, p, len - 1);
2385
2386 ohash = hash;
2387 orestart_point = restart_point;
2388 overbose = verbose;
2389 hash = restart_point = verbose = 0;
2390 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2391 (void)free(pager);
2392 hash = ohash;
2393 restart_point = orestart_point;
2394 verbose = overbose;
2395 if (oldargv1 != argv[1]) /* free up after globulize() */
2396 free(argv[1]);
2397 }
2398
2399 /*
2400 * Set the socket send or receive buffer size.
2401 */
2402 void
2403 setxferbuf(argc, argv)
2404 int argc;
2405 char *argv[];
2406 {
2407 int size, dir;
2408
2409 if (argc != 2) {
2410 usage:
2411 fprintf(ttyout, "usage: %s size\n", argv[0]);
2412 code = -1;
2413 return;
2414 }
2415 if (strcasecmp(argv[0], "sndbuf") == 0)
2416 dir = RATE_PUT;
2417 else if (strcasecmp(argv[0], "rcvbuf") == 0)
2418 dir = RATE_GET;
2419 else if (strcasecmp(argv[0], "xferbuf") == 0)
2420 dir = RATE_ALL;
2421 else
2422 goto usage;
2423
2424 if ((size = strsuftoi(argv[1])) == -1)
2425 goto usage;
2426
2427 if (size == 0) {
2428 fprintf(ttyout, "%s: size must be positive.\n", argv[0]);
2429 goto usage;
2430 }
2431
2432 if (dir & RATE_PUT)
2433 sndbuf_size = size;
2434 if (dir & RATE_GET)
2435 rcvbuf_size = size;
2436 fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n",
2437 sndbuf_size, rcvbuf_size);
2438 }
2439
2440
2441 void
2442 setepsv4(argc, argv)
2443 int argc;
2444 char *argv[];
2445 {
2446
2447 code = togglevar(argc, argv, &epsv4,
2448 verbose ? "EPSV/EPRT on IPv4" : NULL);
2449 }
2450