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