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