Annotation of embedaddon/curl/src/tool_getparam.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>