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