Annotation of src/usr.bin/ftp/cmds.c, Revision 1.72
1.72 ! deraadt 1: /* $OpenBSD: cmds.c,v 1.71 2012/10/15 21:20:05 bluhm Exp $ */
1.23 millert 2: /* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */
1.1 deraadt 3:
4: /*
1.32 itojun 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: /*
1.1 deraadt 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.
1.45 millert 45: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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:
1.70 martynas 62: #ifndef SMALL
63:
1.1 deraadt 64: /*
65: * FTP User Program -- Command Routines.
66: */
1.13 millert 67: #include <sys/types.h>
68: #include <sys/socket.h>
69: #include <sys/stat.h>
1.1 deraadt 70: #include <sys/wait.h>
71: #include <arpa/ftp.h>
72:
73: #include <ctype.h>
74: #include <err.h>
1.63 martynas 75: #include <fnmatch.h>
1.1 deraadt 76: #include <glob.h>
77: #include <netdb.h>
78: #include <stdio.h>
79: #include <stdlib.h>
80: #include <string.h>
81: #include <unistd.h>
1.72 ! deraadt 82: #include <errno.h>
1.1 deraadt 83:
84: #include "ftp_var.h"
85: #include "pathnames.h"
1.70 martynas 86: #include "cmds.h"
1.1 deraadt 87:
88: /*
89: * Set ascii transfer type.
90: */
1.48 deraadt 91: /*ARGSUSED*/
1.1 deraadt 92: void
1.47 deraadt 93: setascii(int argc, char *argv[])
1.1 deraadt 94: {
95:
96: stype[1] = "ascii";
97: settype(2, stype);
98: }
99:
100: /*
101: * Set tenex transfer type.
102: */
1.48 deraadt 103: /*ARGSUSED*/
1.1 deraadt 104: void
1.47 deraadt 105: settenex(int argc, char *argv[])
1.1 deraadt 106: {
107:
108: stype[1] = "tenex";
109: settype(2, stype);
110: }
111:
112: /*
113: * Set file transfer mode.
114: */
115: /*ARGSUSED*/
116: void
1.47 deraadt 117: setftmode(int argc, char *argv[])
1.1 deraadt 118: {
119:
1.20 deraadt 120: fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
1.1 deraadt 121: code = -1;
122: }
123:
124: /*
125: * Set file transfer format.
126: */
127: /*ARGSUSED*/
128: void
1.47 deraadt 129: setform(int argc, char *argv[])
1.1 deraadt 130: {
131:
1.20 deraadt 132: fprintf(ttyout, "We only support %s format, sorry.\n", formname);
1.1 deraadt 133: code = -1;
134: }
135:
136: /*
137: * Set file transfer structure.
138: */
139: /*ARGSUSED*/
140: void
1.47 deraadt 141: setstruct(int argc, char *argv[])
1.1 deraadt 142: {
143:
1.20 deraadt 144: fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
1.1 deraadt 145: code = -1;
146: }
147:
1.62 martynas 148: void
149: reput(int argc, char *argv[])
150: {
151:
152: (void)putit(argc, argv, 1);
153: }
154:
155: void
156: put(int argc, char *argv[])
157: {
158:
159: (void)putit(argc, argv, 0);
160: }
161:
1.1 deraadt 162: /*
163: * Send a single file.
164: */
165: void
1.62 martynas 166: putit(int argc, char *argv[], int restartit)
1.1 deraadt 167: {
168: char *cmd;
169: int loc = 0;
170: char *oldargv1, *oldargv2;
171:
172: if (argc == 2) {
173: argc++;
174: argv[2] = argv[1];
175: loc++;
176: }
177: if (argc < 2 && !another(&argc, &argv, "local-file"))
178: goto usage;
1.13 millert 179: if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
1.1 deraadt 180: usage:
1.64 sobrado 181: fprintf(ttyout, "usage: %s local-file [remote-file]\n",
182: argv[0]);
1.1 deraadt 183: code = -1;
184: return;
185: }
186: oldargv1 = argv[1];
187: oldargv2 = argv[2];
188: if (!globulize(&argv[1])) {
189: code = -1;
190: return;
191: }
192: /*
193: * If "globulize" modifies argv[1], and argv[2] is a copy of
194: * the old argv[1], make it a copy of the new argv[1].
195: */
196: if (argv[1] != oldargv1 && argv[2] == oldargv1) {
197: argv[2] = argv[1];
198: }
1.62 martynas 199: if (restartit == 1) {
200: if (curtype != type)
201: changetype(type, 0);
202: restart_point = remotesize(argv[2], 1);
203: if (restart_point < 0) {
204: restart_point = 0;
205: code = -1;
206: return;
207: }
208: }
209: if (strcmp(argv[0], "append") == 0) {
210: restartit = 1;
211: }
212: cmd = restartit ? "APPE" : ((sunique) ? "STOU" : "STOR");
1.1 deraadt 213: if (loc && ntflag) {
214: argv[2] = dotrans(argv[2]);
215: }
216: if (loc && mapflag) {
217: argv[2] = domap(argv[2]);
218: }
219: sendrequest(cmd, argv[1], argv[2],
220: argv[1] != oldargv1 || argv[2] != oldargv2);
1.62 martynas 221: restart_point = 0;
1.23 millert 222: if (oldargv1 != argv[1]) /* free up after globulize() */
223: free(argv[1]);
1.1 deraadt 224: }
225:
226: /*
227: * Send multiple files.
228: */
229: void
1.47 deraadt 230: mput(int argc, char *argv[])
1.1 deraadt 231: {
1.62 martynas 232: extern int optind, optreset;
233: int ch, i, restartit = 0;
1.1 deraadt 234: sig_t oldintr;
1.71 bluhm 235: char *cmd, *tp, *xargv[] = { argv[0], NULL, NULL };
236: const char *errstr;
237: static int depth = 0, max_depth = 0;
1.62 martynas 238:
239: optind = optreset = 1;
1.1 deraadt 240:
1.71 bluhm 241: if (depth)
242: depth++;
243:
244: while ((ch = getopt(argc, argv, "cd:r")) != -1) {
1.62 martynas 245: switch(ch) {
246: case 'c':
247: restartit = 1;
248: break;
1.71 bluhm 249: case 'd':
250: max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
251: if (errstr != NULL) {
252: fprintf(ttyout, "bad depth value, %s: %s\n",
253: errstr, optarg);
254: code = -1;
255: return;
256: }
257: break;
258: case 'r':
259: depth = 1;
260: break;
1.62 martynas 261: default:
262: goto usage;
263: }
264: }
265:
266: if (argc - optind < 1 && !another(&argc, &argv, "local-files")) {
267: usage:
1.71 bluhm 268: fprintf(ttyout, "usage: %s [-cr] [-d depth] local-files\n",
269: argv[0]);
1.1 deraadt 270: code = -1;
271: return;
272: }
1.62 martynas 273:
1.63 martynas 274: argv[optind - 1] = argv[0];
275: argc -= optind - 1;
276: argv += optind - 1;
1.62 martynas 277:
1.1 deraadt 278: mname = argv[0];
279: mflag = 1;
1.62 martynas 280:
1.1 deraadt 281: oldintr = signal(SIGINT, mabort);
1.14 millert 282: (void)setjmp(jabort);
1.1 deraadt 283: if (proxy) {
284: char *cp, *tp2, tmpbuf[MAXPATHLEN];
285:
1.16 millert 286: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.13 millert 287: if (*cp == '\0') {
1.1 deraadt 288: mflag = 0;
289: continue;
290: }
1.63 martynas 291: if (mflag && confirm(argv[0], cp)) {
1.1 deraadt 292: tp = cp;
293: if (mcase) {
294: while (*tp && !islower(*tp)) {
295: tp++;
296: }
297: if (!*tp) {
298: tp = cp;
299: tp2 = tmpbuf;
1.21 millert 300: while ((*tp2 = *tp) != '\0') {
1.1 deraadt 301: if (isupper(*tp2)) {
1.23 millert 302: *tp2 =
303: tolower(*tp2);
1.1 deraadt 304: }
305: tp++;
306: tp2++;
307: }
308: }
309: tp = tmpbuf;
310: }
311: if (ntflag) {
312: tp = dotrans(tp);
313: }
314: if (mapflag) {
315: tp = domap(tp);
316: }
1.62 martynas 317: if (restartit == 1) {
318: off_t ret;
319:
320: if (curtype != type)
321: changetype(type, 0);
322: ret = remotesize(tp, 0);
323: restart_point = (ret < 0) ? 0 : ret;
324: }
325: cmd = restartit ? "APPE" : ((sunique) ?
326: "STOU" : "STOR");
327: sendrequest(cmd, cp, tp,
328: cp != tp || !interactive);
329: restart_point = 0;
1.1 deraadt 330: if (!mflag && fromatty) {
1.63 martynas 331: if (confirm(argv[0], NULL))
1.61 martynas 332: mflag = 1;
1.1 deraadt 333: }
334: }
335: }
1.14 millert 336: (void)signal(SIGINT, oldintr);
1.1 deraadt 337: mflag = 0;
338: return;
339: }
1.71 bluhm 340:
1.1 deraadt 341: for (i = 1; i < argc; i++) {
1.13 millert 342: char **cpp;
1.1 deraadt 343: glob_t gl;
344: int flags;
345:
1.71 bluhm 346: /* Copy files without word expansion */
1.1 deraadt 347: if (!doglob) {
1.63 martynas 348: if (mflag && confirm(argv[0], argv[i])) {
1.1 deraadt 349: tp = (ntflag) ? dotrans(argv[i]) : argv[i];
350: tp = (mapflag) ? domap(tp) : tp;
1.62 martynas 351: if (restartit == 1) {
352: off_t ret;
353:
354: if (curtype != type)
355: changetype(type, 0);
356: ret = remotesize(tp, 0);
357: restart_point = (ret < 0) ? 0 : ret;
358: }
359: cmd = restartit ? "APPE" : ((sunique) ?
360: "STOU" : "STOR");
361: sendrequest(cmd, argv[i], tp,
362: tp != argv[i] || !interactive);
363: restart_point = 0;
1.1 deraadt 364: if (!mflag && fromatty) {
1.63 martynas 365: if (confirm(argv[0], NULL))
1.61 martynas 366: mflag = 1;
1.1 deraadt 367: }
368: }
369: continue;
370: }
371:
1.71 bluhm 372: /* expanding file names */
1.1 deraadt 373: memset(&gl, 0, sizeof(gl));
374: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
375: if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
376: warnx("%s: not found", argv[i]);
377: globfree(&gl);
378: continue;
379: }
1.71 bluhm 380:
381: /* traverse all expanded file names */
1.1 deraadt 382: for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
1.71 bluhm 383: struct stat filestat;
384:
385: if (!mflag)
386: continue;
387: if (stat(*cpp, &filestat) != 0) {
388: warn("local: %s", *cpp);
389: continue;
390: }
391: if (S_ISDIR(filestat.st_mode) && depth == max_depth)
392: continue;
393: if (!confirm(argv[0], *cpp))
394: continue;
395:
396: /*
397: * If file is a directory then create a new one
398: * at the remote machine.
399: */
400: if (S_ISDIR(filestat.st_mode)) {
401: xargv[1] = *cpp;
402: makedir(2, xargv);
403: cd(2, xargv);
404: if (dirchange != 1) {
405: warnx("remote: %s", *cpp);
406: continue;
407: }
408:
409: if (chdir(*cpp) != 0) {
410: warn("local: %s", *cpp);
411: goto out;
412: }
1.62 martynas 413:
1.71 bluhm 414: /* Copy the whole directory recursively. */
415: xargv[1] = "*";
416: mput(2, xargv);
417:
418: if (chdir("..") != 0) {
419: mflag = 0;
420: warn("local: %s", *cpp);
421: goto out;
1.62 martynas 422: }
1.71 bluhm 423:
424: out:
425: xargv[1] = "..";
426: cd(2, xargv);
427: if (dirchange != 1) {
428: warnx("remote: %s", *cpp);
429: mflag = 0;
1.1 deraadt 430: }
1.71 bluhm 431: continue;
432: }
433:
434: tp = (ntflag) ? dotrans(*cpp) : *cpp;
435: tp = (mapflag) ? domap(tp) : tp;
436: if (restartit == 1) {
437: off_t ret;
438:
439: if (curtype != type)
440: changetype(type, 0);
441: ret = remotesize(tp, 0);
442: restart_point = (ret < 0) ? 0 : ret;
443: }
444: cmd = restartit ? "APPE" : ((sunique) ?
445: "STOU" : "STOR");
446: sendrequest(cmd, *cpp, tp,
447: *cpp != tp || !interactive);
448: restart_point = 0;
449: if (!mflag && fromatty) {
450: if (confirm(argv[0], NULL))
451: mflag = 1;
1.1 deraadt 452: }
453: }
454: globfree(&gl);
455: }
1.71 bluhm 456:
1.14 millert 457: (void)signal(SIGINT, oldintr);
1.71 bluhm 458:
459: if (depth)
460: depth--;
461: if (depth == 0 || mflag == 0)
462: depth = max_depth = mflag = 0;
1.1 deraadt 463: }
464:
465: void
1.47 deraadt 466: reget(int argc, char *argv[])
1.1 deraadt 467: {
468:
1.67 martynas 469: (void)getit(argc, argv, 1, "a+w");
1.1 deraadt 470: }
471:
472: char *
1.47 deraadt 473: onoff(int bool)
1.1 deraadt 474: {
475:
476: return (bool ? "on" : "off");
477: }
478:
479: /*
480: * Show status.
481: */
482: /*ARGSUSED*/
483: void
1.47 deraadt 484: status(int argc, char *argv[])
1.1 deraadt 485: {
486: int i;
487:
488: if (connected)
1.20 deraadt 489: fprintf(ttyout, "Connected %sto %s.\n",
1.19 millert 490: connected == -1 ? "and logged in" : "", hostname);
1.1 deraadt 491: else
1.20 deraadt 492: fputs("Not connected.\n", ttyout);
1.1 deraadt 493: if (!proxy) {
494: pswitch(1);
495: if (connected) {
1.20 deraadt 496: fprintf(ttyout, "Connected for proxy commands to %s.\n",
1.13 millert 497: hostname);
1.1 deraadt 498: }
499: else {
1.20 deraadt 500: fputs("No proxy connection.\n", ttyout);
1.1 deraadt 501: }
502: pswitch(0);
503: }
1.32 itojun 504: fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
505: *gateserver ? gateserver : "(none)", gateport);
1.20 deraadt 506: fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode));
507: fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
1.1 deraadt 508: modename, typename, formname, structname);
1.20 deraadt 509: fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
1.1 deraadt 510: onoff(verbose), onoff(bell), onoff(interactive),
511: onoff(doglob));
1.20 deraadt 512: fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique),
1.1 deraadt 513: onoff(runique));
1.20 deraadt 514: fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
515: fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
1.1 deraadt 516: if (ntflag) {
1.20 deraadt 517: fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
1.1 deraadt 518: }
519: else {
1.20 deraadt 520: fputs("Ntrans: off.\n", ttyout);
1.1 deraadt 521: }
522: if (mapflag) {
1.20 deraadt 523: fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
1.1 deraadt 524: }
525: else {
1.20 deraadt 526: fputs("Nmap: off.\n", ttyout);
1.1 deraadt 527: }
1.20 deraadt 528: fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
1.13 millert 529: onoff(hash), mark, onoff(progress));
1.32 itojun 530: fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport));
1.34 itojun 531: fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
532: epsv4bad ? " (disabled for this connection)" : "");
1.20 deraadt 533: fprintf(ttyout, "Command line editing: %s.\n", onoff(editing));
1.1 deraadt 534: if (macnum > 0) {
1.27 millert 535: fputs("Macros:\n", ttyout);
1.1 deraadt 536: for (i=0; i<macnum; i++) {
1.20 deraadt 537: fprintf(ttyout, "\t%s\n", macros[i].mac_name);
1.1 deraadt 538: }
539: }
540: code = 0;
541: }
542:
543: /*
1.13 millert 544: * Toggle a variable
545: */
546: int
1.47 deraadt 547: togglevar(int argc, char *argv[], int *var, const char *mesg)
1.13 millert 548: {
549: if (argc < 2) {
550: *var = !*var;
551: } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
552: *var = 1;
553: } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
554: *var = 0;
555: } else {
1.64 sobrado 556: fprintf(ttyout, "usage: %s [on | off]\n", argv[0]);
1.16 millert 557: return (-1);
1.13 millert 558: }
1.15 millert 559: if (mesg)
1.20 deraadt 560: fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
1.14 millert 561: return (*var);
1.13 millert 562: }
563:
564: /*
1.1 deraadt 565: * Set beep on cmd completed mode.
566: */
1.48 deraadt 567: /*ARGSUSED*/
1.1 deraadt 568: void
1.47 deraadt 569: setbell(int argc, char *argv[])
1.1 deraadt 570: {
571:
1.13 millert 572: code = togglevar(argc, argv, &bell, "Bell mode");
1.1 deraadt 573: }
574:
575: /*
1.13 millert 576: * Set command line editing
1.1 deraadt 577: */
1.48 deraadt 578: /*ARGSUSED*/
1.1 deraadt 579: void
1.47 deraadt 580: setedit(int argc, char *argv[])
1.1 deraadt 581: {
582:
1.13 millert 583: code = togglevar(argc, argv, &editing, "Editing mode");
1.18 millert 584: controlediting();
1.1 deraadt 585: }
1.34 itojun 586:
587: /*
588: * Toggle use of IPv4 EPSV/EPRT
589: */
1.48 deraadt 590: /*ARGSUSED*/
1.34 itojun 591: void
1.47 deraadt 592: setepsv4(int argc, char *argv[])
1.34 itojun 593: {
594:
595: code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4");
596: epsv4bad = 0;
597: }
1.1 deraadt 598:
599: /*
1.13 millert 600: * Turn on packet tracing.
1.1 deraadt 601: */
1.48 deraadt 602: /*ARGSUSED*/
1.1 deraadt 603: void
1.47 deraadt 604: settrace(int argc, char *argv[])
1.1 deraadt 605: {
606:
1.13 millert 607: code = togglevar(argc, argv, &trace, "Packet tracing");
1.1 deraadt 608: }
1.6 kstailey 609:
610: /*
1.13 millert 611: * Toggle hash mark printing during transfers, or set hash mark bytecount.
1.6 kstailey 612: */
1.48 deraadt 613: /*ARGSUSED*/
1.6 kstailey 614: void
1.47 deraadt 615: sethash(int argc, char *argv[])
1.6 kstailey 616: {
617: if (argc == 1)
1.13 millert 618: hash = !hash;
1.6 kstailey 619: else if (argc != 2) {
1.64 sobrado 620: fprintf(ttyout, "usage: %s [on | off | size]\n", argv[0]);
1.13 millert 621: code = -1;
622: return;
623: } else if (strcasecmp(argv[1], "on") == 0)
624: hash = 1;
625: else if (strcasecmp(argv[1], "off") == 0)
626: hash = 0;
627: else {
1.50 tedu 628: int nmark;
629: const char *errstr;
1.28 millert 630:
1.50 tedu 631: nmark = strtonum(argv[1], 1, INT_MAX, &errstr);
632: if (errstr) {
633: fprintf(ttyout, "bytecount value is %s: %s\n",
634: errstr, argv[1]);
1.13 millert 635: code = -1;
636: return;
1.6 kstailey 637: }
1.13 millert 638: mark = nmark;
639: hash = 1;
1.6 kstailey 640: }
1.20 deraadt 641: fprintf(ttyout, "Hash mark printing %s", onoff(hash));
1.13 millert 642: if (hash)
1.20 deraadt 643: fprintf(ttyout, " (%d bytes/hash mark)", mark);
644: fputs(".\n", ttyout);
1.13 millert 645: code = hash;
1.6 kstailey 646: }
647:
1.1 deraadt 648: /*
649: * Turn on printing of server echo's.
650: */
1.48 deraadt 651: /*ARGSUSED*/
1.1 deraadt 652: void
1.47 deraadt 653: setverbose(int argc, char *argv[])
1.1 deraadt 654: {
655:
1.13 millert 656: code = togglevar(argc, argv, &verbose, "Verbose mode");
1.1 deraadt 657: }
658:
659: /*
1.32 itojun 660: * Toggle PORT/LPRT cmd use before each data connection.
1.1 deraadt 661: */
1.48 deraadt 662: /*ARGSUSED*/
1.1 deraadt 663: void
1.47 deraadt 664: setport(int argc, char *argv[])
1.1 deraadt 665: {
666:
1.32 itojun 667: code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
1.13 millert 668: }
669:
670: /*
671: * Toggle transfer progress bar.
672: */
1.48 deraadt 673: /*ARGSUSED*/
1.13 millert 674: void
1.47 deraadt 675: setprogress(int argc, char *argv[])
1.13 millert 676: {
677:
678: code = togglevar(argc, argv, &progress, "Progress bar");
1.1 deraadt 679: }
680:
681: /*
1.23 millert 682: * Turn on interactive prompting during mget, mput, and mdelete.
1.1 deraadt 683: */
1.48 deraadt 684: /*ARGSUSED*/
1.1 deraadt 685: void
1.47 deraadt 686: setprompt(int argc, char *argv[])
1.1 deraadt 687: {
688:
1.13 millert 689: code = togglevar(argc, argv, &interactive, "Interactive mode");
1.1 deraadt 690: }
691:
692: /*
1.23 millert 693: * Toggle gate-ftp mode, or set gate-ftp server
694: */
1.48 deraadt 695: /*ARGSUSED*/
1.23 millert 696: void
1.47 deraadt 697: setgate(int argc, char *argv[])
1.23 millert 698: {
699: static char gsbuf[MAXHOSTNAMELEN];
700:
701: if (argc > 3) {
1.64 sobrado 702: fprintf(ttyout, "usage: %s [on | off | host [port]]\n",
1.23 millert 703: argv[0]);
704: code = -1;
705: return;
706: } else if (argc < 2) {
707: gatemode = !gatemode;
708: } else {
709: if (argc == 2 && strcasecmp(argv[1], "on") == 0)
710: gatemode = 1;
711: else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
712: gatemode = 0;
713: else {
714: if (argc == 3) {
1.32 itojun 715: gateport = strdup(argv[2]);
1.41 deraadt 716: if (gateport == NULL)
717: err(1, NULL);
1.23 millert 718: }
1.36 lebel 719: strlcpy(gsbuf, argv[1], sizeof(gsbuf));
1.23 millert 720: gateserver = gsbuf;
721: gatemode = 1;
722: }
723: }
724: if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
725: fprintf(ttyout,
726: "Disabling gate-ftp mode - no gate-ftp server defined.\n");
727: gatemode = 0;
728: } else {
1.32 itojun 729: fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
1.23 millert 730: onoff(gatemode),
1.32 itojun 731: *gateserver ? gateserver : "(none)", gateport);
1.23 millert 732: }
733: code = gatemode;
734: }
735:
736: /*
737: * Toggle metacharacter interpretation on local file names.
1.1 deraadt 738: */
1.48 deraadt 739: /*ARGSUSED*/
1.1 deraadt 740: void
1.47 deraadt 741: setglob(int argc, char *argv[])
1.1 deraadt 742: {
1.13 millert 743:
744: code = togglevar(argc, argv, &doglob, "Globbing");
745: }
746:
747: /*
1.31 aaron 748: * Toggle preserving modification times on retrieved files.
1.13 millert 749: */
1.48 deraadt 750: /*ARGSUSED*/
1.13 millert 751: void
1.47 deraadt 752: setpreserve(int argc, char *argv[])
1.13 millert 753: {
754:
755: code = togglevar(argc, argv, &preserve, "Preserve modification times");
1.1 deraadt 756: }
757:
758: /*
1.23 millert 759: * Set debugging mode on/off and/or set level of debugging.
1.1 deraadt 760: */
1.48 deraadt 761: /*ARGSUSED*/
1.1 deraadt 762: void
1.47 deraadt 763: setdebug(int argc, char *argv[])
1.1 deraadt 764: {
1.13 millert 765: if (argc > 2) {
1.64 sobrado 766: fprintf(ttyout, "usage: %s [on | off | debuglevel]\n", argv[0]);
1.13 millert 767: code = -1;
768: return;
769: } else if (argc == 2) {
770: if (strcasecmp(argv[1], "on") == 0)
771: debug = 1;
772: else if (strcasecmp(argv[1], "off") == 0)
773: debug = 0;
774: else {
1.50 tedu 775: const char *errstr;
776: int val;
1.21 millert 777:
1.50 tedu 778: val = strtonum(argv[1], 0, INT_MAX, &errstr);
779: if (errstr) {
780: fprintf(ttyout, "debugging value is %s: %s\n",
781: errstr, argv[1]);
1.13 millert 782: code = -1;
783: return;
784: }
1.50 tedu 785: debug = val;
1.1 deraadt 786: }
787: } else
1.13 millert 788: debug = !debug;
1.1 deraadt 789: if (debug)
790: options |= SO_DEBUG;
791: else
792: options &= ~SO_DEBUG;
1.20 deraadt 793: fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
1.1 deraadt 794: code = debug > 0;
795: }
796:
797: /*
1.23 millert 798: * Set current working directory on local machine.
1.1 deraadt 799: */
800: void
1.47 deraadt 801: lcd(int argc, char *argv[])
1.1 deraadt 802: {
803: char buf[MAXPATHLEN];
1.23 millert 804: char *oldargv1;
1.1 deraadt 805:
806: if (argc < 2)
807: argc++, argv[1] = home;
808: if (argc != 2) {
1.64 sobrado 809: fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
1.1 deraadt 810: code = -1;
811: return;
812: }
1.23 millert 813: oldargv1 = argv[1];
1.1 deraadt 814: if (!globulize(&argv[1])) {
815: code = -1;
816: return;
817: }
818: if (chdir(argv[1]) < 0) {
819: warn("local: %s", argv[1]);
820: code = -1;
1.23 millert 821: } else {
822: if (getcwd(buf, sizeof(buf)) != NULL)
823: fprintf(ttyout, "Local directory now %s\n", buf);
824: else
825: warn("getcwd: %s", argv[1]);
826: code = 0;
1.1 deraadt 827: }
1.23 millert 828: if (oldargv1 != argv[1]) /* free up after globulize() */
829: free(argv[1]);
1.1 deraadt 830: }
831:
832: /*
833: * Delete a single file.
834: */
835: void
1.48 deraadt 836: deletecmd(int argc, char *argv[])
1.1 deraadt 837: {
838:
1.13 millert 839: if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1.20 deraadt 840: fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
1.1 deraadt 841: code = -1;
842: return;
843: }
1.14 millert 844: (void)command("DELE %s", argv[1]);
1.1 deraadt 845: }
846:
847: /*
848: * Delete multiple files.
849: */
850: void
1.47 deraadt 851: mdelete(int argc, char *argv[])
1.1 deraadt 852: {
853: sig_t oldintr;
854: char *cp;
855:
856: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1.20 deraadt 857: fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
1.1 deraadt 858: code = -1;
859: return;
860: }
861: mname = argv[0];
862: mflag = 1;
863: oldintr = signal(SIGINT, mabort);
1.14 millert 864: (void)setjmp(jabort);
1.16 millert 865: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.1 deraadt 866: if (*cp == '\0') {
867: mflag = 0;
868: continue;
869: }
1.63 martynas 870: if (mflag && confirm(argv[0], cp)) {
1.14 millert 871: (void)command("DELE %s", cp);
1.1 deraadt 872: if (!mflag && fromatty) {
1.63 martynas 873: if (confirm(argv[0], NULL))
1.61 martynas 874: mflag = 1;
1.1 deraadt 875: }
876: }
877: }
1.14 millert 878: (void)signal(SIGINT, oldintr);
1.1 deraadt 879: mflag = 0;
880: }
881:
882: /*
883: * Rename a remote file.
884: */
885: void
1.47 deraadt 886: renamefile(int argc, char *argv[])
1.1 deraadt 887: {
888:
889: if (argc < 2 && !another(&argc, &argv, "from-name"))
890: goto usage;
1.13 millert 891: if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1.1 deraadt 892: usage:
1.20 deraadt 893: fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
1.1 deraadt 894: code = -1;
895: return;
896: }
897: if (command("RNFR %s", argv[1]) == CONTINUE)
1.14 millert 898: (void)command("RNTO %s", argv[2]);
1.1 deraadt 899: }
900:
901: /*
1.23 millert 902: * Get a directory listing of remote files.
1.1 deraadt 903: */
904: void
1.47 deraadt 905: ls(int argc, char *argv[])
1.1 deraadt 906: {
1.13 millert 907: const char *cmd;
1.23 millert 908: char *oldargv2, *globargv2;
1.1 deraadt 909:
910: if (argc < 2)
911: argc++, argv[1] = NULL;
912: if (argc < 3)
913: argc++, argv[2] = "-";
914: if (argc > 3) {
1.64 sobrado 915: fprintf(ttyout, "usage: %s [remote-directory [local-file]]\n",
916: argv[0]);
1.1 deraadt 917: code = -1;
918: return;
919: }
1.33 millert 920: cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
1.23 millert 921: oldargv2 = argv[2];
1.1 deraadt 922: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
923: code = -1;
924: return;
925: }
1.23 millert 926: globargv2 = argv[2];
927: if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) ||
1.63 martynas 928: !confirm("output to local-file:", argv[2]))) {
1.23 millert 929: code = -1;
930: goto freels;
1.1 deraadt 931: }
1.23 millert 932: recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1.3 downsj 933:
934: /* flush results in case commands are coming from a pipe */
1.20 deraadt 935: fflush(ttyout);
1.23 millert 936: freels:
937: if (argv[2] != globargv2) /* free up after globulize() */
938: free(argv[2]);
939: if (globargv2 != oldargv2)
940: free(globargv2);
1.1 deraadt 941: }
942:
943: /*
1.23 millert 944: * Get a directory listing of multiple remote files.
1.1 deraadt 945: */
946: void
1.47 deraadt 947: mls(int argc, char *argv[])
1.1 deraadt 948: {
949: sig_t oldintr;
1.60 martynas 950: int i;
1.51 ray 951: char lmode[1], *dest, *odest;
1.1 deraadt 952:
953: if (argc < 2 && !another(&argc, &argv, "remote-files"))
954: goto usage;
955: if (argc < 3 && !another(&argc, &argv, "local-file")) {
956: usage:
1.20 deraadt 957: fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
1.1 deraadt 958: code = -1;
959: return;
960: }
1.23 millert 961: odest = dest = argv[argc - 1];
1.1 deraadt 962: argv[argc - 1] = NULL;
963: if (strcmp(dest, "-") && *dest != '|')
964: if (!globulize(&dest) ||
1.63 martynas 965: !confirm("output to local-file:", dest)) {
1.1 deraadt 966: code = -1;
967: return;
968: }
969: mname = argv[0];
970: mflag = 1;
971: oldintr = signal(SIGINT, mabort);
1.14 millert 972: (void)setjmp(jabort);
1.1 deraadt 973: for (i = 1; mflag && i < argc-1; ++i) {
1.51 ray 974: *lmode = (i == 1) ? 'w' : 'a';
975: recvrequest("LIST", dest, argv[i], lmode, 0, 0);
1.1 deraadt 976: if (!mflag && fromatty) {
1.63 martynas 977: if (confirm(argv[0], NULL))
1.1 deraadt 978: mflag ++;
979: }
980: }
1.14 millert 981: (void)signal(SIGINT, oldintr);
1.1 deraadt 982: mflag = 0;
1.23 millert 983: if (dest != odest) /* free up after globulize() */
984: free(dest);
1.1 deraadt 985: }
986:
987: /*
988: * Do a shell escape
989: */
990: /*ARGSUSED*/
991: void
1.47 deraadt 992: shell(int argc, char *argv[])
1.1 deraadt 993: {
994: pid_t pid;
995: sig_t old1, old2;
1.51 ray 996: char shellnam[MAXPATHLEN], *shellp, *namep;
1.24 millert 997: int wait_status;
1.1 deraadt 998:
999: old1 = signal (SIGINT, SIG_IGN);
1000: old2 = signal (SIGQUIT, SIG_IGN);
1001: if ((pid = fork()) == 0) {
1002: for (pid = 3; pid < 20; pid++)
1.14 millert 1003: (void)close(pid);
1004: (void)signal(SIGINT, SIG_DFL);
1005: (void)signal(SIGQUIT, SIG_DFL);
1.51 ray 1006: shellp = getenv("SHELL");
1007: if (shellp == NULL || *shellp == '\0')
1008: shellp = _PATH_BSHELL;
1009: namep = strrchr(shellp, '/');
1.1 deraadt 1010: if (namep == NULL)
1.51 ray 1011: namep = shellp;
1.13 millert 1012: shellnam[0] = '-';
1.36 lebel 1013: (void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1);
1.1 deraadt 1014: if (strcmp(namep, "sh") != 0)
1015: shellnam[0] = '+';
1016: if (debug) {
1.51 ray 1017: fputs(shellp, ttyout);
1.21 millert 1018: fputc('\n', ttyout);
1.20 deraadt 1019: (void)fflush(ttyout);
1.1 deraadt 1020: }
1021: if (argc > 1) {
1.51 ray 1022: execl(shellp, shellnam, "-c", altarg, (char *)0);
1.1 deraadt 1023: }
1024: else {
1.51 ray 1025: execl(shellp, shellnam, (char *)0);
1.1 deraadt 1026: }
1.51 ray 1027: warn("%s", shellp);
1.1 deraadt 1028: code = -1;
1029: exit(1);
1030: }
1031: if (pid > 0)
1.24 millert 1032: while (wait(&wait_status) != pid)
1.1 deraadt 1033: ;
1.14 millert 1034: (void)signal(SIGINT, old1);
1035: (void)signal(SIGQUIT, old2);
1.1 deraadt 1036: if (pid == -1) {
1.16 millert 1037: warn("Try again later");
1.1 deraadt 1038: code = -1;
1039: }
1040: else {
1041: code = 0;
1042: }
1043: }
1044:
1045: /*
1046: * Send new user information (re-login)
1047: */
1048: void
1.47 deraadt 1049: user(int argc, char *argv[])
1.1 deraadt 1050: {
1.51 ray 1051: char acctname[80];
1.1 deraadt 1052: int n, aflag = 0;
1053:
1054: if (argc < 2)
1.14 millert 1055: (void)another(&argc, &argv, "username");
1.1 deraadt 1056: if (argc < 2 || argc > 4) {
1.64 sobrado 1057: fprintf(ttyout, "usage: %s username [password [account]]\n",
1058: argv[0]);
1.1 deraadt 1059: code = -1;
1060: return;
1061: }
1062: n = command("USER %s", argv[1]);
1063: if (n == CONTINUE) {
1064: if (argc < 3 )
1.56 millert 1065: argv[2] = getpass("Password:"), argc++;
1.1 deraadt 1066: n = command("PASS %s", argv[2]);
1067: }
1068: if (n == CONTINUE) {
1069: if (argc < 4) {
1.20 deraadt 1070: (void)fputs("Account: ", ttyout);
1071: (void)fflush(ttyout);
1.59 martynas 1072: if (fgets(acctname, sizeof(acctname), stdin) == NULL) {
1073: clearerr(stdin);
1.53 ray 1074: goto fail;
1.59 martynas 1075: }
1.57 gilles 1076:
1077: acctname[strcspn(acctname, "\n")] = '\0';
1078:
1.51 ray 1079: argv[3] = acctname;
1080: argc++;
1.1 deraadt 1081: }
1082: n = command("ACCT %s", argv[3]);
1083: aflag++;
1084: }
1085: if (n != COMPLETE) {
1.53 ray 1086: fail:
1.20 deraadt 1087: fputs("Login failed.\n", ttyout);
1.1 deraadt 1088: return;
1089: }
1090: if (!aflag && argc == 4) {
1.14 millert 1091: (void)command("ACCT %s", argv[3]);
1.1 deraadt 1092: }
1.19 millert 1093: connected = -1;
1.1 deraadt 1094: }
1095:
1096: /*
1.13 millert 1097: * Print working directory on remote machine.
1.1 deraadt 1098: */
1.48 deraadt 1099: /*ARGSUSED*/
1.1 deraadt 1100: void
1.47 deraadt 1101: pwd(int argc, char *argv[])
1.1 deraadt 1102: {
1103: int oldverbose = verbose;
1104:
1105: /*
1106: * If we aren't verbose, this doesn't do anything!
1107: */
1108: verbose = 1;
1109: if (command("PWD") == ERROR && code == 500) {
1.20 deraadt 1110: fputs("PWD command not recognized, trying XPWD.\n", ttyout);
1.14 millert 1111: (void)command("XPWD");
1.1 deraadt 1112: }
1113: verbose = oldverbose;
1114: }
1115:
1116: /*
1.13 millert 1117: * Print working directory on local machine.
1118: */
1.48 deraadt 1119: /* ARGSUSED */
1.13 millert 1120: void
1.47 deraadt 1121: lpwd(int argc, char *argv[])
1.13 millert 1122: {
1123: char buf[MAXPATHLEN];
1124:
1125: if (getcwd(buf, sizeof(buf)) != NULL)
1.20 deraadt 1126: fprintf(ttyout, "Local directory %s\n", buf);
1.13 millert 1127: else
1128: warn("getcwd");
1129: code = 0;
1130: }
1131:
1132: /*
1.1 deraadt 1133: * Make a directory.
1134: */
1135: void
1.47 deraadt 1136: makedir(int argc, char *argv[])
1.1 deraadt 1137: {
1138:
1.13 millert 1139: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1140: argc > 2) {
1.20 deraadt 1141: fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1.1 deraadt 1142: code = -1;
1143: return;
1144: }
1145: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1146: if (verbose)
1.20 deraadt 1147: fputs("MKD command not recognized, trying XMKD.\n", ttyout);
1.14 millert 1148: (void)command("XMKD %s", argv[1]);
1.1 deraadt 1149: }
1150: }
1151:
1152: /*
1153: * Remove a directory.
1154: */
1155: void
1.47 deraadt 1156: removedir(int argc, char *argv[])
1.1 deraadt 1157: {
1158:
1.13 millert 1159: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1160: argc > 2) {
1.20 deraadt 1161: fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1.1 deraadt 1162: code = -1;
1163: return;
1164: }
1165: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1166: if (verbose)
1.20 deraadt 1167: fputs("RMD command not recognized, trying XRMD.\n", ttyout);
1.14 millert 1168: (void)command("XRMD %s", argv[1]);
1.1 deraadt 1169: }
1170: }
1171:
1172: /*
1173: * Send a line, verbatim, to the remote machine.
1174: */
1175: void
1.47 deraadt 1176: quote(int argc, char *argv[])
1.1 deraadt 1177: {
1178:
1179: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1.64 sobrado 1180: fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1.1 deraadt 1181: code = -1;
1182: return;
1183: }
1184: quote1("", argc, argv);
1185: }
1186:
1187: /*
1188: * Send a SITE command to the remote machine. The line
1189: * is sent verbatim to the remote machine, except that the
1190: * word "SITE" is added at the front.
1191: */
1192: void
1.47 deraadt 1193: site(int argc, char *argv[])
1.1 deraadt 1194: {
1195:
1196: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1.64 sobrado 1197: fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1.1 deraadt 1198: code = -1;
1199: return;
1200: }
1.26 weingart 1201: quote1("SITE", argc, argv);
1.1 deraadt 1202: }
1203:
1204: /*
1205: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1206: * Send the result as a one-line command and get response.
1207: */
1208: void
1.47 deraadt 1209: quote1(const char *initial, int argc, char *argv[])
1.1 deraadt 1210: {
1211: int i, len;
1212: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1213:
1.36 lebel 1214: (void)strlcpy(buf, initial, sizeof(buf));
1.1 deraadt 1215: if (argc > 1) {
1.26 weingart 1216: for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) {
1217: /* Space for next arg */
1218: if (len > 1)
1219: buf[len++] = ' ';
1220:
1221: /* Sanity check */
1222: if (len >= sizeof(buf) - 1)
1223: break;
1224:
1.27 millert 1225: /* Copy next argument, NUL terminate always */
1.36 lebel 1226: strlcpy(&buf[len], argv[i], sizeof(buf) - len);
1.26 weingart 1227:
1228: /* Update string length */
1229: len = strlen(buf);
1.1 deraadt 1230: }
1231: }
1.26 weingart 1232:
1.35 aaron 1233: /* Make double (triple?) sure the sucker is NUL terminated */
1.26 weingart 1234: buf[sizeof(buf) - 1] = '\0';
1235:
1.29 deraadt 1236: if (command("%s", buf) == PRELIM) {
1.1 deraadt 1237: while (getreply(0) == PRELIM)
1238: continue;
1239: }
1240: }
1241:
1242: void
1.47 deraadt 1243: do_chmod(int argc, char *argv[])
1.1 deraadt 1244: {
1245:
1246: if (argc < 2 && !another(&argc, &argv, "mode"))
1247: goto usage;
1.64 sobrado 1248: if ((argc < 3 && !another(&argc, &argv, "file")) || argc > 3) {
1.1 deraadt 1249: usage:
1.64 sobrado 1250: fprintf(ttyout, "usage: %s mode file\n", argv[0]);
1.1 deraadt 1251: code = -1;
1252: return;
1253: }
1.14 millert 1254: (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1.1 deraadt 1255: }
1256:
1257: void
1.47 deraadt 1258: do_umask(int argc, char *argv[])
1.1 deraadt 1259: {
1260: int oldverbose = verbose;
1261:
1262: verbose = 1;
1.14 millert 1263: (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1.1 deraadt 1264: verbose = oldverbose;
1265: }
1266:
1267: void
1.47 deraadt 1268: idle(int argc, char *argv[])
1.1 deraadt 1269: {
1270: int oldverbose = verbose;
1271:
1272: verbose = 1;
1.14 millert 1273: (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1.1 deraadt 1274: verbose = oldverbose;
1275: }
1276:
1277: /*
1278: * Ask the other side for help.
1279: */
1280: void
1.47 deraadt 1281: rmthelp(int argc, char *argv[])
1.1 deraadt 1282: {
1283: int oldverbose = verbose;
1284:
1285: verbose = 1;
1.14 millert 1286: (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1.1 deraadt 1287: verbose = oldverbose;
1288: }
1289:
1290: /*
1291: * Terminate session and exit.
1292: */
1.48 deraadt 1293: /*ARGSUSED*/
1.1 deraadt 1294: void
1.47 deraadt 1295: quit(int argc, char *argv[])
1.1 deraadt 1296: {
1297:
1298: if (connected)
1299: disconnect(0, 0);
1300: pswitch(1);
1301: if (connected) {
1302: disconnect(0, 0);
1303: }
1304: exit(0);
1305: }
1306:
1307: void
1.47 deraadt 1308: account(int argc, char *argv[])
1.1 deraadt 1309: {
1.13 millert 1310: char *ap;
1.1 deraadt 1311:
1.13 millert 1312: if (argc > 2) {
1.20 deraadt 1313: fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1.13 millert 1314: code = -1;
1315: return;
1.1 deraadt 1316: }
1.13 millert 1317: else if (argc == 2)
1318: ap = argv[1];
1319: else
1.1 deraadt 1320: ap = getpass("Account:");
1.14 millert 1321: (void)command("ACCT %s", ap);
1.1 deraadt 1322: }
1323:
1324: jmp_buf abortprox;
1325:
1.48 deraadt 1326: /* ARGSUSED */
1.1 deraadt 1327: void
1.48 deraadt 1328: proxabort(int signo)
1.1 deraadt 1329: {
1.72 ! deraadt 1330: int save_errno = errno;
1.1 deraadt 1331:
1.13 millert 1332: alarmtimer(0);
1.1 deraadt 1333: if (!proxy) {
1334: pswitch(1);
1335: }
1336: if (connected) {
1337: proxflag = 1;
1338: }
1339: else {
1340: proxflag = 0;
1341: }
1342: pswitch(0);
1.72 ! deraadt 1343: errno = save_errno;
1.13 millert 1344: longjmp(abortprox, 1);
1.1 deraadt 1345: }
1346:
1347: void
1.47 deraadt 1348: doproxy(int argc, char *argv[])
1.1 deraadt 1349: {
1350: struct cmd *c;
1.13 millert 1351: int cmdpos;
1.1 deraadt 1352: sig_t oldintr;
1353:
1354: if (argc < 2 && !another(&argc, &argv, "command")) {
1.20 deraadt 1355: fprintf(ttyout, "usage: %s command\n", argv[0]);
1.1 deraadt 1356: code = -1;
1357: return;
1358: }
1359: c = getcmd(argv[1]);
1360: if (c == (struct cmd *) -1) {
1.20 deraadt 1361: fputs("?Ambiguous command.\n", ttyout);
1362: (void)fflush(ttyout);
1.1 deraadt 1363: code = -1;
1364: return;
1365: }
1366: if (c == 0) {
1.20 deraadt 1367: fputs("?Invalid command.\n", ttyout);
1368: (void)fflush(ttyout);
1.1 deraadt 1369: code = -1;
1370: return;
1371: }
1372: if (!c->c_proxy) {
1.20 deraadt 1373: fputs("?Invalid proxy command.\n", ttyout);
1374: (void)fflush(ttyout);
1.1 deraadt 1375: code = -1;
1376: return;
1377: }
1378: if (setjmp(abortprox)) {
1379: code = -1;
1380: return;
1381: }
1382: oldintr = signal(SIGINT, proxabort);
1383: pswitch(1);
1384: if (c->c_conn && !connected) {
1.20 deraadt 1385: fputs("Not connected.\n", ttyout);
1386: (void)fflush(ttyout);
1.1 deraadt 1387: pswitch(0);
1.14 millert 1388: (void)signal(SIGINT, oldintr);
1.1 deraadt 1389: code = -1;
1390: return;
1391: }
1.13 millert 1392: cmdpos = strcspn(line, " \t");
1393: if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1394: memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1.1 deraadt 1395: (*c->c_handler)(argc-1, argv+1);
1396: if (connected) {
1397: proxflag = 1;
1398: }
1399: else {
1400: proxflag = 0;
1401: }
1402: pswitch(0);
1.14 millert 1403: (void)signal(SIGINT, oldintr);
1.1 deraadt 1404: }
1405:
1406: void
1.47 deraadt 1407: setcase(int argc, char *argv[])
1.1 deraadt 1408: {
1409:
1.13 millert 1410: code = togglevar(argc, argv, &mcase, "Case mapping");
1.1 deraadt 1411: }
1412:
1413: void
1.47 deraadt 1414: setcr(int argc, char *argv[])
1.1 deraadt 1415: {
1416:
1.13 millert 1417: code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1.1 deraadt 1418: }
1419:
1420: void
1.47 deraadt 1421: setntrans(int argc, char *argv[])
1.1 deraadt 1422: {
1423: if (argc == 1) {
1424: ntflag = 0;
1.20 deraadt 1425: fputs("Ntrans off.\n", ttyout);
1.1 deraadt 1426: code = ntflag;
1427: return;
1428: }
1429: ntflag++;
1430: code = ntflag;
1.36 lebel 1431: (void)strlcpy(ntin, argv[1], sizeof(ntin));
1.1 deraadt 1432: if (argc == 2) {
1433: ntout[0] = '\0';
1434: return;
1435: }
1.36 lebel 1436: (void)strlcpy(ntout, argv[2], sizeof(ntout));
1.1 deraadt 1437: }
1438:
1439: void
1.47 deraadt 1440: setnmap(int argc, char *argv[])
1.1 deraadt 1441: {
1442: char *cp;
1443:
1444: if (argc == 1) {
1445: mapflag = 0;
1.20 deraadt 1446: fputs("Nmap off.\n", ttyout);
1.1 deraadt 1447: code = mapflag;
1448: return;
1449: }
1.64 sobrado 1450: if ((argc < 3 && !another(&argc, &argv, "outpattern")) || argc > 3) {
1451: fprintf(ttyout, "usage: %s [inpattern outpattern]\n", argv[0]);
1.1 deraadt 1452: code = -1;
1453: return;
1454: }
1455: mapflag = 1;
1456: code = 1;
1457: cp = strchr(altarg, ' ');
1458: if (proxy) {
1459: while(*++cp == ' ')
1460: continue;
1461: altarg = cp;
1462: cp = strchr(altarg, ' ');
1463: }
1464: *cp = '\0';
1.14 millert 1465: (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1.1 deraadt 1466: while (*++cp == ' ')
1467: continue;
1.14 millert 1468: (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1.1 deraadt 1469: }
1470:
1471: void
1.47 deraadt 1472: setpassive(int argc, char *argv[])
1.1 deraadt 1473: {
1474:
1.15 millert 1475: code = togglevar(argc, argv, &passivemode,
1476: verbose ? "Passive mode" : NULL);
1.1 deraadt 1477: }
1478:
1479: void
1.47 deraadt 1480: setsunique(int argc, char *argv[])
1.1 deraadt 1481: {
1482:
1.13 millert 1483: code = togglevar(argc, argv, &sunique, "Store unique");
1.1 deraadt 1484: }
1485:
1486: void
1.47 deraadt 1487: setrunique(int argc, char *argv[])
1.1 deraadt 1488: {
1489:
1.13 millert 1490: code = togglevar(argc, argv, &runique, "Receive unique");
1.1 deraadt 1491: }
1492:
1.13 millert 1493: /* change directory to parent directory */
1.48 deraadt 1494: /* ARGSUSED */
1.1 deraadt 1495: void
1.47 deraadt 1496: cdup(int argc, char *argv[])
1.1 deraadt 1497: {
1.13 millert 1498: int r;
1.1 deraadt 1499:
1.13 millert 1500: r = command("CDUP");
1501: if (r == ERROR && code == 500) {
1.1 deraadt 1502: if (verbose)
1.20 deraadt 1503: fputs("CDUP command not recognized, trying XCUP.\n", ttyout);
1.13 millert 1504: r = command("XCUP");
1.1 deraadt 1505: }
1.13 millert 1506: if (r == COMPLETE)
1507: dirchange = 1;
1.1 deraadt 1508: }
1509:
1.23 millert 1510: /*
1511: * Restart transfer at specific point
1512: */
1.1 deraadt 1513: void
1.47 deraadt 1514: restart(int argc, char *argv[])
1.1 deraadt 1515: {
1.27 millert 1516: quad_t nrestart_point;
1517: char *ep;
1.1 deraadt 1518:
1519: if (argc != 2)
1.20 deraadt 1520: fputs("restart: offset not specified.\n", ttyout);
1.1 deraadt 1521: else {
1.38 millert 1522: nrestart_point = strtoq(argv[1], &ep, 10);
1.27 millert 1523: if (nrestart_point == QUAD_MAX || *ep != '\0')
1524: fputs("restart: invalid offset.\n", ttyout);
1525: else {
1.39 millert 1526: fprintf(ttyout, "Restarting at %lld. Execute get, put "
1527: "or append to initiate transfer\n",
1.37 deraadt 1528: (long long)nrestart_point);
1.27 millert 1529: restart_point = nrestart_point;
1530: }
1.1 deraadt 1531: }
1532: }
1533:
1.23 millert 1534: /*
1535: * Show remote system type
1536: */
1.48 deraadt 1537: /* ARGSUSED */
1.1 deraadt 1538: void
1.47 deraadt 1539: syst(int argc, char *argv[])
1.1 deraadt 1540: {
1541:
1.14 millert 1542: (void)command("SYST");
1.1 deraadt 1543: }
1544:
1545: void
1.47 deraadt 1546: macdef(int argc, char *argv[])
1.1 deraadt 1547: {
1548: char *tmp;
1549: int c;
1550:
1551: if (macnum == 16) {
1.20 deraadt 1552: fputs("Limit of 16 macros have already been defined.\n", ttyout);
1.1 deraadt 1553: code = -1;
1554: return;
1555: }
1.64 sobrado 1556: if ((argc < 2 && !another(&argc, &argv, "macro-name")) || argc > 2) {
1557: fprintf(ttyout, "usage: %s macro-name\n", argv[0]);
1.1 deraadt 1558: code = -1;
1559: return;
1560: }
1.16 millert 1561: if (interactive)
1.20 deraadt 1562: fputs(
1563: "Enter macro line by line, terminating it with a null line.\n", ttyout);
1.36 lebel 1564: (void)strlcpy(macros[macnum].mac_name, argv[1],
1565: sizeof(macros[macnum].mac_name));
1.14 millert 1566: if (macnum == 0)
1.1 deraadt 1567: macros[macnum].mac_start = macbuf;
1.14 millert 1568: else
1.1 deraadt 1569: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1570: tmp = macros[macnum].mac_start;
1571: while (tmp != macbuf+4096) {
1572: if ((c = getchar()) == EOF) {
1.20 deraadt 1573: fputs("macdef: end of file encountered.\n", ttyout);
1.1 deraadt 1574: code = -1;
1575: return;
1576: }
1577: if ((*tmp = c) == '\n') {
1578: if (tmp == macros[macnum].mac_start) {
1579: macros[macnum++].mac_end = tmp;
1580: code = 0;
1581: return;
1582: }
1583: if (*(tmp-1) == '\0') {
1584: macros[macnum++].mac_end = tmp - 1;
1585: code = 0;
1586: return;
1587: }
1588: *tmp = '\0';
1589: }
1590: tmp++;
1591: }
1592: while (1) {
1593: while ((c = getchar()) != '\n' && c != EOF)
1594: /* LOOP */;
1595: if (c == EOF || getchar() == '\n') {
1.20 deraadt 1596: fputs("Macro not defined - 4K buffer exceeded.\n", ttyout);
1.1 deraadt 1597: code = -1;
1598: return;
1599: }
1600: }
1601: }
1602:
1603: /*
1.23 millert 1604: * Get size of file on remote machine
1.1 deraadt 1605: */
1606: void
1.47 deraadt 1607: sizecmd(int argc, char *argv[])
1.1 deraadt 1608: {
1.13 millert 1609: off_t size;
1.1 deraadt 1610:
1.64 sobrado 1611: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1612: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.1 deraadt 1613: code = -1;
1614: return;
1615: }
1.13 millert 1616: size = remotesize(argv[1], 1);
1617: if (size != -1)
1.37 deraadt 1618: fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size);
1.13 millert 1619: code = size;
1.1 deraadt 1620: }
1621:
1622: /*
1.23 millert 1623: * Get last modification time of file on remote machine
1.1 deraadt 1624: */
1625: void
1.47 deraadt 1626: modtime(int argc, char *argv[])
1.1 deraadt 1627: {
1.13 millert 1628: time_t mtime;
1.1 deraadt 1629:
1.64 sobrado 1630: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1631: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.1 deraadt 1632: code = -1;
1633: return;
1634: }
1.13 millert 1635: mtime = remotemodtime(argv[1], 1);
1636: if (mtime != -1)
1.20 deraadt 1637: fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
1.13 millert 1638: code = mtime;
1.1 deraadt 1639: }
1640:
1641: /*
1.23 millert 1642: * Show status on remote machine
1.1 deraadt 1643: */
1644: void
1.47 deraadt 1645: rmtstatus(int argc, char *argv[])
1.1 deraadt 1646: {
1647:
1.14 millert 1648: (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
1.1 deraadt 1649: }
1650:
1651: /*
1.23 millert 1652: * Get file if modtime is more recent than current file
1.1 deraadt 1653: */
1654: void
1.47 deraadt 1655: newer(int argc, char *argv[])
1.1 deraadt 1656: {
1657:
1658: if (getit(argc, argv, -1, "w"))
1.20 deraadt 1659: fprintf(ttyout, "Local file \"%s\" is newer than remote file \"%s\".\n",
1.1 deraadt 1660: argv[2], argv[1]);
1.16 millert 1661: }
1662:
1663: /*
1664: * Display one file through $PAGER (defaults to "more").
1665: */
1666: void
1.47 deraadt 1667: page(int argc, char *argv[])
1.16 millert 1668: {
1669: int orestart_point, ohash, overbose;
1.23 millert 1670: char *p, *pager, *oldargv1;
1.16 millert 1671:
1.64 sobrado 1672: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1673: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.16 millert 1674: code = -1;
1675: return;
1676: }
1.23 millert 1677: oldargv1 = argv[1];
1.16 millert 1678: if (!globulize(&argv[1])) {
1679: code = -1;
1680: return;
1681: }
1682: p = getenv("PAGER");
1.30 pjanzen 1683: if (p == NULL || (*p == '\0'))
1.16 millert 1684: p = PAGER;
1.44 deraadt 1685: if (asprintf(&pager, "|%s", p) == -1)
1.16 millert 1686: errx(1, "Can't allocate memory for $PAGER");
1687:
1688: orestart_point = restart_point;
1689: ohash = hash;
1690: overbose = verbose;
1691: restart_point = hash = verbose = 0;
1.23 millert 1692: recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
1.16 millert 1693: (void)free(pager);
1694: restart_point = orestart_point;
1695: hash = ohash;
1696: verbose = overbose;
1.23 millert 1697: if (oldargv1 != argv[1]) /* free up after globulize() */
1698: free(argv[1]);
1.1 deraadt 1699: }
1.70 martynas 1700:
1701: #endif /* !SMALL */
1702: