Skip to content
Snippets Groups Projects
main.c 58.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
            /* 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);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          if(((unsigned ) ~0) == 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="<stdin>";
            }
            if(PARAM_HELP_REQUESTED != res) {
              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("--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
    
    
      /*
       * 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);
    
    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);
    
            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);
    
          
          res = curl_easy_perform(curl);
    
          if(config->writeout) {
            ourWriteOut(curl, config->writeout);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef	VMS
    	if (!config->showerror)  {
    		vms_show = VMSSTS_HIDE;
    	}
    #else
    
          if((res!=CURLE_OK) && config->showerror)
            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((config->errors != stderr) &&
             (config->errors != stdout))
            /* it wasn't directed to stdout or stderr so close the file! */
            fclose(config->errors);
        
          if(config->headerfile && !headerfilep && heads.stream)
            fclose(heads.stream);
    
          if(urlbuffer)
            free(urlbuffer);
          if (outfile && !strequal(outfile, "-") && outs.stream)
            fclose(outs.stream);
          if (config->infile)
            fclose(infd);
          if(headerfilep)
            fclose(headerfilep);
          
          if(url)
            free(url);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
          if(outfile)
            free(outfile);
    
        if(outfiles)
          free(outfiles);
    
        if(urls)
          /* cleanup memory used for URL globbing patterns */
          glob_cleanup(urls);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        /* empty this urlnode struct */
        if(urlnode->url)
          free(urlnode->url);
        if(urlnode->outfile)
          free(urlnode->outfile);