diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 1154 |
1 files changed, 1154 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 000000000..5666c777e --- /dev/null +++ b/src/main.c @@ -0,0 +1,1154 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <ctype.h> + +#include <curl/curl.h> +#include <curl/mprintf.h> +#include "../lib/getdate.h" +#ifdef GLOBURL +#include "urlglob.h" +#define CURLseparator "--_curl_--" +#define MIMEseparator "_curl_" +#endif + +/* This is now designed to have its own local setup.h */ +#include "setup.h" + +#include "version.h" + +#ifdef HAVE_IO_H /* typical win32 habit */ +#include <io.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +extern void hugehelp(void); + +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"); +} + +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/--ftp-ascii Use ASCII transfer (F)\n" + " -c/--continue Resume a previous transfer where we left it\n" + " -C/--continue-at <offset> Specify absolute resume offset\n" + " -d/--data POST data (H)\n" + " -D/--dump-header <file> Write the headers to this file\n" + " -e/--referer Referer page (H)\n" + " -E/--cert <cert:passwd> Specifies your certificate file and password (HTTPS)\n" + " -f/--fail Fail silently (no output at all) on errors (H)\n" + " -F/--form <name=content> Specify HTTP POST data (H)\n" + + " -h/--help This help text\n" + " -H/--header <line> Custom header to pass to server. (H)\n" + " -i/--include Include the HTTP-header in the output (H)\n" + " -I/--head Fetch document info only (HTTP HEAD/FTP SIZE)\n" + " -K/--config Specify which config file to read\n" + " -l/--list-only List only names of an FTP directory (F)\n" + " -L/--location Follow Location: hints (H)\n" + " -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" + " -o/--output <file> Write output to <file> instead of stdout\n" + " -O/--remote-name Write output to a file named as the remote file\n" +#if 0 + " -p/--port <port> Use port other than default for current protocol.\n" +#endif + " -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)\n" + " -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server\n" + " -s/--silent Silent mode. Don't output anything\n" + " -S/--show-error Show error. With -s, make curl show errors when they occur\n" + " -t/--upload Transfer/upload stdin to remote site\n" + " -T/--upload-file <file> Transfer/upload <file> to remote site\n" + " -u/--user <user:password> Specify user and password to use\n" + " -U/--proxy-user <user:password> Specify Proxy authentication\n" + " -v/--verbose Makes the operation more talkative\n" + " -V/--version Outputs version number then quits\n" + " -x/--proxy <host> Use proxy. (Default port is 1080)\n" + " -X/--request <command> Specific request command to use\n" + " -y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs\n" + " -Y/--speed-time Time needed to trig speed-limit abort. Defaults to 30\n" + " -z/--time-cond <time> Includes a time condition to the server (H)\n" + " -2/--sslv2 Force usage of SSLv2 (H)\n" + " -3/--sslv3 Force usage of SSLv3 (H)\n" + " -#/--progress-bar Display transfer progress as a progress bar\n" + " --crlf Convert LF to CRLF in upload. Useful for MVS (OS/390)\n" + " --stderr <file> Where to redirect stderr. - means stdout.\n", + curl_version() + ); +} + +struct LongShort { + char *letter; + char *lname; + bool extraparam; +}; + +struct Configurable { + char *useragent; + char *cookie; + bool use_resume; + int resume_from; + char *postfields; + char *referer; + long timeout; + char *outfile; + char *headerfile; + char remotefile; + char *ftpport; + 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; + long conf; + char *url; + char *cert; + char *cert_passwd; + bool crlf; + char *cookiefile; + char *customrequest; + bool progressmode; + + FILE *errors; /* if stderr redirect is requested */ + + struct curl_slist *quote; + + long ssl_version; + TimeCond timecond; + time_t condtime; + + struct HttpHeader *headers; + struct HttpHeader *last_header; + + struct HttpPost *httppost; + struct HttpPost *last_post; +}; + +static int parseconfig(char *filename, + struct Configurable *config); + +static void GetStr(char **string, + char *value) +{ + if(*string) + free(*string); + *string = strdup(value); +} + +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 int 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 letter; + char *parse=NULL; + int res; + struct HttpHeader *head; + int j; + time_t now; + int hit=-1; + + /* single-letter, + long-name, + boolean whether it takes an additional argument + */ + struct LongShort aliases[]= { + {"9", "crlf", FALSE}, + {"8", "stderr", TRUE}, + + {"2", "sslv2", FALSE}, + {"3", "sslv3", FALSE}, + {"a", "append", FALSE}, + {"A", "user-agent", TRUE}, + {"b", "cookie", TRUE}, + {"B", "ftp-ascii", FALSE}, + {"c", "continue", FALSE}, + {"C", "continue-at", TRUE}, + {"d", "data", TRUE}, + {"D", "dump-header", TRUE}, + {"e", "referer", TRUE}, + {"E", "cert", TRUE}, + {"f", "fail", FALSE}, + {"F", "form", TRUE}, + + {"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}, + {"o", "output", TRUE}, + {"O", "remote-name", FALSE}, +#if 0 + {"p", "port", TRUE}, +#endif + {"P", "ftpport", TRUE}, + {"q", "disable", FALSE}, + {"Q", "quote", TRUE}, + {"r", "range", TRUE}, + {"s", "silent", FALSE}, + {"S", "show-error", FALSE}, + {"t", "upload", FALSE}, + {"T", "upload-file", TRUE}, + {"u", "user", TRUE}, + {"U", "proxy-user", TRUE}, + {"v", "verbose", FALSE}, + {"V", "version", FALSE}, + {"x", "proxy", TRUE}, + {"X", "request", TRUE}, + {"X", "http-request", TRUE}, /* OBSOLETE VERSION */ + {"y", "speed-time", TRUE}, + {"Y", "speed-limit", TRUE}, + {"z", "time-cond", TRUE}, + {"#", "progress-bar",FALSE}, + }; + + if('-' == flag[0]) { + /* try a long name */ + int fnam=strlen(&flag[1]); + for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) { + if(strnequal(aliases[j].lname, &flag[1], fnam)) { + if(strequal(aliases[j].lname, &flag[1])) { + parse = aliases[j].letter; + hit = j; + break; + } + if(parse) { + /* this is the second match, we can't continue! */ + helpf("option --%s is ambiguous\n", &flag[1]); + return URG_FAILED_INIT; + } + parse = aliases[j].letter; + hit = j; + } + } + if(hit < 0) { + helpf("unknown option -%s.\n", flag); + return URG_FAILED_INIT; + } + } + else { + hit=-1; + parse = flag; + } + + do { + /* we can loop here if we have multiple single-letters */ + + letter = parse?*parse:'\0'; + *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) { + hit = j; + break; + } + } + if(hit < 0) { + helpf("unknown option -%c.\n", letter); + return URG_FAILED_INIT; + } + } + if(hit < 0) { + helpf("unknown option -%c.\n", letter); + return URG_FAILED_INIT; + } + if(!nextarg && aliases[hit].extraparam) { + helpf("option -%s/--%s requires an extra argument!\n", + aliases[hit].letter, + aliases[hit].lname); + return URG_FAILED_INIT; + } + else if(nextarg && aliases[hit].extraparam) + *usedarg = TRUE; /* mark it as used */ + + switch(letter) { + 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=get_date(nextarg, &now); + if(-1 == 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 '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 '#': /* 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(strchr(nextarg, '=')) { + /* A cookie string must have a =-letter */ + GetStr(&config->cookie, nextarg); + } + else { + /* We have a cookie file to read from! */ + GetStr(&config->cookiefile, nextarg); + } + break; + case 'B': + /* use type ASCII when transfering ftp files */ + config->conf ^= CONF_FTPASCII; + break; + case 'c': + /* This makes us continue an ftp transfer */ + config->use_resume^=TRUE; + break; + case 'C': + /* This makes us continue an ftp transfer at given position */ + config->resume_from= atoi(nextarg); + config->use_resume=TRUE; + break; + case 'd': + /* postfield data */ + 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->postfields = file2string(file); + if(file && (file != stdin)) + fclose(stdin); + } + else { + GetStr(&config->postfields, nextarg); + } + if(config->postfields) + config->conf |= CONF_POST; + break; + case 'D': + /* dump-header to given file name */ + GetStr(&config->headerfile, nextarg); + break; + case 'e': + GetStr(&config->referer, nextarg); + config->conf |= CONF_REFERER; + break; + case 'E': + { + 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 */ + if(curl_FormParse(nextarg, + &config->httppost, + &config->last_post)) + return URG_FAILED_INIT; + config->conf |= CONF_HTTPPOST; /* no toggle, OR! */ + break; + + case 'h': /* h for help */ + help(); + return URG_FAILED_INIT; + case 'H': + head = (struct HttpHeader *)malloc(sizeof(struct HttpHeader)); + if(head) { + head->next = NULL; + head->header = NULL; /* first zero this */ + GetStr(&head->header, nextarg); /* now get the header line */ + + /* point on our new one */ + if(config->last_header) + config->last_header->next = head; + else { + config->headers = head; + } + + config->last_header = head; + } + 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 */ + 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(); + return URG_FAILED_INIT; + 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 'o': + /* output file */ + GetStr(&config->outfile, nextarg); /* write to this file */ + break; + case 'O': + /* output file */ + config->remotefile ^= TRUE; + 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! + */ + config->conf |= CONF_FTPPORT; + GetStr(&config->ftpport, nextarg); + break; +#if 0 + case 'p': + /* specified port */ + fputs("You've used the -p option, it will be removed in a future version\n", + stderr); + config->porttouse = atoi(nextarg); + config->conf |= CONF_PORT; /* changed port */ + break; +#endif + 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 */ + config->quote = curl_slist_append(config->quote, nextarg); + break; + case 'r': + /* byte range requested */ + GetStr(&config->range, nextarg); + config->conf |= CONF_RANGE; + 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': + /* we are uploading */ + config->conf ^= CONF_UPLOAD; + break; + case 'T': + /* we are uploading */ + config->conf |= CONF_UPLOAD; + GetStr(&config->infile, nextarg); + break; + case 'u': + /* user:password */ + GetStr(&config->userpwd, nextarg); + config->conf |= CONF_USERPWD; + break; + case 'U': + /* Proxy user:password */ + GetStr(&config->proxyuserpwd, nextarg); + config->conf |= CONF_PROXYUSERPWD; + break; + case 'v': + config->conf ^= CONF_VERBOSE; /* talk a lot */ + break; + case 'V': + printf(CURL_ID "%s\n", curl_version()); + return URG_FAILED_INIT; + case 'x': + /* proxy */ + if(!*nextarg) { + /* disable proxy when no proxy is given */ + config->conf &= ~CONF_PROXY; + } + else { + config->conf |= CONF_PROXY; + GetStr(&config->proxy, nextarg); + } + break; + case 'X': + /* HTTP request */ + GetStr(&config->customrequest, nextarg); + break; + case 'Y': + /* low speed time */ + config->low_speed_time = atoi(nextarg); + if(!config->low_speed_limit) + config->low_speed_limit = 1; + break; + case 'y': + /* low speed limit */ + config->low_speed_limit = atoi(nextarg); + if(!config->low_speed_time) + config->low_speed_time=30; + break; + + default: /* unknown flag */ + if(letter) + helpf("Unknown option '%c'\n", letter); + else + helpf("Unknown option\n"); /* short help blurb */ + return URG_FAILED_INIT; + } + hit = -1; + + } while(*++parse && !*usedarg); + + return URG_OK; +} + + +static int parseconfig(char *filename, + struct Configurable *config) +{ + int res; + FILE *file; + char configbuffer[4096]; + char filebuffer[256]; + bool usedarg; + + if(!filename || !*filename) { + /* NULL or no file name attempts to load .curlrc from the homedir! */ + +#define CURLRC DOT_CHAR "curlrc" + + char *home = curl_GetEnv("HOME"); /* portable environment reader */ + + if(!home || (strlen(home)>(sizeof(filebuffer)-strlen(CURLRC)))) + return URG_OK; + + sprintf(filebuffer, "%s%s%s", home, DIR_CHAR, CURLRC); + + filename = filebuffer; + } + + if(strcmp(filename,"-")) + file = fopen(filename, "r"); + else + file = stdin; + + if(file) { + char *tok; + char *tok2; + while(fgets(configbuffer, sizeof(configbuffer), file)) { + /* lines with # in the fist column is a comment! */ + +#if 0 + fprintf(stderr, "%s", configbuffer); +#endif + if('#' == configbuffer[0]) + continue; + tok = configbuffer; + + while(*tok && isspace((int)*tok)) + tok++; +/* tok=strtok(configbuffer, " \t\n"); */ +#if 0 + fprintf(stderr, "TOK: %s\n", tok); +#endif + if('-' != tok[0]) { + char *nl; + if(config->url) + free(config->url); + config->url = strdup(tok); + nl = strchr(config->url, '\n'); + if(nl) + *nl=0; + } + while(('-' == tok[0])) { + /* this is a flag */ + char *firsttok = strdup(tok); + char *nl; + + /* remove newline from firsttok */ + nl = strchr(firsttok, '\n'); + if(nl) + *nl=0; + + /* pass the -flag */ + tok2=tok; + while(*tok2 && !isspace((int)*tok2)) + tok2++; + + /* pass the following white space */ + while(*tok2 && isspace((int)*tok2)) + tok2++; + + while(!*tok2 && + fgets(configbuffer, sizeof(configbuffer), file)) { + /* lines with # in the fist column is a comment! */ +#if 0 + fprintf(stderr, "%s", configbuffer); +#endif + if('#' == configbuffer[0]) + continue; + tok2 = configbuffer; + /* tok2=strtok(configbuffer, " \t\n"); */ + /* pass white space */ + while(*tok2 && isspace((int)*tok2)) + tok2++; + } + /* remove newline from tok2 */ + nl = strchr(tok2, '\n'); + if(nl) + *nl=0; + + res = getparameter(firsttok+1, + *tok2?tok2:NULL, + &usedarg, + config); + free(firsttok); +#if 0 + fprintf(stderr, "TOK %s TOK2: %s RES: %d\n", + firsttok, tok2?tok2:"NULL", res); +#endif + if(res) + return res; + if(!usedarg) { + /* tok2 is unused, */ + tok = tok2; + } + else + break; /* we've used both our words */ + } + } + if(file != stdin) + fclose(file); + } + return URG_OK; +} + +struct OutStruct { + char *filename; + FILE *stream; +}; + +int my_fwrite(void *buffer, size_t size, size_t nmemb, FILE *stream) +{ + 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 */ + } + return fwrite(buffer, size, nmemb, out->stream); +} + + +int main(int argc, char *argv[]) +{ + char errorbuffer[URLGET_ERROR_SIZE]; + + struct OutStruct outs; + + char *url = NULL; +#ifdef GLOBURL + URLGlob *urls; + int urlnum; + char *outfiles = NULL; + int separator = 0; +#endif + + FILE *infd = stdin; + FILE *headerfilep = NULL; + char *urlbuffer=NULL; + int infilesize=-1; /* -1 means unknown */ + bool stillflags=TRUE; + + int res=URG_OK; + int i; + struct Configurable config; + + outs.stream = stdout; + + memset(&config, 0, sizeof(struct Configurable)); + + /* set non-zero default values: */ + config.useragent= maprintf(CURL_NAME "/" CURL_VERSION " (" OS ") " + "%s", curl_version()); + config.showerror=TRUE; + config.conf=CONF_DEFAULT; + config.crlf=FALSE; + config.quote=NULL; + + 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! + */ +#if 0 + fprintf(stderr, "I TURNED OFF THE CRAP\n"); +#endif + ; + } + else { + res = parseconfig(NULL, &config); + if(res) + return res; + } + + if ((argc < 2) && !config.url) { + helpf(NULL); + return URG_FAILED_INIT; + } + + /* Parse options */ + for (i = 1; i < argc; i++) { + if(stillflags && + ('-' == argv[i][0])) { + char *nextarg; + bool passarg; + + char *flag = &argv[i][1]; + + 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) + return res; + + if(passarg) /* we're supposed to skip this */ + i++; + } + } + else { + if(url) { + helpf("only one URL is supported!\n"); + return URG_FAILED_INIT; + } + url = argv[i]; + } + } + + /* if no URL was specified and there was one in the config file, get that + one */ + if(!url && config.url) + url = config.url; + + if(!url) { + helpf("no URL specified!\n"); + return URG_FAILED_INIT; + } +#if 0 + fprintf(stderr, "URL: %s PROXY: %s\n", url, config.proxy?config.proxy:"none"); +#endif + +#ifdef GLOBURL + urlnum = glob_url(&urls, url); /* expand '{...}' and '[...]' expressions and return + total number of URLs in pattern set */ + outfiles = config.outfile; /* save outfile pattern befor expansion */ + if (!outfiles && !config.remotefile && urlnum > 1) { +#ifdef CURL_SEPARATORS + /* multiple files extracted to stdout, insert separators! */ + separator = 1; +#endif +#ifdef MIME_SEPARATORS + /* multiple files extracted to stdout, insert MIME separators! */ + separator = 1; + printf("MIME-Version: 1.0\n"); + printf("Content-Type: multipart/mixed; boundary=%s\n\n", MIMEseparator); +#endif + } + for (i = 0; (url = next_url(urls)); ++i) { + if (outfiles) + config.outfile = strdup(outfiles); +#endif + + if(config.outfile && config.infile) { + helpf("you can't both upload and download!\n"); + return URG_FAILED_INIT; + } + + if (config.outfile || config.remotefile) { + /* + * We have specified a file name to store the result in, or we have + * decided we want to use the remote file name. + */ + + if(config.remotefile) { + /* Find and get the remote file name */ + config.outfile=strstr(url, "://"); + if(config.outfile) + config.outfile+=3; + else + config.outfile=url; + config.outfile = strrchr(config.outfile, '/'); + if(!config.outfile || !strlen(++config.outfile)) { + helpf("Remote file name has no length!\n"); + return URG_WRITE_ERROR; + } + } +#ifdef GLOBURL + else /* fill '#1' ... '#9' terms from URL pattern */ + config.outfile = match_url(config.outfile, *urls); +#endif + + if((0 == config.resume_from) && config.use_resume) { + /* 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; + + if(0 == stat(config.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(config.outfile, config.resume_from?"ab":"wb"); + if (!outs.stream) { + helpf("Can't open '%s'!\n", config.outfile); + return URG_WRITE_ERROR; + } + } + else { + outs.filename = config.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; + else + 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 URG_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! */ + } + + infd=(FILE *) fopen(config.infile, "rb"); + if (!infd || stat(config.infile, &fileinfo)) { + helpf("Can't open '%s'!\n", config.infile); + return URG_READ_ERROR; + } + infilesize=fileinfo.st_size; + + } + if((config.conf&CONF_UPLOAD) && + config.use_resume && + (0==config.resume_from)) { + config.resume_from = -1; /* -1 will then force get-it-yourself */ + } + if(config.headerfile) { + /* open file for output: */ + if(strcmp(config.headerfile,"-")) + { + headerfilep=(FILE *) fopen(config.headerfile, "wb"); + if (!headerfilep) { + helpf("Can't open '%s'!\n", config.headerfile); + return URG_WRITE_ERROR; + } + } + else + headerfilep=stdout; + } + + /* This was previously done in urlget, but that was wrong place to do it */ + if(outs.stream && isatty(fileno(outs.stream))) + /* we send the output to a tty, and therefor we switch off the progress + meter right away */ + config.conf |= CONF_NOPROGRESS; + +#ifdef GLOBURL + if (urlnum > 1) { + fprintf(stderr, "\n[%d/%d]: %s --> %s\n", i+1, urlnum, url, config.outfile ? config.outfile : "<stdout>"); + if (separator) { +#ifdef CURL_SEPARATORS + printf("%s%s\n", CURLseparator, url); +#endif +#ifdef MIME_SEPARATORS + printf("--%s\n", MIMEseparator); + printf("Content-ID: %s\n\n", url); +#endif + } + } +#endif + + if(!config.errors) + config.errors = stderr; + + res = curl_urlget(URGTAG_FILE, (FILE *)&outs, /* where to store */ + URGTAG_WRITEFUNCTION, my_fwrite, /* what call to write */ + URGTAG_INFILE, infd, /* for uploads */ + URGTAG_INFILESIZE, infilesize, /* size of uploaded file */ + URGTAG_URL, url, /* what to fetch */ + URGTAG_PROXY, config.proxy, /* proxy to use */ + URGTAG_FLAGS, config.conf, /* flags */ + URGTAG_USERPWD, config.userpwd, /* user + passwd */ + URGTAG_PROXYUSERPWD, config.proxyuserpwd, /* Proxy user + passwd */ + URGTAG_RANGE, config.range, /* range of document */ + URGTAG_ERRORBUFFER, errorbuffer, + URGTAG_TIMEOUT, config.timeout, + URGTAG_POSTFIELDS, config.postfields, + URGTAG_REFERER, config.referer, + URGTAG_USERAGENT, config.useragent, + URGTAG_FTPPORT, config.ftpport, + URGTAG_LOW_SPEED_LIMIT, config.low_speed_limit, + URGTAG_LOW_SPEED_TIME, config.low_speed_time, + URGTAG_RESUME_FROM, config.use_resume?config.resume_from:0, + URGTAG_COOKIE, config.cookie, + URGTAG_HTTPHEADER, config.headers, + URGTAG_HTTPPOST, config.httppost, + URGTAG_SSLCERT, config.cert, + URGTAG_SSLCERTPASSWD, config.cert_passwd, + URGTAG_CRLF, config.crlf, + URGTAG_QUOTE, config.quote, + URGTAG_WRITEHEADER, headerfilep, + URGTAG_COOKIEFILE, config.cookiefile, + URGTAG_SSLVERSION, config.ssl_version, + URGTAG_TIMECONDITION, config.timecond, + URGTAG_TIMEVALUE, config.condtime, + URGTAG_CUSTOMREQUEST, config.customrequest, + URGTAG_STDERR, config.errors, + URGTAG_DONE); /* always terminate the list of tags */ + if((res!=URG_OK) && config.showerror) + fprintf(config.errors, "curl: (%d) %s\n", res, errorbuffer); + + if((config.errors != stderr) && + (config.errors != stdout)) + /* it wasn't directed to stdout or stderr so close the file! */ + fclose(config.errors); + + if(urlbuffer) + free(urlbuffer); + if (config.outfile && outs.stream) + fclose(outs.stream); + if (config.infile) + fclose(infd); + if(headerfilep) + fclose(headerfilep); + + if(config.url) + free(config.url); + +#ifdef GLOBURL + if(url) + free(url); + if(config.outfile && !config.remotefile) + free(config.outfile); + } +#ifdef MIME_SEPARATORS + if (separator) + printf("--%s--\n", MIMEseparator); +#endif +#endif + + curl_slist_free_all(config.quote); /* the checks for config.quote == NULL */ + + return(res); +} |