Newer
Older
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
Daniel Stenberg
committed
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
* 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 COPYING file.
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "getpass.h"
#include "homedir.h"
#include "hugehelp.h"
#ifdef USE_ENVIRONMENT
#include "writeenv.h"
#endif
#define CURLseparator "--_curl_--"
#if defined(WIN32)&&!defined(__CYGWIN32__)
#include <winsock2.h>
#ifdef __NOVELL_LIBC__
#include <screen.h>
#endif
Daniel Stenberg
committed
#ifdef TIME_WITH_SYS_TIME
/* We can include both fine */
#include <sys/time.h>
Daniel Stenberg
committed
#include <time.h>
#else
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
# include <time.h>
#endif
#endif
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
#ifdef HAVE_UTIME_H
Daniel Stenberg
committed
#include <utime.h>
Daniel Stenberg
committed
#ifdef HAVE_SYS_UTIME_H
#include <sys/utime.h>
#endif
#endif /* HAVE_UTIME_H */
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#endif
#ifdef HAVE_LOCALE_H
#include <locale.h> /* for setlocale() */
#endif
Daniel Stenberg
committed
#define ENABLE_CURLX_PRINTF
/* make the curlx header define all printf() functions to use the curlx_*
versions instead */
#include <curlx.h> /* header from the libcurl directory */
/* The last #include file should be: */
#ifndef CURLTOOLDEBUG
#define MEMDEBUG_NODEFINES
#endif
/* This is low-level hard-hacking memory leak tracking and similar. Using
the library level code from this client-side is ugly, but we do this
anyway for convenience. */
#include "memdebug.h"
#define DEFAULT_MAXREDIRS 50L
#ifdef __DJGPP__
char *msdosify(char *);
char *rename_if_dos_device_name(char *);
/* we want to glob our own argv[] */
char **__crt0_glob_function (char *arg)
{
(void)arg;
return (char**)0;
}
#endif /* __DJGPP__ */
#define CURL_PROGRESS_STATS 0 /* default progress display */
#define CURL_PROGRESS_BAR 1
/**
* @def MIN
* standard MIN macro
*/
#ifndef MIN
#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
#endif
Daniel Stenberg
committed
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_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_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_MUTE (1<<28) /* force NOPROGRESS */
#define CONF_NETRC_OPT (1<<29) /* read user+password from either
* .netrc or URL*/
#define CONF_UNRESTRICTED_AUTH (1<<30)
/* Send authentication (user+password) when following
* locations, even when hostname changed */
#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;
}
#ifdef WIN32
#include <direct.h>
#define F_OK 0
#define mkdir(x,y) (mkdir)(x)
#endif
#include "curlmsg_vms.h"
/* Support uploading and resuming of >2GB files
*/
#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
#define struct_stat struct _stati64
#define stat(file,st) _stati64(file,st)
#else
#define struct_stat struct stat
#endif
* Truncate a file handle at a 64-bit position 'where'.
* Borland doesn't even support 64-bit types.
#ifdef __BORLANDC__
#define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
#endif
{
curl_off_t curr;
int rc = 0;
if ((curr = _lseeki64(fd, 0, SEEK_CUR)) < 0)
return -1;
if (_lseeki64(fd, where, SEEK_SET) < 0)
return -1;
rc = -1;
_lseeki64(fd, curr, SEEK_SET);
return rc;
}
/*
* 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.
*/
static 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.
*/
static void main_free(void)
Daniel Stenberg
committed
curl_global_cleanup();
static int SetHTTPrequest(HttpReq req, HttpReq *store)
Daniel Stenberg
committed
{
if((*store == HTTPREQ_UNSPEC) ||
(*store == req)) {
*store = req;
return 0;
Daniel Stenberg
committed
}
fprintf(stderr, "You can only select one HTTP request!\n");
return 1;
Daniel Stenberg
committed
}
{
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' "
#ifdef USE_MANUAL
"or 'curl --manual' "
#endif
"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; /* next one */
char *url; /* the URL we deal with */
char *outfile; /* where to store the output */
char *infile; /* file to upload, if GETOUT_UPLOAD is set */
int flags; /* options */
#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 */
#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
int i;
static const char * const helptext[]={
"Usage: curl [options...] <url>",
"Options: (H) means HTTP/HTTPS only, (F) means FTP only",
" -a/--append Append to target file when uploading (F)",
" -A/--user-agent <string> User-Agent to send to server (H)",
" --anyauth Tell curl to choose authentication method (H)",
" -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
" --basic Enable HTTP Basic Authentication (H)",
" -B/--use-ascii Use ASCII/text transfer",
Daniel Stenberg
committed
" -c/--cookie-jar <file> Write cookies to this file after operation (H)",
" -C/--continue-at <offset> Resumed transfer offset",
" -d/--data <data> HTTP POST data (H)",
" --data-ascii <data> HTTP POST ASCII data (H)",
" --data-binary <data> HTTP POST binary data (H)",
Daniel Stenberg
committed
" --negotiate Enable HTTP Negotiate Authentication (H)",
" --digest Enable HTTP Digest Authentication (H)",
Daniel Stenberg
committed
" --disable-eprt Prevent curl from using EPRT or LPRT (F)",
" --disable-epsv Prevent curl from using EPSV (F)",
" -D/--dump-header <file> Write the headers to this file",
" --egd-file <file> EGD socket path for random data (SSL)",
" --tcp-nodelay Set the TCP_NODELAY option",
#ifdef USE_ENVIRONMENT
" --environment Write result codes to environment variables (RISC OS)",
Daniel Stenberg
committed
" -e/--referer Referer URL (H)",
" -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
" --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
" --key <key> Private key file name (SSL)",
" --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
" --pass <pass> Pass phrase for the private key (SSL)",
" --engine <eng> Crypto engine to use (SSL). \"--engine list\" for list",
" --cacert <file> CA certificate to verify peer against (SSL)",
" --capath <directory> CA directory (made using c_rehash) to verify",
" peer against (SSL)",
Daniel Stenberg
committed
" --ciphers <list> SSL ciphers to use (SSL)",
" --compressed Request compressed response (using deflate or gzip)",
" --connect-timeout <seconds> Maximum time allowed for connection",
Daniel Stenberg
committed
" --create-dirs Create necessary local directory hierarchy",
" -f/--fail Fail silently (no output at all) on errors (H)",
" --ftp-create-dirs Create the remote dirs if not present (F)",
" --ftp-pasv Use PASV instead of PORT (F)",
" --ftp-ssl Enable SSL/TLS for the ftp transfer (F)",
Daniel Stenberg
committed
" -F/--form <name=content> Specify HTTP multipart POST data (H)",
" -g/--globoff Disable URL sequences and ranges using {} and []",
" -G/--get Send the -d data with a HTTP GET (H)",
" -h/--help This help text",
" -H/--header <line> Custom header to pass to server (H)",
Daniel Stenberg
committed
" -i/--include Include protocol headers in the output (H/F)",
" -j/--junk-session-cookies Ignore session cookies read from file (H)",
Daniel Stenberg
committed
" --interface <interface> Specify network interface to use",
" --krb4 <level> Enable krb4 with specified security level (F)",
" -k/--insecure Allow curl to connect to SSL sites without certs (H)",
" -K/--config Specify which config file to read",
" -l/--list-only List only names of an FTP directory (F)",
Daniel Stenberg
committed
" --limit-rate <rate> Limit transfer speed to this rate",
" -L/--location Follow Location: hints (H)",
Daniel Stenberg
committed
" --location-trusted Follow Location: and send authentication even ",
" to other hostnames (H)",
" -m/--max-time <seconds> Maximum time allowed for the transfer",
Daniel Stenberg
committed
" --max-redirs <num> Maximum number of redirects allowed (H)",
" --max-filesize <bytes> Maximum file size to download (H/F)",
" -M/--manual Display the full manual",
" -n/--netrc Must read .netrc for user name and password",
Daniel Stenberg
committed
" --netrc-optional Use either .netrc or URL; overrides -n",
" --ntlm Enable HTTP NTLM authentication (H)",
Daniel Stenberg
committed
" -N/--no-buffer Disable buffering of the output stream",
" -o/--output <file> Write output to <file> instead of stdout",
" -O/--remote-name Write output to a file named as the remote file",
Daniel Stenberg
committed
" -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
" --proxy-basic Enable Basic authentication on the proxy (H)",
" --proxy-digest Enable Digest authentication on the proxy (H)",
Daniel Stenberg
committed
" --proxy-ntlm Enable NTLM authentication on the proxy (H)",
" -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
Daniel Stenberg
committed
" -q If used as the first parameter disables .curlrc",
" -Q/--quote <cmd> Send command(s) to server before file transfer (F)",
" -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server",
Daniel Stenberg
committed
" --random-file <file> File for reading random data from (SSL)",
" -R/--remote-time Set the remote file's time on the local output",
Daniel Stenberg
committed
" --retry <num> Retry request <num> times if transient problems occur",
" --retry-delay <seconds> When retrying, wait this many seconds between each",
" --retry-max-time <seconds> Retry only within this period",
" -s/--silent Silent mode. Don't output anything",
" -S/--show-error Show error. With -s, make curl show errors when they occur",
" --socks <host[:port]> Use SOCKS5 proxy on given host + port",
" --stderr <file> Where to redirect stderr. - means stdout",
" -t/--telnet-option <OPT=val> Set telnet option",
" --trace <file> Write a debug trace to the given file",
Daniel Stenberg
committed
" --trace-ascii <file> Like --trace but without the hex output",
" -T/--upload-file <file> Transfer <file> to remote site",
" --url <URL> Spet URL to work with",
" -u/--user <user[:password]> Set server user and password",
" -U/--proxy-user <user[:password]> Set proxy user and password",
Daniel Stenberg
committed
" -v/--verbose Make the operation more talkative",
" -V/--version Show version number and quit",
" --wdebug Turn on Watt-32 debugging under DJGPP",
" -w/--write-out [format] What to output after completion",
" -x/--proxy <host[:port]> Use HTTP proxy on given port",
Daniel Stenberg
committed
" -X/--request <command> Specify request command to use",
" -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
" -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
Daniel Stenberg
committed
" -z/--time-cond <time> Transfer based on a time condition",
" -0/--http1.0 Use HTTP 1.0 (H)",
" -1/--tlsv1 Use TLSv1 (SSL)",
" -2/--sslv2 Use SSLv2 (SSL)",
" -3/--sslv3 Use SSLv3 (SSL)",
" --3p-quote like -Q for the source URL for 3rd party transfer (F)",
" --3p-url source URL to activate 3rd party transfer (F)",
" --3p-user user and password for source 3rd party transfer (F)",
" -4/--ipv4 Resolve name to IPv4 address",
" -6/--ipv6 Resolve name to IPv6 address",
" -#/--progress-bar Display transfer progress as a progress bar",
NULL
};
#ifdef __NOVELL_LIBC__
if (i && ((i % 23) == 0))
pressanykey();
#endif
}
const char *letter;
const char *lname;
bool extraparam;
};
struct Configurable {
bool remote_time;
char *random_file;
char *egd_file;
char *cookie; /* single line with specified cookies */
char *cookiejar; /* write to this file */
char *cookiefile; /* read from this file */
bool cookiesession; /* new session? */
bool encoding; /* Accept-Encoding please */
Daniel Stenberg
committed
bool resume_from_current;
long low_speed_limit;
long low_speed_time;
bool showerror;
char *userpwd;
char *proxyuserpwd;
char *proxy;
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 */
char *key;
char *key_type;
char *key_passwd;
char *engine;
Daniel Stenberg
committed
char *trace_dump; /* file to dump the network trace to, or NULL */
FILE *trace_stream;
bool nobuffer;
Daniel Stenberg
committed
bool globoff;
Daniel Stenberg
committed
bool use_httpget;
bool insecure_ok; /* set TRUE to allow insecure SSL connects */
bool create_dirs;
Daniel Stenberg
committed
char *writeout; /* %-styled format string to output */
bool writeenv; /* write results to environment, if available */
bool errors_fopened;
curl_TimeCond timecond;
struct curl_slist *headers;
Daniel Stenberg
committed
struct curl_httppost *httppost;
struct curl_httppost *last_post;
struct curl_slist *telnet_options;
Daniel Stenberg
committed
HttpReq httpreq;
curl_off_t sendpersecond; /* send to peer */
curl_off_t recvpersecond; /* receive from peer */
Daniel Stenberg
committed
struct timeval lastsendtime;
Daniel Stenberg
committed
struct timeval lastrecvtime;
Daniel Stenberg
committed
long req_retry; /* number of retries */
long retry_delay; /* delay between retries (in seconds) */
long retry_maxtime; /* maximum time to keep retrying */
char *tp_url; /* third party URL */
char *tp_user; /* third party userpwd */
struct curl_slist *tp_quote;
struct curl_slist *tp_postquote;
struct curl_slist *tp_prequote;
Daniel Stenberg
committed
char *ftp_account; /* for ACCT */
/* global variable to hold info about libcurl */
static curl_version_info_data *curlinfo;
static void parseconfig(const char *filename,
struct Configurable *config);
Daniel Stenberg
committed
static char *my_get_line(FILE *fp);
static int create_dir_hierarchy(char *outfile);
if(value)
*string = strdup(value);
else
*string = NULL;
}
static char *file2string(FILE *file)
{
char buffer[256];
char *ptr;
char *string=NULL;
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;
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 */
}
static 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);
if(node->infile)
free(node->infile);
free(node);
node = next; /* GOTO next */
}
}
static 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;
}
/* Structure for storing the information needed to build a multiple files
* section
*/
struct multi_files {
struct curl_forms form;
struct multi_files *next;
};
/* Add a new list entry possibly with a type_name
*/
Daniel Stenberg
committed
static struct multi_files *
AddMultiFiles (const char *file_name,
const char *type_name,
const char *show_filename,
struct multi_files **multi_start,
struct multi_files **multi_current)
{
struct multi_files *multi;
struct multi_files *multi_type = NULL;
Daniel Stenberg
committed
struct multi_files *multi_name = NULL;
multi = (struct multi_files *)malloc(sizeof(struct multi_files));
if (multi) {
memset(multi, 0, sizeof(struct multi_files));
multi->form.option = CURLFORM_FILE;
multi->form.value = file_name;
}
else
return NULL;
Daniel Stenberg
committed
if (!*multi_start)
*multi_start = multi;
if (type_name) {
multi_type = (struct multi_files *)malloc(sizeof(struct multi_files));
if (multi_type) {
memset(multi_type, 0, sizeof(struct multi_files));
multi_type->form.option = CURLFORM_CONTENTTYPE;
multi_type->form.value = type_name;
multi->next = multi_type;
Daniel Stenberg
committed
multi = multi_type;
}
else {
free (multi);
return NULL;
}
}
Daniel Stenberg
committed
if (show_filename) {
multi_name = (struct multi_files *)malloc(sizeof(struct multi_files));
if (multi_name) {
memset(multi_name, 0, sizeof(struct multi_files));
multi_name->form.option = CURLFORM_FILENAME;
multi_name->form.value = show_filename;
multi->next = multi_name;
multi = multi_name;
}
else {
Daniel Stenberg
committed
free (multi);
return NULL;
}
}
Daniel Stenberg
committed
if (*multi_current)
(*multi_current)->next = multi;
*multi_current = multi;
return *multi_current;
}
/* Free the items of the list.
*/
Daniel Stenberg
committed
static void FreeMultiInfo (struct multi_files *multi_start)
{
struct multi_files *multi;
Daniel Stenberg
committed
while (multi_start) {
multi = multi_start;
multi_start = multi_start->next;
free (multi);
}
}
/* Print list of OpenSSL engines supported.
*/
static void list_engines (const struct curl_slist *engines)
{
puts ("Build-time engines:");
if (!engines) {
puts (" <none>");
return;
}
for ( ; engines; engines = engines->next)
printf (" %s\n", engines->data);
}
/***************************************************************************
*
* formparse()
* Reads a 'name=value' paramter and builds the appropriate linked list.
*
* Specify files to upload with 'name=@filename'. Supports specified
* given Content-Type of the files. Such as ';type=<content-type>'.
*
* You may specify more than one file for a single name (field). Specify
* multiple files by writing it like:
*
* 'name=@filename,filename2,filename3'
*
* If you want content-types specified for each too, write them like:
*
* 'name=@filename;type=image/gif,filename2,filename3'
*
Daniel Stenberg
committed
* If you want custom headers added for a single part, write them in a separate
* file and do like this:
*
* 'name=foo;headers=@headerfile' or why not
* 'name=@filemame;headers=@headerfile'
*
* To upload a file, but to fake the file name that will be included in the
* formpost, do like this:
*
* 'name=@filename;filename=/dev/null'
*
* This function uses curl_formadd to fulfill it's job. Is heavily based on
* the old curl_formparse code.
*
***************************************************************************/
#define FORM_FILE_SEPARATOR ','
#define FORM_TYPE_SEPARATOR ';'
static int formparse(char *input,
Daniel Stenberg
committed
struct curl_httppost **httppost,
struct curl_httppost **last_post)
{
/* nextarg MUST be a string in the format 'name=contents' and we'll
build a linked list with the info */
char name[256];
char *contents;
char major[128];
char minor[128];
char *contp;
const char *type = NULL;
char *sep;
char *sep2;
Daniel Stenberg
committed
if((1 == sscanf(input, "%255[^=]=", name)) &&
(contp = strchr(input, '='))) {
/* the input was using the correct format */
Daniel Stenberg
committed
/* Allocate the contents */
contents = strdup(contp+1);
if(!contents) {
fprintf(stderr, "out of memory\n");
return 1;
}
contp = contents;
if('@' == contp[0]) {
struct multi_files *multi_start = NULL, *multi_current = NULL;
/* we use the @-letter to indicate file name(s) */
contp++;
multi_start = multi_current=NULL;
do {
/* since this was a file, it may have a content-type specifier
at the end too, or a filename. Or both. */
Daniel Stenberg
committed
char *ptr;
char *filename=NULL;
sep=strchr(contp, FORM_TYPE_SEPARATOR);
sep2=strchr(contp, FORM_FILE_SEPARATOR);
/* pick the closest */
if(sep2 && (sep2 < sep)) {
sep = sep2;
/* no type was specified! */
}
Daniel Stenberg
committed
type = NULL;
/* if we got here on a comma, don't do much */
if(FORM_FILE_SEPARATOR == *sep)
ptr = NULL;
else
Daniel Stenberg
committed
ptr = sep+1;
*sep=0; /* terminate file name at separator */
while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
Daniel Stenberg
committed
/* pass all white spaces */
while(isspace((int)*ptr))
ptr++;
Daniel Stenberg
committed
if(curlx_strnequal("type=", ptr, 5)) {
Daniel Stenberg
committed
/* set type pointer */
type = &ptr[5];
Daniel Stenberg
committed
/* verify that this is a fine type specifier */
if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
major, minor)) {
fprintf(stderr, "Illegally formatted content-type field!\n");
free(contents);
FreeMultiInfo (multi_start);
return 2; /* illegal content-type syntax! */
}
/* now point beyond the content-type specifier */
sep = (char *)type + strlen(major)+strlen(minor)+1;
if(*sep) {
*sep=0; /* zero terminate type string */
Daniel Stenberg
committed
ptr=sep+1;
}
else
ptr = NULL; /* end */
Daniel Stenberg
committed
}
Daniel Stenberg
committed
else if(curlx_strnequal("filename=", ptr, 9)) {
Daniel Stenberg
committed
filename = &ptr[9];
ptr=strchr(filename, FORM_TYPE_SEPARATOR);
if(!ptr) {
ptr=strchr(filename, FORM_FILE_SEPARATOR);
}
if(ptr) {
*ptr=0; /* zero terminate */
ptr++;
}
}
else
/* confusion, bail out of loop */
break;
Daniel Stenberg
committed
/* find the following comma */
if(ptr)
sep=strchr(ptr, FORM_FILE_SEPARATOR);
else
sep=NULL;
}
else {
sep=strchr(contp, FORM_FILE_SEPARATOR);
}
if(sep) {
/* the next file name starts here */
*sep =0;
sep++;
}
/* if type == NULL curl_formadd takes care of the problem */
Daniel Stenberg
committed
if (!AddMultiFiles (contp, type, filename, &multi_start,
&multi_current)) {
fprintf(stderr, "Error building form post!\n");
free(contents);
Daniel Stenberg
committed
FreeMultiInfo (multi_start);
return 3;
}
contp = sep; /* move the contents pointer to after the separator */
Daniel Stenberg
committed
} while(sep && *sep); /* loop if there's another file name */
Daniel Stenberg
committed
/* now we add the multiple files section */
if (multi_start) {
struct curl_forms *forms = NULL;
struct multi_files *ptr = multi_start;
unsigned int i, count = 0;
while (ptr) {
ptr = ptr->next;
++count;
}
forms =
(struct curl_forms *)malloc((count+1)*sizeof(struct curl_forms));
if (!forms)
{
fprintf(stderr, "Error building form post!\n");
free(contents);
Daniel Stenberg
committed
FreeMultiInfo (multi_start);
return 4;
}
for (i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
{
forms[i].option = ptr->form.option;
forms[i].value = ptr->form.value;
}
forms[count].option = CURLFORM_END;
Daniel Stenberg
committed
FreeMultiInfo (multi_start);
Daniel Stenberg
committed
if (curl_formadd(httppost, last_post,
CURLFORM_COPYNAME, name,
CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
fprintf(stderr, "curl_formadd failed!\n");
free(forms);
free(contents);
return 5;
}
free(forms);
}
}
else {
struct curl_forms info[4];
int i = 0;
char *ct = strstr(contp, ";type=");
info[i].option = CURLFORM_COPYNAME;
info[i].value = name;
i++;
if(ct) {
info[i].option = CURLFORM_CONTENTTYPE;
info[i].value = &ct[6];
i++;
ct[0]=0; /* zero terminate here */
}
if( contp[0]=='<' ) {
info[i].option = CURLFORM_FILECONTENT;
info[i].value = contp+1;
i++;
info[i].option = CURLFORM_END;
Daniel Stenberg
committed
if (curl_formadd(httppost, last_post,
CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
fprintf(stderr, "curl_formadd failed, possibly the file %s is bad!\n",
contp+1);
free(contents);