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