Skip to content
Snippets Groups Projects
main.c 54.2 KiB
Newer Older
Daniel Stenberg's avatar
Daniel Stenberg committed
/*****************************************************************************
 *                                  _   _ ____  _     
 *  Project                     ___| | | |  _ \| |    
 *                             / __| | | | |_) | |    
 *                            | (__| |_| |  _ <| |___ 
 *                             \___|\___/|_| \_\_____|
 *
Daniel Stenberg's avatar
Daniel Stenberg committed
 * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
Daniel Stenberg's avatar
Daniel Stenberg committed
 *
Daniel Stenberg's avatar
Daniel Stenberg committed
 * In order to be useful for every potential user, curl and libcurl are
 * dual-licensed under the MPL and the MIT/X-derivate licenses.
Daniel Stenberg's avatar
Daniel Stenberg committed
 *
Daniel Stenberg's avatar
Daniel Stenberg committed
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the MPL or the MIT/X-derivate
 * licenses. You may pick one of these licenses.
Daniel Stenberg's avatar
Daniel Stenberg committed
 *
Daniel Stenberg's avatar
Daniel Stenberg committed
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
Daniel Stenberg's avatar
Daniel Stenberg committed
 *
Daniel Stenberg's avatar
Daniel Stenberg committed
 * $Id$
 *****************************************************************************/
Daniel Stenberg's avatar
Daniel Stenberg committed

/* This is now designed to have its own local setup.h */
#include "setup.h"

Daniel Stenberg's avatar
Daniel Stenberg committed
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
Daniel Stenberg's avatar
Daniel Stenberg committed
#include <sys/stat.h>
#include <ctype.h>

#include <curl/curl.h>
Daniel Stenberg's avatar
Daniel Stenberg committed

#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
Daniel Stenberg's avatar
Daniel Stenberg committed
#include <curl/mprintf.h>
Daniel Stenberg's avatar
Daniel Stenberg committed
#include "urlglob.h"
#include "writeout.h"

Daniel Stenberg's avatar
Daniel Stenberg committed
#define CURLseparator	"--_curl_--"
#if defined(WIN32)&&!defined(__CYGWIN32__)
Daniel Stenberg's avatar
Daniel Stenberg committed
#include <winsock.h>
#endif

Daniel Stenberg's avatar
Daniel Stenberg committed
#include "version.h"

#ifdef HAVE_IO_H /* typical win32 habit */
#include <io.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

/* The last #include file should be: */
#ifdef MALLOCDEBUG
/* this is low-level hard-hacking memory leak tracking shit */
#include "../lib/memdebug.h"
#endif

#define DEFAULT_MAXREDIRS  50L
Daniel Stenberg's avatar
Daniel Stenberg committed
#ifndef __cplusplus        /* (rabe) */
typedef char bool;
#endif                     /* (rabe) */

#define CURL_PROGRESS_STATS 0 /* default progress display */
#define CURL_PROGRESS_BAR   1

typedef enum {
  HTTPREQ_UNSPEC,
  HTTPREQ_GET,
  HTTPREQ_HEAD,
  HTTPREQ_POST,
  HTTPREQ_SIMPLEPOST,
  HTTPREQ_CUSTOM,
  HTTPREQ_LAST
} HttpReq;

/* Just a set of bits */
#define CONF_DEFAULT  0
#define CONF_USEREMOTETIME (1<<0) /* set the remote time on the local file */
#define CONF_AUTO_REFERER (1<<4) /* the automatic referer-system please! */
#define CONF_VERBOSE  (1<<5) /* talk a lot */
#define CONF_HEADER   (1<<8) /* throw the header out too */
#define CONF_NOPROGRESS (1<<10) /* shut off the progress meter */
#define CONF_NOBODY   (1<<11) /* use HEAD to get http document */
#define CONF_FAILONERROR (1<<12) /* no output on http error codes >= 300 */
#define CONF_UPLOAD   (1<<14) /* this is an upload */
#define CONF_FTPLISTONLY (1<<16) /* Use NLST when listing ftp dir */
#define CONF_FTPAPPEND (1<<20) /* Append instead of overwrite on upload! */
#define CONF_NETRC    (1<<22)  /* read user+password from .netrc */
#define CONF_FOLLOWLOCATION (1<<23) /* use Location: Luke! */
#define CONF_GETTEXT  (1<<24) /* use ASCII/text for transfer */
#define CONF_HTTPPOST (1<<25) /* multipart/form-data HTTP POST */
#define CONF_MUTE     (1<<28) /* force NOPROGRESS */

#ifndef HAVE_STRDUP
/* Ultrix doesn't have strdup(), so make a quick clone: */
char *strdup(char *str)
{
  int len;
  char *newstr;

  len = strlen(str);
  newstr = (char *) malloc((len+1)*sizeof(char));
  if (!newstr)
    return (char *)NULL;

  strcpy(newstr,str);

  return newstr;

}
#endif 

Daniel Stenberg's avatar
Daniel Stenberg committed
extern void hugehelp(void);

/*
 * This is the main global constructor for the app. Call this before
 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
 * used, or havoc may be the result.
 */
CURLcode main_init(void)
  return curl_global_init(CURL_GLOBAL_DEFAULT);
}

/*
 * This is the main global destructor for the app. Call this after
 * _all_ libcurl usage is done.
 */
void main_free(void)
{
int SetHTTPrequest(HttpReq req, HttpReq *store)
{
  if((*store == HTTPREQ_UNSPEC) ||
     (*store == req)) {
    *store = req;
  }
  fprintf(stderr, "You can only select one HTTP request!\n");
Daniel Stenberg's avatar
Daniel Stenberg committed
static void helpf(char *fmt, ...)
{
  va_list ap;
  if(fmt) {
    va_start(ap, fmt);
    fputs("curl: ", stderr); /* prefix it */
    vfprintf(stderr, fmt, ap);
    va_end(ap);
  }
  fprintf(stderr, "curl: try 'curl --help' for more information\n");
}

/*
 * A chain of these nodes contain URL to get and where to put the URL's
 * contents.
 */
struct getout {
  struct getout *next;
  char *url;
  char *outfile;
  int flags;
};
#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
#define GETOUT_URL     (1<<1) /* set when URL is deemed done */
#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */

Daniel Stenberg's avatar
Daniel Stenberg committed
static void help(void)
{
  printf(CURL_ID "%s\n"
       "Usage: curl [options...] <url>\n"
       "Options: (H) means HTTP/HTTPS only, (F) means FTP only\n"
       " -a/--append        Append to target file when uploading (F)\n"
       " -A/--user-agent <string> User-Agent to send to server (H)\n"
       " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)\n"
       " -B/--use-ascii     Use ASCII/text transfer\n",
         curl_version());
  puts(" -C/--continue-at <offset> Specify absolute resume offset\n"
       " -d/--data <data>   HTTP POST data (H)\n"
       "    --data-ascii <data>   HTTP POST ASCII data (H)\n"
       "    --data-binary <data>  HTTP POST binary data (H)\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -D/--dump-header <file> Write the headers to this file\n"
       "    --egd-file <file> EGD socket path for random data (SSL)\n"
       " -e/--referer       Referer page (H)");
  puts(" -E/--cert <cert[:passwd]> Specifies your certificate file and password (HTTPS)\n"
       "    --cacert <file> CA certifciate to verify peer against (HTTPS)\n"
       "    --connect-timeout <seconds> Maximum time allowed for connection\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -f/--fail          Fail silently (no output at all) on errors (H)\n"
       " -F/--form <name=content> Specify HTTP POST data (H)\n"
       " -g/--globoff       Disable URL sequences and ranges using {} and []\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -h/--help          This help text\n"
       " -H/--header <line> Custom header to pass to server. (H)");
  puts(" -i/--include       Include the HTTP-header in the output (H)\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -I/--head          Fetch document info only (HTTP HEAD/FTP SIZE)\n"
       "    --interface <interface> Specify the interface to be used\n"
       "    --krb4 <level>  Enable krb4 with specified security level (F)\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -K/--config        Specify which config file to read\n"
       " -l/--list-only     List only names of an FTP directory (F)");
  puts(" -L/--location      Follow Location: hints (H)\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -m/--max-time <seconds> Maximum time allowed for the transfer\n"
       " -M/--manual        Display huge help text\n"
       " -n/--netrc         Read .netrc for user name and password\n"
       " -N/--no-buffer     Disables the buffering of the output stream");
  puts(" -o/--output <file> Write output to <file> instead of stdout\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -O/--remote-name   Write output to a file named as the remote file\n"
       " -p/--proxytunnel   Perform non-HTTP services through a HTTP proxy\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -P/--ftpport <address> Use PORT with address instead of PASV when ftping (F)\n"
       " -q                 When used as the first parameter disables .curlrc\n"
       " -Q/--quote <cmd>   Send QUOTE command to FTP before file transfer (F)");
  puts(" -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -s/--silent        Silent mode. Don't output anything\n"
       " -S/--show-error    Show error. With -s, make curl show errors when they occur\n"
       "    --stderr <file> Where to redirect stderr. - means stdout.\n"
       " -t/--telnet-option <OPT=val> Set telnet option\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -T/--upload-file <file> Transfer/upload <file> to remote site\n"
       "    --url <URL>     Another way to specify URL to work with");
  puts(" -u/--user <user[:password]> Specify user and password to use\n"
       " -U/--proxy-user <user[:password]> Specify Proxy authentication\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -v/--verbose       Makes the operation more talkative\n"
       " -V/--version       Outputs version number then quits\n"
       " -w/--write-out [format] What to output after completion\n"
       " -x/--proxy <host[:port]>  Use proxy. (Default port is 1080)\n"
       "    --random-file <file> File to use for reading random data from (SSL)\n"
       " -X/--request <command> Specific request command to use");
  puts(" -y/--speed-time    Time needed to trig speed-limit abort. Defaults to 30\n"
       " -Y/--speed-limit   Stop transfer if below speed-limit for 'speed-time' secs\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -z/--time-cond <time> Includes a time condition to the server (H)\n"
       " -Z/--max-redirs <num> Set maximum number of redirections allowed (H)\n"
Daniel Stenberg's avatar
Daniel Stenberg committed
       " -2/--sslv2         Force usage of SSLv2 (H)\n"
       " -3/--sslv3         Force usage of SSLv3 (H)");
  puts(" -#/--progress-bar  Display transfer progress as a progress bar\n"
       "    --crlf          Convert LF to CRLF in upload. Useful for MVS (OS/390)");
Daniel Stenberg's avatar
Daniel Stenberg committed
}

struct LongShort {
  char *letter;
  char *lname;
  bool extraparam;
};

struct Configurable {
  char *random_file;
  char *egd_file;
Daniel Stenberg's avatar
Daniel Stenberg committed
  char *useragent;
  char *cookie;
  bool use_resume;
Daniel Stenberg's avatar
Daniel Stenberg committed
  int resume_from;
  char *postfields;
  long postfieldsize;
Daniel Stenberg's avatar
Daniel Stenberg committed
  char *referer;
  long timeout;
  long connecttimeout;
Daniel Stenberg's avatar
Daniel Stenberg committed
  char *headerfile;
  char *ftpport;
  char *iface;
Daniel Stenberg's avatar
Daniel Stenberg committed
  unsigned short porttouse;
  char *range;
  int low_speed_limit;
  int low_speed_time;
  bool showerror;
  char *infile;
  char *userpwd;
  char *proxyuserpwd;
  char *proxy;
  bool configread;
  bool proxytunnel;
Daniel Stenberg's avatar
Daniel Stenberg committed
  long conf;

  struct getout *url_list; /* point to the first node */
  struct getout *url_last; /* point to the last/current node */

  struct getout *url_get;  /* point to the node to fill in URL */
  struct getout *url_out;  /* point to the node to fill in outfile */

Daniel Stenberg's avatar
Daniel Stenberg committed
  char *cert;
  char *cacert;
Daniel Stenberg's avatar
Daniel Stenberg committed
  char *cert_passwd;
  bool crlf;
  char *cookiefile;
  char *customrequest;
  char *krb4level;
Daniel Stenberg's avatar
Daniel Stenberg committed
  bool progressmode;
Daniel Stenberg's avatar
Daniel Stenberg committed

  char *writeout; /* %-styled format string to output */

Daniel Stenberg's avatar
Daniel Stenberg committed
  FILE *errors; /* if stderr redirect is requested */

  struct curl_slist *quote;
Daniel Stenberg's avatar
Daniel Stenberg committed
  struct curl_slist *postquote;
Daniel Stenberg's avatar
Daniel Stenberg committed

  long ssl_version;
  TimeCond timecond;
  time_t condtime;

Daniel Stenberg's avatar
Daniel Stenberg committed

  struct HttpPost *httppost;
  struct HttpPost *last_post;
  struct curl_slist *telnet_options;
        
Daniel Stenberg's avatar
Daniel Stenberg committed
};

static int parseconfig(char *filename,
		       struct Configurable *config);
Daniel Stenberg's avatar
Daniel Stenberg committed

static void GetStr(char **string,
		   char *value)
{
  if(*string)
    free(*string);
  if(value && *value)
    *string = strdup(value);
  else
    *string = NULL;
Daniel Stenberg's avatar
Daniel Stenberg committed
}

static char *file2string(FILE *file)
{
  char buffer[256];
  char *ptr;
  char *string=NULL;
  int len=0;
  int stringlen;

  if(file) {
    while(fgets(buffer, sizeof(buffer), file)) {
      ptr= strchr(buffer, '\r');
      if(ptr)
        *ptr=0;
      ptr= strchr(buffer, '\n');
      if(ptr)
        *ptr=0;
      stringlen=strlen(buffer);
      if(string)
        string = realloc(string, len+stringlen+1);
      else
        string = malloc(stringlen+1);

      strcpy(string+len, buffer);

      len+=stringlen;
    }
    return string;
  }
  else
    return NULL; /* no string */
}

static char *file2memory(FILE *file, long *size)
{
  char buffer[1024];
  char *string=NULL;
  char *newstring=NULL;
  long len=0;
  long stringlen=0;

  if(file) {
    while((len = fread(buffer, 1, sizeof(buffer), file))) {
      if(string) {
        newstring = realloc(string, len+stringlen);
        if(newstring)
          string = newstring;
        else
          break; /* no more strings attached! :-) */
      }
      else
        string = malloc(len);
      memcpy(&string[stringlen], buffer, len);
      stringlen+=len;
    }
    *size = stringlen;
    return string;
  }
  else
    return NULL; /* no string */
}

void clean_getout(struct Configurable *config)
{
  struct getout *node=config->url_list;
  struct getout *next;

  while(node) {
    next = node->next;
    if(node->url)
      free(node->url);
    if(node->outfile)
      free(node->outfile);
    free(node);

    node = next; /* GOTO next */
  }
}

struct getout *new_getout(struct Configurable *config)
{
  struct getout *node =malloc(sizeof(struct getout));
  struct getout *last= config->url_last;
  if(node) {
    /* clear the struct */
    memset(node, 0, sizeof(struct getout));
        
    /* append this new node last in the list */
    if(last)
      last->next = node;
    else
      config->url_list = node; /* first node */
            
    /* move the last pointer */
    config->url_last = node;
  }
  return node;
}




typedef enum {
  PARAM_OK,
  PARAM_OPTION_AMBIGUOUS,
  PARAM_OPTION_UNKNOWN,
  PARAM_REQUIRES_PARAMETER,  
  PARAM_BAD_USE,
  PARAM_HELP_REQUESTED,
  PARAM_GOT_EXTRA_PARAMETER,

  PARAM_LAST
} ParameterError;

static ParameterError getparameter(char *flag, /* f or -long-flag */
                                   char *nextarg, /* NULL if unset */
                                   bool *usedarg, /* set to TRUE if the arg
                                                     has been used */
                                   struct Configurable *config)
Daniel Stenberg's avatar
Daniel Stenberg committed
{
  char letter;
  char subletter=0; /* subletters can only occur on long options */

Daniel Stenberg's avatar
Daniel Stenberg committed
  char *parse=NULL;
  int res;
  int j;
  time_t now;
  int hit=-1;
  bool longopt=FALSE;
  bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */

Daniel Stenberg's avatar
Daniel Stenberg committed

  /* single-letter,
     long-name,
     boolean whether it takes an additional argument
     */
  struct LongShort aliases[]= {
    {"9", "crlf",        FALSE},
    {"8", "stderr",      TRUE},
    {"7", "interface",   TRUE},
    {"6", "krb4",        TRUE},
    {"5a", "random-file", TRUE},
    {"5b", "egd-file",   TRUE},
    {"5c", "connect-timeout", TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed

    {"2", "sslv2",       FALSE},
    {"3", "sslv3",       FALSE},
    {"a", "append",      FALSE},
    {"A", "user-agent",  TRUE},
    {"b", "cookie",      TRUE},
    {"B", "ftp-ascii",   FALSE}, /* this long format is OBSOLETEE now! */
    {"B", "use-ascii",   FALSE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"c", "continue",    FALSE},
    {"C", "continue-at", TRUE},
    {"d", "data",        TRUE},
    {"da", "data-ascii", TRUE},
    {"db", "data-binary", TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"D", "dump-header", TRUE},
    {"e", "referer",     TRUE},
    {"E", "cert",        TRUE},
    {"Ea", "cacert",     TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"f", "fail",        FALSE},
    {"F", "form",        TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"h", "help",        FALSE},
    {"H", "header",      TRUE},
    {"i", "include",     FALSE},
    {"I", "head",        FALSE},
    {"K", "config",      TRUE},
    {"l", "list-only",   FALSE},
    {"L", "location",    FALSE},
    {"m", "max-time",    TRUE},
    {"M", "manual",      FALSE},
    {"n", "netrc",       FALSE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"o", "output",      TRUE},
    {"O", "remote-name", FALSE},
    {"p", "proxytunnel", FALSE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"P", "ftpport",     TRUE},
    {"q", "disable",     FALSE},
    {"Q", "quote",       TRUE},
    {"r", "range",       TRUE},
    {"s", "silent",      FALSE},
    {"S", "show-error",  FALSE},
    {"t", "telnet-options", TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"T", "upload-file", TRUE},
    {"u", "user",        TRUE},
    {"U", "proxy-user",  TRUE},
    {"v", "verbose",     FALSE},
    {"V", "version",     FALSE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"x", "proxy",       TRUE},
    {"X", "request",     TRUE},
    {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
    {"Y", "speed-limit",  TRUE},
    {"y", "speed-time", TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"z", "time-cond",   TRUE},
    {"Z", "max-redirs",   TRUE},
Daniel Stenberg's avatar
Daniel Stenberg committed
    {"#", "progress-bar",FALSE},
  };

  if(('-' != flag[0]) ||
     (('-' == flag[0]) && ('-' == flag[1]))) {
    /* this should be a long name */
    char *word=('-' == flag[0])?flag+2:flag;
    int fnam=strlen(word);
    int numhits=0;
Daniel Stenberg's avatar
Daniel Stenberg committed
    for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
      if(strnequal(aliases[j].lname, word, fnam)) {
        longopt = TRUE;
        numhits++;
        if(strequal(aliases[j].lname, word)) {
Daniel Stenberg's avatar
Daniel Stenberg committed
          parse = aliases[j].letter;
          hit = j;
          numhits = 1; /* a single unique hit */
Daniel Stenberg's avatar
Daniel Stenberg committed
          break;
        }
	parse = aliases[j].letter;
	hit = j;
      }
    }
    if(numhits>1) {
      /* this is at least the second match! */
Daniel Stenberg's avatar
Daniel Stenberg committed
    if(hit < 0) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    }    
  }
  else {
    flag++; /* prefixed with one dash, pass it */
Daniel Stenberg's avatar
Daniel Stenberg committed
    hit=-1;
    parse = flag;
  }

  do {
    /* we can loop here if we have multiple single-letters */

    if(!longopt)
      letter = parse?*parse:'\0';
    else {
      letter = parse[0];
      subletter = parse[1];
    }
Daniel Stenberg's avatar
Daniel Stenberg committed
    *usedarg = FALSE; /* default is that we don't use the arg */

#if 0
    fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
#endif
    if(hit < 0) {
      for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
	if(letter == aliases[j].letter[0]) {
Daniel Stenberg's avatar
Daniel Stenberg committed
	  hit = j;
	  break;
	}
      }
      if(hit < 0) {
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
    }
    if(hit < 0) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    }    
    if(!longopt && aliases[hit].extraparam && parse[1]) {
      nextarg=&parse[1]; /* this is the actual extra parameter */
      singleopt=TRUE;   /* don't loop anymore after this */
    }
    else if((!nextarg || !*nextarg) && aliases[hit].extraparam) {
Daniel Stenberg's avatar
Daniel Stenberg committed
    }
    else if(nextarg && aliases[hit].extraparam)
      *usedarg = TRUE; /* mark it as used */

    switch(letter) {
    case '9': /* there is no short letter for this */
      /* LF -> CRLF conversinon? */
      config->crlf = TRUE;
      break;
    case '8': /* there is no short letter for this */
      if(strcmp(nextarg, "-"))
        config->errors = fopen(nextarg, "wt");
      else
        config->errors = stdout;
      break;
    case '7': /* there is no short letter for this */
      /* interface */
      GetStr(&config->iface, nextarg);
      break;
    case '6': /* there is no short letter for this */
      /* krb4 level string */
      GetStr(&config->krb4level, nextarg);
      break;
      switch(subletter) {
      case 'a': /* random-file */
        GetStr(&config->random_file, nextarg);
        break;
      case 'b': /* egd-file */
        GetStr(&config->egd_file, nextarg);
        break;
      case 'c': /* connect-timeout */
        config->connecttimeout=atoi(nextarg);
        break;
      default: /* the URL! */
        {
          struct getout *url;
          if(config->url_get || (config->url_get=config->url_list)) {
            /* there's a node here, if it already is filled-in continue to find
               an "empty" node */
            while(config->url_get && (config->url_get->flags&GETOUT_URL))
              config->url_get = config->url_get->next;
          }
          /* now there might or might not be an available node to fill in! */
          if(config->url_get)
            /* existing node */
            url = config->url_get;
          else
            /* there was no free node, create one! */
            url=new_getout(config);
          
          if(url) {
            /* fill in the URL */
            GetStr(&url->url, nextarg);
            url->flags |= GETOUT_URL;
          }
Daniel Stenberg's avatar
Daniel Stenberg committed
    case '#': /* added 19990617 larsa */
      config->progressmode ^= CURL_PROGRESS_BAR;
      break;
    case '2': 
      /* SSL version 2 */
      config->ssl_version = 2;
      break;
    case '3': 
      /* SSL version 2 */
      config->ssl_version = 3;
      break;
    case 'a':
      /* This makes the FTP sessions use APPE instead of STOR */
      config->conf ^= CONF_FTPAPPEND;
      break;
    case 'A':
      /* This specifies the User-Agent name */
      GetStr(&config->useragent, nextarg);
      break;
    case 'b': /* cookie string coming up: */
      if(nextarg[0] == '@') {
        nextarg++;
      }
      else if(strchr(nextarg, '=')) {
Daniel Stenberg's avatar
Daniel Stenberg committed
        /* A cookie string must have a =-letter */
        GetStr(&config->cookie, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
      /* We have a cookie file to read from! */
      GetStr(&config->cookiefile, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'B':
      /* use ASCII/text when transfering */
      config->conf ^= CONF_GETTEXT;
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'c':
      /* This makes us continue an ftp transfer */
      config->use_resume^=TRUE;
      fprintf(stderr, "-c is a deprecated switch, use '-C -' instead!\n");
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'C':
      /* This makes us continue an ftp transfer at given position */
        config->resume_from= atoi(nextarg);
        config->resume_from_current = FALSE;
      }
      else {
        config->resume_from_current = TRUE;
        config->resume_from = 0;
      }
Daniel Stenberg's avatar
Daniel Stenberg committed
      config->use_resume=TRUE;
      break;
    case 'd':
      /* postfield data */
      {
        char *postdata=NULL;

        if('@' == *nextarg) {
          /* the data begins with a '@' letter, it means that a file name
             or - (stdin) follows */
          FILE *file;

          nextarg++; /* pass the @ */

          if(strequal("-", nextarg))
            file = stdin;
          else 
            file = fopen(nextarg, "r");

          if(subletter == 'b') /* forced binary */
            postdata = file2memory(file, &config->postfieldsize);
          else
            postdata = file2string(file);
          if(file && (file != stdin))
            fclose(stdin);
        }
        else {
          GetStr(&postdata, nextarg);
        }
        if(config->postfields && *config->postfields) {
          /* we already have a string, we append this one
             with a separating &-letter */
          char *oldpost=config->postfields;
          config->postfields=aprintf("%s&%s", oldpost, postdata);
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
      if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'D':
      /* dump-header to given file name */
      GetStr(&config->headerfile, nextarg);
      break;
    case 'e':
      {
        char *ptr = strstr(nextarg, ";auto");
        if(ptr) {
          /* Automatic referer requested, this may be combined with a
             set initial one */
          config->conf |= CONF_AUTO_REFERER;
          *ptr = 0; /* zero terminate here */
        }
        GetStr(&config->referer, nextarg);
      }
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'E':
      if(subletter == 'a') {
        /* CA info PEM file */
        GetStr(&config->cacert, nextarg);
      }
      else {
Daniel Stenberg's avatar
Daniel Stenberg committed
	char *ptr = strchr(nextarg, ':');
	if(ptr) {
	  /* we have a password too */
	  *ptr=0;
	  ptr++;
	  GetStr(&config->cert_passwd, ptr);
	}
	GetStr(&config->cert, nextarg);
      }
      break;
    case 'f':
      /* fail hard on errors  */
      config->conf ^= CONF_FAILONERROR;
      break;
    case 'F':
      /* "form data" simulation, this is a little advanced so lets do our best
	 to sort this out slowly and carefully */
Daniel Stenberg's avatar
Daniel Stenberg committed
                        &config->httppost,
                        &config->last_post))
      if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;

    case 'g': /* g disables URLglobbing */
      config->globoff ^= TRUE;
      break;

Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'h': /* h for help */
      help();
Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'H':
      /* A custom header to append to a list */
      config->headers = curl_slist_append(config->headers, nextarg);
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'i':
      config->conf ^= CONF_HEADER; /* include the HTTP header as well */
      break;
    case 'I':
      config->conf ^= CONF_HEADER; /* include the HTTP header in the output */
      config->conf ^= CONF_NOBODY; /* don't fetch the body at all */
      if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'K':
      res = parseconfig(nextarg, config);
      config->configread = TRUE;
      if(res)
	return res;
      break;
    case 'l':
      config->conf ^= CONF_FTPLISTONLY; /* only list the names of the FTP dir */
      break;
    case 'L':
      config->conf ^= CONF_FOLLOWLOCATION; /* Follow Location: HTTP headers */
      break;
    case 'm':
      /* specified max time */
      config->timeout = atoi(nextarg);
      break;
    case 'M': /* M for manual, huge help */
      hugehelp();
Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'n':
      /* pick info from .netrc, if this is used for http, curl will
	 automatically enfore user+password with the request */
      config->conf ^= CONF_NETRC;
      break;
    case 'N':
      /* disable the output I/O buffering */
      config->nobuffer ^= 1;
      break;
Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'o':
    case 'O':
      /* output file */
      {
        struct getout *url;
        if(config->url_out || (config->url_out=config->url_list)) {
          /* there's a node here, if it already is filled-in continue to find
             an "empty" node */
          while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
            config->url_out = config->url_out->next;
        }

        /* now there might or might not be an available node to fill in! */

        if(config->url_out)
          /* existing node */
          url = config->url_out;
        else
          /* there was no free node, create one! */
          url=new_getout(config);

        if(url) {
          /* fill in the outfile */
          if('o' == letter)
            GetStr(&url->outfile, nextarg);
          else {
            url->outfile=NULL; /* leave it */
            url->flags |= GETOUT_USEREMOTE;
          }
          url->flags |= GETOUT_OUTFILE;
        }
      }
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
    case 'P':
      /* This makes the FTP sessions use PORT instead of PASV */
      /* use <eth0> or <192.168.10.10> style addresses. Anything except
	 this will make us try to get the "default" address.
	 NOTE: this is a changed behaviour since the released 4.1!
	 */
      GetStr(&config->ftpport, nextarg);
      break;
    case 'p':
      /* proxy tunnel for non-http protocols */
      config->proxytunnel ^= TRUE;
Daniel Stenberg's avatar
Daniel Stenberg committed
      break;
Daniel Stenberg's avatar
Daniel Stenberg committed
    case 'q': /* if used first, already taken care of, we do it like
		 this so we don't cause an error! */
      break;
    case 'Q':
      /* QUOTE command to send to FTP server */
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) {