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