Skip to content
Snippets Groups Projects
main.c 109 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
          GetStr(&config->customrequest, nextarg);
          break;
    
        case 'y':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* low speed time */
    
          if(str2num(&config->low_speed_time, nextarg))
            return PARAM_BAD_NUMERIC;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          if(!config->low_speed_limit)
    	config->low_speed_limit = 1;
          break;
    
        case 'Y':
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* low speed limit */
    
          if(str2num(&config->low_speed_limit, nextarg))
            return PARAM_BAD_NUMERIC;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          if(!config->low_speed_time)
    	config->low_speed_time=30;
          break;
    
        case 'z': /* time condition coming up */
          switch(*nextarg) {
          case '+':
            nextarg++;
          default:
            /* If-Modified-Since: (section 14.28 in RFC2068) */
    
            config->timecond = CURL_TIMECOND_IFMODSINCE;
    
            break;
          case '-':
            /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
    
            config->timecond = CURL_TIMECOND_IFUNMODSINCE;
    
            nextarg++;
            break;
          case '=':
            /* Last-Modified:  (section 14.29 in RFC2068) */
    
            config->timecond = CURL_TIMECOND_LASTMOD;
    
            nextarg++;
            break;
          }
          now=time(NULL);
          config->condtime=curl_getdate(nextarg, &now);
    
          if(-1 == (int)config->condtime) {
    
            /* now let's see if it is a file name to get the time from instead! */
            struct stat statbuf;
            if(-1 == stat(nextarg, &statbuf)) {
              /* failed, remove time condition */
    
              config->timecond = CURL_TIMECOND_NONE;
    
            }
            else {
              /* pull the time out from the file */
              config->condtime = statbuf.st_mtime;
            }
          }
          break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        default: /* unknown flag */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        hit = -1;
    
    
      } while(!longopt && !singleopt && *++parse && !*usedarg);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    static void parseconfig(const char *filename,
                            struct Configurable *config)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      int res;
      FILE *file;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      bool usedarg;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(!filename || !*filename) {
        /* NULL or no file name attempts to load .curlrc from the homedir! */
    
    #define CURLRC DOT_CHAR "curlrc"
    
    
        filename = CURLRC;   /* sensible default */
        home = homedir();    /* portable homedir finder */
    
        if(home) {
          if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
            snprintf(filebuffer, sizeof(filebuffer),
                     "%s%s%s", home, DIR_CHAR, CURLRC);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          free(home); /* we've used it, now free it */
    
    # else /* AmigaOS */
      /* On AmigaOS all the config files are into env:
       */
      filename = "ENV:" CURLRC;
    
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      if(strcmp(filename,"-"))
        file = fopen(filename, "r");
      else
        file = stdin;
    
        char *aline;
        char *option;
        char *param;
        int lineno=0;
        bool alloced_param;
    
    #define isseparator(x) (((x)=='=') || ((x) == ':'))
    
        while (NULL != (aline = my_get_line(file))) {
          lineno++;
          line = aline;
          alloced_param=FALSE;
    
    
          /* lines with # in the fist column is a comment! */
    
            line++;
    
          switch(*line) {
          case '#':
          case '/':
          case '\r':
          case '\n':
          case '*':
          case '\0':
    
            free(aline);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          /* the option keywords starts here */
          option = line;
    
          while(*line && !isspace((int)*line) && !isseparator(*line))
    
          if(*line)
            *line++=0; /* zero terminate, we have a local copy of the data */
    
    
    #ifdef DEBUG_CONFIG
          fprintf(stderr, "GOT: %s\n", option);
    #endif
    
          /* pass spaces and separator(s) */
    
          while(*line && (isspace((int)*line) || isseparator(*line)))
    
          /* the parameter starts here (unless quoted) */
          if(*line == '\"') {
            char *ptr;
            /* quoted parameter, do the qoute dance */
            line++;
            param=strdup(line); /* parameter */
            alloced_param=TRUE;
    
            ptr=param;
            while(*line && (*line != '\"')) {
              if(*line == '\\') {
    
    
                /* default is to output the letter after the backslah */
                switch(out = *line) {
                case '\0':
                  continue; /* this'll break out of the loop */
                case 't':
                  out='\t';
                  break;
                case 'n':
                  out='\n';
                  break;
                case 'r':
                  out='\r';
                  break;
                case 'v':
                  out='\v';
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          else {
            param=line; /* parameter starts here */
    
            while(*line && !isspace((int)*line))
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
    
          if (param && !*param) {
            /* do this so getparameter can check for required parameters.
               Otherwise it always thinks there's a parameter. */
            if (alloced_param)
              free(param);
            param = NULL;
          }
    
    
          fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
    
    #endif
          res = getparameter(option, param, &usedarg, config);
    
            /* we passed in a parameter that wasn't used! */
            res = PARAM_GOT_EXTRA_PARAMETER;
    
          if(res != PARAM_OK) {
            /* the help request isn't really an error */
            if(!strcmp(filename, "-")) {
    
              filename=(char *)"<stdin>";
    
              const char *reason = param2text(res);
    
              fprintf(stderr, "%s:%d: warning: '%s' %s\n",
                      filename, lineno, option, reason);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
        if(file != stdin)
          fclose(file);
      }
    }
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    static void go_sleep(long ms)
    {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /* portable subsecond "sleep" */
      poll((void *)0, 0, ms);
    
    #else
      /* systems without poll() need other solutions */
    
    #ifdef WIN32
      /* Windows offers a millisecond sleep */
      Sleep(ms);
    
    #elif defined(__MSDOS__)
      delay(ms);
    
    #else
      /* Other systems must use select() for this */
      struct timeval timeout;
    
    
      timeout.tv_usec = ms * 1000;
    
      select(0, NULL,  NULL, NULL, &timeout);
    #endif
    
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    struct OutStruct {
      char *filename;
      FILE *stream;
    
      struct Configurable *config;
    
    static int my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      struct OutStruct *out=(struct OutStruct *)stream;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      struct Configurable *config = out->config;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(out && !out->stream) {
        /* open file for writing */
        out->stream=fopen(out->filename, "wb");
        if(!out->stream)
          return -1; /* failure */
      }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(config->recvpersecond) {
        /*
         * We know when we received data the previous time. We know how much data
         * we get now. Make sure that this is not faster than we are told to run.
         * If we're faster, sleep a while *before* doing the fwrite() here.
         */
    
    
        struct timeval now;
        long timediff;
        long sleep_time;
    
        now = curlx_tvnow();
        timediff = curlx_tvdiff(now, config->lastrecvtime); /* milliseconds */
    
        if((config->recvpersecond > CURL_MAX_WRITE_SIZE) && (timediff < 100) ) {
          /* If we allow a rather speedy transfer, add this amount for later
           * checking. Also, do not modify the lastrecvtime as we will use a
           * longer scope due to this addition.  We wait for at least 100 ms to
           * pass to get better values to do better math for the sleep. */
          addit += size;
        }
        else {
          size += addit; /* add up the possibly added bonus rounds from the
                            zero timediff calls */
          addit = 0; /* clear the addition pool */
    
          if( size*1000 > config->recvpersecond*timediff) {
            /* figure out how many milliseconds to rest */
    
            sleep_time = (long)(size*1000/config->recvpersecond - timediff);
    
    
            /*
             * Make sure we don't sleep for so long that we trigger the speed
             * limit.  This won't limit the bandwidth quite the way we've been
             * asked to, but at least the transfer has a chance.
             */
            if (config->low_speed_time > 0)
              sleep_time = MIN(sleep_time,(config->low_speed_time * 1000) / 2);
    
            if(sleep_time > 0) {
              go_sleep(sleep_time);
              now = curlx_tvnow();
            }
          }
          config->lastrecvtime = now;
    
      rc = fwrite(buffer, sz, nmemb, out->stream);
    
      if(config->nobuffer)
        /* disable output buffering */
        fflush(out->stream);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    struct InStruct {
      FILE *stream;
      struct Configurable *config;
    };
    
    
    static int my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      struct InStruct *in=(struct InStruct *)userp;
      struct Configurable *config = in->config;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(config->sendpersecond) {
        /*
         * We know when we sent data the previous time. We know how much data
         * we sent. Make sure that this was not faster than we are told to run.
         * If we're faster, sleep a while *before* doing the fread() here.
         * Also, make no larger fread() than should be sent this second!
         */
    
    
        struct timeval now;
        long timediff;
        long sleep_time;
    
        static curl_off_t addit = 0;
    
        now = curlx_tvnow();
        timediff = curlx_tvdiff(now, config->lastsendtime); /* milliseconds */
    
        if((config->sendpersecond > CURL_MAX_WRITE_SIZE) &&
           (timediff < 100)) {
          /*
           * We allow very fast transfers, then allow at least 100 ms between
           * each sleeping mile-stone to create more accurate long-term rates.
           */
          addit += size;
        }
        else {
          /* If 'addit' is non-zero, it contains the total amount of bytes
             uploaded during the last 'timediff' milliseconds. If it is zero,
             we use the stored previous size. */
    
          curl_off_t xfered = addit?addit:(curl_off_t)config->lastsendsize;
    
          addit = 0; /* clear it for the next round */
    
          if( xfered*1000 > config->sendpersecond*timediff) {
            /* figure out how many milliseconds to rest */
    
            sleep_time = (long)(xfered*1000/config->sendpersecond - timediff);
    
            if(sleep_time > 0) {
              go_sleep (sleep_time);
              now = curlx_tvnow();
            }
          }
          config->lastsendtime = now;
    
          if(size > config->sendpersecond) {
            /* lower the size to actually read */
    
      return fread(buffer, sz, nmemb, in->stream);
    
      FILE *out; /* where to write everything to */
    
      curl_off_t initial_size;
    
    static int myprogress (void *clientp,
                           double dltotal,
                           double dlnow,
                           double ultotal,
                           double ulnow)
    
    {
      /* The original progress-bar source code was written for curl by Lars Aas,
    
         and this new edition inherits some of his concepts. */
    
      char line[256];
      char outline[256];
      char format[40];
    
      int barwidth;
      int num;
      int i;
    
      struct ProgressData *bar = (struct ProgressData *)clientp;
    
      double total = dltotal + ultotal + bar->initial_size;
      double point = dlnow + ulnow + bar->initial_size; /* we've come this far */
    
        int prevblock = (int)bar->prev / 1024;
    
          fprintf( bar->out, "#" );
    
        percent = frac * 100.0f;
        barwidth = bar->width - 7;
    
        num = (int) (((double)barwidth) * frac);
    
        i = 0;
        for ( i = 0; i < num; i++ ) {
          line[i] = '#';
        }
        line[i] = '\0';
        sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
        sprintf( outline, format, line, percent );
    
        fprintf( bar->out, "\r%s", outline );
    
    static
    void progressbarinit(struct ProgressData *bar,
                         struct Configurable *config)
    
    {
    #ifdef __EMX__
      /* 20000318 mgs */
      int scr_size [2];
    #endif
      char *colp;
    
      memset(bar, 0, sizeof(struct ProgressData));
    
    
      /* pass this through to progress function so
       * it can display progress towards total file
       * not just the part that's left. (21-may-03, dbyron) */
      if (config->use_resume)
        bar->initial_size = config->resume_from;
    
    
    /* TODO: get terminal width through ansi escapes or something similar.
             try to update width when xterm is resized... - 19990617 larsa */
    #ifndef __EMX__
      /* 20000318 mgs
       * OS/2 users most likely won't have this env var set, and besides that
       * we're using our own way to determine screen width */
    
      if (colp != NULL) {
        bar->width = atoi(colp);
    
        curl_free(colp);
    
      }
      else
        bar->width = 79;
    #else
      /* 20000318 mgs
       * We use this emx library call to get the screen width, and subtract
       * one from what we got in order to avoid a problem with the cursor
       * advancing to the next line if we print a string that is as long as
       * the screen is wide. */
    
      _scrsize(scr_size);
      bar->width = scr_size[0] - 1;
    #endif
    
    
      bar->out = config->errors;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
              FILE *stream, unsigned char *ptr, size_t size,
              bool nohex)
    
      unsigned int width=0x10;
    
      if(nohex)
        /* without the hex output, we can fit more on screen */
        width = 0x40;
    
      fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size);
    
      for(i=0; i<size; i+= width) {
    
        if(!nohex) {
          /* hex not disabled, show it */
          for(c = 0; c < width; c++)
            if(i+c < size)
              fprintf(stream, "%02x ", ptr[i+c]);
            else
              fputs("   ", stream);
        }
    
    
        for(c = 0; (c < width) && (i+c < size); c++) {
          /* check for 0D0A; if found, skip past and start a new line of output */
          if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
            i+=(c+2-width);
            break;
          }
    
          fprintf(stream, "%c",
                  (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
    
          /* check again for 0D0A, to avoid an extra \n if it's at width */
          if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
            i+=(c+3-width);
            break;
          }
        }
    
      fflush(stream);
    
    }
    
    static
    int my_trace(CURL *handle, curl_infotype type,
                 unsigned char *data, size_t size,
                 void *userp)
    {
      struct Configurable *config = (struct Configurable *)userp;
      FILE *output=config->errors;
    
      const char *text;
    
      if(!config->trace_stream) {
    
        if(curlx_strequal("-", config->trace_dump))
    
          config->trace_stream = stdout;
        else {
          config->trace_stream = fopen(config->trace_dump, "w");
          config->trace_fopened = TRUE;
        }
      }
    
    
      if(config->trace_stream)
        output = config->trace_stream;
    
      switch (type) {
      case CURLINFO_TEXT:
        fprintf(output, "== Info: %s", data);
    
      default: /* in case a new one is introduced to shock us */
        return 0;
    
    
        text = "=> Send header";
    
        text = "=> Send data";
    
        text = "<= Recv header";
    
        text = "<= Recv data";
    
    
      dump(text, output, data, size, config->trace_ascii);
    
    static void free_config_fields(struct Configurable *config)
    
      if(config->random_file)
        free(config->random_file);
      if(config->egd_file)
        free(config->egd_file);
    
      if(config->userpwd)
        free(config->userpwd);
      if(config->postfields)
        free(config->postfields);
      if(config->proxy)
        free(config->proxy);
      if(config->proxyuserpwd)
        free(config->proxyuserpwd);
      if(config->cookie)
        free(config->cookie);
      if(config->cookiefile)
        free(config->cookiefile);
      if(config->krb4level)
        free(config->krb4level);
      if(config->headerfile)
        free(config->headerfile);
      if(config->ftpport)
        free(config->ftpport);
      if(config->range)
        free(config->range);
      if(config->customrequest)
        free(config->customrequest);
      if(config->writeout)
        free(config->writeout);
      if(config->httppost)
        curl_formfree(config->httppost);
      if(config->cacert)
        free(config->cacert);
    
      if(config->capath)
        free(config->capath);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(config->cookiejar)
        free(config->cookiejar);
    
    
      curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
      curl_slist_free_all(config->postquote); /*  */
      curl_slist_free_all(config->headers); /*  */
    
    #if defined(WIN32) && !defined(__CYGWIN32__)
    
    /* Function to find CACert bundle on a Win32 platform using SearchPath.
     * (SearchPath is defined in windows.h, which is #included into libcurl)
     * (Use the ASCII version instead of the unicode one!)
     * The order of the directories it searches is:
     *  1. application's directory
     *  2. current working directory
     *  3. Windows System directory (e.g. C:\windows\system32)
     *  4. Windows Directory (e.g. C:\windows)
     *  5. all directories along %PATH%
     */
    
    static void FindWin32CACert(struct Configurable *config,
    
                                const char *bundle_file)
    {
      /* only check for cert file if "we" support SSL */
    
      if(curlinfo->features & CURL_VERSION_SSL) {
    
        DWORD buflen;
        char *ptr = NULL;
        char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
        if (!retval)
          return;
        retval[0] = '\0';
        buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
        if (buflen > 0) {
          GetStr(&config->cacert, retval);
        }
        free(retval);
      }
    }
    
    #endif
    
    static int
    
    operate(struct Configurable *config, int argc, char *argv[])
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      char errorbuffer[CURL_ERROR_SIZE];
    
      char useragent[128]; /* buah, we don't want a larger default user agent */
    
      struct getout *urlnode;
      struct getout *nextnode;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      struct OutStruct outs;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      struct InStruct input;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      char *url = NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int urlnum;
    
      char *infiles; /* might a glob pattern */
      char *uploadfile=NULL; /* a single file, never a glob */
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int separator = 0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      FILE *headerfilep = NULL;
      char *urlbuffer=NULL;
    
      curl_off_t uploadfilesize; /* -1 means unknown */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      bool stillflags=TRUE;
    
    
      bool allocuseragent=FALSE;
    
    
      CURL *curl;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int i;
    
      int up; /* upload file counter within a single upload glob */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #ifdef CURLDEBUG
    
      /* this sends all memory debug messages to a logfile named memdump */
    
        curl_free(env);
    
      if(env) {
        curl_memlimit(atoi(env));
        curl_free(env);
      }
    
      memset(&outs,0,sizeof(outs));
    
    
      /* we get libcurl info right away */
      curlinfo = curl_version_info(CURLVERSION_NOW);
    
    
      errorbuffer[0]=0; /* prevent junk from being output */
    
    
      /* inits */
      if (main_init() != CURLE_OK) {
        helpf("error initializing curl library\n");
        return CURLE_FAILED_INIT;
      }
    
      config->showerror=TRUE;
      config->conf=CONF_DEFAULT;
    
      config->lastrecvtime = curlx_tvnow();
      config->lastsendtime = curlx_tvnow();
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(argc>1 &&
    
         (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
         strchr(argv[1], 'q')) {
        /*
         * The first flag, that is not a verbose name, but a shortname
         * and it includes the 'q' flag!
         */
        ;
      }
      else {
    
        parseconfig(NULL, config);
    
      if ((argc < 2)  && !config->url_list) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        helpf(NULL);
    
        return CURLE_FAILED_INIT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      /* Parse options */
      for (i = 1; i < argc; i++) {
        if(stillflags &&
           ('-' == argv[i][0])) {
          char *nextarg;
          bool passarg;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    	/* this indicates the end of the flags and thus enables the
    	   following (URL) argument to start with -. */
    	stillflags=FALSE;
          else {
    	nextarg= (i < argc - 1)? argv[i+1]: NULL;
    
    
    	res = getparameter(flag, nextarg, &passarg, config);
    
              const char *reason = param2text(res);
              if(res != PARAM_HELP_REQUESTED)
                helpf("option %s: %s\n", origopt, reason);
    
              clean_getout(config);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    	if(passarg) /* we're supposed to skip this */
    	  i++;
          }
        }
        else {
    
          bool used;
          /* just add the URL please */
    
          res = getparameter((char *)"--url", argv[i], &used, config);
    
          if(res)
            return res;
    
      if(!config->url_list || !config->url_list->url) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        helpf("no URL specified!\n");
    
        return CURLE_FAILED_INIT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      if(NULL == config->useragent) {
    
        /* set non-zero default values: */
        snprintf(useragent, sizeof(useragent),
                 CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
    
        config->useragent= useragent;
    
      else
        allocuseragent = TRUE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /* On WIN32 (non-cygwin), we can't set the path to curl-ca-bundle.crt
       * at compile time. So we look here for the file in two ways:
       * 1: look at the environment variable CURL_CA_BUNDLE for a path
       * 2: if #1 isn't found, use the windows API function SearchPath()
       *    to find it along the app's path (includes app's dir and CWD)
       *
       * We support the environment variable thing for non-Windows platforms
       * too. Just for the sake of it.
       */
    
      if (!config->cacert &&
          !config->capath &&
          !config->insecure_ok) {
    
          curl_free(env);
    
        }
    #if defined(WIN32) && !defined(__CYGWIN32__)
    
        else
          FindWin32CACert(config, "curl-ca-bundle.crt");
    
      if (config->postfields) {
        if (config->use_httpget) {
          /* Use the postfields data for a http get */
          httpgetfields = strdup(config->postfields);
          free(config->postfields);
          config->postfields = NULL;
    
          if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
                            &config->httpreq)) {
    
            free(httpgetfields);
            return PARAM_BAD_USE;
          }
        }
        else {
          if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
            return PARAM_BAD_USE;
        }
      }
    
    
      /*
       * Get a curl handle to use for all forthcoming curl transfers.  Cleanup
    
       */
      curl = curl_easy_init();
    
        return CURLE_FAILED_INIT;
    
      /* After this point, we should call curl_easy_cleanup() if we decide to bail
       * out from this function! */
    
    
      urlnode = config->url_list;
    
      if(config->headerfile) {
        /* open file for output: */
        if(strcmp(config->headerfile,"-")) {
          heads.filename = config->headerfile;
          headerfilep=NULL;
        }
        else
          headerfilep=stdout;
        heads.stream = headerfilep;
        heads.config = config;
      }
    
    
      /* loop through the list of given URLs */
    
        /* get the full URL (it might be NULL) */
    
        if(NULL == url) {
          /* This node had no URL, skip it and continue to the next */
          if(urlnode->outfile)
            free(urlnode->outfile);
    
          /* move on to the next URL */
          nextnode=urlnode->next;
          free(urlnode); /* free the node */
          urlnode = nextnode;
          continue; /* next please */
        }
    
    
        /* default output stream is stdout */
        outs.stream = stdout;
        outs.config = config;
    
        /* save outfile pattern before expansion */
        outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;
    
        infiles = urlnode->infile;
    
        if(!config->globoff && infiles) {
          /* Unless explicitly shut off */
          res = glob_url(&inglob, infiles, &infilenum,
    
                         config->showerror?
                         (config->errors?config->errors:stderr):NULL);
    
          if(res != CURLE_OK) {
            clean_getout(config);
    
            if(outfiles)
              free(outfiles);
    
        /* Here's the loop for uploading multiple files within the same
           single globbed string. If no upload, we enter the loop once anyway. */
        for(up = 0;
            (!up && !infiles) ||
              (uploadfile = inglob?
               glob_next_url(inglob):
               (!up?strdup(infiles):NULL));
            up++) {
          uploadfilesize=-1;
    
          if(!config->globoff) {
            /* Unless explicitly shut off, we expand '{...}' and '[...]'
               expressions and return total number of URLs in pattern set */
            res = glob_url(&urls, dourl, &urlnum,
                           config->showerror?
                           (config->errors?config->errors:stderr):NULL);
            if(res != CURLE_OK) {
              break;
            }
          }
    
          else
            urlnum = 1; /* without globbing, this is a single URL */
    
          /* if multiple files extracted to stdout, insert separators! */
    
          separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
    
          /* Here's looping around each globbed URL */
          for(i = 0;
              (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
              i++) {
            char *outfile;
            outfile = outfiles?strdup(outfiles):NULL;
    
            if((urlnode->flags&GETOUT_USEREMOTE) ||
    
               (outfile && !curlx_strequal("-", outfile)) ) {
    
               * We have specified a file name to store the result in, or we have
               * decided we want to use the remote file name.
               */
    
              if(!outfile) {
                /* Find and get the remote file name */
                char * pc =strstr(url, "://");
                if(pc)
                  pc+=3;
                else
                  pc=url;
                pc = strrchr(pc, '/');
    
                if(pc) {
                  /* duplicate the string beyond the slash */
                  pc++;
                  outfile = *pc ? strdup(pc): NULL;
                }
                if(!outfile || !*outfile) {
                  helpf("Remote file name has no length!\n");
                  res = CURLE_WRITE_ERROR;