Annotation of src/usr.bin/ftp/main.c, Revision 1.80
1.80 ! sobrado 1: /* $OpenBSD: main.c,v 1.79 2009/06/06 12:07:33 martynas Exp $ */
1.36 millert 2: /* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
1.5 deraadt 3:
1.1 deraadt 4: /*
1.44 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.53 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:
62: /*
63: * FTP User Program -- Command Interface.
64: */
65: #include <sys/types.h>
66: #include <sys/socket.h>
67:
1.18 millert 68: #include <ctype.h>
1.1 deraadt 69: #include <err.h>
70: #include <netdb.h>
71: #include <pwd.h>
72: #include <stdio.h>
1.39 deraadt 73: #include <errno.h>
1.18 millert 74: #include <stdlib.h>
1.1 deraadt 75: #include <string.h>
76: #include <unistd.h>
77:
78: #include "ftp_var.h"
1.77 martynas 79: #include "cmds.h"
1.1 deraadt 80:
1.49 deraadt 81: int family = PF_UNSPEC;
82:
1.1 deraadt 83: int
1.54 deraadt 84: main(volatile int argc, char *argv[])
1.1 deraadt 85: {
1.34 millert 86: int ch, top, rval;
1.1 deraadt 87: struct passwd *pw = NULL;
1.44 itojun 88: char *cp, homedir[MAXPATHLEN];
1.38 millert 89: char *outfile = NULL;
1.62 tedu 90: const char *errstr;
1.28 millert 91: int dumb_terminal = 0;
1.1 deraadt 92:
1.44 itojun 93: ftpport = "ftp";
94: httpport = "http";
1.61 deraadt 95: #ifndef SMALL
96: httpsport = "https";
1.69 martynas 97: #endif /* !SMALL */
1.44 itojun 98: gateport = getenv("FTPSERVERPORT");
1.51 millert 99: if (gateport == NULL || *gateport == '\0')
1.44 itojun 100: gateport = "ftpgate";
1.1 deraadt 101: doglob = 1;
102: interactive = 1;
103: autologin = 1;
1.37 millert 104: passivemode = 1;
105: activefallback = 1;
1.17 millert 106: preserve = 1;
107: verbose = 0;
108: progress = 0;
1.36 millert 109: gatemode = 0;
1.25 millert 110: #ifndef SMALL
1.22 millert 111: editing = 0;
1.28 millert 112: el = NULL;
113: hist = NULL;
1.63 pyr 114: cookiefile = NULL;
1.67 martynas 115: resume = 0;
1.77 martynas 116: marg_sl = sl_init();
1.69 martynas 117: #endif /* !SMALL */
1.8 kstailey 118: mark = HASHBYTES;
1.47 itojun 119: #ifdef INET6
120: epsv4 = 1;
121: #else
122: epsv4 = 0;
123: #endif
124: epsv4bad = 0;
1.1 deraadt 125:
1.37 millert 126: /* Set default operation mode based on FTPMODE environment variable */
1.51 millert 127: if ((cp = getenv("FTPMODE")) != NULL && *cp != '\0') {
1.37 millert 128: if (strcmp(cp, "passive") == 0) {
129: passivemode = 1;
130: activefallback = 0;
131: } else if (strcmp(cp, "active") == 0) {
132: passivemode = 0;
133: activefallback = 0;
134: } else if (strcmp(cp, "gate") == 0) {
135: gatemode = 1;
136: } else if (strcmp(cp, "auto") == 0) {
137: passivemode = 1;
138: activefallback = 1;
139: } else
140: warnx("unknown FTPMODE: %s. Using defaults", cp);
141: }
142:
143: if (strcmp(__progname, "gate-ftp") == 0)
1.36 millert 144: gatemode = 1;
145: gateserver = getenv("FTPSERVER");
146: if (gateserver == NULL || *gateserver == '\0')
147: gateserver = GATE_SERVER;
148: if (gatemode) {
149: if (*gateserver == '\0') {
150: warnx(
1.37 millert 151: "Neither $FTPSERVER nor $GATE_SERVER is defined; disabling gate-ftp");
1.36 millert 152: gatemode = 0;
153: }
154: }
1.17 millert 155:
1.31 millert 156: cp = getenv("TERM");
1.51 millert 157: dumb_terminal = (cp == NULL || *cp == '\0' || !strcmp(cp, "dumb") ||
1.31 millert 158: !strcmp(cp, "emacs") || !strcmp(cp, "su"));
1.17 millert 159: fromatty = isatty(fileno(stdin));
1.22 millert 160: if (fromatty) {
1.17 millert 161: verbose = 1; /* verbose if from a tty */
1.25 millert 162: #ifndef SMALL
1.28 millert 163: if (!dumb_terminal)
1.34 millert 164: editing = 1; /* editing mode on if tty is usable */
1.69 martynas 165: #endif /* !SMALL */
1.22 millert 166: }
1.30 deraadt 167:
168: ttyout = stdout;
1.33 millert 169: if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc())
1.34 millert 170: progress = 1; /* progress bar on if tty is usable */
1.32 deraadt 171:
1.63 pyr 172: #ifndef SMALL
173: cookiefile = getenv("http_cookies");
1.69 martynas 174: #endif /* !SMALL */
1.63 pyr 175:
1.73 martynas 176: while ((ch = getopt(argc, argv, "46AaCc:dEegik:mno:pP:r:tvV")) != -1) {
1.1 deraadt 177: switch (ch) {
1.49 deraadt 178: case '4':
179: family = PF_INET;
180: break;
181: case '6':
182: family = PF_INET6;
183: break;
1.37 millert 184: case 'A':
185: activefallback = 0;
186: passivemode = 0;
187: break;
188:
1.17 millert 189: case 'a':
190: anonftp = 1;
191: break;
192:
1.67 martynas 193: case 'C':
194: #ifndef SMALL
195: resume = 1;
1.69 martynas 196: #endif /* !SMALL */
1.67 martynas 197: break;
198:
1.63 pyr 199: case 'c':
200: #ifndef SMALL
201: cookiefile = optarg;
1.69 martynas 202: #endif /* !SMALL */
1.63 pyr 203: break;
204:
1.1 deraadt 205: case 'd':
1.70 martynas 206: #ifndef SMALL
1.1 deraadt 207: options |= SO_DEBUG;
208: debug++;
1.70 martynas 209: #endif /* !SMALL */
1.1 deraadt 210: break;
1.17 millert 211:
1.59 fgsch 212: case 'E':
213: epsv4 = 0;
214: break;
215:
1.28 millert 216: case 'e':
217: #ifndef SMALL
1.22 millert 218: editing = 0;
1.69 martynas 219: #endif /* !SMALL */
1.21 kstailey 220: break;
221:
1.1 deraadt 222: case 'g':
223: doglob = 0;
224: break;
225:
226: case 'i':
227: interactive = 0;
1.41 millert 228: break;
229:
1.65 espie 230: case 'k':
231: keep_alive_timeout = strtonum(optarg, 0, INT_MAX,
232: &errstr);
233: if (errstr != NULL) {
234: warnx("keep alive amount is %s: %s", errstr,
235: optarg);
236: usage();
237: }
238: break;
1.41 millert 239: case 'm':
1.42 millert 240: progress = -1;
1.1 deraadt 241: break;
242:
243: case 'n':
244: autologin = 0;
245: break;
246:
1.38 millert 247: case 'o':
248: outfile = optarg;
249: if (strcmp(outfile, "-") == 0)
250: ttyout = stderr;
251: break;
252:
1.3 deraadt 253: case 'p':
1.17 millert 254: passivemode = 1;
1.37 millert 255: activefallback = 0;
1.3 deraadt 256: break;
257:
1.17 millert 258: case 'P':
1.44 itojun 259: ftpport = optarg;
1.7 mickey 260: break;
261:
1.18 millert 262: case 'r':
1.62 tedu 263: retry_connect = strtonum(optarg, 0, INT_MAX, &errstr);
1.65 espie 264: if (errstr != NULL) {
265: warnx("retry amount is %s: %s", errstr,
1.62 tedu 266: optarg);
1.65 espie 267: usage();
268: }
1.18 millert 269: break;
270:
1.1 deraadt 271: case 't':
1.17 millert 272: trace = 1;
1.1 deraadt 273: break;
274:
275: case 'v':
1.17 millert 276: verbose = 1;
277: break;
278:
279: case 'V':
280: verbose = 0;
1.1 deraadt 281: break;
282:
283: default:
1.17 millert 284: usage();
1.1 deraadt 285: }
286: }
287: argc -= optind;
288: argv += optind;
1.63 pyr 289:
290: #ifndef SMALL
291: cookie_load();
1.69 martynas 292: #endif /* !SMALL */
1.1 deraadt 293:
294: cpend = 0; /* no pending replies */
295: proxy = 0; /* proxy not active */
296: crflag = 1; /* strip c.r. on ascii gets */
297: sendport = -1; /* not using ports */
298: /*
299: * Set up the home directory in case we're globbing.
300: */
301: cp = getlogin();
302: if (cp != NULL) {
303: pw = getpwnam(cp);
304: }
305: if (pw == NULL)
306: pw = getpwuid(getuid());
307: if (pw != NULL) {
1.52 deraadt 308: (void)strlcpy(homedir, pw->pw_dir, sizeof homedir);
1.1 deraadt 309: home = homedir;
1.3 deraadt 310: }
1.9 michaels 311:
1.17 millert 312: setttywidth(0);
1.18 millert 313: (void)signal(SIGWINCH, setttywidth);
1.34 millert 314:
1.17 millert 315: if (argc > 0) {
1.44 itojun 316: if (isurl(argv[0])) {
1.38 millert 317: rval = auto_fetch(argc, argv, outfile);
1.17 millert 318: if (rval >= 0) /* -1 == connected and cd-ed */
319: exit(rval);
320: } else {
1.77 martynas 321: #ifndef SMALL
1.3 deraadt 322: char *xargv[5];
323:
324: if (setjmp(toplevel))
325: exit(0);
1.20 millert 326: (void)signal(SIGINT, (sig_t)intr);
327: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.3 deraadt 328: xargv[0] = __progname;
1.17 millert 329: xargv[1] = argv[0];
330: xargv[2] = argv[1];
331: xargv[3] = argv[2];
332: xargv[4] = NULL;
1.18 millert 333: do {
334: setpeer(argc+1, xargv);
335: if (!retry_connect)
336: break;
337: if (!connected) {
338: macnum = 0;
1.30 deraadt 339: fputs("Retrying...\n", ttyout);
1.18 millert 340: sleep(retry_connect);
341: }
342: } while (!connected);
1.35 mickey 343: retry_connect = 0; /* connected, stop hiding msgs */
1.77 martynas 344: #endif /* !SMALL */
1.3 deraadt 345: }
1.1 deraadt 346: }
1.28 millert 347: #ifndef SMALL
348: controlediting();
1.1 deraadt 349: top = setjmp(toplevel) == 0;
350: if (top) {
1.20 millert 351: (void)signal(SIGINT, (sig_t)intr);
352: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1 deraadt 353: }
354: for (;;) {
355: cmdscanner(top);
356: top = 1;
357: }
1.77 martynas 358: #else /* !SMALL */
359: usage();
360: #endif /* !SMALL */
1.1 deraadt 361: }
362:
363: void
1.58 deraadt 364: intr(void)
1.1 deraadt 365: {
366:
1.17 millert 367: alarmtimer(0);
1.1 deraadt 368: longjmp(toplevel, 1);
369: }
370:
371: void
1.58 deraadt 372: lostpeer(void)
1.1 deraadt 373: {
1.39 deraadt 374: int save_errno = errno;
1.1 deraadt 375:
1.17 millert 376: alarmtimer(0);
1.1 deraadt 377: if (connected) {
378: if (cout != NULL) {
1.66 moritz 379: (void)shutdown(fileno(cout), SHUT_RDWR);
1.18 millert 380: (void)fclose(cout);
1.1 deraadt 381: cout = NULL;
382: }
383: if (data >= 0) {
1.66 moritz 384: (void)shutdown(data, SHUT_RDWR);
1.18 millert 385: (void)close(data);
1.1 deraadt 386: data = -1;
387: }
388: connected = 0;
389: }
390: pswitch(1);
391: if (connected) {
392: if (cout != NULL) {
1.66 moritz 393: (void)shutdown(fileno(cout), SHUT_RDWR);
1.18 millert 394: (void)fclose(cout);
1.1 deraadt 395: cout = NULL;
396: }
397: connected = 0;
398: }
399: proxflag = 0;
400: pswitch(0);
1.39 deraadt 401: errno = save_errno;
1.1 deraadt 402: }
403:
1.77 martynas 404: #ifndef SMALL
1.1 deraadt 405: /*
1.17 millert 406: * Generate a prompt
407: */
1.1 deraadt 408: char *
1.58 deraadt 409: prompt(void)
1.1 deraadt 410: {
1.17 millert 411: return ("ftp> ");
1.1 deraadt 412: }
413:
414: /*
415: * Command parser.
416: */
417: void
1.58 deraadt 418: cmdscanner(int top)
1.1 deraadt 419: {
420: struct cmd *c;
1.17 millert 421: int num;
1.55 otto 422: HistEvent hev;
1.1 deraadt 423:
1.77 martynas 424: if (!top && !editing)
1.30 deraadt 425: (void)putc('\n', ttyout);
1.1 deraadt 426: for (;;) {
1.17 millert 427: if (!editing) {
428: if (fromatty) {
1.30 deraadt 429: fputs(prompt(), ttyout);
430: (void)fflush(ttyout);
1.17 millert 431: }
432: if (fgets(line, sizeof(line), stdin) == NULL)
433: quit(0, 0);
434: num = strlen(line);
435: if (num == 0)
436: break;
437: if (line[--num] == '\n') {
438: if (num == 0)
439: break;
440: line[num] = '\0';
441: } else if (num == sizeof(line) - 2) {
1.30 deraadt 442: fputs("sorry, input line too long.\n", ttyout);
1.17 millert 443: while ((num = getchar()) != '\n' && num != EOF)
444: /* void */;
445: break;
446: } /* else it was a line without a newline */
447: } else {
448: const char *buf;
449: cursor_pos = NULL;
450:
451: if ((buf = el_gets(el, &num)) == NULL || num == 0)
452: quit(0, 0);
1.46 fgsch 453: if (buf[--num] == '\n') {
1.17 millert 454: if (num == 0)
455: break;
1.46 fgsch 456: }
457: if (num >= sizeof(line)) {
1.30 deraadt 458: fputs("sorry, input line too long.\n", ttyout);
1.1 deraadt 459: break;
1.17 millert 460: }
1.34 millert 461: memcpy(line, buf, (size_t)num);
1.17 millert 462: line[num] = '\0';
1.55 otto 463: history(hist, &hev, H_ENTER, buf);
1.17 millert 464: }
465:
1.1 deraadt 466: makeargv();
1.17 millert 467: if (margc == 0)
1.1 deraadt 468: continue;
469: c = getcmd(margv[0]);
470: if (c == (struct cmd *)-1) {
1.30 deraadt 471: fputs("?Ambiguous command.\n", ttyout);
1.1 deraadt 472: continue;
473: }
474: if (c == 0) {
1.24 millert 475: /*
476: * Give editline(3) a shot at unknown commands.
477: * XXX - bogus commands with a colon in
478: * them will not elicit an error.
479: */
1.45 markus 480: if (editing &&
1.55 otto 481: el_parse(el, margc, (const char **)margv) != 0)
1.30 deraadt 482: fputs("?Invalid command.\n", ttyout);
1.1 deraadt 483: continue;
484: }
485: if (c->c_conn && !connected) {
1.30 deraadt 486: fputs("Not connected.\n", ttyout);
1.1 deraadt 487: continue;
488: }
1.17 millert 489: confirmrest = 0;
1.1 deraadt 490: (*c->c_handler)(margc, margv);
491: if (bell && c->c_bell)
1.30 deraadt 492: (void)putc('\007', ttyout);
1.1 deraadt 493: if (c->c_handler != help)
494: break;
495: }
1.20 millert 496: (void)signal(SIGINT, (sig_t)intr);
497: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1 deraadt 498: }
499:
500: struct cmd *
1.58 deraadt 501: getcmd(const char *name)
1.1 deraadt 502: {
1.17 millert 503: const char *p, *q;
1.1 deraadt 504: struct cmd *c, *found;
505: int nmatches, longest;
1.2 deraadt 506:
507: if (name == NULL)
508: return (0);
1.1 deraadt 509:
510: longest = 0;
511: nmatches = 0;
512: found = 0;
1.17 millert 513: for (c = cmdtab; (p = c->c_name) != NULL; c++) {
1.1 deraadt 514: for (q = name; *q == *p++; q++)
515: if (*q == 0) /* exact match? */
516: return (c);
517: if (!*q) { /* the name was a prefix */
518: if (q - name > longest) {
519: longest = q - name;
520: nmatches = 1;
521: found = c;
522: } else if (q - name == longest)
523: nmatches++;
524: }
525: }
526: if (nmatches > 1)
527: return ((struct cmd *)-1);
528: return (found);
529: }
530:
531: /*
532: * Slice a string up into argc/argv.
533: */
534:
535: int slrflag;
536:
537: void
1.58 deraadt 538: makeargv(void)
1.1 deraadt 539: {
1.17 millert 540: char *argp;
1.1 deraadt 541:
542: stringbase = line; /* scan from first of buffer */
543: argbase = argbuf; /* store from first of buffer */
544: slrflag = 0;
1.17 millert 545: marg_sl->sl_cur = 0; /* reset to start of marg_sl */
1.1 deraadt 546: for (margc = 0; ; margc++) {
1.17 millert 547: argp = slurpstring();
548: sl_add(marg_sl, argp);
549: if (argp == NULL)
1.1 deraadt 550: break;
551: }
1.17 millert 552: if (cursor_pos == line) {
553: cursor_argc = 0;
554: cursor_argo = 0;
555: } else if (cursor_pos != NULL) {
556: cursor_argc = margc;
557: cursor_argo = strlen(margv[margc-1]);
558: }
559: }
1.1 deraadt 560:
1.17 millert 561: #define INC_CHKCURSOR(x) { (x)++ ; \
562: if (x == cursor_pos) { \
563: cursor_argc = margc; \
564: cursor_argo = ap-argbase; \
565: cursor_pos = NULL; \
566: } }
1.1 deraadt 567:
568: /*
569: * Parse string into argbuf;
570: * implemented with FSM to
571: * handle quoting and strings
572: */
573: char *
1.58 deraadt 574: slurpstring(void)
1.1 deraadt 575: {
576: int got_one = 0;
577: char *sb = stringbase;
578: char *ap = argbase;
579: char *tmp = argbase; /* will return this if token found */
580:
581: if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
582: switch (slrflag) { /* and $ as token for macro invoke */
583: case 0:
584: slrflag++;
1.17 millert 585: INC_CHKCURSOR(stringbase);
1.1 deraadt 586: return ((*sb == '!') ? "!" : "$");
587: /* NOTREACHED */
588: case 1:
589: slrflag++;
590: altarg = stringbase;
591: break;
592: default:
593: break;
594: }
595: }
596:
597: S0:
598: switch (*sb) {
599:
600: case '\0':
601: goto OUT;
602:
603: case ' ':
604: case '\t':
1.17 millert 605: INC_CHKCURSOR(sb);
606: goto S0;
1.1 deraadt 607:
608: default:
609: switch (slrflag) {
610: case 0:
611: slrflag++;
612: break;
613: case 1:
614: slrflag++;
615: altarg = sb;
616: break;
617: default:
618: break;
619: }
620: goto S1;
621: }
622:
623: S1:
624: switch (*sb) {
625:
626: case ' ':
627: case '\t':
628: case '\0':
629: goto OUT; /* end of token */
630:
631: case '\\':
1.17 millert 632: INC_CHKCURSOR(sb);
633: goto S2; /* slurp next character */
1.1 deraadt 634:
635: case '"':
1.17 millert 636: INC_CHKCURSOR(sb);
637: goto S3; /* slurp quoted string */
1.1 deraadt 638:
639: default:
1.17 millert 640: *ap = *sb; /* add character to token */
641: ap++;
642: INC_CHKCURSOR(sb);
1.1 deraadt 643: got_one = 1;
644: goto S1;
645: }
646:
647: S2:
648: switch (*sb) {
649:
650: case '\0':
651: goto OUT;
652:
653: default:
1.17 millert 654: *ap = *sb;
655: ap++;
656: INC_CHKCURSOR(sb);
1.1 deraadt 657: got_one = 1;
658: goto S1;
659: }
660:
661: S3:
662: switch (*sb) {
663:
664: case '\0':
665: goto OUT;
666:
667: case '"':
1.17 millert 668: INC_CHKCURSOR(sb);
669: goto S1;
1.1 deraadt 670:
671: default:
1.17 millert 672: *ap = *sb;
673: ap++;
674: INC_CHKCURSOR(sb);
1.1 deraadt 675: got_one = 1;
676: goto S3;
677: }
678:
679: OUT:
680: if (got_one)
681: *ap++ = '\0';
682: argbase = ap; /* update storage pointer */
683: stringbase = sb; /* update scan pointer */
684: if (got_one) {
685: return (tmp);
686: }
687: switch (slrflag) {
688: case 0:
689: slrflag++;
690: break;
691: case 1:
692: slrflag++;
693: altarg = (char *) 0;
694: break;
695: default:
696: break;
697: }
698: return ((char *)0);
699: }
700:
701: /*
702: * Help command.
703: * Call each command handler with argc == 0 and argv[0] == name.
704: */
705: void
1.58 deraadt 706: help(int argc, char *argv[])
1.1 deraadt 707: {
708: struct cmd *c;
709:
710: if (argc == 1) {
1.17 millert 711: StringList *buf;
1.1 deraadt 712:
1.17 millert 713: buf = sl_init();
1.30 deraadt 714: fprintf(ttyout, "%sommands may be abbreviated. Commands are:\n\n",
1.17 millert 715: proxy ? "Proxy c" : "C");
716: for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
717: if (c->c_name && (!proxy || c->c_proxy))
718: sl_add(buf, c->c_name);
719: list_vertical(buf);
720: sl_free(buf, 0);
1.1 deraadt 721: return;
722: }
1.17 millert 723:
1.18 millert 724: #define HELPINDENT ((int) sizeof("disconnect"))
1.17 millert 725:
1.1 deraadt 726: while (--argc > 0) {
727: char *arg;
1.17 millert 728:
1.1 deraadt 729: arg = *++argv;
730: c = getcmd(arg);
731: if (c == (struct cmd *)-1)
1.30 deraadt 732: fprintf(ttyout, "?Ambiguous help command %s\n", arg);
1.1 deraadt 733: else if (c == (struct cmd *)0)
1.30 deraadt 734: fprintf(ttyout, "?Invalid help command %s\n", arg);
1.1 deraadt 735: else
1.30 deraadt 736: fprintf(ttyout, "%-*s\t%s\n", HELPINDENT,
1.1 deraadt 737: c->c_name, c->c_help);
738: }
1.17 millert 739: }
1.77 martynas 740: #endif /* !SMALL */
1.17 millert 741:
742: void
1.58 deraadt 743: usage(void)
1.17 millert 744: {
1.77 martynas 745: (void)fprintf(stderr, "usage: %s "
1.70 martynas 746: #ifndef SMALL
1.77 martynas 747: "[-46AadEegimnptVv] [-k seconds] [-P port] "
748: "[-r seconds] [host [port]]\n"
749: " %s [-C] "
1.70 martynas 750: #endif /* !SMALL */
751: "[-o output] "
1.79 martynas 752: "ftp://[user:password@]host[:port]/file[/] ...\n"
1.70 martynas 753: " %s "
754: #ifndef SMALL
755: "[-C] [-c cookie] "
756: #endif /* !SMALL */
757: "[-o output] "
1.79 martynas 758: "http://host[:port]/file ...\n"
1.61 deraadt 759: #ifndef SMALL
1.68 jmc 760: " %s [-C] [-c cookie] [-o output] "
1.79 martynas 761: "https://host[:port]/file ...\n"
1.69 martynas 762: #endif /* !SMALL */
1.70 martynas 763: " %s "
764: #ifndef SMALL
765: "[-C] "
766: #endif /* !SMALL */
1.80 ! sobrado 767: "[-o output] "
! 768: "file:file ...\n"
! 769: " %s "
! 770: #ifndef SMALL
! 771: "[-C] "
! 772: #endif /* !SMALL */
1.79 martynas 773: "[-o output] host:/file[/] ...\n",
1.61 deraadt 774: #ifndef SMALL
1.80 ! sobrado 775: __progname, __progname, __progname, __progname, __progname,
! 776: __progname);
1.69 martynas 777: #else /* !SMALL */
1.80 ! sobrado 778: __progname, __progname, __progname, __progname);
1.69 martynas 779: #endif /* !SMALL */
1.17 millert 780: exit(1);
1.1 deraadt 781: }
1.77 martynas 782: