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