Newer
Older
}
}
}
else {
fprintf(stderr, "Illegally formatted input field!\n");
return 1;
}
free(contents);
return 0;
}
typedef enum {
PARAM_OK,
PARAM_OPTION_AMBIGUOUS,
PARAM_OPTION_UNKNOWN,
PARAM_BAD_USE,
PARAM_HELP_REQUESTED,
PARAM_GOT_EXTRA_PARAMETER,
PARAM_BAD_NUMERIC,
PARAM_LIBCURL_DOESNT_SUPPORT,
PARAM_NO_MEM,
PARAM_LAST
} ParameterError;
Daniel Stenberg
committed
static const char *param2text(int res)
Daniel Stenberg
committed
ParameterError error = (ParameterError)res;
switch(error) {
case PARAM_GOT_EXTRA_PARAMETER:
return "had unsupported trailing garbage";
case PARAM_OPTION_UNKNOWN:
return "is unknown";
case PARAM_OPTION_AMBIGUOUS:
return "is ambiguous";
case PARAM_REQUIRES_PARAMETER:
return "requires parameter";
case PARAM_BAD_USE:
return "is badly used here";
case PARAM_BAD_NUMERIC:
return "expected a proper numerical parameter";
case PARAM_LIBCURL_DOESNT_SUPPORT:
return "the installed libcurl version doesn't support this";
case PARAM_NO_MEM:
return "out of memory";
default:
return "unknown error";
}
}
static void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
/* now that GetStr has copied the contents of nextarg, wipe the next
* argument out so that the username:password isn't displayed in the
* system process list */
if (str) {
size_t len = strlen(str);
memset(str, ' ', len);
}
#else
(void)str;
#endif
}
/*
* Parse the string and write the integer in the given address. Return
* non-zero on failure, zero on success.
*
* The string must start with a digit to be valid.
*/
static int str2num(long *val, char *str)
{
int retcode = 0;
if(isdigit((int)*str))
*val = atoi(str);
else
retcode = 1; /* badness */
}
/**
* Parses the given string looking for an offset (which may be
* a larger-than-integer value).
*
* @param val the offset to populate
* @param str the buffer containing the offset
* @return zero if successful, non-zero if failure.
*/
static int str2offset(curl_off_t *val, char *str)
/* Ugly, but without going through a bunch of rigmarole, we don't have the
* definitions for LLONG_{MIN,MAX} or LONG_LONG_{MIN,MAX}.
#ifdef _MSC_VER
#define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFi64
#define LLONG_MIN (curl_off_t)0x8000000000000000i64
#else
#define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFLL
#define LLONG_MIN (curl_off_t)0x8000000000000000LL
#endif
Daniel Stenberg
committed
/* this is a duplicate of the function that is also used in libcurl */
Daniel Stenberg
committed
*val = curlx_strtoofft(str, NULL, 0);
if ((*val == LLONG_MAX || *val == LLONG_MIN) && errno == ERANGE)
return 1;
#else
*val = strtol(str, NULL, 0);
if ((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
return 1;
#endif
return 0;
}
static void checkpasswd(const char *kind, /* for what purpose */
char **userpwd) /* pointer to allocated string */
{
Daniel Stenberg
committed
char *ptr;
if(!*userpwd)
return;
ptr = strchr(*userpwd, ':');
if(!ptr) {
/* no password present, prompt for one */
char passwd[256]="";
size_t passwdlen;
size_t userlen = strlen(*userpwd);
Daniel Stenberg
committed
curlx_msnprintf(prompt, sizeof(prompt),
"Enter %s password for user '%s':",
kind, *userpwd);
/* get password */
getpass_r(prompt, passwd, sizeof(passwd));
passwdlen = strlen(passwd);
/* extend the allocated memory area to fit the password too */
passptr = realloc(*userpwd,
passwdlen + 1 + /* an extra for the colon */
userlen + 1); /* an extra for the zero */
/* append the password separated with a colon */
passptr[userlen]=':';
memcpy(&passptr[userlen+1], passwd, passwdlen+1);
*userpwd = passptr;
}
}
}
static ParameterError add2list(struct curl_slist **list,
char *ptr)
{
struct curl_slist *newlist = curl_slist_append(*list, ptr);
if(newlist)
*list = newlist;
else
return PARAM_NO_MEM;
return PARAM_OK;
}
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)
char subletter=0; /* subletters can only occur on long options */
const char *parse=NULL;
unsigned int j;
bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
ParameterError err;
/* single-letter,
long-name,
boolean whether it takes an additional argument
*/
static const struct LongShort aliases[]= {
/* all these ones, starting with "*" or "$" as a short-option have *no*
short option to mention. */
{"*", "url", TRUE},
{"*a", "random-file", TRUE},
{"*b", "egd-file", TRUE},
{"*c", "connect-timeout", TRUE},
{"*d", "ciphers", TRUE},
{"*e", "disable-epsv", FALSE},
#ifdef USE_ENVIRONMENT
{"*g", "trace", TRUE},
{"*h", "trace-ascii", TRUE},
{"*i", "limit-rate", TRUE},
{"*j", "compressed", FALSE}, /* might take an arg someday */
{"*k", "digest", FALSE},
{"*l", "negotiate", FALSE},
{"*m", "ntlm", FALSE},
{"*n", "basic", FALSE},
{"*o", "anyauth", FALSE},
{"*r", "create-dirs", FALSE},
{"*s", "max-redirs", TRUE},
{"*t", "proxy-ntlm", FALSE},
{"*u", "crlf", FALSE},
{"*v", "stderr", TRUE},
{"*w", "interface", TRUE},
{"*x", "krb4", TRUE},
{"*y", "max-filesize", TRUE},
{"*z", "disable-eprt", FALSE},
{"$b", "ftp-pasv", FALSE},
{"$e", "proxy-digest", FALSE},
{"$f", "proxy-basic", FALSE},
Daniel Stenberg
committed
{"$g", "retry", TRUE},
{"$h", "retry-delay", TRUE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
{"4", "ipv4", FALSE},
{"6", "ipv6", FALSE},
{"a", "append", FALSE},
{"A", "user-agent", TRUE},
{"b", "cookie", TRUE},
{"B", "use-ascii", FALSE},
{"C", "continue-at", TRUE},
{"d", "data", TRUE},
{"da", "data-ascii", TRUE},
{"db", "data-binary", TRUE},
{"D", "dump-header", TRUE},
{"e", "referer", TRUE},
{"E", "cert", TRUE},
{"Eb","cert-type", TRUE},
{"Ec","key", TRUE},
{"Ed","key-type", TRUE},
{"Ee","pass", TRUE},
{"Ef","engine", TRUE},
Daniel Stenberg
committed
{"g", "globoff", FALSE},
Daniel Stenberg
committed
{"G", "get", FALSE},
{"h", "help", FALSE},
{"H", "header", TRUE},
{"i", "include", FALSE},
{"I", "head", FALSE},
{"j", "junk-session-cookies", FALSE},
{"K", "config", TRUE},
{"l", "list-only", FALSE},
{"L", "location", FALSE},
{"Lt", "location-trusted", FALSE},
{"m", "max-time", TRUE},
{"M", "manual", FALSE},
{"n", "netrc", FALSE},
{"no", "netrc-optional", FALSE},
{"N", "no-buffer", FALSE},
{"o", "output", TRUE},
{"O", "remote-name", FALSE},
{"P", "ftpport", TRUE}, /* older version */
{"P", "ftp-port", TRUE},
{"q", "disable", FALSE},
{"Q", "quote", TRUE},
{"r", "range", TRUE},
{"R", "remote-time", FALSE},
{"s", "silent", FALSE},
{"S", "show-error", FALSE},
{"t", "telnet-options", TRUE},
{"T", "upload-file", TRUE},
{"u", "user", TRUE},
{"U", "proxy-user", TRUE},
{"v", "verbose", FALSE},
{"V", "version", FALSE},
Daniel Stenberg
committed
{"w", "write-out", TRUE},
{"x", "proxy", TRUE},
{"X", "request", TRUE},
{"X", "http-request", TRUE}, /* OBSOLETE VERSION */
{"Y", "speed-limit", TRUE},
{"y", "speed-time", TRUE},
{"z", "time-cond", TRUE},
{"#", "progress-bar",FALSE},
};
if(('-' != flag[0]) ||
(('-' == flag[0]) && ('-' == flag[1]))) {
/* this should be a long name */
char *word=('-' == flag[0])?flag+2:flag;
for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
Daniel Stenberg
committed
if(curlx_strnequal(aliases[j].lname, word, fnam)) {
Daniel Stenberg
committed
if(curlx_strequal(aliases[j].lname, word)) {
numhits = 1; /* a single unique hit */
parse = aliases[j].letter;
hit = j;
if(numhits>1) {
/* this is at least the second match! */
return PARAM_OPTION_AMBIGUOUS;
return PARAM_OPTION_UNKNOWN;
flag++; /* prefixed with one dash, pass it */
hit=-1;
parse = flag;
}
do {
/* we can loop here if we have multiple single-letters */
else {
letter = parse[0];
subletter = parse[1];
}
*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]) {
hit = j;
break;
}
return PARAM_OPTION_UNKNOWN;
return PARAM_OPTION_UNKNOWN;
Daniel Stenberg
committed
if(!longopt && aliases[hit].extraparam && parse[1]) {
nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
singleopt=TRUE; /* don't loop anymore after this */
}
else if(!nextarg && aliases[hit].extraparam) {
return PARAM_REQUIRES_PARAMETER;
}
else if(nextarg && aliases[hit].extraparam)
*usedarg = TRUE; /* mark it as used */
switch(letter) {
case '*': /* options without a short option */
switch(subletter) {
case 'a': /* random-file */
GetStr(&config->random_file, nextarg);
break;
case 'b': /* egd-file */
GetStr(&config->egd_file, nextarg);
break;
if(str2num(&config->connecttimeout, nextarg))
return PARAM_BAD_NUMERIC;
case 'd': /* ciphers */
GetStr(&config->cipher_list, nextarg);
break;
case 'e': /* --disable-epsv */
config->disable_epsv ^= TRUE;
break;
#ifdef USE_ENVIRONMENT
case 'f':
config->writeenv ^= TRUE;
break;
#endif
Daniel Stenberg
committed
case 'g': /* --trace */
GetStr(&config->trace_dump, nextarg);
break;
case 'h': /* --trace-ascii */
GetStr(&config->trace_dump, nextarg);
config->trace_ascii = TRUE;
Daniel Stenberg
committed
break;
case 'i': /* --limit-rate */
{
/* We support G, M, K too */
char *unit;
Daniel Stenberg
committed
curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
switch(nextarg[strlen(nextarg)-1]) {
case 'G':
case 'g':
value *= 1024*1024*1024;
break;
case 'M':
case 'm':
value *= 1024*1024;
break;
case 'K':
case 'k':
value *= 1024;
break;
}
config->recvpersecond = value;
config->sendpersecond = value;
}
break;
case 'j': /* --compressed */
config->encoding ^= TRUE;
break;
config->authtype = CURLAUTH_DIGEST;
break;
case 'l': /* --negotiate */
if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
config->authtype = CURLAUTH_GSSNEGOTIATE;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
if(curlinfo->features & CURL_VERSION_NTLM)
config->authtype = CURLAUTH_NTLM;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
case 'n': /* --basic for completeness */
config->authtype = CURLAUTH_BASIC;
break;
case 'o': /* --anyauth, let libcurl pick it */
config->authtype = CURLAUTH_ANY;
break;
#ifdef __DJGPP__
case 'p': /* --wdebug */
dbug_init();
break;
#endif
case 'q': /* --ftp-create-dirs */
config->ftp_create_dirs ^= TRUE;
break;
case 'r': /* --create-dirs */
config->create_dirs = TRUE;
break;
case 's': /* --max-redirs */
/* specified max no of redirects (http(s)) */
if(str2num(&config->maxredirs, nextarg))
return PARAM_BAD_NUMERIC;
break;
if(curlinfo->features & CURL_VERSION_NTLM)
config->proxyntlm ^= TRUE;
else
case 'u': /* --crlf */
/* LF -> CRLF conversinon? */
config->crlf = TRUE;
break;
case 'v': /* --stderr */
if(strcmp(nextarg, "-")) {
config->errors = fopen(nextarg, "wt");
config->errors_fopened = TRUE;
}
else
config->errors = stdout;
break;
case 'w': /* --interface */
/* interface */
GetStr(&config->iface, nextarg);
break;
case 'x': /* --krb4 */
/* krb4 level string */
if(curlinfo->features & CURL_VERSION_KERBEROS4)
GetStr(&config->krb4level, nextarg);
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
case 'y': /* --max-filesize */
if(str2offset(&config->max_filesize, nextarg))
return PARAM_BAD_NUMERIC;
break;
case 'z': /* --disable-eprt */
config->disable_eprt ^= TRUE;
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;
}
break;
case '$': /* more options without a short option */
switch(subletter) {
case 'a': /* --ftp-ssl */
config->ftp_ssl ^= TRUE;
break;
case 'b': /* --ftp-pasv */
if(config->ftpport)
free(config->ftpport);
config->ftpport = NULL;
break;
case 'c': /* --socks specifies a socks5 proxy to use */
GetStr(&config->socks5proxy, nextarg);
break;
config->tcp_nodelay ^= TRUE;
break;
case 'e': /* --proxy-digest */
config->proxydigest ^= TRUE;
break;
case 'f': /* --proxy-basic */
config->proxybasic ^= TRUE;
break;
Daniel Stenberg
committed
case 'g': /* --retry */
if(str2num(&config->req_retry, nextarg))
return PARAM_BAD_NUMERIC;
break;
case 'h': /* --retry-delay */
if(str2num(&config->retry_delay, nextarg))
return PARAM_BAD_NUMERIC;
break;
case 'i': /* --retry-max-time */
if(str2num(&config->retry_maxtime, nextarg))
return PARAM_BAD_NUMERIC;
/* break */
case '#': /* added 19990617 larsa */
config->progressmode ^= CURL_PROGRESS_BAR;
break;
/* HTTP version 1.0 */
config->httpversion = CURL_HTTP_VERSION_1_0;
break;
case '1':
/* TLS version 1 */
config->ssl_version = CURL_SSLVERSION_TLSv1;
break;
config->ssl_version = CURL_SSLVERSION_SSLv2;
/* SSL version 3 */
config->ssl_version = CURL_SSLVERSION_SSLv3;
/* IPv4 */
config->ip_version = 4;
break;
/* IPv6 */
config->ip_version = 6;
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, '=')) {
/* A cookie string must have a =-letter */
GetStr(&config->cookie, nextarg);
break;
/* We have a cookie file to read from! */
GetStr(&config->cookiefile, nextarg);
/* use ASCII/text when transfering */
config->conf ^= CONF_GETTEXT;
/* get the file name to dump all cookies in */
GetStr(&config->cookiejar, nextarg);
break;
case 'C':
/* This makes us continue an ftp transfer at given position */
Daniel Stenberg
committed
if(!curlx_strequal(nextarg, "-")) {
if(str2offset(&config->resume_from, nextarg))
return PARAM_BAD_NUMERIC;
Daniel Stenberg
committed
config->resume_from_current = FALSE;
}
else {
config->resume_from_current = TRUE;
config->resume_from = 0;
}
config->use_resume=TRUE;
break;
case 'd':
/* postfield data */
Daniel Stenberg
committed
{
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 @ */
Daniel Stenberg
committed
if(curlx_strequal("-", nextarg))
Daniel Stenberg
committed
file = stdin;
file = fopen(nextarg, "rb");
Daniel Stenberg
committed
if(subletter == 'b') /* forced binary */
postdata = file2memory(file, &config->postfieldsize);
else
postdata = file2string(file);
if(file && (file != stdin))
fclose(file);
Daniel Stenberg
committed
}
else {
GetStr(&postdata, nextarg);
}
if(config->postfields) {
Daniel Stenberg
committed
/* 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
committed
free(oldpost);
free(postdata);
}
Daniel Stenberg
committed
config->postfields=postdata;
Daniel Stenberg
committed
/*
We can't set the request type here, as this data might be used in
a simple GET if -G is used. Already or soon.
Daniel Stenberg
committed
if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;
*/
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);
}
switch(subletter) {
case 'a': /* CA info PEM file */
/* CA info PEM file */
GetStr(&config->cacert, nextarg);
break;
case 'b': /* cert file type */
GetStr(&config->cert_type, nextarg);
break;
case 'c': /* private key file */
GetStr(&config->key, nextarg);
break;
case 'd': /* private key file type */
GetStr(&config->key_type, nextarg);
break;
case 'e': /* private key passphrase */
GetStr(&config->key_passwd, nextarg);
cleanarg(nextarg);
break;
case 'f': /* crypto engine */
GetStr(&config->engine, nextarg);
if (config->engine && curlx_strequal(config->engine,"list"))
config->list_engines = TRUE;
case 'g': /* CA info PEM file */
/* CA cert directory */
GetStr(&config->capath, nextarg);
break;
default: /* certificate file */
{
char *ptr = strchr(nextarg, ':');
/* Since we live in a world of weirdness and confusion, the win32
dudes can use : when using drive letters and thus
c:\file:password needs to work. In order not to break
compatibility, we still use : as separator, but we try to detect
when it is used for a file name! On windows. */
Daniel Stenberg
committed
#ifdef WIN32
if(ptr &&
(ptr == &nextarg[1]) &&
(nextarg[2] == '\\') &&
(isalpha((int)nextarg[0])) )
/* colon in the second column, followed by a backslash, and the
first character is an alphabetic letter:
this is a drive letter colon */
ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
Daniel Stenberg
committed
#endif
if(ptr) {
/* we have a password too */
*ptr=0;
ptr++;
GetStr(&config->key_passwd, ptr);
}
GetStr(&config->cert, nextarg);
cleanarg(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 */
if(formparse(nextarg,
&config->httppost,
&config->last_post))
return PARAM_BAD_USE;
Daniel Stenberg
committed
if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
return PARAM_BAD_USE;
Daniel Stenberg
committed
case 'g': /* g disables URLglobbing */
config->globoff ^= TRUE;
break;
Daniel Stenberg
committed
case 'G': /* HTTP GET */
config->use_httpget = TRUE;
break;
return PARAM_HELP_REQUESTED;
/* A custom header to append to a list */
err = add2list(&config->headers, nextarg);
if(err)
return err;
break;
case 'i':
config->conf ^= CONF_HEADER; /* include the HTTP header as well */
break;
case 'j':
config->cookiesession ^= TRUE;
break;
/*
* This is a bit tricky. We either SET both bits, or we clear both
* bits. Let's not make any other outcomes from this.
*/
if((CONF_HEADER|CONF_NOBODY) !=
(config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
/* one of them weren't set, set both */
config->conf |= (CONF_HEADER|CONF_NOBODY);
if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
return PARAM_BAD_USE;
}
else {
/* both were set, clear both */
config->conf &= ~(CONF_HEADER|CONF_NOBODY);
if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
return PARAM_BAD_USE;
}
case 'k': /* allow insecure SSL connects */
config->insecure_ok ^= TRUE;
break;
case 'K': /* parse config file */
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 */
switch (subletter) {
case 't':
/* Continue to send authentication (user+password) when following
* locations, even when hostname changed */
config->conf ^= CONF_UNRESTRICTED_AUTH;
break;
}
if(str2num(&config->timeout, nextarg))
return PARAM_BAD_NUMERIC;
return PARAM_HELP_REQUESTED;
fprintf(stderr,
"curl: built-in manual was disabled at build-time!\n");
return PARAM_OPTION_UNKNOWN;
#endif
switch(subletter) {
case 'o': /* CA info PEM file */
/* use .netrc or URL */
config->conf ^= CONF_NETRC_OPT;
break;
default:
/* 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;
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
{
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;
}
}
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;
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 */
err = PARAM_OK;
switch(nextarg[0]) {
case '-':
/* prefixed with a dash makes it a POST TRANSFER one */
nextarg++;
err = add2list(&config->postquote, nextarg);
break;
case '+':
/* prefixed with a plus makes it a just-before-transfer one */
nextarg++;
err = add2list(&config->prequote, nextarg);
err = add2list(&config->quote, nextarg);
break;
if(err)
return err;
break;
case 'r':
/* byte range requested */
GetStr(&config->range, nextarg);
break;
case 'R':
/* use remote file's time */
config->remote_time ^= TRUE;
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':
err = add2list(&config->telnet_options, nextarg);
if(err)
return err;
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
{
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_UPLOAD))
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) {
url->flags |= GETOUT_UPLOAD; /* mark -T used */
if(!*nextarg)
url->flags |= GETOUT_NOUPLOAD;
else {
/* "-" equals stdin, but keep the string around for now */