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