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