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