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