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