/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, , 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. * * $Id: main.c,v 1.420 2007-06-20 21:57:28 bagder Exp $ ***************************************************************************/ #include "setup.h" #include #include #include #include #include #include #include #include #include #include "urlglob.h" #include "writeout.h" #include "getpass.h" #include "homedir.h" #include "curlutil.h" #ifdef USE_MANUAL #include "hugehelp.h" #endif #ifdef USE_ENVIRONMENT #include "writeenv.h" #endif #define CURLseparator "--_curl_--" #ifdef __NOVELL_LIBC__ #include #endif #include "version.h" #ifdef HAVE_IO_H /* typical win32 habit */ #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_UTIME_H #include #else #ifdef HAVE_SYS_UTIME_H #include #endif #endif /* HAVE_UTIME_H */ #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif #ifdef HAVE_LOCALE_H #include /* for setlocale() */ #endif #define ENABLE_CURLX_PRINTF /* make the curlx header define all printf() functions to use the curlx_* versions instead */ #include /* header from the libcurl directory */ #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) #include /* set default codesets for iconv */ #ifndef CURL_ICONV_CODESET_OF_NETWORK #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" #endif #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ /* The last #include file should be: */ #ifdef CURLDEBUG #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" #endif #define DEFAULT_MAXREDIRS 50L #if defined(O_BINARY) && defined(HAVE_SETMODE) #ifdef __HIGHC__ #define SET_BINMODE(file) _setmode(file,O_BINARY) #else #define SET_BINMODE(file) setmode(fileno(file),O_BINARY) #endif #else #define SET_BINMODE(file) ((void)0) #endif #ifdef MSDOS #include const char *msdosify(const char *); char *rename_if_dos_device_name(char *); #ifdef DJGPP /* we want to glob our own argv[] */ char **__crt0_glob_function (char *arg) { (void)arg; return (char**)0; } #endif /* __DJGPP__ */ #endif /* MSDOS */ #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 typedef enum { HTTPREQ_UNSPEC, HTTPREQ_GET, HTTPREQ_HEAD, HTTPREQ_POST, HTTPREQ_SIMPLEPOST, HTTPREQ_CUSTOM, HTTPREQ_LAST } HttpReq; /* Just a set of bits */ #ifndef CONF_DEFAULT #define CONF_DEFAULT 0 #endif #define CONF_ISATTY (1<<0) /* output to tty! */ #define CONF_AUTO_REFERER (1<<4) /* the automatic referer-system please! */ #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 */ #ifdef WIN32 #include #define F_OK 0 #define mkdir(x,y) (mkdir)(x) #endif #ifdef VMS #include "curlmsg_vms.h" #endif /* 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 #ifdef CURL_DOES_CONVERSIONS #ifdef HAVE_ICONV iconv_t inbound_cd = (iconv_t)-1; iconv_t outbound_cd = (iconv_t)-1; /* * convert_to_network() is an internal function to convert * from the host encoding to ASCII on non-ASCII platforms. */ static CURLcode convert_to_network(char *buffer, size_t length) { CURLcode rc; /* translate from the host encoding to the network encoding */ char *input_ptr, *output_ptr; size_t in_bytes, out_bytes; /* open an iconv conversion descriptor if necessary */ if(outbound_cd == (iconv_t)-1) { outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST); if(outbound_cd == (iconv_t)-1) { return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; rc = iconv(outbound_cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if ((rc == -1) || (in_bytes != 0)) { return CURLE_CONV_FAILED; } return CURLE_OK; } /* * convert_from_network() is an internal function * for performing ASCII conversions on non-ASCII platforms. */ static CURLcode convert_from_network(char *buffer, size_t length) { CURLcode rc; /* translate from the network encoding to the host encoding */ char *input_ptr, *output_ptr; size_t in_bytes, out_bytes; /* open an iconv conversion descriptor if necessary */ if(inbound_cd == (iconv_t)-1) { inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); if(inbound_cd == (iconv_t)-1) { return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; rc = iconv(inbound_cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if ((rc == -1) || (in_bytes != 0)) { return CURLE_CONV_FAILED; } return CURLE_OK; } #endif /* HAVE_ICONV */ static char convert_char(curl_infotype infotype, char this_char) { /* determine how this specific character should be displayed */ switch(infotype) { case CURLINFO_DATA_IN: case CURLINFO_DATA_OUT: case CURLINFO_SSL_DATA_IN: case CURLINFO_SSL_DATA_OUT: /* data, treat as ASCII */ if ((this_char >= 0x20) && (this_char < 0x7f)) { /* printable ASCII hex value: convert to host encoding */ convert_from_network(&this_char, 1); } else { /* non-printable ASCII, use a replacement character */ return UNPRINTABLE_CHAR; } /* fall through to default */ default: /* treat as host encoding */ if (ISPRINT(this_char) && (this_char != '\t') && (this_char != '\r') && (this_char != '\n')) { /* printable characters excluding tabs and line end characters */ return this_char; } break; } /* non-printable, use a replacement character */ return UNPRINTABLE_CHAR; } #endif /* CURL_DOES_CONVERSIONS */ #ifdef WIN32 /* * 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 static int ftruncate64 (int fd, curl_off_t where) { 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; if (write(fd, 0, 0) < 0) rc = -1; _lseeki64(fd, curr, SEEK_SET); return rc; } #define ftruncate(fd,where) ftruncate64(fd,where) #endif typedef enum { TRACE_BIN, /* tcpdump inspired look */ TRACE_ASCII, /* like *BIN but without the hex output */ TRACE_PLAIN /* -v/--verbose type */ } trace; struct OutStruct { char *filename; FILE *stream; struct Configurable *config; curl_off_t bytes; /* amount written so far */ curl_off_t init; /* original size (non-zero when appending) */ }; struct Configurable { bool remote_time; char *random_file; char *egd_file; char *useragent; 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 */ long authtype; /* auth bitmask */ bool use_resume; bool resume_from_current; bool disable_epsv; bool disable_eprt; curl_off_t resume_from; char *postfields; long postfieldsize; char *referer; long timeout; long connecttimeout; long maxredirs; curl_off_t max_filesize; char *headerfile; char *ftpport; char *iface; int localport; int localportrange; unsigned short porttouse; char *range; long low_speed_limit; long low_speed_time; bool showerror; char *userpwd; char *proxyuserpwd; char *proxy; bool proxytunnel; 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 */ char *cipher_list; char *cert; char *cert_type; char *cacert; char *capath; char *key; char *key_type; char *key_passwd; char *pubkey; char *engine; bool list_engines; bool crlf; char *customrequest; char *krb4level; char *trace_dump; /* file to dump the network trace to, or NULL */ FILE *trace_stream; bool trace_fopened; trace tracetype; bool tracetime; /* include timestamp? */ long httpversion; bool progressmode; bool nobuffer; bool globoff; bool use_httpget; bool insecure_ok; /* set TRUE to allow insecure SSL connects */ bool create_dirs; bool ftp_create_dirs; bool ftp_skip_ip; bool proxyntlm; bool proxydigest; bool proxybasic; bool proxyanyauth; char *writeout; /* %-styled format string to output */ bool writeenv; /* write results to environment, if available */ FILE *errors; /* if stderr redirect is requested */ bool errors_fopened; struct curl_slist *quote; struct curl_slist *postquote; struct curl_slist *prequote; long ssl_version; long ip_version; curl_TimeCond timecond; time_t condtime; struct curl_slist *headers; struct curl_httppost *httppost; struct curl_httppost *last_post; struct curl_slist *telnet_options; HttpReq httpreq; /* for bandwidth limiting features: */ curl_off_t sendpersecond; /* send to peer */ curl_off_t recvpersecond; /* receive from peer */ struct timeval lastsendtime; size_t lastsendsize; struct timeval lastrecvtime; size_t lastrecvsize; bool ftp_ssl; bool ftp_ssl_reqd; bool ftp_ssl_control; bool ftp_ssl_ccc; int ftp_ssl_ccc_mode; char *socksproxy; /* set to server string */ int socksver; /* set to CURLPROXY_SOCKS* define */ bool tcp_nodelay; long req_retry; /* number of retries */ long retry_delay; /* delay between retries (in seconds) */ long retry_maxtime; /* maximum time to keep retrying */ char *ftp_account; /* for ACCT */ char *ftp_alternative_to_user; /* send command if USER/PASS fails */ int ftp_filemethod; bool ignorecl; /* --ignore-content-length */ bool disable_sessionid; char *libcurl; /* output libcurl code to this file name */ bool raw; struct OutStruct *outs; }; #define WARN_PREFIX "Warning: " #define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX)) /* produce this text message to the user unless mute was selected */ static void warnf(struct Configurable *config, const char *fmt, ...) { if(!(config->conf & CONF_MUTE)) { va_list ap; int len; char *ptr; char print_buffer[256]; va_start(ap, fmt); va_start(ap, fmt); len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); va_end(ap); ptr = print_buffer; while(len > 0) { fputs(WARN_PREFIX, config->errors); if(len > (int)WARN_TEXTWIDTH) { int cut = WARN_TEXTWIDTH-1; while(!ISSPACE(ptr[cut]) && cut) { cut--; } if(0 == cut) /* not a single cutting position was found, just cut it at the max text width then! */ cut = WARN_TEXTWIDTH-1; fwrite(ptr, cut + 1, 1, config->errors); fputs("\n", config->errors); ptr += cut+1; /* skip the space too */ len -= cut; } else { fputs(ptr, config->errors); len = 0; } } } } /* * 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) { #ifdef DJGPP /* stop stat() wasting time */ _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; #endif 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) { curl_global_cleanup(); #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) /* close iconv conversion descriptor */ if(inbound_cd != (iconv_t)-1) iconv_close(inbound_cd); if(outbound_cd != (iconv_t)-1) iconv_close(outbound_cd); #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ } static int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store) { if((*store == HTTPREQ_UNSPEC) || (*store == req)) { *store = req; return 0; } warnf(config, "You can only select one HTTP request!\n"); return 1; } static void helpf(const 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' " #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 */ static void help(void) { int i; static const char * const helptext[]={ "Usage: curl [options...] ", "Options: (H) means HTTP/HTTPS only, (F) means FTP only", " -a/--append Append to target file when uploading (F)", " -A/--user-agent User-Agent to send to server (H)", " --anyauth Pick \"any\" authentication method (H)", " -b/--cookie Cookie string or file to read cookies from (H)", " --basic Use HTTP Basic Authentication (H)", " -B/--use-ascii Use ASCII/text transfer", " -c/--cookie-jar Write cookies to this file after operation (H)", " -C/--continue-at Resumed transfer offset", " -d/--data HTTP POST data (H)", " --data-ascii HTTP POST ASCII data (H)", " --data-binary HTTP POST binary data (H)", " --negotiate Use HTTP Negotiate Authentication (H)", " --digest Use HTTP Digest Authentication (H)", " --disable-eprt Inhibit using EPRT or LPRT (F)", " --disable-epsv Inhibit using EPSV (F)", " -D/--dump-header Write the headers to this file", " --egd-file EGD socket path for random data (SSL)", " --tcp-nodelay Use the TCP_NODELAY option", #ifdef USE_ENVIRONMENT " --environment Write results to environment variables (RISC OS)", #endif " -e/--referer Referer URL (H)", " -E/--cert Client certificate file and password (SSL)", " --cert-type Certificate file type (DER/PEM/ENG) (SSL)", " --key Private key file name (SSL/SSH)", " --key-type Private key file type (DER/PEM/ENG) (SSL)", " --pass Pass phrase for the private key (SSL/SSH)", " --pubkey Public key file name (SSH)", " --engine Crypto engine to use (SSL). \"--engine list\" for list", " --cacert CA certificate to verify peer against (SSL)", " --capath CA directory (made using c_rehash) to verify", " peer against (SSL)", " --ciphers SSL ciphers to use (SSL)", " --compressed Request compressed response (using deflate or gzip)", " --connect-timeout Maximum time allowed for connection", " --create-dirs Create necessary local directory hierarchy", " --crlf Convert LF to CRLF in upload", " -f/--fail Fail silently (no output at all) on HTTP errors (H)", " --ftp-account Account data to send when requested by server (F)", " --ftp-alternative-to-user String to replace \"USER [name]\" (F)", " --ftp-create-dirs Create the remote dirs if not present (F)", " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)", " --ftp-pasv Use PASV/EPSV instead of PORT (F)", " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n" " --ftp-ssl Try SSL/TLS for ftp transfer (F)", " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)", " --ftp-ssl-reqd Require SSL/TLS for ftp transfer (F)", " --ftp-ssl-ccc Send CCC after authenticating (F)", " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)", " -F/--form Specify HTTP multipart POST data (H)", " --form-string 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 Custom header to pass to server (H)", " --ignore-content-length Ignore the HTTP Content-Length header", " -i/--include Include protocol headers in the output (H/F)", " -I/--head Show document info only", " -j/--junk-session-cookies Ignore session cookies read from file (H)", " --interface Specify network interface/address to use", " --krb4 Enable krb4 with specified security level (F)", " -k/--insecure Allow connections to SSL sites without certs (H)", " -K/--config Specify which config file to read", " --libcurl Dump libcurl equivalent code of this command line", " -l/--list-only List only names of an FTP directory (F)", " --limit-rate Limit transfer speed to this rate", " --local-port [-num] Force use of these local port numbers\n", " -L/--location Follow Location: hints (H)", " --location-trusted Follow Location: and send authentication even ", " to other hostnames (H)", " -m/--max-time Maximum time allowed for the transfer", " --max-redirs Maximum number of redirects allowed (H)", " --max-filesize Maximum file size to download (H/F)", " -M/--manual Display the full manual", " -n/--netrc Must read .netrc for user name and password", " --netrc-optional Use either .netrc or URL; overrides -n", " --ntlm Use HTTP NTLM authentication (H)", " -N/--no-buffer Disable buffering of the output stream", " --no-sessionid Disable SSL session-ID reusing (SSL)", " -o/--output Write output to instead of stdout", " -O/--remote-name Write output to a file named as the remote file", " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)", " --proxy-anyauth Pick \"any\" proxy authentication method (H)", " --proxy-basic Use Basic authentication on the proxy (H)", " --proxy-digest Use Digest authentication on the proxy (H)", " --proxy-ntlm Use NTLM authentication on the proxy (H)", " -P/--ftp-port
Use PORT with address instead of PASV (F)", " -q If used as the first parameter disables .curlrc", " -Q/--quote Send command(s) to server before file transfer (F/SFTP)", " -r/--range Retrieve a byte range from a HTTP/1.1 or FTP server", " --random-file File for reading random data from (SSL)", " --raw Pass HTTP \"raw\", without any transfer decoding (H)", " -R/--remote-time Set the remote file's time on the local output", " --retry Retry request times if transient problems occur", " --retry-delay When retrying, wait this many seconds between each", " --retry-max-time 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", " --socks4 Use SOCKS4 proxy on given host + port", " --socks5 Use SOCKS5 proxy on given host + port", " --stderr Where to redirect stderr. - means stdout", " -t/--telnet-option Set telnet option", " --trace Write a debug trace to the given file", " --trace-ascii Like --trace but without the hex output", " --trace-time Add time stamps to trace/verbose output", " -T/--upload-file Transfer to remote site", " --url Set URL to work with", " -u/--user Set server user and password", " -U/--proxy-user Set proxy user and password", " -v/--verbose Make the operation more talkative", " -V/--version Show version number and quit", #ifdef MSDOS " --wdebug Turn on Watt-32 debugging under DJGPP", #endif " -w/--write-out [format] What to output after completion", " -x/--proxy Use HTTP proxy on given port", " -X/--request 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", " -z/--time-cond