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