tool_getparam.c (98831B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "tool_setup.h" 25 26 #include "tool_cfgable.h" 27 #include "tool_cb_prg.h" 28 #include "tool_filetime.h" 29 #include "tool_formparse.h" 30 #include "tool_getparam.h" 31 #include "tool_helpers.h" 32 #include "tool_libinfo.h" 33 #include "tool_msgs.h" 34 #include "tool_paramhlp.h" 35 #include "tool_parsecfg.h" 36 #include "tool_main.h" 37 #include "tool_stderr.h" 38 #include "tool_help.h" 39 #include "var.h" 40 41 #include "memdebug.h" /* keep this as LAST include */ 42 43 #define ALLOW_BLANK TRUE 44 #define DENY_BLANK FALSE 45 46 static ParameterError getstr(char **str, const char *val, bool allowblank) 47 { 48 if(*str) { 49 free(*str); 50 *str = NULL; 51 } 52 DEBUGASSERT(val); 53 if(!allowblank && !val[0]) 54 return PARAM_BLANK_STRING; 55 56 *str = strdup(val); 57 if(!*str) 58 return PARAM_NO_MEM; 59 60 return PARAM_OK; 61 } 62 63 static ParameterError getstrn(char **str, const char *val, 64 size_t len, bool allowblank) 65 { 66 if(*str) { 67 free(*str); 68 *str = NULL; 69 } 70 DEBUGASSERT(val); 71 if(!allowblank && !val[0]) 72 return PARAM_BLANK_STRING; 73 74 *str = malloc(len + 1); 75 if(!*str) 76 return PARAM_NO_MEM; 77 78 memcpy(*str, val, len); 79 (*str)[len] = 0; /* null-terminate */ 80 81 return PARAM_OK; 82 } 83 84 /* this array MUST be alphasorted based on the 'lname' */ 85 static const struct LongShort aliases[]= { 86 {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET}, 87 {"alpn", ARG_BOOL|ARG_NO|ARG_TLS, ' ', C_ALPN}, 88 {"alt-svc", ARG_STRG, ' ', C_ALT_SVC}, 89 {"anyauth", ARG_NONE, ' ', C_ANYAUTH}, 90 {"append", ARG_BOOL, 'a', C_APPEND}, 91 {"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4}, 92 {"basic", ARG_BOOL, ' ', C_BASIC}, 93 {"buffer", ARG_BOOL|ARG_NO, 'N', C_BUFFER}, 94 {"ca-native", ARG_BOOL|ARG_TLS, ' ', C_CA_NATIVE}, 95 {"cacert", ARG_FILE|ARG_TLS, ' ', C_CACERT}, 96 {"capath", ARG_FILE|ARG_TLS, ' ', C_CAPATH}, 97 {"cert", ARG_FILE|ARG_TLS|ARG_CLEAR, 'E', C_CERT}, 98 {"cert-status", ARG_BOOL|ARG_TLS, ' ', C_CERT_STATUS}, 99 {"cert-type", ARG_STRG|ARG_TLS, ' ', C_CERT_TYPE}, 100 {"ciphers", ARG_STRG|ARG_TLS, ' ', C_CIPHERS}, 101 {"clobber", ARG_BOOL|ARG_NO, ' ', C_CLOBBER}, 102 {"compressed", ARG_BOOL, ' ', C_COMPRESSED}, 103 {"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH}, 104 {"config", ARG_FILE, 'K', C_CONFIG}, 105 {"connect-timeout", ARG_STRG, ' ', C_CONNECT_TIMEOUT}, 106 {"connect-to", ARG_STRG, ' ', C_CONNECT_TO}, 107 {"continue-at", ARG_STRG, 'C', C_CONTINUE_AT}, 108 {"cookie", ARG_STRG, 'b', C_COOKIE}, 109 {"cookie-jar", ARG_STRG, 'c', C_COOKIE_JAR}, 110 {"create-dirs", ARG_BOOL, ' ', C_CREATE_DIRS}, 111 {"create-file-mode", ARG_STRG, ' ', C_CREATE_FILE_MODE}, 112 {"crlf", ARG_BOOL, ' ', C_CRLF}, 113 {"crlfile", ARG_FILE|ARG_TLS, ' ', C_CRLFILE}, 114 {"curves", ARG_STRG|ARG_TLS, ' ', C_CURVES}, 115 {"data", ARG_STRG, 'd', C_DATA}, 116 {"data-ascii", ARG_STRG, ' ', C_DATA_ASCII}, 117 {"data-binary", ARG_STRG, ' ', C_DATA_BINARY}, 118 {"data-raw", ARG_STRG, ' ', C_DATA_RAW}, 119 {"data-urlencode", ARG_STRG, ' ', C_DATA_URLENCODE}, 120 {"delegation", ARG_STRG, ' ', C_DELEGATION}, 121 {"digest", ARG_BOOL, ' ', C_DIGEST}, 122 {"disable", ARG_BOOL, 'q', C_DISABLE}, 123 {"disable-eprt", ARG_BOOL, ' ', C_DISABLE_EPRT}, 124 {"disable-epsv", ARG_BOOL, ' ', C_DISABLE_EPSV}, 125 {"disallow-username-in-url", ARG_BOOL, ' ', C_DISALLOW_USERNAME_IN_URL}, 126 {"dns-interface", ARG_STRG, ' ', C_DNS_INTERFACE}, 127 {"dns-ipv4-addr", ARG_STRG, ' ', C_DNS_IPV4_ADDR}, 128 {"dns-ipv6-addr", ARG_STRG, ' ', C_DNS_IPV6_ADDR}, 129 {"dns-servers", ARG_STRG, ' ', C_DNS_SERVERS}, 130 {"doh-cert-status", ARG_BOOL|ARG_TLS, ' ', C_DOH_CERT_STATUS}, 131 {"doh-insecure", ARG_BOOL|ARG_TLS, ' ', C_DOH_INSECURE}, 132 {"doh-url" , ARG_STRG, ' ', C_DOH_URL}, 133 {"dump-ca-embed", ARG_NONE|ARG_TLS, ' ', C_DUMP_CA_EMBED}, 134 {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER}, 135 {"ech", ARG_STRG|ARG_TLS, ' ', C_ECH}, 136 {"egd-file", ARG_STRG|ARG_DEPR, ' ', C_EGD_FILE}, 137 {"engine", ARG_STRG|ARG_TLS, ' ', C_ENGINE}, 138 {"eprt", ARG_BOOL, ' ', C_EPRT}, 139 {"epsv", ARG_BOOL, ' ', C_EPSV}, 140 {"etag-compare", ARG_FILE, ' ', C_ETAG_COMPARE}, 141 {"etag-save", ARG_FILE, ' ', C_ETAG_SAVE}, 142 {"expect100-timeout", ARG_STRG, ' ', C_EXPECT100_TIMEOUT}, 143 {"fail", ARG_BOOL, 'f', C_FAIL}, 144 {"fail-early", ARG_BOOL, ' ', C_FAIL_EARLY}, 145 {"fail-with-body", ARG_BOOL, ' ', C_FAIL_WITH_BODY}, 146 {"false-start", ARG_BOOL, ' ', C_FALSE_START}, 147 {"form", ARG_STRG, 'F', C_FORM}, 148 {"form-escape", ARG_BOOL, ' ', C_FORM_ESCAPE}, 149 {"form-string", ARG_STRG, ' ', C_FORM_STRING}, 150 {"ftp-account", ARG_STRG, ' ', C_FTP_ACCOUNT}, 151 {"ftp-alternative-to-user", ARG_STRG, ' ', C_FTP_ALTERNATIVE_TO_USER}, 152 {"ftp-create-dirs", ARG_BOOL, ' ', C_FTP_CREATE_DIRS}, 153 {"ftp-method", ARG_STRG, ' ', C_FTP_METHOD}, 154 {"ftp-pasv", ARG_NONE, ' ', C_FTP_PASV}, 155 {"ftp-port", ARG_STRG, 'P', C_FTP_PORT}, 156 {"ftp-pret", ARG_BOOL, ' ', C_FTP_PRET}, 157 {"ftp-skip-pasv-ip", ARG_BOOL, ' ', C_FTP_SKIP_PASV_IP}, 158 {"ftp-ssl", ARG_BOOL|ARG_TLS, ' ', C_FTP_SSL}, 159 {"ftp-ssl-ccc", ARG_BOOL|ARG_TLS, ' ', C_FTP_SSL_CCC}, 160 {"ftp-ssl-ccc-mode", ARG_STRG|ARG_TLS, ' ', C_FTP_SSL_CCC_MODE}, 161 {"ftp-ssl-control", ARG_BOOL|ARG_TLS, ' ', C_FTP_SSL_CONTROL}, 162 {"ftp-ssl-reqd", ARG_BOOL|ARG_TLS, ' ', C_FTP_SSL_REQD}, 163 {"get", ARG_BOOL, 'G', C_GET}, 164 {"globoff", ARG_BOOL, 'g', C_GLOBOFF}, 165 {"happy-eyeballs-timeout-ms", ARG_STRG, ' ', C_HAPPY_EYEBALLS_TIMEOUT_MS}, 166 {"haproxy-clientip", ARG_STRG, ' ', C_HAPROXY_CLIENTIP}, 167 {"haproxy-protocol", ARG_BOOL, ' ', C_HAPROXY_PROTOCOL}, 168 {"head", ARG_BOOL, 'I', C_HEAD}, 169 {"header", ARG_STRG, 'H', C_HEADER}, 170 {"help", ARG_STRG, 'h', C_HELP}, 171 {"hostpubmd5", ARG_STRG, ' ', C_HOSTPUBMD5}, 172 {"hostpubsha256", ARG_STRG, ' ', C_HOSTPUBSHA256}, 173 {"hsts", ARG_STRG|ARG_TLS, ' ', C_HSTS}, 174 {"http0.9", ARG_BOOL, ' ', C_HTTP0_9}, 175 {"http1.0", ARG_NONE, '0', C_HTTP1_0}, 176 {"http1.1", ARG_NONE, ' ', C_HTTP1_1}, 177 {"http2", ARG_NONE, ' ', C_HTTP2}, 178 {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE}, 179 {"http3", ARG_NONE|ARG_TLS, ' ', C_HTTP3}, 180 {"http3-only", ARG_NONE|ARG_TLS, ' ', C_HTTP3_ONLY}, 181 {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH}, 182 {"include", ARG_BOOL, ' ', C_INCLUDE}, 183 {"insecure", ARG_BOOL, 'k', C_INSECURE}, 184 {"interface", ARG_STRG, ' ', C_INTERFACE}, 185 {"ip-tos", ARG_STRG, ' ', C_IP_TOS}, 186 #ifndef CURL_DISABLE_IPFS 187 {"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY}, 188 #endif /* !CURL_DISABLE_IPFS */ 189 {"ipv4", ARG_NONE, '4', C_IPV4}, 190 {"ipv6", ARG_NONE, '6', C_IPV6}, 191 {"json", ARG_STRG, ' ', C_JSON}, 192 {"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES}, 193 {"keepalive", ARG_BOOL|ARG_NO, ' ', C_KEEPALIVE}, 194 {"keepalive-cnt", ARG_STRG, ' ', C_KEEPALIVE_CNT}, 195 {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, 196 {"key", ARG_FILE, ' ', C_KEY}, 197 {"key-type", ARG_STRG|ARG_TLS, ' ', C_KEY_TYPE}, 198 {"krb", ARG_STRG, ' ', C_KRB}, 199 {"krb4", ARG_STRG, ' ', C_KRB4}, 200 {"libcurl", ARG_STRG, ' ', C_LIBCURL}, 201 {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE}, 202 {"list-only", ARG_BOOL, 'l', C_LIST_ONLY}, 203 {"local-port", ARG_STRG, ' ', C_LOCAL_PORT}, 204 {"location", ARG_BOOL, 'L', C_LOCATION}, 205 {"location-trusted", ARG_BOOL, ' ', C_LOCATION_TRUSTED}, 206 {"login-options", ARG_STRG, ' ', C_LOGIN_OPTIONS}, 207 {"mail-auth", ARG_STRG, ' ', C_MAIL_AUTH}, 208 {"mail-from", ARG_STRG, ' ', C_MAIL_FROM}, 209 {"mail-rcpt", ARG_STRG, ' ', C_MAIL_RCPT}, 210 {"mail-rcpt-allowfails", ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS}, 211 {"manual", ARG_BOOL, 'M', C_MANUAL}, 212 {"max-filesize", ARG_STRG, ' ', C_MAX_FILESIZE}, 213 {"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS}, 214 {"max-time", ARG_STRG, 'm', C_MAX_TIME}, 215 {"metalink", ARG_BOOL|ARG_DEPR, ' ', C_METALINK}, 216 {"mptcp", ARG_BOOL, ' ', C_MPTCP}, 217 {"negotiate", ARG_BOOL, ' ', C_NEGOTIATE}, 218 {"netrc", ARG_BOOL, 'n', C_NETRC}, 219 {"netrc-file", ARG_FILE, ' ', C_NETRC_FILE}, 220 {"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL}, 221 {"next", ARG_NONE, ':', C_NEXT}, 222 {"noproxy", ARG_STRG, ' ', C_NOPROXY}, 223 {"npn", ARG_BOOL|ARG_DEPR, ' ', C_NPN}, 224 {"ntlm", ARG_BOOL, ' ', C_NTLM}, 225 {"ntlm-wb", ARG_BOOL|ARG_DEPR, ' ', C_NTLM_WB}, 226 {"oauth2-bearer", ARG_STRG|ARG_CLEAR, ' ', C_OAUTH2_BEARER}, 227 {"output", ARG_FILE, 'o', C_OUTPUT}, 228 {"output-dir", ARG_STRG, ' ', C_OUTPUT_DIR}, 229 {"parallel", ARG_BOOL, 'Z', C_PARALLEL}, 230 {"parallel-immediate", ARG_BOOL, ' ', C_PARALLEL_IMMEDIATE}, 231 {"parallel-max", ARG_STRG, ' ', C_PARALLEL_MAX}, 232 {"pass", ARG_STRG|ARG_CLEAR, ' ', C_PASS}, 233 {"path-as-is", ARG_BOOL, ' ', C_PATH_AS_IS}, 234 {"pinnedpubkey", ARG_STRG|ARG_TLS, ' ', C_PINNEDPUBKEY}, 235 {"post301", ARG_BOOL, ' ', C_POST301}, 236 {"post302", ARG_BOOL, ' ', C_POST302}, 237 {"post303", ARG_BOOL, ' ', C_POST303}, 238 {"preproxy", ARG_STRG, ' ', C_PREPROXY}, 239 {"progress-bar", ARG_BOOL, '#', C_PROGRESS_BAR}, 240 {"progress-meter", ARG_BOOL|ARG_NO, ' ', C_PROGRESS_METER}, 241 {"proto", ARG_STRG, ' ', C_PROTO}, 242 {"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT}, 243 {"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR}, 244 {"proxy", ARG_STRG, 'x', C_PROXY}, 245 {"proxy-anyauth", ARG_BOOL, ' ', C_PROXY_ANYAUTH}, 246 {"proxy-basic", ARG_BOOL, ' ', C_PROXY_BASIC}, 247 {"proxy-ca-native", ARG_BOOL|ARG_TLS, ' ', C_PROXY_CA_NATIVE}, 248 {"proxy-cacert", ARG_FILE|ARG_TLS, ' ', C_PROXY_CACERT}, 249 {"proxy-capath", ARG_FILE|ARG_TLS, ' ', C_PROXY_CAPATH}, 250 {"proxy-cert", ARG_FILE|ARG_TLS|ARG_CLEAR, ' ', C_PROXY_CERT}, 251 {"proxy-cert-type", ARG_STRG|ARG_TLS, ' ', C_PROXY_CERT_TYPE}, 252 {"proxy-ciphers", ARG_STRG|ARG_TLS, ' ', C_PROXY_CIPHERS}, 253 {"proxy-crlfile", ARG_FILE|ARG_TLS, ' ', C_PROXY_CRLFILE}, 254 {"proxy-digest", ARG_BOOL, ' ', C_PROXY_DIGEST}, 255 {"proxy-header", ARG_STRG, ' ', C_PROXY_HEADER}, 256 {"proxy-http2", ARG_BOOL, ' ', C_PROXY_HTTP2}, 257 {"proxy-insecure", ARG_BOOL, ' ', C_PROXY_INSECURE}, 258 {"proxy-key", ARG_FILE|ARG_TLS, ' ', C_PROXY_KEY}, 259 {"proxy-key-type", ARG_STRG|ARG_TLS, ' ', C_PROXY_KEY_TYPE}, 260 {"proxy-negotiate", ARG_BOOL, ' ', C_PROXY_NEGOTIATE}, 261 {"proxy-ntlm", ARG_BOOL, ' ', C_PROXY_NTLM}, 262 {"proxy-pass", ARG_STRG|ARG_CLEAR, ' ', C_PROXY_PASS}, 263 {"proxy-pinnedpubkey", ARG_STRG|ARG_TLS, ' ', C_PROXY_PINNEDPUBKEY}, 264 {"proxy-service-name", ARG_STRG, ' ', C_PROXY_SERVICE_NAME}, 265 {"proxy-ssl-allow-beast", ARG_BOOL|ARG_TLS, ' ', 266 C_PROXY_SSL_ALLOW_BEAST}, 267 {"proxy-ssl-auto-client-cert", ARG_BOOL|ARG_TLS, ' ', 268 C_PROXY_SSL_AUTO_CLIENT_CERT}, 269 {"proxy-tls13-ciphers", ARG_STRG|ARG_TLS, ' ', C_PROXY_TLS13_CIPHERS}, 270 {"proxy-tlsauthtype", ARG_STRG|ARG_TLS, ' ', C_PROXY_TLSAUTHTYPE}, 271 {"proxy-tlspassword", ARG_STRG|ARG_TLS|ARG_CLEAR, ' ', C_PROXY_TLSPASSWORD}, 272 {"proxy-tlsuser", ARG_STRG|ARG_TLS|ARG_CLEAR, ' ', C_PROXY_TLSUSER}, 273 {"proxy-tlsv1", ARG_NONE|ARG_TLS, ' ', C_PROXY_TLSV1}, 274 {"proxy-user", ARG_STRG|ARG_CLEAR, 'U', C_PROXY_USER}, 275 {"proxy1.0", ARG_STRG, ' ', C_PROXY1_0}, 276 {"proxytunnel", ARG_BOOL, 'p', C_PROXYTUNNEL}, 277 {"pubkey", ARG_STRG, ' ', C_PUBKEY}, 278 {"quote", ARG_STRG, 'Q', C_QUOTE}, 279 {"random-file", ARG_FILE|ARG_DEPR, ' ', C_RANDOM_FILE}, 280 {"range", ARG_STRG, 'r', C_RANGE}, 281 {"rate", ARG_STRG, ' ', C_RATE}, 282 {"raw", ARG_BOOL, ' ', C_RAW}, 283 {"referer", ARG_STRG, 'e', C_REFERER}, 284 {"remote-header-name", ARG_BOOL, 'J', C_REMOTE_HEADER_NAME}, 285 {"remote-name", ARG_BOOL, 'O', C_REMOTE_NAME}, 286 {"remote-name-all", ARG_BOOL, ' ', C_REMOTE_NAME_ALL}, 287 {"remote-time", ARG_BOOL, 'R', C_REMOTE_TIME}, 288 {"remove-on-error", ARG_BOOL, ' ', C_REMOVE_ON_ERROR}, 289 {"request", ARG_STRG, 'X', C_REQUEST}, 290 {"request-target", ARG_STRG, ' ', C_REQUEST_TARGET}, 291 {"resolve", ARG_STRG, ' ', C_RESOLVE}, 292 {"retry", ARG_STRG, ' ', C_RETRY}, 293 {"retry-all-errors", ARG_BOOL, ' ', C_RETRY_ALL_ERRORS}, 294 {"retry-connrefused", ARG_BOOL, ' ', C_RETRY_CONNREFUSED}, 295 {"retry-delay", ARG_STRG, ' ', C_RETRY_DELAY}, 296 {"retry-max-time", ARG_STRG, ' ', C_RETRY_MAX_TIME}, 297 {"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID}, 298 {"sasl-ir", ARG_BOOL, ' ', C_SASL_IR}, 299 {"service-name", ARG_STRG, ' ', C_SERVICE_NAME}, 300 {"sessionid", ARG_BOOL|ARG_NO, ' ', C_SESSIONID}, 301 {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR}, 302 {"show-headers", ARG_BOOL, 'i', C_SHOW_HEADERS}, 303 {"sigalgs", ARG_STRG|ARG_TLS, ' ', 304 C_SIGNATURE_ALGORITHMS}, 305 {"silent", ARG_BOOL, 's', C_SILENT}, 306 {"skip-existing", ARG_BOOL, ' ', C_SKIP_EXISTING}, 307 {"socks4", ARG_STRG, ' ', C_SOCKS4}, 308 {"socks4a", ARG_STRG, ' ', C_SOCKS4A}, 309 {"socks5", ARG_STRG, ' ', C_SOCKS5}, 310 {"socks5-basic", ARG_BOOL, ' ', C_SOCKS5_BASIC}, 311 {"socks5-gssapi", ARG_BOOL, ' ', C_SOCKS5_GSSAPI}, 312 {"socks5-gssapi-nec", ARG_BOOL, ' ', C_SOCKS5_GSSAPI_NEC}, 313 {"socks5-gssapi-service", ARG_STRG, ' ', C_SOCKS5_GSSAPI_SERVICE}, 314 {"socks5-hostname", ARG_STRG, ' ', C_SOCKS5_HOSTNAME}, 315 {"speed-limit", ARG_STRG, 'Y', C_SPEED_LIMIT}, 316 {"speed-time", ARG_STRG, 'y', C_SPEED_TIME}, 317 {"ssl", ARG_BOOL|ARG_TLS, ' ', C_SSL}, 318 {"ssl-allow-beast", ARG_BOOL|ARG_TLS, ' ', C_SSL_ALLOW_BEAST}, 319 {"ssl-auto-client-cert", ARG_BOOL|ARG_TLS, ' ', 320 C_SSL_AUTO_CLIENT_CERT}, 321 {"ssl-no-revoke", ARG_BOOL|ARG_TLS, ' ', C_SSL_NO_REVOKE}, 322 {"ssl-reqd", ARG_BOOL|ARG_TLS, ' ', C_SSL_REQD}, 323 {"ssl-revoke-best-effort", ARG_BOOL|ARG_TLS, ' ', 324 C_SSL_REVOKE_BEST_EFFORT}, 325 {"ssl-sessions", ARG_FILE|ARG_TLS, ' ', C_SSL_SESSIONS}, 326 {"sslv2", ARG_NONE|ARG_DEPR, '2', C_SSLV2}, 327 {"sslv3", ARG_NONE|ARG_DEPR, '3', C_SSLV3}, 328 {"stderr", ARG_FILE, ' ', C_STDERR}, 329 {"styled-output", ARG_BOOL, ' ', C_STYLED_OUTPUT}, 330 {"suppress-connect-headers", ARG_BOOL, ' ', C_SUPPRESS_CONNECT_HEADERS}, 331 {"tcp-fastopen", ARG_BOOL, ' ', C_TCP_FASTOPEN}, 332 {"tcp-nodelay", ARG_BOOL, ' ', C_TCP_NODELAY}, 333 {"telnet-option", ARG_STRG, 't', C_TELNET_OPTION}, 334 #ifdef DEBUGBUILD 335 {"test-duphandle", ARG_BOOL, ' ', C_TEST_DUPHANDLE}, 336 {"test-event", ARG_BOOL, ' ', C_TEST_EVENT}, 337 #endif 338 {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE}, 339 {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS}, 340 {"time-cond", ARG_STRG, 'z', C_TIME_COND}, 341 {"tls-earlydata", ARG_BOOL|ARG_TLS, ' ', C_TLS_EARLYDATA}, 342 {"tls-max", ARG_STRG|ARG_TLS, ' ', C_TLS_MAX}, 343 {"tls13-ciphers", ARG_STRG|ARG_TLS, ' ', C_TLS13_CIPHERS}, 344 {"tlsauthtype", ARG_STRG|ARG_TLS, ' ', C_TLSAUTHTYPE}, 345 {"tlspassword", ARG_STRG|ARG_TLS|ARG_CLEAR, ' ', C_TLSPASSWORD}, 346 {"tlsuser", ARG_STRG|ARG_TLS|ARG_CLEAR, ' ', C_TLSUSER}, 347 {"tlsv1", ARG_NONE|ARG_TLS, '1', C_TLSV1}, 348 {"tlsv1.0", ARG_NONE|ARG_TLS, ' ', C_TLSV1_0}, 349 {"tlsv1.1", ARG_NONE|ARG_TLS, ' ', C_TLSV1_1}, 350 {"tlsv1.2", ARG_NONE|ARG_TLS, ' ', C_TLSV1_2}, 351 {"tlsv1.3", ARG_NONE|ARG_TLS, ' ', C_TLSV1_3}, 352 {"tr-encoding", ARG_BOOL, ' ', C_TR_ENCODING}, 353 {"trace", ARG_FILE, ' ', C_TRACE}, 354 {"trace-ascii", ARG_FILE, ' ', C_TRACE_ASCII}, 355 {"trace-config", ARG_STRG, ' ', C_TRACE_CONFIG}, 356 {"trace-ids", ARG_BOOL, ' ', C_TRACE_IDS}, 357 {"trace-time", ARG_BOOL, ' ', C_TRACE_TIME}, 358 {"unix-socket", ARG_FILE, ' ', C_UNIX_SOCKET}, 359 {"upload-file", ARG_FILE, 'T', C_UPLOAD_FILE}, 360 {"upload-flags", ARG_STRG, ' ', C_UPLOAD_FLAGS}, 361 {"url", ARG_STRG, ' ', C_URL}, 362 {"url-query", ARG_STRG, ' ', C_URL_QUERY}, 363 {"use-ascii", ARG_BOOL, 'B', C_USE_ASCII}, 364 {"user", ARG_STRG|ARG_CLEAR, 'u', C_USER}, 365 {"user-agent", ARG_STRG, 'A', C_USER_AGENT}, 366 {"variable", ARG_STRG, ' ', C_VARIABLE}, 367 {"verbose", ARG_BOOL, 'v', C_VERBOSE}, 368 {"version", ARG_BOOL, 'V', C_VERSION}, 369 {"vlan-priority", ARG_STRG, ' ', C_VLAN_PRIORITY}, 370 #ifdef USE_WATT32 371 {"wdebug", ARG_BOOL, ' ', C_WDEBUG}, 372 #endif 373 {"write-out", ARG_STRG, 'w', C_WRITE_OUT}, 374 {"xattr", ARG_BOOL, ' ', C_XATTR}, 375 }; 376 377 /* Split the argument of -E to 'certname' and 'passphrase' separated by colon. 378 * We allow ':' and '\' to be escaped by '\' so that we can use certificate 379 * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/> 380 * for details. */ 381 #ifndef UNITTESTS 382 static 383 #endif 384 void parse_cert_parameter(const char *cert_parameter, 385 char **certname, 386 char **passphrase) 387 { 388 size_t param_length = strlen(cert_parameter); 389 size_t span; 390 const char *param_place = NULL; 391 char *certname_place = NULL; 392 *certname = NULL; 393 *passphrase = NULL; 394 395 /* most trivial assumption: cert_parameter is empty */ 396 if(param_length == 0) 397 return; 398 399 /* next less trivial: cert_parameter starts 'pkcs11:' and thus 400 * looks like a RFC7512 PKCS#11 URI which can be used as-is. 401 * Also if cert_parameter contains no colon nor backslash, this 402 * means no passphrase was given and no characters escaped */ 403 if(curl_strnequal(cert_parameter, "pkcs11:", 7) || 404 !strpbrk(cert_parameter, ":\\")) { 405 *certname = strdup(cert_parameter); 406 return; 407 } 408 /* deal with escaped chars; find unescaped colon if it exists */ 409 certname_place = malloc(param_length + 1); 410 if(!certname_place) 411 return; 412 413 *certname = certname_place; 414 param_place = cert_parameter; 415 while(*param_place) { 416 span = strcspn(param_place, ":\\"); 417 memcpy(certname_place, param_place, span); 418 param_place += span; 419 certname_place += span; 420 /* we just ate all the non-special chars. now we are on either a special 421 * char or the end of the string. */ 422 switch(*param_place) { 423 case '\0': 424 break; 425 case '\\': 426 param_place++; 427 switch(*param_place) { 428 case '\0': 429 *certname_place++ = '\\'; 430 break; 431 case '\\': 432 *certname_place++ = '\\'; 433 param_place++; 434 break; 435 case ':': 436 *certname_place++ = ':'; 437 param_place++; 438 break; 439 default: 440 *certname_place++ = '\\'; 441 *certname_place++ = *param_place; 442 param_place++; 443 break; 444 } 445 break; 446 case ':': 447 /* Since we live in a world of weirdness and confusion, the Windows 448 dudes can use : when using drive letters and thus c:\file:password 449 needs to work. In order not to break compatibility, we still use : as 450 separator, but we try to detect when it is used for a filename! On 451 Windows. */ 452 #ifdef _WIN32 453 if((param_place == &cert_parameter[1]) && 454 (cert_parameter[2] == '\\' || cert_parameter[2] == '/') && 455 (ISALPHA(cert_parameter[0])) ) { 456 /* colon in the second column, followed by a backslash, and the 457 first character is an alphabetic letter: 458 459 this is a drive letter colon */ 460 *certname_place++ = ':'; 461 param_place++; 462 break; 463 } 464 #endif 465 /* escaped colons and Windows drive letter colons were handled 466 * above; if we are still here, this is a separating colon */ 467 param_place++; 468 if(*param_place) { 469 *passphrase = strdup(param_place); 470 } 471 goto done; 472 } 473 } 474 done: 475 *certname_place = '\0'; 476 } 477 478 /* Replace (in-place) '%20' by '+' according to RFC1866 */ 479 static size_t replace_url_encoded_space_by_plus(char *url) 480 { 481 size_t orig_len = strlen(url); 482 size_t orig_index = 0; 483 size_t new_index = 0; 484 485 while(orig_index < orig_len) { 486 if((url[orig_index] == '%') && 487 (url[orig_index + 1] == '2') && 488 (url[orig_index + 2] == '0')) { 489 url[new_index] = '+'; 490 orig_index += 3; 491 } 492 else{ 493 if(new_index != orig_index) { 494 url[new_index] = url[orig_index]; 495 } 496 orig_index++; 497 } 498 new_index++; 499 } 500 501 url[new_index] = 0; /* terminate string */ 502 503 return new_index; /* new size */ 504 } 505 506 static void 507 GetFileAndPassword(const char *nextarg, char **file, char **password) 508 { 509 char *certname, *passphrase; 510 /* nextarg is never NULL here */ 511 parse_cert_parameter(nextarg, &certname, &passphrase); 512 free(*file); 513 *file = certname; 514 if(passphrase) { 515 free(*password); 516 *password = passphrase; 517 } 518 } 519 520 /* Get a size parameter for '--limit-rate' or '--max-filesize'. 521 * We support a 'G', 'M' or 'K' suffix too. 522 */ 523 static ParameterError GetSizeParameter(struct GlobalConfig *global, 524 const char *arg, 525 const char *which, 526 curl_off_t *value_out) 527 { 528 const char *unit = arg; 529 curl_off_t value; 530 531 if(curlx_str_number(&unit, &value, CURL_OFF_T_MAX)) { 532 warnf(global, "invalid number specified for %s", which); 533 return PARAM_BAD_USE; 534 } 535 536 if(!*unit) 537 unit = "b"; 538 else if(strlen(unit) > 1) 539 unit = "w"; /* unsupported */ 540 541 switch(*unit) { 542 case 'G': 543 case 'g': 544 if(value > (CURL_OFF_T_MAX / (1024*1024*1024))) 545 return PARAM_NUMBER_TOO_LARGE; 546 value *= 1024*1024*1024; 547 break; 548 case 'M': 549 case 'm': 550 if(value > (CURL_OFF_T_MAX / (1024*1024))) 551 return PARAM_NUMBER_TOO_LARGE; 552 value *= 1024*1024; 553 break; 554 case 'K': 555 case 'k': 556 if(value > (CURL_OFF_T_MAX / 1024)) 557 return PARAM_NUMBER_TOO_LARGE; 558 value *= 1024; 559 break; 560 case 'b': 561 case 'B': 562 /* for plain bytes, leave as-is */ 563 break; 564 default: 565 warnf(global, "unsupported %s unit. Use G, M, K or B", which); 566 return PARAM_BAD_USE; 567 } 568 *value_out = value; 569 return PARAM_OK; 570 } 571 572 #ifdef HAVE_WRITABLE_ARGV 573 static void cleanarg(char *str) 574 { 575 /* now that getstr has copied the contents of nextarg, wipe the next 576 * argument out so that the username:password is not displayed in the 577 * system process list */ 578 if(str) { 579 size_t len = strlen(str); 580 memset(str, '*', len); 581 } 582 } 583 #else 584 #define cleanarg(x) tool_nop_stmt 585 #endif 586 587 /* the maximum size we allow the dynbuf generated string */ 588 #define MAX_DATAURLENCODE (500*1024*1024) 589 590 /* --data-urlencode */ 591 static ParameterError data_urlencode(struct GlobalConfig *global, 592 const char *nextarg, 593 char **postp, 594 size_t *lenp) 595 { 596 /* [name]=[content], we encode the content part only 597 * [name]@[filename] 598 * 599 * Case 2: we first load the file using that name and then encode 600 * the content. 601 */ 602 ParameterError err; 603 const char *p = strchr(nextarg, '='); 604 size_t nlen; 605 char is_file; 606 char *postdata = NULL; 607 size_t size = 0; 608 if(!p) 609 /* there was no '=' letter, check for a '@' instead */ 610 p = strchr(nextarg, '@'); 611 if(p) { 612 nlen = p - nextarg; /* length of the name part */ 613 is_file = *p++; /* pass the separator */ 614 } 615 else { 616 /* neither @ nor =, so no name and it is not a file */ 617 nlen = 0; 618 is_file = 0; 619 p = nextarg; 620 } 621 if('@' == is_file) { 622 FILE *file; 623 /* a '@' letter, it means that a filename or - (stdin) follows */ 624 if(!strcmp("-", p)) { 625 file = stdin; 626 CURLX_SET_BINMODE(stdin); 627 } 628 else { 629 file = fopen(p, "rb"); 630 if(!file) { 631 errorf(global, "Failed to open %s", p); 632 return PARAM_READ_ERROR; 633 } 634 } 635 636 err = file2memory(&postdata, &size, file); 637 638 if(file && (file != stdin)) 639 fclose(file); 640 if(err) 641 return err; 642 } 643 else { 644 err = getstr(&postdata, p, ALLOW_BLANK); 645 if(err) 646 goto error; 647 size = strlen(postdata); 648 } 649 650 if(!postdata) { 651 /* no data from the file, point to a zero byte string to make this 652 get sent as a POST anyway */ 653 postdata = strdup(""); 654 if(!postdata) 655 return PARAM_NO_MEM; 656 size = 0; 657 } 658 else { 659 char *enc = curl_easy_escape(NULL, postdata, (int)size); 660 tool_safefree(postdata); /* no matter if it worked or not */ 661 if(enc) { 662 char *n; 663 replace_url_encoded_space_by_plus(enc); 664 if(nlen > 0) { /* only append '=' if we have a name */ 665 struct dynbuf dyn; 666 curlx_dyn_init(&dyn, MAX_DATAURLENCODE); 667 if(curlx_dyn_addn(&dyn, nextarg, nlen) || 668 curlx_dyn_addn(&dyn, "=", 1) || 669 curlx_dyn_add(&dyn, enc)) { 670 curl_free(enc); 671 return PARAM_NO_MEM; 672 } 673 curl_free(enc); 674 n = curlx_dyn_ptr(&dyn); 675 size = curlx_dyn_len(&dyn); 676 } 677 else { 678 n = enc; 679 size = strlen(n); 680 } 681 postdata = n; 682 } 683 else 684 return PARAM_NO_MEM; 685 } 686 *postp = postdata; 687 *lenp = size; 688 return PARAM_OK; 689 error: 690 return err; 691 } 692 693 static void sethttpver(struct OperationConfig *config, 694 long httpversion) 695 { 696 if(config->httpversion && 697 (config->httpversion != httpversion)) 698 warnf(config->global, "Overrides previous HTTP version option"); 699 700 config->httpversion = httpversion; 701 } 702 703 static CURLcode set_trace_config(struct GlobalConfig *global, 704 const char *token) 705 { 706 CURLcode result = CURLE_OK; 707 const char *next, *name; 708 bool toggle; 709 710 while(token) { 711 size_t len; 712 next = strchr(token, ','); 713 714 if(next) 715 len = next - token; 716 else 717 len = strlen(token); 718 719 switch(*token) { 720 case '-': 721 toggle = FALSE; 722 name = token + 1; 723 len--; 724 break; 725 case '+': 726 toggle = TRUE; 727 name = token + 1; 728 len--; 729 break; 730 default: 731 toggle = TRUE; 732 name = token; 733 break; 734 } 735 736 if((len == 3) && curl_strnequal(name, "all", 3)) { 737 global->traceids = toggle; 738 global->tracetime = toggle; 739 result = curl_global_trace(token); 740 if(result) 741 goto out; 742 } 743 else if((len == 3) && curl_strnequal(name, "ids", 3)) { 744 global->traceids = toggle; 745 } 746 else if((len == 4) && curl_strnequal(name, "time", 4)) { 747 global->tracetime = toggle; 748 } 749 else { 750 char buffer[32]; 751 msnprintf(buffer, sizeof(buffer), "%c%.*s", toggle ? '+' : '-', 752 (int)len, name); 753 result = curl_global_trace(buffer); 754 if(result) 755 goto out; 756 } 757 if(next) { 758 next++; 759 if(*next == ' ') 760 next++; 761 } 762 token = next; 763 } 764 out: 765 return result; 766 } 767 768 static int findarg(const void *a, const void *b) 769 { 770 const struct LongShort *aa = a; 771 const struct LongShort *bb = b; 772 return strcmp(aa->lname, bb->lname); 773 } 774 775 const struct LongShort *findshortopt(char letter) 776 { 777 static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */ 778 static bool singles_done = FALSE; 779 if((letter >= 127) || (letter <= ' ')) 780 return NULL; 781 782 if(!singles_done) { 783 unsigned int j; 784 for(j = 0; j < CURL_ARRAYSIZE(aliases); j++) { 785 if(aliases[j].letter != ' ') { 786 unsigned char l = (unsigned char)aliases[j].letter; 787 singles[l - ' '] = &aliases[j]; 788 } 789 } 790 singles_done = TRUE; 791 } 792 return singles[letter - ' ']; 793 } 794 795 struct TOSEntry { 796 const char *name; 797 unsigned char value; 798 }; 799 800 static const struct TOSEntry tos_entries[] = { 801 {"AF11", 0x28}, 802 {"AF12", 0x30}, 803 {"AF13", 0x38}, 804 {"AF21", 0x48}, 805 {"AF22", 0x50}, 806 {"AF23", 0x58}, 807 {"AF31", 0x68}, 808 {"AF32", 0x70}, 809 {"AF33", 0x78}, 810 {"AF41", 0x88}, 811 {"AF42", 0x90}, 812 {"AF43", 0x98}, 813 {"CE", 0x03}, 814 {"CS0", 0x00}, 815 {"CS1", 0x20}, 816 {"CS2", 0x40}, 817 {"CS3", 0x60}, 818 {"CS4", 0x80}, 819 {"CS5", 0xa0}, 820 {"CS6", 0xc0}, 821 {"CS7", 0xe0}, 822 {"ECT0", 0x02}, 823 {"ECT1", 0x01}, 824 {"EF", 0xb8}, 825 {"LE", 0x04}, 826 {"LOWCOST", 0x02}, 827 {"LOWDELAY", 0x10}, 828 {"MINCOST", 0x02}, 829 {"RELIABILITY", 0x04}, 830 {"THROUGHPUT", 0x08}, 831 {"VOICE-ADMIT", 0xb0} 832 }; 833 834 static int find_tos(const void *a, const void *b) 835 { 836 const struct TOSEntry *aa = a; 837 const struct TOSEntry *bb = b; 838 return strcmp(aa->name, bb->name); 839 } 840 841 #define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */ 842 static ParameterError url_query(const char *nextarg, 843 struct OperationConfig *config) 844 { 845 size_t size = 0; 846 ParameterError err = PARAM_OK; 847 char *query; 848 struct dynbuf dyn; 849 curlx_dyn_init(&dyn, MAX_QUERY_LEN); 850 851 if(*nextarg == '+') { 852 /* use without encoding */ 853 query = strdup(&nextarg[1]); 854 if(!query) 855 err = PARAM_NO_MEM; 856 } 857 else 858 err = data_urlencode(config->global, nextarg, &query, &size); 859 860 if(!err) { 861 if(config->query) { 862 CURLcode result = curlx_dyn_addf(&dyn, "%s&%s", config->query, query); 863 free(query); 864 if(result) 865 err = PARAM_NO_MEM; 866 else { 867 free(config->query); 868 config->query = curlx_dyn_ptr(&dyn); 869 } 870 } 871 else 872 config->query = query; 873 } 874 return err; 875 } 876 877 static ParameterError set_data(cmdline_t cmd, 878 const char *nextarg, 879 struct OperationConfig *config) 880 { 881 char *postdata = NULL; 882 FILE *file; 883 size_t size = 0; 884 ParameterError err = PARAM_OK; 885 struct GlobalConfig *global = config->global; 886 887 if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */ 888 err = data_urlencode(global, nextarg, &postdata, &size); 889 if(err) 890 return err; 891 } 892 else if('@' == *nextarg && (cmd != C_DATA_RAW)) { 893 /* the data begins with a '@' letter, it means that a filename 894 or - (stdin) follows */ 895 nextarg++; /* pass the @ */ 896 897 if(!strcmp("-", nextarg)) { 898 file = stdin; 899 if(cmd == C_DATA_BINARY) /* forced data-binary */ 900 CURLX_SET_BINMODE(stdin); 901 } 902 else { 903 file = fopen(nextarg, "rb"); 904 if(!file) { 905 errorf(global, "Failed to open %s", nextarg); 906 return PARAM_READ_ERROR; 907 } 908 } 909 910 if((cmd == C_DATA_BINARY) || /* --data-binary */ 911 (cmd == C_JSON) /* --json */) 912 /* forced binary */ 913 err = file2memory(&postdata, &size, file); 914 else { 915 err = file2string(&postdata, file); 916 if(postdata) 917 size = strlen(postdata); 918 } 919 920 if(file && (file != stdin)) 921 fclose(file); 922 if(err) 923 return err; 924 925 if(!postdata) { 926 /* no data from the file, point to a zero byte string to make this 927 get sent as a POST anyway */ 928 postdata = strdup(""); 929 if(!postdata) 930 return PARAM_NO_MEM; 931 } 932 } 933 else { 934 err = getstr(&postdata, nextarg, ALLOW_BLANK); 935 if(err) 936 return err; 937 size = strlen(postdata); 938 } 939 if(cmd == C_JSON) 940 config->jsoned = TRUE; 941 942 if(curlx_dyn_len(&config->postdata)) { 943 /* skip separator append for --json */ 944 if(!err && (cmd != C_JSON) && 945 curlx_dyn_addn(&config->postdata, "&", 1)) 946 err = PARAM_NO_MEM; 947 } 948 949 if(!err && curlx_dyn_addn(&config->postdata, postdata, size)) 950 err = PARAM_NO_MEM; 951 952 tool_safefree(postdata); 953 954 config->postfields = curlx_dyn_ptr(&config->postdata); 955 return err; 956 } 957 958 static ParameterError set_rate(struct GlobalConfig *global, 959 const char *nextarg) 960 { 961 /* --rate */ 962 /* support a few different suffixes, extract the suffix first, then 963 get the number and convert to per hour. 964 /s == per second 965 /m == per minute 966 /h == per hour (default) 967 /d == per day (24 hours) 968 */ 969 ParameterError err = PARAM_OK; 970 const char *div = strchr(nextarg, '/'); 971 char number[26]; 972 long denominator; 973 long numerator = 60*60*1000; /* default per hour */ 974 size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg); 975 if(numlen > sizeof(number) -1) 976 return PARAM_NUMBER_TOO_LARGE; 977 978 memcpy(number, nextarg, numlen); 979 number[numlen] = 0; 980 err = str2unum(&denominator, number); 981 if(err) 982 return err; 983 984 if(denominator < 1) 985 return PARAM_BAD_USE; 986 987 if(div) { 988 curl_off_t numunits; 989 div++; 990 991 if(curlx_str_number(&div, &numunits, CURL_OFF_T_MAX)) 992 numunits = 1; 993 994 switch(*div) { 995 case 's': /* per second */ 996 numerator = 1000; 997 break; 998 case 'm': /* per minute */ 999 numerator = 60*1000; 1000 break; 1001 case 'h': /* per hour */ 1002 break; 1003 case 'd': /* per day */ 1004 numerator = 24*60*60*1000; 1005 break; 1006 default: 1007 errorf(global, "unsupported --rate unit"); 1008 err = PARAM_BAD_USE; 1009 break; 1010 } 1011 1012 if((LONG_MAX / numerator) < numunits) { 1013 /* overflow, too large number */ 1014 errorf(global, "too large --rate unit"); 1015 err = PARAM_NUMBER_TOO_LARGE; 1016 } 1017 /* this typecast is okay based on the check above */ 1018 numerator *= (long)numunits; 1019 } 1020 1021 if(err) 1022 ; 1023 else if(denominator > numerator) 1024 err = PARAM_NUMBER_TOO_LARGE; 1025 else 1026 global->ms_per_transfer = numerator/denominator; 1027 1028 return err; 1029 } 1030 1031 const struct LongShort *findlongopt(const char *opt) 1032 { 1033 struct LongShort key; 1034 key.lname = opt; 1035 1036 return bsearch(&key, aliases, CURL_ARRAYSIZE(aliases), 1037 sizeof(aliases[0]), findarg); 1038 } 1039 1040 static ParameterError add_url(struct OperationConfig *config, 1041 const char *thisurl, 1042 bool remote_noglob) 1043 { 1044 ParameterError err = PARAM_OK; 1045 struct getout *url; 1046 1047 if(!config->url_get) 1048 config->url_get = config->url_list; 1049 1050 if(config->url_get) { 1051 /* there is a node here, if it already is filled-in continue to find 1052 an "empty" node */ 1053 while(config->url_get && config->url_get->urlset) 1054 config->url_get = config->url_get->next; 1055 } 1056 1057 /* now there might or might not be an available node to fill in! */ 1058 1059 if(config->url_get) 1060 /* existing node */ 1061 url = config->url_get; 1062 else 1063 /* there was no free node, create one! */ 1064 config->url_get = url = new_getout(config); 1065 1066 if(!url) 1067 return PARAM_NO_MEM; 1068 else { 1069 /* fill in the URL */ 1070 err = getstr(&url->url, thisurl, DENY_BLANK); 1071 url->urlset = TRUE; 1072 if(remote_noglob) 1073 url->useremote = url->noglob = TRUE; 1074 if(!err && (++config->num_urls > 1) && 1075 (config->etag_save_file || config->etag_compare_file)) { 1076 errorf(config->global, "The etag options only work on a single URL"); 1077 return PARAM_BAD_USE; 1078 } 1079 } 1080 return err; 1081 } 1082 1083 static ParameterError parse_url(struct OperationConfig *config, 1084 const char *nextarg) 1085 { 1086 /* nextarg is never NULL here */ 1087 if(nextarg[0] == '@') { 1088 /* read URLs from a file, treat all as -O */ 1089 struct dynbuf line; 1090 ParameterError err = PARAM_OK; 1091 bool error = FALSE; 1092 bool fromstdin = !strcmp("-", &nextarg[1]); 1093 FILE *f; 1094 1095 if(fromstdin) 1096 f = stdin; 1097 else 1098 f = fopen(&nextarg[1], FOPEN_READTEXT); 1099 if(f) { 1100 curlx_dyn_init(&line, 8092); 1101 while(my_get_line(f, &line, &error)) { 1102 const char *ptr = curlx_dyn_ptr(&line); 1103 err = add_url(config, ptr, TRUE); 1104 if(err) 1105 break; 1106 } 1107 if(!fromstdin) 1108 fclose(f); 1109 curlx_dyn_free(&line); 1110 if(error || err) 1111 return PARAM_READ_ERROR; 1112 return PARAM_OK; 1113 } 1114 return PARAM_READ_ERROR; /* file not found */ 1115 } 1116 return add_url(config, nextarg, FALSE); 1117 } 1118 1119 1120 static ParameterError parse_localport(struct OperationConfig *config, 1121 const char *nextarg) 1122 { 1123 const char *pp = NULL; 1124 const char *p = nextarg; 1125 char buffer[22]; 1126 size_t plen = 0; 1127 while(ISDIGIT(*p)) 1128 p++; 1129 plen = p - nextarg; 1130 if(*p) { 1131 pp = p; 1132 /* check for ' - [end]' */ 1133 if(ISBLANK(*pp)) 1134 pp++; 1135 if(*pp != '-') 1136 return PARAM_BAD_USE; 1137 pp++; 1138 if(ISBLANK(*pp)) 1139 pp++; 1140 } 1141 msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, nextarg); 1142 if(str2unummax(&config->localport, buffer, 65535)) 1143 return PARAM_BAD_USE; 1144 if(!pp) 1145 config->localportrange = 1; /* default number of ports to try */ 1146 else { 1147 if(str2unummax(&config->localportrange, pp, 65535)) 1148 return PARAM_BAD_USE; 1149 config->localportrange -= (config->localport-1); 1150 if(config->localportrange < 1) 1151 return PARAM_BAD_USE; 1152 } 1153 return PARAM_OK; 1154 } 1155 1156 static ParameterError parse_continue_at(struct OperationConfig *config, 1157 const char *nextarg) 1158 { 1159 struct GlobalConfig *global = config->global; 1160 ParameterError err = PARAM_OK; 1161 if(config->range) { 1162 errorf(global, "--continue-at is mutually exclusive with --range"); 1163 return PARAM_BAD_USE; 1164 } 1165 if(config->rm_partial) { 1166 errorf(config->global, 1167 "--continue-at is mutually exclusive with --remove-on-error"); 1168 return PARAM_BAD_USE; 1169 } 1170 if(config->file_clobber_mode == CLOBBER_NEVER) { 1171 errorf(config->global, 1172 "--continue-at is mutually exclusive with --no-clobber"); 1173 return PARAM_BAD_USE; 1174 } 1175 /* This makes us continue an ftp transfer at given position */ 1176 if(strcmp(nextarg, "-")) { 1177 err = str2offset(&config->resume_from, nextarg); 1178 config->resume_from_current = FALSE; 1179 } 1180 else { 1181 config->resume_from_current = TRUE; 1182 config->resume_from = 0; 1183 } 1184 config->use_resume = TRUE; 1185 return err; 1186 } 1187 1188 static ParameterError parse_ech(struct OperationConfig *config, 1189 const char *nextarg) 1190 { 1191 ParameterError err = PARAM_OK; 1192 if(!feature_ech) 1193 err = PARAM_LIBCURL_DOESNT_SUPPORT; 1194 else if(strlen(nextarg) > 4 && curl_strnequal("pn:", nextarg, 3)) { 1195 /* a public_name */ 1196 err = getstr(&config->ech_public, nextarg, DENY_BLANK); 1197 } 1198 else if(strlen(nextarg) > 5 && curl_strnequal("ecl:", nextarg, 4)) { 1199 /* an ECHConfigList */ 1200 if('@' != *(nextarg + 4)) { 1201 err = getstr(&config->ech_config, nextarg, DENY_BLANK); 1202 } 1203 else { 1204 /* Indirect case: @filename or @- for stdin */ 1205 char *tmpcfg = NULL; 1206 FILE *file; 1207 1208 nextarg += 5; /* skip over 'ecl:@' */ 1209 if(!strcmp("-", nextarg)) { 1210 file = stdin; 1211 } 1212 else { 1213 file = fopen(nextarg, FOPEN_READTEXT); 1214 } 1215 if(!file) { 1216 warnf(config->global, 1217 "Couldn't read file \"%s\" " 1218 "specified for \"--ech ecl:\" option", 1219 nextarg); 1220 return PARAM_BAD_USE; /* */ 1221 } 1222 err = file2string(&tmpcfg, file); 1223 if(file != stdin) 1224 fclose(file); 1225 if(err) 1226 return err; 1227 config->ech_config = aprintf("ecl:%s",tmpcfg); 1228 free(tmpcfg); 1229 if(!config->ech_config) 1230 return PARAM_NO_MEM; 1231 } /* file done */ 1232 } 1233 else { 1234 /* Simple case: just a string, with a keyword */ 1235 err = getstr(&config->ech, nextarg, DENY_BLANK); 1236 } 1237 return err; 1238 } 1239 1240 static ParameterError parse_header(struct OperationConfig *config, 1241 cmdline_t cmd, 1242 const char *nextarg) 1243 { 1244 ParameterError err = PARAM_OK; 1245 1246 /* A custom header to append to a list */ 1247 if(nextarg[0] == '@') { 1248 /* read many headers from a file or stdin */ 1249 bool use_stdin = !strcmp(&nextarg[1], "-"); 1250 FILE *file = use_stdin ? stdin : fopen(&nextarg[1], FOPEN_READTEXT); 1251 if(!file) { 1252 errorf(config->global, "Failed to open %s", &nextarg[1]); 1253 err = PARAM_READ_ERROR; 1254 } 1255 else { 1256 struct dynbuf line; 1257 bool error = FALSE; 1258 curlx_dyn_init(&line, 1024*100); 1259 while(my_get_line(file, &line, &error)) { 1260 const char *ptr = curlx_dyn_ptr(&line); 1261 err = add2list(cmd == C_PROXY_HEADER ? /* --proxy-header? */ 1262 &config->proxyheaders : 1263 &config->headers, ptr); 1264 if(err) 1265 break; 1266 } 1267 if(error) 1268 err = PARAM_READ_ERROR; 1269 curlx_dyn_free(&line); 1270 if(!use_stdin) 1271 fclose(file); 1272 } 1273 } 1274 else { 1275 if(cmd == C_PROXY_HEADER) /* --proxy-header */ 1276 err = add2list(&config->proxyheaders, nextarg); 1277 else 1278 err = add2list(&config->headers, nextarg); 1279 } 1280 return err; 1281 } 1282 1283 static ParameterError parse_output(struct OperationConfig *config, 1284 const char *nextarg) 1285 { 1286 ParameterError err = PARAM_OK; 1287 struct getout *url; 1288 1289 /* output file */ 1290 if(!config->url_out) 1291 config->url_out = config->url_list; 1292 if(config->url_out) { 1293 /* there is a node here, if it already is filled-in continue to find 1294 an "empty" node */ 1295 while(config->url_out && config->url_out->outset) 1296 config->url_out = config->url_out->next; 1297 } 1298 1299 /* now there might or might not be an available node to fill in! */ 1300 1301 if(config->url_out) 1302 /* existing node */ 1303 url = config->url_out; 1304 else { 1305 /* there was no free node, create one! */ 1306 config->url_out = url = new_getout(config); 1307 } 1308 1309 if(!url) 1310 return PARAM_NO_MEM; 1311 1312 /* fill in the outfile */ 1313 err = getstr(&url->outfile, nextarg, DENY_BLANK); 1314 url->useremote = FALSE; /* switch off */ 1315 url->outset = TRUE; 1316 return err; 1317 } 1318 1319 static ParameterError parse_remote_name(struct OperationConfig *config, 1320 bool toggle) 1321 { 1322 ParameterError err = PARAM_OK; 1323 struct getout *url; 1324 1325 if(!toggle && !config->remote_name_all) 1326 return err; /* nothing to do */ 1327 1328 /* output file */ 1329 if(!config->url_out) 1330 config->url_out = config->url_list; 1331 if(config->url_out) { 1332 /* there is a node here, if it already is filled-in continue to find 1333 an "empty" node */ 1334 while(config->url_out && config->url_out->outset) 1335 config->url_out = config->url_out->next; 1336 } 1337 1338 /* now there might or might not be an available node to fill in! */ 1339 1340 if(config->url_out) 1341 /* existing node */ 1342 url = config->url_out; 1343 else { 1344 /* there was no free node, create one! */ 1345 config->url_out = url = new_getout(config); 1346 } 1347 1348 if(!url) 1349 return PARAM_NO_MEM; 1350 1351 url->outfile = NULL; /* leave it */ 1352 url->useremote = toggle; 1353 url->outset = TRUE; 1354 return PARAM_OK; 1355 } 1356 1357 static ParameterError parse_quote(struct OperationConfig *config, 1358 const char *nextarg) 1359 { 1360 ParameterError err = PARAM_OK; 1361 1362 /* QUOTE command to send to FTP server */ 1363 switch(nextarg[0]) { 1364 case '-': 1365 /* prefixed with a dash makes it a POST TRANSFER one */ 1366 nextarg++; 1367 err = add2list(&config->postquote, nextarg); 1368 break; 1369 case '+': 1370 /* prefixed with a plus makes it a just-before-transfer one */ 1371 nextarg++; 1372 err = add2list(&config->prequote, nextarg); 1373 break; 1374 default: 1375 err = add2list(&config->quote, nextarg); 1376 break; 1377 } 1378 return err; 1379 } 1380 1381 static ParameterError parse_range(struct OperationConfig *config, 1382 const char *nextarg) 1383 { 1384 ParameterError err = PARAM_OK; 1385 curl_off_t value; 1386 const char *orig = nextarg; 1387 struct GlobalConfig *global = config->global; 1388 1389 if(config->use_resume) { 1390 errorf(global, "--continue-at is mutually exclusive with --range"); 1391 return PARAM_BAD_USE; 1392 } 1393 if(!curlx_str_number(&nextarg, &value, CURL_OFF_T_MAX) && 1394 curlx_str_single(&nextarg, '-')) { 1395 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range 1396 (and will not actually be range by definition). The manpage previously 1397 claimed that to be a good way, why this code is added to work-around 1398 it. */ 1399 char buffer[32]; 1400 warnf(global, "A specified range MUST include at least one dash (-). " 1401 "Appending one for you"); 1402 msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", 1403 value); 1404 free(config->range); 1405 config->range = strdup(buffer); 1406 if(!config->range) 1407 err = PARAM_NO_MEM; 1408 } 1409 else { 1410 /* byte range requested */ 1411 while(*nextarg) { 1412 if(!ISDIGIT(*nextarg) && *nextarg != '-' && *nextarg != ',') { 1413 warnf(global, "Invalid character is found in given range. " 1414 "A specified range MUST have only digits in " 1415 "\'start\'-\'stop\'. The server's response to this " 1416 "request is uncertain."); 1417 break; 1418 } 1419 nextarg++; 1420 } 1421 err = getstr(&config->range, orig, DENY_BLANK); 1422 } 1423 return err; 1424 } 1425 1426 static ParameterError parse_upload_file(struct OperationConfig *config, 1427 const char *nextarg) 1428 { 1429 ParameterError err = PARAM_OK; 1430 struct getout *url; 1431 1432 /* we are uploading */ 1433 if(!config->url_ul) 1434 config->url_ul = config->url_list; 1435 if(config->url_ul) { 1436 /* there is a node here, if it already is filled-in continue to find 1437 an "empty" node */ 1438 while(config->url_ul && config->url_ul->uploadset) 1439 config->url_ul = config->url_ul->next; 1440 } 1441 1442 /* now there might or might not be an available node to fill in! */ 1443 1444 if(config->url_ul) 1445 /* existing node */ 1446 url = config->url_ul; 1447 else 1448 /* there was no free node, create one! */ 1449 config->url_ul = url = new_getout(config); 1450 1451 if(!url) 1452 return PARAM_NO_MEM; 1453 1454 url->uploadset = TRUE; /* mark -T used */ 1455 if(!*nextarg) 1456 url->noupload = TRUE; 1457 else { 1458 /* "-" equals stdin, but keep the string around for now */ 1459 err = getstr(&url->infile, nextarg, DENY_BLANK); 1460 } 1461 return err; 1462 } 1463 1464 static size_t verbose_nopts; 1465 1466 static ParameterError parse_verbose(struct GlobalConfig *global, 1467 bool toggle) 1468 { 1469 ParameterError err = PARAM_OK; 1470 1471 /* This option is a super-boolean with side effect when applied 1472 * more than once in the same argument flag, like `-vvv`. */ 1473 if(!toggle) { 1474 global->verbosity = 0; 1475 if(set_trace_config(global, "-all")) 1476 err = PARAM_NO_MEM; 1477 global->tracetype = TRACE_NONE; 1478 return err; 1479 } 1480 else if(!verbose_nopts) { 1481 /* fist `-v` in an argument resets to base verbosity */ 1482 global->verbosity = 0; 1483 if(set_trace_config(global, "-all")) 1484 return PARAM_NO_MEM; 1485 } 1486 /* the '%' thing here will cause the trace get sent to stderr */ 1487 switch(global->verbosity) { 1488 case 0: 1489 global->verbosity = 1; 1490 free(global->trace_dump); 1491 global->trace_dump = strdup("%"); 1492 if(!global->trace_dump) 1493 err = PARAM_NO_MEM; 1494 else { 1495 if(global->tracetype && (global->tracetype != TRACE_PLAIN)) 1496 warnf(global, 1497 "-v, --verbose overrides an earlier trace option"); 1498 global->tracetype = TRACE_PLAIN; 1499 } 1500 break; 1501 case 1: 1502 global->verbosity = 2; 1503 if(set_trace_config(global, "ids,time,protocol")) 1504 err = PARAM_NO_MEM; 1505 break; 1506 case 2: 1507 global->verbosity = 3; 1508 global->tracetype = TRACE_ASCII; 1509 if(set_trace_config(global, "ssl,read,write")) 1510 err = PARAM_NO_MEM; 1511 break; 1512 case 3: 1513 global->verbosity = 4; 1514 if(set_trace_config(global, "network")) 1515 err = PARAM_NO_MEM; 1516 break; 1517 default: 1518 /* no effect for now */ 1519 break; 1520 } 1521 return err; 1522 } 1523 1524 static ParameterError parse_writeout(struct OperationConfig *config, 1525 const char *nextarg) 1526 { 1527 ParameterError err = PARAM_OK; 1528 1529 /* get the output string */ 1530 if('@' == *nextarg) { 1531 /* the data begins with a '@' letter, it means that a filename 1532 or - (stdin) follows */ 1533 FILE *file; 1534 const char *fname; 1535 nextarg++; /* pass the @ */ 1536 if(!strcmp("-", nextarg)) { 1537 fname = "<stdin>"; 1538 file = stdin; 1539 } 1540 else { 1541 fname = nextarg; 1542 file = fopen(fname, FOPEN_READTEXT); 1543 if(!file) { 1544 errorf(config->global, "Failed to open %s", fname); 1545 return PARAM_READ_ERROR; 1546 } 1547 } 1548 tool_safefree(config->writeout); 1549 err = file2string(&config->writeout, file); 1550 if(file && (file != stdin)) 1551 fclose(file); 1552 if(err) 1553 return err; 1554 if(!config->writeout) 1555 warnf(config->global, "Failed to read %s", fname); 1556 } 1557 else 1558 err = getstr(&config->writeout, nextarg, ALLOW_BLANK); 1559 1560 return err; 1561 } 1562 1563 static ParameterError parse_time_cond(struct OperationConfig *config, 1564 const char *nextarg) 1565 { 1566 ParameterError err = PARAM_OK; 1567 1568 switch(*nextarg) { 1569 case '+': 1570 nextarg++; 1571 FALLTHROUGH(); 1572 default: 1573 /* If-Modified-Since: (section 14.28 in RFC2068) */ 1574 config->timecond = CURL_TIMECOND_IFMODSINCE; 1575 break; 1576 case '-': 1577 /* If-Unmodified-Since: (section 14.24 in RFC2068) */ 1578 config->timecond = CURL_TIMECOND_IFUNMODSINCE; 1579 nextarg++; 1580 break; 1581 case '=': 1582 /* Last-Modified: (section 14.29 in RFC2068) */ 1583 config->timecond = CURL_TIMECOND_LASTMOD; 1584 nextarg++; 1585 break; 1586 } 1587 config->condtime = (curl_off_t)curl_getdate(nextarg, NULL); 1588 if(-1 == config->condtime) { 1589 curl_off_t value; 1590 /* now let's see if it is a filename to get the time from instead! */ 1591 int rc = getfiletime(nextarg, config->global, &value); 1592 if(!rc) 1593 /* pull the time out from the file */ 1594 config->condtime = value; 1595 else { 1596 /* failed, remove time condition */ 1597 config->timecond = CURL_TIMECOND_NONE; 1598 warnf(config->global, 1599 "Illegal date format for -z, --time-cond (and not " 1600 "a filename). Disabling time condition. " 1601 "See curl_getdate(3) for valid date syntax."); 1602 } 1603 } 1604 return err; 1605 } 1606 1607 struct flagmap { 1608 const char *name; 1609 size_t len; 1610 unsigned char flag; 1611 }; 1612 1613 static const struct flagmap flag_table[] = { 1614 {"answered", 8, CURLULFLAG_ANSWERED}, 1615 {"deleted", 7, CURLULFLAG_DELETED}, 1616 {"draft", 5, CURLULFLAG_DRAFT}, 1617 {"flagged", 7, CURLULFLAG_FLAGGED}, 1618 {"seen", 4, CURLULFLAG_SEEN}, 1619 {NULL, 0, 0} 1620 }; 1621 1622 static ParameterError parse_upload_flags(struct OperationConfig *config, 1623 const char *flag) 1624 { 1625 ParameterError err = PARAM_OK; 1626 1627 while(flag) { 1628 bool negate; 1629 const struct flagmap *map; 1630 size_t len; 1631 char *next = strchr(flag, ','); /* Find next comma or end */ 1632 if(next) 1633 len = next - flag; 1634 else 1635 len = strlen(flag); 1636 1637 negate = (*flag == '-'); 1638 if(negate) { 1639 flag++; 1640 len--; 1641 } 1642 1643 for(map = flag_table; map->name; map++) { 1644 if((len == map->len) && !strncmp(flag, map->name, map->len)) { 1645 if(negate) 1646 config->upload_flags &= (unsigned char)~map->flag; 1647 else 1648 config->upload_flags |= map->flag; 1649 break; 1650 } 1651 } 1652 1653 if(!map->name) { 1654 err = PARAM_OPTION_UNKNOWN; 1655 break; 1656 } 1657 1658 if(next) 1659 /* move over the comma */ 1660 next++; 1661 flag = next; 1662 } 1663 1664 return err; 1665 } 1666 1667 /* if 'toggle' is TRUE, set the 'bits' in 'modify'. 1668 if 'toggle' is FALSE, clear the 'bits' in 'modify' 1669 */ 1670 static void togglebit(bool toggle, unsigned long *modify, unsigned long bits) 1671 { 1672 if(toggle) 1673 *modify |= bits; 1674 else 1675 *modify &= ~bits; 1676 } 1677 1678 /* opt_depr is the function that handles ARG_DEPR options */ 1679 static void opt_depr(struct GlobalConfig *global, 1680 const struct LongShort *a) 1681 { 1682 warnf(global, "--%s is deprecated and has no function anymore", a->lname); 1683 } 1684 1685 /* opt_none is the function that handles ARG_NONE options */ 1686 static ParameterError opt_none(struct OperationConfig *config, 1687 const struct LongShort *a) 1688 { 1689 switch(a->cmd) { 1690 case C_ANYAUTH: /* --anyauth */ 1691 config->authtype = CURLAUTH_ANY; 1692 break; 1693 case C_DUMP_CA_EMBED: /* --dump-ca-embed */ 1694 return PARAM_CA_EMBED_REQUESTED; 1695 case C_FTP_PASV: /* --ftp-pasv */ 1696 tool_safefree(config->ftpport); 1697 break; 1698 1699 case C_HTTP1_0: /* --http1.0 */ 1700 /* HTTP version 1.0 */ 1701 sethttpver(config, CURL_HTTP_VERSION_1_0); 1702 break; 1703 case C_HTTP1_1: /* --http1.1 */ 1704 /* HTTP version 1.1 */ 1705 sethttpver(config, CURL_HTTP_VERSION_1_1); 1706 break; 1707 case C_HTTP2: /* --http2 */ 1708 /* HTTP version 2.0 */ 1709 if(!feature_http2) 1710 return PARAM_LIBCURL_DOESNT_SUPPORT; 1711 sethttpver(config, CURL_HTTP_VERSION_2_0); 1712 break; 1713 case C_HTTP2_PRIOR_KNOWLEDGE: /* --http2-prior-knowledge */ 1714 /* HTTP version 2.0 over clean TCP */ 1715 if(!feature_http2) 1716 return PARAM_LIBCURL_DOESNT_SUPPORT; 1717 sethttpver(config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); 1718 break; 1719 case C_HTTP3: /* --http3: */ 1720 /* Try HTTP/3, allow fallback */ 1721 if(!feature_http3) 1722 return PARAM_LIBCURL_DOESNT_SUPPORT; 1723 else 1724 sethttpver(config, CURL_HTTP_VERSION_3); 1725 break; 1726 case C_HTTP3_ONLY: /* --http3-only */ 1727 /* Try HTTP/3 without fallback */ 1728 if(!feature_http3) 1729 return PARAM_LIBCURL_DOESNT_SUPPORT; 1730 else 1731 sethttpver(config, CURL_HTTP_VERSION_3ONLY); 1732 break; 1733 case C_TLSV1: /* --tlsv1 */ 1734 config->ssl_version = CURL_SSLVERSION_TLSv1; 1735 break; 1736 case C_TLSV1_0: /* --tlsv1.0 */ 1737 config->ssl_version = CURL_SSLVERSION_TLSv1_0; 1738 break; 1739 case C_TLSV1_1: /* --tlsv1.1 */ 1740 config->ssl_version = CURL_SSLVERSION_TLSv1_1; 1741 break; 1742 case C_TLSV1_2: /* --tlsv1.2 */ 1743 config->ssl_version = CURL_SSLVERSION_TLSv1_2; 1744 break; 1745 case C_TLSV1_3: /* --tlsv1.3 */ 1746 config->ssl_version = CURL_SSLVERSION_TLSv1_3; 1747 break; 1748 case C_IPV4: /* --ipv4 */ 1749 config->ip_version = CURL_IPRESOLVE_V4; 1750 break; 1751 case C_IPV6: /* --ipv6 */ 1752 config->ip_version = CURL_IPRESOLVE_V6; 1753 break; 1754 case C_NEXT: /* --next */ 1755 return PARAM_NEXT_OPERATION; 1756 case C_PROXY_TLSV1: /* --proxy-tlsv1 */ 1757 /* TLS version 1 for proxy */ 1758 config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; 1759 break; 1760 } 1761 return PARAM_OK; 1762 } 1763 1764 /* opt_bool is the function that handles boolean options */ 1765 static ParameterError opt_bool(struct OperationConfig *config, 1766 const struct LongShort *a, 1767 bool toggle) 1768 { 1769 struct GlobalConfig *global = config->global; 1770 switch(a->cmd) { 1771 case C_ALPN: /* --alpn */ 1772 config->noalpn = !toggle; 1773 break; 1774 case C_DISABLE_EPSV: /* --disable-epsv */ 1775 config->disable_epsv = toggle; 1776 break; 1777 case C_DISALLOW_USERNAME_IN_URL: /* --disallow-username-in-url */ 1778 config->disallow_username_in_url = toggle; 1779 break; 1780 case C_EPSV: /* --epsv */ 1781 config->disable_epsv = !toggle; 1782 break; 1783 case C_COMPRESSED: /* --compressed */ 1784 if(toggle && !(feature_libz || feature_brotli || feature_zstd)) 1785 return PARAM_LIBCURL_DOESNT_SUPPORT; 1786 else 1787 config->encoding = toggle; 1788 break; 1789 case C_TR_ENCODING: /* --tr-encoding */ 1790 config->tr_encoding = toggle; 1791 break; 1792 case C_DIGEST: /* --digest */ 1793 togglebit(toggle, &config->authtype, CURLAUTH_DIGEST); 1794 break; 1795 case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */ 1796 config->ftp_create_dirs = toggle; 1797 break; 1798 case C_CREATE_DIRS: /* --create-dirs */ 1799 config->create_dirs = toggle; 1800 break; 1801 case C_PROXY_NTLM: /* --proxy-ntlm */ 1802 if(!feature_ntlm) 1803 return PARAM_LIBCURL_DOESNT_SUPPORT; 1804 else 1805 config->proxyntlm = toggle; 1806 break; 1807 case C_CRLF: /* --crlf */ 1808 config->crlf = toggle; 1809 break; 1810 case C_HAPROXY_PROTOCOL: /* --haproxy-protocol */ 1811 config->haproxy_protocol = toggle; 1812 break; 1813 case C_NEGOTIATE: /* --negotiate */ 1814 if(!feature_spnego && toggle) 1815 return PARAM_LIBCURL_DOESNT_SUPPORT; 1816 togglebit(toggle, &config->authtype, CURLAUTH_NEGOTIATE); 1817 break; 1818 case C_NTLM: /* --ntlm */ 1819 if(!feature_ntlm && toggle) 1820 return PARAM_LIBCURL_DOESNT_SUPPORT; 1821 togglebit(toggle, &config->authtype, CURLAUTH_NTLM); 1822 break; 1823 case C_BASIC: /* --basic */ 1824 togglebit(toggle, &config->authtype, CURLAUTH_BASIC); 1825 break; 1826 #ifdef USE_WATT32 1827 case C_WDEBUG: /* --wdebug */ 1828 dbug_init(); 1829 break; 1830 #endif 1831 case C_DISABLE_EPRT: /* --disable-eprt */ 1832 config->disable_eprt = toggle; 1833 break; 1834 case C_EPRT: /* --eprt */ 1835 config->disable_eprt = !toggle; 1836 break; 1837 case C_XATTR: /* --xattr */ 1838 config->xattr = toggle; 1839 break; 1840 case C_FTP_SSL: /* --ftp-ssl */ 1841 case C_SSL: /* --ssl */ 1842 config->ftp_ssl = toggle; 1843 if(config->ftp_ssl) 1844 warnf(global, "--%s is an insecure option, consider --ssl-reqd instead", 1845 a->lname); 1846 break; 1847 case C_FTP_SSL_CCC: /* --ftp-ssl-ccc */ 1848 config->ftp_ssl_ccc = toggle; 1849 if(!config->ftp_ssl_ccc_mode) 1850 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; 1851 break; 1852 case C_TCP_NODELAY: /* --tcp-nodelay */ 1853 config->tcp_nodelay = toggle; 1854 break; 1855 case C_PROXY_DIGEST: /* --proxy-digest */ 1856 config->proxydigest = toggle; 1857 break; 1858 case C_PROXY_BASIC: /* --proxy-basic */ 1859 config->proxybasic = toggle; 1860 break; 1861 case C_RETRY_CONNREFUSED: /* --retry-connrefused */ 1862 config->retry_connrefused = toggle; 1863 break; 1864 case C_RETRY_ALL_ERRORS: /* --retry-all-errors */ 1865 config->retry_all_errors = toggle; 1866 break; 1867 case C_PROXY_NEGOTIATE: /* --proxy-negotiate */ 1868 if(!feature_spnego) 1869 return PARAM_LIBCURL_DOESNT_SUPPORT; 1870 else 1871 config->proxynegotiate = toggle; 1872 break; 1873 case C_FORM_ESCAPE: /* --form-escape */ 1874 togglebit(toggle, &config->mime_options, CURLMIMEOPT_FORMESCAPE); 1875 break; 1876 case C_PROXY_ANYAUTH: /* --proxy-anyauth */ 1877 config->proxyanyauth = toggle; 1878 break; 1879 case C_TRACE_TIME: /* --trace-time */ 1880 global->tracetime = toggle; 1881 break; 1882 case C_IGNORE_CONTENT_LENGTH: /* --ignore-content-length */ 1883 config->ignorecl = toggle; 1884 break; 1885 case C_FTP_SKIP_PASV_IP: /* --ftp-skip-pasv-ip */ 1886 config->ftp_skip_ip = toggle; 1887 break; 1888 case C_FTP_SSL_REQD: /* --ftp-ssl-reqd */ 1889 case C_SSL_REQD: /* --ssl-reqd */ 1890 config->ftp_ssl_reqd = toggle; 1891 break; 1892 case C_SESSIONID: /* --sessionid */ 1893 config->disable_sessionid = !toggle; 1894 break; 1895 case C_FTP_SSL_CONTROL: /* --ftp-ssl-control */ 1896 config->ftp_ssl_control = toggle; 1897 break; 1898 case C_RAW: /* --raw */ 1899 config->raw = toggle; 1900 break; 1901 case C_KEEPALIVE: /* --keepalive */ 1902 config->nokeepalive = !toggle; 1903 break; 1904 case C_POST301: /* --post301 */ 1905 config->post301 = toggle; 1906 break; 1907 case C_POST302: /* --post302 */ 1908 config->post302 = toggle; 1909 break; 1910 case C_POST303: /* --post303 */ 1911 config->post303 = toggle; 1912 break; 1913 case C_SOCKS5_GSSAPI_NEC: /* --socks5-gssapi-nec */ 1914 config->socks5_gssapi_nec = toggle; 1915 break; 1916 case C_FTP_PRET: /* --ftp-pret */ 1917 config->ftp_pret = toggle; 1918 break; 1919 case C_SASL_IR: /* --sasl-ir */ 1920 config->sasl_ir = toggle; 1921 break; 1922 #ifdef DEBUGBUILD 1923 case C_TEST_DUPHANDLE: /* --test-duphandle */ 1924 global->test_duphandle = toggle; 1925 break; 1926 case C_TEST_EVENT: /* --test-event */ 1927 global->test_event_based = toggle; 1928 break; 1929 #endif 1930 case C_PATH_AS_IS: /* --path-as-is */ 1931 config->path_as_is = toggle; 1932 break; 1933 case C_TFTP_NO_OPTIONS: /* --tftp-no-options */ 1934 config->tftp_no_options = toggle; 1935 break; 1936 case C_TLS_EARLYDATA: /* --tls-earlydata */ 1937 config->ssl_allow_earlydata = toggle; 1938 break; 1939 case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */ 1940 config->suppress_connect_headers = toggle; 1941 break; 1942 case C_COMPRESSED_SSH: /* --compressed-ssh */ 1943 config->ssh_compression = toggle; 1944 break; 1945 case C_TRACE_IDS: /* --trace-ids */ 1946 global->traceids = toggle; 1947 break; 1948 case C_PROGRESS_METER: /* --progress-meter */ 1949 global->noprogress = !toggle; 1950 break; 1951 case C_PROGRESS_BAR: /* --progress-bar */ 1952 global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS; 1953 break; 1954 case C_HTTP0_9: /* --http0.9 */ 1955 config->http09_allowed = toggle; 1956 break; 1957 case C_PROXY_HTTP2: /* --proxy-http2 */ 1958 if(!feature_httpsproxy || !feature_http2) 1959 return PARAM_LIBCURL_DOESNT_SUPPORT; 1960 1961 config->proxyver = toggle ? CURLPROXY_HTTPS2 : CURLPROXY_HTTPS; 1962 break; 1963 case C_APPEND: /* --append */ 1964 config->ftp_append = toggle; 1965 break; 1966 case C_USE_ASCII: /* --use-ascii */ 1967 config->use_ascii = toggle; 1968 break; 1969 case C_CA_NATIVE: /* --ca-native */ 1970 config->native_ca_store = toggle; 1971 break; 1972 case C_PROXY_CA_NATIVE: /* --proxy-ca-native */ 1973 config->proxy_native_ca_store = toggle; 1974 break; 1975 case C_SSL_ALLOW_BEAST: /* --ssl-allow-beast */ 1976 config->ssl_allow_beast = toggle; 1977 break; 1978 case C_SSL_AUTO_CLIENT_CERT: /* --ssl-auto-client-cert */ 1979 config->ssl_auto_client_cert = toggle; 1980 break; 1981 case C_PROXY_SSL_AUTO_CLIENT_CERT: /* --proxy-ssl-auto-client-cert */ 1982 config->proxy_ssl_auto_client_cert = toggle; 1983 break; 1984 case C_CERT_STATUS: /* --cert-status */ 1985 config->verifystatus = toggle; 1986 break; 1987 case C_DOH_CERT_STATUS: /* --doh-cert-status */ 1988 config->doh_verifystatus = toggle; 1989 break; 1990 case C_FALSE_START: /* --false-start */ 1991 opt_depr(global, a); 1992 break; 1993 case C_SSL_NO_REVOKE: /* --ssl-no-revoke */ 1994 config->ssl_no_revoke = toggle; 1995 break; 1996 case C_SSL_REVOKE_BEST_EFFORT: /* --ssl-revoke-best-effort */ 1997 config->ssl_revoke_best_effort = toggle; 1998 break; 1999 case C_TCP_FASTOPEN: /* --tcp-fastopen */ 2000 config->tcp_fastopen = toggle; 2001 break; 2002 case C_PROXY_SSL_ALLOW_BEAST: /* --proxy-ssl-allow-beast */ 2003 config->proxy_ssl_allow_beast = toggle; 2004 break; 2005 case C_PROXY_INSECURE: /* --proxy-insecure */ 2006 config->proxy_insecure_ok = toggle; 2007 break; 2008 case C_SOCKS5_BASIC: /* --socks5-basic */ 2009 togglebit(toggle, &config->socks5_auth, CURLAUTH_BASIC); 2010 break; 2011 case C_SOCKS5_GSSAPI: /* --socks5-gssapi */ 2012 togglebit(toggle, &config->socks5_auth, CURLAUTH_GSSAPI); 2013 break; 2014 case C_FAIL_EARLY: /* --fail-early */ 2015 global->fail_early = toggle; 2016 break; 2017 case C_STYLED_OUTPUT: /* --styled-output */ 2018 global->styled_output = toggle; 2019 break; 2020 case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */ 2021 config->mail_rcpt_allowfails = toggle; 2022 break; 2023 case C_FAIL_WITH_BODY: /* --fail-with-body */ 2024 config->failwithbody = toggle; 2025 if(config->failonerror && config->failwithbody) { 2026 errorf(config->global, "You must select either --fail or " 2027 "--fail-with-body, not both."); 2028 return PARAM_BAD_USE; 2029 } 2030 break; 2031 case C_REMOVE_ON_ERROR: /* --remove-on-error */ 2032 if(config->use_resume && toggle) { 2033 errorf(config->global, 2034 "--continue-at is mutually exclusive with --remove-on-error"); 2035 return PARAM_BAD_USE; 2036 } 2037 config->rm_partial = toggle; 2038 break; 2039 case C_FAIL: /* --fail */ 2040 config->failonerror = toggle; 2041 if(config->failonerror && config->failwithbody) { 2042 errorf(config->global, "You must select either --fail or " 2043 "--fail-with-body, not both."); 2044 return PARAM_BAD_USE; 2045 } 2046 break; 2047 case C_GLOBOFF: /* --globoff */ 2048 config->globoff = toggle; 2049 break; 2050 case C_GET: /* --get */ 2051 config->use_httpget = toggle; 2052 break; 2053 case C_INCLUDE: /* --include */ 2054 case C_SHOW_HEADERS: /* --show-headers */ 2055 config->show_headers = toggle; 2056 break; 2057 case C_JUNK_SESSION_COOKIES: /* --junk-session-cookies */ 2058 config->cookiesession = toggle; 2059 break; 2060 case C_HEAD: /* --head */ 2061 config->no_body = toggle; 2062 config->show_headers = toggle; 2063 if(SetHTTPrequest(config, (config->no_body) ? TOOL_HTTPREQ_HEAD : 2064 TOOL_HTTPREQ_GET, &config->httpreq)) 2065 return PARAM_BAD_USE; 2066 break; 2067 case C_REMOTE_HEADER_NAME: /* --remote-header-name */ 2068 config->content_disposition = toggle; 2069 break; 2070 case C_INSECURE: /* --insecure */ 2071 config->insecure_ok = toggle; 2072 break; 2073 case C_DOH_INSECURE: /* --doh-insecure */ 2074 config->doh_insecure_ok = toggle; 2075 break; 2076 case C_LIST_ONLY: /* --list-only */ 2077 config->dirlistonly = toggle; /* only list the names of the FTP dir */ 2078 break; 2079 case C_LOCATION_TRUSTED: /* --location-trusted */ 2080 config->unrestricted_auth = toggle; 2081 FALLTHROUGH(); 2082 case C_LOCATION: /* --location */ 2083 config->followlocation = toggle; /* Follow Location: HTTP headers */ 2084 break; 2085 case C_MANUAL: /* --manual */ 2086 if(toggle) /* --no-manual shows no manual... */ 2087 return PARAM_MANUAL_REQUESTED; 2088 break; 2089 case C_NETRC_OPTIONAL: /* --netrc-optional */ 2090 config->netrc_opt = toggle; 2091 break; 2092 case C_NETRC: /* --netrc */ 2093 config->netrc = toggle; 2094 break; 2095 case C_BUFFER: /* --buffer */ 2096 config->nobuffer = !toggle; 2097 break; 2098 case C_REMOTE_NAME_ALL: /* --remote-name-all */ 2099 config->remote_name_all = toggle; 2100 break; 2101 case C_CLOBBER: /* --clobber */ 2102 if(config->use_resume && !toggle) { 2103 errorf(config->global, 2104 "--continue-at is mutually exclusive with --no-clobber"); 2105 return PARAM_BAD_USE; 2106 } 2107 config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER; 2108 break; 2109 case C_REMOTE_NAME: /* --remote-name */ 2110 return parse_remote_name(config, toggle); 2111 break; 2112 case C_PROXYTUNNEL: /* --proxytunnel */ 2113 config->proxytunnel = toggle; 2114 break; 2115 case C_DISABLE: /* --disable */ 2116 /* if used first, already taken care of, we do it like this so we do not 2117 cause an error! */ 2118 break; 2119 case C_REMOTE_TIME: /* --remote-time */ 2120 config->remote_time = toggle; 2121 break; 2122 case C_SILENT: /* --silent */ 2123 global->silent = toggle; 2124 break; 2125 case C_SKIP_EXISTING: /* --skip-existing */ 2126 config->skip_existing = toggle; 2127 break; 2128 case C_SHOW_ERROR: /* --show-error */ 2129 global->showerror = toggle; 2130 break; 2131 case C_VERBOSE: /* --verbose */ 2132 return parse_verbose(global, toggle); 2133 break; 2134 case C_VERSION: /* --version */ 2135 if(toggle) /* --no-version yields no output! */ 2136 return PARAM_VERSION_INFO_REQUESTED; 2137 break; 2138 case C_PARALLEL: /* --parallel */ 2139 global->parallel = toggle; 2140 break; 2141 case C_PARALLEL_IMMEDIATE: /* --parallel-immediate */ 2142 global->parallel_connect = toggle; 2143 break; 2144 case C_MPTCP: /* --mptcp */ 2145 config->mptcp = toggle; 2146 break; 2147 default: 2148 return PARAM_OPTION_UNKNOWN; 2149 } 2150 return PARAM_OK; 2151 } 2152 2153 2154 /* opt_filestring handles string and file options */ 2155 static ParameterError opt_filestring(struct OperationConfig *config, 2156 const struct LongShort *a, 2157 const char *nextarg) 2158 { 2159 ParameterError err = PARAM_OK; 2160 curl_off_t value; 2161 struct GlobalConfig *global = config->global; 2162 static const char *redir_protos[] = { 2163 "http", 2164 "https", 2165 "ftp", 2166 "ftps", 2167 NULL 2168 }; 2169 if(!nextarg) 2170 nextarg = ""; 2171 2172 switch(a->cmd) { 2173 case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */ 2174 if(!curlinfo->ares_num) /* c-ares is needed for this */ 2175 return PARAM_LIBCURL_DOESNT_SUPPORT; 2176 /* addr in dot notation */ 2177 return getstr(&config->dns_ipv4_addr, nextarg, DENY_BLANK); 2178 2179 case C_DNS_IPV6_ADDR: /* --dns-ipv6-addr */ 2180 if(!curlinfo->ares_num) /* c-ares is needed for this */ 2181 return PARAM_LIBCURL_DOESNT_SUPPORT; 2182 /* addr in dot notation */ 2183 return getstr(&config->dns_ipv6_addr, nextarg, DENY_BLANK); 2184 2185 case C_OAUTH2_BEARER: /* --oauth2-bearer */ 2186 config->authtype |= CURLAUTH_BEARER; 2187 return getstr(&config->oauth_bearer, nextarg, DENY_BLANK); 2188 2189 case C_CONNECT_TIMEOUT: /* --connect-timeout */ 2190 return secs2ms(&config->connecttimeout_ms, nextarg); 2191 2192 case C_DOH_URL: /* --doh-url */ 2193 err = getstr(&config->doh_url, nextarg, ALLOW_BLANK); 2194 if(!err && config->doh_url && !config->doh_url[0]) 2195 /* if given a blank string, make it NULL again */ 2196 tool_safefree(config->doh_url); 2197 break; 2198 2199 case C_CIPHERS: /* -- ciphers */ 2200 err = getstr(&config->cipher_list, nextarg, DENY_BLANK); 2201 break; 2202 2203 case C_DNS_INTERFACE: /* --dns-interface */ 2204 if(!curlinfo->ares_num) /* c-ares is needed for this */ 2205 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2206 else 2207 /* interface name */ 2208 err = getstr(&config->dns_interface, nextarg, DENY_BLANK); 2209 break; 2210 case C_DNS_SERVERS: /* --dns-servers */ 2211 if(!curlinfo->ares_num) /* c-ares is needed for this */ 2212 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2213 else 2214 /* IP addrs of DNS servers */ 2215 err = getstr(&config->dns_servers, nextarg, DENY_BLANK); 2216 break; 2217 case C_TRACE: /* --trace */ 2218 err = getstr(&global->trace_dump, nextarg, DENY_BLANK); 2219 if(!err) { 2220 if(global->tracetype && (global->tracetype != TRACE_BIN)) 2221 warnf(global, "--trace overrides an earlier trace/verbose option"); 2222 global->tracetype = TRACE_BIN; 2223 } 2224 break; 2225 case C_TRACE_ASCII: /* --trace-ascii */ 2226 err = getstr(&global->trace_dump, nextarg, DENY_BLANK); 2227 if(!err) { 2228 if(global->tracetype && (global->tracetype != TRACE_ASCII)) 2229 warnf(global, 2230 "--trace-ascii overrides an earlier trace/verbose option"); 2231 global->tracetype = TRACE_ASCII; 2232 } 2233 break; 2234 case C_LIMIT_RATE: /* --limit-rate */ 2235 err = GetSizeParameter(global, nextarg, "rate", &value); 2236 if(!err) { 2237 config->recvpersecond = value; 2238 config->sendpersecond = value; 2239 } 2240 break; 2241 case C_RATE: 2242 err = set_rate(global, nextarg); 2243 break; 2244 case C_CREATE_FILE_MODE: /* --create-file-mode */ 2245 err = oct2nummax(&config->create_file_mode, nextarg, 0777); 2246 break; 2247 case C_MAX_REDIRS: /* --max-redirs */ 2248 /* specified max no of redirects (http(s)), this accepts -1 as a 2249 special condition */ 2250 err = str2num(&config->maxredirs, nextarg); 2251 if(!err && (config->maxredirs < -1)) 2252 err = PARAM_BAD_NUMERIC; 2253 break; 2254 #ifndef CURL_DISABLE_IPFS 2255 case C_IPFS_GATEWAY: /* --ipfs-gateway */ 2256 err = getstr(&config->ipfs_gateway, nextarg, DENY_BLANK); 2257 break; 2258 #endif /* !CURL_DISABLE_IPFS */ 2259 case C_AWS_SIGV4: /* --aws-sigv4 */ 2260 config->authtype |= CURLAUTH_AWS_SIGV4; 2261 err = getstr(&config->aws_sigv4, nextarg, ALLOW_BLANK); 2262 break; 2263 case C_STDERR: /* --stderr */ 2264 tool_set_stderr_file(global, nextarg); 2265 break; 2266 case C_INTERFACE: /* --interface */ 2267 /* interface */ 2268 err = getstr(&config->iface, nextarg, DENY_BLANK); 2269 break; 2270 case C_KRB: /* --krb */ 2271 /* kerberos level string */ 2272 if(!feature_spnego) 2273 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2274 else 2275 err = getstr(&config->krblevel, nextarg, DENY_BLANK); 2276 break; 2277 case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */ 2278 err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK); 2279 break; 2280 case C_MAX_FILESIZE: /* --max-filesize */ 2281 err = GetSizeParameter(global, nextarg, "max-filesize", &value); 2282 if(!err) 2283 config->max_filesize = value; 2284 break; 2285 case C_URL: /* --url */ 2286 err = parse_url(config, nextarg); 2287 break; 2288 case C_SOCKS5: /* --socks5 */ 2289 /* socks5 proxy to use, and resolves the name locally and passes on the 2290 resolved address */ 2291 err = getstr(&config->proxy, nextarg, DENY_BLANK); 2292 config->proxyver = CURLPROXY_SOCKS5; 2293 break; 2294 case C_SOCKS4: /* --socks4 */ 2295 err = getstr(&config->proxy, nextarg, DENY_BLANK); 2296 config->proxyver = CURLPROXY_SOCKS4; 2297 break; 2298 case C_SOCKS4A: /* --socks4a */ 2299 err = getstr(&config->proxy, nextarg, DENY_BLANK); 2300 config->proxyver = CURLPROXY_SOCKS4A; 2301 break; 2302 case C_SOCKS5_HOSTNAME: /* --socks5-hostname */ 2303 err = getstr(&config->proxy, nextarg, DENY_BLANK); 2304 config->proxyver = CURLPROXY_SOCKS5_HOSTNAME; 2305 break; 2306 case C_IP_TOS: { /* --ip-tos */ 2307 struct TOSEntry find; 2308 const struct TOSEntry *entry; 2309 find.name = nextarg; 2310 entry = bsearch(&find, tos_entries, 2311 CURL_ARRAYSIZE(tos_entries), 2312 sizeof(*tos_entries), find_tos); 2313 if(entry) 2314 config->ip_tos = entry->value; 2315 else /* numeric tos value */ 2316 err = str2unummax(&config->ip_tos, nextarg, 0xFF); 2317 break; 2318 } 2319 case C_VLAN_PRIORITY: /* --vlan-priority */ 2320 err = str2unummax(&config->vlan_priority, nextarg, 7); 2321 break; 2322 case C_RETRY: /* --retry */ 2323 err = str2unum(&config->req_retry, nextarg); 2324 break; 2325 case C_RETRY_DELAY: /* --retry-delay */ 2326 err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000); 2327 break; 2328 case C_RETRY_MAX_TIME: /* --retry-max-time */ 2329 err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000); 2330 break; 2331 case C_FTP_ACCOUNT: /* --ftp-account */ 2332 err = getstr(&config->ftp_account, nextarg, DENY_BLANK); 2333 break; 2334 case C_FTP_METHOD: /* --ftp-method */ 2335 config->ftp_filemethod = ftpfilemethod(config, nextarg); 2336 break; 2337 case C_LOCAL_PORT: /* --local-port */ 2338 err = parse_localport(config, nextarg); 2339 break; 2340 case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */ 2341 err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK); 2342 break; 2343 case C_LIBCURL: /* --libcurl */ 2344 #ifdef CURL_DISABLE_LIBCURL_OPTION 2345 warnf(global, 2346 "--libcurl option was disabled at build-time"); 2347 err = PARAM_OPTION_UNKNOWN; 2348 #else 2349 err = getstr(&global->libcurl, nextarg, DENY_BLANK); 2350 #endif 2351 break; 2352 case C_KEEPALIVE_TIME: /* --keepalive-time */ 2353 err = str2unum(&config->alivetime, nextarg); 2354 break; 2355 case C_KEEPALIVE_CNT: /* --keepalive-cnt */ 2356 err = str2unum(&config->alivecnt, nextarg); 2357 break; 2358 case C_NOPROXY: /* --noproxy */ 2359 /* This specifies the noproxy list */ 2360 err = getstr(&config->noproxy, nextarg, ALLOW_BLANK); 2361 break; 2362 case C_PROXY1_0: /* --proxy1.0 */ 2363 /* http 1.0 proxy */ 2364 err = getstr(&config->proxy, nextarg, DENY_BLANK); 2365 config->proxyver = CURLPROXY_HTTP_1_0; 2366 break; 2367 case C_TFTP_BLKSIZE: /* --tftp-blksize */ 2368 err = str2unum(&config->tftp_blksize, nextarg); 2369 break; 2370 case C_MAIL_FROM: /* --mail-from */ 2371 err = getstr(&config->mail_from, nextarg, DENY_BLANK); 2372 break; 2373 case C_MAIL_RCPT: /* --mail-rcpt */ 2374 /* append receiver to a list */ 2375 err = add2list(&config->mail_rcpt, nextarg); 2376 break; 2377 case C_PROTO: /* --proto */ 2378 config->proto_present = TRUE; 2379 err = proto2num(config, built_in_protos, &config->proto_str, nextarg); 2380 break; 2381 case C_PROTO_REDIR: /* --proto-redir */ 2382 config->proto_redir_present = TRUE; 2383 if(proto2num(config, redir_protos, &config->proto_redir_str, 2384 nextarg)) 2385 err = PARAM_BAD_USE; 2386 break; 2387 case C_RESOLVE: /* --resolve */ 2388 err = add2list(&config->resolve, nextarg); 2389 break; 2390 case C_DELEGATION: /* --delegation */ 2391 config->gssapi_delegation = delegation(config, nextarg); 2392 break; 2393 case C_MAIL_AUTH: /* --mail-auth */ 2394 err = getstr(&config->mail_auth, nextarg, DENY_BLANK); 2395 break; 2396 case C_SASL_AUTHZID: /* --sasl-authzid */ 2397 err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK); 2398 break; 2399 case C_UNIX_SOCKET: /* --unix-socket */ 2400 config->abstract_unix_socket = FALSE; 2401 err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); 2402 break; 2403 case C_PROXY_SERVICE_NAME: /* --proxy-service-name */ 2404 err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK); 2405 break; 2406 case C_SERVICE_NAME: /* --service-name */ 2407 err = getstr(&config->service_name, nextarg, DENY_BLANK); 2408 break; 2409 case C_PROTO_DEFAULT: /* --proto-default */ 2410 err = getstr(&config->proto_default, nextarg, DENY_BLANK); 2411 if(!err) 2412 err = check_protocol(config->proto_default); 2413 break; 2414 case C_EXPECT100_TIMEOUT: /* --expect100-timeout */ 2415 err = secs2ms(&config->expect100timeout_ms, nextarg); 2416 break; 2417 case C_CONNECT_TO: /* --connect-to */ 2418 err = add2list(&config->connect_to, nextarg); 2419 break; 2420 case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ 2421 config->abstract_unix_socket = TRUE; 2422 err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); 2423 break; 2424 case C_TLS_MAX: /* --tls-max */ 2425 err = str2tls_max(&config->ssl_version_max, nextarg); 2426 break; 2427 case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */ 2428 err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); 2429 /* 0 is a valid value for this timeout */ 2430 break; 2431 case C_TRACE_CONFIG: /* --trace-config */ 2432 if(set_trace_config(global, nextarg)) 2433 err = PARAM_NO_MEM; 2434 break; 2435 case C_VARIABLE: /* --variable */ 2436 err = setvariable(global, nextarg); 2437 break; 2438 case C_TLS13_CIPHERS: /* --tls13-ciphers */ 2439 err = getstr(&config->cipher13_list, nextarg, DENY_BLANK); 2440 break; 2441 case C_PROXY_TLS13_CIPHERS: /* --proxy-tls13-ciphers */ 2442 err = getstr(&config->proxy_cipher13_list, nextarg, DENY_BLANK); 2443 break; 2444 case C_USER_AGENT: /* --user-agent */ 2445 err = getstr(&config->useragent, nextarg, ALLOW_BLANK); 2446 break; 2447 case C_ALT_SVC: /* --alt-svc */ 2448 if(!feature_altsvc) 2449 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2450 else 2451 err = getstr(&config->altsvc, nextarg, ALLOW_BLANK); 2452 break; 2453 case C_HSTS: /* --hsts */ 2454 if(!feature_hsts) 2455 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2456 else 2457 err = getstr(&config->hsts, nextarg, ALLOW_BLANK); 2458 break; 2459 case C_COOKIE: /* --cookie */ 2460 if(strchr(nextarg, '=')) { 2461 /* A cookie string must have a =-letter */ 2462 err = add2list(&config->cookies, nextarg); 2463 break; 2464 } 2465 else { 2466 /* We have a cookie file to read from! */ 2467 err = add2list(&config->cookiefiles, nextarg); 2468 } 2469 break; 2470 case C_COOKIE_JAR: /* --cookie-jar */ 2471 err = getstr(&config->cookiejar, nextarg, DENY_BLANK); 2472 break; 2473 case C_CONTINUE_AT: /* --continue-at */ 2474 err = parse_continue_at(config, nextarg); 2475 break; 2476 case C_DATA: /* --data */ 2477 case C_DATA_ASCII: /* --data-ascii */ 2478 case C_DATA_BINARY: /* --data-binary */ 2479 case C_DATA_URLENCODE: /* --data-urlencode */ 2480 case C_JSON: /* --json */ 2481 case C_DATA_RAW: /* --data-raw */ 2482 err = set_data((cmdline_t)a->cmd, nextarg, config); 2483 break; 2484 case C_URL_QUERY: /* --url-query */ 2485 err = url_query(nextarg, config); 2486 break; 2487 case C_DUMP_HEADER: /* --dump-header */ 2488 err = getstr(&config->headerfile, nextarg, DENY_BLANK); 2489 break; 2490 case C_REFERER: { /* --referer */ 2491 size_t len = strlen(nextarg); 2492 /* does it end with ;auto ? */ 2493 if(len >= 5 && !strcmp(";auto", &nextarg[len - 5])) { 2494 /* Automatic referer requested, this may be combined with a set initial 2495 one */ 2496 config->autoreferer = TRUE; 2497 len -= 5; 2498 } 2499 else 2500 config->autoreferer = FALSE; 2501 2502 if(len) 2503 err = getstrn(&config->referer, nextarg, len, ALLOW_BLANK); 2504 else 2505 tool_safefree(config->referer); 2506 } 2507 break; 2508 case C_CERT: /* --cert */ 2509 GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); 2510 break; 2511 case C_CACERT: /* --cacert */ 2512 err = getstr(&config->cacert, nextarg, DENY_BLANK); 2513 break; 2514 case C_CERT_TYPE: /* --cert-type */ 2515 err = getstr(&config->cert_type, nextarg, DENY_BLANK); 2516 break; 2517 case C_KEY: /* --key */ 2518 err = getstr(&config->key, nextarg, DENY_BLANK); 2519 break; 2520 case C_KEY_TYPE: /* --key-type */ 2521 err = getstr(&config->key_type, nextarg, DENY_BLANK); 2522 break; 2523 case C_PASS: /* --pass */ 2524 err = getstr(&config->key_passwd, nextarg, DENY_BLANK); 2525 break; 2526 case C_ENGINE: /* --engine */ 2527 err = getstr(&config->engine, nextarg, DENY_BLANK); 2528 if(!err && 2529 config->engine && !strcmp(config->engine, "list")) { 2530 err = PARAM_ENGINES_REQUESTED; 2531 } 2532 break; 2533 case C_ECH: /* --ech */ 2534 err = parse_ech(config, nextarg); 2535 break; 2536 case C_CAPATH: /* --capath */ 2537 err = getstr(&config->capath, nextarg, DENY_BLANK); 2538 break; 2539 case C_PUBKEY: /* --pubkey */ 2540 err = getstr(&config->pubkey, nextarg, DENY_BLANK); 2541 break; 2542 case C_HOSTPUBMD5: /* --hostpubmd5 */ 2543 err = getstr(&config->hostpubmd5, nextarg, DENY_BLANK); 2544 if(!err) { 2545 if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) 2546 err = PARAM_BAD_USE; 2547 } 2548 break; 2549 case C_HOSTPUBSHA256: /* --hostpubsha256 */ 2550 if(!feature_libssh2) 2551 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2552 else 2553 err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK); 2554 break; 2555 case C_CRLFILE: /* --crlfile */ 2556 err = getstr(&config->crlfile, nextarg, DENY_BLANK); 2557 break; 2558 case C_TLSUSER: /* --tlsuser */ 2559 if(!feature_tls_srp) 2560 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2561 else 2562 err = getstr(&config->tls_username, nextarg, DENY_BLANK); 2563 break; 2564 case C_TLSPASSWORD: /* --tlspassword */ 2565 if(!feature_tls_srp) 2566 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2567 else 2568 err = getstr(&config->tls_password, nextarg, ALLOW_BLANK); 2569 break; 2570 case C_TLSAUTHTYPE: /* --tlsauthtype */ 2571 if(!feature_tls_srp) 2572 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2573 else { 2574 err = getstr(&config->tls_authtype, nextarg, DENY_BLANK); 2575 if(!err && config->tls_authtype && strcmp(config->tls_authtype, "SRP")) 2576 err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ 2577 } 2578 break; 2579 case C_PINNEDPUBKEY: /* --pinnedpubkey */ 2580 err = getstr(&config->pinnedpubkey, nextarg, DENY_BLANK); 2581 break; 2582 case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */ 2583 err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK); 2584 break; 2585 case C_SSL_SESSIONS: /* --ssl-sessions */ 2586 if(feature_ssls_export) 2587 err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); 2588 else 2589 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2590 break; 2591 case C_PROXY_TLSUSER: /* --proxy-tlsuser */ 2592 if(!feature_tls_srp) 2593 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2594 else 2595 err = getstr(&config->proxy_tls_username, nextarg, ALLOW_BLANK); 2596 break; 2597 case C_PROXY_TLSPASSWORD: /* --proxy-tlspassword */ 2598 if(!feature_tls_srp) 2599 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2600 else 2601 err = getstr(&config->proxy_tls_password, nextarg, DENY_BLANK); 2602 break; 2603 case C_PROXY_TLSAUTHTYPE: /* --proxy-tlsauthtype */ 2604 if(!feature_tls_srp) 2605 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2606 else { 2607 err = getstr(&config->proxy_tls_authtype, nextarg, DENY_BLANK); 2608 if(!err && config->proxy_tls_authtype && 2609 strcmp(config->proxy_tls_authtype, "SRP")) 2610 err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ 2611 } 2612 break; 2613 case C_PROXY_CERT: /* --proxy-cert */ 2614 GetFileAndPassword(nextarg, &config->proxy_cert, 2615 &config->proxy_key_passwd); 2616 break; 2617 case C_PROXY_CERT_TYPE: /* --proxy-cert-type */ 2618 err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK); 2619 break; 2620 case C_PROXY_KEY: /* --proxy-key */ 2621 err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); 2622 break; 2623 case C_PROXY_KEY_TYPE: /* --proxy-key-type */ 2624 err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK); 2625 break; 2626 case C_PROXY_PASS: /* --proxy-pass */ 2627 err = getstr(&config->proxy_key_passwd, nextarg, ALLOW_BLANK); 2628 break; 2629 case C_PROXY_CIPHERS: /* --proxy-ciphers */ 2630 err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK); 2631 break; 2632 case C_PROXY_CRLFILE: /* --proxy-crlfile */ 2633 err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); 2634 break; 2635 case C_LOGIN_OPTIONS: /* --login-options */ 2636 err = getstr(&config->login_options, nextarg, ALLOW_BLANK); 2637 break; 2638 case C_PROXY_CACERT: /* --proxy-cacert */ 2639 err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); 2640 break; 2641 case C_PROXY_CAPATH: /* --proxy-capath */ 2642 err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); 2643 break; 2644 case C_ETAG_SAVE: /* --etag-save */ 2645 if(config->num_urls > 1) { 2646 errorf(global, "The etag options only work on a single URL"); 2647 err = PARAM_BAD_USE; 2648 } 2649 else 2650 err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); 2651 break; 2652 case C_ETAG_COMPARE: /* --etag-compare */ 2653 if(config->num_urls > 1) { 2654 errorf(global, "The etag options only work on a single URL"); 2655 err = PARAM_BAD_USE; 2656 } 2657 else 2658 err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); 2659 break; 2660 case C_CURVES: /* --curves */ 2661 err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK); 2662 break; 2663 case C_SIGNATURE_ALGORITHMS: /* --sigalgs */ 2664 err = getstr(&config->ssl_signature_algorithms, nextarg, DENY_BLANK); 2665 break; 2666 case C_FORM: /* --form */ 2667 case C_FORM_STRING: /* --form-string */ 2668 /* "form data" simulation, this is a little advanced so lets do our best 2669 to sort this out slowly and carefully */ 2670 if(formparse(config, 2671 nextarg, 2672 &config->mimeroot, 2673 &config->mimecurrent, 2674 (a->cmd == C_FORM_STRING))) /* literal string */ 2675 err = PARAM_BAD_USE; 2676 else if(SetHTTPrequest(config, TOOL_HTTPREQ_MIMEPOST, &config->httpreq)) 2677 err = PARAM_BAD_USE; 2678 break; 2679 case C_REQUEST_TARGET: /* --request-target */ 2680 err = getstr(&config->request_target, nextarg, DENY_BLANK); 2681 break; 2682 case C_HEADER: /* --header */ 2683 case C_PROXY_HEADER: /* --proxy-header */ 2684 err = parse_header(config, (cmdline_t)a->cmd, nextarg); 2685 break; 2686 case C_CONFIG: /* --config */ 2687 if(parseconfig(nextarg, global)) { 2688 errorf(global, "cannot read config from '%s'", nextarg); 2689 err = PARAM_READ_ERROR; 2690 } 2691 break; 2692 case C_MAX_TIME: /* --max-time */ 2693 /* specified max time */ 2694 err = secs2ms(&config->timeout_ms, nextarg); 2695 break; 2696 case C_NETRC_FILE: /* --netrc-file */ 2697 err = getstr(&config->netrc_file, nextarg, DENY_BLANK); 2698 break; 2699 case C_OUTPUT_DIR: /* --output-dir */ 2700 err = getstr(&config->output_dir, nextarg, DENY_BLANK); 2701 break; 2702 case C_OUTPUT: /* --output */ 2703 err = parse_output(config, nextarg); 2704 break; 2705 case C_FTP_PORT: /* --ftp-port */ 2706 /* This makes the FTP sessions use PORT instead of PASV */ 2707 /* use <eth0> or <192.168.10.10> style addresses. Anything except 2708 this will make us try to get the "default" address. 2709 NOTE: this is a changed behavior since the released 4.1! 2710 */ 2711 err = getstr(&config->ftpport, nextarg, DENY_BLANK); 2712 break; 2713 case C_FTP_SSL_CCC_MODE: /* --ftp-ssl-ccc-mode */ 2714 config->ftp_ssl_ccc = TRUE; 2715 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); 2716 break; 2717 case C_QUOTE: /* --quote */ 2718 err = parse_quote(config, nextarg); 2719 break; 2720 case C_RANGE: /* --range */ 2721 err = parse_range(config, nextarg); 2722 break; 2723 case C_TELNET_OPTION: /* --telnet-option */ 2724 /* Telnet options */ 2725 err = add2list(&config->telnet_options, nextarg); 2726 break; 2727 case C_UPLOAD_FILE: /* --upload-file */ 2728 err = parse_upload_file(config, nextarg); 2729 break; 2730 case C_USER: /* --user */ 2731 /* user:password */ 2732 err = getstr(&config->userpwd, nextarg, ALLOW_BLANK); 2733 break; 2734 case C_PROXY_USER: /* --proxy-user */ 2735 /* Proxy user:password */ 2736 err = getstr(&config->proxyuserpwd, nextarg, ALLOW_BLANK); 2737 break; 2738 case C_WRITE_OUT: /* --write-out */ 2739 err = parse_writeout(config, nextarg); 2740 break; 2741 case C_PREPROXY: /* --preproxy */ 2742 err = getstr(&config->preproxy, nextarg, DENY_BLANK); 2743 break; 2744 case C_PROXY: /* --proxy */ 2745 /* --proxy */ 2746 err = getstr(&config->proxy, nextarg, ALLOW_BLANK); 2747 if(config->proxyver != CURLPROXY_HTTPS2) 2748 config->proxyver = CURLPROXY_HTTP; 2749 break; 2750 case C_REQUEST: /* --request */ 2751 /* set custom request */ 2752 err = getstr(&config->customrequest, nextarg, DENY_BLANK); 2753 break; 2754 case C_SPEED_TIME: /* --speed-time */ 2755 /* low speed time */ 2756 err = str2unum(&config->low_speed_time, nextarg); 2757 if(!err && !config->low_speed_limit) 2758 config->low_speed_limit = 1; 2759 break; 2760 case C_SPEED_LIMIT: /* --speed-limit */ 2761 /* low speed limit */ 2762 err = str2unum(&config->low_speed_limit, nextarg); 2763 if(!err && !config->low_speed_time) 2764 config->low_speed_time = 30; 2765 break; 2766 case C_PARALLEL_MAX: { /* --parallel-max */ 2767 long val; 2768 err = str2unum(&val, nextarg); 2769 if(err) 2770 break; 2771 if(val > MAX_PARALLEL) 2772 global->parallel_max = MAX_PARALLEL; 2773 else if(val < 1) 2774 global->parallel_max = PARALLEL_DEFAULT; 2775 else 2776 global->parallel_max = (unsigned short)val; 2777 break; 2778 } 2779 case C_TIME_COND: /* --time-cond */ 2780 err = parse_time_cond(config, nextarg); 2781 break; 2782 case C_UPLOAD_FLAGS: /* --upload-flags */ 2783 err = parse_upload_flags(config, nextarg); 2784 break; 2785 } 2786 return err; 2787 } 2788 2789 ParameterError getparameter(const char *flag, /* f or -long-flag */ 2790 const char *nextarg, /* NULL if unset */ 2791 bool *usedarg, /* set to TRUE if the arg 2792 has been used */ 2793 struct OperationConfig *config) 2794 { 2795 const char *parse = NULL; 2796 bool longopt = FALSE; 2797 bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ 2798 ParameterError err = PARAM_OK; 2799 bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled 2800 by using --OPTION or --no-OPTION */ 2801 bool nextalloc = FALSE; /* if nextarg is allocated */ 2802 const struct LongShort *a = NULL; 2803 struct GlobalConfig *global = config->global; 2804 verbose_nopts = 0; /* options processed in `flag`*/ 2805 2806 *usedarg = FALSE; /* default is that we do not use the arg */ 2807 2808 if(('-' != flag[0]) || ('-' == flag[1])) { 2809 /* this should be a long name */ 2810 const char *word = ('-' == flag[0]) ? flag + 2 : flag; 2811 bool noflagged = FALSE; 2812 bool expand = FALSE; 2813 2814 if(!strncmp(word, "no-", 3)) { 2815 /* disable this option but ignore the "no-" part when looking for it */ 2816 word += 3; 2817 toggle = FALSE; 2818 noflagged = TRUE; 2819 } 2820 else if(!strncmp(word, "expand-", 7)) { 2821 /* variable expansions is to be done on the argument */ 2822 word += 7; 2823 expand = TRUE; 2824 } 2825 2826 a = findlongopt(word); 2827 if(a) { 2828 longopt = TRUE; 2829 } 2830 else { 2831 err = PARAM_OPTION_UNKNOWN; 2832 goto error; 2833 } 2834 if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) { 2835 /* --no- prefixed an option that is not boolean! */ 2836 err = PARAM_NO_PREFIX; 2837 goto error; 2838 } 2839 else if(expand && nextarg) { 2840 struct dynbuf nbuf; 2841 bool replaced; 2842 2843 if((ARGTYPE(a->desc) != ARG_STRG) && 2844 (ARGTYPE(a->desc) != ARG_FILE)) { 2845 /* --expand on an option that is not a string or a filename */ 2846 err = PARAM_EXPAND_ERROR; 2847 goto error; 2848 } 2849 err = varexpand(global, nextarg, &nbuf, &replaced); 2850 if(err) { 2851 curlx_dyn_free(&nbuf); 2852 goto error; 2853 } 2854 if(replaced) { 2855 nextarg = curlx_dyn_ptr(&nbuf); 2856 nextalloc = TRUE; 2857 } 2858 } 2859 } 2860 else { 2861 flag++; /* prefixed with one dash, pass it */ 2862 parse = flag; 2863 } 2864 2865 do { 2866 /* we can loop here if we have multiple single-letters */ 2867 if(!longopt) { 2868 a = findshortopt(*parse); 2869 if(!a) { 2870 err = PARAM_OPTION_UNKNOWN; 2871 break; 2872 } 2873 toggle = !(a->desc & ARG_NO); 2874 } 2875 if((a->desc & ARG_TLS) && !feature_ssl) { 2876 err = PARAM_LIBCURL_DOESNT_SUPPORT; 2877 break; 2878 } 2879 else if(ARGTYPE(a->desc) >= ARG_STRG) { 2880 /* this option requires an extra parameter */ 2881 if(!longopt && parse[1]) { 2882 nextarg = &parse[1]; /* this is the actual extra parameter */ 2883 singleopt = TRUE; /* do not loop anymore after this */ 2884 } 2885 else if(a->cmd == C_HELP) { 2886 /* --help is special */ 2887 tool_help((nextarg && *nextarg) ? nextarg : NULL); 2888 err = PARAM_HELP_REQUESTED; 2889 break; 2890 } 2891 else if(!nextarg) { 2892 err = PARAM_REQUIRES_PARAMETER; 2893 break; 2894 } 2895 else { 2896 *usedarg = TRUE; /* mark it as used */ 2897 } 2898 if(a->desc & ARG_DEPR) { 2899 opt_depr(global, a); 2900 break; 2901 } 2902 2903 if((ARGTYPE(a->desc) == ARG_FILE) && 2904 (nextarg[0] == '-') && nextarg[1]) { 2905 /* if the filename looks like a command line option */ 2906 warnf(global, "The filename argument '%s' looks like a flag.", 2907 nextarg); 2908 } 2909 else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) { 2910 warnf(global, "The argument '%s' starts with a Unicode quote where " 2911 "maybe an ASCII \" was intended?", 2912 nextarg); 2913 } 2914 /* ARG_FILE | ARG_STRG */ 2915 err = opt_filestring(config, a, nextarg); 2916 if(a->desc & ARG_CLEAR) 2917 cleanarg(CURL_UNCONST(nextarg)); 2918 } 2919 else { 2920 if(a->desc & ARG_DEPR) { 2921 opt_depr(global, a); 2922 break; 2923 } 2924 /* ARG_NONE | ARG_BOOL */ 2925 if(ARGTYPE(a->desc) == ARG_BOOL) 2926 err = opt_bool(config, a, toggle); 2927 else 2928 err = opt_none(config, a); 2929 } 2930 2931 ++verbose_nopts; /* processed one option from `flag` input, loop for 2932 more */ 2933 } while(!longopt && !singleopt && *++parse && !*usedarg && !err); 2934 2935 error: 2936 if(nextalloc) 2937 free(CURL_UNCONST(nextarg)); 2938 return err; 2939 } 2940 2941 ParameterError parse_args(struct GlobalConfig *global, int argc, 2942 argv_item_t argv[]) 2943 { 2944 int i; 2945 bool stillflags; 2946 const char *orig_opt = NULL; 2947 ParameterError result = PARAM_OK; 2948 struct OperationConfig *config = global->first; 2949 2950 for(i = 1, stillflags = TRUE; i < argc && !result; i++) { 2951 orig_opt = convert_tchar_to_UTF8(argv[i]); 2952 if(!orig_opt) 2953 return PARAM_NO_MEM; 2954 2955 if(stillflags && ('-' == orig_opt[0])) { 2956 bool passarg; 2957 2958 if(!strcmp("--", orig_opt)) 2959 /* This indicates the end of the flags and thus enables the 2960 following (URL) argument to start with -. */ 2961 stillflags = FALSE; 2962 else { 2963 const char *nextarg = NULL; 2964 if(i < (argc - 1)) { 2965 nextarg = convert_tchar_to_UTF8(argv[i + 1]); 2966 if(!nextarg) { 2967 unicodefree(orig_opt); 2968 return PARAM_NO_MEM; 2969 } 2970 } 2971 2972 result = getparameter(orig_opt, nextarg, &passarg, config); 2973 2974 unicodefree(nextarg); 2975 config = global->last; 2976 if(result == PARAM_NEXT_OPERATION) { 2977 /* Reset result as PARAM_NEXT_OPERATION is only used here and not 2978 returned from this function */ 2979 result = PARAM_OK; 2980 2981 if(config->url_list && config->url_list->url) { 2982 /* Allocate the next config */ 2983 config->next = config_alloc(global); 2984 if(config->next) { 2985 /* Update the last config pointer */ 2986 global->last = config->next; 2987 2988 /* Move onto the new config */ 2989 config->next->prev = config; 2990 config = config->next; 2991 } 2992 else 2993 result = PARAM_NO_MEM; 2994 } 2995 else { 2996 errorf(global, "missing URL before --next"); 2997 result = PARAM_BAD_USE; 2998 } 2999 } 3000 else if(!result && passarg) 3001 i++; /* we are supposed to skip this */ 3002 } 3003 } 3004 else { 3005 bool used; 3006 3007 /* Just add the URL please */ 3008 result = getparameter("--url", orig_opt, &used, config); 3009 } 3010 3011 if(!result) { 3012 unicodefree(orig_opt); 3013 orig_opt = NULL; 3014 } 3015 } 3016 3017 if(!result && config->content_disposition) { 3018 if(config->resume_from_current) 3019 result = PARAM_CONTDISP_RESUME_FROM; 3020 } 3021 3022 if(result && result != PARAM_HELP_REQUESTED && 3023 result != PARAM_MANUAL_REQUESTED && 3024 result != PARAM_VERSION_INFO_REQUESTED && 3025 result != PARAM_ENGINES_REQUESTED && 3026 result != PARAM_CA_EMBED_REQUESTED) { 3027 const char *reason = param2text(result); 3028 3029 if(orig_opt && strcmp(":", orig_opt)) 3030 helpf(tool_stderr, "option %s: %s", orig_opt, reason); 3031 else 3032 helpf(tool_stderr, "%s", reason); 3033 } 3034 3035 unicodefree(orig_opt); 3036 return result; 3037 }