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