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