cmds.c revision 1.46 1 /* $NetBSD: cmds.c,v 1.46 1999/01/24 02:39:29 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.46 1999/01/24 02:39:29 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 <limits.h>
96 #include <netdb.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #include <time.h>
101 #include <unistd.h>
102
103 #include "ftp_var.h"
104 #include "pathnames.h"
105
106 jmp_buf jabort;
107 char *mname;
108 char *home = "/";
109
110 struct types {
111 char *t_name;
112 char *t_mode;
113 int t_type;
114 char *t_arg;
115 } types[] = {
116 { "ascii", "A", TYPE_A, 0 },
117 { "binary", "I", TYPE_I, 0 },
118 { "image", "I", TYPE_I, 0 },
119 { "ebcdic", "E", TYPE_E, 0 },
120 { "tenex", "L", TYPE_L, bytename },
121 { NULL }
122 };
123
124 /*
125 * Set transfer type.
126 */
127 void
128 settype(argc, argv)
129 int argc;
130 char *argv[];
131 {
132 struct types *p;
133 int comret;
134
135 if (argc > 2) {
136 char *sep;
137
138 fprintf(ttyout, "usage: %s [", argv[0]);
139 sep = " ";
140 for (p = types; p->t_name; p++) {
141 fprintf(ttyout, "%s%s", sep, p->t_name);
142 sep = " | ";
143 }
144 fputs(" ]\n", ttyout);
145 code = -1;
146 return;
147 }
148 if (argc < 2) {
149 fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
150 code = 0;
151 return;
152 }
153 for (p = types; p->t_name; p++)
154 if (strcmp(argv[1], p->t_name) == 0)
155 break;
156 if (p->t_name == 0) {
157 fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
158 code = -1;
159 return;
160 }
161 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
162 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
163 else
164 comret = command("TYPE %s", p->t_mode);
165 if (comret == COMPLETE) {
166 (void)strcpy(typename, p->t_name);
167 curtype = type = p->t_type;
168 }
169 }
170
171 /*
172 * Internal form of settype; changes current type in use with server
173 * without changing our notion of the type for data transfers.
174 * Used to change to and from ascii for listings.
175 */
176 void
177 changetype(newtype, show)
178 int newtype, show;
179 {
180 struct types *p;
181 int comret, oldverbose = verbose;
182
183 if (newtype == 0)
184 newtype = TYPE_I;
185 if (newtype == curtype)
186 return;
187 if (debug == 0 && show == 0)
188 verbose = 0;
189 for (p = types; p->t_name; p++)
190 if (newtype == p->t_type)
191 break;
192 if (p->t_name == 0) {
193 warnx("internal error: unknown type %d.", newtype);
194 return;
195 }
196 if (newtype == TYPE_L && bytename[0] != '\0')
197 comret = command("TYPE %s %s", p->t_mode, bytename);
198 else
199 comret = command("TYPE %s", p->t_mode);
200 if (comret == COMPLETE)
201 curtype = newtype;
202 verbose = oldverbose;
203 }
204
205 char *stype[] = {
206 "type",
207 "",
208 0
209 };
210
211 /*
212 * Set binary transfer type.
213 */
214 /*VARARGS*/
215 void
216 setbinary(argc, argv)
217 int argc;
218 char *argv[];
219 {
220
221 stype[1] = "binary";
222 settype(2, stype);
223 }
224
225 /*
226 * Set ascii transfer type.
227 */
228 /*VARARGS*/
229 void
230 setascii(argc, argv)
231 int argc;
232 char *argv[];
233 {
234
235 stype[1] = "ascii";
236 settype(2, stype);
237 }
238
239 /*
240 * Set tenex transfer type.
241 */
242 /*VARARGS*/
243 void
244 settenex(argc, argv)
245 int argc;
246 char *argv[];
247 {
248
249 stype[1] = "tenex";
250 settype(2, stype);
251 }
252
253 /*
254 * Set file transfer mode.
255 */
256 /*ARGSUSED*/
257 void
258 setftmode(argc, argv)
259 int argc;
260 char *argv[];
261 {
262
263 fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
264 code = -1;
265 }
266
267 /*
268 * Set file transfer format.
269 */
270 /*ARGSUSED*/
271 void
272 setform(argc, argv)
273 int argc;
274 char *argv[];
275 {
276
277 fprintf(ttyout, "We only support %s format, sorry.\n", formname);
278 code = -1;
279 }
280
281 /*
282 * Set file transfer structure.
283 */
284 /*ARGSUSED*/
285 void
286 setstruct(argc, argv)
287 int argc;
288 char *argv[];
289 {
290
291 fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
292 code = -1;
293 }
294
295 /*
296 * Send a single file.
297 */
298 void
299 put(argc, argv)
300 int argc;
301 char *argv[];
302 {
303 char *cmd;
304 int loc = 0;
305 char *oldargv1, *oldargv2;
306
307 if (argc == 2) {
308 argc++;
309 argv[2] = argv[1];
310 loc++;
311 }
312 if (argc < 2 && !another(&argc, &argv, "local-file"))
313 goto usage;
314 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
315 usage:
316 fprintf(ttyout, "usage: %s local-file [ remote-file ]\n",
317 argv[0]);
318 code = -1;
319 return;
320 }
321 oldargv1 = argv[1];
322 oldargv2 = argv[2];
323 if (!globulize(&argv[1])) {
324 code = -1;
325 return;
326 }
327 /*
328 * If "globulize" modifies argv[1], and argv[2] is a copy of
329 * the old argv[1], make it a copy of the new argv[1].
330 */
331 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
332 argv[2] = argv[1];
333 }
334 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
335 if (loc && ntflag) {
336 argv[2] = dotrans(argv[2]);
337 }
338 if (loc && mapflag) {
339 argv[2] = domap(argv[2]);
340 }
341 sendrequest(cmd, argv[1], argv[2],
342 argv[1] != oldargv1 || argv[2] != oldargv2);
343 if (oldargv1 != argv[1]) /* free up after globulize() */
344 free(argv[1]);
345 }
346
347 /*
348 * Send multiple files.
349 */
350 void
351 mput(argc, argv)
352 int argc;
353 char *argv[];
354 {
355 int i;
356 sig_t oldintr;
357 int ointer;
358 char *tp;
359
360 if (argc < 2 && !another(&argc, &argv, "local-files")) {
361 fprintf(ttyout, "usage: %s local-files\n", argv[0]);
362 code = -1;
363 return;
364 }
365 mname = argv[0];
366 mflag = 1;
367 oldintr = signal(SIGINT, mabort);
368 (void)setjmp(jabort);
369 if (proxy) {
370 char *cp, *tp2, tmpbuf[MAXPATHLEN];
371
372 while ((cp = remglob(argv, 0, NULL)) != NULL) {
373 if (*cp == '\0') {
374 mflag = 0;
375 continue;
376 }
377 if (mflag && confirm(argv[0], cp)) {
378 tp = cp;
379 if (mcase) {
380 while (*tp &&
381 !islower((unsigned char)*tp)) {
382 tp++;
383 }
384 if (!*tp) {
385 tp = cp;
386 tp2 = tmpbuf;
387 while ((*tp2 = *tp) != '\0') {
388 if (isupper((unsigned char)*tp2)) {
389 *tp2 =
390 tolower(*tp2);
391 }
392 tp++;
393 tp2++;
394 }
395 }
396 tp = tmpbuf;
397 }
398 if (ntflag) {
399 tp = dotrans(tp);
400 }
401 if (mapflag) {
402 tp = domap(tp);
403 }
404 sendrequest((sunique) ? "STOU" : "STOR",
405 cp, tp, cp != tp || !interactive);
406 if (!mflag && fromatty) {
407 ointer = interactive;
408 interactive = 1;
409 if (confirm("Continue with", "mput")) {
410 mflag++;
411 }
412 interactive = ointer;
413 }
414 }
415 }
416 (void)signal(SIGINT, oldintr);
417 mflag = 0;
418 return;
419 }
420 for (i = 1; i < argc; i++) {
421 char **cpp;
422 glob_t gl;
423 int flags;
424
425 if (!doglob) {
426 if (mflag && confirm(argv[0], argv[i])) {
427 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
428 tp = (mapflag) ? domap(tp) : tp;
429 sendrequest((sunique) ? "STOU" : "STOR",
430 argv[i], tp, tp != argv[i] || !interactive);
431 if (!mflag && fromatty) {
432 ointer = interactive;
433 interactive = 1;
434 if (confirm("Continue with", "mput")) {
435 mflag++;
436 }
437 interactive = ointer;
438 }
439 }
440 continue;
441 }
442
443 memset(&gl, 0, sizeof(gl));
444 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
445 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
446 warnx("%s: not found", argv[i]);
447 globfree(&gl);
448 continue;
449 }
450 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
451 if (mflag && confirm(argv[0], *cpp)) {
452 tp = (ntflag) ? dotrans(*cpp) : *cpp;
453 tp = (mapflag) ? domap(tp) : tp;
454 sendrequest((sunique) ? "STOU" : "STOR",
455 *cpp, tp, *cpp != tp || !interactive);
456 if (!mflag && fromatty) {
457 ointer = interactive;
458 interactive = 1;
459 if (confirm("Continue with", "mput")) {
460 mflag++;
461 }
462 interactive = ointer;
463 }
464 }
465 }
466 globfree(&gl);
467 }
468 (void)signal(SIGINT, oldintr);
469 mflag = 0;
470 }
471
472 void
473 reget(argc, argv)
474 int argc;
475 char *argv[];
476 {
477
478 (void)getit(argc, argv, 1, "r+w");
479 }
480
481 void
482 get(argc, argv)
483 int argc;
484 char *argv[];
485 {
486
487 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
488 }
489
490 /*
491 * Receive one file.
492 */
493 int
494 getit(argc, argv, restartit, mode)
495 int argc;
496 char *argv[];
497 int restartit;
498 const char *mode;
499 {
500 int loc = 0;
501 int rval = 0;
502 char *oldargv1, *oldargv2, *globargv2;
503
504 if (argc == 2) {
505 argc++;
506 argv[2] = argv[1];
507 loc++;
508 }
509 if (argc < 2 && !another(&argc, &argv, "remote-file"))
510 goto usage;
511 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
512 usage:
513 fprintf(ttyout, "usage: %s remote-file [ local-file ]\n",
514 argv[0]);
515 code = -1;
516 return (0);
517 }
518 oldargv1 = argv[1];
519 oldargv2 = argv[2];
520 if (!globulize(&argv[2])) {
521 code = -1;
522 return (0);
523 }
524 globargv2 = argv[2];
525 if (loc && mcase) {
526 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
527
528 while (*tp && !islower((unsigned char)*tp)) {
529 tp++;
530 }
531 if (!*tp) {
532 tp = argv[2];
533 tp2 = tmpbuf;
534 while ((*tp2 = *tp) != '\0') {
535 if (isupper((unsigned char)*tp2)) {
536 *tp2 = tolower(*tp2);
537 }
538 tp++;
539 tp2++;
540 }
541 argv[2] = tmpbuf;
542 }
543 }
544 if (loc && ntflag)
545 argv[2] = dotrans(argv[2]);
546 if (loc && mapflag)
547 argv[2] = domap(argv[2]);
548 if (restartit) {
549 struct stat stbuf;
550 int ret;
551
552 ret = stat(argv[2], &stbuf);
553 if (restartit == 1) {
554 if (ret < 0) {
555 warn("local: %s", argv[2]);
556 goto freegetit;
557 }
558 restart_point = stbuf.st_size;
559 } else {
560 if (ret == 0) {
561 time_t mtime;
562
563 mtime = remotemodtime(argv[1], 0);
564 if (mtime == -1)
565 goto freegetit;
566 if (stbuf.st_mtime >= mtime) {
567 rval = 1;
568 goto freegetit;
569 }
570 }
571 }
572 }
573
574 recvrequest("RETR", argv[2], argv[1], mode,
575 argv[1] != oldargv1 || argv[2] != oldargv2, loc);
576 restart_point = 0;
577 freegetit:
578 if (oldargv2 != globargv2) /* free up after globulize() */
579 free(globargv2);
580 return (rval);
581 }
582
583 /* ARGSUSED */
584 void
585 mabort(signo)
586 int signo;
587 {
588 int ointer, oconf;
589
590 alarmtimer(0);
591 putc('\n', 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 if (hash)
846 progress = 0;
847 code = hash;
848 }
849
850 /*
851 * Turn on printing of server echo's.
852 */
853 /*VARARGS*/
854 void
855 setverbose(argc, argv)
856 int argc;
857 char *argv[];
858 {
859
860 code = togglevar(argc, argv, &verbose, "Verbose mode");
861 }
862
863 /*
864 * Toggle PORT cmd use before each data connection.
865 */
866 /*VARARGS*/
867 void
868 setport(argc, argv)
869 int argc;
870 char *argv[];
871 {
872
873 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
874 }
875
876 /*
877 * Toggle transfer progress bar.
878 */
879 /*VARARGS*/
880 void
881 setprogress(argc, argv)
882 int argc;
883 char *argv[];
884 {
885
886 code = togglevar(argc, argv, &progress, "Progress bar");
887 if (progress)
888 hash = 0;
889 }
890
891 /*
892 * Turn on interactive prompting during mget, mput, and mdelete.
893 */
894 /*VARARGS*/
895 void
896 setprompt(argc, argv)
897 int argc;
898 char *argv[];
899 {
900
901 code = togglevar(argc, argv, &interactive, "Interactive mode");
902 }
903
904 /*
905 * Toggle gate-ftp mode, or set gate-ftp server
906 */
907 /*VARARGS*/
908 void
909 setgate(argc, argv)
910 int argc;
911 char *argv[];
912 {
913 static char gsbuf[MAXHOSTNAMELEN];
914
915 if (argc > 3) {
916 fprintf(ttyout,
917 "usage: %s [ on | off | gateserver [ port ] ]\n", argv[0]);
918 code = -1;
919 return;
920 } else if (argc < 2) {
921 gatemode = !gatemode;
922 } else {
923 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
924 gatemode = 1;
925 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
926 gatemode = 0;
927 else {
928 if (argc == 3) {
929 char *ep;
930 long port;
931
932 port = strtol(argv[2], &ep, 10);
933 if (port < 0 || port > MAX_IN_PORT_T ||
934 *ep != '\0') {
935 fprintf(ttyout,
936 "%s: bad gateport value.\n",
937 argv[2]);
938 code = -1;
939 return;
940 }
941 gateport = htons(port);
942 }
943 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
944 gsbuf[sizeof(gsbuf) - 1] = '\0';
945 gateserver = gsbuf;
946 gatemode = 1;
947 }
948 }
949 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
950 fprintf(ttyout,
951 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
952 gatemode = 0;
953 } else {
954 fprintf(ttyout, "Gate ftp: %s, server %s, port %d.\n",
955 onoff(gatemode), *gateserver ? gateserver : "(none)",
956 ntohs(gateport));
957 }
958 code = gatemode;
959 }
960
961 /*
962 * Toggle metacharacter interpretation on local file names.
963 */
964 /*VARARGS*/
965 void
966 setglob(argc, argv)
967 int argc;
968 char *argv[];
969 {
970
971 code = togglevar(argc, argv, &doglob, "Globbing");
972 }
973
974 /*
975 * Toggle preserving modification times on retrieved files.
976 */
977 /*VARARGS*/
978 void
979 setpreserve(argc, argv)
980 int argc;
981 char *argv[];
982 {
983
984 code = togglevar(argc, argv, &preserve, "Preserve modification times");
985 }
986
987 /*
988 * Set debugging mode on/off and/or set level of debugging.
989 */
990 /*VARARGS*/
991 void
992 setdebug(argc, argv)
993 int argc;
994 char *argv[];
995 {
996 if (argc > 2) {
997 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n",
998 argv[0]);
999 code = -1;
1000 return;
1001 } else if (argc == 2) {
1002 if (strcasecmp(argv[1], "on") == 0)
1003 debug = 1;
1004 else if (strcasecmp(argv[1], "off") == 0)
1005 debug = 0;
1006 else {
1007 char *ep;
1008 long val;
1009
1010 val = strtol(argv[1], &ep, 10);
1011 if (val < 0 || val > INT_MAX || *ep != '\0') {
1012 fprintf(ttyout, "%s: bad debugging value.\n",
1013 argv[1]);
1014 code = -1;
1015 return;
1016 }
1017 debug = (int)val;
1018 }
1019 } else
1020 debug = !debug;
1021 if (debug)
1022 options |= SO_DEBUG;
1023 else
1024 options &= ~SO_DEBUG;
1025 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
1026 code = debug > 0;
1027 }
1028
1029 /*
1030 * Set current working directory on remote machine.
1031 */
1032 void
1033 cd(argc, argv)
1034 int argc;
1035 char *argv[];
1036 {
1037 int r;
1038
1039 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
1040 argc > 2) {
1041 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
1042 code = -1;
1043 return;
1044 }
1045 r = command("CWD %s", argv[1]);
1046 if (r == ERROR && code == 500) {
1047 if (verbose)
1048 fputs("CWD command not recognized, trying XCWD.\n",
1049 ttyout);
1050 r = command("XCWD %s", argv[1]);
1051 }
1052 if (r == COMPLETE)
1053 dirchange = 1;
1054 }
1055
1056 /*
1057 * Set current working directory on local machine.
1058 */
1059 void
1060 lcd(argc, argv)
1061 int argc;
1062 char *argv[];
1063 {
1064 char buf[MAXPATHLEN];
1065 char *oldargv1;
1066
1067 if (argc < 2)
1068 argc++, argv[1] = home;
1069 if (argc != 2) {
1070 fprintf(ttyout, "usage: %s local-directory\n", argv[0]);
1071 code = -1;
1072 return;
1073 }
1074 oldargv1 = argv[1];
1075 if (!globulize(&argv[1])) {
1076 code = -1;
1077 return;
1078 }
1079 if (chdir(argv[1]) < 0) {
1080 warn("local: %s", argv[1]);
1081 code = -1;
1082 } else {
1083 if (getcwd(buf, sizeof(buf)) != NULL)
1084 fprintf(ttyout, "Local directory now %s\n", buf);
1085 else
1086 warn("getcwd: %s", argv[1]);
1087 code = 0;
1088 }
1089 if (oldargv1 != argv[1]) /* free up after globulize() */
1090 free(argv[1]);
1091 }
1092
1093 /*
1094 * Delete a single file.
1095 */
1096 void
1097 delete(argc, argv)
1098 int argc;
1099 char *argv[];
1100 {
1101
1102 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1103 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
1104 code = -1;
1105 return;
1106 }
1107 (void)command("DELE %s", argv[1]);
1108 }
1109
1110 /*
1111 * Delete multiple files.
1112 */
1113 void
1114 mdelete(argc, argv)
1115 int argc;
1116 char *argv[];
1117 {
1118 sig_t oldintr;
1119 int ointer;
1120 char *cp;
1121
1122 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1123 fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
1124 code = -1;
1125 return;
1126 }
1127 mname = argv[0];
1128 mflag = 1;
1129 oldintr = signal(SIGINT, mabort);
1130 (void)setjmp(jabort);
1131 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1132 if (*cp == '\0') {
1133 mflag = 0;
1134 continue;
1135 }
1136 if (mflag && confirm(argv[0], cp)) {
1137 (void)command("DELE %s", cp);
1138 if (!mflag && fromatty) {
1139 ointer = interactive;
1140 interactive = 1;
1141 if (confirm("Continue with", "mdelete")) {
1142 mflag++;
1143 }
1144 interactive = ointer;
1145 }
1146 }
1147 }
1148 (void)signal(SIGINT, oldintr);
1149 mflag = 0;
1150 }
1151
1152 /*
1153 * Rename a remote file.
1154 */
1155 void
1156 renamefile(argc, argv)
1157 int argc;
1158 char *argv[];
1159 {
1160
1161 if (argc < 2 && !another(&argc, &argv, "from-name"))
1162 goto usage;
1163 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1164 usage:
1165 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
1166 code = -1;
1167 return;
1168 }
1169 if (command("RNFR %s", argv[1]) == CONTINUE)
1170 (void)command("RNTO %s", argv[2]);
1171 }
1172
1173 /*
1174 * Get a directory listing of remote files.
1175 */
1176 void
1177 ls(argc, argv)
1178 int argc;
1179 char *argv[];
1180 {
1181 const char *cmd;
1182 char *oldargv2, *globargv2;
1183
1184 if (argc < 2)
1185 argc++, argv[1] = NULL;
1186 if (argc < 3)
1187 argc++, argv[2] = "-";
1188 if (argc > 3) {
1189 fprintf(ttyout, "usage: %s remote-directory local-file\n",
1190 argv[0]);
1191 code = -1;
1192 return;
1193 }
1194 cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
1195 oldargv2 = argv[2];
1196 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1197 code = -1;
1198 return;
1199 }
1200 globargv2 = argv[2];
1201 if (strcmp(argv[2], "-") && *argv[2] != '|')
1202 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1203 argv[2])) {
1204 code = -1;
1205 goto freels;
1206 }
1207 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1208 freels:
1209 if (argv[2] != globargv2) /* free up after globulize() */
1210 free(argv[2]);
1211 if (globargv2 != oldargv2)
1212 free(globargv2);
1213 }
1214
1215 /*
1216 * Get a directory listing of multiple remote files.
1217 */
1218 void
1219 mls(argc, argv)
1220 int argc;
1221 char *argv[];
1222 {
1223 sig_t oldintr;
1224 int ointer, i;
1225 int dolist;
1226 char mode[1], *dest, *odest;
1227
1228 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1229 goto usage;
1230 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1231 usage:
1232 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
1233 code = -1;
1234 return;
1235 }
1236 odest = dest = argv[argc - 1];
1237 argv[argc - 1] = NULL;
1238 if (strcmp(dest, "-") && *dest != '|')
1239 if (!globulize(&dest) ||
1240 !confirm("output to local-file:", dest)) {
1241 code = -1;
1242 return;
1243 }
1244 dolist = strcmp(argv[0], "mls");
1245 mname = argv[0];
1246 mflag = 1;
1247 oldintr = signal(SIGINT, mabort);
1248 (void)setjmp(jabort);
1249 for (i = 1; mflag && i < argc-1; ++i) {
1250 *mode = (i == 1) ? 'w' : 'a';
1251 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1252 0, 0);
1253 if (!mflag && fromatty) {
1254 ointer = interactive;
1255 interactive = 1;
1256 if (confirm("Continue with", argv[0])) {
1257 mflag ++;
1258 }
1259 interactive = ointer;
1260 }
1261 }
1262 (void)signal(SIGINT, oldintr);
1263 mflag = 0;
1264 if (dest != odest) /* free up after globulize() */
1265 free(dest);
1266 }
1267
1268 /*
1269 * Do a shell escape
1270 */
1271 /*ARGSUSED*/
1272 void
1273 shell(argc, argv)
1274 int argc;
1275 char *argv[];
1276 {
1277 pid_t pid;
1278 sig_t old1, old2;
1279 char shellnam[MAXPATHLEN], *shell, *namep;
1280 int wait_status;
1281
1282 old1 = signal (SIGINT, SIG_IGN);
1283 old2 = signal (SIGQUIT, SIG_IGN);
1284 if ((pid = fork()) == 0) {
1285 for (pid = 3; pid < 20; pid++)
1286 (void)close(pid);
1287 (void)signal(SIGINT, SIG_DFL);
1288 (void)signal(SIGQUIT, SIG_DFL);
1289 shell = getenv("SHELL");
1290 if (shell == NULL)
1291 shell = _PATH_BSHELL;
1292 namep = strrchr(shell, '/');
1293 if (namep == NULL)
1294 namep = shell;
1295 shellnam[0] = '-';
1296 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1297 shellnam[sizeof(shellnam) - 1] = '\0';
1298 if (strcmp(namep, "sh") != 0)
1299 shellnam[0] = '+';
1300 if (debug) {
1301 fputs(shell, ttyout);
1302 putc('\n', 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("%s", 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 code = -1;
1686 return;
1687 }
1688 if (c == 0) {
1689 fputs("?Invalid command.\n", ttyout);
1690 code = -1;
1691 return;
1692 }
1693 if (!c->c_proxy) {
1694 fputs("?Invalid proxy command.\n", ttyout);
1695 code = -1;
1696 return;
1697 }
1698 if (setjmp(abortprox)) {
1699 code = -1;
1700 return;
1701 }
1702 oldintr = signal(SIGINT, proxabort);
1703 pswitch(1);
1704 if (c->c_conn && !connected) {
1705 fputs("Not connected.\n", ttyout);
1706 pswitch(0);
1707 (void)signal(SIGINT, oldintr);
1708 code = -1;
1709 return;
1710 }
1711 cmdpos = strcspn(line, " \t");
1712 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1713 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1714 (*c->c_handler)(argc-1, argv+1);
1715 if (connected) {
1716 proxflag = 1;
1717 }
1718 else {
1719 proxflag = 0;
1720 }
1721 pswitch(0);
1722 (void)signal(SIGINT, oldintr);
1723 }
1724
1725 void
1726 setcase(argc, argv)
1727 int argc;
1728 char *argv[];
1729 {
1730
1731 code = togglevar(argc, argv, &mcase, "Case mapping");
1732 }
1733
1734 void
1735 setcr(argc, argv)
1736 int argc;
1737 char *argv[];
1738 {
1739
1740 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1741 }
1742
1743 void
1744 setntrans(argc, argv)
1745 int argc;
1746 char *argv[];
1747 {
1748 if (argc == 1) {
1749 ntflag = 0;
1750 fputs("Ntrans off.\n", ttyout);
1751 code = ntflag;
1752 return;
1753 }
1754 ntflag++;
1755 code = ntflag;
1756 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1757 ntin[sizeof(ntin) - 1] = '\0';
1758 if (argc == 2) {
1759 ntout[0] = '\0';
1760 return;
1761 }
1762 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1763 ntout[sizeof(ntout) - 1] = '\0';
1764 }
1765
1766 char *
1767 dotrans(name)
1768 char *name;
1769 {
1770 static char new[MAXPATHLEN];
1771 char *cp1, *cp2 = new;
1772 int i, ostop, found;
1773
1774 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1775 continue;
1776 for (cp1 = name; *cp1; cp1++) {
1777 found = 0;
1778 for (i = 0; *(ntin + i) && i < 16; i++) {
1779 if (*cp1 == *(ntin + i)) {
1780 found++;
1781 if (i < ostop) {
1782 *cp2++ = *(ntout + i);
1783 }
1784 break;
1785 }
1786 }
1787 if (!found) {
1788 *cp2++ = *cp1;
1789 }
1790 }
1791 *cp2 = '\0';
1792 return (new);
1793 }
1794
1795 void
1796 setnmap(argc, argv)
1797 int argc;
1798 char *argv[];
1799 {
1800 char *cp;
1801
1802 if (argc == 1) {
1803 mapflag = 0;
1804 fputs("Nmap off.\n", ttyout);
1805 code = mapflag;
1806 return;
1807 }
1808 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1809 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]);
1810 code = -1;
1811 return;
1812 }
1813 mapflag = 1;
1814 code = 1;
1815 cp = strchr(altarg, ' ');
1816 if (proxy) {
1817 while(*++cp == ' ')
1818 continue;
1819 altarg = cp;
1820 cp = strchr(altarg, ' ');
1821 }
1822 *cp = '\0';
1823 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1824 while (*++cp == ' ')
1825 continue;
1826 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1827 }
1828
1829 char *
1830 domap(name)
1831 char *name;
1832 {
1833 static char new[MAXPATHLEN];
1834 char *cp1 = name, *cp2 = mapin;
1835 char *tp[9], *te[9];
1836 int i, toks[9], toknum = 0, match = 1;
1837
1838 for (i=0; i < 9; ++i) {
1839 toks[i] = 0;
1840 }
1841 while (match && *cp1 && *cp2) {
1842 switch (*cp2) {
1843 case '\\':
1844 if (*++cp2 != *cp1) {
1845 match = 0;
1846 }
1847 break;
1848 case '$':
1849 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1850 if (*cp1 != *(++cp2+1)) {
1851 toks[toknum = *cp2 - '1']++;
1852 tp[toknum] = cp1;
1853 while (*++cp1 && *(cp2+1)
1854 != *cp1);
1855 te[toknum] = cp1;
1856 }
1857 cp2++;
1858 break;
1859 }
1860 /* FALLTHROUGH */
1861 default:
1862 if (*cp2 != *cp1) {
1863 match = 0;
1864 }
1865 break;
1866 }
1867 if (match && *cp1) {
1868 cp1++;
1869 }
1870 if (match && *cp2) {
1871 cp2++;
1872 }
1873 }
1874 if (!match && *cp1) /* last token mismatch */
1875 {
1876 toks[toknum] = 0;
1877 }
1878 cp1 = new;
1879 *cp1 = '\0';
1880 cp2 = mapout;
1881 while (*cp2) {
1882 match = 0;
1883 switch (*cp2) {
1884 case '\\':
1885 if (*(cp2 + 1)) {
1886 *cp1++ = *++cp2;
1887 }
1888 break;
1889 case '[':
1890 LOOP:
1891 if (*++cp2 == '$' &&
1892 isdigit((unsigned char)*(cp2+1))) {
1893 if (*++cp2 == '0') {
1894 char *cp3 = name;
1895
1896 while (*cp3) {
1897 *cp1++ = *cp3++;
1898 }
1899 match = 1;
1900 }
1901 else if (toks[toknum = *cp2 - '1']) {
1902 char *cp3 = tp[toknum];
1903
1904 while (cp3 != te[toknum]) {
1905 *cp1++ = *cp3++;
1906 }
1907 match = 1;
1908 }
1909 }
1910 else {
1911 while (*cp2 && *cp2 != ',' &&
1912 *cp2 != ']') {
1913 if (*cp2 == '\\') {
1914 cp2++;
1915 }
1916 else if (*cp2 == '$' &&
1917 isdigit((unsigned char)*(cp2+1))) {
1918 if (*++cp2 == '0') {
1919 char *cp3 = name;
1920
1921 while (*cp3) {
1922 *cp1++ = *cp3++;
1923 }
1924 }
1925 else if (toks[toknum =
1926 *cp2 - '1']) {
1927 char *cp3=tp[toknum];
1928
1929 while (cp3 !=
1930 te[toknum]) {
1931 *cp1++ = *cp3++;
1932 }
1933 }
1934 }
1935 else if (*cp2) {
1936 *cp1++ = *cp2++;
1937 }
1938 }
1939 if (!*cp2) {
1940 fputs(
1941 "nmap: unbalanced brackets.\n",
1942 ttyout);
1943 return (name);
1944 }
1945 match = 1;
1946 cp2--;
1947 }
1948 if (match) {
1949 while (*++cp2 && *cp2 != ']') {
1950 if (*cp2 == '\\' && *(cp2 + 1)) {
1951 cp2++;
1952 }
1953 }
1954 if (!*cp2) {
1955 fputs(
1956 "nmap: unbalanced brackets.\n",
1957 ttyout);
1958 return (name);
1959 }
1960 break;
1961 }
1962 switch (*++cp2) {
1963 case ',':
1964 goto LOOP;
1965 case ']':
1966 break;
1967 default:
1968 cp2--;
1969 goto LOOP;
1970 }
1971 break;
1972 case '$':
1973 if (isdigit((unsigned char)*(cp2 + 1))) {
1974 if (*++cp2 == '0') {
1975 char *cp3 = name;
1976
1977 while (*cp3) {
1978 *cp1++ = *cp3++;
1979 }
1980 }
1981 else if (toks[toknum = *cp2 - '1']) {
1982 char *cp3 = tp[toknum];
1983
1984 while (cp3 != te[toknum]) {
1985 *cp1++ = *cp3++;
1986 }
1987 }
1988 break;
1989 }
1990 /* intentional drop through */
1991 default:
1992 *cp1++ = *cp2;
1993 break;
1994 }
1995 cp2++;
1996 }
1997 *cp1 = '\0';
1998 if (!*new) {
1999 return (name);
2000 }
2001 return (new);
2002 }
2003
2004 void
2005 setpassive(argc, argv)
2006 int argc;
2007 char *argv[];
2008 {
2009
2010 code = togglevar(argc, argv, &passivemode,
2011 verbose ? "Passive mode" : NULL);
2012 }
2013
2014 void
2015 setsunique(argc, argv)
2016 int argc;
2017 char *argv[];
2018 {
2019
2020 code = togglevar(argc, argv, &sunique, "Store unique");
2021 }
2022
2023 void
2024 setrunique(argc, argv)
2025 int argc;
2026 char *argv[];
2027 {
2028
2029 code = togglevar(argc, argv, &runique, "Receive unique");
2030 }
2031
2032 /* change directory to parent directory */
2033 void
2034 cdup(argc, argv)
2035 int argc;
2036 char *argv[];
2037 {
2038 int r;
2039
2040 r = command("CDUP");
2041 if (r == ERROR && code == 500) {
2042 if (verbose)
2043 fputs("CDUP command not recognized, trying XCUP.\n",
2044 ttyout);
2045 r = command("XCUP");
2046 }
2047 if (r == COMPLETE)
2048 dirchange = 1;
2049 }
2050
2051 /*
2052 * Restart transfer at specific point
2053 */
2054 void
2055 restart(argc, argv)
2056 int argc;
2057 char *argv[];
2058 {
2059
2060 if (argc > 2) {
2061 fprintf(ttyout, "usage: %s [restart_point]\n", argv[0]);
2062 code = -1;
2063 return;
2064 }
2065 if (argc == 2) {
2066 #ifndef NO_QUAD
2067 quad_t rp;
2068 #else
2069 long rp;
2070 #endif
2071 char *ep;
2072
2073 #ifndef NO_QUAD
2074 rp = strtoq(argv[1], &ep, 10);
2075 #else
2076 rp = strtol(argv[1], &ep, 10);
2077 #endif
2078 if (rp < 0 || *ep != '\0')
2079 fprintf(ttyout, "restart: Invalid offset `%s'\n",
2080 argv[1]);
2081 else
2082 restart_point = rp;
2083 }
2084 if (restart_point == 0)
2085 fputs("No restart point defined.\n", ttyout);
2086 else
2087 fprintf(ttyout,
2088 #ifndef NO_QUAD
2089 "Restarting at %qd for next get, put or append\n",
2090 (long long)restart_point);
2091 #else
2092 "Restarting at %ld for next get, put or append\n",
2093 (long)restart_point);
2094 #endif
2095 }
2096
2097 /*
2098 * Show remote system type
2099 */
2100 void
2101 syst(argc, argv)
2102 int argc;
2103 char *argv[];
2104 {
2105
2106 (void)command("SYST");
2107 }
2108
2109 void
2110 macdef(argc, argv)
2111 int argc;
2112 char *argv[];
2113 {
2114 char *tmp;
2115 int c;
2116
2117 if (macnum == 16) {
2118 fputs("Limit of 16 macros have already been defined.\n",
2119 ttyout);
2120 code = -1;
2121 return;
2122 }
2123 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2124 fprintf(ttyout, "usage: %s macro_name\n", argv[0]);
2125 code = -1;
2126 return;
2127 }
2128 if (interactive)
2129 fputs(
2130 "Enter macro line by line, terminating it with a null line.\n",
2131 ttyout);
2132 (void)strncpy(macros[macnum].mac_name, argv[1],
2133 sizeof(macros[macnum].mac_name) - 1);
2134 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
2135 if (macnum == 0)
2136 macros[macnum].mac_start = macbuf;
2137 else
2138 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2139 tmp = macros[macnum].mac_start;
2140 while (tmp != macbuf+4096) {
2141 if ((c = getchar()) == EOF) {
2142 fputs("macdef: end of file encountered.\n", ttyout);
2143 code = -1;
2144 return;
2145 }
2146 if ((*tmp = c) == '\n') {
2147 if (tmp == macros[macnum].mac_start) {
2148 macros[macnum++].mac_end = tmp;
2149 code = 0;
2150 return;
2151 }
2152 if (*(tmp-1) == '\0') {
2153 macros[macnum++].mac_end = tmp - 1;
2154 code = 0;
2155 return;
2156 }
2157 *tmp = '\0';
2158 }
2159 tmp++;
2160 }
2161 while (1) {
2162 while ((c = getchar()) != '\n' && c != EOF)
2163 /* LOOP */;
2164 if (c == EOF || getchar() == '\n') {
2165 fputs("Macro not defined - 4K buffer exceeded.\n",
2166 ttyout);
2167 code = -1;
2168 return;
2169 }
2170 }
2171 }
2172
2173 /*
2174 * Get size of file on remote machine
2175 */
2176 void
2177 sizecmd(argc, argv)
2178 int argc;
2179 char *argv[];
2180 {
2181 off_t size;
2182
2183 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2184 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2185 code = -1;
2186 return;
2187 }
2188 size = remotesize(argv[1], 1);
2189 if (size != -1)
2190 fprintf(ttyout,
2191 #ifndef NO_QUAD
2192 "%s\t%qd\n", argv[1], (long long)size);
2193 #else
2194 "%s\t%ld\n", argv[1], (long)size);
2195 #endif
2196 code = size;
2197 }
2198
2199 /*
2200 * Get last modification time of file on remote machine
2201 */
2202 void
2203 modtime(argc, argv)
2204 int argc;
2205 char *argv[];
2206 {
2207 time_t mtime;
2208
2209 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2210 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2211 code = -1;
2212 return;
2213 }
2214 mtime = remotemodtime(argv[1], 1);
2215 if (mtime != -1)
2216 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
2217 code = mtime;
2218 }
2219
2220 /*
2221 * Show status on remote machine
2222 */
2223 void
2224 rmtstatus(argc, argv)
2225 int argc;
2226 char *argv[];
2227 {
2228
2229 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2230 }
2231
2232 /*
2233 * Get file if modtime is more recent than current file
2234 */
2235 void
2236 newer(argc, argv)
2237 int argc;
2238 char *argv[];
2239 {
2240
2241 if (getit(argc, argv, -1, "w"))
2242 fprintf(ttyout,
2243 "Local file \"%s\" is newer than remote file \"%s\".\n",
2244 argv[2], argv[1]);
2245 }
2246
2247 /*
2248 * Display one file through $PAGER (defaults to "more").
2249 */
2250 void
2251 page(argc, argv)
2252 int argc;
2253 char *argv[];
2254 {
2255 int ohash, orestart_point, overbose;
2256 char *p, *pager, *oldargv1;
2257
2258 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2259 fprintf(ttyout, "usage: %s filename\n", argv[0]);
2260 code = -1;
2261 return;
2262 }
2263 oldargv1 = argv[1];
2264 if (!globulize(&argv[1])) {
2265 code = -1;
2266 return;
2267 }
2268 p = getenv("PAGER");
2269 if (p == NULL)
2270 p = PAGER;
2271 pager = xmalloc(strlen(p) + 2);
2272 (void)sprintf(pager, "|%s", p);
2273
2274 ohash = hash;
2275 orestart_point = restart_point;
2276 overbose = verbose;
2277 hash = restart_point = verbose = 0;
2278 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2279 (void)free(pager);
2280 hash = ohash;
2281 restart_point = orestart_point;
2282 verbose = overbose;
2283 if (oldargv1 != argv[1]) /* free up after globulize() */
2284 free(argv[1]);
2285 }
2286
2287 /*
2288 * Set the socket send buffer size.
2289 */
2290 void
2291 sndbuf(argc, argv)
2292 int argc;
2293 char *argv[];
2294 {
2295 int size;
2296
2297 if (argc != 2) {
2298 printf("usage: %s size\n", argv[0]);
2299 code = -1;
2300 return;
2301 }
2302
2303 if ((size = getsockbufsize(argv[1])) == -1) {
2304 printf("invalid socket buffer size: %s\n", argv[1]);
2305 code = -1;
2306 return;
2307 }
2308
2309 sndbuf_size = size;
2310 if (sndbuf_size)
2311 sndbuf_manual = 1;
2312 else
2313 sndbuf_manual = 0;
2314 }
2315
2316 /*
2317 * Set the socket receive buffer size.
2318 */
2319 void
2320 rcvbuf(argc, argv)
2321 int argc;
2322 char *argv[];
2323 {
2324 int size;
2325
2326 if (argc != 2) {
2327 printf("usage: %s size\n", argv[0]);
2328 code = -1;
2329 return;
2330 }
2331
2332 if ((size = getsockbufsize(argv[1])) == -1) {
2333 printf("invalid socket buffer size: %s\n", argv[1]);
2334 code = -1;
2335 return;
2336 }
2337
2338 rcvbuf_size = size;
2339 if (rcvbuf_size)
2340 rcvbuf_manual = 1;
2341 else
2342 rcvbuf_manual = 0;
2343 }
2344