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