1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 "setup.h" 23 24#include <curl/curl.h> 25 26#include "rawstr.h" 27 28#define ENABLE_CURLX_PRINTF 29/* use our own printf() functions */ 30#include "curlx.h" 31 32#ifdef USE_MANUAL 33# include "hugehelp.h" 34#endif 35 36#include "tool_binmode.h" 37#include "tool_cfgable.h" 38#include "tool_cb_prg.h" 39#include "tool_formparse.h" 40#include "tool_getparam.h" 41#include "tool_help.h" 42#include "tool_helpers.h" 43#include "tool_libinfo.h" 44#include "tool_msgs.h" 45#include "tool_paramhlp.h" 46#include "tool_parsecfg.h" 47#include "tool_version.h" 48 49#include "memdebug.h" /* keep this as LAST include */ 50 51#ifdef MSDOS 52# define USE_WATT32 53#endif 54 55#define GetStr(str,val) do { \ 56 if(*(str)) { \ 57 free(*(str)); \ 58 *(str) = NULL; \ 59 } \ 60 if((val)) \ 61 *(str) = strdup((val)); \ 62 if(!(val)) \ 63 return PARAM_NO_MEM; \ 64} WHILE_FALSE 65 66struct LongShort { 67 const char *letter; /* short name option */ 68 const char *lname; /* long name option */ 69 bool extraparam; /* whether it takes an additional argument */ 70}; 71 72static const struct LongShort aliases[]= { 73 /* all these ones, starting with "*" or "$" as a short-option have *no* 74 short option to mention. */ 75 {"*", "url", TRUE}, 76 {"*a", "random-file", TRUE}, 77 {"*b", "egd-file", TRUE}, 78 {"*c", "connect-timeout", TRUE}, 79 {"*d", "ciphers", TRUE}, 80 {"*e", "disable-epsv", FALSE}, 81 {"*E", "epsv", FALSE}, 82 /* 'epsv' made like this to make --no-epsv and --epsv to work 83 although --disable-epsv is the documented option */ 84#ifdef USE_ENVIRONMENT 85 {"*f", "environment", FALSE}, 86#endif 87 {"*g", "trace", TRUE}, 88 {"*h", "trace-ascii", TRUE}, 89 {"*i", "limit-rate", TRUE}, 90 {"*j", "compressed", FALSE}, 91 {"*J", "tr-encoding", FALSE}, 92 {"*k", "digest", FALSE}, 93 {"*l", "negotiate", FALSE}, 94 {"*m", "ntlm", FALSE}, 95 {"*M", "ntlm-wb", FALSE}, 96 {"*n", "basic", FALSE}, 97 {"*o", "anyauth", FALSE}, 98#ifdef USE_WATT32 99 {"*p", "wdebug", FALSE}, 100#endif 101 {"*q", "ftp-create-dirs", FALSE}, 102 {"*r", "create-dirs", FALSE}, 103 {"*s", "max-redirs", TRUE}, 104 {"*t", "proxy-ntlm", FALSE}, 105 {"*u", "crlf", FALSE}, 106 {"*v", "stderr", TRUE}, 107 {"*w", "interface", TRUE}, 108 {"*x", "krb" , TRUE}, 109 {"*x", "krb4" , TRUE}, 110 /* 'krb4' is the previous name */ 111 {"*y", "max-filesize", TRUE}, 112 {"*z", "disable-eprt", FALSE}, 113 {"*Z", "eprt", FALSE}, 114 /* 'eprt' made like this to make --no-eprt and --eprt to work 115 although --disable-eprt is the documented option */ 116 {"$a", "ftp-ssl", FALSE}, 117 /* 'ftp-ssl' deprecated name since 7.20.0 */ 118 {"$a", "ssl", FALSE}, 119 /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */ 120 {"$b", "ftp-pasv", FALSE}, 121 {"$c", "socks5", TRUE}, 122 {"$c", "socks", TRUE}, 123 /* 'socks' is how the option once was documented but we prefer 124 the --socks5 version for explicit version */ 125 {"$d", "tcp-nodelay", FALSE}, 126 {"$e", "proxy-digest", FALSE}, 127 {"$f", "proxy-basic", FALSE}, 128 {"$g", "retry", TRUE}, 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#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) 161 {"$6", "socks5-gssapi-service", TRUE}, 162 {"$7", "socks5-gssapi-nec", FALSE}, 163#endif 164 {"$8", "proxy1.0", TRUE}, 165 {"$9", "tftp-blksize", TRUE}, 166 {"$A", "mail-from", TRUE}, 167 {"$B", "mail-rcpt", TRUE}, 168 {"$C", "ftp-pret", FALSE}, 169 {"$D", "proto", TRUE}, 170 {"$E", "proto-redir", TRUE}, 171 {"$F", "resolve", TRUE}, 172 {"$G", "delegation", TRUE}, 173 {"0", "http1.0", FALSE}, 174 {"1", "tlsv1", FALSE}, 175 {"2", "sslv2", FALSE}, 176 {"3", "sslv3", FALSE}, 177 {"4", "ipv4", FALSE}, 178 {"6", "ipv6", FALSE}, 179 {"a", "append", FALSE}, 180 {"A", "user-agent", TRUE}, 181 {"b", "cookie", TRUE}, 182 {"B", "use-ascii", FALSE}, 183 {"c", "cookie-jar", TRUE}, 184 {"C", "continue-at", TRUE}, 185 {"d", "data", TRUE}, 186 {"da", "data-ascii", TRUE}, 187 {"db", "data-binary", TRUE}, 188 {"de", "data-urlencode", TRUE}, 189 {"D", "dump-header", TRUE}, 190 {"e", "referer", TRUE}, 191 {"E", "cert", TRUE}, 192 {"Ea", "cacert", TRUE}, 193 {"Eb", "cert-type", TRUE}, 194 {"Ec", "key", TRUE}, 195 {"Ed", "key-type", TRUE}, 196 {"Ee", "pass", TRUE}, 197 {"Ef", "engine", TRUE}, 198 {"Eg", "capath ", TRUE}, 199 {"Eh", "pubkey", TRUE}, 200 {"Ei", "hostpubmd5", TRUE}, 201 {"Ej", "crlfile", TRUE}, 202 {"Ek", "tlsuser", TRUE}, 203 {"El", "tlspassword", TRUE}, 204 {"Em", "tlsauthtype", TRUE}, 205 {"f", "fail", FALSE}, 206 {"F", "form", TRUE}, 207 {"Fs", "form-string", TRUE}, 208 {"g", "globoff", FALSE}, 209 {"G", "get", FALSE}, 210 {"h", "help", FALSE}, 211 {"H", "header", TRUE}, 212 {"i", "include", FALSE}, 213 {"I", "head", FALSE}, 214 {"j", "junk-session-cookies", FALSE}, 215 {"J", "remote-header-name", FALSE}, 216 {"k", "insecure", FALSE}, 217 {"K", "config", TRUE}, 218 {"l", "list-only", FALSE}, 219 {"L", "location", FALSE}, 220 {"Lt", "location-trusted", FALSE}, 221 {"m", "max-time", TRUE}, 222 {"M", "manual", FALSE}, 223 {"n", "netrc", FALSE}, 224 {"no", "netrc-optional", FALSE}, 225 {"ne", "netrc-file", TRUE}, 226 {"N", "buffer", FALSE}, 227 /* 'buffer' listed as --no-buffer in the help */ 228 {"o", "output", TRUE}, 229 {"O", "remote-name", FALSE}, 230 {"Oa", "remote-name-all", FALSE}, 231 {"p", "proxytunnel", FALSE}, 232 {"P", "ftpport", TRUE}, 233 /* 'ftpport' old version */ 234 {"P", "ftp-port", TRUE}, 235 {"q", "disable", FALSE}, 236 {"Q", "quote", TRUE}, 237 {"r", "range", TRUE}, 238 {"R", "remote-time", FALSE}, 239 {"s", "silent", FALSE}, 240 {"S", "show-error", FALSE}, 241 {"t", "telnet-options", TRUE}, 242 /* 'telnet-options' documented as telnet-option */ 243 {"T", "upload-file", TRUE}, 244 {"u", "user", TRUE}, 245 {"U", "proxy-user", TRUE}, 246 {"v", "verbose", FALSE}, 247 {"V", "version", FALSE}, 248 {"w", "write-out", TRUE}, 249 {"x", "proxy", TRUE}, 250 {"X", "request", TRUE}, 251 {"X", "http-request", TRUE}, 252 /* 'http-request' OBSOLETE VERSION */ 253 {"Y", "speed-limit", TRUE}, 254 {"y", "speed-time", TRUE}, 255 {"z", "time-cond", TRUE}, 256 {"#", "progress-bar", FALSE}, 257 {"~", "xattr", FALSE}, 258}; 259 260struct feat { 261 const char *name; 262 int bitmask; 263}; 264 265static const struct feat feats[] = { 266 {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, 267 {"Debug", CURL_VERSION_DEBUG}, 268 {"TrackMemory", CURL_VERSION_CURLDEBUG}, 269 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, 270 {"IDN", CURL_VERSION_IDN}, 271 {"IPv6", CURL_VERSION_IPV6}, 272 {"Largefile", CURL_VERSION_LARGEFILE}, 273 {"NTLM", CURL_VERSION_NTLM}, 274 {"NTLM_WB", CURL_VERSION_NTLM_WB}, 275 {"SPNEGO", CURL_VERSION_SPNEGO}, 276 {"SSL", CURL_VERSION_SSL}, 277 {"SSPI", CURL_VERSION_SSPI}, 278 {"krb4", CURL_VERSION_KERBEROS4}, 279 {"libz", CURL_VERSION_LIBZ}, 280 {"CharConv", CURL_VERSION_CONV}, 281 {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP} 282}; 283 284ParameterError getparameter(char *flag, /* f or -long-flag */ 285 char *nextarg, /* NULL if unset */ 286 bool *usedarg, /* set to TRUE if the arg 287 has been used */ 288 struct Configurable *config) 289{ 290 char letter; 291 char subletter = '\0'; /* subletters can only occur on long options */ 292 int rc; 293 const char *parse = NULL; 294 unsigned int j; 295 time_t now; 296 int hit = -1; 297 bool longopt = FALSE; 298 bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ 299 ParameterError err; 300 bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled 301 by using --OPTION or --no-OPTION */ 302 303 304 if(('-' != flag[0]) || 305 (('-' == flag[0]) && ('-' == flag[1]))) { 306 /* this should be a long name */ 307 char *word = ('-' == flag[0]) ? flag+2 : flag; 308 size_t fnam = strlen(word); 309 int numhits = 0; 310 311 if(!strncmp(word, "no-", 3)) { 312 /* disable this option but ignore the "no-" part when looking for it */ 313 word += 3; 314 toggle = FALSE; 315 } 316 317 for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { 318 if(curlx_strnequal(aliases[j].lname, word, fnam)) { 319 longopt = TRUE; 320 numhits++; 321 if(curlx_raw_equal(aliases[j].lname, word)) { 322 parse = aliases[j].letter; 323 hit = j; 324 numhits = 1; /* a single unique hit */ 325 break; 326 } 327 parse = aliases[j].letter; 328 hit = j; 329 } 330 } 331 if(numhits > 1) { 332 /* this is at least the second match! */ 333 return PARAM_OPTION_AMBIGUOUS; 334 } 335 if(hit < 0) { 336 return PARAM_OPTION_UNKNOWN; 337 } 338 } 339 else { 340 flag++; /* prefixed with one dash, pass it */ 341 hit = -1; 342 parse = flag; 343 } 344 345 do { 346 /* we can loop here if we have multiple single-letters */ 347 348 if(!longopt) { 349 if(NULL != parse) { 350 letter = (char)*parse; 351 } 352 else { 353 letter = '\0'; 354 } 355 subletter='\0'; 356 } 357 else { 358 letter = parse[0]; 359 subletter = parse[1]; 360 } 361 *usedarg = FALSE; /* default is that we don't use the arg */ 362 363 if(hit < 0) { 364 for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { 365 if(letter == aliases[j].letter[0]) { 366 hit = j; 367 break; 368 } 369 } 370 if(hit < 0) { 371 return PARAM_OPTION_UNKNOWN; 372 } 373 } 374 375 if(aliases[hit].extraparam) { 376 /* this option requires an extra parameter */ 377 if(!longopt && parse[1]) { 378 nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ 379 singleopt = TRUE; /* don't loop anymore after this */ 380 } 381 else if(!nextarg) 382 return PARAM_REQUIRES_PARAMETER; 383 else 384 *usedarg = TRUE; /* mark it as used */ 385 } 386 387 switch(letter) { 388 case '*': /* options without a short option */ 389 switch(subletter) { 390 case 'a': /* random-file */ 391 GetStr(&config->random_file, nextarg); 392 break; 393 case 'b': /* egd-file */ 394 GetStr(&config->egd_file, nextarg); 395 break; 396 case 'c': /* connect-timeout */ 397 if(str2num(&config->connecttimeout, nextarg)) 398 return PARAM_BAD_NUMERIC; 399 break; 400 case 'd': /* ciphers */ 401 GetStr(&config->cipher_list, nextarg); 402 break; 403 case 'e': /* --disable-epsv */ 404 config->disable_epsv = toggle; 405 break; 406 case 'E': /* --epsv */ 407 config->disable_epsv = (!toggle)?TRUE:FALSE; 408 break; 409#ifdef USE_ENVIRONMENT 410 case 'f': 411 config->writeenv = toggle; 412 break; 413#endif 414 case 'g': /* --trace */ 415 GetStr(&config->trace_dump, nextarg); 416 if(config->tracetype && (config->tracetype != TRACE_BIN)) 417 warnf(config, "--trace overrides an earlier trace/verbose option\n"); 418 config->tracetype = TRACE_BIN; 419 break; 420 case 'h': /* --trace-ascii */ 421 GetStr(&config->trace_dump, nextarg); 422 if(config->tracetype && (config->tracetype != TRACE_ASCII)) 423 warnf(config, 424 "--trace-ascii overrides an earlier trace/verbose option\n"); 425 config->tracetype = TRACE_ASCII; 426 break; 427 case 'i': /* --limit-rate */ 428 { 429 /* We support G, M, K too */ 430 char *unit; 431 curl_off_t value = curlx_strtoofft(nextarg, &unit, 0); 432 433 if(!*unit) 434 unit = (char *)"b"; 435 else if(strlen(unit) > 1) 436 unit = (char *)"w"; /* unsupported */ 437 438 switch(*unit) { 439 case 'G': 440 case 'g': 441 value *= 1024*1024*1024; 442 break; 443 case 'M': 444 case 'm': 445 value *= 1024*1024; 446 break; 447 case 'K': 448 case 'k': 449 value *= 1024; 450 break; 451 case 'b': 452 case 'B': 453 /* for plain bytes, leave as-is */ 454 break; 455 default: 456 warnf(config, "unsupported rate unit. Use G, M, K or B!\n"); 457 return PARAM_BAD_USE; 458 } 459 config->recvpersecond = value; 460 config->sendpersecond = value; 461 } 462 break; 463 464 case 'j': /* --compressed */ 465 if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ)) 466 return PARAM_LIBCURL_DOESNT_SUPPORT; 467 config->encoding = toggle; 468 break; 469 470 case 'J': /* --tr-encoding */ 471 config->tr_encoding = toggle; 472 break; 473 474 case 'k': /* --digest */ 475 if(toggle) 476 config->authtype |= CURLAUTH_DIGEST; 477 else 478 config->authtype &= ~CURLAUTH_DIGEST; 479 break; 480 481 case 'l': /* --negotiate */ 482 if(toggle) { 483 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) 484 config->authtype |= CURLAUTH_GSSNEGOTIATE; 485 else 486 return PARAM_LIBCURL_DOESNT_SUPPORT; 487 } 488 else 489 config->authtype &= ~CURLAUTH_GSSNEGOTIATE; 490 break; 491 492 case 'm': /* --ntlm */ 493 if(toggle) { 494 if(curlinfo->features & CURL_VERSION_NTLM) 495 config->authtype |= CURLAUTH_NTLM; 496 else 497 return PARAM_LIBCURL_DOESNT_SUPPORT; 498 } 499 else 500 config->authtype &= ~CURLAUTH_NTLM; 501 break; 502 503 case 'M': /* --ntlm-wb */ 504 if(toggle) { 505 if(curlinfo->features & CURL_VERSION_NTLM_WB) 506 config->authtype |= CURLAUTH_NTLM_WB; 507 else 508 return PARAM_LIBCURL_DOESNT_SUPPORT; 509 } 510 else 511 config->authtype &= ~CURLAUTH_NTLM_WB; 512 break; 513 514 case 'n': /* --basic for completeness */ 515 if(toggle) 516 config->authtype |= CURLAUTH_BASIC; 517 else 518 config->authtype &= ~CURLAUTH_BASIC; 519 break; 520 521 case 'o': /* --anyauth, let libcurl pick it */ 522 if(toggle) 523 config->authtype = CURLAUTH_ANY; 524 /* --no-anyauth simply doesn't touch it */ 525 break; 526 527#ifdef USE_WATT32 528 case 'p': /* --wdebug */ 529 dbug_init(); 530 break; 531#endif 532 case 'q': /* --ftp-create-dirs */ 533 config->ftp_create_dirs = toggle; 534 break; 535 536 case 'r': /* --create-dirs */ 537 config->create_dirs = TRUE; 538 break; 539 540 case 's': /* --max-redirs */ 541 /* specified max no of redirects (http(s)) */ 542 if(str2num(&config->maxredirs, nextarg)) 543 return PARAM_BAD_NUMERIC; 544 break; 545 546 case 't': /* --proxy-ntlm */ 547 if(curlinfo->features & CURL_VERSION_NTLM) 548 config->proxyntlm = toggle; 549 else 550 return PARAM_LIBCURL_DOESNT_SUPPORT; 551 break; 552 553 case 'u': /* --crlf */ 554 /* LF -> CRLF conversion? */ 555 config->crlf = TRUE; 556 break; 557 558 case 'v': /* --stderr */ 559 if(strcmp(nextarg, "-")) { 560 FILE *newfile = fopen(nextarg, "wt"); 561 if(!newfile) 562 warnf(config, "Failed to open %s!\n", nextarg); 563 else { 564 if(config->errors_fopened) 565 fclose(config->errors); 566 config->errors = newfile; 567 config->errors_fopened = TRUE; 568 } 569 } 570 else 571 config->errors = stdout; 572 break; 573 case 'w': /* --interface */ 574 /* interface */ 575 GetStr(&config->iface, nextarg); 576 break; 577 case 'x': /* --krb */ 578 /* kerberos level string */ 579 if(curlinfo->features & (CURL_VERSION_KERBEROS4 | 580 CURL_VERSION_GSSNEGOTIATE)) 581 GetStr(&config->krblevel, nextarg); 582 else 583 return PARAM_LIBCURL_DOESNT_SUPPORT; 584 break; 585 case 'y': /* --max-filesize */ 586 if(str2offset(&config->max_filesize, nextarg)) 587 return PARAM_BAD_NUMERIC; 588 break; 589 case 'z': /* --disable-eprt */ 590 config->disable_eprt = toggle; 591 break; 592 case 'Z': /* --eprt */ 593 config->disable_eprt = (!toggle)?TRUE:FALSE; 594 break; 595 596 default: /* the URL! */ 597 { 598 struct getout *url; 599 if(config->url_get || ((config->url_get = config->url_list) != NULL)) { 600 /* there's a node here, if it already is filled-in continue to find 601 an "empty" node */ 602 while(config->url_get && (config->url_get->flags & GETOUT_URL)) 603 config->url_get = config->url_get->next; 604 } 605 606 /* now there might or might not be an available node to fill in! */ 607 608 if(config->url_get) 609 /* existing node */ 610 url = config->url_get; 611 else 612 /* there was no free node, create one! */ 613 url = new_getout(config); 614 615 if(!url) 616 return PARAM_NO_MEM; 617 else { 618 /* fill in the URL */ 619 GetStr(&url->url, nextarg); 620 url->flags |= GETOUT_URL; 621 } 622 } 623 } 624 break; 625 case '$': /* more options without a short option */ 626 switch(subletter) { 627 case 'a': /* --ftp-ssl */ 628 if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) 629 return PARAM_LIBCURL_DOESNT_SUPPORT; 630 config->ftp_ssl = toggle; 631 break; 632 case 'b': /* --ftp-pasv */ 633 Curl_safefree(config->ftpport); 634 break; 635 case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves 636 the name locally and passes on the resolved address */ 637 GetStr(&config->socksproxy, nextarg); 638 config->socksver = CURLPROXY_SOCKS5; 639 break; 640 case 't': /* --socks4 specifies a socks4 proxy to use */ 641 GetStr(&config->socksproxy, nextarg); 642 config->socksver = CURLPROXY_SOCKS4; 643 break; 644 case 'T': /* --socks4a specifies a socks4a proxy to use */ 645 GetStr(&config->socksproxy, nextarg); 646 config->socksver = CURLPROXY_SOCKS4A; 647 break; 648 case '2': /* --socks5-hostname specifies a socks5 proxy and enables name 649 resolving with the proxy */ 650 GetStr(&config->socksproxy, nextarg); 651 config->socksver = CURLPROXY_SOCKS5_HOSTNAME; 652 break; 653 case 'd': /* --tcp-nodelay option */ 654 config->tcp_nodelay = toggle; 655 break; 656 case 'e': /* --proxy-digest */ 657 config->proxydigest = toggle; 658 break; 659 case 'f': /* --proxy-basic */ 660 config->proxybasic = toggle; 661 break; 662 case 'g': /* --retry */ 663 if(str2num(&config->req_retry, nextarg)) 664 return PARAM_BAD_NUMERIC; 665 break; 666 case 'h': /* --retry-delay */ 667 if(str2num(&config->retry_delay, nextarg)) 668 return PARAM_BAD_NUMERIC; 669 break; 670 case 'i': /* --retry-max-time */ 671 if(str2num(&config->retry_maxtime, nextarg)) 672 return PARAM_BAD_NUMERIC; 673 break; 674 675 case 'k': /* --proxy-negotiate */ 676 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) 677 config->proxynegotiate = toggle; 678 else 679 return PARAM_LIBCURL_DOESNT_SUPPORT; 680 break; 681 case 'm': /* --ftp-account */ 682 GetStr(&config->ftp_account, nextarg); 683 break; 684 case 'n': /* --proxy-anyauth */ 685 config->proxyanyauth = toggle; 686 break; 687 case 'o': /* --trace-time */ 688 config->tracetime = toggle; 689 break; 690 case 'p': /* --ignore-content-length */ 691 config->ignorecl = toggle; 692 break; 693 case 'q': /* --ftp-skip-pasv-ip */ 694 config->ftp_skip_ip = toggle; 695 break; 696 case 'r': /* --ftp-method (undocumented at this point) */ 697 config->ftp_filemethod = ftpfilemethod(config, nextarg); 698 break; 699 case 's': /* --local-port */ 700 rc = sscanf(nextarg, "%d - %d", 701 &config->localport, 702 &config->localportrange); 703 if(!rc) 704 return PARAM_BAD_USE; 705 else if(rc == 1) 706 config->localportrange = 1; /* default number of ports to try */ 707 else { 708 config->localportrange -= config->localport; 709 if(config->localportrange < 1) { 710 warnf(config, "bad range input\n"); 711 return PARAM_BAD_USE; 712 } 713 } 714 break; 715 case 'u': /* --ftp-alternative-to-user */ 716 GetStr(&config->ftp_alternative_to_user, nextarg); 717 break; 718 case 'v': /* --ftp-ssl-reqd */ 719 if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) 720 return PARAM_LIBCURL_DOESNT_SUPPORT; 721 config->ftp_ssl_reqd = toggle; 722 break; 723 case 'w': /* --no-sessionid */ 724 config->disable_sessionid = (!toggle)?TRUE:FALSE; 725 break; 726 case 'x': /* --ftp-ssl-control */ 727 if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) 728 return PARAM_LIBCURL_DOESNT_SUPPORT; 729 config->ftp_ssl_control = toggle; 730 break; 731 case 'y': /* --ftp-ssl-ccc */ 732 config->ftp_ssl_ccc = toggle; 733 if(!config->ftp_ssl_ccc_mode) 734 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; 735 break; 736 case 'j': /* --ftp-ssl-ccc-mode */ 737 config->ftp_ssl_ccc = TRUE; 738 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); 739 break; 740 case 'z': /* --libcurl */ 741 GetStr(&config->libcurl, nextarg); 742 break; 743 case '#': /* --raw */ 744 config->raw = toggle; 745 break; 746 case '0': /* --post301 */ 747 config->post301 = toggle; 748 break; 749 case '1': /* --no-keepalive */ 750 config->nokeepalive = (!toggle)?TRUE:FALSE; 751 break; 752 case '3': /* --keepalive-time */ 753 if(str2num(&config->alivetime, nextarg)) 754 return PARAM_BAD_NUMERIC; 755 break; 756 case '4': /* --post302 */ 757 config->post302 = toggle; 758 break; 759 case '5': /* --noproxy */ 760 /* This specifies the noproxy list */ 761 GetStr(&config->noproxy, nextarg); 762 break; 763#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) 764 case '6': /* --socks5-gssapi-service */ 765 GetStr(&config->socks5_gssapi_service, nextarg); 766 break; 767 case '7': /* --socks5-gssapi-nec*/ 768 config->socks5_gssapi_nec = TRUE; 769 break; 770#endif 771 case '8': /* --proxy1.0 */ 772 /* http 1.0 proxy */ 773 GetStr(&config->proxy, nextarg); 774 config->proxyver = CURLPROXY_HTTP_1_0; 775 break; 776 case '9': /* --tftp-blksize */ 777 str2num(&config->tftp_blksize, nextarg); 778 break; 779 case 'A': /* --mail-from */ 780 GetStr(&config->mail_from, nextarg); 781 break; 782 case 'B': /* --mail-rcpt */ 783 /* append receiver to a list */ 784 err = add2list(&config->mail_rcpt, nextarg); 785 if(err) 786 return err; 787 break; 788 case 'C': /* --ftp-pret */ 789 config->ftp_pret = toggle; 790 break; 791 case 'D': /* --proto */ 792 config->proto_present = TRUE; 793 if(proto2num(config, &config->proto, nextarg)) 794 return PARAM_BAD_USE; 795 break; 796 case 'E': /* --proto-redir */ 797 config->proto_redir_present = TRUE; 798 if(proto2num(config, &config->proto_redir, nextarg)) 799 return PARAM_BAD_USE; 800 break; 801 case 'F': /* --resolve */ 802 err = add2list(&config->resolve, nextarg); 803 if(err) 804 return err; 805 break; 806 case 'G': /* --delegation LEVEL */ 807 config->gssapi_delegation = delegation(config, nextarg); 808 break; 809 } 810 break; 811 case '#': /* --progress-bar */ 812 if(toggle) 813 config->progressmode = CURL_PROGRESS_BAR; 814 else 815 config->progressmode = CURL_PROGRESS_STATS; 816 break; 817 case '~': /* --xattr */ 818 config->xattr = toggle; 819 break; 820 case '0': 821 /* HTTP version 1.0 */ 822 config->httpversion = CURL_HTTP_VERSION_1_0; 823 break; 824 case '1': 825 /* TLS version 1 */ 826 config->ssl_version = CURL_SSLVERSION_TLSv1; 827 break; 828 case '2': 829 /* SSL version 2 */ 830 config->ssl_version = CURL_SSLVERSION_SSLv2; 831 break; 832 case '3': 833 /* SSL version 3 */ 834 config->ssl_version = CURL_SSLVERSION_SSLv3; 835 break; 836 case '4': 837 /* IPv4 */ 838 config->ip_version = 4; 839 break; 840 case '6': 841 /* IPv6 */ 842 config->ip_version = 6; 843 break; 844 case 'a': 845 /* This makes the FTP sessions use APPE instead of STOR */ 846 config->ftp_append = toggle; 847 break; 848 case 'A': 849 /* This specifies the User-Agent name */ 850 GetStr(&config->useragent, nextarg); 851 break; 852 case 'b': /* cookie string coming up: */ 853 if(nextarg[0] == '@') { 854 nextarg++; 855 } 856 else if(strchr(nextarg, '=')) { 857 /* A cookie string must have a =-letter */ 858 GetStr(&config->cookie, nextarg); 859 break; 860 } 861 /* We have a cookie file to read from! */ 862 GetStr(&config->cookiefile, nextarg); 863 break; 864 case 'B': 865 /* use ASCII/text when transferring */ 866 config->use_ascii = toggle; 867 break; 868 case 'c': 869 /* get the file name to dump all cookies in */ 870 GetStr(&config->cookiejar, nextarg); 871 break; 872 case 'C': 873 /* This makes us continue an ftp transfer at given position */ 874 if(!curlx_strequal(nextarg, "-")) { 875 if(str2offset(&config->resume_from, nextarg)) 876 return PARAM_BAD_NUMERIC; 877 config->resume_from_current = FALSE; 878 } 879 else { 880 config->resume_from_current = TRUE; 881 config->resume_from = 0; 882 } 883 config->use_resume=TRUE; 884 break; 885 case 'd': 886 /* postfield data */ 887 { 888 char *postdata = NULL; 889 FILE *file; 890 size_t size = 0; 891 892 if(subletter == 'e') { /* --data-urlencode*/ 893 /* [name]=[content], we encode the content part only 894 * [name]@[file name] 895 * 896 * Case 2: we first load the file using that name and then encode 897 * the content. 898 */ 899 const char *p = strchr(nextarg, '='); 900 size_t nlen; 901 char is_file; 902 if(!p) 903 /* there was no '=' letter, check for a '@' instead */ 904 p = strchr(nextarg, '@'); 905 if(p) { 906 nlen = p - nextarg; /* length of the name part */ 907 is_file = *p++; /* pass the separator */ 908 } 909 else { 910 /* neither @ nor =, so no name and it isn't a file */ 911 nlen = is_file = 0; 912 p = nextarg; 913 } 914 if('@' == is_file) { 915 /* a '@' letter, it means that a file name or - (stdin) follows */ 916 917 if(curlx_strequal("-", p)) { 918 file = stdin; 919 set_binmode(stdin); 920 } 921 else { 922 file = fopen(p, "rb"); 923 if(!file) 924 warnf(config, 925 "Couldn't read data from file \"%s\", this makes " 926 "an empty POST.\n", nextarg); 927 } 928 929 err = file2memory(&postdata, &size, file); 930 931 if(file && (file != stdin)) 932 fclose(file); 933 if(err) 934 return err; 935 } 936 else { 937 GetStr(&postdata, p); 938 if(postdata) 939 size = strlen(postdata); 940 } 941 942 if(!postdata) { 943 /* no data from the file, point to a zero byte string to make this 944 get sent as a POST anyway */ 945 postdata = strdup(""); 946 if(!postdata) 947 return PARAM_NO_MEM; 948 size = 0; 949 } 950 else { 951 char *enc = curl_easy_escape(config->easy, postdata, (int)size); 952 Curl_safefree(postdata); /* no matter if it worked or not */ 953 if(enc) { 954 /* now make a string with the name from above and append the 955 encoded string */ 956 size_t outlen = nlen + strlen(enc) + 2; 957 char *n = malloc(outlen); 958 if(!n) { 959 curl_free(enc); 960 return PARAM_NO_MEM; 961 } 962 if(nlen > 0) { /* only append '=' if we have a name */ 963 snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); 964 size = outlen-1; 965 } 966 else { 967 strcpy(n, enc); 968 size = outlen-2; /* since no '=' was inserted */ 969 } 970 curl_free(enc); 971 postdata = n; 972 } 973 else 974 return PARAM_NO_MEM; 975 } 976 } 977 else if('@' == *nextarg) { 978 /* the data begins with a '@' letter, it means that a file name 979 or - (stdin) follows */ 980 nextarg++; /* pass the @ */ 981 982 if(curlx_strequal("-", nextarg)) { 983 file = stdin; 984 if(subletter == 'b') /* forced data-binary */ 985 set_binmode(stdin); 986 } 987 else { 988 file = fopen(nextarg, "rb"); 989 if(!file) 990 warnf(config, "Couldn't read data from file \"%s\", this makes " 991 "an empty POST.\n", nextarg); 992 } 993 994 if(subletter == 'b') 995 /* forced binary */ 996 err = file2memory(&postdata, &size, file); 997 else { 998 err = file2string(&postdata, file); 999 if(postdata) 1000 size = strlen(postdata); 1001 } 1002 1003 if(file && (file != stdin)) 1004 fclose(file); 1005 if(err) 1006 return err; 1007 1008 if(!postdata) { 1009 /* no data from the file, point to a zero byte string to make this 1010 get sent as a POST anyway */ 1011 postdata = strdup(""); 1012 if(!postdata) 1013 return PARAM_NO_MEM; 1014 } 1015 } 1016 else { 1017 GetStr(&postdata, nextarg); 1018 if(postdata) 1019 size = strlen(postdata); 1020 } 1021 1022#ifdef CURL_DOES_CONVERSIONS 1023 if(subletter != 'b') { 1024 /* NOT forced binary, convert to ASCII */ 1025 if(convert_to_network(postdata, strlen(postdata))) { 1026 Curl_safefree(postdata); 1027 return PARAM_NO_MEM; 1028 } 1029 } 1030#endif 1031 1032 if(config->postfields) { 1033 /* we already have a string, we append this one with a separating 1034 &-letter */ 1035 char *oldpost = config->postfields; 1036 curl_off_t oldlen = config->postfieldsize; 1037 curl_off_t newlen = oldlen + size + 2; 1038 config->postfields = malloc((size_t)newlen); 1039 if(!config->postfields) { 1040 Curl_safefree(oldpost); 1041 Curl_safefree(postdata); 1042 return PARAM_NO_MEM; 1043 } 1044 memcpy(config->postfields, oldpost, (size_t)oldlen); 1045 /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */ 1046 config->postfields[oldlen] = '\x26'; 1047 memcpy(&config->postfields[oldlen+1], postdata, size); 1048 config->postfields[oldlen+1+size] = '\0'; 1049 Curl_safefree(oldpost); 1050 Curl_safefree(postdata); 1051 config->postfieldsize += size+1; 1052 } 1053 else { 1054 config->postfields = postdata; 1055 config->postfieldsize = size; 1056 } 1057 } 1058 /* 1059 We can't set the request type here, as this data might be used in 1060 a simple GET if -G is used. Already or soon. 1061 1062 if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) { 1063 Curl_safefree(postdata); 1064 return PARAM_BAD_USE; 1065 } 1066 */ 1067 break; 1068 case 'D': 1069 /* dump-header to given file name */ 1070 GetStr(&config->headerfile, nextarg); 1071 break; 1072 case 'e': 1073 { 1074 char *ptr = strstr(nextarg, ";auto"); 1075 if(ptr) { 1076 /* Automatic referer requested, this may be combined with a 1077 set initial one */ 1078 config->autoreferer = TRUE; 1079 *ptr = 0; /* zero terminate here */ 1080 } 1081 else 1082 config->autoreferer = FALSE; 1083 GetStr(&config->referer, nextarg); 1084 } 1085 break; 1086 case 'E': 1087 switch(subletter) { 1088 case 'a': /* CA info PEM file */ 1089 /* CA info PEM file */ 1090 GetStr(&config->cacert, nextarg); 1091 break; 1092 case 'b': /* cert file type */ 1093 GetStr(&config->cert_type, nextarg); 1094 break; 1095 case 'c': /* private key file */ 1096 GetStr(&config->key, nextarg); 1097 break; 1098 case 'd': /* private key file type */ 1099 GetStr(&config->key_type, nextarg); 1100 break; 1101 case 'e': /* private key passphrase */ 1102 GetStr(&config->key_passwd, nextarg); 1103 cleanarg(nextarg); 1104 break; 1105 case 'f': /* crypto engine */ 1106 GetStr(&config->engine, nextarg); 1107 if(config->engine && curlx_raw_equal(config->engine,"list")) 1108 config->list_engines = TRUE; 1109 break; 1110 case 'g': /* CA info PEM file */ 1111 /* CA cert directory */ 1112 GetStr(&config->capath, nextarg); 1113 break; 1114 case 'h': /* --pubkey public key file */ 1115 GetStr(&config->pubkey, nextarg); 1116 break; 1117 case 'i': /* --hostpubmd5 md5 of the host public key */ 1118 GetStr(&config->hostpubmd5, nextarg); 1119 if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) 1120 return PARAM_BAD_USE; 1121 break; 1122 case 'j': /* CRL info PEM file */ 1123 /* CRL file */ 1124 GetStr(&config->crlfile, nextarg); 1125 break; 1126 case 'k': /* TLS username */ 1127 if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) 1128 GetStr(&config->tls_username, nextarg); 1129 else 1130 return PARAM_LIBCURL_DOESNT_SUPPORT; 1131 break; 1132 case 'l': /* TLS password */ 1133 if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) 1134 GetStr(&config->tls_password, nextarg); 1135 else 1136 return PARAM_LIBCURL_DOESNT_SUPPORT; 1137 break; 1138 case 'm': /* TLS authentication type */ 1139 if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { 1140 GetStr(&config->tls_authtype, nextarg); 1141 if(!strequal(config->tls_authtype, "SRP")) 1142 return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ 1143 } 1144 else 1145 return PARAM_LIBCURL_DOESNT_SUPPORT; 1146 break; 1147 default: /* certificate file */ 1148 { 1149 char *ptr = strchr(nextarg, ':'); 1150 /* Since we live in a world of weirdness and confusion, the win32 1151 dudes can use : when using drive letters and thus 1152 c:\file:password needs to work. In order not to break 1153 compatibility, we still use : as separator, but we try to detect 1154 when it is used for a file name! On windows. */ 1155#ifdef WIN32 1156 if(ptr && 1157 (ptr == &nextarg[1]) && 1158 (nextarg[2] == '\\' || nextarg[2] == '/') && 1159 (ISALPHA(nextarg[0])) ) 1160 /* colon in the second column, followed by a backslash, and the 1161 first character is an alphabetic letter: 1162 1163 this is a drive letter colon */ 1164 ptr = strchr(&nextarg[3], ':'); /* find the next one instead */ 1165#endif 1166 if(ptr) { 1167 /* we have a password too */ 1168 *ptr = '\0'; 1169 ptr++; 1170 GetStr(&config->key_passwd, ptr); 1171 } 1172 GetStr(&config->cert, nextarg); 1173 cleanarg(nextarg); 1174 } 1175 } 1176 break; 1177 case 'f': 1178 /* fail hard on errors */ 1179 config->failonerror = toggle; 1180 break; 1181 case 'F': 1182 /* "form data" simulation, this is a little advanced so lets do our best 1183 to sort this out slowly and carefully */ 1184 if(formparse(config, 1185 nextarg, 1186 &config->httppost, 1187 &config->last_post, 1188 (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */ 1189 return PARAM_BAD_USE; 1190 if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq)) 1191 return PARAM_BAD_USE; 1192 break; 1193 1194 case 'g': /* g disables URLglobbing */ 1195 config->globoff = toggle; 1196 break; 1197 1198 case 'G': /* HTTP GET */ 1199 config->use_httpget = TRUE; 1200 break; 1201 1202 case 'h': /* h for help */ 1203 if(toggle) { 1204 tool_help(); 1205 return PARAM_HELP_REQUESTED; 1206 } 1207 /* we now actually support --no-help too! */ 1208 break; 1209 case 'H': 1210 /* A custom header to append to a list */ 1211 err = add2list(&config->headers, nextarg); 1212 if(err) 1213 return err; 1214 break; 1215 case 'i': 1216 config->include_headers = toggle; /* include the headers as well in the 1217 general output stream */ 1218 break; 1219 case 'j': 1220 config->cookiesession = toggle; 1221 break; 1222 case 'I': 1223 /* 1224 * no_body will imply include_headers later on 1225 */ 1226 config->no_body = toggle; 1227 if(SetHTTPrequest(config, 1228 (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, 1229 &config->httpreq)) 1230 return PARAM_BAD_USE; 1231 break; 1232 case 'J': /* --remote-header-name */ 1233 if(config->include_headers) { 1234 warnf(config, 1235 "--include and --remote-header-name cannot be combined.\n"); 1236 return PARAM_BAD_USE; 1237 } 1238 config->content_disposition = toggle; 1239 break; 1240 case 'k': /* allow insecure SSL connects */ 1241 config->insecure_ok = toggle; 1242 break; 1243 case 'K': /* parse config file */ 1244 if(parseconfig(nextarg, config)) 1245 warnf(config, "error trying read config from the '%s' file\n", 1246 nextarg); 1247 break; 1248 case 'l': 1249 config->dirlistonly = toggle; /* only list the names of the FTP dir */ 1250 break; 1251 case 'L': 1252 config->followlocation = toggle; /* Follow Location: HTTP headers */ 1253 switch (subletter) { 1254 case 't': 1255 /* Continue to send authentication (user+password) when following 1256 * locations, even when hostname changed */ 1257 config->unrestricted_auth = toggle; 1258 break; 1259 } 1260 break; 1261 case 'm': 1262 /* specified max time */ 1263 if(str2num(&config->timeout, nextarg)) 1264 return PARAM_BAD_NUMERIC; 1265 break; 1266 case 'M': /* M for manual, huge help */ 1267 if(toggle) { /* --no-manual shows no manual... */ 1268#ifdef USE_MANUAL 1269 hugehelp(); 1270 return PARAM_HELP_REQUESTED; 1271#else 1272 warnf(config, 1273 "built-in manual was disabled at build-time!\n"); 1274 return PARAM_OPTION_UNKNOWN; 1275#endif 1276 } 1277 break; 1278 case 'n': 1279 switch(subletter) { 1280 case 'o': /* CA info PEM file */ 1281 /* use .netrc or URL */ 1282 config->netrc_opt = toggle; 1283 break; 1284 case 'e': /* netrc-file */ 1285 GetStr(&config->netrc_file, nextarg); 1286 break; 1287 default: 1288 /* pick info from .netrc, if this is used for http, curl will 1289 automatically enfore user+password with the request */ 1290 config->netrc = toggle; 1291 break; 1292 } 1293 break; 1294 case 'N': 1295 /* disable the output I/O buffering. note that the option is called 1296 --buffer but is mostly used in the negative form: --no-buffer */ 1297 if(longopt) 1298 config->nobuffer = (!toggle)?TRUE:FALSE; 1299 else 1300 config->nobuffer = toggle; 1301 break; 1302 case 'O': /* --remote-name */ 1303 if(subletter == 'a') { /* --remote-name-all */ 1304 config->default_node_flags = toggle?GETOUT_USEREMOTE:0; 1305 break; 1306 } 1307 /* fall-through! */ 1308 case 'o': /* --output */ 1309 /* output file */ 1310 { 1311 struct getout *url; 1312 if(config->url_out || ((config->url_out = config->url_list) != NULL)) { 1313 /* there's a node here, if it already is filled-in continue to find 1314 an "empty" node */ 1315 while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) 1316 config->url_out = config->url_out->next; 1317 } 1318 1319 /* now there might or might not be an available node to fill in! */ 1320 1321 if(config->url_out) 1322 /* existing node */ 1323 url = config->url_out; 1324 else 1325 /* there was no free node, create one! */ 1326 url = new_getout(config); 1327 1328 if(!url) 1329 return PARAM_NO_MEM; 1330 else { 1331 /* fill in the outfile */ 1332 if('o' == letter) { 1333 GetStr(&url->outfile, nextarg); 1334 url->flags &= ~GETOUT_USEREMOTE; /* switch off */ 1335 } 1336 else { 1337 url->outfile = NULL; /* leave it */ 1338 if(toggle) 1339 url->flags |= GETOUT_USEREMOTE; /* switch on */ 1340 else 1341 url->flags &= ~GETOUT_USEREMOTE; /* switch off */ 1342 } 1343 url->flags |= GETOUT_OUTFILE; 1344 } 1345 } 1346 break; 1347 case 'P': 1348 /* This makes the FTP sessions use PORT instead of PASV */ 1349 /* use <eth0> or <192.168.10.10> style addresses. Anything except 1350 this will make us try to get the "default" address. 1351 NOTE: this is a changed behaviour since the released 4.1! 1352 */ 1353 GetStr(&config->ftpport, nextarg); 1354 break; 1355 case 'p': 1356 /* proxy tunnel for non-http protocols */ 1357 config->proxytunnel = toggle; 1358 break; 1359 1360 case 'q': /* if used first, already taken care of, we do it like 1361 this so we don't cause an error! */ 1362 break; 1363 case 'Q': 1364 /* QUOTE command to send to FTP server */ 1365 switch(nextarg[0]) { 1366 case '-': 1367 /* prefixed with a dash makes it a POST TRANSFER one */ 1368 nextarg++; 1369 err = add2list(&config->postquote, nextarg); 1370 break; 1371 case '+': 1372 /* prefixed with a plus makes it a just-before-transfer one */ 1373 nextarg++; 1374 err = add2list(&config->prequote, nextarg); 1375 break; 1376 default: 1377 err = add2list(&config->quote, nextarg); 1378 break; 1379 } 1380 if(err) 1381 return err; 1382 break; 1383 case 'r': 1384 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range 1385 (and won't actually be range by definition). The man page previously 1386 claimed that to be a good way, why this code is added to work-around 1387 it. */ 1388 if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { 1389 char buffer[32]; 1390 curl_off_t off; 1391 warnf(config, 1392 "A specified range MUST include at least one dash (-). " 1393 "Appending one for you!\n"); 1394 off = curlx_strtoofft(nextarg, NULL, 10); 1395 snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); 1396 Curl_safefree(config->range); 1397 config->range = strdup(buffer); 1398 if(!config->range) 1399 return PARAM_NO_MEM; 1400 } 1401 { 1402 /* byte range requested */ 1403 char *tmp_range; 1404 tmp_range = nextarg; 1405 while(*tmp_range != '\0') { 1406 if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { 1407 warnf(config,"Invalid character is found in given range. " 1408 "A specified range MUST have only digits in " 1409 "\'start\'-\'stop\'. The server's response to this " 1410 "request is uncertain.\n"); 1411 break; 1412 } 1413 tmp_range++; 1414 } 1415 /* byte range requested */ 1416 GetStr(&config->range, nextarg); 1417 } 1418 break; 1419 case 'R': 1420 /* use remote file's time */ 1421 config->remote_time = toggle; 1422 break; 1423 case 's': 1424 /* don't show progress meter, don't show errors : */ 1425 if(toggle) 1426 config->mute = config->noprogress = TRUE; 1427 else 1428 config->mute = config->noprogress = FALSE; 1429 if(config->showerror < 0) 1430 /* if still on the default value, set showerror to the reverse of 1431 toggle. This is to allow -S and -s to be used in an independent 1432 order but still have the same effect. */ 1433 config->showerror = (!toggle)?TRUE:FALSE; /* toggle off */ 1434 break; 1435 case 'S': 1436 /* show errors */ 1437 config->showerror = toggle?1:0; /* toggle on if used with -s */ 1438 break; 1439 case 't': 1440 /* Telnet options */ 1441 err = add2list(&config->telnet_options, nextarg); 1442 if(err) 1443 return err; 1444 break; 1445 case 'T': 1446 /* we are uploading */ 1447 { 1448 struct getout *url; 1449 if(config->url_out || ((config->url_out = config->url_list) != NULL)) { 1450 /* there's a node here, if it already is filled-in continue to find 1451 an "empty" node */ 1452 while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD)) 1453 config->url_out = config->url_out->next; 1454 } 1455 1456 /* now there might or might not be an available node to fill in! */ 1457 1458 if(config->url_out) 1459 /* existing node */ 1460 url = config->url_out; 1461 else 1462 /* there was no free node, create one! */ 1463 url = new_getout(config); 1464 1465 if(!url) 1466 return PARAM_NO_MEM; 1467 else { 1468 url->flags |= GETOUT_UPLOAD; /* mark -T used */ 1469 if(!*nextarg) 1470 url->flags |= GETOUT_NOUPLOAD; 1471 else { 1472 /* "-" equals stdin, but keep the string around for now */ 1473 GetStr(&url->infile, nextarg); 1474 } 1475 } 1476 } 1477 break; 1478 case 'u': 1479 /* user:password */ 1480 GetStr(&config->userpwd, nextarg); 1481 cleanarg(nextarg); 1482 err = checkpasswd("host", &config->userpwd); 1483 if(err) 1484 return err; 1485 break; 1486 case 'U': 1487 /* Proxy user:password */ 1488 GetStr(&config->proxyuserpwd, nextarg); 1489 cleanarg(nextarg); 1490 err = checkpasswd("proxy", &config->proxyuserpwd); 1491 if(err) 1492 return err; 1493 break; 1494 case 'v': 1495 if(toggle) { 1496 /* the '%' thing here will cause the trace get sent to stderr */ 1497 Curl_safefree(config->trace_dump); 1498 config->trace_dump = strdup("%"); 1499 if(!config->trace_dump) 1500 return PARAM_NO_MEM; 1501 if(config->tracetype && (config->tracetype != TRACE_PLAIN)) 1502 warnf(config, 1503 "-v, --verbose overrides an earlier trace/verbose option\n"); 1504 config->tracetype = TRACE_PLAIN; 1505 } 1506 else 1507 /* verbose is disabled here */ 1508 config->tracetype = TRACE_NONE; 1509 break; 1510 case 'V': 1511 { 1512 const char *const *proto; 1513 1514 if(!toggle) 1515 /* --no-version yields no output! */ 1516 break; 1517 1518 printf(CURL_ID "%s\n", curl_version()); 1519 if(curlinfo->protocols) { 1520 printf("Protocols: "); 1521 for(proto = curlinfo->protocols; *proto; ++proto) { 1522 printf("%s ", *proto); 1523 } 1524 puts(""); /* newline */ 1525 } 1526 if(curlinfo->features) { 1527 unsigned int i; 1528 printf("Features: "); 1529 for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) { 1530 if(curlinfo->features & feats[i].bitmask) 1531 printf("%s ", feats[i].name); 1532 } 1533 puts(""); /* newline */ 1534 } 1535 } 1536 return PARAM_HELP_REQUESTED; 1537 case 'w': 1538 /* get the output string */ 1539 if('@' == *nextarg) { 1540 /* the data begins with a '@' letter, it means that a file name 1541 or - (stdin) follows */ 1542 FILE *file; 1543 const char *fname; 1544 nextarg++; /* pass the @ */ 1545 if(curlx_strequal("-", nextarg)) { 1546 fname = "<stdin>"; 1547 file = stdin; 1548 } 1549 else { 1550 fname = nextarg; 1551 file = fopen(nextarg, "r"); 1552 } 1553 err = file2string(&config->writeout, file); 1554 if(file && (file != stdin)) 1555 fclose(file); 1556 if(err) 1557 return err; 1558 if(!config->writeout) 1559 warnf(config, "Failed to read %s", fname); 1560 } 1561 else 1562 GetStr(&config->writeout, nextarg); 1563 break; 1564 case 'x': 1565 /* proxy */ 1566 GetStr(&config->proxy, nextarg); 1567 config->proxyver = CURLPROXY_HTTP; 1568 break; 1569 case 'X': 1570 /* set custom request */ 1571 GetStr(&config->customrequest, nextarg); 1572 break; 1573 case 'y': 1574 /* low speed time */ 1575 if(str2num(&config->low_speed_time, nextarg)) 1576 return PARAM_BAD_NUMERIC; 1577 if(!config->low_speed_limit) 1578 config->low_speed_limit = 1; 1579 break; 1580 case 'Y': 1581 /* low speed limit */ 1582 if(str2num(&config->low_speed_limit, nextarg)) 1583 return PARAM_BAD_NUMERIC; 1584 if(!config->low_speed_time) 1585 config->low_speed_time = 30; 1586 break; 1587 case 'z': /* time condition coming up */ 1588 switch(*nextarg) { 1589 case '+': 1590 nextarg++; 1591 default: 1592 /* If-Modified-Since: (section 14.28 in RFC2068) */ 1593 config->timecond = CURL_TIMECOND_IFMODSINCE; 1594 break; 1595 case '-': 1596 /* If-Unmodified-Since: (section 14.24 in RFC2068) */ 1597 config->timecond = CURL_TIMECOND_IFUNMODSINCE; 1598 nextarg++; 1599 break; 1600 case '=': 1601 /* Last-Modified: (section 14.29 in RFC2068) */ 1602 config->timecond = CURL_TIMECOND_LASTMOD; 1603 nextarg++; 1604 break; 1605 } 1606 now = time(NULL); 1607 config->condtime=curl_getdate(nextarg, &now); 1608 if(-1 == (int)config->condtime) { 1609 /* now let's see if it is a file name to get the time from instead! */ 1610 struct_stat statbuf; 1611 if(-1 == stat(nextarg, &statbuf)) { 1612 /* failed, remove time condition */ 1613 config->timecond = CURL_TIMECOND_NONE; 1614 warnf(config, 1615 "Illegal date format for -z, --timecond (and not " 1616 "a file name). Disabling time condition. " 1617 "See curl_getdate(3) for valid date syntax.\n"); 1618 } 1619 else { 1620 /* pull the time out from the file */ 1621 config->condtime = statbuf.st_mtime; 1622 } 1623 } 1624 break; 1625 default: /* unknown flag */ 1626 return PARAM_OPTION_UNKNOWN; 1627 } 1628 hit = -1; 1629 1630 } while(!longopt && !singleopt && *++parse && !*usedarg); 1631 1632 return PARAM_OK; 1633} 1634 1635