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