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