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