Skip to content
Snippets Groups Projects
main.c 110 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Parse the string and write the integer in the given address. Return
     * non-zero on failure, zero on success.
     *
     * The string must start with a digit to be valid.
     */
    
    
    static int str2num(long *val, char *str)
    
    {
      int retcode = 0;
      if(isdigit((int)*str))
        *val = atoi(str);
      else
        retcode = 1; /* badness */
    
      return retcode;
    
    /**
     * Parses the given string looking for an offset (which may be
     * a larger-than-integer value).
     *
     * @param val  the offset to populate
     * @param str  the buffer containing the offset
     * @return zero if successful, non-zero if failure.
     */
    
    static int str2offset(curl_off_t *val, char *str)
    
    #if SIZEOF_CURL_OFF_T > 4
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /* Ugly, but without going through a bunch of rigmarole, we don't have the
       * definitions for LLONG_{MIN,MAX} or LONG_LONG_{MIN,MAX}.
    
       */
    #ifndef LLONG_MAX
    
    #ifdef _MSC_VER
    #define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFi64
    #define LLONG_MIN (curl_off_t)0x8000000000000000i64
    #else
    
    #define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFLL
    #define LLONG_MIN (curl_off_t)0x8000000000000000LL
    
      /* this is a duplicate of the function that is also used in libcurl */
    
    
      if ((*val == LLONG_MAX || *val == LLONG_MIN) && errno == ERANGE)
        return 1;
    #else
      *val = strtol(str, NULL, 0);
      if ((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
        return 1;
    #endif
      return 0;
    }
    
    
    static void checkpasswd(const char *kind, /* for what purpose */
                            char **userpwd) /* pointer to allocated string */
    
      char *ptr;
      if(!*userpwd)
        return;
    
      ptr = strchr(*userpwd, ':');
    
      if(!ptr) {
        /* no password present, prompt for one */
        char passwd[256]="";
    
        char prompt[256];
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        size_t passwdlen;
        size_t userlen = strlen(*userpwd);
    
        /* build a nice-looking prompt */
    
        curlx_msnprintf(prompt, sizeof(prompt),
    
                       "Enter %s password for user '%s':",
                       kind, *userpwd);
    
        /* get password */
    
        getpass_r(prompt, passwd, sizeof(passwd));
        passwdlen = strlen(passwd);
    
    
        /* extend the allocated memory area to fit the password too */
        passptr = realloc(*userpwd,
                          passwdlen + 1 + /* an extra for the colon */
                          userlen + 1);   /* an extra for the zero */
    
          /* append the password separated with a colon */
    
          passptr[userlen]=':';
          memcpy(&passptr[userlen+1], passwd, passwdlen+1);
          *userpwd = passptr;
    
    static ParameterError add2list(struct curl_slist **list,
                                   char *ptr)
    {
      struct curl_slist *newlist = curl_slist_append(*list, ptr);
      if(newlist)
        *list = newlist;
      else
        return PARAM_NO_MEM;
    
      return PARAM_OK;
    }
    
    
    static ParameterError getparameter(char *flag, /* f or -long-flag */
                                       char *nextarg, /* NULL if unset */
                                       bool *usedarg, /* set to TRUE if the arg
                                                         has been used */
                                       struct Configurable *config)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      char letter;
    
      char subletter=0; /* subletters can only occur on long options */
    
    
      const char *parse=NULL;
      unsigned int j;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      time_t now;
      int hit=-1;
    
      bool longopt=FALSE;
    
      bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      /* single-letter,
         long-name,
         boolean whether it takes an additional argument
         */
      struct LongShort aliases[]= {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* all these ones, starting with "*" or "$" as a short-option have *no*
           short option to mention. */
    
        {"*", "url",         TRUE},
        {"*a", "random-file", TRUE},
        {"*b", "egd-file",   TRUE},
        {"*c", "connect-timeout", TRUE},
        {"*d", "ciphers",    TRUE},
        {"*e", "disable-epsv", FALSE},
    
    #ifdef USE_ENVIRONMENT
    
        {"*f", "environment", FALSE},
    
        {"*g", "trace",      TRUE},
        {"*h", "trace-ascii", TRUE},
        {"*i", "limit-rate", TRUE},
        {"*j", "compressed",  FALSE}, /* might take an arg someday */
        {"*k", "digest",     FALSE},
        {"*l", "negotiate",  FALSE},
        {"*m", "ntlm",       FALSE},
        {"*n", "basic",      FALSE},
        {"*o", "anyauth",    FALSE},
    
        {"*p", "wdebug",     FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"*q", "ftp-create-dirs", FALSE},
    
        {"*r", "create-dirs", FALSE},
        {"*s", "max-redirs",   TRUE},
        {"*t", "proxy-ntlm",   FALSE},
        {"*u", "crlf",        FALSE},
        {"*v", "stderr",      TRUE},
        {"*w", "interface",   TRUE},
        {"*x", "krb4",        TRUE},
    
        {"*z", "disable-eprt", FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"$a", "ftp-ssl",    FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"$c", "socks5",     TRUE},
    
        {"$d", "tcp-nodelay",FALSE},
    
        {"$e", "proxy-digest", FALSE},
        {"$f", "proxy-basic", FALSE},
    
        {"0", "http1.0",     FALSE},
    
        {"1", "tlsv1",       FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"2", "sslv2",       FALSE},
        {"3", "sslv3",       FALSE},
    
        {"4", "ipv4",       FALSE},
        {"6", "ipv6",       FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"a", "append",      FALSE},
        {"A", "user-agent",  TRUE},
        {"b", "cookie",      TRUE},
    
        {"B", "use-ascii",   FALSE},
    
        {"c", "cookie-jar",  TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"C", "continue-at", TRUE},
        {"d", "data",        TRUE},
    
        {"da", "data-ascii", TRUE},
        {"db", "data-binary", TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"D", "dump-header", TRUE},
        {"e", "referer",     TRUE},
        {"E", "cert",        TRUE},
    
        {"Ea", "cacert",     TRUE},
    
        {"Eb","cert-type",   TRUE},
        {"Ec","key",         TRUE},
        {"Ed","key-type",    TRUE},
        {"Ee","pass",        TRUE},
        {"Ef","engine",      TRUE},
    
        {"Eg","capath ",     TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"f", "fail",        FALSE},
        {"F", "form",        TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"h", "help",        FALSE},
        {"H", "header",      TRUE},
        {"i", "include",     FALSE},
        {"I", "head",        FALSE},
    
        {"j", "junk-session-cookies", FALSE},
    
        {"k", "insecure",    FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"K", "config",      TRUE},
        {"l", "list-only",   FALSE},
        {"L", "location",    FALSE},
    
        {"Lt", "location-trusted", FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"m", "max-time",    TRUE},
        {"M", "manual",      FALSE},
        {"n", "netrc",       FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"o", "output",      TRUE},
        {"O", "remote-name", FALSE},
    
        {"p", "proxytunnel", FALSE},
    
        {"P", "ftpport",     TRUE}, /* older version */
        {"P", "ftp-port",    TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"q", "disable",     FALSE},
        {"Q", "quote",       TRUE},
        {"r", "range",       TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"s", "silent",      FALSE},
        {"S", "show-error",  FALSE},
    
        {"t", "telnet-options", TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"T", "upload-file", TRUE},
        {"u", "user",        TRUE},
        {"U", "proxy-user",  TRUE},
        {"v", "verbose",     FALSE},
        {"V", "version",     FALSE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"x", "proxy",       TRUE},
        {"X", "request",     TRUE},
        {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
    
        {"Y", "speed-limit",  TRUE},
        {"y", "speed-time", TRUE},
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        {"z", "time-cond",   TRUE},
        {"#", "progress-bar",FALSE},
      };
    
    
      if(('-' != flag[0]) ||
         (('-' == flag[0]) && ('-' == flag[1]))) {
        /* this should be a long name */
        char *word=('-' == flag[0])?flag+2:flag;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        size_t fnam=strlen(word);
    
        int numhits=0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
    
          if(curlx_strnequal(aliases[j].lname, word, fnam)) {
    
            longopt = TRUE;
    
            if(curlx_strequal(aliases[j].lname, word)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              parse = aliases[j].letter;
              hit = j;
    
              numhits = 1; /* a single unique hit */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              break;
            }
    	parse = aliases[j].letter;
    	hit = j;
          }
        }
    
        if(numhits>1) {
          /* this is at least the second match! */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(hit < 0) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
      else {
    
        flag++; /* prefixed with one dash, pass it */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        hit=-1;
        parse = flag;
      }
    
      do {
        /* we can loop here if we have multiple single-letters */
    
    
        if(!longopt)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          letter = parse?(char)*parse:'\0';
    
        else {
          letter = parse[0];
          subletter = parse[1];
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        *usedarg = FALSE; /* default is that we don't use the arg */
    
    #if 0
        fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
    #endif
        if(hit < 0) {
          for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
    
    	if(letter == aliases[j].letter[0]) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	  hit = j;
    	  break;
    	}
          }
          if(hit < 0) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
        }
        if(hit < 0) {
    
        if(!longopt && aliases[hit].extraparam && parse[1]) {
    
          nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
    
          singleopt=TRUE;   /* don't loop anymore after this */
        }
    
        else if(!nextarg && aliases[hit].extraparam) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        else if(nextarg && aliases[hit].extraparam)
          *usedarg = TRUE; /* mark it as used */
    
        switch(letter) {
    
        case '*': /* options without a short option */
    
          switch(subletter) {
          case 'a': /* random-file */
            GetStr(&config->random_file, nextarg);
            break;
          case 'b': /* egd-file */
            GetStr(&config->egd_file, nextarg);
            break;
    
          case 'c': /* connect-timeout */
    
            if(str2num(&config->connecttimeout, nextarg))
              return PARAM_BAD_NUMERIC;
    
          case 'd': /* ciphers */
            GetStr(&config->cipher_list, nextarg);
            break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'e': /* --disable-epsv */
            config->disable_epsv ^= TRUE;
            break;
    
    #ifdef USE_ENVIRONMENT
          case 'f':
            config->writeenv ^= TRUE;
            break;
    #endif
    
          case 'g': /* --trace */
            GetStr(&config->trace_dump, nextarg);
    
            break;
          case 'h': /* --trace-ascii */
            GetStr(&config->trace_dump, nextarg);
            config->trace_ascii = TRUE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'i': /* --limit-rate */
            {
              /* We support G, M, K too */
              char *unit;
    
              curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              switch(nextarg[strlen(nextarg)-1]) {
              case 'G':
              case 'g':
                value *= 1024*1024*1024;
                break;
              case 'M':
              case 'm':
                value *= 1024*1024;
                break;
              case 'K':
              case 'k':
                value *= 1024;
                break;
              }
              config->recvpersecond = value;
              config->sendpersecond = value;
            }
            break;
    
    
          case 'j': /* --compressed */
     	config->encoding ^= TRUE;
     	break;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'k': /* --digest */
    
     	config->authtype = CURLAUTH_DIGEST;
    
            if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
              config->authtype = CURLAUTH_GSSNEGOTIATE;
            else
              return PARAM_LIBCURL_DOESNT_SUPPORT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'm': /* --ntlm */
    
            if(curlinfo->features & CURL_VERSION_NTLM)
              config->authtype = CURLAUTH_NTLM;
            else
              return PARAM_LIBCURL_DOESNT_SUPPORT;
    
    	break;
    
          case 'n': /* --basic for completeness */
    	config->authtype = CURLAUTH_BASIC;
    	break;
    
          case 'o': /* --anyauth, let libcurl pick it */
    	config->authtype = CURLAUTH_ANY;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	break;
    
    
    #ifdef __DJGPP__
          case 'p': /* --wdebug */
            dbug_init();
            break;
    #endif
    
            config->ftp_create_dirs ^= TRUE;
            break;
    
          case 'r': /* --create-dirs */
            config->create_dirs = TRUE;
            break;
    
          case 's': /* --max-redirs */
            /* specified max no of redirects (http(s)) */
    
            if(str2num(&config->maxredirs, nextarg))
              return PARAM_BAD_NUMERIC;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 't': /* --proxy-ntlm */
    
            if(curlinfo->features & CURL_VERSION_NTLM)
              config->proxyntlm ^= TRUE;
            else
    
              return PARAM_LIBCURL_DOESNT_SUPPORT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            break;
    
    
          case 'u': /* --crlf */
            /* LF -> CRLF conversinon? */
            config->crlf = TRUE;
            break;
    
          case 'v': /* --stderr */
            if(strcmp(nextarg, "-")) {
              config->errors = fopen(nextarg, "wt");
              config->errors_fopened = TRUE;
            }
            else
              config->errors = stdout;
          break;
          case 'w': /* --interface */
            /* interface */
            GetStr(&config->iface, nextarg);
            break;
          case 'x': /* --krb4 */
            /* krb4 level string */
    
            if(curlinfo->features & CURL_VERSION_KERBEROS4)
              GetStr(&config->krb4level, nextarg);
            else
              return PARAM_LIBCURL_DOESNT_SUPPORT;
    
            if(str2offset(&config->max_filesize, nextarg))
    
          case 'z': /* --disable-eprt */
            config->disable_eprt ^= TRUE;
            break;
    
          default: /* the URL! */
            {
              struct getout *url;
              if(config->url_get || (config->url_get=config->url_list)) {
                /* there's a node here, if it already is filled-in continue to find
                   an "empty" node */
                while(config->url_get && (config->url_get->flags&GETOUT_URL))
                  config->url_get = config->url_get->next;
              }
    
              /* now there might or might not be an available node to fill in! */
    
              if(config->url_get)
                /* existing node */
                url = config->url_get;
              else
                /* there was no free node, create one! */
                url=new_getout(config);
    
              if(url) {
                /* fill in the URL */
                GetStr(&url->url, nextarg);
                url->flags |= GETOUT_URL;
              }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case '$': /* more options without a short option */
          switch(subletter) {
          case 'a': /* --ftp-ssl */
            config->ftp_ssl ^= TRUE;
            break;
    
          case 'b': /* --ftp-pasv */
            if(config->ftpport)
              free(config->ftpport);
            config->ftpport = NULL;
            break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          case 'c': /* --socks specifies a socks5 proxy to use */
            GetStr(&config->socks5proxy, nextarg);
            break;
    
          case 'd': /* --tcp-nodelay option */
    	config->tcp_nodelay ^= TRUE;
    	break;
    
          case 'e': /* --proxy-digest */
            config->proxydigest ^= TRUE;
            break;
    
          case 'f': /* --proxy-basic */
            config->proxybasic ^= TRUE;
            break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case '#': /* added 19990617 larsa */
          config->progressmode ^= CURL_PROGRESS_BAR;
          break;
    
        case '0':
    
          /* HTTP version 1.0 */
          config->httpversion = CURL_HTTP_VERSION_1_0;
          break;
    
        case '1':
          /* TLS version 1 */
          config->ssl_version = CURL_SSLVERSION_TLSv1;
          break;
    
        case '2':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* SSL version 2 */
    
          config->ssl_version = CURL_SSLVERSION_SSLv2;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
        case '3':
    
          /* SSL version 3 */
          config->ssl_version = CURL_SSLVERSION_SSLv3;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
        case '4':
    
          /* IPv4 */
          config->ip_version = 4;
          break;
    
        case '6':
    
          /* IPv6 */
          config->ip_version = 6;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'a':
          /* This makes the FTP sessions use APPE instead of STOR */
          config->conf ^= CONF_FTPAPPEND;
          break;
        case 'A':
          /* This specifies the User-Agent name */
          GetStr(&config->useragent, nextarg);
          break;
        case 'b': /* cookie string coming up: */
    
          if(nextarg[0] == '@') {
            nextarg++;
          }
          else if(strchr(nextarg, '=')) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            /* A cookie string must have a =-letter */
            GetStr(&config->cookie, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          /* We have a cookie file to read from! */
          GetStr(&config->cookiefile, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'B':
    
          /* use ASCII/text when transfering */
          config->conf ^= CONF_GETTEXT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'c':
    
          /* get the file name to dump all cookies in */
          GetStr(&config->cookiejar, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'C':
          /* This makes us continue an ftp transfer at given position */
    
            if(str2offset(&config->resume_from, nextarg))
    
            config->resume_from_current = FALSE;
          }
          else {
            config->resume_from_current = TRUE;
            config->resume_from = 0;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          config->use_resume=TRUE;
          break;
        case 'd':
          /* postfield data */
    
          {
            char *postdata=NULL;
    
            if('@' == *nextarg) {
              /* the data begins with a '@' letter, it means that a file name
                 or - (stdin) follows */
              FILE *file;
    
              nextarg++; /* pass the @ */
    
    
    
              if(subletter == 'b') /* forced binary */
                postdata = file2memory(file, &config->postfieldsize);
              else
                postdata = file2string(file);
              if(file && (file != stdin))
    
              /* we already have a string, we append this one
                 with a separating &-letter */
              char *oldpost=config->postfields;
    
              config->postfields=aprintf("%s&%s", oldpost, postdata);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          /*
            We can't set the request type here, as this data might be used in
            a simple GET if -G is used. Already or soon.
    
            if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
              return PARAM_BAD_USE;
          */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'D':
          /* dump-header to given file name */
          GetStr(&config->headerfile, nextarg);
          break;
        case 'e':
    
          {
            char *ptr = strstr(nextarg, ";auto");
            if(ptr) {
              /* Automatic referer requested, this may be combined with a
                 set initial one */
              config->conf |= CONF_AUTO_REFERER;
              *ptr = 0; /* zero terminate here */
            }
            GetStr(&config->referer, nextarg);
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'E':
    
          switch(subletter) {
          case 'a': /* CA info PEM file */
    
            /* CA info PEM file */
            GetStr(&config->cacert, nextarg);
    
            break;
          case 'b': /* cert file type */
            GetStr(&config->cert_type, nextarg);
            break;
          case 'c': /* private key file */
            GetStr(&config->key, nextarg);
            break;
          case 'd': /* private key file type */
            GetStr(&config->key_type, nextarg);
            break;
          case 'e': /* private key passphrase */
            GetStr(&config->key_passwd, nextarg);
    
            break;
          case 'f': /* crypto engine */
            GetStr(&config->engine, nextarg);
            break;
    
          case 'g': /* CA info PEM file */
            /* CA cert directory */
            GetStr(&config->capath, nextarg);
            break;
    
          default: /* certificate file */
            {
              char *ptr = strchr(nextarg, ':');
              /* Since we live in a world of weirdness and confusion, the win32
                 dudes can use : when using drive letters and thus
                 c:\file:password needs to work. In order not to break
                 compatibility, we still use : as separator, but we try to detect
                 when it is used for a file name! On windows. */
    
              if(ptr &&
                 (ptr == &nextarg[1]) &&
                 (nextarg[2] == '\\') &&
                 (isalpha((int)nextarg[0])) )
                 /* colon in the second column, followed by a backslash, and the
                    first character is an alphabetic letter:
    
                    this is a drive letter colon */
                ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
    
              if(ptr) {
                /* we have a password too */
                *ptr=0;
                ptr++;
                GetStr(&config->key_passwd, ptr);
              }
              GetStr(&config->cert, nextarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
          break;
        case 'f':
          /* fail hard on errors  */
          config->conf ^= CONF_FAILONERROR;
          break;
        case 'F':
          /* "form data" simulation, this is a little advanced so lets do our best
    	 to sort this out slowly and carefully */
    
          if(formparse(nextarg,
                       &config->httppost,
                       &config->last_post))
    
          if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
    
        case 'g': /* g disables URLglobbing */
          config->globoff ^= TRUE;
          break;
    
    
        case 'G': /* HTTP GET */
          config->use_httpget = TRUE;
          break;
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'h': /* h for help */
          help();
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'H':
    
          /* A custom header to append to a list */
    
          err = add2list(&config->headers, nextarg);
          if(err)
            return err;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'i':
          config->conf ^= CONF_HEADER; /* include the HTTP header as well */
          break;
    
        case 'j':
          config->cookiesession ^= TRUE;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'I':
    
          /*
           * This is a bit tricky. We either SET both bits, or we clear both
           * bits. Let's not make any other outcomes from this.
           */
          if((CONF_HEADER|CONF_NOBODY) !=
             (config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
            /* one of them weren't set, set both */
            config->conf |= (CONF_HEADER|CONF_NOBODY);
            if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
              return PARAM_BAD_USE;
          }
          else {
            /* both were set, clear both */
            config->conf &= ~(CONF_HEADER|CONF_NOBODY);
            if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
              return PARAM_BAD_USE;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
        case 'k': /* allow insecure SSL connects */
          config->insecure_ok ^= TRUE;
          break;
        case 'K': /* parse config file */
    
          parseconfig(nextarg, config);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'l':
          config->conf ^= CONF_FTPLISTONLY; /* only list the names of the FTP dir */
          break;
        case 'L':
          config->conf ^= CONF_FOLLOWLOCATION; /* Follow Location: HTTP headers */
    
          switch (subletter) {
          case 't':
            /* Continue to send authentication (user+password) when following
             * locations, even when hostname changed */
            config->conf ^= CONF_UNRESTRICTED_AUTH;
            break;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'm':
          /* specified max time */
    
          if(str2num(&config->timeout, nextarg))
            return PARAM_BAD_NUMERIC;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'M': /* M for manual, huge help */
    
    #ifdef USE_MANUAL
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          hugehelp();
    
          fprintf(stderr,
                  "curl: built-in manual was disabled at build-time!\n");
    
          return PARAM_OPTION_UNKNOWN;
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'n':
    
          switch(subletter) {
          case 'o': /* CA info PEM file */
            /* use .netrc or URL */
            config->conf ^= CONF_NETRC_OPT;
            break;
          default:
            /* pick info from .netrc, if this is used for http, curl will
               automatically enfore user+password with the request */
            config->conf ^= CONF_NETRC;
            break;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
        case 'N':
          /* disable the output I/O buffering */
          config->nobuffer ^= 1;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'o':
        case 'O':
          /* output file */
    
          {
            struct getout *url;
            if(config->url_out || (config->url_out=config->url_list)) {
              /* there's a node here, if it already is filled-in continue to find
                 an "empty" node */
              while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
                config->url_out = config->url_out->next;
            }
    
            /* now there might or might not be an available node to fill in! */
    
            if(config->url_out)
              /* existing node */
              url = config->url_out;
            else
              /* there was no free node, create one! */
              url=new_getout(config);
    
            if(url) {
              /* fill in the outfile */
              if('o' == letter)
                GetStr(&url->outfile, nextarg);
              else {
                url->outfile=NULL; /* leave it */
                url->flags |= GETOUT_USEREMOTE;
              }
              url->flags |= GETOUT_OUTFILE;
            }
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'P':
          /* This makes the FTP sessions use PORT instead of PASV */
          /* use <eth0> or <192.168.10.10> style addresses. Anything except
    	 this will make us try to get the "default" address.
    	 NOTE: this is a changed behaviour since the released 4.1!
    	 */
          GetStr(&config->ftpport, nextarg);
          break;
        case 'p':
    
          /* proxy tunnel for non-http protocols */
          config->proxytunnel ^= TRUE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 'q': /* if used first, already taken care of, we do it like
    		 this so we don't cause an error! */
          break;
        case 'Q':
          /* QUOTE command to send to FTP server */
    
          switch(nextarg[0]) {
          case '-':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            /* prefixed with a dash makes it a POST TRANSFER one */
            nextarg++;
    
            err = add2list(&config->postquote, nextarg);
    
            break;
          case '+':
            /* prefixed with a plus makes it a just-before-transfer one */
            nextarg++;
    
            err = add2list(&config->prequote, nextarg);
    
            err = add2list(&config->quote, nextarg);
            break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'r':
          /* byte range requested */
          GetStr(&config->range, nextarg);
          break;
    
        case 'R':
          /* use remote file's time */
          config->remote_time ^= TRUE;
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        case 's':
          /* don't show progress meter, don't show errors : */
          config->conf |= (CONF_MUTE|CONF_NOPROGRESS);
          config->showerror ^= TRUE; /* toggle off */
          break;
        case 'S':
          /* show errors */
          config->showerror ^= TRUE; /* toggle on if used with -s */
          break;
        case 't':
    
          /* Telnet options */
    
          err = add2list(&config->telnet_options, nextarg);
          if(err)
            return err;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'T':
          /* we are uploading */
    
          {
            struct getout *url;
            if(config->url_out || (config->url_out=config->url_list)) {
              /* there's a node here, if it already is filled-in continue to find
                 an "empty" node */
              while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
                config->url_out = config->url_out->next;
            }
    
            /* now there might or might not be an available node to fill in! */
    
            if(config->url_out)
              /* existing node */
              url = config->url_out;
            else
              /* there was no free node, create one! */
              url=new_getout(config);
    
            if(url) {
              url->flags |= GETOUT_UPLOAD; /* mark -T used */
              if(!*nextarg)
                url->flags |= GETOUT_NOUPLOAD;
              else {
                /* "-" equals stdin, but keep the string around for now */
                GetStr(&url->infile, nextarg);
              }
            }
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'u':
          /* user:password  */
          GetStr(&config->userpwd, nextarg);
    
          checkpasswd("host", &config->userpwd);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'U':
          /* Proxy user:password  */
          GetStr(&config->proxyuserpwd, nextarg);
    
          checkpasswd("proxy", &config->proxyuserpwd);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          break;
        case 'v':
          config->conf ^= CONF_VERBOSE; /* talk a lot */
          break;
        case 'V':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          printf(CURL_ID "%s\n", curl_version());
    
          if (curlinfo->protocols) {
            printf("Protocols: ");
            for (proto=curlinfo->protocols; *proto; ++proto) {
    
            puts(""); /* newline */
          }
          if(curlinfo->features) {
            unsigned int i;
            struct feat {
              const char *name;
              int bitmask;
            };
            struct feat feats[] = {
    
              {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
              {"Debug", CURL_VERSION_DEBUG},
              {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
              {"IDN", CURL_VERSION_IDN},
    
              {"IPv6", CURL_VERSION_IPV6},
    
              {"Largefile", CURL_VERSION_LARGEFILE},
    
              {"NTLM", CURL_VERSION_NTLM},
    
              {"SPNEGO", CURL_VERSION_SPNEGO},
    
              {"SSL",  CURL_VERSION_SSL},
              {"krb4", CURL_VERSION_KERBEROS4},
              {"libz", CURL_VERSION_LIBZ}
    
            };
            printf("Features: ");
            for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
              if(curlinfo->features & feats[i].bitmask)
                printf("%s ", feats[i].name);
            }
            puts(""); /* newline */
    
          if('@' == *nextarg) {
            /* the data begins with a '@' letter, it means that a file name
               or - (stdin) follows */
            FILE *file;
            nextarg++; /* pass the @ */
    
              file = fopen(nextarg, "r");
            config->writeout = file2string(file);
            if(file && (file != stdin))
    
            GetStr(&config->writeout, nextarg);