Annotation of embedaddon/curl/src/tool_getparam.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22: #include "tool_setup.h"
23:
24: #include "strcase.h"
25:
26: #define ENABLE_CURLX_PRINTF
27: /* use our own printf() functions */
28: #include "curlx.h"
29:
30: #include "tool_binmode.h"
31: #include "tool_cfgable.h"
32: #include "tool_cb_prg.h"
33: #include "tool_convert.h"
34: #include "tool_filetime.h"
35: #include "tool_formparse.h"
36: #include "tool_getparam.h"
37: #include "tool_helpers.h"
38: #include "tool_libinfo.h"
39: #include "tool_metalink.h"
40: #include "tool_msgs.h"
41: #include "tool_paramhlp.h"
42: #include "tool_parsecfg.h"
43: #include "tool_main.h"
44:
45: #include "memdebug.h" /* keep this as LAST include */
46:
47: #ifdef MSDOS
48: # define USE_WATT32
49: #endif
50:
51: #define GetStr(str,val) do { \
52: if(*(str)) { \
53: free(*(str)); \
54: *(str) = NULL; \
55: } \
56: if((val)) { \
57: *(str) = strdup((val)); \
58: if(!(*(str))) \
59: return PARAM_NO_MEM; \
60: } \
61: } while(0)
62:
63: struct LongShort {
64: const char *letter; /* short name option */
65: const char *lname; /* long name option */
66: enum {
67: ARG_NONE, /* stand-alone but not a boolean */
68: ARG_BOOL, /* accepts a --no-[name] prefix */
69: ARG_STRING, /* requires an argument */
70: ARG_FILENAME /* requires an argument, usually a file name */
71: } desc;
72: };
73:
74: static const struct LongShort aliases[]= {
75: /* 'letter' strings with more than one character have *no* short option to
76: mention. */
77: {"*@", "url", ARG_STRING},
78: {"*4", "dns-ipv4-addr", ARG_STRING},
79: {"*6", "dns-ipv6-addr", ARG_STRING},
80: {"*a", "random-file", ARG_FILENAME},
81: {"*b", "egd-file", ARG_STRING},
82: {"*B", "oauth2-bearer", ARG_STRING},
83: {"*c", "connect-timeout", ARG_STRING},
84: {"*C", "doh-url" , ARG_STRING},
85: {"*d", "ciphers", ARG_STRING},
86: {"*D", "dns-interface", ARG_STRING},
87: {"*e", "disable-epsv", ARG_BOOL},
88: {"*f", "disallow-username-in-url", ARG_BOOL},
89: {"*E", "epsv", ARG_BOOL},
90: /* 'epsv' made like this to make --no-epsv and --epsv to work
91: although --disable-epsv is the documented option */
92: {"*F", "dns-servers", ARG_STRING},
93: {"*g", "trace", ARG_FILENAME},
94: {"*G", "npn", ARG_BOOL},
95: {"*h", "trace-ascii", ARG_FILENAME},
96: {"*H", "alpn", ARG_BOOL},
97: {"*i", "limit-rate", ARG_STRING},
98: {"*j", "compressed", ARG_BOOL},
99: {"*J", "tr-encoding", ARG_BOOL},
100: {"*k", "digest", ARG_BOOL},
101: {"*l", "negotiate", ARG_BOOL},
102: {"*m", "ntlm", ARG_BOOL},
103: {"*M", "ntlm-wb", ARG_BOOL},
104: {"*n", "basic", ARG_BOOL},
105: {"*o", "anyauth", ARG_BOOL},
106: #ifdef USE_WATT32
107: {"*p", "wdebug", ARG_BOOL},
108: #endif
109: {"*q", "ftp-create-dirs", ARG_BOOL},
110: {"*r", "create-dirs", ARG_BOOL},
111: {"*s", "max-redirs", ARG_STRING},
112: {"*t", "proxy-ntlm", ARG_BOOL},
113: {"*u", "crlf", ARG_BOOL},
114: {"*v", "stderr", ARG_FILENAME},
115: {"*w", "interface", ARG_STRING},
116: {"*x", "krb", ARG_STRING},
117: {"*x", "krb4", ARG_STRING},
118: /* 'krb4' is the previous name */
119: {"*X", "haproxy-protocol", ARG_BOOL},
120: {"*y", "max-filesize", ARG_STRING},
121: {"*z", "disable-eprt", ARG_BOOL},
122: {"*Z", "eprt", ARG_BOOL},
123: /* 'eprt' made like this to make --no-eprt and --eprt to work
124: although --disable-eprt is the documented option */
125: {"*~", "xattr", ARG_BOOL},
126: {"$a", "ftp-ssl", ARG_BOOL},
127: /* 'ftp-ssl' deprecated name since 7.20.0 */
128: {"$a", "ssl", ARG_BOOL},
129: /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */
130: {"$b", "ftp-pasv", ARG_BOOL},
131: {"$c", "socks5", ARG_STRING},
132: {"$d", "tcp-nodelay", ARG_BOOL},
133: {"$e", "proxy-digest", ARG_BOOL},
134: {"$f", "proxy-basic", ARG_BOOL},
135: {"$g", "retry", ARG_STRING},
136: {"$V", "retry-connrefused", ARG_BOOL},
137: {"$h", "retry-delay", ARG_STRING},
138: {"$i", "retry-max-time", ARG_STRING},
139: {"$k", "proxy-negotiate", ARG_BOOL},
140: {"$m", "ftp-account", ARG_STRING},
141: {"$n", "proxy-anyauth", ARG_BOOL},
142: {"$o", "trace-time", ARG_BOOL},
143: {"$p", "ignore-content-length", ARG_BOOL},
144: {"$q", "ftp-skip-pasv-ip", ARG_BOOL},
145: {"$r", "ftp-method", ARG_STRING},
146: {"$s", "local-port", ARG_STRING},
147: {"$t", "socks4", ARG_STRING},
148: {"$T", "socks4a", ARG_STRING},
149: {"$u", "ftp-alternative-to-user", ARG_STRING},
150: {"$v", "ftp-ssl-reqd", ARG_BOOL},
151: /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */
152: {"$v", "ssl-reqd", ARG_BOOL},
153: /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */
154: {"$w", "sessionid", ARG_BOOL},
155: /* 'sessionid' listed as --no-sessionid in the help */
156: {"$x", "ftp-ssl-control", ARG_BOOL},
157: {"$y", "ftp-ssl-ccc", ARG_BOOL},
158: {"$j", "ftp-ssl-ccc-mode", ARG_STRING},
159: {"$z", "libcurl", ARG_STRING},
160: {"$#", "raw", ARG_BOOL},
161: {"$0", "post301", ARG_BOOL},
162: {"$1", "keepalive", ARG_BOOL},
163: /* 'keepalive' listed as --no-keepalive in the help */
164: {"$2", "socks5-hostname", ARG_STRING},
165: {"$3", "keepalive-time", ARG_STRING},
166: {"$4", "post302", ARG_BOOL},
167: {"$5", "noproxy", ARG_STRING},
168: {"$7", "socks5-gssapi-nec", ARG_BOOL},
169: {"$8", "proxy1.0", ARG_STRING},
170: {"$9", "tftp-blksize", ARG_STRING},
171: {"$A", "mail-from", ARG_STRING},
172: {"$B", "mail-rcpt", ARG_STRING},
173: {"$C", "ftp-pret", ARG_BOOL},
174: {"$D", "proto", ARG_STRING},
175: {"$E", "proto-redir", ARG_STRING},
176: {"$F", "resolve", ARG_STRING},
177: {"$G", "delegation", ARG_STRING},
178: {"$H", "mail-auth", ARG_STRING},
179: {"$I", "post303", ARG_BOOL},
180: {"$J", "metalink", ARG_BOOL},
181: {"$6", "sasl-authzid", ARG_STRING},
182: {"$K", "sasl-ir", ARG_BOOL },
183: {"$L", "test-event", ARG_BOOL},
184: {"$M", "unix-socket", ARG_FILENAME},
185: {"$N", "path-as-is", ARG_BOOL},
186: {"$O", "socks5-gssapi-service", ARG_STRING},
187: /* 'socks5-gssapi-service' merged with'proxy-service-name' and
188: deprecated since 7.49.0 */
189: {"$O", "proxy-service-name", ARG_STRING},
190: {"$P", "service-name", ARG_STRING},
191: {"$Q", "proto-default", ARG_STRING},
192: {"$R", "expect100-timeout", ARG_STRING},
193: {"$S", "tftp-no-options", ARG_BOOL},
194: {"$U", "connect-to", ARG_STRING},
195: {"$W", "abstract-unix-socket", ARG_FILENAME},
196: {"$X", "tls-max", ARG_STRING},
197: {"$Y", "suppress-connect-headers", ARG_BOOL},
198: {"$Z", "compressed-ssh", ARG_BOOL},
199: {"$~", "happy-eyeballs-timeout-ms", ARG_STRING},
200: {"0", "http1.0", ARG_NONE},
201: {"01", "http1.1", ARG_NONE},
202: {"02", "http2", ARG_NONE},
203: {"03", "http2-prior-knowledge", ARG_NONE},
204: {"04", "http3", ARG_NONE},
205: {"09", "http0.9", ARG_BOOL},
206: {"1", "tlsv1", ARG_NONE},
207: {"10", "tlsv1.0", ARG_NONE},
208: {"11", "tlsv1.1", ARG_NONE},
209: {"12", "tlsv1.2", ARG_NONE},
210: {"13", "tlsv1.3", ARG_NONE},
211: {"1A", "tls13-ciphers", ARG_STRING},
212: {"1B", "proxy-tls13-ciphers", ARG_STRING},
213: {"2", "sslv2", ARG_NONE},
214: {"3", "sslv3", ARG_NONE},
215: {"4", "ipv4", ARG_NONE},
216: {"6", "ipv6", ARG_NONE},
217: {"a", "append", ARG_BOOL},
218: {"A", "user-agent", ARG_STRING},
219: {"b", "cookie", ARG_STRING},
220: {"ba", "alt-svc", ARG_STRING},
221: {"B", "use-ascii", ARG_BOOL},
222: {"c", "cookie-jar", ARG_STRING},
223: {"C", "continue-at", ARG_STRING},
224: {"d", "data", ARG_STRING},
225: {"dr", "data-raw", ARG_STRING},
226: {"da", "data-ascii", ARG_STRING},
227: {"db", "data-binary", ARG_STRING},
228: {"de", "data-urlencode", ARG_STRING},
229: {"D", "dump-header", ARG_FILENAME},
230: {"e", "referer", ARG_STRING},
231: {"E", "cert", ARG_FILENAME},
232: {"Ea", "cacert", ARG_FILENAME},
233: {"Eb", "cert-type", ARG_STRING},
234: {"Ec", "key", ARG_FILENAME},
235: {"Ed", "key-type", ARG_STRING},
236: {"Ee", "pass", ARG_STRING},
237: {"Ef", "engine", ARG_STRING},
238: {"Eg", "capath", ARG_FILENAME},
239: {"Eh", "pubkey", ARG_STRING},
240: {"Ei", "hostpubmd5", ARG_STRING},
241: {"Ej", "crlfile", ARG_FILENAME},
242: {"Ek", "tlsuser", ARG_STRING},
243: {"El", "tlspassword", ARG_STRING},
244: {"Em", "tlsauthtype", ARG_STRING},
245: {"En", "ssl-allow-beast", ARG_BOOL},
246: /* Eo */
247: {"Ep", "pinnedpubkey", ARG_STRING},
248: {"EP", "proxy-pinnedpubkey", ARG_STRING},
249: {"Eq", "cert-status", ARG_BOOL},
250: {"Er", "false-start", ARG_BOOL},
251: {"Es", "ssl-no-revoke", ARG_BOOL},
252: {"ES", "ssl-revoke-best-effort", ARG_BOOL},
253: {"Et", "tcp-fastopen", ARG_BOOL},
254: {"Eu", "proxy-tlsuser", ARG_STRING},
255: {"Ev", "proxy-tlspassword", ARG_STRING},
256: {"Ew", "proxy-tlsauthtype", ARG_STRING},
257: {"Ex", "proxy-cert", ARG_FILENAME},
258: {"Ey", "proxy-cert-type", ARG_STRING},
259: {"Ez", "proxy-key", ARG_FILENAME},
260: {"E0", "proxy-key-type", ARG_STRING},
261: {"E1", "proxy-pass", ARG_STRING},
262: {"E2", "proxy-ciphers", ARG_STRING},
263: {"E3", "proxy-crlfile", ARG_FILENAME},
264: {"E4", "proxy-ssl-allow-beast", ARG_BOOL},
265: {"E5", "login-options", ARG_STRING},
266: {"E6", "proxy-cacert", ARG_FILENAME},
267: {"E7", "proxy-capath", ARG_FILENAME},
268: {"E8", "proxy-insecure", ARG_BOOL},
269: {"E9", "proxy-tlsv1", ARG_NONE},
270: {"EA", "socks5-basic", ARG_BOOL},
271: {"EB", "socks5-gssapi", ARG_BOOL},
272: {"EC", "etag-save", ARG_FILENAME},
273: {"ED", "etag-compare", ARG_FILENAME},
274: {"f", "fail", ARG_BOOL},
275: {"fa", "fail-early", ARG_BOOL},
276: {"fb", "styled-output", ARG_BOOL},
277: {"fc", "mail-rcpt-allowfails", ARG_BOOL},
278: {"F", "form", ARG_STRING},
279: {"Fs", "form-string", ARG_STRING},
280: {"g", "globoff", ARG_BOOL},
281: {"G", "get", ARG_NONE},
282: {"Ga", "request-target", ARG_STRING},
283: {"h", "help", ARG_BOOL},
284: {"H", "header", ARG_STRING},
285: {"Hp", "proxy-header", ARG_STRING},
286: {"i", "include", ARG_BOOL},
287: {"I", "head", ARG_BOOL},
288: {"j", "junk-session-cookies", ARG_BOOL},
289: {"J", "remote-header-name", ARG_BOOL},
290: {"k", "insecure", ARG_BOOL},
291: {"K", "config", ARG_FILENAME},
292: {"l", "list-only", ARG_BOOL},
293: {"L", "location", ARG_BOOL},
294: {"Lt", "location-trusted", ARG_BOOL},
295: {"m", "max-time", ARG_STRING},
296: {"M", "manual", ARG_BOOL},
297: {"n", "netrc", ARG_BOOL},
298: {"no", "netrc-optional", ARG_BOOL},
299: {"ne", "netrc-file", ARG_FILENAME},
300: {"N", "buffer", ARG_BOOL},
301: /* 'buffer' listed as --no-buffer in the help */
302: {"o", "output", ARG_FILENAME},
303: {"O", "remote-name", ARG_NONE},
304: {"Oa", "remote-name-all", ARG_BOOL},
305: {"p", "proxytunnel", ARG_BOOL},
306: {"P", "ftp-port", ARG_STRING},
307: {"q", "disable", ARG_BOOL},
308: {"Q", "quote", ARG_STRING},
309: {"r", "range", ARG_STRING},
310: {"R", "remote-time", ARG_BOOL},
311: {"s", "silent", ARG_BOOL},
312: {"S", "show-error", ARG_BOOL},
313: {"t", "telnet-option", ARG_STRING},
314: {"T", "upload-file", ARG_FILENAME},
315: {"u", "user", ARG_STRING},
316: {"U", "proxy-user", ARG_STRING},
317: {"v", "verbose", ARG_BOOL},
318: {"V", "version", ARG_BOOL},
319: {"w", "write-out", ARG_STRING},
320: {"x", "proxy", ARG_STRING},
321: {"xa", "preproxy", ARG_STRING},
322: {"X", "request", ARG_STRING},
323: {"Y", "speed-limit", ARG_STRING},
324: {"y", "speed-time", ARG_STRING},
325: {"z", "time-cond", ARG_STRING},
326: {"Z", "parallel", ARG_BOOL},
327: {"Zb", "parallel-max", ARG_STRING},
328: {"Zc", "parallel-immediate", ARG_BOOL},
329: {"#", "progress-bar", ARG_BOOL},
330: {"#m", "progress-meter", ARG_BOOL},
331: {":", "next", ARG_NONE},
332: };
333:
334: /* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
335: * We allow ':' and '\' to be escaped by '\' so that we can use certificate
336: * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
337: * for details. */
338: #ifndef UNITTESTS
339: static
340: #endif
341: void parse_cert_parameter(const char *cert_parameter,
342: char **certname,
343: char **passphrase)
344: {
345: size_t param_length = strlen(cert_parameter);
346: size_t span;
347: const char *param_place = NULL;
348: char *certname_place = NULL;
349: *certname = NULL;
350: *passphrase = NULL;
351:
352: /* most trivial assumption: cert_parameter is empty */
353: if(param_length == 0)
354: return;
355:
356: /* next less trivial: cert_parameter starts 'pkcs11:' and thus
357: * looks like a RFC7512 PKCS#11 URI which can be used as-is.
358: * Also if cert_parameter contains no colon nor backslash, this
359: * means no passphrase was given and no characters escaped */
360: if(curl_strnequal(cert_parameter, "pkcs11:", 7) ||
361: !strpbrk(cert_parameter, ":\\")) {
362: *certname = strdup(cert_parameter);
363: return;
364: }
365: /* deal with escaped chars; find unescaped colon if it exists */
366: certname_place = malloc(param_length + 1);
367: if(!certname_place)
368: return;
369:
370: *certname = certname_place;
371: param_place = cert_parameter;
372: while(*param_place) {
373: span = strcspn(param_place, ":\\");
374: strncpy(certname_place, param_place, span);
375: param_place += span;
376: certname_place += span;
377: /* we just ate all the non-special chars. now we're on either a special
378: * char or the end of the string. */
379: switch(*param_place) {
380: case '\0':
381: break;
382: case '\\':
383: param_place++;
384: switch(*param_place) {
385: case '\0':
386: *certname_place++ = '\\';
387: break;
388: case '\\':
389: *certname_place++ = '\\';
390: param_place++;
391: break;
392: case ':':
393: *certname_place++ = ':';
394: param_place++;
395: break;
396: default:
397: *certname_place++ = '\\';
398: *certname_place++ = *param_place;
399: param_place++;
400: break;
401: }
402: break;
403: case ':':
404: /* Since we live in a world of weirdness and confusion, the win32
405: dudes can use : when using drive letters and thus c:\file:password
406: needs to work. In order not to break compatibility, we still use : as
407: separator, but we try to detect when it is used for a file name! On
408: windows. */
409: #ifdef WIN32
410: if(param_place &&
411: (param_place == &cert_parameter[1]) &&
412: (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
413: (ISALPHA(cert_parameter[0])) ) {
414: /* colon in the second column, followed by a backslash, and the
415: first character is an alphabetic letter:
416:
417: this is a drive letter colon */
418: *certname_place++ = ':';
419: param_place++;
420: break;
421: }
422: #endif
423: /* escaped colons and Windows drive letter colons were handled
424: * above; if we're still here, this is a separating colon */
425: param_place++;
426: if(*param_place) {
427: *passphrase = strdup(param_place);
428: }
429: goto done;
430: }
431: }
432: done:
433: *certname_place = '\0';
434: }
435:
436: static void
437: GetFileAndPassword(char *nextarg, char **file, char **password)
438: {
439: char *certname, *passphrase;
440: parse_cert_parameter(nextarg, &certname, &passphrase);
441: Curl_safefree(*file);
442: *file = certname;
443: if(passphrase) {
444: Curl_safefree(*password);
445: *password = passphrase;
446: }
447: cleanarg(nextarg);
448: }
449:
450: /* Get a size parameter for '--limit-rate' or '--max-filesize'.
451: * We support a 'G', 'M' or 'K' suffix too.
452: */
453: static ParameterError GetSizeParameter(struct GlobalConfig *global,
454: const char *arg,
455: const char *which,
456: curl_off_t *value_out)
457: {
458: char *unit;
459: curl_off_t value;
460:
461: if(curlx_strtoofft(arg, &unit, 0, &value)) {
462: warnf(global, "invalid number specified for %s\n", which);
463: return PARAM_BAD_USE;
464: }
465:
466: if(!*unit)
467: unit = (char *)"b";
468: else if(strlen(unit) > 1)
469: unit = (char *)"w"; /* unsupported */
470:
471: switch(*unit) {
472: case 'G':
473: case 'g':
474: if(value > (CURL_OFF_T_MAX / (1024*1024*1024)))
475: return PARAM_NUMBER_TOO_LARGE;
476: value *= 1024*1024*1024;
477: break;
478: case 'M':
479: case 'm':
480: if(value > (CURL_OFF_T_MAX / (1024*1024)))
481: return PARAM_NUMBER_TOO_LARGE;
482: value *= 1024*1024;
483: break;
484: case 'K':
485: case 'k':
486: if(value > (CURL_OFF_T_MAX / 1024))
487: return PARAM_NUMBER_TOO_LARGE;
488: value *= 1024;
489: break;
490: case 'b':
491: case 'B':
492: /* for plain bytes, leave as-is */
493: break;
494: default:
495: warnf(global, "unsupported %s unit. Use G, M, K or B!\n", which);
496: return PARAM_BAD_USE;
497: }
498: *value_out = value;
499: return PARAM_OK;
500: }
501:
502: ParameterError getparameter(const char *flag, /* f or -long-flag */
503: char *nextarg, /* NULL if unset */
504: bool *usedarg, /* set to TRUE if the arg
505: has been used */
506: struct GlobalConfig *global,
507: struct OperationConfig *config)
508: {
509: char letter;
510: char subletter = '\0'; /* subletters can only occur on long options */
511: int rc;
512: const char *parse = NULL;
513: unsigned int j;
514: time_t now;
515: int hit = -1;
516: bool longopt = FALSE;
517: bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
518: ParameterError err;
519: bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
520: by using --OPTION or --no-OPTION */
521:
522: *usedarg = FALSE; /* default is that we don't use the arg */
523:
524: if(('-' != flag[0]) || ('-' == flag[1])) {
525: /* this should be a long name */
526: const char *word = ('-' == flag[0]) ? flag + 2 : flag;
527: size_t fnam = strlen(word);
528: int numhits = 0;
529: bool noflagged = FALSE;
530:
531: if(!strncmp(word, "no-", 3)) {
532: /* disable this option but ignore the "no-" part when looking for it */
533: word += 3;
534: toggle = FALSE;
535: noflagged = TRUE;
536: }
537:
538: for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
539: if(curl_strnequal(aliases[j].lname, word, fnam)) {
540: longopt = TRUE;
541: numhits++;
542: if(curl_strequal(aliases[j].lname, word)) {
543: parse = aliases[j].letter;
544: hit = j;
545: numhits = 1; /* a single unique hit */
546: break;
547: }
548: parse = aliases[j].letter;
549: hit = j;
550: }
551: }
552: if(numhits > 1) {
553: /* this is at least the second match! */
554: return PARAM_OPTION_AMBIGUOUS;
555: }
556: if(hit < 0) {
557: return PARAM_OPTION_UNKNOWN;
558: }
559: if(noflagged && (aliases[hit].desc != ARG_BOOL))
560: /* --no- prefixed an option that isn't boolean! */
561: return PARAM_NO_NOT_BOOLEAN;
562: }
563: else {
564: flag++; /* prefixed with one dash, pass it */
565: hit = -1;
566: parse = flag;
567: }
568:
569: do {
570: /* we can loop here if we have multiple single-letters */
571:
572: if(!longopt) {
573: letter = (char)*parse;
574: subletter = '\0';
575: }
576: else {
577: letter = parse[0];
578: subletter = parse[1];
579: }
580:
581: if(hit < 0) {
582: for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
583: if(letter == aliases[j].letter[0]) {
584: hit = j;
585: break;
586: }
587: }
588: if(hit < 0) {
589: return PARAM_OPTION_UNKNOWN;
590: }
591: }
592:
593: if(aliases[hit].desc >= ARG_STRING) {
594: /* this option requires an extra parameter */
595: if(!longopt && parse[1]) {
596: nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
597: singleopt = TRUE; /* don't loop anymore after this */
598: }
599: else if(!nextarg)
600: return PARAM_REQUIRES_PARAMETER;
601: else
602: *usedarg = TRUE; /* mark it as used */
603:
604: if((aliases[hit].desc == ARG_FILENAME) &&
605: (nextarg[0] == '-') && nextarg[1]) {
606: /* if the file name looks like a command line option */
607: warnf(global, "The file name argument '%s' looks like a flag.\n",
608: nextarg);
609: }
610: }
611: else if((aliases[hit].desc == ARG_NONE) && !toggle)
612: return PARAM_NO_PREFIX;
613:
614: switch(letter) {
615: case '*': /* options without a short option */
616: switch(subletter) {
617: case '4': /* --dns-ipv4-addr */
618: /* addr in dot notation */
619: GetStr(&config->dns_ipv4_addr, nextarg);
620: break;
621: case '6': /* --dns-ipv6-addr */
622: /* addr in dot notation */
623: GetStr(&config->dns_ipv6_addr, nextarg);
624: break;
625: case 'a': /* random-file */
626: GetStr(&config->random_file, nextarg);
627: break;
628: case 'b': /* egd-file */
629: GetStr(&config->egd_file, nextarg);
630: break;
631: case 'B': /* OAuth 2.0 bearer token */
632: GetStr(&config->oauth_bearer, nextarg);
633: config->authtype |= CURLAUTH_BEARER;
634: break;
635: case 'c': /* connect-timeout */
636: err = str2udouble(&config->connecttimeout, nextarg,
637: LONG_MAX/1000);
638: if(err)
639: return err;
640: break;
641: case 'C': /* doh-url */
642: GetStr(&config->doh_url, nextarg);
643: break;
644: case 'd': /* ciphers */
645: GetStr(&config->cipher_list, nextarg);
646: break;
647: case 'D': /* --dns-interface */
648: /* interface name */
649: GetStr(&config->dns_interface, nextarg);
650: break;
651: case 'e': /* --disable-epsv */
652: config->disable_epsv = toggle;
653: break;
654: case 'f': /* --disallow-username-in-url */
655: config->disallow_username_in_url = toggle;
656: break;
657: case 'E': /* --epsv */
658: config->disable_epsv = (!toggle)?TRUE:FALSE;
659: break;
660: case 'F': /* --dns-servers */
661: /* IP addrs of DNS servers */
662: GetStr(&config->dns_servers, nextarg);
663: break;
664: case 'g': /* --trace */
665: GetStr(&global->trace_dump, nextarg);
666: if(global->tracetype && (global->tracetype != TRACE_BIN))
667: warnf(global, "--trace overrides an earlier trace/verbose option\n");
668: global->tracetype = TRACE_BIN;
669: break;
670: case 'G': /* --npn */
671: config->nonpn = (!toggle)?TRUE:FALSE;
672: break;
673: case 'h': /* --trace-ascii */
674: GetStr(&global->trace_dump, nextarg);
675: if(global->tracetype && (global->tracetype != TRACE_ASCII))
676: warnf(global,
677: "--trace-ascii overrides an earlier trace/verbose option\n");
678: global->tracetype = TRACE_ASCII;
679: break;
680: case 'H': /* --alpn */
681: config->noalpn = (!toggle)?TRUE:FALSE;
682: break;
683: case 'i': /* --limit-rate */
684: {
685: curl_off_t value;
686: ParameterError pe = GetSizeParameter(global, nextarg, "rate", &value);
687:
688: if(pe != PARAM_OK)
689: return pe;
690: config->recvpersecond = value;
691: config->sendpersecond = value;
692: }
693: break;
694:
695: case 'j': /* --compressed */
696: if(toggle &&
697: !(curlinfo->features & (CURL_VERSION_LIBZ | CURL_VERSION_BROTLI)))
698: return PARAM_LIBCURL_DOESNT_SUPPORT;
699: config->encoding = toggle;
700: break;
701:
702: case 'J': /* --tr-encoding */
703: config->tr_encoding = toggle;
704: break;
705:
706: case 'k': /* --digest */
707: if(toggle)
708: config->authtype |= CURLAUTH_DIGEST;
709: else
710: config->authtype &= ~CURLAUTH_DIGEST;
711: break;
712:
713: case 'l': /* --negotiate */
714: if(toggle) {
715: if(curlinfo->features & CURL_VERSION_SPNEGO)
716: config->authtype |= CURLAUTH_NEGOTIATE;
717: else
718: return PARAM_LIBCURL_DOESNT_SUPPORT;
719: }
720: else
721: config->authtype &= ~CURLAUTH_NEGOTIATE;
722: break;
723:
724: case 'm': /* --ntlm */
725: if(toggle) {
726: if(curlinfo->features & CURL_VERSION_NTLM)
727: config->authtype |= CURLAUTH_NTLM;
728: else
729: return PARAM_LIBCURL_DOESNT_SUPPORT;
730: }
731: else
732: config->authtype &= ~CURLAUTH_NTLM;
733: break;
734:
735: case 'M': /* --ntlm-wb */
736: if(toggle) {
737: if(curlinfo->features & CURL_VERSION_NTLM_WB)
738: config->authtype |= CURLAUTH_NTLM_WB;
739: else
740: return PARAM_LIBCURL_DOESNT_SUPPORT;
741: }
742: else
743: config->authtype &= ~CURLAUTH_NTLM_WB;
744: break;
745:
746: case 'n': /* --basic for completeness */
747: if(toggle)
748: config->authtype |= CURLAUTH_BASIC;
749: else
750: config->authtype &= ~CURLAUTH_BASIC;
751: break;
752:
753: case 'o': /* --anyauth, let libcurl pick it */
754: if(toggle)
755: config->authtype = CURLAUTH_ANY;
756: /* --no-anyauth simply doesn't touch it */
757: break;
758:
759: #ifdef USE_WATT32
760: case 'p': /* --wdebug */
761: dbug_init();
762: break;
763: #endif
764: case 'q': /* --ftp-create-dirs */
765: config->ftp_create_dirs = toggle;
766: break;
767:
768: case 'r': /* --create-dirs */
769: config->create_dirs = toggle;
770: break;
771:
772: case 's': /* --max-redirs */
773: /* specified max no of redirects (http(s)), this accepts -1 as a
774: special condition */
775: err = str2num(&config->maxredirs, nextarg);
776: if(err)
777: return err;
778: if(config->maxredirs < -1)
779: return PARAM_BAD_NUMERIC;
780: break;
781:
782: case 't': /* --proxy-ntlm */
783: if(curlinfo->features & CURL_VERSION_NTLM)
784: config->proxyntlm = toggle;
785: else
786: return PARAM_LIBCURL_DOESNT_SUPPORT;
787: break;
788:
789: case 'u': /* --crlf */
790: /* LF -> CRLF conversion? */
791: config->crlf = toggle;
792: break;
793:
794: case 'v': /* --stderr */
795: if(strcmp(nextarg, "-")) {
796: FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT);
797: if(!newfile)
798: warnf(global, "Failed to open %s!\n", nextarg);
799: else {
800: if(global->errors_fopened)
801: fclose(global->errors);
802: global->errors = newfile;
803: global->errors_fopened = TRUE;
804: }
805: }
806: else
807: global->errors = stdout;
808: break;
809: case 'w': /* --interface */
810: /* interface */
811: GetStr(&config->iface, nextarg);
812: break;
813: case 'x': /* --krb */
814: /* kerberos level string */
815: if(curlinfo->features & CURL_VERSION_KERBEROS4)
816: GetStr(&config->krblevel, nextarg);
817: else
818: return PARAM_LIBCURL_DOESNT_SUPPORT;
819: break;
820: case 'X': /* --haproxy-protocol */
821: config->haproxy_protocol = toggle;
822: break;
823: case 'y': /* --max-filesize */
824: {
825: curl_off_t value;
826: ParameterError pe =
827: GetSizeParameter(global, nextarg, "max-filesize", &value);
828:
829: if(pe != PARAM_OK)
830: return pe;
831: config->max_filesize = value;
832: }
833: break;
834: case 'z': /* --disable-eprt */
835: config->disable_eprt = toggle;
836: break;
837: case 'Z': /* --eprt */
838: config->disable_eprt = (!toggle)?TRUE:FALSE;
839: break;
840: case '~': /* --xattr */
841: config->xattr = toggle;
842: break;
843: case '@': /* the URL! */
844: {
845: struct getout *url;
846:
847: if(!config->url_get)
848: config->url_get = config->url_list;
849:
850: if(config->url_get) {
851: /* there's a node here, if it already is filled-in continue to find
852: an "empty" node */
853: while(config->url_get && (config->url_get->flags & GETOUT_URL))
854: config->url_get = config->url_get->next;
855: }
856:
857: /* now there might or might not be an available node to fill in! */
858:
859: if(config->url_get)
860: /* existing node */
861: url = config->url_get;
862: else
863: /* there was no free node, create one! */
864: config->url_get = url = new_getout(config);
865:
866: if(!url)
867: return PARAM_NO_MEM;
868:
869: /* fill in the URL */
870: GetStr(&url->url, nextarg);
871: url->flags |= GETOUT_URL;
872: }
873: }
874: break;
875: case '$': /* more options without a short option */
876: switch(subletter) {
877: case 'a': /* --ssl */
878: if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
879: return PARAM_LIBCURL_DOESNT_SUPPORT;
880: config->ftp_ssl = toggle;
881: break;
882: case 'b': /* --ftp-pasv */
883: Curl_safefree(config->ftpport);
884: break;
885: case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
886: the name locally and passes on the resolved address */
887: GetStr(&config->proxy, nextarg);
888: config->proxyver = CURLPROXY_SOCKS5;
889: break;
890: case 't': /* --socks4 specifies a socks4 proxy to use */
891: GetStr(&config->proxy, nextarg);
892: config->proxyver = CURLPROXY_SOCKS4;
893: break;
894: case 'T': /* --socks4a specifies a socks4a proxy to use */
895: GetStr(&config->proxy, nextarg);
896: config->proxyver = CURLPROXY_SOCKS4A;
897: break;
898: case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
899: resolving with the proxy */
900: GetStr(&config->proxy, nextarg);
901: config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
902: break;
903: case 'd': /* --tcp-nodelay option */
904: config->tcp_nodelay = toggle;
905: break;
906: case 'e': /* --proxy-digest */
907: config->proxydigest = toggle;
908: break;
909: case 'f': /* --proxy-basic */
910: config->proxybasic = toggle;
911: break;
912: case 'g': /* --retry */
913: err = str2unum(&config->req_retry, nextarg);
914: if(err)
915: return err;
916: break;
917: case 'V': /* --retry-connrefused */
918: config->retry_connrefused = toggle;
919: break;
920: case 'h': /* --retry-delay */
921: err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000);
922: if(err)
923: return err;
924: break;
925: case 'i': /* --retry-max-time */
926: err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000);
927: if(err)
928: return err;
929: break;
930:
931: case 'k': /* --proxy-negotiate */
932: if(curlinfo->features & CURL_VERSION_SPNEGO)
933: config->proxynegotiate = toggle;
934: else
935: return PARAM_LIBCURL_DOESNT_SUPPORT;
936: break;
937:
938: case 'm': /* --ftp-account */
939: GetStr(&config->ftp_account, nextarg);
940: break;
941: case 'n': /* --proxy-anyauth */
942: config->proxyanyauth = toggle;
943: break;
944: case 'o': /* --trace-time */
945: global->tracetime = toggle;
946: break;
947: case 'p': /* --ignore-content-length */
948: config->ignorecl = toggle;
949: break;
950: case 'q': /* --ftp-skip-pasv-ip */
951: config->ftp_skip_ip = toggle;
952: break;
953: case 'r': /* --ftp-method (undocumented at this point) */
954: config->ftp_filemethod = ftpfilemethod(config, nextarg);
955: break;
956: case 's': { /* --local-port */
957: char lrange[7]; /* 16bit base 10 is 5 digits, but we allow 6 so that
958: this catches overflows, not just truncates */
959: char *p = nextarg;
960: while(ISDIGIT(*p))
961: p++;
962: if(*p) {
963: /* if there's anything more than a plain decimal number */
964: rc = sscanf(p, " - %6s", lrange);
965: *p = 0; /* zero terminate to make str2unum() work below */
966: }
967: else
968: rc = 0;
969:
970: err = str2unum(&config->localport, nextarg);
971: if(err || (config->localport > 65535))
972: return PARAM_BAD_USE;
973: if(!rc)
974: config->localportrange = 1; /* default number of ports to try */
975: else {
976: err = str2unum(&config->localportrange, lrange);
977: if(err || (config->localportrange > 65535))
978: return PARAM_BAD_USE;
979: config->localportrange -= (config->localport-1);
980: if(config->localportrange < 1)
981: return PARAM_BAD_USE;
982: }
983: break;
984: }
985: case 'u': /* --ftp-alternative-to-user */
986: GetStr(&config->ftp_alternative_to_user, nextarg);
987: break;
988: case 'v': /* --ssl-reqd */
989: if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
990: return PARAM_LIBCURL_DOESNT_SUPPORT;
991: config->ftp_ssl_reqd = toggle;
992: break;
993: case 'w': /* --no-sessionid */
994: config->disable_sessionid = (!toggle)?TRUE:FALSE;
995: break;
996: case 'x': /* --ftp-ssl-control */
997: if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
998: return PARAM_LIBCURL_DOESNT_SUPPORT;
999: config->ftp_ssl_control = toggle;
1000: break;
1001: case 'y': /* --ftp-ssl-ccc */
1002: config->ftp_ssl_ccc = toggle;
1003: if(!config->ftp_ssl_ccc_mode)
1004: config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
1005: break;
1006: case 'j': /* --ftp-ssl-ccc-mode */
1007: config->ftp_ssl_ccc = TRUE;
1008: config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
1009: break;
1010: case 'z': /* --libcurl */
1011: #ifdef CURL_DISABLE_LIBCURL_OPTION
1012: warnf(global,
1013: "--libcurl option was disabled at build-time!\n");
1014: return PARAM_OPTION_UNKNOWN;
1015: #else
1016: GetStr(&global->libcurl, nextarg);
1017: break;
1018: #endif
1019: case '#': /* --raw */
1020: config->raw = toggle;
1021: break;
1022: case '0': /* --post301 */
1023: config->post301 = toggle;
1024: break;
1025: case '1': /* --no-keepalive */
1026: config->nokeepalive = (!toggle)?TRUE:FALSE;
1027: break;
1028: case '3': /* --keepalive-time */
1029: err = str2unum(&config->alivetime, nextarg);
1030: if(err)
1031: return err;
1032: break;
1033: case '4': /* --post302 */
1034: config->post302 = toggle;
1035: break;
1036: case 'I': /* --post303 */
1037: config->post303 = toggle;
1038: break;
1039: case '5': /* --noproxy */
1040: /* This specifies the noproxy list */
1041: GetStr(&config->noproxy, nextarg);
1042: break;
1043: case '7': /* --socks5-gssapi-nec*/
1044: config->socks5_gssapi_nec = toggle;
1045: break;
1046: case '8': /* --proxy1.0 */
1047: /* http 1.0 proxy */
1048: GetStr(&config->proxy, nextarg);
1049: config->proxyver = CURLPROXY_HTTP_1_0;
1050: break;
1051: case '9': /* --tftp-blksize */
1052: err = str2unum(&config->tftp_blksize, nextarg);
1053: if(err)
1054: return err;
1055: break;
1056: case 'A': /* --mail-from */
1057: GetStr(&config->mail_from, nextarg);
1058: break;
1059: case 'B': /* --mail-rcpt */
1060: /* append receiver to a list */
1061: err = add2list(&config->mail_rcpt, nextarg);
1062: if(err)
1063: return err;
1064: break;
1065: case 'C': /* --ftp-pret */
1066: config->ftp_pret = toggle;
1067: break;
1068: case 'D': /* --proto */
1069: config->proto_present = TRUE;
1070: if(proto2num(config, &config->proto, nextarg))
1071: return PARAM_BAD_USE;
1072: break;
1073: case 'E': /* --proto-redir */
1074: config->proto_redir_present = TRUE;
1075: if(proto2num(config, &config->proto_redir, nextarg))
1076: return PARAM_BAD_USE;
1077: break;
1078: case 'F': /* --resolve */
1079: err = add2list(&config->resolve, nextarg);
1080: if(err)
1081: return err;
1082: break;
1083: case 'G': /* --delegation LEVEL */
1084: config->gssapi_delegation = delegation(config, nextarg);
1085: break;
1086: case 'H': /* --mail-auth */
1087: GetStr(&config->mail_auth, nextarg);
1088: break;
1089: case 'J': /* --metalink */
1090: {
1091: #ifdef USE_METALINK
1092: int mlmaj, mlmin, mlpatch;
1093: metalink_get_version(&mlmaj, &mlmin, &mlpatch);
1094: if((mlmaj*10000)+(mlmin*100) + mlpatch < CURL_REQ_LIBMETALINK_VERS) {
1095: warnf(global,
1096: "--metalink option cannot be used because the version of "
1097: "the linked libmetalink library is too old. "
1098: "Required: %d.%d.%d, found %d.%d.%d\n",
1099: CURL_REQ_LIBMETALINK_MAJOR,
1100: CURL_REQ_LIBMETALINK_MINOR,
1101: CURL_REQ_LIBMETALINK_PATCH,
1102: mlmaj, mlmin, mlpatch);
1103: return PARAM_BAD_USE;
1104: }
1105: else
1106: config->use_metalink = toggle;
1107: #else
1108: warnf(global, "--metalink option is ignored because the binary is "
1109: "built without the Metalink support.\n");
1110: #endif
1111: break;
1112: }
1113: case '6': /* --sasl-authzid */
1114: GetStr(&config->sasl_authzid, nextarg);
1115: break;
1116: case 'K': /* --sasl-ir */
1117: config->sasl_ir = toggle;
1118: break;
1119: case 'L': /* --test-event */
1120: #ifdef CURLDEBUG
1121: global->test_event_based = toggle;
1122: #else
1123: warnf(global, "--test-event is ignored unless a debug build!\n");
1124: #endif
1125: break;
1126: case 'M': /* --unix-socket */
1127: config->abstract_unix_socket = FALSE;
1128: GetStr(&config->unix_socket_path, nextarg);
1129: break;
1130: case 'N': /* --path-as-is */
1131: config->path_as_is = toggle;
1132: break;
1133: case 'O': /* --proxy-service-name */
1134: GetStr(&config->proxy_service_name, nextarg);
1135: break;
1136: case 'P': /* --service-name */
1137: GetStr(&config->service_name, nextarg);
1138: break;
1139: case 'Q': /* --proto-default */
1140: GetStr(&config->proto_default, nextarg);
1141: err = check_protocol(config->proto_default);
1142: if(err)
1143: return err;
1144: break;
1145: case 'R': /* --expect100-timeout */
1146: err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000);
1147: if(err)
1148: return err;
1149: break;
1150: case 'S': /* --tftp-no-options */
1151: config->tftp_no_options = toggle;
1152: break;
1153: case 'U': /* --connect-to */
1154: err = add2list(&config->connect_to, nextarg);
1155: if(err)
1156: return err;
1157: break;
1158: case 'W': /* --abstract-unix-socket */
1159: config->abstract_unix_socket = TRUE;
1160: GetStr(&config->unix_socket_path, nextarg);
1161: break;
1162: case 'X': /* --tls-max */
1163: err = str2tls_max(&config->ssl_version_max, nextarg);
1164: if(err)
1165: return err;
1166: break;
1167: case 'Y': /* --suppress-connect-headers */
1168: config->suppress_connect_headers = toggle;
1169: break;
1170: case 'Z': /* --compressed-ssh */
1171: config->ssh_compression = toggle;
1172: break;
1173: case '~': /* --happy-eyeballs-timeout-ms */
1174: err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg);
1175: if(err)
1176: return err;
1177: /* 0 is a valid value for this timeout */
1178: break;
1179: }
1180: break;
1181: case '#':
1182: switch(subletter) {
1183: case 'm': /* --progress-meter */
1184: global->noprogress = !toggle;
1185: break;
1186: default: /* --progress-bar */
1187: global->progressmode =
1188: toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
1189: break;
1190: }
1191: break;
1192: case ':': /* --next */
1193: return PARAM_NEXT_OPERATION;
1194: case '0': /* --http* options */
1195: switch(subletter) {
1196: case '\0':
1197: /* HTTP version 1.0 */
1198: config->httpversion = CURL_HTTP_VERSION_1_0;
1199: break;
1200: case '1':
1201: /* HTTP version 1.1 */
1202: config->httpversion = CURL_HTTP_VERSION_1_1;
1203: break;
1204: case '2':
1205: /* HTTP version 2.0 */
1206: config->httpversion = CURL_HTTP_VERSION_2_0;
1207: break;
1208: case '3': /* --http2-prior-knowledge */
1209: /* HTTP version 2.0 over clean TCP*/
1210: config->httpversion = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE;
1211: break;
1212: case '4': /* --http3 */
1213: /* HTTP version 3 go over QUIC - at once */
1214: if(curlinfo->features & CURL_VERSION_HTTP3)
1215: config->httpversion = CURL_HTTP_VERSION_3;
1216: else
1217: return PARAM_LIBCURL_DOESNT_SUPPORT;
1218: break;
1219: case '9':
1220: /* Allow HTTP/0.9 responses! */
1221: config->http09_allowed = toggle;
1222: break;
1223: }
1224: break;
1225: case '1': /* --tlsv1* options */
1226: switch(subletter) {
1227: case '\0':
1228: /* TLS version 1.x */
1229: config->ssl_version = CURL_SSLVERSION_TLSv1;
1230: break;
1231: case '0':
1232: /* TLS version 1.0 */
1233: config->ssl_version = CURL_SSLVERSION_TLSv1_0;
1234: break;
1235: case '1':
1236: /* TLS version 1.1 */
1237: config->ssl_version = CURL_SSLVERSION_TLSv1_1;
1238: break;
1239: case '2':
1240: /* TLS version 1.2 */
1241: config->ssl_version = CURL_SSLVERSION_TLSv1_2;
1242: break;
1243: case '3':
1244: /* TLS version 1.3 */
1245: config->ssl_version = CURL_SSLVERSION_TLSv1_3;
1246: break;
1247: case 'A': /* --tls13-ciphers */
1248: GetStr(&config->cipher13_list, nextarg);
1249: break;
1250: case 'B': /* --proxy-tls13-ciphers */
1251: GetStr(&config->proxy_cipher13_list, nextarg);
1252: break;
1253: }
1254: break;
1255: case '2':
1256: /* SSL version 2 */
1257: config->ssl_version = CURL_SSLVERSION_SSLv2;
1258: break;
1259: case '3':
1260: /* SSL version 3 */
1261: config->ssl_version = CURL_SSLVERSION_SSLv3;
1262: break;
1263: case '4':
1264: /* IPv4 */
1265: config->ip_version = 4;
1266: break;
1267: case '6':
1268: /* IPv6 */
1269: config->ip_version = 6;
1270: break;
1271: case 'a':
1272: /* This makes the FTP sessions use APPE instead of STOR */
1273: config->ftp_append = toggle;
1274: break;
1275: case 'A':
1276: /* This specifies the User-Agent name */
1277: GetStr(&config->useragent, nextarg);
1278: break;
1279: case 'b':
1280: switch(subletter) {
1281: case 'a': /* --alt-svc */
1282: if(curlinfo->features & CURL_VERSION_ALTSVC)
1283: GetStr(&config->altsvc, nextarg);
1284: else
1285: return PARAM_LIBCURL_DOESNT_SUPPORT;
1286: break;
1287: default: /* --cookie string coming up: */
1288: if(nextarg[0] == '@') {
1289: nextarg++;
1290: }
1291: else if(strchr(nextarg, '=')) {
1292: /* A cookie string must have a =-letter */
1293: GetStr(&config->cookie, nextarg);
1294: break;
1295: }
1296: /* We have a cookie file to read from! */
1297: GetStr(&config->cookiefile, nextarg);
1298: }
1299: break;
1300: case 'B':
1301: /* use ASCII/text when transferring */
1302: config->use_ascii = toggle;
1303: break;
1304: case 'c':
1305: /* get the file name to dump all cookies in */
1306: GetStr(&config->cookiejar, nextarg);
1307: break;
1308: case 'C':
1309: /* This makes us continue an ftp transfer at given position */
1310: if(strcmp(nextarg, "-")) {
1311: err = str2offset(&config->resume_from, nextarg);
1312: if(err)
1313: return err;
1314: config->resume_from_current = FALSE;
1315: }
1316: else {
1317: config->resume_from_current = TRUE;
1318: config->resume_from = 0;
1319: }
1320: config->use_resume = TRUE;
1321: break;
1322: case 'd':
1323: /* postfield data */
1324: {
1325: char *postdata = NULL;
1326: FILE *file;
1327: size_t size = 0;
1328: bool raw_mode = (subletter == 'r');
1329:
1330: if(subletter == 'e') { /* --data-urlencode*/
1331: /* [name]=[content], we encode the content part only
1332: * [name]@[file name]
1333: *
1334: * Case 2: we first load the file using that name and then encode
1335: * the content.
1336: */
1337: const char *p = strchr(nextarg, '=');
1338: size_t nlen;
1339: char is_file;
1340: if(!p)
1341: /* there was no '=' letter, check for a '@' instead */
1342: p = strchr(nextarg, '@');
1343: if(p) {
1344: nlen = p - nextarg; /* length of the name part */
1345: is_file = *p++; /* pass the separator */
1346: }
1347: else {
1348: /* neither @ nor =, so no name and it isn't a file */
1349: nlen = is_file = 0;
1350: p = nextarg;
1351: }
1352: if('@' == is_file) {
1353: /* a '@' letter, it means that a file name or - (stdin) follows */
1354: if(!strcmp("-", p)) {
1355: file = stdin;
1356: set_binmode(stdin);
1357: }
1358: else {
1359: file = fopen(p, "rb");
1360: if(!file)
1361: warnf(global,
1362: "Couldn't read data from file \"%s\", this makes "
1363: "an empty POST.\n", nextarg);
1364: }
1365:
1366: err = file2memory(&postdata, &size, file);
1367:
1368: if(file && (file != stdin))
1369: fclose(file);
1370: if(err)
1371: return err;
1372: }
1373: else {
1374: GetStr(&postdata, p);
1375: if(postdata)
1376: size = strlen(postdata);
1377: }
1378:
1379: if(!postdata) {
1380: /* no data from the file, point to a zero byte string to make this
1381: get sent as a POST anyway */
1382: postdata = strdup("");
1383: if(!postdata)
1384: return PARAM_NO_MEM;
1385: size = 0;
1386: }
1387: else {
1388: char *enc = curl_easy_escape(NULL, postdata, (int)size);
1389: Curl_safefree(postdata); /* no matter if it worked or not */
1390: if(enc) {
1391: /* now make a string with the name from above and append the
1392: encoded string */
1393: size_t outlen = nlen + strlen(enc) + 2;
1394: char *n = malloc(outlen);
1395: if(!n) {
1396: curl_free(enc);
1397: return PARAM_NO_MEM;
1398: }
1399: if(nlen > 0) { /* only append '=' if we have a name */
1400: msnprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
1401: size = outlen-1;
1402: }
1403: else {
1404: strcpy(n, enc);
1405: size = outlen-2; /* since no '=' was inserted */
1406: }
1407: curl_free(enc);
1408: postdata = n;
1409: }
1410: else
1411: return PARAM_NO_MEM;
1412: }
1413: }
1414: else if('@' == *nextarg && !raw_mode) {
1415: /* the data begins with a '@' letter, it means that a file name
1416: or - (stdin) follows */
1417: nextarg++; /* pass the @ */
1418:
1419: if(!strcmp("-", nextarg)) {
1420: file = stdin;
1421: if(subletter == 'b') /* forced data-binary */
1422: set_binmode(stdin);
1423: }
1424: else {
1425: file = fopen(nextarg, "rb");
1426: if(!file)
1427: warnf(global, "Couldn't read data from file \"%s\", this makes "
1428: "an empty POST.\n", nextarg);
1429: }
1430:
1431: if(subletter == 'b')
1432: /* forced binary */
1433: err = file2memory(&postdata, &size, file);
1434: else {
1435: err = file2string(&postdata, file);
1436: if(postdata)
1437: size = strlen(postdata);
1438: }
1439:
1440: if(file && (file != stdin))
1441: fclose(file);
1442: if(err)
1443: return err;
1444:
1445: if(!postdata) {
1446: /* no data from the file, point to a zero byte string to make this
1447: get sent as a POST anyway */
1448: postdata = strdup("");
1449: if(!postdata)
1450: return PARAM_NO_MEM;
1451: }
1452: }
1453: else {
1454: GetStr(&postdata, nextarg);
1455: if(postdata)
1456: size = strlen(postdata);
1457: }
1458:
1459: #ifdef CURL_DOES_CONVERSIONS
1460: if(subletter != 'b') {
1461: /* NOT forced binary, convert to ASCII */
1462: if(convert_to_network(postdata, strlen(postdata))) {
1463: Curl_safefree(postdata);
1464: return PARAM_NO_MEM;
1465: }
1466: }
1467: #endif
1468:
1469: if(config->postfields) {
1470: /* we already have a string, we append this one with a separating
1471: &-letter */
1472: char *oldpost = config->postfields;
1473: curl_off_t oldlen = config->postfieldsize;
1474: curl_off_t newlen = oldlen + curlx_uztoso(size) + 2;
1475: config->postfields = malloc((size_t)newlen);
1476: if(!config->postfields) {
1477: Curl_safefree(oldpost);
1478: Curl_safefree(postdata);
1479: return PARAM_NO_MEM;
1480: }
1481: memcpy(config->postfields, oldpost, (size_t)oldlen);
1482: /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */
1483: config->postfields[oldlen] = '\x26';
1484: memcpy(&config->postfields[oldlen + 1], postdata, size);
1485: config->postfields[oldlen + 1 + size] = '\0';
1486: Curl_safefree(oldpost);
1487: Curl_safefree(postdata);
1488: config->postfieldsize += size + 1;
1489: }
1490: else {
1491: config->postfields = postdata;
1492: config->postfieldsize = curlx_uztoso(size);
1493: }
1494: }
1495: /*
1496: We can't set the request type here, as this data might be used in
1497: a simple GET if -G is used. Already or soon.
1498:
1499: if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) {
1500: Curl_safefree(postdata);
1501: return PARAM_BAD_USE;
1502: }
1503: */
1504: break;
1505: case 'D':
1506: /* dump-header to given file name */
1507: GetStr(&config->headerfile, nextarg);
1508: break;
1509: case 'e':
1510: {
1511: char *ptr = strstr(nextarg, ";auto");
1512: if(ptr) {
1513: /* Automatic referer requested, this may be combined with a
1514: set initial one */
1515: config->autoreferer = TRUE;
1516: *ptr = 0; /* zero terminate here */
1517: }
1518: else
1519: config->autoreferer = FALSE;
1520: GetStr(&config->referer, nextarg);
1521: }
1522: break;
1523: case 'E':
1524: switch(subletter) {
1525: case '\0': /* certificate file */
1526: GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
1527: break;
1528: case 'a': /* CA info PEM file */
1529: GetStr(&config->cacert, nextarg);
1530: break;
1531: case 'b': /* cert file type */
1532: GetStr(&config->cert_type, nextarg);
1533: break;
1534: case 'c': /* private key file */
1535: GetStr(&config->key, nextarg);
1536: break;
1537: case 'd': /* private key file type */
1538: GetStr(&config->key_type, nextarg);
1539: break;
1540: case 'e': /* private key passphrase */
1541: GetStr(&config->key_passwd, nextarg);
1542: cleanarg(nextarg);
1543: break;
1544: case 'f': /* crypto engine */
1545: GetStr(&config->engine, nextarg);
1546: if(config->engine && curl_strequal(config->engine, "list"))
1547: return PARAM_ENGINES_REQUESTED;
1548: break;
1549: case 'g': /* CA cert directory */
1550: GetStr(&config->capath, nextarg);
1551: break;
1552: case 'h': /* --pubkey public key file */
1553: GetStr(&config->pubkey, nextarg);
1554: break;
1555: case 'i': /* --hostpubmd5 md5 of the host public key */
1556: GetStr(&config->hostpubmd5, nextarg);
1557: if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
1558: return PARAM_BAD_USE;
1559: break;
1560: case 'j': /* CRL file */
1561: GetStr(&config->crlfile, nextarg);
1562: break;
1563: case 'k': /* TLS username */
1564: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
1565: GetStr(&config->tls_username, nextarg);
1566: else
1567: return PARAM_LIBCURL_DOESNT_SUPPORT;
1568: break;
1569: case 'l': /* TLS password */
1570: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
1571: GetStr(&config->tls_password, nextarg);
1572: else
1573: return PARAM_LIBCURL_DOESNT_SUPPORT;
1574: break;
1575: case 'm': /* TLS authentication type */
1576: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
1577: GetStr(&config->tls_authtype, nextarg);
1578: if(!curl_strequal(config->tls_authtype, "SRP"))
1579: return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
1580: }
1581: else
1582: return PARAM_LIBCURL_DOESNT_SUPPORT;
1583: break;
1584: case 'n': /* no empty SSL fragments, --ssl-allow-beast */
1585: if(curlinfo->features & CURL_VERSION_SSL)
1586: config->ssl_allow_beast = toggle;
1587: break;
1588:
1589: case 'p': /* Pinned public key DER file */
1590: GetStr(&config->pinnedpubkey, nextarg);
1591: break;
1592:
1593: case 'P': /* proxy pinned public key */
1594: GetStr(&config->proxy_pinnedpubkey, nextarg);
1595: break;
1596:
1597: case 'q': /* --cert-status */
1598: config->verifystatus = TRUE;
1599: break;
1600:
1601: case 'r': /* --false-start */
1602: config->falsestart = TRUE;
1603: break;
1604:
1605: case 's': /* --ssl-no-revoke */
1606: if(curlinfo->features & CURL_VERSION_SSL)
1607: config->ssl_no_revoke = TRUE;
1608: break;
1609:
1610: case 'S': /* --ssl-revoke-best-effort */
1611: if(curlinfo->features & CURL_VERSION_SSL)
1612: config->ssl_revoke_best_effort = TRUE;
1613: break;
1614:
1615: case 't': /* --tcp-fastopen */
1616: config->tcp_fastopen = TRUE;
1617: break;
1618:
1619: case 'u': /* TLS username for proxy */
1620: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
1621: GetStr(&config->proxy_tls_username, nextarg);
1622: else
1623: return PARAM_LIBCURL_DOESNT_SUPPORT;
1624: break;
1625:
1626: case 'v': /* TLS password for proxy */
1627: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
1628: GetStr(&config->proxy_tls_password, nextarg);
1629: else
1630: return PARAM_LIBCURL_DOESNT_SUPPORT;
1631: break;
1632:
1633: case 'w': /* TLS authentication type for proxy */
1634: if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
1635: GetStr(&config->proxy_tls_authtype, nextarg);
1636: if(!curl_strequal(config->proxy_tls_authtype, "SRP"))
1637: return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
1638: }
1639: else
1640: return PARAM_LIBCURL_DOESNT_SUPPORT;
1641: break;
1642:
1643: case 'x': /* certificate file for proxy */
1644: GetFileAndPassword(nextarg, &config->proxy_cert,
1645: &config->proxy_key_passwd);
1646: break;
1647:
1648: case 'y': /* cert file type for proxy */
1649: GetStr(&config->proxy_cert_type, nextarg);
1650: break;
1651:
1652: case 'z': /* private key file for proxy */
1653: GetStr(&config->proxy_key, nextarg);
1654: break;
1655:
1656: case '0': /* private key file type for proxy */
1657: GetStr(&config->proxy_key_type, nextarg);
1658: break;
1659:
1660: case '1': /* private key passphrase for proxy */
1661: GetStr(&config->proxy_key_passwd, nextarg);
1662: cleanarg(nextarg);
1663: break;
1664:
1665: case '2': /* ciphers for proxy */
1666: GetStr(&config->proxy_cipher_list, nextarg);
1667: break;
1668:
1669: case '3': /* CRL file for proxy */
1670: GetStr(&config->proxy_crlfile, nextarg);
1671: break;
1672:
1673: case '4': /* no empty SSL fragments for proxy */
1674: if(curlinfo->features & CURL_VERSION_SSL)
1675: config->proxy_ssl_allow_beast = toggle;
1676: break;
1677:
1678: case '5': /* --login-options */
1679: GetStr(&config->login_options, nextarg);
1680: break;
1681:
1682: case '6': /* CA info PEM file for proxy */
1683: GetStr(&config->proxy_cacert, nextarg);
1684: break;
1685:
1686: case '7': /* CA cert directory for proxy */
1687: GetStr(&config->proxy_capath, nextarg);
1688: break;
1689:
1690: case '8': /* allow insecure SSL connects for proxy */
1691: config->proxy_insecure_ok = toggle;
1692: break;
1693:
1694: case '9': /* --proxy-tlsv1 */
1695: /* TLS version 1 for proxy */
1696: config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
1697: break;
1698:
1699: case 'A':
1700: /* --socks5-basic */
1701: if(toggle)
1702: config->socks5_auth |= CURLAUTH_BASIC;
1703: else
1704: config->socks5_auth &= ~CURLAUTH_BASIC;
1705: break;
1706:
1707: case 'B':
1708: /* --socks5-gssapi */
1709: if(toggle)
1710: config->socks5_auth |= CURLAUTH_GSSAPI;
1711: else
1712: config->socks5_auth &= ~CURLAUTH_GSSAPI;
1713: break;
1714:
1715: case 'C':
1716: GetStr(&config->etag_save_file, nextarg);
1717: break;
1718:
1719: case 'D':
1720: GetStr(&config->etag_compare_file, nextarg);
1721: break;
1722:
1723: default: /* unknown flag */
1724: return PARAM_OPTION_UNKNOWN;
1725: }
1726: break;
1727: case 'f':
1728: switch(subletter) {
1729: case 'a': /* --fail-early */
1730: global->fail_early = toggle;
1731: break;
1732: case 'b': /* --styled-output */
1733: global->styled_output = toggle;
1734: break;
1735: case 'c': /* --mail-rcpt-allowfails */
1736: config->mail_rcpt_allowfails = toggle;
1737: break;
1738: default: /* --fail (hard on errors) */
1739: config->failonerror = toggle;
1740: }
1741: break;
1742: case 'F':
1743: /* "form data" simulation, this is a little advanced so lets do our best
1744: to sort this out slowly and carefully */
1745: if(formparse(config,
1746: nextarg,
1747: &config->mimeroot,
1748: &config->mimecurrent,
1749: (subletter == 's')?TRUE:FALSE)) /* 's' is literal string */
1750: return PARAM_BAD_USE;
1751: if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq))
1752: return PARAM_BAD_USE;
1753: break;
1754:
1755: case 'g': /* g disables URLglobbing */
1756: config->globoff = toggle;
1757: break;
1758:
1759: case 'G': /* HTTP GET */
1760: if(subletter == 'a') { /* --request-target */
1761: GetStr(&config->request_target, nextarg);
1762: }
1763: else
1764: config->use_httpget = TRUE;
1765: break;
1766:
1767: case 'h': /* h for help */
1768: if(toggle) {
1769: return PARAM_HELP_REQUESTED;
1770: }
1771: /* we now actually support --no-help too! */
1772: break;
1773: case 'H':
1774: /* A custom header to append to a list */
1775: if(nextarg[0] == '@') {
1776: /* read many headers from a file or stdin */
1777: char *string;
1778: size_t len;
1779: bool use_stdin = !strcmp(&nextarg[1], "-");
1780: FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT);
1781: if(!file)
1782: warnf(global, "Failed to open %s!\n", &nextarg[1]);
1783: else {
1784: err = file2memory(&string, &len, file);
1785: if(!err && string) {
1786: /* Allow strtok() here since this isn't used threaded */
1787: /* !checksrc! disable BANNEDFUNC 2 */
1788: char *h = strtok(string, "\r\n");
1789: while(h) {
1790: if(subletter == 'p') /* --proxy-header */
1791: err = add2list(&config->proxyheaders, h);
1792: else
1793: err = add2list(&config->headers, h);
1794: if(err)
1795: break;
1796: h = strtok(NULL, "\r\n");
1797: }
1798: free(string);
1799: }
1800: if(!use_stdin)
1801: fclose(file);
1802: if(err)
1803: return err;
1804: }
1805: }
1806: else {
1807: if(subletter == 'p') /* --proxy-header */
1808: err = add2list(&config->proxyheaders, nextarg);
1809: else
1810: err = add2list(&config->headers, nextarg);
1811: if(err)
1812: return err;
1813: }
1814: break;
1815: case 'i':
1816: config->show_headers = toggle; /* show the headers as well in the
1817: general output stream */
1818: break;
1819: case 'j':
1820: config->cookiesession = toggle;
1821: break;
1822: case 'I': /* --head */
1823: config->no_body = toggle;
1824: config->show_headers = toggle;
1825: if(SetHTTPrequest(config,
1826: (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
1827: &config->httpreq))
1828: return PARAM_BAD_USE;
1829: break;
1830: case 'J': /* --remote-header-name */
1831: if(config->show_headers) {
1832: warnf(global,
1833: "--include and --remote-header-name cannot be combined.\n");
1834: return PARAM_BAD_USE;
1835: }
1836: config->content_disposition = toggle;
1837: break;
1838: case 'k': /* allow insecure SSL connects */
1839: config->insecure_ok = toggle;
1840: break;
1841: case 'K': /* parse config file */
1842: if(parseconfig(nextarg, global))
1843: warnf(global, "error trying read config from the '%s' file\n",
1844: nextarg);
1845: break;
1846: case 'l':
1847: config->dirlistonly = toggle; /* only list the names of the FTP dir */
1848: break;
1849: case 'L':
1850: config->followlocation = toggle; /* Follow Location: HTTP headers */
1851: switch(subletter) {
1852: case 't':
1853: /* Continue to send authentication (user+password) when following
1854: * locations, even when hostname changed */
1855: config->unrestricted_auth = toggle;
1856: break;
1857: }
1858: break;
1859: case 'm':
1860: /* specified max time */
1861: err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000);
1862: if(err)
1863: return err;
1864: break;
1865: case 'M': /* M for manual, huge help */
1866: if(toggle) { /* --no-manual shows no manual... */
1867: #ifdef USE_MANUAL
1868: return PARAM_MANUAL_REQUESTED;
1869: #else
1870: warnf(global,
1871: "built-in manual was disabled at build-time!\n");
1872: return PARAM_OPTION_UNKNOWN;
1873: #endif
1874: }
1875: break;
1876: case 'n':
1877: switch(subletter) {
1878: case 'o': /* use .netrc or URL */
1879: config->netrc_opt = toggle;
1880: break;
1881: case 'e': /* netrc-file */
1882: GetStr(&config->netrc_file, nextarg);
1883: break;
1884: default:
1885: /* pick info from .netrc, if this is used for http, curl will
1886: automatically enfore user+password with the request */
1887: config->netrc = toggle;
1888: break;
1889: }
1890: break;
1891: case 'N':
1892: /* disable the output I/O buffering. note that the option is called
1893: --buffer but is mostly used in the negative form: --no-buffer */
1894: if(longopt)
1895: config->nobuffer = (!toggle)?TRUE:FALSE;
1896: else
1897: config->nobuffer = toggle;
1898: break;
1899: case 'O': /* --remote-name */
1900: if(subletter == 'a') { /* --remote-name-all */
1901: config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
1902: break;
1903: }
1904: /* FALLTHROUGH */
1905: case 'o': /* --output */
1906: /* output file */
1907: {
1908: struct getout *url;
1909: if(!config->url_out)
1910: config->url_out = config->url_list;
1911: if(config->url_out) {
1912: /* there's a node here, if it already is filled-in continue to find
1913: an "empty" node */
1914: while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
1915: config->url_out = config->url_out->next;
1916: }
1917:
1918: /* now there might or might not be an available node to fill in! */
1919:
1920: if(config->url_out)
1921: /* existing node */
1922: url = config->url_out;
1923: else
1924: /* there was no free node, create one! */
1925: config->url_out = url = new_getout(config);
1926:
1927: if(!url)
1928: return PARAM_NO_MEM;
1929:
1930: /* fill in the outfile */
1931: if('o' == letter) {
1932: GetStr(&url->outfile, nextarg);
1933: url->flags &= ~GETOUT_USEREMOTE; /* switch off */
1934: }
1935: else {
1936: url->outfile = NULL; /* leave it */
1937: if(toggle)
1938: url->flags |= GETOUT_USEREMOTE; /* switch on */
1939: else
1940: url->flags &= ~GETOUT_USEREMOTE; /* switch off */
1941: }
1942: url->flags |= GETOUT_OUTFILE;
1943: }
1944: break;
1945: case 'P':
1946: /* This makes the FTP sessions use PORT instead of PASV */
1947: /* use <eth0> or <192.168.10.10> style addresses. Anything except
1948: this will make us try to get the "default" address.
1949: NOTE: this is a changed behaviour since the released 4.1!
1950: */
1951: GetStr(&config->ftpport, nextarg);
1952: break;
1953: case 'p':
1954: /* proxy tunnel for non-http protocols */
1955: config->proxytunnel = toggle;
1956: break;
1957:
1958: case 'q': /* if used first, already taken care of, we do it like
1959: this so we don't cause an error! */
1960: break;
1961: case 'Q':
1962: /* QUOTE command to send to FTP server */
1963: switch(nextarg[0]) {
1964: case '-':
1965: /* prefixed with a dash makes it a POST TRANSFER one */
1966: nextarg++;
1967: err = add2list(&config->postquote, nextarg);
1968: break;
1969: case '+':
1970: /* prefixed with a plus makes it a just-before-transfer one */
1971: nextarg++;
1972: err = add2list(&config->prequote, nextarg);
1973: break;
1974: default:
1975: err = add2list(&config->quote, nextarg);
1976: break;
1977: }
1978: if(err)
1979: return err;
1980: break;
1981: case 'r':
1982: /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
1983: (and won't actually be range by definition). The man page previously
1984: claimed that to be a good way, why this code is added to work-around
1985: it. */
1986: if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
1987: char buffer[32];
1988: curl_off_t off;
1989: if(curlx_strtoofft(nextarg, NULL, 10, &off)) {
1990: warnf(global, "unsupported range point\n");
1991: return PARAM_BAD_USE;
1992: }
1993: warnf(global,
1994: "A specified range MUST include at least one dash (-). "
1995: "Appending one for you!\n");
1996: msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
1997: Curl_safefree(config->range);
1998: config->range = strdup(buffer);
1999: if(!config->range)
2000: return PARAM_NO_MEM;
2001: }
2002: {
2003: /* byte range requested */
2004: const char *tmp_range = nextarg;
2005: while(*tmp_range != '\0') {
2006: if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
2007: warnf(global, "Invalid character is found in given range. "
2008: "A specified range MUST have only digits in "
2009: "\'start\'-\'stop\'. The server's response to this "
2010: "request is uncertain.\n");
2011: break;
2012: }
2013: tmp_range++;
2014: }
2015: /* byte range requested */
2016: GetStr(&config->range, nextarg);
2017: }
2018: break;
2019: case 'R':
2020: /* use remote file's time */
2021: config->remote_time = toggle;
2022: break;
2023: case 's':
2024: /* don't show progress meter, don't show errors : */
2025: if(toggle)
2026: global->mute = global->noprogress = TRUE;
2027: else
2028: global->mute = global->noprogress = FALSE;
2029: if(global->showerror < 0)
2030: /* if still on the default value, set showerror to the reverse of
2031: toggle. This is to allow -S and -s to be used in an independent
2032: order but still have the same effect. */
2033: global->showerror = (!toggle)?TRUE:FALSE; /* toggle off */
2034: break;
2035: case 'S':
2036: /* show errors */
2037: global->showerror = toggle?1:0; /* toggle on if used with -s */
2038: break;
2039: case 't':
2040: /* Telnet options */
2041: err = add2list(&config->telnet_options, nextarg);
2042: if(err)
2043: return err;
2044: break;
2045: case 'T':
2046: /* we are uploading */
2047: {
2048: struct getout *url;
2049: if(!config->url_ul)
2050: config->url_ul = config->url_list;
2051: if(config->url_ul) {
2052: /* there's a node here, if it already is filled-in continue to find
2053: an "empty" node */
2054: while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
2055: config->url_ul = config->url_ul->next;
2056: }
2057:
2058: /* now there might or might not be an available node to fill in! */
2059:
2060: if(config->url_ul)
2061: /* existing node */
2062: url = config->url_ul;
2063: else
2064: /* there was no free node, create one! */
2065: config->url_ul = url = new_getout(config);
2066:
2067: if(!url)
2068: return PARAM_NO_MEM;
2069:
2070: url->flags |= GETOUT_UPLOAD; /* mark -T used */
2071: if(!*nextarg)
2072: url->flags |= GETOUT_NOUPLOAD;
2073: else {
2074: /* "-" equals stdin, but keep the string around for now */
2075: GetStr(&url->infile, nextarg);
2076: }
2077: }
2078: break;
2079: case 'u':
2080: /* user:password */
2081: GetStr(&config->userpwd, nextarg);
2082: cleanarg(nextarg);
2083: break;
2084: case 'U':
2085: /* Proxy user:password */
2086: GetStr(&config->proxyuserpwd, nextarg);
2087: cleanarg(nextarg);
2088: break;
2089: case 'v':
2090: if(toggle) {
2091: /* the '%' thing here will cause the trace get sent to stderr */
2092: Curl_safefree(global->trace_dump);
2093: global->trace_dump = strdup("%");
2094: if(!global->trace_dump)
2095: return PARAM_NO_MEM;
2096: if(global->tracetype && (global->tracetype != TRACE_PLAIN))
2097: warnf(global,
2098: "-v, --verbose overrides an earlier trace/verbose option\n");
2099: global->tracetype = TRACE_PLAIN;
2100: }
2101: else
2102: /* verbose is disabled here */
2103: global->tracetype = TRACE_NONE;
2104: break;
2105: case 'V':
2106: if(toggle) /* --no-version yields no output! */
2107: return PARAM_VERSION_INFO_REQUESTED;
2108: break;
2109:
2110: case 'w':
2111: /* get the output string */
2112: if('@' == *nextarg) {
2113: /* the data begins with a '@' letter, it means that a file name
2114: or - (stdin) follows */
2115: FILE *file;
2116: const char *fname;
2117: nextarg++; /* pass the @ */
2118: if(!strcmp("-", nextarg)) {
2119: fname = "<stdin>";
2120: file = stdin;
2121: }
2122: else {
2123: fname = nextarg;
2124: file = fopen(nextarg, FOPEN_READTEXT);
2125: }
2126: Curl_safefree(config->writeout);
2127: err = file2string(&config->writeout, file);
2128: if(file && (file != stdin))
2129: fclose(file);
2130: if(err)
2131: return err;
2132: if(!config->writeout)
2133: warnf(global, "Failed to read %s", fname);
2134: }
2135: else
2136: GetStr(&config->writeout, nextarg);
2137: break;
2138: case 'x':
2139: switch(subletter) {
2140: case 'a': /* --preproxy */
2141: GetStr(&config->preproxy, nextarg);
2142: break;
2143: default:
2144: /* --proxy */
2145: GetStr(&config->proxy, nextarg);
2146: config->proxyver = CURLPROXY_HTTP;
2147: break;
2148: }
2149: break;
2150: case 'X':
2151: /* set custom request */
2152: GetStr(&config->customrequest, nextarg);
2153: break;
2154: case 'y':
2155: /* low speed time */
2156: err = str2unum(&config->low_speed_time, nextarg);
2157: if(err)
2158: return err;
2159: if(!config->low_speed_limit)
2160: config->low_speed_limit = 1;
2161: break;
2162: case 'Y':
2163: /* low speed limit */
2164: err = str2unum(&config->low_speed_limit, nextarg);
2165: if(err)
2166: return err;
2167: if(!config->low_speed_time)
2168: config->low_speed_time = 30;
2169: break;
2170: case 'Z':
2171: switch(subletter) {
2172: case '\0': /* --parallel */
2173: global->parallel = toggle;
2174: break;
2175: case 'b': /* --parallel-max */
2176: err = str2unum(&global->parallel_max, nextarg);
2177: if(err)
2178: return err;
2179: if((global->parallel_max > MAX_PARALLEL) ||
2180: (global->parallel_max < 1))
2181: global->parallel_max = PARALLEL_DEFAULT;
2182: break;
2183: case 'c': /* --parallel-connect */
2184: global->parallel_connect = toggle;
2185: break;
2186: }
2187: break;
2188: case 'z': /* time condition coming up */
2189: switch(*nextarg) {
2190: case '+':
2191: nextarg++;
2192: /* FALLTHROUGH */
2193: default:
2194: /* If-Modified-Since: (section 14.28 in RFC2068) */
2195: config->timecond = CURL_TIMECOND_IFMODSINCE;
2196: break;
2197: case '-':
2198: /* If-Unmodified-Since: (section 14.24 in RFC2068) */
2199: config->timecond = CURL_TIMECOND_IFUNMODSINCE;
2200: nextarg++;
2201: break;
2202: case '=':
2203: /* Last-Modified: (section 14.29 in RFC2068) */
2204: config->timecond = CURL_TIMECOND_LASTMOD;
2205: nextarg++;
2206: break;
2207: }
2208: now = time(NULL);
2209: config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
2210: if(-1 == config->condtime) {
2211: /* now let's see if it is a file name to get the time from instead! */
2212: curl_off_t filetime = getfiletime(nextarg, config->global->errors);
2213: if(filetime >= 0) {
2214: /* pull the time out from the file */
2215: config->condtime = filetime;
2216: }
2217: else {
2218: /* failed, remove time condition */
2219: config->timecond = CURL_TIMECOND_NONE;
2220: warnf(global,
2221: "Illegal date format for -z, --time-cond (and not "
2222: "a file name). Disabling time condition. "
2223: "See curl_getdate(3) for valid date syntax.\n");
2224: }
2225: }
2226: break;
2227: default: /* unknown flag */
2228: return PARAM_OPTION_UNKNOWN;
2229: }
2230: hit = -1;
2231:
2232: } while(!longopt && !singleopt && *++parse && !*usedarg);
2233:
2234: return PARAM_OK;
2235: }
2236:
2237: ParameterError parse_args(struct GlobalConfig *global, int argc,
2238: argv_item_t argv[])
2239: {
2240: int i;
2241: bool stillflags;
2242: char *orig_opt = NULL;
2243: ParameterError result = PARAM_OK;
2244: struct OperationConfig *config = global->first;
2245:
2246: for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
2247: orig_opt = argv[i];
2248:
2249: if(stillflags && ('-' == argv[i][0])) {
2250: bool passarg;
2251: char *flag = argv[i];
2252:
2253: if(!strcmp("--", argv[i]))
2254: /* This indicates the end of the flags and thus enables the
2255: following (URL) argument to start with -. */
2256: stillflags = FALSE;
2257: else {
2258: char *nextarg = (i < (argc - 1)) ? argv[i + 1] : NULL;
2259:
2260: result = getparameter(flag, nextarg, &passarg, global, config);
2261: config = global->last;
2262: if(result == PARAM_NEXT_OPERATION) {
2263: /* Reset result as PARAM_NEXT_OPERATION is only used here and not
2264: returned from this function */
2265: result = PARAM_OK;
2266:
2267: if(config->url_list && config->url_list->url) {
2268: /* Allocate the next config */
2269: config->next = malloc(sizeof(struct OperationConfig));
2270: if(config->next) {
2271: /* Initialise the newly created config */
2272: config_init(config->next);
2273:
2274: /* Set the global config pointer */
2275: config->next->global = global;
2276:
2277: /* Update the last config pointer */
2278: global->last = config->next;
2279:
2280: /* Move onto the new config */
2281: config->next->prev = config;
2282: config = config->next;
2283: }
2284: else
2285: result = PARAM_NO_MEM;
2286: }
2287: }
2288: else if(!result && passarg)
2289: i++; /* we're supposed to skip this */
2290: }
2291: }
2292: else {
2293: bool used;
2294:
2295: /* Just add the URL please */
2296: result = getparameter((char *)"--url", argv[i], &used, global,
2297: config);
2298: }
2299: }
2300:
2301: if(result && result != PARAM_HELP_REQUESTED &&
2302: result != PARAM_MANUAL_REQUESTED &&
2303: result != PARAM_VERSION_INFO_REQUESTED &&
2304: result != PARAM_ENGINES_REQUESTED) {
2305: const char *reason = param2text(result);
2306:
2307: if(orig_opt && strcmp(":", orig_opt))
2308: helpf(global->errors, "option %s: %s\n", orig_opt, reason);
2309: else
2310: helpf(global->errors, "%s\n", reason);
2311: }
2312:
2313: return result;
2314: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>