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