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