cmds.c revision 1.17 1 /* $NetBSD: cmds.c,v 1.17 1997/01/19 20:17:37 veego 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.17 1997/01/19 20:17:37 veego 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 printf(" ]\n");
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 printf("ftp: internal error: unknown type %d\n", 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) {
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 printf("\n");
537 (void) fflush(stdout);
538 if (mflag && fromatty) {
539 ointer = interactive;
540 oconf = confirmrest;
541 interactive = 1;
542 confirmrest = 0;
543 if (confirm("Continue with", mname)) {
544 interactive = ointer;
545 confirmrest = oconf;
546 longjmp(jabort, 0);
547 }
548 interactive = ointer;
549 confirmrest = oconf;
550 }
551 mflag = 0;
552 longjmp(jabort, 0);
553 }
554
555 /*
556 * Get multiple files.
557 */
558 void
559 mget(argc, argv)
560 int argc;
561 char *argv[];
562 {
563 sig_t oldintr;
564 int ch, ointer;
565 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
566
567 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
568 printf("usage: %s remote-files\n", argv[0]);
569 code = -1;
570 return;
571 }
572 mname = argv[0];
573 mflag = 1;
574 oldintr = signal(SIGINT, mabort);
575 (void) setjmp(jabort);
576 while ((cp = remglob(argv, proxy)) != NULL) {
577 if (*cp == '\0') {
578 mflag = 0;
579 continue;
580 }
581 if (mflag && confirm(argv[0], cp)) {
582 tp = cp;
583 if (mcase) {
584 for (tp2 = tmpbuf; (ch = *tp++) != NULL; )
585 *tp2++ = isupper(ch) ? tolower(ch) : ch;
586 *tp2 = '\0';
587 tp = tmpbuf;
588 }
589 if (ntflag) {
590 tp = dotrans(tp);
591 }
592 if (mapflag) {
593 tp = domap(tp);
594 }
595 recvrequest("RETR", tp, cp, "w",
596 tp != cp || !interactive);
597 if (!mflag && fromatty) {
598 ointer = interactive;
599 interactive = 1;
600 if (confirm("Continue with", "mget")) {
601 mflag++;
602 }
603 interactive = ointer;
604 }
605 }
606 }
607 (void) signal(SIGINT, oldintr);
608 mflag = 0;
609 }
610
611 char *
612 onoff(bool)
613 int bool;
614 {
615
616 return (bool ? "on" : "off");
617 }
618
619 /*
620 * Show status.
621 */
622 /*ARGSUSED*/
623 void
624 status(argc, argv)
625 int argc;
626 char *argv[];
627 {
628 int i;
629
630 if (connected)
631 printf("Connected to %s.\n", hostname);
632 else
633 printf("Not connected.\n");
634 if (!proxy) {
635 pswitch(1);
636 if (connected) {
637 printf("Connected for proxy commands to %s.\n",
638 hostname);
639 }
640 else {
641 printf("No proxy connection.\n");
642 }
643 pswitch(0);
644 }
645 printf("Passive mode: %s.\n", onoff(passivemode));
646 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
647 modename, typename, formname, structname);
648 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
649 onoff(verbose), onoff(bell), onoff(interactive),
650 onoff(doglob));
651 printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
652 onoff(runique));
653 printf("Preserve modification times: %s\n", onoff(preserve));
654 printf("Case: %s; CR stripping: %s\n", onoff(mcase), onoff(crflag));
655 if (ntflag) {
656 printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
657 }
658 else {
659 printf("Ntrans: off\n");
660 }
661 if (mapflag) {
662 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
663 }
664 else {
665 printf("Nmap: off\n");
666 }
667 printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s\n",
668 onoff(hash), mark, onoff(progress));
669 printf("Use of PORT cmds: %s\n", onoff(sendport));
670 #ifndef SMALLFTP
671 printf("Command line editing: %s\n", onoff(editing));
672 #endif /* !SMALLFTP */
673 if (macnum > 0) {
674 printf("Macros:\n");
675 for (i=0; i<macnum; i++) {
676 printf("\t%s\n", macros[i].mac_name);
677 }
678 }
679 code = 0;
680 }
681
682 /*
683 * Toggle a variable
684 */
685 int
686 togglevar(argc, argv, var, mesg)
687 int argc;
688 char *argv[];
689 int *var;
690 const char *mesg;
691 {
692 if (argc < 2) {
693 *var = !*var;
694 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
695 *var = 1;
696 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
697 *var = 0;
698 } else {
699 printf("usage: %s [ on | off ]\n", argv[0]);
700 return -1;
701 }
702 printf("%s %s.\n", mesg, onoff(*var));
703 return *var;
704 }
705
706 /*
707 * Set beep on cmd completed mode.
708 */
709 /*VARARGS*/
710 void
711 setbell(argc, argv)
712 int argc;
713 char *argv[];
714 {
715
716 code = togglevar(argc, argv, &bell, "Bell mode");
717 }
718
719 #ifndef SMALLFTP
720 /*
721 * Set command line editing
722 */
723 /*VARARGS*/
724 void
725 setedit(argc, argv)
726 int argc;
727 char *argv[];
728 {
729
730 code = togglevar(argc, argv, &editing, "Editing mode");
731 }
732 #endif /* !SMALLFTP */
733
734 /*
735 * Turn on packet tracing.
736 */
737 /*VARARGS*/
738 void
739 settrace(argc, argv)
740 int argc;
741 char *argv[];
742 {
743
744 code = togglevar(argc, argv, &trace, "Packet tracing");
745 }
746
747 /*
748 * Toggle hash mark printing during transfers, or set hash mark bytecount.
749 */
750 /*VARARGS*/
751 void
752 sethash(argc, argv)
753 int argc;
754 char *argv[];
755 {
756 if (argc == 1)
757 hash = !hash;
758 else if (argc != 2) {
759 printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
760 code = -1;
761 return;
762 } else if (strcasecmp(argv[1], "on") == 0)
763 hash = 1;
764 else if (strcasecmp(argv[1], "off") == 0)
765 hash = 0;
766 else {
767 int nmark = atol(argv[1]);
768 if (nmark < 1) {
769 printf("%s: bad bytecount value\n", argv[1]);
770 code = -1;
771 return;
772 }
773 mark = nmark;
774 hash = 1;
775 }
776 printf("Hash mark printing %s", onoff(hash));
777 if (hash)
778 printf(" (%d bytes/hash mark)", mark);
779 printf(".\n");
780 code = hash;
781 }
782
783 /*
784 * Turn on printing of server echo's.
785 */
786 /*VARARGS*/
787 void
788 setverbose(argc, argv)
789 int argc;
790 char *argv[];
791 {
792
793 code = togglevar(argc, argv, &verbose, "Verbose mode");
794 }
795
796 /*
797 * Toggle PORT cmd use before each data connection.
798 */
799 /*VARARGS*/
800 void
801 setport(argc, argv)
802 int argc;
803 char *argv[];
804 {
805
806 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
807 }
808
809 /*
810 * Toggle transfer progress bar.
811 */
812 /*VARARGS*/
813 void
814 setprogress(argc, argv)
815 int argc;
816 char *argv[];
817 {
818
819 code = togglevar(argc, argv, &progress, "Progress bar");
820 }
821
822 /*
823 * Turn on interactive prompting
824 * during mget, mput, and mdelete.
825 */
826 /*VARARGS*/
827 void
828 setprompt(argc, argv)
829 int argc;
830 char *argv[];
831 {
832
833 code = togglevar(argc, argv, &interactive, "Interactive mode");
834 }
835
836 /*
837 * Toggle metacharacter interpretation
838 * on local file names.
839 */
840 /*VARARGS*/
841 void
842 setglob(argc, argv)
843 int argc;
844 char *argv[];
845 {
846
847 code = togglevar(argc, argv, &doglob, "Globbing");
848 }
849
850 /*
851 * Toggle preserving modification times on retreived files.
852 */
853 /*VARARGS*/
854 void
855 setpreserve(argc, argv)
856 int argc;
857 char *argv[];
858 {
859
860 code = togglevar(argc, argv, &preserve, "Preserve modification times");
861 }
862
863 /*
864 * Set debugging mode on/off and/or
865 * set level of debugging.
866 */
867 /*VARARGS*/
868 void
869 setdebug(argc, argv)
870 int argc;
871 char *argv[];
872 {
873 int val;
874
875 if (argc > 2) {
876 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
877 code = -1;
878 return;
879 } else if (argc == 2) {
880 if (strcasecmp(argv[1], "on") == 0)
881 debug = 1;
882 else if (strcasecmp(argv[1], "off") == 0)
883 debug = 0;
884 else {
885 val = atoi(argv[1]);
886 if (val < 0) {
887 printf("%s: bad debugging value.\n", argv[1]);
888 code = -1;
889 return;
890 }
891 debug = val;
892 }
893 } else
894 debug = !debug;
895 if (debug)
896 options |= SO_DEBUG;
897 else
898 options &= ~SO_DEBUG;
899 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
900 code = debug > 0;
901 }
902
903 /*
904 * Set current working directory
905 * on remote machine.
906 */
907 void
908 cd(argc, argv)
909 int argc;
910 char *argv[];
911 {
912 int r;
913
914 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
915 argc > 2) {
916 printf("usage: %s remote-directory\n", argv[0]);
917 code = -1;
918 return;
919 }
920 r = command("CWD %s", argv[1]);
921 if (r == ERROR && code == 500) {
922 if (verbose)
923 printf("CWD command not recognized, trying XCWD\n");
924 r = command("XCWD %s", argv[1]);
925 }
926 if (r == COMPLETE)
927 dirchange = 1;
928 }
929
930 /*
931 * Set current working directory
932 * on local machine.
933 */
934 void
935 lcd(argc, argv)
936 int argc;
937 char *argv[];
938 {
939 char buf[MAXPATHLEN];
940
941 if (argc < 2)
942 argc++, argv[1] = home;
943 if (argc != 2) {
944 printf("usage: %s local-directory\n", argv[0]);
945 code = -1;
946 return;
947 }
948 if (!globulize(&argv[1])) {
949 code = -1;
950 return;
951 }
952 if (chdir(argv[1]) < 0) {
953 warn("local: %s", argv[1]);
954 code = -1;
955 return;
956 }
957 if (getwd(buf) != NULL)
958 printf("Local directory now %s\n", buf);
959 else
960 warnx("getwd: %s", buf);
961 code = 0;
962 }
963
964 /*
965 * Delete a single file.
966 */
967 void
968 delete(argc, argv)
969 int argc;
970 char *argv[];
971 {
972
973 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
974 printf("usage: %s remote-file\n", argv[0]);
975 code = -1;
976 return;
977 }
978 (void) command("DELE %s", argv[1]);
979 }
980
981 /*
982 * Delete multiple files.
983 */
984 void
985 mdelete(argc, argv)
986 int argc;
987 char *argv[];
988 {
989 sig_t oldintr;
990 int ointer;
991 char *cp;
992
993 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
994 printf("usage: %s remote-files\n", argv[0]);
995 code = -1;
996 return;
997 }
998 mname = argv[0];
999 mflag = 1;
1000 oldintr = signal(SIGINT, mabort);
1001 (void) setjmp(jabort);
1002 while ((cp = remglob(argv, 0)) != NULL) {
1003 if (*cp == '\0') {
1004 mflag = 0;
1005 continue;
1006 }
1007 if (mflag && confirm(argv[0], cp)) {
1008 (void) command("DELE %s", cp);
1009 if (!mflag && fromatty) {
1010 ointer = interactive;
1011 interactive = 1;
1012 if (confirm("Continue with", "mdelete")) {
1013 mflag++;
1014 }
1015 interactive = ointer;
1016 }
1017 }
1018 }
1019 (void) signal(SIGINT, oldintr);
1020 mflag = 0;
1021 }
1022
1023 /*
1024 * Rename a remote file.
1025 */
1026 void
1027 renamefile(argc, argv)
1028 int argc;
1029 char *argv[];
1030 {
1031
1032 if (argc < 2 && !another(&argc, &argv, "from-name"))
1033 goto usage;
1034 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1035 usage:
1036 printf("%s from-name to-name\n", argv[0]);
1037 code = -1;
1038 return;
1039 }
1040 if (command("RNFR %s", argv[1]) == CONTINUE)
1041 (void) command("RNTO %s", argv[2]);
1042 }
1043
1044 /*
1045 * Get a directory listing
1046 * of remote files.
1047 */
1048 void
1049 ls(argc, argv)
1050 int argc;
1051 char *argv[];
1052 {
1053 const char *cmd;
1054
1055 if (argc < 2)
1056 argc++, argv[1] = NULL;
1057 if (argc < 3)
1058 argc++, argv[2] = "-";
1059 if (argc > 3) {
1060 printf("usage: %s remote-directory local-file\n", argv[0]);
1061 code = -1;
1062 return;
1063 }
1064 cmd = strcmp(argv[0], "dir") == 0 ? "LIST" : "NLST";
1065 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1066 code = -1;
1067 return;
1068 }
1069 if (strcmp(argv[2], "-") && *argv[2] != '|')
1070 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1071 argv[2])) {
1072 code = -1;
1073 return;
1074 }
1075 recvrequest(cmd, argv[2], argv[1], "w", 0);
1076
1077 /* flush results in case commands are coming from a pipe */
1078 fflush(stdout);
1079 }
1080
1081 /*
1082 * Get a directory listing
1083 * of multiple remote files.
1084 */
1085 void
1086 mls(argc, argv)
1087 int argc;
1088 char *argv[];
1089 {
1090 sig_t oldintr;
1091 int ointer, i;
1092 const char *cmd;
1093 char mode[1], *dest;
1094
1095 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1096 goto usage;
1097 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1098 usage:
1099 printf("usage: %s remote-files local-file\n", argv[0]);
1100 code = -1;
1101 return;
1102 }
1103 dest = argv[argc - 1];
1104 argv[argc - 1] = NULL;
1105 if (strcmp(dest, "-") && *dest != '|')
1106 if (!globulize(&dest) ||
1107 !confirm("output to local-file:", dest)) {
1108 code = -1;
1109 return;
1110 }
1111 cmd = strcmp(argv[0], "mls") == 0 ? "NLST" : "LIST";
1112 mname = argv[0];
1113 mflag = 1;
1114 oldintr = signal(SIGINT, mabort);
1115 (void) setjmp(jabort);
1116 for (i = 1; mflag && i < argc-1; ++i) {
1117 *mode = (i == 1) ? 'w' : 'a';
1118 recvrequest(cmd, dest, argv[i], mode, 0);
1119 if (!mflag && fromatty) {
1120 ointer = interactive;
1121 interactive = 1;
1122 if (confirm("Continue with", argv[0])) {
1123 mflag ++;
1124 }
1125 interactive = ointer;
1126 }
1127 }
1128 (void) signal(SIGINT, oldintr);
1129 mflag = 0;
1130 }
1131
1132 /*
1133 * Do a shell escape
1134 */
1135 /*ARGSUSED*/
1136 void
1137 shell(argc, argv)
1138 int argc;
1139 char *argv[];
1140 {
1141 pid_t pid;
1142 sig_t old1, old2;
1143 char shellnam[MAXPATHLEN], *shell, *namep;
1144 union wait status;
1145
1146 old1 = signal (SIGINT, SIG_IGN);
1147 old2 = signal (SIGQUIT, SIG_IGN);
1148 if ((pid = fork()) == 0) {
1149 for (pid = 3; pid < 20; pid++)
1150 (void) close(pid);
1151 (void) signal(SIGINT, SIG_DFL);
1152 (void) signal(SIGQUIT, SIG_DFL);
1153 shell = getenv("SHELL");
1154 if (shell == NULL)
1155 shell = _PATH_BSHELL;
1156 namep = strrchr(shell, '/');
1157 if (namep == NULL)
1158 namep = shell;
1159 shellnam[0] = '-';
1160 (void) strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 1);
1161 if (strcmp(namep, "sh") != 0)
1162 shellnam[0] = '+';
1163 if (debug) {
1164 printf ("%s\n", shell);
1165 (void) fflush (stdout);
1166 }
1167 if (argc > 1) {
1168 execl(shell, shellnam, "-c", altarg, (char *)0);
1169 }
1170 else {
1171 execl(shell, shellnam, (char *)0);
1172 }
1173 warn("%s", shell);
1174 code = -1;
1175 exit(1);
1176 }
1177 if (pid > 0)
1178 while (wait((int *)&status) != pid)
1179 ;
1180 (void) signal(SIGINT, old1);
1181 (void) signal(SIGQUIT, old2);
1182 if (pid == -1) {
1183 warn("%s", "Try again later");
1184 code = -1;
1185 }
1186 else {
1187 code = 0;
1188 }
1189 }
1190
1191 /*
1192 * Send new user information (re-login)
1193 */
1194 void
1195 user(argc, argv)
1196 int argc;
1197 char *argv[];
1198 {
1199 char acct[80];
1200 int n, aflag = 0;
1201
1202 if (argc < 2)
1203 (void) another(&argc, &argv, "username");
1204 if (argc < 2 || argc > 4) {
1205 printf("usage: %s username [password] [account]\n", argv[0]);
1206 code = -1;
1207 return;
1208 }
1209 n = command("USER %s", argv[1]);
1210 if (n == CONTINUE) {
1211 if (argc < 3 )
1212 argv[2] = getpass("Password: "), argc++;
1213 n = command("PASS %s", argv[2]);
1214 }
1215 if (n == CONTINUE) {
1216 if (argc < 4) {
1217 printf("Account: "); (void) fflush(stdout);
1218 (void) fgets(acct, sizeof(acct) - 1, stdin);
1219 acct[strlen(acct) - 1] = '\0';
1220 argv[3] = acct; argc++;
1221 }
1222 n = command("ACCT %s", argv[3]);
1223 aflag++;
1224 }
1225 if (n != COMPLETE) {
1226 fprintf(stdout, "Login failed.\n");
1227 return;
1228 }
1229 if (!aflag && argc == 4) {
1230 (void) command("ACCT %s", argv[3]);
1231 }
1232 }
1233
1234 /*
1235 * Print working directory on remote machine.
1236 */
1237 /*VARARGS*/
1238 void
1239 pwd(argc, argv)
1240 int argc;
1241 char *argv[];
1242 {
1243 int oldverbose = verbose;
1244
1245 /*
1246 * If we aren't verbose, this doesn't do anything!
1247 */
1248 verbose = 1;
1249 if (command("PWD") == ERROR && code == 500) {
1250 printf("PWD command not recognized, trying XPWD\n");
1251 (void) command("XPWD");
1252 }
1253 verbose = oldverbose;
1254 }
1255
1256 /*
1257 * Print working directory on local machine.
1258 */
1259 void
1260 lpwd(argc, argv)
1261 int argc;
1262 char *argv[];
1263 {
1264 char buf[MAXPATHLEN];
1265
1266 if (getwd(buf) != NULL)
1267 printf("Local directory %s\n", buf);
1268 else
1269 warnx("getwd: %s", buf);
1270 code = 0;
1271 }
1272
1273 /*
1274 * Make a directory.
1275 */
1276 void
1277 makedir(argc, argv)
1278 int argc;
1279 char *argv[];
1280 {
1281
1282 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1283 argc > 2) {
1284 printf("usage: %s directory-name\n", argv[0]);
1285 code = -1;
1286 return;
1287 }
1288 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1289 if (verbose)
1290 printf("MKD command not recognized, trying XMKD\n");
1291 (void) command("XMKD %s", argv[1]);
1292 }
1293 }
1294
1295 /*
1296 * Remove a directory.
1297 */
1298 void
1299 removedir(argc, argv)
1300 int argc;
1301 char *argv[];
1302 {
1303
1304 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1305 argc > 2) {
1306 printf("usage: %s directory-name\n", argv[0]);
1307 code = -1;
1308 return;
1309 }
1310 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1311 if (verbose)
1312 printf("RMD command not recognized, trying XRMD\n");
1313 (void) command("XRMD %s", argv[1]);
1314 }
1315 }
1316
1317 /*
1318 * Send a line, verbatim, to the remote machine.
1319 */
1320 void
1321 quote(argc, argv)
1322 int argc;
1323 char *argv[];
1324 {
1325
1326 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1327 printf("usage: %s line-to-send\n", argv[0]);
1328 code = -1;
1329 return;
1330 }
1331 quote1("", argc, argv);
1332 }
1333
1334 /*
1335 * Send a SITE command to the remote machine. The line
1336 * is sent verbatim to the remote machine, except that the
1337 * word "SITE" is added at the front.
1338 */
1339 void
1340 site(argc, argv)
1341 int argc;
1342 char *argv[];
1343 {
1344
1345 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1346 printf("usage: %s line-to-send\n", argv[0]);
1347 code = -1;
1348 return;
1349 }
1350 quote1("SITE ", argc, argv);
1351 }
1352
1353 /*
1354 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1355 * Send the result as a one-line command and get response.
1356 */
1357 void
1358 quote1(initial, argc, argv)
1359 const char *initial;
1360 int argc;
1361 char *argv[];
1362 {
1363 int i, len;
1364 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1365
1366 (void) strncpy(buf, initial, sizeof(buf));
1367 if (argc > 1) {
1368 len = strlen(buf);
1369 len += strlen(strncpy(&buf[len], argv[1], sizeof(buf) - len));
1370 for (i = 2; i < argc; i++) {
1371 buf[len++] = ' ';
1372 len += strlen(strncpy(&buf[len], argv[i],
1373 sizeof(buf) - len));
1374 }
1375 }
1376 if (command(buf) == PRELIM) {
1377 while (getreply(0) == PRELIM)
1378 continue;
1379 }
1380 }
1381
1382 void
1383 do_chmod(argc, argv)
1384 int argc;
1385 char *argv[];
1386 {
1387
1388 if (argc < 2 && !another(&argc, &argv, "mode"))
1389 goto usage;
1390 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1391 usage:
1392 printf("usage: %s mode file-name\n", argv[0]);
1393 code = -1;
1394 return;
1395 }
1396 (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
1397 }
1398
1399 void
1400 do_umask(argc, argv)
1401 int argc;
1402 char *argv[];
1403 {
1404 int oldverbose = verbose;
1405
1406 verbose = 1;
1407 (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1408 verbose = oldverbose;
1409 }
1410
1411 void
1412 idle(argc, argv)
1413 int argc;
1414 char *argv[];
1415 {
1416 int oldverbose = verbose;
1417
1418 verbose = 1;
1419 (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1420 verbose = oldverbose;
1421 }
1422
1423 /*
1424 * Ask the other side for help.
1425 */
1426 void
1427 rmthelp(argc, argv)
1428 int argc;
1429 char *argv[];
1430 {
1431 int oldverbose = verbose;
1432
1433 verbose = 1;
1434 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1435 verbose = oldverbose;
1436 }
1437
1438 /*
1439 * Terminate session and exit.
1440 */
1441 /*VARARGS*/
1442 void
1443 quit(argc, argv)
1444 int argc;
1445 char *argv[];
1446 {
1447
1448 if (connected)
1449 disconnect(0, 0);
1450 pswitch(1);
1451 if (connected) {
1452 disconnect(0, 0);
1453 }
1454 exit(0);
1455 }
1456
1457 /*
1458 * Terminate session, but don't exit.
1459 */
1460 void
1461 disconnect(argc, argv)
1462 int argc;
1463 char *argv[];
1464 {
1465
1466 if (!connected)
1467 return;
1468 (void) command("QUIT");
1469 if (cout) {
1470 (void) fclose(cout);
1471 }
1472 cout = NULL;
1473 connected = 0;
1474 data = -1;
1475 if (!proxy) {
1476 macnum = 0;
1477 }
1478 }
1479
1480 void
1481 account(argc, argv)
1482 int argc;
1483 char *argv[];
1484 {
1485 char *ap;
1486
1487 if (argc > 2) {
1488 printf("usage: %s [password]\n", argv[0]);
1489 code = -1;
1490 return;
1491 }
1492 else if (argc == 2)
1493 ap = argv[1];
1494 else
1495 ap = getpass("Account:");
1496 (void) command("ACCT %s", ap);
1497 }
1498
1499 jmp_buf abortprox;
1500
1501 void
1502 proxabort()
1503 {
1504
1505 if (!proxy) {
1506 pswitch(1);
1507 }
1508 if (connected) {
1509 proxflag = 1;
1510 }
1511 else {
1512 proxflag = 0;
1513 }
1514 pswitch(0);
1515 longjmp(abortprox, 1);
1516 }
1517
1518 void
1519 doproxy(argc, argv)
1520 int argc;
1521 char *argv[];
1522 {
1523 struct cmd *c;
1524 int cmdpos;
1525 sig_t oldintr;
1526
1527 if (argc < 2 && !another(&argc, &argv, "command")) {
1528 printf("usage: %s command\n", argv[0]);
1529 code = -1;
1530 return;
1531 }
1532 c = getcmd(argv[1]);
1533 if (c == (struct cmd *) -1) {
1534 printf("?Ambiguous command\n");
1535 (void) fflush(stdout);
1536 code = -1;
1537 return;
1538 }
1539 if (c == 0) {
1540 printf("?Invalid command\n");
1541 (void) fflush(stdout);
1542 code = -1;
1543 return;
1544 }
1545 if (!c->c_proxy) {
1546 printf("?Invalid proxy command\n");
1547 (void) fflush(stdout);
1548 code = -1;
1549 return;
1550 }
1551 if (setjmp(abortprox)) {
1552 code = -1;
1553 return;
1554 }
1555 oldintr = signal(SIGINT, proxabort);
1556 pswitch(1);
1557 if (c->c_conn && !connected) {
1558 printf("Not connected\n");
1559 (void) fflush(stdout);
1560 pswitch(0);
1561 (void) signal(SIGINT, oldintr);
1562 code = -1;
1563 return;
1564 }
1565 cmdpos = strcspn(line, " \t");
1566 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1567 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1568 (*c->c_handler)(argc-1, argv+1);
1569 if (connected) {
1570 proxflag = 1;
1571 }
1572 else {
1573 proxflag = 0;
1574 }
1575 pswitch(0);
1576 (void) signal(SIGINT, oldintr);
1577 }
1578
1579 void
1580 setcase(argc, argv)
1581 int argc;
1582 char *argv[];
1583 {
1584
1585 code = togglevar(argc, argv, &mcase, "Case mapping");
1586 }
1587
1588 void
1589 setcr(argc, argv)
1590 int argc;
1591 char *argv[];
1592 {
1593
1594 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1595 }
1596
1597 void
1598 setntrans(argc, argv)
1599 int argc;
1600 char *argv[];
1601 {
1602 if (argc == 1) {
1603 ntflag = 0;
1604 printf("Ntrans off.\n");
1605 code = ntflag;
1606 return;
1607 }
1608 ntflag++;
1609 code = ntflag;
1610 (void) strncpy(ntin, argv[1], 16);
1611 ntin[16] = '\0';
1612 if (argc == 2) {
1613 ntout[0] = '\0';
1614 return;
1615 }
1616 (void) strncpy(ntout, argv[2], 16);
1617 ntout[16] = '\0';
1618 }
1619
1620 char *
1621 dotrans(name)
1622 char *name;
1623 {
1624 static char new[MAXPATHLEN];
1625 char *cp1, *cp2 = new;
1626 int i, ostop, found;
1627
1628 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1629 continue;
1630 for (cp1 = name; *cp1; cp1++) {
1631 found = 0;
1632 for (i = 0; *(ntin + i) && i < 16; i++) {
1633 if (*cp1 == *(ntin + i)) {
1634 found++;
1635 if (i < ostop) {
1636 *cp2++ = *(ntout + i);
1637 }
1638 break;
1639 }
1640 }
1641 if (!found) {
1642 *cp2++ = *cp1;
1643 }
1644 }
1645 *cp2 = '\0';
1646 return (new);
1647 }
1648
1649 void
1650 setnmap(argc, argv)
1651 int argc;
1652 char *argv[];
1653 {
1654 char *cp;
1655
1656 if (argc == 1) {
1657 mapflag = 0;
1658 printf("Nmap off.\n");
1659 code = mapflag;
1660 return;
1661 }
1662 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1663 printf("Usage: %s [mapin mapout]\n", argv[0]);
1664 code = -1;
1665 return;
1666 }
1667 mapflag = 1;
1668 code = 1;
1669 cp = strchr(altarg, ' ');
1670 if (proxy) {
1671 while(*++cp == ' ')
1672 continue;
1673 altarg = cp;
1674 cp = strchr(altarg, ' ');
1675 }
1676 *cp = '\0';
1677 (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1678 while (*++cp == ' ')
1679 continue;
1680 (void) strncpy(mapout, cp, MAXPATHLEN - 1);
1681 }
1682
1683 char *
1684 domap(name)
1685 char *name;
1686 {
1687 static char new[MAXPATHLEN];
1688 char *cp1 = name, *cp2 = mapin;
1689 char *tp[9], *te[9];
1690 int i, toks[9], toknum = 0, match = 1;
1691
1692 for (i=0; i < 9; ++i) {
1693 toks[i] = 0;
1694 }
1695 while (match && *cp1 && *cp2) {
1696 switch (*cp2) {
1697 case '\\':
1698 if (*++cp2 != *cp1) {
1699 match = 0;
1700 }
1701 break;
1702 case '$':
1703 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1704 if (*cp1 != *(++cp2+1)) {
1705 toks[toknum = *cp2 - '1']++;
1706 tp[toknum] = cp1;
1707 while (*++cp1 && *(cp2+1)
1708 != *cp1);
1709 te[toknum] = cp1;
1710 }
1711 cp2++;
1712 break;
1713 }
1714 /* FALLTHROUGH */
1715 default:
1716 if (*cp2 != *cp1) {
1717 match = 0;
1718 }
1719 break;
1720 }
1721 if (match && *cp1) {
1722 cp1++;
1723 }
1724 if (match && *cp2) {
1725 cp2++;
1726 }
1727 }
1728 if (!match && *cp1) /* last token mismatch */
1729 {
1730 toks[toknum] = 0;
1731 }
1732 cp1 = new;
1733 *cp1 = '\0';
1734 cp2 = mapout;
1735 while (*cp2) {
1736 match = 0;
1737 switch (*cp2) {
1738 case '\\':
1739 if (*(cp2 + 1)) {
1740 *cp1++ = *++cp2;
1741 }
1742 break;
1743 case '[':
1744 LOOP:
1745 if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1746 if (*++cp2 == '0') {
1747 char *cp3 = name;
1748
1749 while (*cp3) {
1750 *cp1++ = *cp3++;
1751 }
1752 match = 1;
1753 }
1754 else if (toks[toknum = *cp2 - '1']) {
1755 char *cp3 = tp[toknum];
1756
1757 while (cp3 != te[toknum]) {
1758 *cp1++ = *cp3++;
1759 }
1760 match = 1;
1761 }
1762 }
1763 else {
1764 while (*cp2 && *cp2 != ',' &&
1765 *cp2 != ']') {
1766 if (*cp2 == '\\') {
1767 cp2++;
1768 }
1769 else if (*cp2 == '$' &&
1770 isdigit(*(cp2+1))) {
1771 if (*++cp2 == '0') {
1772 char *cp3 = name;
1773
1774 while (*cp3) {
1775 *cp1++ = *cp3++;
1776 }
1777 }
1778 else if (toks[toknum =
1779 *cp2 - '1']) {
1780 char *cp3=tp[toknum];
1781
1782 while (cp3 !=
1783 te[toknum]) {
1784 *cp1++ = *cp3++;
1785 }
1786 }
1787 }
1788 else if (*cp2) {
1789 *cp1++ = *cp2++;
1790 }
1791 }
1792 if (!*cp2) {
1793 printf("nmap: unbalanced "
1794 "brackets\n");
1795 return (name);
1796 }
1797 match = 1;
1798 cp2--;
1799 }
1800 if (match) {
1801 while (*++cp2 && *cp2 != ']') {
1802 if (*cp2 == '\\' && *(cp2 + 1)) {
1803 cp2++;
1804 }
1805 }
1806 if (!*cp2) {
1807 printf("nmap: unbalanced "
1808 "brackets\n");
1809 return (name);
1810 }
1811 break;
1812 }
1813 switch (*++cp2) {
1814 case ',':
1815 goto LOOP;
1816 case ']':
1817 break;
1818 default:
1819 cp2--;
1820 goto LOOP;
1821 }
1822 break;
1823 case '$':
1824 if (isdigit(*(cp2 + 1))) {
1825 if (*++cp2 == '0') {
1826 char *cp3 = name;
1827
1828 while (*cp3) {
1829 *cp1++ = *cp3++;
1830 }
1831 }
1832 else if (toks[toknum = *cp2 - '1']) {
1833 char *cp3 = tp[toknum];
1834
1835 while (cp3 != te[toknum]) {
1836 *cp1++ = *cp3++;
1837 }
1838 }
1839 break;
1840 }
1841 /* intentional drop through */
1842 default:
1843 *cp1++ = *cp2;
1844 break;
1845 }
1846 cp2++;
1847 }
1848 *cp1 = '\0';
1849 if (!*new) {
1850 return (name);
1851 }
1852 return (new);
1853 }
1854
1855 void
1856 setpassive(argc, argv)
1857 int argc;
1858 char *argv[];
1859 {
1860
1861 code = togglevar(argc, argv, &passivemode, "Passive mode");
1862 }
1863
1864 void
1865 setsunique(argc, argv)
1866 int argc;
1867 char *argv[];
1868 {
1869
1870 code = togglevar(argc, argv, &sunique, "Store unique");
1871 }
1872
1873 void
1874 setrunique(argc, argv)
1875 int argc;
1876 char *argv[];
1877 {
1878
1879 code = togglevar(argc, argv, &runique, "Receive unique");
1880 }
1881
1882 /* change directory to parent directory */
1883 void
1884 cdup(argc, argv)
1885 int argc;
1886 char *argv[];
1887 {
1888 int r;
1889
1890 r = command("CDUP");
1891 if (r == ERROR && code == 500) {
1892 if (verbose)
1893 printf("CDUP command not recognized, trying XCUP\n");
1894 r = command("XCUP");
1895 }
1896 if (r == COMPLETE)
1897 dirchange = 1;
1898 }
1899
1900 /* restart transfer at specific point */
1901 void
1902 restart(argc, argv)
1903 int argc;
1904 char *argv[];
1905 {
1906
1907 if (argc != 2)
1908 printf("restart: offset not specified\n");
1909 else {
1910 restart_point = atol(argv[1]);
1911 printf("Restarting at %qd. Execute get, put or append to"
1912 "initiate transfer\n", restart_point);
1913 }
1914 }
1915
1916 /* show remote system type */
1917 void
1918 syst(argc, argv)
1919 int argc;
1920 char *argv[];
1921 {
1922
1923 (void) command("SYST");
1924 }
1925
1926 void
1927 macdef(argc, argv)
1928 int argc;
1929 char *argv[];
1930 {
1931 char *tmp;
1932 int c;
1933
1934 if (macnum == 16) {
1935 printf("Limit of 16 macros have already been defined\n");
1936 code = -1;
1937 return;
1938 }
1939 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
1940 printf("Usage: %s macro_name\n", argv[0]);
1941 code = -1;
1942 return;
1943 }
1944 if (interactive) {
1945 printf("Enter macro line by line, terminating it with a "
1946 "null line\n");
1947 }
1948 (void) strncpy(macros[macnum].mac_name, argv[1], 8);
1949 if (macnum == 0) {
1950 macros[macnum].mac_start = macbuf;
1951 }
1952 else {
1953 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1954 }
1955 tmp = macros[macnum].mac_start;
1956 while (tmp != macbuf+4096) {
1957 if ((c = getchar()) == EOF) {
1958 printf("macdef:end of file encountered\n");
1959 code = -1;
1960 return;
1961 }
1962 if ((*tmp = c) == '\n') {
1963 if (tmp == macros[macnum].mac_start) {
1964 macros[macnum++].mac_end = tmp;
1965 code = 0;
1966 return;
1967 }
1968 if (*(tmp-1) == '\0') {
1969 macros[macnum++].mac_end = tmp - 1;
1970 code = 0;
1971 return;
1972 }
1973 *tmp = '\0';
1974 }
1975 tmp++;
1976 }
1977 while (1) {
1978 while ((c = getchar()) != '\n' && c != EOF)
1979 /* LOOP */;
1980 if (c == EOF || getchar() == '\n') {
1981 printf("Macro not defined - 4k buffer exceeded\n");
1982 code = -1;
1983 return;
1984 }
1985 }
1986 }
1987
1988 /*
1989 * get size of file on remote machine
1990 */
1991 void
1992 sizecmd(argc, argv)
1993 int argc;
1994 char *argv[];
1995 {
1996 off_t size;
1997
1998 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
1999 printf("usage: %s filename\n", argv[0]);
2000 code = -1;
2001 return;
2002 }
2003 size = remotesize(argv[1], 1);
2004 if (size != -1)
2005 printf("%s\t%qd\n", argv[1], size);
2006 code = size;
2007 }
2008
2009 /*
2010 * get last modification time of file on remote machine
2011 */
2012 void
2013 modtime(argc, argv)
2014 int argc;
2015 char *argv[];
2016 {
2017 time_t mtime;
2018
2019 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2020 printf("usage: %s filename\n", argv[0]);
2021 code = -1;
2022 return;
2023 }
2024 mtime = remotemodtime(argv[1], 1);
2025 if (mtime != -1)
2026 printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2027 code = mtime;
2028 }
2029
2030 /*
2031 * show status on remote machine
2032 */
2033 void
2034 rmtstatus(argc, argv)
2035 int argc;
2036 char *argv[];
2037 {
2038
2039 (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2040 }
2041
2042 /*
2043 * get file if modtime is more recent than current file
2044 */
2045 void
2046 newer(argc, argv)
2047 int argc;
2048 char *argv[];
2049 {
2050
2051 if (getit(argc, argv, -1, "w"))
2052 printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2053 argv[2], argv[1]);
2054 }
2055