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