Skip to content
Snippets Groups Projects
main.c 60.7 KiB
Newer Older
          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 */
Daniel Stenberg's avatar
Daniel Stenberg committed
      if(nextarg[0] == '-') {
        /* prefixed with a dash makes it a POST TRANSFER one */
        nextarg++;
        config->postquote = curl_slist_append(config->postquote, nextarg);
      }
      else {
        config->quote = curl_slist_append(config->quote, nextarg);
      }
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'r':
      /* byte range requested */
      GetStr(&config->range, nextarg);
      break;
    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 */
      config->telnet_options = curl_slist_append(config->telnet_options, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'T':
      /* we are uploading */
      config->conf |= CONF_UPLOAD;
      if(!strequal("-", nextarg))
        /* make - equal stdin */
        GetStr(&config->infile, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      break;
    case 'U':
      /* Proxy user:password  */
      GetStr(&config->proxyuserpwd, nextarg);
      break;
    case 'v':
      config->conf ^= CONF_VERBOSE; /* talk a lot */
      break;
    case 'V':
      printf(CURL_ID "%s\n", curl_version());
      if('@' == *nextarg) {
        /* the data begins with a '@' letter, it means that a file name
           or - (stdin) follows */
        FILE *file;
        nextarg++; /* pass the @ */
        if(strequal("-", nextarg))
          file = stdin;
        else 
          file = fopen(nextarg, "r");
        config->writeout = file2string(file);
        if(file && (file != stdin))
          fclose(stdin);
      }
      else 
        GetStr(&config->writeout, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'x':
      /* proxy */
      GetStr(&config->proxy, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'X':
      /* HTTP request */
      GetStr(&config->customrequest, nextarg);
      if(SetHTTPrequest(HTTPREQ_CUSTOM, &config->httpreq))
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'y':
Daniel Stenberg's avatar
Daniel Stenberg committed
      /* low speed time */
      config->low_speed_time = atoi(nextarg);
      if(!config->low_speed_limit)
	config->low_speed_limit = 1;
      break;
    case 'Y':
Daniel Stenberg's avatar
Daniel Stenberg committed
      /* low speed limit */
      config->low_speed_limit = atoi(nextarg);
      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 = TIMECOND_IFMODSINCE;
        break;
      case '-':
        /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
        config->timecond = TIMECOND_IFUNMODSINCE;
        nextarg++;
        break;
      case '=':
        /* Last-Modified:  (section 14.29 in RFC2068) */
        config->timecond = 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 = TIMECOND_NONE;
        }
        else {
          /* pull the time out from the file */
          config->condtime = statbuf.st_mtime;
        }
      }
      break;
    case 'Z':
      /* specified max no of redirects (http(s)) */
      config->maxredirs = atoi(nextarg);
      break;
Daniel Stenberg's avatar
Daniel Stenberg committed

    default: /* unknown flag */
Daniel Stenberg's avatar
Daniel Stenberg committed
    }
    hit = -1;

  } while(!singleopt && *++parse && !*usedarg);
Daniel Stenberg's avatar
Daniel Stenberg committed

Daniel Stenberg's avatar
Daniel Stenberg committed
}


static int parseconfig(char *filename,
		       struct Configurable *config)
{
  int res;
  FILE *file;
  char filebuffer[256];
  bool usedarg;
  char *home=NULL;
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"

    home = curl_getenv("HOME"); /* portable environment reader */
    if(strlen(home)>(sizeof(filebuffer)-strlen(CURLRC))) {
      free(home);
Daniel Stenberg's avatar
Daniel Stenberg committed

    sprintf(filebuffer, "%s%s%s", home, DIR_CHAR, CURLRC);

    filename = filebuffer;
  }

  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! */
      while(isspace((int)*line))
        line++;

      switch(*line) {
      case '#':
      case '/':
      case '\r':
      case '\n':
      case '*':
      case '\0':
Daniel Stenberg's avatar
Daniel Stenberg committed

      /* the option keywords starts here */
      option = line;
      while(*line && !isspace((int)*line) && !isseparator(*line))
        line++;
      /* ... and has ended here */

      *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(isspace((int)*line) || isseparator(*line))
        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
      }
#ifdef DEBUG_CONFIG
      fprintf(stderr, "PARAM: \"%s\"\n", param);
#endif
      res = getparameter(option, param, &usedarg, config);
      if(*param && !usedarg)
        /* 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;
          switch(res) {
          default:
          case PARAM_GOT_EXTRA_PARAMETER:
            reason = "had unsupported trailing garbage";
            break;
          case PARAM_OPTION_UNKNOWN:
            reason = "is unknown";
            break;
          case PARAM_OPTION_AMBIGUOUS:
            reason = "is ambiguous";
            break;
          case PARAM_REQUIRES_PARAMETER:
            reason = "requires parameter";
            break;
          case PARAM_BAD_USE:
            reason = "is badly used here";
          fprintf(stderr, "%s:%d: warning: '%s' %s\n",
                  filename, lineno, option, reason);
Daniel Stenberg's avatar
Daniel Stenberg committed
    }
    if(file != stdin)
      fclose(file);
  }
  if(home)
    free(home);
Daniel Stenberg's avatar
Daniel Stenberg committed
}

struct OutStruct {
  char *filename;
  FILE *stream;
  struct Configurable *config;
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
Daniel Stenberg's avatar
Daniel Stenberg committed
{
  struct OutStruct *out=(struct OutStruct *)stream;
  if(out && !out->stream) {
    /* open file for writing */
    out->stream=fopen(out->filename, "wb");
    if(!out->stream)
      return -1; /* failure */
    if(out->config->nobuffer) {
      /* disable output buffering */
#ifdef HAVE_SETVBUF
      setvbuf(out->stream, NULL, _IONBF, 0);
#endif
    }
Daniel Stenberg's avatar
Daniel Stenberg committed
  }
  return fwrite(buffer, size, nmemb, out->stream);
}

struct ProgressData {
  size_t total;
  size_t prev;
  size_t point;
  int width;
  FILE *out; /* where to write everything to */
};

int myprogress (void *clientp,
                size_t dltotal,
                size_t dlnow,
                size_t ultotal,
                size_t 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];
  float frac;
  float percent;
  int barwidth;
  int num;
  int i;

  struct ProgressData *bar = (struct ProgressData *)clientp;
  size_t total = dltotal + ultotal;

  bar->point = dlnow + ulnow; /* we've come this far */

  if(0 == total) {
    int prevblock = bar->prev / 1024;
    int thisblock = bar->point / 1024;
    while ( thisblock > prevblock ) {
      fprintf( bar->out, "#" );
      prevblock++;
    }
  }
  else {
    frac = (float) bar->point / (float) total;
    percent = frac * 100.0f;
    barwidth = bar->width - 7;
    num = (int) (((float)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

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);

  curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
  curl_slist_free_all(config->postquote); /*  */
  curl_slist_free_all(config->headers); /*  */
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

  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 */
  curl_memdebug("memdump");
#endif

  config->showerror=TRUE;
  config->conf=CONF_DEFAULT;
Daniel Stenberg's avatar
Daniel Stenberg committed

  if(argc>1 &&
     (!strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
     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

      if(strequal("--", argv[i]))
	/* 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) {
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

  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;
  /* 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 || 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 && !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);
          /* we're told to continue where we are now, then we get the size of
             the file as it is now and open it for append instead */
          struct stat fileinfo;

Daniel Stenberg's avatar
Daniel Stenberg committed
/*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 remain 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.*/

          urlbuffer=(char *)malloc(strlen(url) + strlen(config->infile) + 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, config->infile);
          else
            /* thers is no trailing slash on the URL */
            sprintf(urlbuffer, "%s/%s", url, config->infile);
          
          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(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;
      }
      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) {
        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_FILE, (FILE *)&outs); /* where to store */
      /* what call to write: */
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
      curl_easy_setopt(curl, CURLOPT_INFILE, infd); /* for uploads */
      /* 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_VERBOSE, config->conf&CONF_VERBOSE);
      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);
      curl_easy_setopt(curl, CURLOPT_NETRC, config->conf&CONF_NETRC);
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
                       config->conf&CONF_FOLLOWLOCATION);
      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_SSLCERTPASSWD, config->cert_passwd);

      if(config->cacert) {
        /* available from libcurl 7.5: */
        curl_easy_setopt(curl, CURLOPT_CAINFO, config->cacert);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
      else
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
      if(config->conf&(CONF_NOBODY|CONF_USEREMOTETIME)) {
        /* no body or use remote time */
        /* new in 7.5 */
        curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
      }
      
      /* 7.5 news: */
      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);
      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);