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