Skip to content
Snippets Groups Projects
main.c 91.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
          go_sleep ( (size*nmemb)*1000/config->recvpersecond - timediff*1000 );
          now = time(NULL);
        }
        config->lastrecvtime = now;
      }
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      return fwrite(buffer, size, nmemb, out->stream);
    }
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    struct InStruct {
      FILE *stream;
      struct Configurable *config;
    };
    
    int my_fread(void *buffer, size_t size, size_t nmemb, void *userp)
    {
      struct InStruct *in=(struct InStruct *)userp;
    
      struct Configurable *config = in->config;
    
      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!
         */
    
        time_t timediff;
        time_t now;
    
        now = time(NULL);
        timediff = now - config->lastsendtime;
        if( config->lastsendsize > config->sendpersecond*timediff) {
          /* figure out how many milliseconds to rest */
          go_sleep ( config->lastsendsize*1000/config->sendpersecond -
                     timediff*1000 );
          now = time(NULL);
        }
        config->lastsendtime = now;
    
        if(size*nmemb > config->sendpersecond) {
          /* lower the size to actually read */
          nmemb = config->sendpersecond;
          size = 1;
        }
        config->lastsendsize = size*nmemb;    
      }
    
    
      return fread(buffer, size, nmemb, in->stream);
    }
    
    
      FILE *out; /* where to write everything to */
    
                    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 inherites 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->point = dlnow + ulnow; /* we've come this far */
    
    
        int prevblock = (int)bar->prev / 1024;
        int thisblock = (int)bar->point / 1024;
    
          fprintf( bar->out, "#" );
    
        frac = bar->point / total;
    
        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));
    
    /* 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 */
      colp = curl_getenv("COLUMNS");
      if (colp != NULL) {
        bar->width = atoi(colp);
        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, %d bytes (0x%x)\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(curl_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);
    
    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->infile)
        free(config->infile);
      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)
    {
      curl_version_info_data *info;
      info = curl_version_info(CURLVERSION_NOW);
    
      /* only check for cert file if "we" support SSL */
      if(info->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
    
    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;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int separator = 0;
      
      FILE *infd = stdin;
      FILE *headerfilep = NULL;
      char *urlbuffer=NULL;
      int infilesize=-1; /* -1 means unknown */
      bool stillflags=TRUE;
    
    
      bool allocuseragent=FALSE;
    
    
      CURL *curl;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      int i;
    
    
    #ifdef MALLOCDEBUG
      /* this sends all memory debug messages to a logfile named memdump */
    
      env = curl_getenv("CURL_MEMDEBUG");
      if(env) {
        free(env);
        curl_memdebug("memdump");
      }
    
      errorbuffer[0]=0; /* prevent junk from being output */
    
    
      config->showerror=TRUE;
      config->conf=CONF_DEFAULT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      if(argc>1 &&
    
         (!curl_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 {
    
        res = parseconfig(NULL, config);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if(res)
          return res;
      }
    
    
      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
    
    
    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);
    
    	if(res) {
              switch(res) {
              case PARAM_OPTION_AMBIGUOUS:
                helpf("option %s is ambiguous\n", origopt);
                break;
              case PARAM_OPTION_UNKNOWN:
                helpf("option %s is unknown\n", origopt);
                break;
              case PARAM_REQUIRES_PARAMETER:
                helpf("option %s requires an extra argument!\n", origopt);
                break;
              case PARAM_BAD_USE:
                helpf("option %s was wrongly used!\n", origopt);
                break;
              case PARAM_HELP_REQUESTED:
                /* no text */
                break;
              }
    
              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) {
    
        env = curl_getenv("CURL_CA_BUNDLE");
        if(env) {
          GetStr(&config->cacert, env);
          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
       * when all transfers are done. This is supported with libcurl 7.7 and
       * should not be attempted on previous versions.
       */
      curl = curl_easy_init();
      if(!curl)
        return CURLE_FAILED_INIT;
    
    
      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 */
      while(urlnode) {
    
        /* get the full URL (it might be NULL) */
    
        url=urlnode->url;
    
    
        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;
    
    
        if(!config->globoff) {
          /* Unless explicitly shut off, we expand '{...}' and '[...]' expressions
             and return total number of URLs in pattern set */
          res = glob_url(&urls, url, &urlnum);
          if(res != CURLE_OK)
            return res;
        }
    
    
    
        /* save outfile pattern before expansion */
        outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;
    
    
        if ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1) {
    
          /* multiple files extracted to stdout, insert separators! */
          separator = 1;
    
        for(i = 0;
            (url = urls?next_url(urls):(i?NULL:strdup(url)));
            i++) {
    
          char *outfile;
          outfile = outfiles?strdup(outfiles):NULL;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     
    
          if((urlnode->flags&GETOUT_USEREMOTE) ||
    
             (outfile && !curl_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, '/');
              outfile = (char *) NULL == pc ? NULL : strdup(pc+1) ;
              if(!outfile) {
                helpf("Remote file name has no length!\n");
                return CURLE_WRITE_ERROR;
              }
            }
    
              /* fill '#1' ... '#9' terms from URL pattern */
              char *storefile = outfile;
              outfile = match_url(storefile, urls);
              free(storefile);
    
            /* Create the directory hierarchy, if not pre-existant to a multiple
               file output call */
            
    
            if(config->create_dirs)
              if (-1 == create_dir_hierarchy(outfile))
                return CURLE_WRITE_ERROR;
    
              /* We're told to continue from where we are now. Get the
                 size of the file as it is now and open it for append instead */
              
    
              struct stat fileinfo;
    
    
              /*VMS?? -- Danger, the filesize is only valid for stream files */
    
              if(0 == stat(outfile, &fileinfo))
    
                /* set offset to current file size: */
                config->resume_from = fileinfo.st_size;
    
              else
                /* let offset be 0 */
                config->resume_from = 0;
    
            if(config->resume_from) {
              /* open file for output: */
              outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
              if (!outs.stream) {
                helpf("Can't open '%s'!\n", outfile);
                return CURLE_WRITE_ERROR;
              }
    
            else {
              outs.filename = outfile;
              outs.stream = NULL; /* open when needed */
    
          }
          if(config->infile) {
            /*
             * We have specified a file to upload
             */
            struct stat fileinfo;
    
            /* If no file name part is given in the URL, we add this file name */
            char *ptr=strstr(url, "://");
    
            if(ptr)
    
              ptr+=3;
    
              ptr=url;
            ptr = strrchr(ptr, '/');
            if(!ptr || !strlen(++ptr)) {
              /* The URL has no file name part, add the local file name. In order
                 to be able to do so, we have to create a new URL in another
                 buffer.*/
    
    
              /* We only want the part of the local path that is on the right
                 side of the rightmost slash and backslash. */
              char *filep = strrchr(config->infile, '/');
              char *file2 = strrchr(filep?filep:config->infile, '\\');
    
              if(file2)
                filep = file2+1;
              else if(filep)
                filep++;
              else
                filep = config->infile;
    
    
              /* URL encode the file name */
              filep = curl_escape(filep, 0 /* use strlen */);
    
              if(filep) {
    
                urlbuffer=(char *)malloc(strlen(url) + strlen(filep) + 3);
                if(!urlbuffer) {
                  helpf("out of memory\n");
                  return CURLE_OUT_OF_MEMORY;
                }
                if(ptr)
                  /* there is a trailing slash on the URL */
                  sprintf(urlbuffer, "%s%s", url, filep);
                else
                  /* thers is no trailing slash on the URL */
                  sprintf(urlbuffer, "%s/%s", url, filep);
                
                curl_free(filep);
    
                free(url);
                url = urlbuffer; /* use our new URL instead! */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*VMS??-- Reading binary from files can be a problem... */
    /*VMS??   Only FIXED, VAR etc WITHOUT implied CC will work */
    /*VMS??   Others need a \n appended to a line */
    /*VMS??-- Stat gives a size but this is UNRELIABLE in VMS */
    /*VMS??   As a f.e. a fixed file with implied CC needs to have a byte added */
    /*VMS??   for every record processed, this can by derived from Filesize & recordsize */
    /*VMS??   for VARiable record files the records need to be counted! */
    /*VMS??   for every record add 1 for linefeed and subtract 2 for the record header */
    /*VMS??   for VARIABLE header files only the bare record data needs to be considered with one appended if implied CC */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
            infd=(FILE *) fopen(config->infile, "rb");
            if (!infd || stat(config->infile, &fileinfo)) {
              helpf("Can't open '%s'!\n", config->infile);
              return CURLE_READ_ERROR;
            }
            infilesize=fileinfo.st_size;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
          if((config->conf&CONF_UPLOAD) &&
    
            config->resume_from = -1; /* -1 will then force get-it-yourself */
          }
          if(outs.stream && isatty(fileno(outs.stream)) &&
             !(config->conf&(CONF_UPLOAD|CONF_HTTPPOST)))
            /* we send the output to a tty and it isn't an upload operation,
               therefore we switch off the progress meter */
            config->conf |= CONF_NOPROGRESS;
    
          if (urlnum > 1 && !(config->conf&CONF_MUTE)) {
    
            fprintf(stderr, "\n[%d/%d]: %s --> %s\n",
                    i+1, urlnum, url, outfile ? outfile : "<stdout>");
            if (separator)
              printf("%s%s\n", CURLseparator, url);
    
            /* Find out whether the url contains a file name */
            char *pc =strstr(url, "://");
    
            pc = strrchr(pc, '/'); /* check for a slash */
    
            if(pc) {
              /* there is a slash present in the URL */
    
              if(strchr(pc, '?'))
              /* Ouch, there's already a question mark in the URL string, we
                 then appead the data with an amperand separator instead! */
                separator='&';
            }
    
            /*
             * Then append ? followed by the get fields to the url.
             */
            urlbuffer=(char *)malloc(strlen(url) + strlen(httpgetfields) + 2);
            if(!urlbuffer) {
              helpf("out of memory\n");
              return CURLE_OUT_OF_MEMORY;
            }
    
              sprintf(urlbuffer, "%s%c%s", url, separator, httpgetfields);
    
              /* Append  / before the ? to create a well-formed url
                 if the url contains a hostname only
              */
    
              sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
     
    
            free(url); /* free previous URL */
            url = urlbuffer; /* use our new URL instead! */
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          if(!config->errors)
            config->errors = stderr;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #if defined(WIN32) && !defined(__CYGWIN32__)
    
          if(!outfile && !(config->conf & CONF_GETTEXT)) {
            /* We get the output to stdout and we have not got the ASCII/text flag,
               then set stdout to be binary */
            setmode( 1, O_BINARY );
          }
    
          curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
          curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* where to store */
          curl_easy_setopt(curl, CURLOPT_WRITEDATA, (FILE *)&outs);
          /* what call to write */
    
          curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
          /* for uploads */
          input.stream = infd;
          input.config = config;
          curl_easy_setopt(curl, CURLOPT_READDATA, &input);
          /* what call to read */
          curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
    
          if(config->recvpersecond) {
            /* tell libcurl to use a smaller sized buffer as it allows us to
               make better sleeps! 7.9.9 stuff! */
            curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
          }
    
    
          /* size of uploaded file: */
          curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize);
          curl_easy_setopt(curl, CURLOPT_URL, url);     /* what to fetch */
          curl_easy_setopt(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
          curl_easy_setopt(curl, CURLOPT_HEADER, config->conf&CONF_HEADER);
          curl_easy_setopt(curl, CURLOPT_NOPROGRESS, config->conf&CONF_NOPROGRESS);
          curl_easy_setopt(curl, CURLOPT_NOBODY, config->conf&CONF_NOBODY);
          curl_easy_setopt(curl, CURLOPT_FAILONERROR,
                           config->conf&CONF_FAILONERROR);
          curl_easy_setopt(curl, CURLOPT_UPLOAD, config->conf&CONF_UPLOAD);
          curl_easy_setopt(curl, CURLOPT_FTPLISTONLY,
                           config->conf&CONF_FTPLISTONLY);
          curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
    
    
          if (config->conf&CONF_NETRC_OPT)
            curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
          else if (config->conf&CONF_NETRC)
            curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
          else
            curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
    
    
          curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
                           config->conf&CONF_FOLLOWLOCATION);
    
          curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
                           config->conf&CONF_UNRESTRICTED_AUTH);
    
          curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, config->conf&CONF_GETTEXT);
          curl_easy_setopt(curl, CURLOPT_MUTE, config->conf&CONF_MUTE);
          curl_easy_setopt(curl, CURLOPT_USERPWD, config->userpwd);
          curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
          curl_easy_setopt(curl, CURLOPT_RANGE, config->range);
          curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
          curl_easy_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
          curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config->postfields);
    
          /* new in libcurl 7.2: */
          curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, config->postfieldsize);
    
          curl_easy_setopt(curl, CURLOPT_REFERER, config->referer);
          curl_easy_setopt(curl, CURLOPT_AUTOREFERER,
                           config->conf&CONF_AUTO_REFERER);
          curl_easy_setopt(curl, CURLOPT_USERAGENT, config->useragent);
          curl_easy_setopt(curl, CURLOPT_FTPPORT, config->ftpport);
          curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
          curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
          curl_easy_setopt(curl, CURLOPT_RESUME_FROM,
                           config->use_resume?config->resume_from:0);
          curl_easy_setopt(curl, CURLOPT_COOKIE, config->cookie);
          curl_easy_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
          curl_easy_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
          curl_easy_setopt(curl, CURLOPT_SSLCERT, config->cert);
    
          curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
          curl_easy_setopt(curl, CURLOPT_SSLKEY, config->key);
          curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
          curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, config->key_passwd);
    
          /* default to strict verifyhost */
          curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
    
          if(config->cacert || config->capath) {
    
            if (config->cacert)
              curl_easy_setopt(curl, CURLOPT_CAINFO, config->cacert);
    
            if (config->capath)
              curl_easy_setopt(curl, CURLOPT_CAPATH, config->capath);
    
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
          }
    
              /* new stuff needed for libcurl 7.10 */
              curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    
              curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
            }
    
          if((config->conf&CONF_NOBODY) ||
             config->remote_time) {
    
            /* no body or use remote time */
            curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
          }
          
          if (config->maxredirs) 
            curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); 
          else 
            curl_easy_setopt(curl, CURLOPT_MAXREDIRS, DEFAULT_MAXREDIRS); 
    
          curl_easy_setopt(curl, CURLOPT_CRLF, config->crlf);
          curl_easy_setopt(curl, CURLOPT_QUOTE, config->quote);
          curl_easy_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
          curl_easy_setopt(curl, CURLOPT_WRITEHEADER,
                           config->headerfile?&heads:NULL);
          curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config->cookiefile);
    
          /* cookie jar was added in 7.9 */
          curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config->cookiejar);
    
          /* cookie session added in 7.9.7 */
          curl_easy_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
    
    
          curl_easy_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
          curl_easy_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
          curl_easy_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
          curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
          curl_easy_setopt(curl, CURLOPT_STDERR, config->errors);
    
          /* three new ones in libcurl 7.3: */
          curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
          curl_easy_setopt(curl, CURLOPT_INTERFACE, config->iface);
          curl_easy_setopt(curl, CURLOPT_KRB4LEVEL, config->krb4level);
          
          if((config->progressmode == CURL_PROGRESS_BAR) &&
             !(config->conf&(CONF_NOPROGRESS|CONF_MUTE))) {
            /* we want the alternative style, then we have to implement it
               ourselves! */
    
            progressbarinit(&progressbar, config);
    
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
            curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
          }
    
          /* new in libcurl 7.6.2: */
          curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
    
    
          /* new in libcurl 7.7: */
          curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, config->random_file);
          curl_easy_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
    
          curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
    
    
          if(config->cipher_list)
            curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
    
    
          if(config->httpversion)
            curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
          /* new in libcurl 7.9.2: */
          if(config->disable_epsv)
            /* disable it */
            curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
    
    
          /* new in curl 7.9.7 */
          if(config->trace_dump) {
            curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
            curl_easy_setopt(curl, CURLOPT_DEBUGDATA, config);
    
            config->conf |= CONF_VERBOSE; /* force verbose */
    
          curl_easy_setopt(curl, CURLOPT_VERBOSE, config->conf&CONF_VERBOSE);
    
          /* new in curl 7.10 */
          curl_easy_setopt(curl, CURLOPT_ENCODING, 
                           (config->encoding) ? "deflate" : NULL);
    
    
          res = curl_easy_perform(curl);
    
          if((config->progressmode == CURL_PROGRESS_BAR) &&
             progressbar.calls) {
    
            /* if the custom progress bar has been displayed, we output a
               newline here */
            fputs("\n", progressbar.out);
          }
    
    
          if(config->writeout) {
            ourWriteOut(curl, config->writeout);
    
    #ifdef USE_ENVIRONMENT
          if (config->writeenv)
            ourWriteEnv(curl);
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef	VMS
    
          if (!config->showerror)  {
            vms_show = VMSSTS_HIDE;
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #else
    
          if((res!=CURLE_OK) && config->showerror) {
            if(CURLE_SSL_CACERT == res) {
              fprintf(config->errors, "curl: (%d) %s\n\n", res, errorbuffer);
    #define CURL_CA_CERT_ERRORMSG \
    "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
    "curl does peer SSL certificate verification by default. If you\n" \
    "communicate with HTTPS servers using certificates that are signed by CAs\n" \
    "present in the bundle, you will get truly secure SSL connections.\n" \
    "Since you get this error, you probably forgot to point out a working CA\n" \
    "cert for your server, or you forgot to use the -k (or --insecure) option.\n"
    
              fprintf(config->errors, "%s", CURL_CA_CERT_ERRORMSG);
            }
            else
              fprintf(config->errors, "curl: (%d) %s\n", res, errorbuffer);
          }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          if (outfile && !curl_strequal(outfile, "-") && outs.stream)
    
            fclose(outs.stream);
    
    
    #ifdef HAVE_UTIME
          /* Important that we set the time _after_ the file has been 
             closed, as is done above here */
          if(config->remote_time && outs.filename) {
            /* as libcurl if we got a time. Pretty please */
            long filetime;
            curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
            if(filetime >= 0) {
              struct utimbuf times;
              times.actime = filetime;
              times.modtime = filetime;