cmds.c revision 1.29 1 /* $NetBSD: cmds.c,v 1.29 1997/09/21 01:06:30 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.29 1997/09/21 01:06:30 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 = atol(argv[1]);
785 if (nmark < 1) {
786 printf("%s: bad bytecount value.\n", argv[1]);
787 code = -1;
788 return;
789 }
790 mark = nmark;
791 hash = 1;
792 }
793 printf("Hash mark printing %s", onoff(hash));
794 if (hash)
795 printf(" (%d bytes/hash mark)", mark);
796 puts(".");
797 code = hash;
798 }
799
800 /*
801 * Turn on printing of server echo's.
802 */
803 /*VARARGS*/
804 void
805 setverbose(argc, argv)
806 int argc;
807 char *argv[];
808 {
809
810 code = togglevar(argc, argv, &verbose, "Verbose mode");
811 }
812
813 /*
814 * Toggle PORT cmd use before each data connection.
815 */
816 /*VARARGS*/
817 void
818 setport(argc, argv)
819 int argc;
820 char *argv[];
821 {
822
823 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
824 }
825
826 /*
827 * Toggle transfer progress bar.
828 */
829 /*VARARGS*/
830 void
831 setprogress(argc, argv)
832 int argc;
833 char *argv[];
834 {
835
836 code = togglevar(argc, argv, &progress, "Progress bar");
837 }
838
839 /*
840 * Turn on interactive prompting during mget, mput, and mdelete.
841 */
842 /*VARARGS*/
843 void
844 setprompt(argc, argv)
845 int argc;
846 char *argv[];
847 {
848
849 code = togglevar(argc, argv, &interactive, "Interactive mode");
850 }
851
852 /*
853 * Toggle gate-ftp mode, or set gate-ftp server
854 */
855 /*VARARGS*/
856 void
857 setgate(argc, argv)
858 int argc;
859 char *argv[];
860 {
861 static char gsbuf[MAXHOSTNAMELEN];
862
863 if (argc > 3) {
864 printf("usage: %s [ on | off | gateserver [ port ] ]\n",
865 argv[0]);
866 code = -1;
867 return;
868 } else if (argc < 2) {
869 gatemode = !gatemode;
870 } else {
871 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
872 gatemode = 1;
873 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
874 gatemode = 0;
875 else {
876 if (argc == 3) {
877 char *ep;
878 long port;
879
880 port = strtol(argv[2], &ep, 10);
881 if (port < 0 || port > 0xffff || *ep != '\0') {
882 printf("%s: bad gateport value.\n",
883 argv[2]);
884 code = -1;
885 return;
886 }
887 gateport = htons(port);
888 }
889 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
890 gsbuf[sizeof(gsbuf) - 1] = '\0';
891 gateserver = gsbuf;
892 gatemode = 1;
893 }
894 }
895 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
896 printf(
897 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
898 gatemode = 0;
899 } else {
900 printf("Gate ftp: %s, server %s, port %d.\n", onoff(gatemode),
901 *gateserver ? gateserver : "(none)", ntohs(gateport));
902 }
903 code = gatemode;
904 }
905
906 /*
907 * Toggle metacharacter interpretation on local file names.
908 */
909 /*VARARGS*/
910 void
911 setglob(argc, argv)
912 int argc;
913 char *argv[];
914 {
915
916 code = togglevar(argc, argv, &doglob, "Globbing");
917 }
918
919 /*
920 * Toggle preserving modification times on retreived files.
921 */
922 /*VARARGS*/
923 void
924 setpreserve(argc, argv)
925 int argc;
926 char *argv[];
927 {
928
929 code = togglevar(argc, argv, &preserve, "Preserve modification times");
930 }
931
932 /*
933 * Set debugging mode on/off and/or set level of debugging.
934 */
935 /*VARARGS*/
936 void
937 setdebug(argc, argv)
938 int argc;
939 char *argv[];
940 {
941 if (argc > 2) {
942 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
943 code = -1;
944 return;
945 } else if (argc == 2) {
946 if (strcasecmp(argv[1], "on") == 0)
947 debug = 1;
948 else if (strcasecmp(argv[1], "off") == 0)
949 debug = 0;
950 else {
951 char *ep;
952 long val;
953
954 val = strtol(argv[1], &ep, 10);
955 if (val < 0 || val > INT_MAX || *ep != '\0') {
956 printf("%s: bad debugging value.\n", argv[1]);
957 code = -1;
958 return;
959 }
960 debug = (int)val;
961 }
962 } else
963 debug = !debug;
964 if (debug)
965 options |= SO_DEBUG;
966 else
967 options &= ~SO_DEBUG;
968 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
969 code = debug > 0;
970 }
971
972 /*
973 * Set current working directory on remote machine.
974 */
975 void
976 cd(argc, argv)
977 int argc;
978 char *argv[];
979 {
980 int r;
981
982 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
983 argc > 2) {
984 printf("usage: %s remote-directory\n", argv[0]);
985 code = -1;
986 return;
987 }
988 r = command("CWD %s", argv[1]);
989 if (r == ERROR && code == 500) {
990 if (verbose)
991 puts("CWD command not recognized, trying XCWD.");
992 r = command("XCWD %s", argv[1]);
993 }
994 if (r == COMPLETE)
995 dirchange = 1;
996 }
997
998 /*
999 * Set current working directory on local machine.
1000 */
1001 void
1002 lcd(argc, argv)
1003 int argc;
1004 char *argv[];
1005 {
1006 char buf[MAXPATHLEN];
1007 char *oldargv1;
1008
1009 if (argc < 2)
1010 argc++, argv[1] = home;
1011 if (argc != 2) {
1012 printf("usage: %s local-directory\n", argv[0]);
1013 code = -1;
1014 return;
1015 }
1016 oldargv1 = argv[1];
1017 if (!globulize(&argv[1])) {
1018 code = -1;
1019 return;
1020 }
1021 if (chdir(argv[1]) < 0) {
1022 warn("local: %s", argv[1]);
1023 code = -1;
1024 } else {
1025 if (getcwd(buf, sizeof(buf)) != NULL)
1026 printf("Local directory now %s\n", buf);
1027 else
1028 warn("getcwd: %s", argv[1]);
1029 code = 0;
1030 }
1031 if (oldargv1 != argv[1]) /* free up after globulize() */
1032 free(argv[1]);
1033 }
1034
1035 /*
1036 * Delete a single file.
1037 */
1038 void
1039 delete(argc, argv)
1040 int argc;
1041 char *argv[];
1042 {
1043
1044 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1045 printf("usage: %s remote-file\n", argv[0]);
1046 code = -1;
1047 return;
1048 }
1049 (void)command("DELE %s", argv[1]);
1050 }
1051
1052 /*
1053 * Delete multiple files.
1054 */
1055 void
1056 mdelete(argc, argv)
1057 int argc;
1058 char *argv[];
1059 {
1060 sig_t oldintr;
1061 int ointer;
1062 char *cp;
1063
1064 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1065 printf("usage: %s remote-files\n", argv[0]);
1066 code = -1;
1067 return;
1068 }
1069 mname = argv[0];
1070 mflag = 1;
1071 oldintr = signal(SIGINT, mabort);
1072 (void)setjmp(jabort);
1073 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1074 if (*cp == '\0') {
1075 mflag = 0;
1076 continue;
1077 }
1078 if (mflag && confirm(argv[0], cp)) {
1079 (void)command("DELE %s", cp);
1080 if (!mflag && fromatty) {
1081 ointer = interactive;
1082 interactive = 1;
1083 if (confirm("Continue with", "mdelete")) {
1084 mflag++;
1085 }
1086 interactive = ointer;
1087 }
1088 }
1089 }
1090 (void)signal(SIGINT, oldintr);
1091 mflag = 0;
1092 }
1093
1094 /*
1095 * Rename a remote file.
1096 */
1097 void
1098 renamefile(argc, argv)
1099 int argc;
1100 char *argv[];
1101 {
1102
1103 if (argc < 2 && !another(&argc, &argv, "from-name"))
1104 goto usage;
1105 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1106 usage:
1107 printf("usage: %s from-name to-name\n", argv[0]);
1108 code = -1;
1109 return;
1110 }
1111 if (command("RNFR %s", argv[1]) == CONTINUE)
1112 (void)command("RNTO %s", argv[2]);
1113 }
1114
1115 /*
1116 * Get a directory listing of remote files.
1117 */
1118 void
1119 ls(argc, argv)
1120 int argc;
1121 char *argv[];
1122 {
1123 const char *cmd;
1124 char *oldargv2, *globargv2;
1125
1126 if (argc < 2)
1127 argc++, argv[1] = NULL;
1128 if (argc < 3)
1129 argc++, argv[2] = "-";
1130 if (argc > 3) {
1131 printf("usage: %s remote-directory local-file\n", argv[0]);
1132 code = -1;
1133 return;
1134 }
1135 cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
1136 oldargv2 = argv[2];
1137 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1138 code = -1;
1139 return;
1140 }
1141 globargv2 = argv[2];
1142 if (strcmp(argv[2], "-") && *argv[2] != '|')
1143 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1144 argv[2])) {
1145 code = -1;
1146 goto freels;
1147 }
1148 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1149
1150 /* flush results in case commands are coming from a pipe */
1151 fflush(stdout);
1152 freels:
1153 if (argv[2] != globargv2) /* free up after globulize() */
1154 free(argv[2]);
1155 if (globargv2 != oldargv2)
1156 free(globargv2);
1157 }
1158
1159 /*
1160 * Get a directory listing of multiple remote files.
1161 */
1162 void
1163 mls(argc, argv)
1164 int argc;
1165 char *argv[];
1166 {
1167 sig_t oldintr;
1168 int ointer, i;
1169 int dolist;
1170 char mode[1], *dest, *odest;
1171
1172 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1173 goto usage;
1174 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1175 usage:
1176 printf("usage: %s remote-files local-file\n", argv[0]);
1177 code = -1;
1178 return;
1179 }
1180 odest = dest = argv[argc - 1];
1181 argv[argc - 1] = NULL;
1182 if (strcmp(dest, "-") && *dest != '|')
1183 if (!globulize(&dest) ||
1184 !confirm("output to local-file:", dest)) {
1185 code = -1;
1186 return;
1187 }
1188 dolist = strcmp(argv[0], "mls");
1189 mname = argv[0];
1190 mflag = 1;
1191 oldintr = signal(SIGINT, mabort);
1192 (void)setjmp(jabort);
1193 for (i = 1; mflag && i < argc-1; ++i) {
1194 *mode = (i == 1) ? 'w' : 'a';
1195 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1196 0, 0);
1197 if (!mflag && fromatty) {
1198 ointer = interactive;
1199 interactive = 1;
1200 if (confirm("Continue with", argv[0])) {
1201 mflag ++;
1202 }
1203 interactive = ointer;
1204 }
1205 }
1206 (void)signal(SIGINT, oldintr);
1207 mflag = 0;
1208 if (dest != odest) /* free up after globulize() */
1209 free(dest);
1210 }
1211
1212 /*
1213 * Do a shell escape
1214 */
1215 /*ARGSUSED*/
1216 void
1217 shell(argc, argv)
1218 int argc;
1219 char *argv[];
1220 {
1221 pid_t pid;
1222 sig_t old1, old2;
1223 char shellnam[MAXPATHLEN], *shell, *namep;
1224 int wait_status;
1225
1226 old1 = signal (SIGINT, SIG_IGN);
1227 old2 = signal (SIGQUIT, SIG_IGN);
1228 if ((pid = fork()) == 0) {
1229 for (pid = 3; pid < 20; pid++)
1230 (void)close(pid);
1231 (void)signal(SIGINT, SIG_DFL);
1232 (void)signal(SIGQUIT, SIG_DFL);
1233 shell = getenv("SHELL");
1234 if (shell == NULL)
1235 shell = _PATH_BSHELL;
1236 namep = strrchr(shell, '/');
1237 if (namep == NULL)
1238 namep = shell;
1239 shellnam[0] = '-';
1240 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1241 shellnam[sizeof(shellnam) - 1] = '\0';
1242 if (strcmp(namep, "sh") != 0)
1243 shellnam[0] = '+';
1244 if (debug) {
1245 puts(shell);
1246 (void)fflush(stdout);
1247 }
1248 if (argc > 1) {
1249 execl(shell, shellnam, "-c", altarg, (char *)0);
1250 }
1251 else {
1252 execl(shell, shellnam, (char *)0);
1253 }
1254 warn("%s", shell);
1255 code = -1;
1256 exit(1);
1257 }
1258 if (pid > 0)
1259 while (wait(&wait_status) != pid)
1260 ;
1261 (void)signal(SIGINT, old1);
1262 (void)signal(SIGQUIT, old2);
1263 if (pid == -1) {
1264 warn("Try again later");
1265 code = -1;
1266 }
1267 else {
1268 code = 0;
1269 }
1270 }
1271
1272 /*
1273 * Send new user information (re-login)
1274 */
1275 void
1276 user(argc, argv)
1277 int argc;
1278 char *argv[];
1279 {
1280 char acct[80];
1281 int n, aflag = 0;
1282
1283 if (argc < 2)
1284 (void)another(&argc, &argv, "username");
1285 if (argc < 2 || argc > 4) {
1286 printf("usage: %s username [password] [account]\n", argv[0]);
1287 code = -1;
1288 return;
1289 }
1290 n = command("USER %s", argv[1]);
1291 if (n == CONTINUE) {
1292 if (argc < 3 )
1293 argv[2] = getpass("Password: "), argc++;
1294 n = command("PASS %s", argv[2]);
1295 }
1296 if (n == CONTINUE) {
1297 if (argc < 4) {
1298 (void)fputs("Account: ", stdout);
1299 (void)fflush(stdout);
1300 (void)fgets(acct, sizeof(acct) - 1, stdin);
1301 acct[strlen(acct) - 1] = '\0';
1302 argv[3] = acct; argc++;
1303 }
1304 n = command("ACCT %s", argv[3]);
1305 aflag++;
1306 }
1307 if (n != COMPLETE) {
1308 puts("Login failed.");
1309 return;
1310 }
1311 if (!aflag && argc == 4) {
1312 (void)command("ACCT %s", argv[3]);
1313 }
1314 connected = -1;
1315 }
1316
1317 /*
1318 * Print working directory on remote machine.
1319 */
1320 /*VARARGS*/
1321 void
1322 pwd(argc, argv)
1323 int argc;
1324 char *argv[];
1325 {
1326 int oldverbose = verbose;
1327
1328 /*
1329 * If we aren't verbose, this doesn't do anything!
1330 */
1331 verbose = 1;
1332 if (command("PWD") == ERROR && code == 500) {
1333 puts("PWD command not recognized, trying XPWD.");
1334 (void)command("XPWD");
1335 }
1336 verbose = oldverbose;
1337 }
1338
1339 /*
1340 * Print working directory on local machine.
1341 */
1342 void
1343 lpwd(argc, argv)
1344 int argc;
1345 char *argv[];
1346 {
1347 char buf[MAXPATHLEN];
1348
1349 if (getcwd(buf, sizeof(buf)) != NULL)
1350 printf("Local directory %s\n", buf);
1351 else
1352 warn("getcwd");
1353 code = 0;
1354 }
1355
1356 /*
1357 * Make a directory.
1358 */
1359 void
1360 makedir(argc, argv)
1361 int argc;
1362 char *argv[];
1363 {
1364
1365 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1366 argc > 2) {
1367 printf("usage: %s directory-name\n", argv[0]);
1368 code = -1;
1369 return;
1370 }
1371 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1372 if (verbose)
1373 puts("MKD command not recognized, trying XMKD.");
1374 (void)command("XMKD %s", argv[1]);
1375 }
1376 }
1377
1378 /*
1379 * Remove a directory.
1380 */
1381 void
1382 removedir(argc, argv)
1383 int argc;
1384 char *argv[];
1385 {
1386
1387 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1388 argc > 2) {
1389 printf("usage: %s directory-name\n", argv[0]);
1390 code = -1;
1391 return;
1392 }
1393 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1394 if (verbose)
1395 puts("RMD command not recognized, trying XRMD.");
1396 (void)command("XRMD %s", argv[1]);
1397 }
1398 }
1399
1400 /*
1401 * Send a line, verbatim, to the remote machine.
1402 */
1403 void
1404 quote(argc, argv)
1405 int argc;
1406 char *argv[];
1407 {
1408
1409 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1410 printf("usage: %s line-to-send\n", argv[0]);
1411 code = -1;
1412 return;
1413 }
1414 quote1("", argc, argv);
1415 }
1416
1417 /*
1418 * Send a SITE command to the remote machine. The line
1419 * is sent verbatim to the remote machine, except that the
1420 * word "SITE" is added at the front.
1421 */
1422 void
1423 site(argc, argv)
1424 int argc;
1425 char *argv[];
1426 {
1427
1428 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1429 printf("usage: %s line-to-send\n", argv[0]);
1430 code = -1;
1431 return;
1432 }
1433 quote1("SITE ", argc, argv);
1434 }
1435
1436 /*
1437 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1438 * Send the result as a one-line command and get response.
1439 */
1440 void
1441 quote1(initial, argc, argv)
1442 const char *initial;
1443 int argc;
1444 char *argv[];
1445 {
1446 int i, len;
1447 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1448
1449 (void)strncpy(buf, initial, sizeof(buf) - 1);
1450 buf[sizeof(buf) - 1] = '\0';
1451 if (argc > 1) {
1452 len = strlen(buf);
1453 len += strlen(strncpy(&buf[len], argv[1],
1454 sizeof(buf) - len - 1));
1455 for (i = 2; i < argc && len < sizeof(buf); i++) {
1456 buf[len++] = ' ';
1457 len += strlen(strncpy(&buf[len], argv[i],
1458 sizeof(buf) - len) - 1);
1459 }
1460 }
1461 if (command(buf) == PRELIM) {
1462 while (getreply(0) == PRELIM)
1463 continue;
1464 }
1465 }
1466
1467 void
1468 do_chmod(argc, argv)
1469 int argc;
1470 char *argv[];
1471 {
1472
1473 if (argc < 2 && !another(&argc, &argv, "mode"))
1474 goto usage;
1475 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1476 usage:
1477 printf("usage: %s mode file-name\n", argv[0]);
1478 code = -1;
1479 return;
1480 }
1481 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1482 }
1483
1484 void
1485 do_umask(argc, argv)
1486 int argc;
1487 char *argv[];
1488 {
1489 int oldverbose = verbose;
1490
1491 verbose = 1;
1492 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1493 verbose = oldverbose;
1494 }
1495
1496 void
1497 idle(argc, argv)
1498 int argc;
1499 char *argv[];
1500 {
1501 int oldverbose = verbose;
1502
1503 verbose = 1;
1504 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1505 verbose = oldverbose;
1506 }
1507
1508 /*
1509 * Ask the other side for help.
1510 */
1511 void
1512 rmthelp(argc, argv)
1513 int argc;
1514 char *argv[];
1515 {
1516 int oldverbose = verbose;
1517
1518 verbose = 1;
1519 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1520 verbose = oldverbose;
1521 }
1522
1523 /*
1524 * Terminate session and exit.
1525 */
1526 /*VARARGS*/
1527 void
1528 quit(argc, argv)
1529 int argc;
1530 char *argv[];
1531 {
1532
1533 if (connected)
1534 disconnect(0, 0);
1535 pswitch(1);
1536 if (connected) {
1537 disconnect(0, 0);
1538 }
1539 exit(0);
1540 }
1541
1542 /*
1543 * Terminate session, but don't exit.
1544 */
1545 void
1546 disconnect(argc, argv)
1547 int argc;
1548 char *argv[];
1549 {
1550
1551 if (!connected)
1552 return;
1553 (void)command("QUIT");
1554 if (cout) {
1555 (void)fclose(cout);
1556 }
1557 cout = NULL;
1558 connected = 0;
1559 data = -1;
1560 if (!proxy) {
1561 macnum = 0;
1562 }
1563 }
1564
1565 void
1566 account(argc, argv)
1567 int argc;
1568 char *argv[];
1569 {
1570 char *ap;
1571
1572 if (argc > 2) {
1573 printf("usage: %s [password]\n", argv[0]);
1574 code = -1;
1575 return;
1576 }
1577 else if (argc == 2)
1578 ap = argv[1];
1579 else
1580 ap = getpass("Account:");
1581 (void)command("ACCT %s", ap);
1582 }
1583
1584 jmp_buf abortprox;
1585
1586 void
1587 proxabort(notused)
1588 int notused;
1589 {
1590
1591 alarmtimer(0);
1592 if (!proxy) {
1593 pswitch(1);
1594 }
1595 if (connected) {
1596 proxflag = 1;
1597 }
1598 else {
1599 proxflag = 0;
1600 }
1601 pswitch(0);
1602 longjmp(abortprox, 1);
1603 }
1604
1605 void
1606 doproxy(argc, argv)
1607 int argc;
1608 char *argv[];
1609 {
1610 struct cmd *c;
1611 int cmdpos;
1612 sig_t oldintr;
1613
1614 if (argc < 2 && !another(&argc, &argv, "command")) {
1615 printf("usage: %s command\n", argv[0]);
1616 code = -1;
1617 return;
1618 }
1619 c = getcmd(argv[1]);
1620 if (c == (struct cmd *) -1) {
1621 puts("?Ambiguous command.");
1622 (void)fflush(stdout);
1623 code = -1;
1624 return;
1625 }
1626 if (c == 0) {
1627 puts("?Invalid command.");
1628 (void)fflush(stdout);
1629 code = -1;
1630 return;
1631 }
1632 if (!c->c_proxy) {
1633 puts("?Invalid proxy command.");
1634 (void)fflush(stdout);
1635 code = -1;
1636 return;
1637 }
1638 if (setjmp(abortprox)) {
1639 code = -1;
1640 return;
1641 }
1642 oldintr = signal(SIGINT, proxabort);
1643 pswitch(1);
1644 if (c->c_conn && !connected) {
1645 puts("Not connected.");
1646 (void)fflush(stdout);
1647 pswitch(0);
1648 (void)signal(SIGINT, oldintr);
1649 code = -1;
1650 return;
1651 }
1652 cmdpos = strcspn(line, " \t");
1653 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1654 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1655 (*c->c_handler)(argc-1, argv+1);
1656 if (connected) {
1657 proxflag = 1;
1658 }
1659 else {
1660 proxflag = 0;
1661 }
1662 pswitch(0);
1663 (void)signal(SIGINT, oldintr);
1664 }
1665
1666 void
1667 setcase(argc, argv)
1668 int argc;
1669 char *argv[];
1670 {
1671
1672 code = togglevar(argc, argv, &mcase, "Case mapping");
1673 }
1674
1675 void
1676 setcr(argc, argv)
1677 int argc;
1678 char *argv[];
1679 {
1680
1681 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1682 }
1683
1684 void
1685 setntrans(argc, argv)
1686 int argc;
1687 char *argv[];
1688 {
1689 if (argc == 1) {
1690 ntflag = 0;
1691 puts("Ntrans off.");
1692 code = ntflag;
1693 return;
1694 }
1695 ntflag++;
1696 code = ntflag;
1697 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1698 ntin[sizeof(ntin) - 1] = '\0';
1699 if (argc == 2) {
1700 ntout[0] = '\0';
1701 return;
1702 }
1703 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1704 ntout[sizeof(ntout) - 1] = '\0';
1705 }
1706
1707 char *
1708 dotrans(name)
1709 char *name;
1710 {
1711 static char new[MAXPATHLEN];
1712 char *cp1, *cp2 = new;
1713 int i, ostop, found;
1714
1715 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1716 continue;
1717 for (cp1 = name; *cp1; cp1++) {
1718 found = 0;
1719 for (i = 0; *(ntin + i) && i < 16; i++) {
1720 if (*cp1 == *(ntin + i)) {
1721 found++;
1722 if (i < ostop) {
1723 *cp2++ = *(ntout + i);
1724 }
1725 break;
1726 }
1727 }
1728 if (!found) {
1729 *cp2++ = *cp1;
1730 }
1731 }
1732 *cp2 = '\0';
1733 return (new);
1734 }
1735
1736 void
1737 setnmap(argc, argv)
1738 int argc;
1739 char *argv[];
1740 {
1741 char *cp;
1742
1743 if (argc == 1) {
1744 mapflag = 0;
1745 puts("Nmap off.");
1746 code = mapflag;
1747 return;
1748 }
1749 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1750 printf("usage: %s [mapin mapout]\n", argv[0]);
1751 code = -1;
1752 return;
1753 }
1754 mapflag = 1;
1755 code = 1;
1756 cp = strchr(altarg, ' ');
1757 if (proxy) {
1758 while(*++cp == ' ')
1759 continue;
1760 altarg = cp;
1761 cp = strchr(altarg, ' ');
1762 }
1763 *cp = '\0';
1764 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1765 while (*++cp == ' ')
1766 continue;
1767 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1768 }
1769
1770 char *
1771 domap(name)
1772 char *name;
1773 {
1774 static char new[MAXPATHLEN];
1775 char *cp1 = name, *cp2 = mapin;
1776 char *tp[9], *te[9];
1777 int i, toks[9], toknum = 0, match = 1;
1778
1779 for (i=0; i < 9; ++i) {
1780 toks[i] = 0;
1781 }
1782 while (match && *cp1 && *cp2) {
1783 switch (*cp2) {
1784 case '\\':
1785 if (*++cp2 != *cp1) {
1786 match = 0;
1787 }
1788 break;
1789 case '$':
1790 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1791 if (*cp1 != *(++cp2+1)) {
1792 toks[toknum = *cp2 - '1']++;
1793 tp[toknum] = cp1;
1794 while (*++cp1 && *(cp2+1)
1795 != *cp1);
1796 te[toknum] = cp1;
1797 }
1798 cp2++;
1799 break;
1800 }
1801 /* FALLTHROUGH */
1802 default:
1803 if (*cp2 != *cp1) {
1804 match = 0;
1805 }
1806 break;
1807 }
1808 if (match && *cp1) {
1809 cp1++;
1810 }
1811 if (match && *cp2) {
1812 cp2++;
1813 }
1814 }
1815 if (!match && *cp1) /* last token mismatch */
1816 {
1817 toks[toknum] = 0;
1818 }
1819 cp1 = new;
1820 *cp1 = '\0';
1821 cp2 = mapout;
1822 while (*cp2) {
1823 match = 0;
1824 switch (*cp2) {
1825 case '\\':
1826 if (*(cp2 + 1)) {
1827 *cp1++ = *++cp2;
1828 }
1829 break;
1830 case '[':
1831 LOOP:
1832 if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1833 if (*++cp2 == '0') {
1834 char *cp3 = name;
1835
1836 while (*cp3) {
1837 *cp1++ = *cp3++;
1838 }
1839 match = 1;
1840 }
1841 else if (toks[toknum = *cp2 - '1']) {
1842 char *cp3 = tp[toknum];
1843
1844 while (cp3 != te[toknum]) {
1845 *cp1++ = *cp3++;
1846 }
1847 match = 1;
1848 }
1849 }
1850 else {
1851 while (*cp2 && *cp2 != ',' &&
1852 *cp2 != ']') {
1853 if (*cp2 == '\\') {
1854 cp2++;
1855 }
1856 else if (*cp2 == '$' &&
1857 isdigit(*(cp2+1))) {
1858 if (*++cp2 == '0') {
1859 char *cp3 = name;
1860
1861 while (*cp3) {
1862 *cp1++ = *cp3++;
1863 }
1864 }
1865 else if (toks[toknum =
1866 *cp2 - '1']) {
1867 char *cp3=tp[toknum];
1868
1869 while (cp3 !=
1870 te[toknum]) {
1871 *cp1++ = *cp3++;
1872 }
1873 }
1874 }
1875 else if (*cp2) {
1876 *cp1++ = *cp2++;
1877 }
1878 }
1879 if (!*cp2) {
1880 puts(
1881 "nmap: unbalanced brackets.");
1882 return (name);
1883 }
1884 match = 1;
1885 cp2--;
1886 }
1887 if (match) {
1888 while (*++cp2 && *cp2 != ']') {
1889 if (*cp2 == '\\' && *(cp2 + 1)) {
1890 cp2++;
1891 }
1892 }
1893 if (!*cp2) {
1894 puts(
1895 "nmap: unbalanced brackets.");
1896 return (name);
1897 }
1898 break;
1899 }
1900 switch (*++cp2) {
1901 case ',':
1902 goto LOOP;
1903 case ']':
1904 break;
1905 default:
1906 cp2--;
1907 goto LOOP;
1908 }
1909 break;
1910 case '$':
1911 if (isdigit(*(cp2 + 1))) {
1912 if (*++cp2 == '0') {
1913 char *cp3 = name;
1914
1915 while (*cp3) {
1916 *cp1++ = *cp3++;
1917 }
1918 }
1919 else if (toks[toknum = *cp2 - '1']) {
1920 char *cp3 = tp[toknum];
1921
1922 while (cp3 != te[toknum]) {
1923 *cp1++ = *cp3++;
1924 }
1925 }
1926 break;
1927 }
1928 /* intentional drop through */
1929 default:
1930 *cp1++ = *cp2;
1931 break;
1932 }
1933 cp2++;
1934 }
1935 *cp1 = '\0';
1936 if (!*new) {
1937 return (name);
1938 }
1939 return (new);
1940 }
1941
1942 void
1943 setpassive(argc, argv)
1944 int argc;
1945 char *argv[];
1946 {
1947
1948 code = togglevar(argc, argv, &passivemode,
1949 verbose ? "Passive mode" : NULL);
1950 }
1951
1952 void
1953 setsunique(argc, argv)
1954 int argc;
1955 char *argv[];
1956 {
1957
1958 code = togglevar(argc, argv, &sunique, "Store unique");
1959 }
1960
1961 void
1962 setrunique(argc, argv)
1963 int argc;
1964 char *argv[];
1965 {
1966
1967 code = togglevar(argc, argv, &runique, "Receive unique");
1968 }
1969
1970 /* change directory to parent directory */
1971 void
1972 cdup(argc, argv)
1973 int argc;
1974 char *argv[];
1975 {
1976 int r;
1977
1978 r = command("CDUP");
1979 if (r == ERROR && code == 500) {
1980 if (verbose)
1981 puts("CDUP command not recognized, trying XCUP.");
1982 r = command("XCUP");
1983 }
1984 if (r == COMPLETE)
1985 dirchange = 1;
1986 }
1987
1988 /*
1989 * Restart transfer at specific point
1990 */
1991 void
1992 restart(argc, argv)
1993 int argc;
1994 char *argv[];
1995 {
1996
1997 if (argc != 2)
1998 puts("restart: offset not specified.");
1999 else {
2000 restart_point = atol(argv[1]);
2001 printf("Restarting at %qd. Execute get, put or append to"
2002 "initiate transfer\n", (long long)restart_point);
2003 }
2004 }
2005
2006 /*
2007 * Show remote system type
2008 */
2009 void
2010 syst(argc, argv)
2011 int argc;
2012 char *argv[];
2013 {
2014
2015 (void)command("SYST");
2016 }
2017
2018 void
2019 macdef(argc, argv)
2020 int argc;
2021 char *argv[];
2022 {
2023 char *tmp;
2024 int c;
2025
2026 if (macnum == 16) {
2027 puts("Limit of 16 macros have already been defined.");
2028 code = -1;
2029 return;
2030 }
2031 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2032 printf("usage: %s macro_name\n", argv[0]);
2033 code = -1;
2034 return;
2035 }
2036 if (interactive)
2037 puts(
2038 "Enter macro line by line, terminating it with a null line.");
2039 (void)strncpy(macros[macnum].mac_name, argv[1],
2040 sizeof(macros[macnum].mac_name) - 1);
2041 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
2042 if (macnum == 0)
2043 macros[macnum].mac_start = macbuf;
2044 else
2045 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2046 tmp = macros[macnum].mac_start;
2047 while (tmp != macbuf+4096) {
2048 if ((c = getchar()) == EOF) {
2049 puts("macdef: end of file encountered.");
2050 code = -1;
2051 return;
2052 }
2053 if ((*tmp = c) == '\n') {
2054 if (tmp == macros[macnum].mac_start) {
2055 macros[macnum++].mac_end = tmp;
2056 code = 0;
2057 return;
2058 }
2059 if (*(tmp-1) == '\0') {
2060 macros[macnum++].mac_end = tmp - 1;
2061 code = 0;
2062 return;
2063 }
2064 *tmp = '\0';
2065 }
2066 tmp++;
2067 }
2068 while (1) {
2069 while ((c = getchar()) != '\n' && c != EOF)
2070 /* LOOP */;
2071 if (c == EOF || getchar() == '\n') {
2072 puts("Macro not defined - 4K buffer exceeded.");
2073 code = -1;
2074 return;
2075 }
2076 }
2077 }
2078
2079 /*
2080 * Get size of file on remote machine
2081 */
2082 void
2083 sizecmd(argc, argv)
2084 int argc;
2085 char *argv[];
2086 {
2087 off_t size;
2088
2089 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2090 printf("usage: %s filename\n", argv[0]);
2091 code = -1;
2092 return;
2093 }
2094 size = remotesize(argv[1], 1);
2095 if (size != -1)
2096 printf("%s\t%qd\n", argv[1], (long long)size);
2097 code = size;
2098 }
2099
2100 /*
2101 * Get last modification time of file on remote machine
2102 */
2103 void
2104 modtime(argc, argv)
2105 int argc;
2106 char *argv[];
2107 {
2108 time_t mtime;
2109
2110 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2111 printf("usage: %s filename\n", argv[0]);
2112 code = -1;
2113 return;
2114 }
2115 mtime = remotemodtime(argv[1], 1);
2116 if (mtime != -1)
2117 printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2118 code = mtime;
2119 }
2120
2121 /*
2122 * Show status on remote machine
2123 */
2124 void
2125 rmtstatus(argc, argv)
2126 int argc;
2127 char *argv[];
2128 {
2129
2130 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2131 }
2132
2133 /*
2134 * Get file if modtime is more recent than current file
2135 */
2136 void
2137 newer(argc, argv)
2138 int argc;
2139 char *argv[];
2140 {
2141
2142 if (getit(argc, argv, -1, "w"))
2143 printf("Local file \"%s\" is newer than remote file \"%s\".\n",
2144 argv[2], argv[1]);
2145 }
2146
2147 /*
2148 * Display one file through $PAGER (defaults to "more").
2149 */
2150 void
2151 page(argc, argv)
2152 int argc;
2153 char *argv[];
2154 {
2155 int orestart_point, ohash, overbose;
2156 char *p, *pager, *oldargv1;
2157
2158 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2159 printf("usage: %s filename\n", argv[0]);
2160 code = -1;
2161 return;
2162 }
2163 oldargv1 = argv[1];
2164 if (!globulize(&argv[1])) {
2165 code = -1;
2166 return;
2167 }
2168 p = getenv("PAGER");
2169 if (p == NULL)
2170 p = PAGER;
2171 if ((pager = malloc(strlen(p) + 2)) == NULL)
2172 errx(1, "Can't allocate memory for $PAGER");
2173 (void)sprintf(pager, "|%s", p);
2174
2175 orestart_point = restart_point;
2176 ohash = hash;
2177 overbose = verbose;
2178 restart_point = hash = verbose = 0;
2179 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2180 (void)free(pager);
2181 restart_point = orestart_point;
2182 hash = ohash;
2183 verbose = overbose;
2184 if (oldargv1 != argv[1]) /* free up after globulize() */
2185 free(argv[1]);
2186 }
2187