1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
28 #include <sys/types.h>
33 #if defined(MSDOS) || defined(WIN32)
34 # if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
39 #include <curl/curl.h>
49 #ifdef USE_ENVIRONMENT
56 #define CURLseparator "--_curl_--"
59 #ifdef __NOVELL_LIBC__
63 #define mkdir mkdir_510
69 #ifdef HAVE_IO_H /* typical win32 habit */
84 #ifdef HAVE_SYS_UTIME_H
85 #include <sys/utime.h>
88 #endif /* HAVE_UTIME_H */
94 #ifdef HAVE_SYS_POLL_H
96 #elif defined(HAVE_POLL_H)
101 #include <locale.h> /* for setlocale() */
104 #define ENABLE_CURLX_PRINTF
105 /* make the curlx header define all printf() functions to use the curlx_*
107 #include "curlx.h" /* header from the libcurl directory */
109 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
111 /* set default codesets for iconv */
112 #ifndef CURL_ICONV_CODESET_OF_NETWORK
113 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
115 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
117 #ifdef HAVE_NETINET_IN_H
118 #include <netinet/in.h> /* for IPPROTO_TCP */
120 #ifdef HAVE_NETINET_TCP_H
121 #include <netinet/tcp.h> /* for TCP_KEEPIDLE, TCP_KEEPINTVL */
124 #include "os-specific.h"
126 /* The last #include file should be: */
128 #ifndef CURLTOOLDEBUG
129 #define MEMDEBUG_NODEFINES
131 /* This is low-level hard-hacking memory leak tracking and similar. Using
132 the library level code from this client-side is ugly, but we do this
133 anyway for convenience. */
134 #include "memdebug.h"
138 static int vms_show = 0;
142 #define PRINT_LINES_PAUSE 23
145 #if defined(__SYMBIAN32__)
146 #define PRINT_LINES_PAUSE 16
147 #define pressanykey() getchar()
150 #define DEFAULT_MAXREDIRS 50L
152 #if defined(O_BINARY) && defined(HAVE_SETMODE)
154 #define SET_BINMODE(file) _setmode(file,O_BINARY)
156 #define SET_BINMODE(file) setmode(fileno(file),O_BINARY)
159 #define SET_BINMODE(file) ((void)0)
163 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
164 source code but yet it doesn't ruin anything */
168 #if defined(MSDOS) || defined(WIN32)
170 static const char *msdosify(const char *);
171 static char *rename_if_dos_device_name(char *);
172 static char *sanitize_dos_name(char *);
176 # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
178 # define S_ISCHR(m) (0) /* cannot tell if file is a device */
183 # define _use_lfn(f) (1) /* long file names always available */
184 #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
185 # define _use_lfn(f) (0) /* long file names never available */
188 #endif /* MSDOS || WIN32 */
195 /* we want to glob our own argv[] */
196 char **__crt0_glob_function (char *arg)
201 #endif /* __DJGPP__ */
205 #define STDIN_FILENO fileno(stdin)
208 #ifndef STDOUT_FILENO
209 #define STDOUT_FILENO fileno(stdout)
212 #ifndef STDERR_FILENO
213 #define STDERR_FILENO fileno(stderr)
216 #define CURL_PROGRESS_STATS 0 /* default progress display */
217 #define CURL_PROGRESS_BAR 1
230 * Large file support (>2Gb) using WIN32 functions.
233 #ifdef USE_WIN32_LARGE_FILES
235 # include <sys/types.h>
236 # include <sys/stat.h>
237 # define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
238 # define fstat(fdes,stp) _fstati64(fdes, stp)
239 # define stat(fname,stp) _stati64(fname, stp)
240 # define struct_stat struct _stati64
241 # define LSEEK_ERROR (__int64)-1
245 * Small file support (<2Gb) using WIN32 functions.
248 #ifdef USE_WIN32_SMALL_FILES
250 # include <sys/types.h>
251 # include <sys/stat.h>
252 # define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
253 # define fstat(fdes,stp) _fstat(fdes, stp)
254 # define stat(fname,stp) _stat(fname, stp)
255 # define struct_stat struct _stat
256 # define LSEEK_ERROR (long)-1
260 # define struct_stat struct stat
264 # define LSEEK_ERROR (off_t)-1
269 # define mkdir(x,y) (mkdir)(x)
271 # define PATH_MAX MAX_PATH
278 * Default sizeof(off_t) in case it hasn't been defined in config file.
282 # if defined(__VMS) && !defined(__VAX)
283 # if defined(_LARGEFILE)
284 # define SIZEOF_OFF_T 8
286 # elif defined(__OS400__) && defined(__ILEC400__)
287 # if defined(_LARGE_FILES)
288 # define SIZEOF_OFF_T 8
290 # elif defined(__MVS__) && defined(__IBMC__)
291 # if defined(_LP64) || defined(_LARGE_FILES)
292 # define SIZEOF_OFF_T 8
294 # elif defined(__370__) && defined(__IBMC__)
295 # if defined(_LP64) || defined(_LARGE_FILES)
296 # define SIZEOF_OFF_T 8
299 # define SIZEOF_OFF_T 8
301 # ifndef SIZEOF_OFF_T
302 # define SIZEOF_OFF_T 4
306 #ifdef CURL_DOES_CONVERSIONS
308 iconv_t inbound_cd = (iconv_t)-1;
309 iconv_t outbound_cd = (iconv_t)-1;
312 * convert_to_network() is an internal function to convert
313 * from the host encoding to ASCII on non-ASCII platforms.
316 convert_to_network(char *buffer, size_t length)
320 /* translate from the host encoding to the network encoding */
321 char *input_ptr, *output_ptr;
322 size_t in_bytes, out_bytes;
324 /* open an iconv conversion descriptor if necessary */
325 if(outbound_cd == (iconv_t)-1) {
326 outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
327 CURL_ICONV_CODESET_OF_HOST);
328 if(outbound_cd == (iconv_t)-1) {
329 return CURLE_CONV_FAILED;
333 input_ptr = output_ptr = buffer;
334 in_bytes = out_bytes = length;
335 rc = iconv(outbound_cd, &input_ptr, &in_bytes,
336 &output_ptr, &out_bytes);
337 if((rc == -1) || (in_bytes != 0)) {
338 return CURLE_CONV_FAILED;
345 * convert_from_network() is an internal function
346 * for performing ASCII conversions on non-ASCII platforms.
349 convert_from_network(char *buffer, size_t length)
353 /* translate from the network encoding to the host encoding */
354 char *input_ptr, *output_ptr;
355 size_t in_bytes, out_bytes;
357 /* open an iconv conversion descriptor if necessary */
358 if(inbound_cd == (iconv_t)-1) {
359 inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
360 CURL_ICONV_CODESET_OF_NETWORK);
361 if(inbound_cd == (iconv_t)-1) {
362 return CURLE_CONV_FAILED;
366 input_ptr = output_ptr = buffer;
367 in_bytes = out_bytes = length;
368 rc = iconv(inbound_cd, &input_ptr, &in_bytes,
369 &output_ptr, &out_bytes);
370 if((rc == -1) || (in_bytes != 0)) {
371 return CURLE_CONV_FAILED;
376 #endif /* HAVE_ICONV */
379 char convert_char(curl_infotype infotype, char this_char)
381 /* determine how this specific character should be displayed */
383 case CURLINFO_DATA_IN:
384 case CURLINFO_DATA_OUT:
385 case CURLINFO_SSL_DATA_IN:
386 case CURLINFO_SSL_DATA_OUT:
387 /* data, treat as ASCII */
388 if((this_char >= 0x20) && (this_char < 0x7f)) {
389 /* printable ASCII hex value: convert to host encoding */
390 convert_from_network(&this_char, 1);
393 /* non-printable ASCII, use a replacement character */
394 return UNPRINTABLE_CHAR;
396 /* fall through to default */
398 /* treat as host encoding */
399 if(ISPRINT(this_char)
400 && (this_char != '\t')
401 && (this_char != '\r')
402 && (this_char != '\n')) {
403 /* printable characters excluding tabs and line end characters */
408 /* non-printable, use a replacement character */
409 return UNPRINTABLE_CHAR;
411 #endif /* CURL_DOES_CONVERSIONS */
416 /* 64-bit lseek-like function unavailable */
417 # define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
422 /* 64-bit lseek-like function unavailable */
423 # define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
425 # define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
429 #ifndef HAVE_FTRUNCATE
430 #define HAVE_FTRUNCATE 1
434 * Truncate a file handle at a 64-bit position 'where'.
437 static int ftruncate64(int fd, curl_off_t where)
439 if(_lseeki64(fd, where, SEEK_SET) < 0)
442 if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
447 #define ftruncate(fd,where) ftruncate64(fd,where)
452 TRACE_NONE, /* no trace/verbose output at all! */
453 TRACE_BIN, /* tcpdump inspired look */
454 TRACE_ASCII, /* like *BIN but without the hex output */
455 TRACE_PLAIN /* -v/--verbose type */
461 struct Configurable *config;
462 curl_off_t bytes; /* amount written so far */
463 curl_off_t init; /* original size (non-zero when appending) */
466 struct Configurable {
467 CURL *easy; /* once we have one, we keep it here */
472 char *cookie; /* single line with specified cookies */
473 char *cookiejar; /* write to this file */
474 char *cookiefile; /* read from this file */
475 bool cookiesession; /* new session? */
476 bool encoding; /* Accept-Encoding please */
477 long authtype; /* auth bitmask */
479 bool resume_from_current;
486 bool proto_redir_present;
487 curl_off_t resume_from;
489 curl_off_t postfieldsize;
494 curl_off_t max_filesize;
500 unsigned short porttouse;
502 long low_speed_limit;
508 int proxyver; /* set to CURLPROXY_HTTP* define */
511 struct curl_slist *mail_rcpt;
513 bool ftp_append; /* APPE on ftp */
514 bool mute; /* shutup */
515 bool use_ascii; /* select ascii or text transfer */
516 bool autoreferer; /* automatically set referer */
517 bool failonerror; /* fail on (HTTP) errors */
518 bool include_headers; /* send headers to data output */
519 bool no_body; /* don't get the body */
520 bool dirlistonly; /* only get the FTP dir list */
521 bool followlocation; /* follow http redirects */
522 bool unrestricted_auth; /* Continue to send authentication (user+password)
523 when following ocations, even when hostname
528 bool isatty; /* updated internally only if the output is a tty */
529 struct getout *url_list; /* point to the first node */
530 struct getout *url_last; /* point to the last/current node */
531 struct getout *url_get; /* point to the node to fill in URL */
532 struct getout *url_out; /* point to the node to fill in outfile */
549 char *trace_dump; /* file to dump the network trace to, or NULL */
553 bool tracetime; /* include timestamp? */
557 bool readbusy; /* set when reading input returns EAGAIN */
560 bool insecure_ok; /* set TRUE to allow insecure SSL connects */
562 bool ftp_create_dirs;
569 char *writeout; /* %-styled format string to output */
570 bool writeenv; /* write results to environment, if available */
571 FILE *errors; /* if stderr redirect is requested */
573 struct curl_slist *quote;
574 struct curl_slist *postquote;
575 struct curl_slist *prequote;
578 curl_TimeCond timecond;
580 struct curl_slist *headers;
581 struct curl_httppost *httppost;
582 struct curl_httppost *last_post;
583 struct curl_slist *telnet_options;
584 struct curl_slist *resolve;
587 /* for bandwidth limiting features: */
588 curl_off_t sendpersecond; /* send to peer */
589 curl_off_t recvpersecond; /* receive from peer */
593 bool ftp_ssl_control;
595 int ftp_ssl_ccc_mode;
597 char *socksproxy; /* set to server string */
598 int socksver; /* set to CURLPROXY_SOCKS* define */
599 char *socks5_gssapi_service; /* set service name for gssapi principal
601 int socks5_gssapi_nec ; /* The NEC reference server does not protect
602 * the encryption type exchange */
605 long req_retry; /* number of retries */
606 long retry_delay; /* delay between retries (in seconds) */
607 long retry_maxtime; /* maximum time to keep retrying */
609 char *ftp_account; /* for ACCT */
610 char *ftp_alternative_to_user; /* send command if USER/PASS fails */
612 long tftp_blksize; /* TFTP BLKSIZE option */
613 bool ignorecl; /* --ignore-content-length */
614 bool disable_sessionid;
616 char *libcurl; /* output libcurl code to this file name */
620 bool nokeepalive; /* for keepalive needs */
622 bool content_disposition; /* use Content-disposition filename */
624 int default_node_flags; /* default flags to seach for each 'node', which is
625 basically each given URL to transfer */
626 struct OutStruct *outs;
627 bool xattr; /* store metadata in extended attributes */
630 #define WARN_PREFIX "Warning: "
631 #define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
632 /* produce this text message to the user unless mute was selected */
633 static void warnf(struct Configurable *config, const char *fmt, ...)
639 char print_buffer[256];
642 len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
647 fputs(WARN_PREFIX, config->errors);
649 if(len > (int)WARN_TEXTWIDTH) {
650 int cut = WARN_TEXTWIDTH-1;
652 while(!ISSPACE(ptr[cut]) && cut) {
656 /* not a single cutting position was found, just cut it at the
657 max text width then! */
658 cut = WARN_TEXTWIDTH-1;
660 (void)fwrite(ptr, cut + 1, 1, config->errors);
661 fputs("\n", config->errors);
662 ptr += cut+1; /* skip the space too */
666 fputs(ptr, config->errors);
674 * This is the main global constructor for the app. Call this before
675 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
676 * used, or havoc may be the result.
678 static CURLcode main_init(void)
681 /* stop stat() wasting time */
682 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
685 return curl_global_init(CURL_GLOBAL_DEFAULT);
689 * This is the main global destructor for the app. Call this after
690 * _all_ libcurl usage is done.
692 static void main_free(void)
694 curl_global_cleanup();
695 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
696 /* close iconv conversion descriptor */
697 if(inbound_cd != (iconv_t)-1)
698 iconv_close(inbound_cd);
699 if(outbound_cd != (iconv_t)-1)
700 iconv_close(outbound_cd);
701 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
704 static int SetHTTPrequest(struct Configurable *config,
705 HttpReq req, HttpReq *store)
707 if((*store == HTTPREQ_UNSPEC) ||
712 warnf(config, "You can only select one HTTP request!\n");
716 static void helpf(FILE *errors, const char *fmt, ...)
721 fputs("curl: ", errors); /* prefix it */
722 vfprintf(errors, fmt, ap);
725 fprintf(errors, "curl: try 'curl --help' "
727 "or 'curl --manual' "
729 "for more information\n");
733 * A chain of these nodes contain URL to get and where to put the URL's
737 struct getout *next; /* next one */
738 char *url; /* the URL we deal with */
739 char *outfile; /* where to store the output */
740 char *infile; /* file to upload, if GETOUT_UPLOAD is set */
741 int flags; /* options */
743 #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
744 #define GETOUT_URL (1<<1) /* set when URL is deemed done */
745 #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
746 #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
747 #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
749 static void help(void)
752 /* A few of these source lines are >80 columns wide, but that's only because
753 breaking the strings narrower makes this chunk look even worse!
755 Starting with 7.18.0, this list of command line options is sorted based
756 on the long option name. It is not done automatically, although a command
757 line like the following can help out:
759 curl --help | cut -c5- | grep "^-" | sort
761 static const char * const helptext[]={
762 "Usage: curl [options...] <url>",
763 "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
764 " --anyauth Pick \"any\" authentication method (H)",
765 " -a/--append Append to target file when uploading (F/SFTP)",
766 " --basic Use HTTP Basic Authentication (H)",
767 " --cacert <file> CA certificate to verify peer against (SSL)",
768 " --capath <directory> CA directory to verify peer against (SSL)",
769 " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
770 " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
771 " --ciphers <list> SSL ciphers to use (SSL)",
772 " --compressed Request compressed response (using deflate or gzip)",
773 " -K/--config <file> Specify which config file to read",
774 " --connect-timeout <seconds> Maximum time allowed for connection",
775 " -C/--continue-at <offset> Resumed transfer offset",
776 " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
777 " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
778 " --create-dirs Create necessary local directory hierarchy",
779 " --crlf Convert LF to CRLF in upload",
780 " --crlfile <file> Get a CRL list in PEM format from the given file",
781 " -d/--data <data> HTTP POST data (H)",
782 " --data-ascii <data> HTTP POST ASCII data (H)",
783 " --data-binary <data> HTTP POST binary data (H)",
784 " --data-urlencode <name=data/name@filename> HTTP POST data url encoded (H)",
785 " --digest Use HTTP Digest Authentication (H)",
786 " --disable-eprt Inhibit using EPRT or LPRT (F)",
787 " --disable-epsv Inhibit using EPSV (F)",
788 " -D/--dump-header <file> Write the headers to this file",
789 " --egd-file <file> EGD socket path for random data (SSL)",
790 " --engine <eng> Crypto engine to use (SSL). \"--engine list\" for list",
791 #ifdef USE_ENVIRONMENT
792 " --environment Write results to environment variables (RISC OS)",
794 " -f/--fail Fail silently (no output at all) on HTTP errors (H)",
795 " -F/--form <name=content> Specify HTTP multipart POST data (H)",
796 " --form-string <name=string> Specify HTTP multipart POST data (H)",
797 " --ftp-account <data> Account data to send when requested by server (F)",
798 " --ftp-alternative-to-user <cmd> String to replace \"USER [name]\" (F)",
799 " --ftp-create-dirs Create the remote dirs if not present (F)",
800 " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
801 " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
802 " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
803 " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
804 " --ftp-pret Send PRET before PASV (for drftpd) (F)",
805 " --ftp-ssl-ccc Send CCC after authenticating (F)",
806 " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
807 " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
808 " -G/--get Send the -d data with a HTTP GET (H)",
809 " -g/--globoff Disable URL sequences and ranges using {} and []",
810 " -H/--header <line> Custom header to pass to server (H)",
811 " -I/--head Show document info only",
812 " -h/--help This help text",
813 " --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
814 " -0/--http1.0 Use HTTP 1.0 (H)",
815 " --ignore-content-length Ignore the HTTP Content-Length header",
816 " -i/--include Include protocol headers in the output (H/F)",
817 " -k/--insecure Allow connections to SSL sites without certs (H)",
818 " --interface <interface> Specify network interface/address to use",
819 " -4/--ipv4 Resolve name to IPv4 address",
820 " -6/--ipv6 Resolve name to IPv6 address",
821 " -j/--junk-session-cookies Ignore session cookies read from file (H)",
822 " --keepalive-time <seconds> Interval between keepalive probes",
823 " --key <key> Private key file name (SSL/SSH)",
824 " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
825 " --krb <level> Enable Kerberos with specified security level (F)",
826 " --libcurl <file> Dump libcurl equivalent code of this command line",
827 " --limit-rate <rate> Limit transfer speed to this rate",
828 " -J/--remote-header-name Use the header-provided filename (H)",
829 " -l/--list-only List only names of an FTP directory (F)",
830 " --local-port <num>[-num] Force use of these local port numbers",
831 " -L/--location Follow Location: hints (H)",
832 " --location-trusted Follow Location: and send auth to other hosts (H)",
833 " -M/--manual Display the full manual",
834 " --mail-from <from> Mail from this address",
835 " --mail-rcpt <to> Mail to this receiver(s)",
836 " --max-filesize <bytes> Maximum file size to download (H/F)",
837 " --max-redirs <num> Maximum number of redirects allowed (H)",
838 " -m/--max-time <seconds> Maximum time allowed for the transfer",
839 " --negotiate Use HTTP Negotiate Authentication (H)",
840 " -n/--netrc Must read .netrc for user name and password",
841 " --netrc-optional Use either .netrc or URL; overrides -n",
842 " -N/--no-buffer Disable buffering of the output stream",
843 " --no-keepalive Disable keepalive use on the connection",
844 " --no-sessionid Disable SSL session-ID reusing (SSL)",
845 " --noproxy Comma-separated list of hosts which do not use proxy",
846 " --ntlm Use HTTP NTLM authentication (H)",
847 " -o/--output <file> Write output to <file> instead of stdout",
848 " --pass <pass> Pass phrase for the private key (SSL/SSH)",
849 " --post301 Do not switch to GET after following a 301 redirect (H)",
850 " --post302 Do not switch to GET after following a 302 redirect (H)",
851 " -#/--progress-bar Display transfer progress as a progress bar",
852 " --proto <protocols> Enable/disable specified protocols",
853 " --proto-redir <protocols> Enable/disable specified protocols on redirect",
854 " -x/--proxy <host[:port]> Use HTTP proxy on given port",
855 " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
856 " --proxy-basic Use Basic authentication on the proxy (H)",
857 " --proxy-digest Use Digest authentication on the proxy (H)",
858 " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
859 " --proxy-ntlm Use NTLM authentication on the proxy (H)",
860 " -U/--proxy-user <user[:password]> Set proxy user and password",
861 " --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port",
862 " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
863 " --pubkey <key> Public key file name (SSH)",
864 " -Q/--quote <cmd> Send command(s) to server before file transfer (F/SFTP)",
865 " --random-file <file> File for reading random data from (SSL)",
866 " -r/--range <range> Retrieve only the bytes within a range",
867 " --raw Pass HTTP \"raw\", without any transfer decoding (H)",
868 " -e/--referer Referer URL (H)",
869 " -O/--remote-name Write output to a file named as the remote file",
870 " --remote-name-all Use the remote file name for all URLs",
871 " -R/--remote-time Set the remote file's time on the local output",
872 " -X/--request <command> Specify request command to use",
873 " --resolve <host:port:address> Force resolve of HOST:PORT to ADDRESS",
874 " --retry <num> Retry request <num> times if transient problems occur",
875 " --retry-delay <seconds> When retrying, wait this many seconds between each",
876 " --retry-max-time <seconds> Retry only within this period",
877 " -S/--show-error Show error. With -s, make curl show errors when they occur",
878 " -s/--silent Silent mode. Don't output anything",
879 " --socks4 <host[:port]> SOCKS4 proxy on given host + port",
880 " --socks4a <host[:port]> SOCKS4a proxy on given host + port",
881 " --socks5 <host[:port]> SOCKS5 proxy on given host + port",
882 " --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy",
883 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
884 " --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi",
885 " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
887 " -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
888 " -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
889 " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
890 " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
891 " -2/--sslv2 Use SSLv2 (SSL)",
892 " -3/--sslv3 Use SSLv3 (SSL)",
893 " --stderr <file> Where to redirect stderr. - means stdout",
894 " --tcp-nodelay Use the TCP_NODELAY option",
895 " -t/--telnet-option <OPT=val> Set telnet option",
896 " --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)",
897 " -z/--time-cond <time> Transfer based on a time condition",
898 " -1/--tlsv1 Use TLSv1 (SSL)",
899 " --trace <file> Write a debug trace to the given file",
900 " --trace-ascii <file> Like --trace but without the hex output",
901 " --trace-time Add time stamps to trace/verbose output",
902 " -T/--upload-file <file> Transfer <file> to remote site",
903 " --url <URL> Set URL to work with",
904 " -B/--use-ascii Use ASCII/text transfer",
905 " -u/--user <user[:password]> Set server user and password",
906 " -A/--user-agent <string> User-Agent to send to server (H)",
907 " -v/--verbose Make the operation more talkative",
908 " -V/--version Show version number and quit",
911 " --wdebug Turn on Watt-32 debugging",
913 " -w/--write-out <format> What to output after completion",
914 " --xattr Store metadata in extended file attributes",
915 " -q If used as the first parameter disables .curlrc",
918 for(i=0; helptext[i]; i++) {
920 #ifdef PRINT_LINES_PAUSE
921 if(i && ((i % PRINT_LINES_PAUSE) == 0))
933 /* global variable to hold info about libcurl */
934 static curl_version_info_data *curlinfo;
936 static int parseconfig(const char *filename,
937 struct Configurable *config);
938 static char *my_get_line(FILE *fp);
939 static int create_dir_hierarchy(const char *outfile, FILE *errors);
941 static void GetStr(char **string,
947 *string = strdup(value);
952 static void clean_getout(struct Configurable *config)
954 struct getout *node=config->url_list;
967 node = next; /* GOTO next */
971 static struct getout *new_getout(struct Configurable *config)
973 struct getout *node =malloc(sizeof(struct getout));
974 struct getout *last= config->url_last;
976 /* clear the struct */
977 memset(node, 0, sizeof(struct getout));
979 /* append this new node last in the list */
983 config->url_list = node; /* first node */
985 /* move the last pointer */
986 config->url_last = node;
988 node->flags = config->default_node_flags;
993 /* Structure for storing the information needed to build a multiple files
997 struct curl_forms form;
998 struct multi_files *next;
1001 /* Add a new list entry possibly with a type_name
1003 static struct multi_files *
1004 AddMultiFiles(const char *file_name,
1005 const char *type_name,
1006 const char *show_filename,
1007 struct multi_files **multi_start,
1008 struct multi_files **multi_current)
1010 struct multi_files *multi;
1011 struct multi_files *multi_type = NULL;
1012 struct multi_files *multi_name = NULL;
1013 multi = malloc(sizeof(struct multi_files));
1015 memset(multi, 0, sizeof(struct multi_files));
1016 multi->form.option = CURLFORM_FILE;
1017 multi->form.value = file_name;
1023 *multi_start = multi;
1026 multi_type = malloc(sizeof(struct multi_files));
1028 memset(multi_type, 0, sizeof(struct multi_files));
1029 multi_type->form.option = CURLFORM_CONTENTTYPE;
1030 multi_type->form.value = type_name;
1031 multi->next = multi_type;
1041 multi_name = malloc(sizeof(struct multi_files));
1043 memset(multi_name, 0, sizeof(struct multi_files));
1044 multi_name->form.option = CURLFORM_FILENAME;
1045 multi_name->form.value = show_filename;
1046 multi->next = multi_name;
1057 (*multi_current)->next = multi;
1059 *multi_current = multi;
1061 return *multi_current;
1064 /* Free the items of the list.
1066 static void FreeMultiInfo(struct multi_files *multi_start)
1068 struct multi_files *multi;
1069 while(multi_start) {
1070 multi = multi_start;
1071 multi_start = multi_start->next;
1076 /* Print list of OpenSSL engines supported.
1078 static void list_engines(const struct curl_slist *engines)
1080 puts("Build-time engines:");
1085 for( ; engines; engines = engines->next)
1086 printf(" %s\n", engines->data);
1089 /***************************************************************************
1093 * Reads a 'name=value' parameter and builds the appropriate linked list.
1095 * Specify files to upload with 'name=@filename'. Supports specified
1096 * given Content-Type of the files. Such as ';type=<content-type>'.
1098 * If literal_value is set, any initial '@' or '<' in the value string
1099 * loses its special meaning, as does any embedded ';type='.
1101 * You may specify more than one file for a single name (field). Specify
1102 * multiple files by writing it like:
1104 * 'name=@filename,filename2,filename3'
1106 * If you want content-types specified for each too, write them like:
1108 * 'name=@filename;type=image/gif,filename2,filename3'
1110 * If you want custom headers added for a single part, write them in a separate
1111 * file and do like this:
1113 * 'name=foo;headers=@headerfile' or why not
1114 * 'name=@filemame;headers=@headerfile'
1116 * To upload a file, but to fake the file name that will be included in the
1117 * formpost, do like this:
1119 * 'name=@filename;filename=/dev/null'
1121 * This function uses curl_formadd to fulfill it's job. Is heavily based on
1122 * the old curl_formparse code.
1124 ***************************************************************************/
1126 #define FORM_FILE_SEPARATOR ','
1127 #define FORM_TYPE_SEPARATOR ';'
1129 static int formparse(struct Configurable *config,
1131 struct curl_httppost **httppost,
1132 struct curl_httppost **last_post,
1135 /* nextarg MUST be a string in the format 'name=contents' and we'll
1136 build a linked list with the info */
1142 const char *type = NULL;
1146 if((1 == sscanf(input, "%255[^=]=", name)) &&
1147 ((contp = strchr(input, '=')) != NULL)) {
1148 /* the input was using the correct format */
1150 /* Allocate the contents */
1151 contents = strdup(contp+1);
1153 fprintf(config->errors, "out of memory\n");
1158 if('@' == contp[0] && !literal_value) {
1159 struct multi_files *multi_start = NULL, *multi_current = NULL;
1160 /* we use the @-letter to indicate file name(s) */
1163 multi_start = multi_current=NULL;
1166 /* since this was a file, it may have a content-type specifier
1167 at the end too, or a filename. Or both. */
1169 char *filename=NULL;
1171 sep=strchr(contp, FORM_TYPE_SEPARATOR);
1172 sep2=strchr(contp, FORM_FILE_SEPARATOR);
1174 /* pick the closest */
1175 if(sep2 && (sep2 < sep)) {
1178 /* no type was specified! */
1185 /* if we got here on a comma, don't do much */
1186 if(FORM_FILE_SEPARATOR == *sep)
1191 *sep=0; /* terminate file name at separator */
1193 while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
1195 /* pass all white spaces */
1196 while(ISSPACE(*ptr))
1199 if(checkprefix("type=", ptr)) {
1200 /* set type pointer */
1203 /* verify that this is a fine type specifier */
1204 if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
1206 warnf(config, "Illegally formatted content-type field!\n");
1208 FreeMultiInfo(multi_start);
1209 return 2; /* illegal content-type syntax! */
1212 /* now point beyond the content-type specifier */
1213 sep = (char *)type + strlen(major)+strlen(minor)+1;
1215 /* there's a semicolon following - we check if it is a filename
1216 specified and if not we simply assume that it is text that
1217 the user wants included in the type and include that too up
1218 to the next zero or semicolon. */
1219 if((*sep==';') && !checkprefix(";filename=", sep)) {
1220 sep2 = strchr(sep+1, ';');
1224 sep = sep+strlen(sep); /* point to end of string */
1228 *sep=0; /* zero terminate type string */
1233 ptr = NULL; /* end */
1235 else if(checkprefix("filename=", ptr)) {
1237 ptr=strchr(filename, FORM_TYPE_SEPARATOR);
1239 ptr=strchr(filename, FORM_FILE_SEPARATOR);
1242 *ptr=0; /* zero terminate */
1247 /* confusion, bail out of loop */
1250 /* find the following comma */
1252 sep=strchr(ptr, FORM_FILE_SEPARATOR);
1257 sep=strchr(contp, FORM_FILE_SEPARATOR);
1260 /* the next file name starts here */
1264 /* if type == NULL curl_formadd takes care of the problem */
1266 if(!AddMultiFiles(contp, type, filename, &multi_start,
1268 warnf(config, "Error building form post!\n");
1270 FreeMultiInfo(multi_start);
1273 contp = sep; /* move the contents pointer to after the separator */
1275 } while(sep && *sep); /* loop if there's another file name */
1277 /* now we add the multiple files section */
1279 struct curl_forms *forms = NULL;
1280 struct multi_files *ptr = multi_start;
1281 unsigned int i, count = 0;
1286 forms = malloc((count+1)*sizeof(struct curl_forms));
1289 fprintf(config->errors, "Error building form post!\n");
1291 FreeMultiInfo(multi_start);
1294 for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
1296 forms[i].option = ptr->form.option;
1297 forms[i].value = ptr->form.value;
1299 forms[count].option = CURLFORM_END;
1300 FreeMultiInfo(multi_start);
1301 if(curl_formadd(httppost, last_post,
1302 CURLFORM_COPYNAME, name,
1303 CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
1304 warnf(config, "curl_formadd failed!\n");
1313 struct curl_forms info[4];
1315 char *ct = literal_value? NULL: strstr(contp, ";type=");
1317 info[i].option = CURLFORM_COPYNAME;
1318 info[i].value = name;
1322 info[i].option = CURLFORM_CONTENTTYPE;
1323 info[i].value = &ct[6];
1325 ct[0]=0; /* zero terminate here */
1328 if( contp[0]=='<' && !literal_value) {
1329 info[i].option = CURLFORM_FILECONTENT;
1330 info[i].value = contp+1;
1332 info[i].option = CURLFORM_END;
1334 if(curl_formadd(httppost, last_post,
1335 CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
1336 warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
1343 #ifdef CURL_DOES_CONVERSIONS
1344 convert_to_network(contp, strlen(contp));
1346 info[i].option = CURLFORM_COPYCONTENTS;
1347 info[i].value = contp;
1349 info[i].option = CURLFORM_END;
1350 if(curl_formadd(httppost, last_post,
1351 CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
1352 warnf(config, "curl_formadd failed!\n");
1361 warnf(config, "Illegally formatted input field!\n");
1371 PARAM_OPTION_AMBIGUOUS,
1372 PARAM_OPTION_UNKNOWN,
1373 PARAM_REQUIRES_PARAMETER,
1375 PARAM_HELP_REQUESTED,
1376 PARAM_GOT_EXTRA_PARAMETER,
1378 PARAM_LIBCURL_DOESNT_SUPPORT,
1383 static const char *param2text(int res)
1385 ParameterError error = (ParameterError)res;
1387 case PARAM_GOT_EXTRA_PARAMETER:
1388 return "had unsupported trailing garbage";
1389 case PARAM_OPTION_UNKNOWN:
1390 return "is unknown";
1391 case PARAM_OPTION_AMBIGUOUS:
1392 return "is ambiguous";
1393 case PARAM_REQUIRES_PARAMETER:
1394 return "requires parameter";
1396 return "is badly used here";
1397 case PARAM_BAD_NUMERIC:
1398 return "expected a proper numerical parameter";
1399 case PARAM_LIBCURL_DOESNT_SUPPORT:
1400 return "the installed libcurl version doesn't support this";
1402 return "out of memory";
1404 return "unknown error";
1408 static ParameterError file2string(char **bufp, FILE *file)
1412 char *string = NULL;
1413 size_t stringlen = 0;
1417 while(fgets(buffer, sizeof(buffer), file)) {
1418 if((ptr = strchr(buffer, '\r')) != NULL)
1420 if((ptr = strchr(buffer, '\n')) != NULL)
1422 buflen = strlen(buffer);
1423 if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
1426 return PARAM_NO_MEM;
1429 strcpy(string+stringlen, buffer);
1430 stringlen += buflen;
1437 static ParameterError file2memory(char **bufp, size_t *size, FILE *file)
1440 char *buffer = NULL;
1447 if(!buffer || (alloc == nused)) {
1448 /* size_t overflow detection for huge files */
1449 if(alloc+1 > ((size_t)-1)/2) {
1452 return PARAM_NO_MEM;
1455 /* allocate an extra char, reserved space, for null termination */
1456 if((newbuf = realloc(buffer, alloc+1)) == NULL) {
1459 return PARAM_NO_MEM;
1463 nread = fread(buffer+nused, 1, alloc-nused, file);
1466 /* null terminate the buffer in case it's used as a string later */
1467 buffer[nused] = '\0';
1468 /* free trailing slack space, if possible */
1469 if(alloc != nused) {
1470 if((newbuf = realloc(buffer, nused+1)) != NULL)
1473 /* discard buffer if nothing was read */
1476 buffer = NULL; /* no string */
1484 static void cleanarg(char *str)
1486 #ifdef HAVE_WRITABLE_ARGV
1487 /* now that GetStr has copied the contents of nextarg, wipe the next
1488 * argument out so that the username:password isn't displayed in the
1489 * system process list */
1491 size_t len = strlen(str);
1492 memset(str, ' ', len);
1500 * Parse the string and write the integer in the given address. Return
1501 * non-zero on failure, zero on success.
1503 * The string must start with a digit to be valid.
1505 * Since this function gets called with the 'nextarg' pointer from within the
1506 * getparameter a lot, we must check it for NULL before accessing the str
1510 static int str2num(long *val, const char *str)
1512 if(str && ISDIGIT(*str)) {
1514 long num = strtol(str, &endptr, 10);
1515 if((endptr != str) && (endptr == str + strlen(str))) {
1520 return 1; /* badness */
1524 * Parse the string and modify the long in the given address. Return
1525 * non-zero on failure, zero on success.
1527 * The string is a list of protocols
1529 * Since this function gets called with the 'nextarg' pointer from within the
1530 * getparameter a lot, we must check it for NULL before accessing the str
1534 static long proto2num(struct Configurable *config, long *val, const char *str)
1537 const char *sep = ",";
1540 static struct sprotos {
1543 } const protos[] = {
1544 { "all", CURLPROTO_ALL },
1545 { "http", CURLPROTO_HTTP },
1546 { "https", CURLPROTO_HTTPS },
1547 { "ftp", CURLPROTO_FTP },
1548 { "ftps", CURLPROTO_FTPS },
1549 { "scp", CURLPROTO_SCP },
1550 { "sftp", CURLPROTO_SFTP },
1551 { "telnet", CURLPROTO_TELNET },
1552 { "ldap", CURLPROTO_LDAP },
1553 { "ldaps", CURLPROTO_LDAPS },
1554 { "dict", CURLPROTO_DICT },
1555 { "file", CURLPROTO_FILE },
1556 { "tftp", CURLPROTO_TFTP },
1557 { "imap", CURLPROTO_IMAP },
1558 { "imaps", CURLPROTO_IMAPS },
1559 { "pop3", CURLPROTO_POP3 },
1560 { "pop3s", CURLPROTO_POP3S },
1561 { "smtp", CURLPROTO_SMTP },
1562 { "smtps", CURLPROTO_SMTPS },
1563 { "rtsp", CURLPROTO_RTSP },
1564 { "gopher", CURLPROTO_GOPHER },
1571 buffer = strdup(str); /* because strtok corrupts it */
1573 for(token = strtok(buffer, sep);
1575 token = strtok(NULL, sep)) {
1576 enum e_action { allow, deny, set } action = allow;
1578 struct sprotos const *pp;
1580 /* Process token modifiers */
1581 while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
1592 default: /* Includes case of terminating NULL */
1598 for(pp=protos; pp->name; pp++) {
1599 if(curlx_raw_equal(token, pp->name)) {
1615 if(!(pp->name)) { /* unknown protocol */
1616 /* If they have specified only this protocol, we say treat it as
1617 if no protocols are allowed */
1620 warnf(config, "unrecognized protocol '%s'\n", token);
1628 * Parses the given string looking for an offset (which may be
1629 * a larger-than-integer value).
1631 * @param val the offset to populate
1632 * @param str the buffer containing the offset
1633 * @return zero if successful, non-zero if failure.
1635 static int str2offset(curl_off_t *val, const char *str)
1637 #if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
1638 *val = curlx_strtoofft(str, NULL, 0);
1639 if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
1642 *val = strtol(str, NULL, 0);
1643 if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
1649 static void checkpasswd(const char *kind, /* for what purpose */
1650 char **userpwd) /* pointer to allocated string */
1656 ptr = strchr(*userpwd, ':');
1658 /* no password present, prompt for one */
1659 char passwd[256]="";
1662 size_t userlen = strlen(*userpwd);
1665 /* build a nice-looking prompt */
1666 curlx_msnprintf(prompt, sizeof(prompt),
1667 "Enter %s password for user '%s':",
1671 getpass_r(prompt, passwd, sizeof(passwd));
1672 passwdlen = strlen(passwd);
1674 /* extend the allocated memory area to fit the password too */
1675 passptr = realloc(*userpwd,
1676 passwdlen + 1 + /* an extra for the colon */
1677 userlen + 1); /* an extra for the zero */
1680 /* append the password separated with a colon */
1681 passptr[userlen]=':';
1682 memcpy(&passptr[userlen+1], passwd, passwdlen+1);
1688 static ParameterError add2list(struct curl_slist **list,
1691 struct curl_slist *newlist = curl_slist_append(*list, ptr);
1695 return PARAM_NO_MEM;
1700 static int ftpfilemethod(struct Configurable *config, const char *str)
1702 if(curlx_raw_equal("singlecwd", str))
1703 return CURLFTPMETHOD_SINGLECWD;
1704 if(curlx_raw_equal("nocwd", str))
1705 return CURLFTPMETHOD_NOCWD;
1706 if(curlx_raw_equal("multicwd", str))
1707 return CURLFTPMETHOD_MULTICWD;
1708 warnf(config, "unrecognized ftp file method '%s', using default\n", str);
1709 return CURLFTPMETHOD_MULTICWD;
1712 static int ftpcccmethod(struct Configurable *config, const char *str)
1714 if(curlx_raw_equal("passive", str))
1715 return CURLFTPSSL_CCC_PASSIVE;
1716 if(curlx_raw_equal("active", str))
1717 return CURLFTPSSL_CCC_ACTIVE;
1718 warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
1719 return CURLFTPSSL_CCC_PASSIVE;
1723 static int sockoptcallback(void *clientp, curl_socket_t curlfd,
1724 curlsocktype purpose)
1726 struct Configurable *config = (struct Configurable *)clientp;
1727 int onoff = 1; /* this callback is only used if we ask for keepalives on the
1729 #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
1730 int keepidle = (int)config->alivetime;
1734 case CURLSOCKTYPE_IPCXN:
1735 if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
1736 sizeof(onoff)) < 0) {
1737 /* don't abort operation, just issue a warning */
1739 warnf(clientp, "Could not set SO_KEEPALIVE!\n");
1743 if(config->alivetime) {
1745 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
1746 sizeof(keepidle)) < 0) {
1747 /* don't abort operation, just issue a warning */
1749 warnf(clientp, "Could not set TCP_KEEPIDLE!\n");
1753 #ifdef TCP_KEEPINTVL
1754 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
1755 sizeof(keepidle)) < 0) {
1756 /* don't abort operation, just issue a warning */
1758 warnf(clientp, "Could not set TCP_KEEPINTVL!\n");
1773 static ParameterError getparameter(char *flag, /* f or -long-flag */
1774 char *nextarg, /* NULL if unset */
1775 bool *usedarg, /* set to TRUE if the arg
1777 struct Configurable *config)
1780 char subletter=0; /* subletters can only occur on long options */
1781 int rc; /* generic return code variable */
1782 const char *parse=NULL;
1787 bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
1789 bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled
1790 by using --OPTION or --no-OPTION */
1794 boolean whether it takes an additional argument
1796 static const struct LongShort aliases[]= {
1797 /* all these ones, starting with "*" or "$" as a short-option have *no*
1798 short option to mention. */
1800 {"*a", "random-file", TRUE},
1801 {"*b", "egd-file", TRUE},
1802 {"*c", "connect-timeout", TRUE},
1803 {"*d", "ciphers", TRUE},
1804 {"*e", "disable-epsv", FALSE},
1805 {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to
1806 work although --disable-epsv is the documented
1808 #ifdef USE_ENVIRONMENT
1809 {"*f", "environment", FALSE},
1811 {"*g", "trace", TRUE},
1812 {"*h", "trace-ascii", TRUE},
1813 {"*i", "limit-rate", TRUE},
1814 {"*j", "compressed", FALSE}, /* might take an arg someday */
1815 {"*k", "digest", FALSE},
1816 {"*l", "negotiate", FALSE},
1817 {"*m", "ntlm", FALSE},
1818 {"*n", "basic", FALSE},
1819 {"*o", "anyauth", FALSE},
1821 {"*p", "wdebug", FALSE},
1823 {"*q", "ftp-create-dirs", FALSE},
1824 {"*r", "create-dirs", FALSE},
1825 {"*s", "max-redirs", TRUE},
1826 {"*t", "proxy-ntlm", FALSE},
1827 {"*u", "crlf", FALSE},
1828 {"*v", "stderr", TRUE},
1829 {"*w", "interface", TRUE},
1830 {"*x", "krb" , TRUE},
1831 {"*x", "krb4" , TRUE}, /* this is the previous name */
1832 {"*y", "max-filesize", TRUE},
1833 {"*z", "disable-eprt", FALSE},
1834 {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to
1835 work although --disable-eprt is the documented
1837 {"$a", "ftp-ssl", FALSE}, /* deprecated name since 7.20.0 */
1838 {"$a", "ssl", FALSE}, /* new option name in 7.20.0, previously this
1840 {"$b", "ftp-pasv", FALSE},
1841 {"$c", "socks5", TRUE},
1842 {"$c", "socks", TRUE}, /* this is how the option once was documented
1843 but we prefer the --socks5 version for
1845 {"$d", "tcp-nodelay",FALSE},
1846 {"$e", "proxy-digest", FALSE},
1847 {"$f", "proxy-basic", FALSE},
1848 {"$g", "retry", TRUE},
1849 {"$h", "retry-delay", TRUE},
1850 {"$i", "retry-max-time", TRUE},
1851 {"$k", "proxy-negotiate", FALSE},
1852 {"$m", "ftp-account", TRUE},
1853 {"$n", "proxy-anyauth", FALSE},
1854 {"$o", "trace-time", FALSE},
1855 {"$p", "ignore-content-length", FALSE},
1856 {"$q", "ftp-skip-pasv-ip", FALSE},
1857 {"$r", "ftp-method", TRUE},
1858 {"$s", "local-port", TRUE},
1859 {"$t", "socks4", TRUE},
1860 {"$T", "socks4a", TRUE},
1861 {"$u", "ftp-alternative-to-user", TRUE},
1862 {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */
1863 {"$v", "ssl-reqd", FALSE}, /* new option name in 7.20.0, previously this
1865 {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */
1866 {"$x", "ftp-ssl-control", FALSE},
1867 {"$y", "ftp-ssl-ccc", FALSE},
1868 {"$j", "ftp-ssl-ccc-mode", TRUE},
1869 {"$z", "libcurl", TRUE},
1870 {"$#", "raw", FALSE},
1871 {"$0", "post301", FALSE},
1872 {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
1873 {"$2", "socks5-hostname", TRUE},
1874 {"$3", "keepalive-time", TRUE},
1875 {"$4", "post302", FALSE},
1876 {"$5", "noproxy", TRUE},
1878 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1879 {"$6", "socks5-gssapi-service", TRUE},
1880 {"$7", "socks5-gssapi-nec", FALSE},
1882 {"$8", "proxy1.0", TRUE},
1883 {"$9", "tftp-blksize", TRUE},
1884 {"$A", "mail-from", TRUE},
1885 {"$B", "mail-rcpt", TRUE},
1886 {"$C", "ftp-pret", FALSE},
1887 {"$D", "proto", TRUE},
1888 {"$E", "proto-redir", TRUE},
1889 {"$F", "resolve", TRUE},
1890 {"0", "http1.0", FALSE},
1891 {"1", "tlsv1", FALSE},
1892 {"2", "sslv2", FALSE},
1893 {"3", "sslv3", FALSE},
1894 {"4", "ipv4", FALSE},
1895 {"6", "ipv6", FALSE},
1896 {"a", "append", FALSE},
1897 {"A", "user-agent", TRUE},
1898 {"b", "cookie", TRUE},
1899 {"B", "use-ascii", FALSE},
1900 {"c", "cookie-jar", TRUE},
1901 {"C", "continue-at", TRUE},
1902 {"d", "data", TRUE},
1903 {"da", "data-ascii", TRUE},
1904 {"db", "data-binary", TRUE},
1905 {"de", "data-urlencode", TRUE},
1906 {"D", "dump-header", TRUE},
1907 {"e", "referer", TRUE},
1908 {"E", "cert", TRUE},
1909 {"Ea", "cacert", TRUE},
1910 {"Eb","cert-type", TRUE},
1912 {"Ed","key-type", TRUE},
1913 {"Ee","pass", TRUE},
1914 {"Ef","engine", TRUE},
1915 {"Eg","capath ", TRUE},
1916 {"Eh","pubkey", TRUE},
1917 {"Ei", "hostpubmd5", TRUE},
1918 {"Ej","crlfile", TRUE},
1919 {"f", "fail", FALSE},
1920 {"F", "form", TRUE},
1921 {"Fs","form-string", TRUE},
1922 {"g", "globoff", FALSE},
1923 {"G", "get", FALSE},
1924 {"h", "help", FALSE},
1925 {"H", "header", TRUE},
1926 {"i", "include", FALSE},
1927 {"I", "head", FALSE},
1928 {"j", "junk-session-cookies", FALSE},
1929 {"J", "remote-header-name", FALSE},
1930 {"k", "insecure", FALSE},
1931 {"K", "config", TRUE},
1932 {"l", "list-only", FALSE},
1933 {"L", "location", FALSE},
1934 {"Lt", "location-trusted", FALSE},
1935 {"m", "max-time", TRUE},
1936 {"M", "manual", FALSE},
1937 {"n", "netrc", FALSE},
1938 {"no", "netrc-optional", FALSE},
1939 {"N", "buffer", FALSE}, /* listed as --no-buffer in the help */
1940 {"o", "output", TRUE},
1941 {"O", "remote-name", FALSE},
1942 {"Oa", "remote-name-all", FALSE},
1943 {"p", "proxytunnel", FALSE},
1944 {"P", "ftpport", TRUE}, /* older version */
1945 {"P", "ftp-port", TRUE},
1946 {"q", "disable", FALSE},
1947 {"Q", "quote", TRUE},
1948 {"r", "range", TRUE},
1949 {"R", "remote-time", FALSE},
1950 {"s", "silent", FALSE},
1951 {"S", "show-error", FALSE},
1952 {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */
1953 {"T", "upload-file", TRUE},
1954 {"u", "user", TRUE},
1955 {"U", "proxy-user", TRUE},
1956 {"v", "verbose", FALSE},
1957 {"V", "version", FALSE},
1958 {"w", "write-out", TRUE},
1959 {"x", "proxy", TRUE},
1960 {"X", "request", TRUE},
1961 {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
1962 {"Y", "speed-limit", TRUE},
1963 {"y", "speed-time", TRUE},
1964 {"z", "time-cond", TRUE},
1965 {"#", "progress-bar",FALSE},
1966 {"~", "xattr",FALSE},
1969 if(('-' != flag[0]) ||
1970 (('-' == flag[0]) && ('-' == flag[1]))) {
1971 /* this should be a long name */
1972 char *word=('-' == flag[0])?flag+2:flag;
1973 size_t fnam=strlen(word);
1976 if(!strncmp(word, "no-", 3)) {
1977 /* disable this option but ignore the "no-" part when looking for it */
1982 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1983 if(curlx_strnequal(aliases[j].lname, word, fnam)) {
1986 if(curlx_raw_equal(aliases[j].lname, word)) {
1987 parse = aliases[j].letter;
1989 numhits = 1; /* a single unique hit */
1992 parse = aliases[j].letter;
1997 /* this is at least the second match! */
1998 return PARAM_OPTION_AMBIGUOUS;
2001 return PARAM_OPTION_UNKNOWN;
2005 flag++; /* prefixed with one dash, pass it */
2011 /* we can loop here if we have multiple single-letters */
2015 letter = (char)*parse;
2024 subletter = parse[1];
2026 *usedarg = FALSE; /* default is that we don't use the arg */
2029 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
2030 if(letter == aliases[j].letter[0]) {
2036 return PARAM_OPTION_UNKNOWN;
2040 if(aliases[hit].extraparam) {
2041 /* this option requires an extra parameter */
2042 if(!longopt && parse[1]) {
2043 nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
2044 singleopt=TRUE; /* don't loop anymore after this */
2047 return PARAM_REQUIRES_PARAMETER;
2049 *usedarg = TRUE; /* mark it as used */
2053 case '*': /* options without a short option */
2055 case 'a': /* random-file */
2056 GetStr(&config->random_file, nextarg);
2058 case 'b': /* egd-file */
2059 GetStr(&config->egd_file, nextarg);
2061 case 'c': /* connect-timeout */
2062 if(str2num(&config->connecttimeout, nextarg))
2063 return PARAM_BAD_NUMERIC;
2065 case 'd': /* ciphers */
2066 GetStr(&config->cipher_list, nextarg);
2068 case 'e': /* --disable-epsv */
2069 config->disable_epsv = toggle;
2071 case 'E': /* --epsv */
2072 config->disable_epsv = (bool)(!toggle);
2074 #ifdef USE_ENVIRONMENT
2076 config->writeenv = toggle;
2079 case 'g': /* --trace */
2080 GetStr(&config->trace_dump, nextarg);
2081 if(config->tracetype && (config->tracetype != TRACE_BIN))
2082 warnf(config, "--trace overrides an earlier trace/verbose option\n");
2083 config->tracetype = TRACE_BIN;
2085 case 'h': /* --trace-ascii */
2086 GetStr(&config->trace_dump, nextarg);
2087 if(config->tracetype && (config->tracetype != TRACE_ASCII))
2089 "--trace-ascii overrides an earlier trace/verbose option\n");
2090 config->tracetype = TRACE_ASCII;
2092 case 'i': /* --limit-rate */
2094 /* We support G, M, K too */
2096 curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
2100 else if(strlen(unit) > 1)
2101 unit=(char *)"w"; /* unsupported */
2106 value *= 1024*1024*1024;
2118 /* for plain bytes, leave as-is */
2121 warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
2122 return PARAM_BAD_USE;
2124 config->recvpersecond = value;
2125 config->sendpersecond = value;
2129 case 'j': /* --compressed */
2130 if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ))
2131 return PARAM_LIBCURL_DOESNT_SUPPORT;
2132 config->encoding = toggle;
2135 case 'k': /* --digest */
2137 config->authtype |= CURLAUTH_DIGEST;
2139 config->authtype &= ~CURLAUTH_DIGEST;
2142 case 'l': /* --negotiate */
2144 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2145 config->authtype |= CURLAUTH_GSSNEGOTIATE;
2147 return PARAM_LIBCURL_DOESNT_SUPPORT;
2150 config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
2153 case 'm': /* --ntlm */
2155 if(curlinfo->features & CURL_VERSION_NTLM)
2156 config->authtype |= CURLAUTH_NTLM;
2158 return PARAM_LIBCURL_DOESNT_SUPPORT;
2161 config->authtype &= ~CURLAUTH_NTLM;
2164 case 'n': /* --basic for completeness */
2166 config->authtype |= CURLAUTH_BASIC;
2168 config->authtype &= ~CURLAUTH_BASIC;
2171 case 'o': /* --anyauth, let libcurl pick it */
2173 config->authtype = CURLAUTH_ANY;
2174 /* --no-anyauth simply doesn't touch it */
2178 case 'p': /* --wdebug */
2182 case 'q': /* --ftp-create-dirs */
2183 config->ftp_create_dirs = toggle;
2186 case 'r': /* --create-dirs */
2187 config->create_dirs = TRUE;
2190 case 's': /* --max-redirs */
2191 /* specified max no of redirects (http(s)) */
2192 if(str2num(&config->maxredirs, nextarg))
2193 return PARAM_BAD_NUMERIC;
2196 case 't': /* --proxy-ntlm */
2197 if(curlinfo->features & CURL_VERSION_NTLM)
2198 config->proxyntlm = toggle;
2200 return PARAM_LIBCURL_DOESNT_SUPPORT;
2203 case 'u': /* --crlf */
2204 /* LF -> CRLF conversion? */
2205 config->crlf = TRUE;
2208 case 'v': /* --stderr */
2209 if(strcmp(nextarg, "-")) {
2210 FILE *newfile = fopen(nextarg, "wt");
2212 warnf(config, "Failed to open %s!\n", nextarg);
2214 if(config->errors_fopened)
2215 fclose(config->errors);
2216 config->errors = newfile;
2217 config->errors_fopened = TRUE;
2221 config->errors = stdout;
2223 case 'w': /* --interface */
2225 GetStr(&config->iface, nextarg);
2227 case 'x': /* --krb */
2228 /* kerberos level string */
2229 if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
2230 CURL_VERSION_GSSNEGOTIATE))
2231 GetStr(&config->krblevel, nextarg);
2233 return PARAM_LIBCURL_DOESNT_SUPPORT;
2235 case 'y': /* --max-filesize */
2236 if(str2offset(&config->max_filesize, nextarg))
2237 return PARAM_BAD_NUMERIC;
2239 case 'z': /* --disable-eprt */
2240 config->disable_eprt = toggle;
2242 case 'Z': /* --eprt */
2243 config->disable_eprt = (bool)(!toggle);
2246 default: /* the URL! */
2249 if(config->url_get || ((config->url_get = config->url_list) != NULL)) {
2250 /* there's a node here, if it already is filled-in continue to find
2252 while(config->url_get && (config->url_get->flags&GETOUT_URL))
2253 config->url_get = config->url_get->next;
2256 /* now there might or might not be an available node to fill in! */
2260 url = config->url_get;
2262 /* there was no free node, create one! */
2263 url=new_getout(config);
2266 /* fill in the URL */
2267 GetStr(&url->url, nextarg);
2268 url->flags |= GETOUT_URL;
2273 case '$': /* more options without a short option */
2275 case 'a': /* --ftp-ssl */
2276 if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
2277 return PARAM_LIBCURL_DOESNT_SUPPORT;
2278 config->ftp_ssl = toggle;
2280 case 'b': /* --ftp-pasv */
2282 free(config->ftpport);
2283 config->ftpport = NULL;
2285 case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
2286 the name locally and passes on the resolved address */
2287 GetStr(&config->socksproxy, nextarg);
2288 config->socksver = CURLPROXY_SOCKS5;
2290 case 't': /* --socks4 specifies a socks4 proxy to use */
2291 GetStr(&config->socksproxy, nextarg);
2292 config->socksver = CURLPROXY_SOCKS4;
2294 case 'T': /* --socks4a specifies a socks4a proxy to use */
2295 GetStr(&config->socksproxy, nextarg);
2296 config->socksver = CURLPROXY_SOCKS4A;
2298 case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
2299 resolving with the proxy */
2300 GetStr(&config->socksproxy, nextarg);
2301 config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
2303 case 'd': /* --tcp-nodelay option */
2304 config->tcp_nodelay = toggle;
2306 case 'e': /* --proxy-digest */
2307 config->proxydigest = toggle;
2309 case 'f': /* --proxy-basic */
2310 config->proxybasic = toggle;
2312 case 'g': /* --retry */
2313 if(str2num(&config->req_retry, nextarg))
2314 return PARAM_BAD_NUMERIC;
2316 case 'h': /* --retry-delay */
2317 if(str2num(&config->retry_delay, nextarg))
2318 return PARAM_BAD_NUMERIC;
2320 case 'i': /* --retry-max-time */
2321 if(str2num(&config->retry_maxtime, nextarg))
2322 return PARAM_BAD_NUMERIC;
2325 case 'k': /* --proxy-negotiate */
2326 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2327 config->proxynegotiate = toggle;
2329 return PARAM_LIBCURL_DOESNT_SUPPORT;
2331 case 'm': /* --ftp-account */
2332 GetStr(&config->ftp_account, nextarg);
2334 case 'n': /* --proxy-anyauth */
2335 config->proxyanyauth = toggle;
2337 case 'o': /* --trace-time */
2338 config->tracetime = toggle;
2340 case 'p': /* --ignore-content-length */
2341 config->ignorecl = toggle;
2343 case 'q': /* --ftp-skip-pasv-ip */
2344 config->ftp_skip_ip = toggle;
2346 case 'r': /* --ftp-method (undocumented at this point) */
2347 config->ftp_filemethod = ftpfilemethod(config, nextarg);
2349 case 's': /* --local-port */
2350 rc = sscanf(nextarg, "%d - %d",
2352 &config->localportrange);
2354 return PARAM_BAD_USE;
2356 config->localportrange = 1; /* default number of ports to try */
2358 config->localportrange -= config->localport;
2359 if(config->localportrange < 1) {
2360 warnf(config, "bad range input\n");
2361 return PARAM_BAD_USE;
2365 case 'u': /* --ftp-alternative-to-user */
2366 GetStr(&config->ftp_alternative_to_user, nextarg);
2368 case 'v': /* --ftp-ssl-reqd */
2369 if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
2370 return PARAM_LIBCURL_DOESNT_SUPPORT;
2371 config->ftp_ssl_reqd = toggle;
2373 case 'w': /* --no-sessionid */
2374 config->disable_sessionid = (bool)(!toggle);
2376 case 'x': /* --ftp-ssl-control */
2377 if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
2378 return PARAM_LIBCURL_DOESNT_SUPPORT;
2379 config->ftp_ssl_control = toggle;
2381 case 'y': /* --ftp-ssl-ccc */
2382 config->ftp_ssl_ccc = toggle;
2383 if(!config->ftp_ssl_ccc_mode)
2384 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
2386 case 'j': /* --ftp-ssl-ccc-mode */
2387 config->ftp_ssl_ccc = TRUE;
2388 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
2390 case 'z': /* --libcurl */
2391 GetStr(&config->libcurl, nextarg);
2393 case '#': /* --raw */
2394 config->raw = toggle;
2396 case '0': /* --post301 */
2397 config->post301 = toggle;
2399 case '1': /* --no-keepalive */
2400 config->nokeepalive = (bool)(!toggle);
2402 case '3': /* --keepalive-time */
2403 if(str2num(&config->alivetime, nextarg))
2404 return PARAM_BAD_NUMERIC;
2406 case '4': /* --post302 */
2407 config->post302 = toggle;
2409 case '5': /* --noproxy */
2410 /* This specifies the noproxy list */
2411 GetStr(&config->noproxy, nextarg);
2413 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
2414 case '6': /* --socks5-gssapi-service */
2415 GetStr(&config->socks5_gssapi_service, nextarg);
2417 case '7': /* --socks5-gssapi-nec*/
2418 config->socks5_gssapi_nec = TRUE;
2421 case '8': /* --proxy1.0 */
2422 /* http 1.0 proxy */
2423 GetStr(&config->proxy, nextarg);
2424 config->proxyver = CURLPROXY_HTTP_1_0;
2426 case '9': /* --tftp-blksize */
2427 str2num(&config->tftp_blksize, nextarg);
2429 case 'A': /* --mail-from */
2430 GetStr(&config->mail_from, nextarg);
2432 case 'B': /* --mail-rcpt */
2433 /* append receiver to a list */
2434 err = add2list(&config->mail_rcpt, nextarg);
2438 case 'C': /* --ftp-pret */
2439 config->ftp_pret = toggle;
2441 case 'D': /* --proto */
2442 config->proto_present = TRUE;
2443 if(proto2num(config, &config->proto, nextarg))
2444 return PARAM_BAD_USE;
2446 case 'E': /* --proto-redir */
2447 config->proto_redir_present = TRUE;
2448 if(proto2num(config, &config->proto_redir, nextarg))
2449 return PARAM_BAD_USE;
2451 case 'F': /* --resolve */
2452 err = add2list(&config->resolve, nextarg);
2456 case '#': /* --progress-bar */
2458 config->progressmode = CURL_PROGRESS_BAR;
2460 config->progressmode = CURL_PROGRESS_STATS;
2462 case '~': /* --xattr */
2463 config->xattr = toggle;
2466 /* HTTP version 1.0 */
2467 config->httpversion = CURL_HTTP_VERSION_1_0;
2471 config->ssl_version = CURL_SSLVERSION_TLSv1;
2475 config->ssl_version = CURL_SSLVERSION_SSLv2;
2479 config->ssl_version = CURL_SSLVERSION_SSLv3;
2483 config->ip_version = 4;
2487 config->ip_version = 6;
2490 /* This makes the FTP sessions use APPE instead of STOR */
2491 config->ftp_append = toggle;
2494 /* This specifies the User-Agent name */
2495 GetStr(&config->useragent, nextarg);
2497 case 'b': /* cookie string coming up: */
2498 if(nextarg[0] == '@') {
2501 else if(strchr(nextarg, '=')) {
2502 /* A cookie string must have a =-letter */
2503 GetStr(&config->cookie, nextarg);
2506 /* We have a cookie file to read from! */
2507 GetStr(&config->cookiefile, nextarg);
2510 /* use ASCII/text when transfering */
2511 config->use_ascii = toggle;
2514 /* get the file name to dump all cookies in */
2515 GetStr(&config->cookiejar, nextarg);
2518 /* This makes us continue an ftp transfer at given position */
2519 if(!curlx_strequal(nextarg, "-")) {
2520 if(str2offset(&config->resume_from, nextarg))
2521 return PARAM_BAD_NUMERIC;
2522 config->resume_from_current = FALSE;
2525 config->resume_from_current = TRUE;
2526 config->resume_from = 0;
2528 config->use_resume=TRUE;
2531 /* postfield data */
2533 char *postdata=NULL;
2536 if(subletter == 'e') { /* --data-urlencode*/
2537 /* [name]=[content], we encode the content part only
2538 * [name]@[file name]
2540 * Case 2: we first load the file using that name and then encode
2543 const char *p = strchr(nextarg, '=');
2548 /* there was no '=' letter, check for a '@' instead */
2549 p = strchr(nextarg, '@');
2551 nlen = p - nextarg; /* length of the name part */
2552 is_file = *p++; /* pass the separator */
2555 /* neither @ nor =, so no name and it isn't a file */
2559 if('@' == is_file) {
2560 /* a '@' letter, it means that a file name or - (stdin) follows */
2562 if(curlx_strequal("-", p)) {
2567 file = fopen(p, "rb");
2570 "Couldn't read data from file \"%s\", this makes "
2571 "an empty POST.\n", nextarg);
2574 err = file2memory(&postdata, &size, file);
2576 if(file && (file != stdin))
2582 GetStr(&postdata, p);
2583 size = strlen(postdata);
2587 /* no data from the file, point to a zero byte string to make this
2588 get sent as a POST anyway */
2589 postdata=strdup("");
2592 char *enc = curl_easy_escape(config->easy, postdata, (int)size);
2593 free(postdata); /* no matter if it worked or not */
2595 /* now make a string with the name from above and append the
2597 size_t outlen = nlen + strlen(enc) + 2;
2598 char *n = malloc(outlen);
2601 return PARAM_NO_MEM;
2603 if(nlen > 0) /* only append '=' if we have a name */
2604 snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
2611 return PARAM_NO_MEM;
2614 else if('@' == *nextarg) {
2616 /* the data begins with a '@' letter, it means that a file name
2617 or - (stdin) follows */
2618 nextarg++; /* pass the @ */
2620 if(curlx_strequal("-", nextarg)) {
2622 if(subletter == 'b') /* forced data-binary */
2626 file = fopen(nextarg, "rb");
2628 warnf(config, "Couldn't read data from file \"%s\", this makes "
2629 "an empty POST.\n", nextarg);
2632 if(subletter == 'b') {
2634 err = file2memory(&postdata, &size, file);
2635 config->postfieldsize = (curl_off_t)size;
2638 err = file2string(&postdata, file);
2640 if(file && (file != stdin))
2646 /* no data from the file, point to a zero byte string to make this
2647 get sent as a POST anyway */
2648 postdata=strdup("");
2652 GetStr(&postdata, nextarg);
2655 #ifdef CURL_DOES_CONVERSIONS
2656 if(subletter != 'b') { /* NOT forced binary, convert to ASCII */
2657 convert_to_network(postdata, strlen(postdata));
2661 if(config->postfields) {
2662 /* we already have a string, we append this one
2663 with a separating &-letter */
2664 char *oldpost=config->postfields;
2665 size_t newlen = strlen(oldpost) + strlen(postdata) + 2;
2666 config->postfields=malloc(newlen);
2667 if(!config->postfields) {
2669 return PARAM_NO_MEM;
2671 /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
2672 snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata);
2677 config->postfields=postdata;
2680 We can't set the request type here, as this data might be used in
2681 a simple GET if -G is used. Already or soon.
2683 if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
2684 return PARAM_BAD_USE;
2688 /* dump-header to given file name */
2689 GetStr(&config->headerfile, nextarg);
2693 char *ptr = strstr(nextarg, ";auto");
2695 /* Automatic referer requested, this may be combined with a
2697 config->autoreferer = TRUE;
2698 *ptr = 0; /* zero terminate here */
2701 config->autoreferer = FALSE;
2702 GetStr(&config->referer, nextarg);
2707 case 'a': /* CA info PEM file */
2708 /* CA info PEM file */
2709 GetStr(&config->cacert, nextarg);
2711 case 'b': /* cert file type */
2712 GetStr(&config->cert_type, nextarg);
2714 case 'c': /* private key file */
2715 GetStr(&config->key, nextarg);
2717 case 'd': /* private key file type */
2718 GetStr(&config->key_type, nextarg);
2720 case 'e': /* private key passphrase */
2721 GetStr(&config->key_passwd, nextarg);
2724 case 'f': /* crypto engine */
2725 GetStr(&config->engine, nextarg);
2726 if(config->engine && curlx_raw_equal(config->engine,"list"))
2727 config->list_engines = TRUE;
2729 case 'g': /* CA info PEM file */
2730 /* CA cert directory */
2731 GetStr(&config->capath, nextarg);
2733 case 'h': /* --pubkey public key file */
2734 GetStr(&config->pubkey, nextarg);
2736 case 'i': /* --hostpubmd5 md5 of the host public key */
2737 GetStr(&config->hostpubmd5, nextarg);
2738 if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
2739 return PARAM_BAD_USE;
2741 case 'j': /* CRL info PEM file */
2743 GetStr(&config->crlfile, nextarg);
2745 default: /* certificate file */
2747 char *ptr = strchr(nextarg, ':');
2748 /* Since we live in a world of weirdness and confusion, the win32
2749 dudes can use : when using drive letters and thus
2750 c:\file:password needs to work. In order not to break
2751 compatibility, we still use : as separator, but we try to detect
2752 when it is used for a file name! On windows. */
2755 (ptr == &nextarg[1]) &&
2756 (nextarg[2] == '\\' || nextarg[2] == '/') &&
2757 (ISALPHA(nextarg[0])) )
2758 /* colon in the second column, followed by a backslash, and the
2759 first character is an alphabetic letter:
2761 this is a drive letter colon */
2762 ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
2765 /* we have a password too */
2768 GetStr(&config->key_passwd, ptr);
2770 GetStr(&config->cert, nextarg);
2776 /* fail hard on errors */
2777 config->failonerror = toggle;
2780 /* "form data" simulation, this is a little advanced so lets do our best
2781 to sort this out slowly and carefully */
2782 if(formparse(config,
2786 (bool) (subletter=='s'))) /* 's' means literal string */
2787 return PARAM_BAD_USE;
2788 if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
2789 return PARAM_BAD_USE;
2792 case 'g': /* g disables URLglobbing */
2793 config->globoff = toggle;
2796 case 'G': /* HTTP GET */
2797 config->use_httpget = TRUE;
2800 case 'h': /* h for help */
2803 return PARAM_HELP_REQUESTED;
2805 /* we now actually support --no-help too! */
2808 /* A custom header to append to a list */
2809 err = add2list(&config->headers, nextarg);
2814 config->include_headers = toggle; /* include the headers as well in the
2815 general output stream */
2818 config->cookiesession = toggle;
2822 * no_body will imply include_headers later on
2824 config->no_body = toggle;
2825 if(SetHTTPrequest(config,
2826 (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
2828 return PARAM_BAD_USE;
2830 case 'J': /* --remote-header-name */
2831 if(config->include_headers) {
2833 "--include and --remote-header-name cannot be combined.\n");
2834 return PARAM_BAD_USE;
2836 config->content_disposition = toggle;
2838 case 'k': /* allow insecure SSL connects */
2839 config->insecure_ok = toggle;
2841 case 'K': /* parse config file */
2842 if(parseconfig(nextarg, config))
2843 warnf(config, "error trying read config from the '%s' file\n",
2847 config->dirlistonly = toggle; /* only list the names of the FTP dir */
2850 config->followlocation = toggle; /* Follow Location: HTTP headers */
2851 switch (subletter) {
2853 /* Continue to send authentication (user+password) when following
2854 * locations, even when hostname changed */
2855 config->unrestricted_auth = toggle;
2860 /* specified max time */
2861 if(str2num(&config->timeout, nextarg))
2862 return PARAM_BAD_NUMERIC;
2864 case 'M': /* M for manual, huge help */
2865 if(toggle) { /* --no-manual shows no manual... */
2868 return PARAM_HELP_REQUESTED;
2871 "built-in manual was disabled at build-time!\n");
2872 return PARAM_OPTION_UNKNOWN;
2878 case 'o': /* CA info PEM file */
2879 /* use .netrc or URL */
2880 config->netrc_opt = toggle;
2883 /* pick info from .netrc, if this is used for http, curl will
2884 automatically enfore user+password with the request */
2885 config->netrc = toggle;
2890 /* disable the output I/O buffering. note that the option is called
2891 --buffer but is mostly used in the negative form: --no-buffer */
2893 config->nobuffer = (bool)(!toggle);
2895 config->nobuffer = toggle;
2897 case 'O': /* --remote-name */
2898 if(subletter == 'a') { /* --remote-name-all */
2899 config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
2903 case 'o': /* --output */
2907 if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
2908 /* there's a node here, if it already is filled-in continue to find
2910 while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
2911 config->url_out = config->url_out->next;
2914 /* now there might or might not be an available node to fill in! */
2918 url = config->url_out;
2920 /* there was no free node, create one! */
2921 url=new_getout(config);
2924 /* fill in the outfile */
2926 GetStr(&url->outfile, nextarg);
2927 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2930 url->outfile=NULL; /* leave it */
2932 url->flags |= GETOUT_USEREMOTE; /* switch on */
2934 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2936 url->flags |= GETOUT_OUTFILE;
2941 /* This makes the FTP sessions use PORT instead of PASV */
2942 /* use <eth0> or <192.168.10.10> style addresses. Anything except
2943 this will make us try to get the "default" address.
2944 NOTE: this is a changed behaviour since the released 4.1!
2946 GetStr(&config->ftpport, nextarg);
2949 /* proxy tunnel for non-http protocols */
2950 config->proxytunnel = toggle;
2953 case 'q': /* if used first, already taken care of, we do it like
2954 this so we don't cause an error! */
2957 /* QUOTE command to send to FTP server */
2958 switch(nextarg[0]) {
2960 /* prefixed with a dash makes it a POST TRANSFER one */
2962 err = add2list(&config->postquote, nextarg);
2965 /* prefixed with a plus makes it a just-before-transfer one */
2967 err = add2list(&config->prequote, nextarg);
2970 err = add2list(&config->quote, nextarg);
2977 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2978 (and won't actually be range by definition). The man page previously
2979 claimed that to be a good way, why this code is added to work-around
2981 if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
2985 "A specified range MUST include at least one dash (-). "
2986 "Appending one for you!\n");
2987 off = curlx_strtoofft(nextarg, NULL, 10);
2988 snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
2989 GetStr(&config->range, buffer);
2992 /* byte range requested */
2995 while(*tmp_range != '\0') {
2996 if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') {
2997 warnf(config,"Invalid character is found in given range. "
2998 "A specified range MUST have only digits in "
2999 "\'start\'-\'stop\'. The server's response to this "
3000 "request is uncertain.\n");
3005 /* byte range requested */
3006 GetStr(&config->range, nextarg);
3010 /* use remote file's time */
3011 config->remote_time = toggle;
3014 /* don't show progress meter, don't show errors : */
3016 config->mute = config->noprogress = TRUE;
3018 config->mute = config->noprogress = FALSE;
3019 config->showerror = (bool)(!toggle); /* toggle off */
3023 config->showerror = toggle; /* toggle on if used with -s */
3026 /* Telnet options */
3027 err = add2list(&config->telnet_options, nextarg);
3032 /* we are uploading */
3035 if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
3036 /* there's a node here, if it already is filled-in continue to find
3038 while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
3039 config->url_out = config->url_out->next;
3042 /* now there might or might not be an available node to fill in! */
3046 url = config->url_out;
3048 /* there was no free node, create one! */
3049 url=new_getout(config);
3052 url->flags |= GETOUT_UPLOAD; /* mark -T used */
3054 url->flags |= GETOUT_NOUPLOAD;
3056 /* "-" equals stdin, but keep the string around for now */
3057 GetStr(&url->infile, nextarg);
3064 GetStr(&config->userpwd, nextarg);
3066 checkpasswd("host", &config->userpwd);
3069 /* Proxy user:password */
3070 GetStr(&config->proxyuserpwd, nextarg);
3072 checkpasswd("proxy", &config->proxyuserpwd);
3076 /* the '%' thing here will cause the trace get sent to stderr */
3077 GetStr(&config->trace_dump, (char *)"%");
3078 if(config->tracetype && (config->tracetype != TRACE_PLAIN))
3080 "-v/--verbose overrides an earlier trace/verbose option\n");
3081 config->tracetype = TRACE_PLAIN;
3084 /* verbose is disabled here */
3085 config->tracetype = TRACE_NONE;
3089 const char * const *proto;
3092 /* --no-version yields no output! */
3095 printf(CURL_ID "%s\n", curl_version());
3096 if(curlinfo->protocols) {
3097 printf("Protocols: ");
3098 for(proto=curlinfo->protocols; *proto; ++proto) {
3099 printf("%s ", *proto);
3101 puts(""); /* newline */
3103 if(curlinfo->features) {
3109 static const struct feat feats[] = {
3110 {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
3111 {"Debug", CURL_VERSION_DEBUG},
3112 {"TrackMemory", CURL_VERSION_CURLDEBUG},
3113 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
3114 {"IDN", CURL_VERSION_IDN},
3115 {"IPv6", CURL_VERSION_IPV6},
3116 {"Largefile", CURL_VERSION_LARGEFILE},
3117 {"NTLM", CURL_VERSION_NTLM},
3118 {"SPNEGO", CURL_VERSION_SPNEGO},
3119 {"SSL", CURL_VERSION_SSL},
3120 {"SSPI", CURL_VERSION_SSPI},
3121 {"krb4", CURL_VERSION_KERBEROS4},
3122 {"libz", CURL_VERSION_LIBZ},
3123 {"CharConv", CURL_VERSION_CONV}
3125 printf("Features: ");
3126 for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
3127 if(curlinfo->features & feats[i].bitmask)
3128 printf("%s ", feats[i].name);
3130 puts(""); /* newline */
3133 return PARAM_HELP_REQUESTED;
3135 /* get the output string */
3136 if('@' == *nextarg) {
3137 /* the data begins with a '@' letter, it means that a file name
3138 or - (stdin) follows */
3141 nextarg++; /* pass the @ */
3142 if(curlx_strequal("-", nextarg)) {
3148 file = fopen(nextarg, "r");
3150 err = file2string(&config->writeout, file);
3151 if(file && (file != stdin))
3155 if(!config->writeout)
3156 warnf(config, "Failed to read %s", fname);
3159 GetStr(&config->writeout, nextarg);
3163 GetStr(&config->proxy, nextarg);
3164 config->proxyver = CURLPROXY_HTTP;
3167 /* set custom request */
3168 GetStr(&config->customrequest, nextarg);
3171 /* low speed time */
3172 if(str2num(&config->low_speed_time, nextarg))
3173 return PARAM_BAD_NUMERIC;
3174 if(!config->low_speed_limit)
3175 config->low_speed_limit = 1;
3178 /* low speed limit */
3179 if(str2num(&config->low_speed_limit, nextarg))
3180 return PARAM_BAD_NUMERIC;
3181 if(!config->low_speed_time)
3182 config->low_speed_time=30;
3184 case 'z': /* time condition coming up */
3189 /* If-Modified-Since: (section 14.28 in RFC2068) */
3190 config->timecond = CURL_TIMECOND_IFMODSINCE;
3193 /* If-Unmodified-Since: (section 14.24 in RFC2068) */
3194 config->timecond = CURL_TIMECOND_IFUNMODSINCE;
3198 /* Last-Modified: (section 14.29 in RFC2068) */
3199 config->timecond = CURL_TIMECOND_LASTMOD;
3204 config->condtime=curl_getdate(nextarg, &now);
3205 if(-1 == (int)config->condtime) {
3206 /* now let's see if it is a file name to get the time from instead! */
3207 struct_stat statbuf;
3208 if(-1 == stat(nextarg, &statbuf)) {
3209 /* failed, remove time condition */
3210 config->timecond = CURL_TIMECOND_NONE;
3212 "Illegal date format for -z/--timecond (and not "
3213 "a file name). Disabling time condition. "
3214 "See curl_getdate(3) for valid date syntax.\n");
3217 /* pull the time out from the file */
3218 config->condtime = statbuf.st_mtime;
3222 default: /* unknown flag */
3223 return PARAM_OPTION_UNKNOWN;
3227 } while(!longopt && !singleopt && *++parse && !*usedarg);
3233 * Copies the string from line to the buffer at param, unquoting
3234 * backslash-quoted characters and NUL-terminating the output string.
3235 * Stops at the first non-backslash-quoted double quote character or the
3236 * end of the input string. param must be at least as long as the input
3237 * string. Returns the pointer after the last handled input character.
3239 static const char *unslashquote(const char *line, char *param)
3241 while(*line && (*line != '\"')) {
3246 /* default is to output the letter after the backslash */
3247 switch(out = *line) {
3249 continue; /* this'll break out of the loop */
3269 *param=0; /* always zero terminate */
3273 /* return 0 on everything-is-fine, and non-zero otherwise */
3274 static int parseconfig(const char *filename,
3275 struct Configurable *config)
3279 char filebuffer[512];
3284 if(!filename || !*filename) {
3285 /* NULL or no file name attempts to load .curlrc from the homedir! */
3287 #define CURLRC DOT_CHAR "curlrc"
3290 filename = CURLRC; /* sensible default */
3291 home = homedir(); /* portable homedir finder */
3293 if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
3294 snprintf(filebuffer, sizeof(filebuffer),
3295 "%s%s%s", home, DIR_CHAR, CURLRC);
3298 /* Check if the file exists - if not, try CURLRC in the same
3299 * directory as our executable
3301 file = fopen(filebuffer, "r");
3304 filename = filebuffer;
3307 /* Get the filename of our executable. GetModuleFileName is
3308 * already declared via inclusions done in setup header file.
3309 * We assume that we are using the ASCII version here.
3311 int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
3312 if(n > 0 && n < (int)sizeof(filebuffer)) {
3313 /* We got a valid filename - get the directory part */
3314 char *lastdirchar = strrchr(filebuffer, '\\');
3318 /* If we have enough space, build the RC filename */
3319 remaining = sizeof(filebuffer) - strlen(filebuffer);
3320 if(strlen(CURLRC) < remaining - 1) {
3321 snprintf(lastdirchar, remaining,
3322 "%s%s", DIR_CHAR, CURLRC);
3323 /* Don't bother checking if it exists - we do
3326 filename = filebuffer;
3332 filename = filebuffer;
3335 free(home); /* we've used it, now free it */
3338 # else /* __AMIGA__ */
3339 /* On AmigaOS all the config files are into env:
3341 filename = "ENV:" CURLRC;
3346 if(strcmp(filename,"-"))
3347 file = fopen(filename, "r");
3359 #define ISSEP(x) (((x)=='=') || ((x) == ':'))
3361 while(NULL != (aline = my_get_line(file))) {
3364 alloced_param=FALSE;
3366 /* line with # in the first non-blank column is a comment! */
3367 while(*line && ISSPACE(*line))
3381 /* the option keywords starts here */
3383 while(*line && !ISSPACE(*line) && !ISSEP(*line))
3385 /* ... and has ended here */
3388 *line++=0; /* zero terminate, we have a local copy of the data */
3391 fprintf(stderr, "GOT: %s\n", option);
3394 /* pass spaces and separator(s) */
3395 while(*line && (ISSPACE(*line) || ISSEP(*line)))
3398 /* the parameter starts here (unless quoted) */
3400 /* quoted parameter, do the quote dance */
3402 param=malloc(strlen(line)+1); /* parameter */
3410 (void)unslashquote(line, param);
3413 param=line; /* parameter starts here */
3414 while(*line && !ISSPACE(*line))
3416 *line=0; /* zero terminate */
3419 if(param && !*param) {
3420 /* do this so getparameter can check for required parameters.
3421 Otherwise it always thinks there's a parameter. */
3428 fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
3430 res = getparameter(option, param, &usedarg, config);
3432 if(param && *param && !usedarg)
3433 /* we passed in a parameter that wasn't used! */
3434 res = PARAM_GOT_EXTRA_PARAMETER;
3436 if(res != PARAM_OK) {
3437 /* the help request isn't really an error */
3438 if(!strcmp(filename, "-")) {
3439 filename=(char *)"<stdin>";
3441 if(PARAM_HELP_REQUESTED != res) {
3442 const char *reason = param2text(res);
3443 warnf(config, "%s:%d: warning: '%s' %s\n",
3444 filename, lineno, option, reason);
3460 rc = 1; /* couldn't open the file */
3464 static void go_sleep(long ms)
3466 #ifdef HAVE_POLL_FINE
3467 /* portable subsecond "sleep" */
3468 poll((void *)0, 0, (int)ms);
3470 /* systems without poll() need other solutions */
3473 /* Windows offers a millisecond sleep */
3475 #elif defined(MSDOS)
3478 /* Other systems must use select() for this */
3479 struct timeval timeout;
3481 timeout.tv_sec = ms/1000;
3483 timeout.tv_usec = ms * 1000;
3485 select(0, NULL, NULL, NULL, &timeout);
3491 static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
3494 struct OutStruct *out=(struct OutStruct *)stream;
3495 struct Configurable *config = out->config;
3498 * Once that libcurl has called back my_fwrite() the returned value
3499 * is checked against the amount that was intended to be written, if
3500 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
3501 * point returning a value different from sz*nmemb indicates failure.
3503 const size_t err_rc = (sz * nmemb) ? 0 : 1;
3506 out->bytes = 0; /* nothing written yet */
3507 if(!out->filename) {
3508 warnf(config, "Remote filename has no length!\n");
3509 return err_rc; /* Failure */
3512 if(config->content_disposition) {
3513 /* don't overwrite existing files */
3514 FILE* f = fopen(out->filename, "r");
3517 warnf(config, "Refusing to overwrite %s: %s\n", out->filename,
3519 return err_rc; /* Failure */
3523 /* open file for writing */
3524 out->stream=fopen(out->filename, "wb");
3526 warnf(config, "Failed to create the file %s: %s\n", out->filename,
3528 return err_rc; /* failure */
3532 rc = fwrite(buffer, sz, nmemb, out->stream);
3534 if((sz * nmemb) == rc)
3535 /* we added this amount of data to the output */
3536 out->bytes += (sz * nmemb);
3538 if(config->readbusy) {
3539 config->readbusy = FALSE;
3540 curl_easy_pause(config->easy, CURLPAUSE_CONT);
3543 if(config->nobuffer) {
3544 /* disable output buffering */
3545 int res = fflush(out->stream);
3547 /* return a value that isn't the same as sz * nmemb */
3548 return err_rc; /* failure */
3557 struct Configurable *config;
3560 #define MAX_SEEK 2147483647
3563 * my_seek() is the CURLOPT_SEEKFUNCTION we use
3565 static int my_seek(void *stream, curl_off_t offset, int whence)
3567 struct InStruct *in=(struct InStruct *)stream;
3569 #if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
3570 /* The offset check following here is only interesting if curl_off_t is
3571 larger than off_t and we are not using the WIN32 large file support
3572 macros that provide the support to do 64bit seeks correctly */
3574 if(offset > MAX_SEEK) {
3575 /* Some precaution code to work around problems with different data sizes
3576 to allow seeking >32bit even if off_t is 32bit. Should be very rare and
3577 is really valid on weirdo-systems. */
3578 curl_off_t left = offset;
3580 if(whence != SEEK_SET)
3581 /* this code path doesn't support other types */
3584 if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
3585 /* couldn't rewind to beginning */
3589 long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
3590 if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
3591 /* couldn't seek forwards the desired amount */
3598 if(LSEEK_ERROR == lseek(in->fd, offset, whence))
3599 /* couldn't rewind, the reason is in errno but errno is just not portable
3600 enough and we don't actually care that much why we failed. We'll let
3601 libcurl know that it may try other means if it wants to. */
3602 return CURL_SEEKFUNC_CANTSEEK;
3607 static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
3610 struct InStruct *in=(struct InStruct *)userp;
3612 rc = read(in->fd, buffer, sz*nmemb);
3614 if(errno == EAGAIN) {
3616 in->config->readbusy = TRUE;
3617 return CURL_READFUNC_PAUSE;
3619 /* since size_t is unsigned we can't return negative values fine */
3622 in->config->readbusy = FALSE;
3626 struct ProgressData {
3630 FILE *out; /* where to write everything to */
3631 curl_off_t initial_size;
3634 static int myprogress (void *clientp,
3640 /* The original progress-bar source code was written for curl by Lars Aas,
3641 and this new edition inherits some of his concepts. */
3652 struct ProgressData *bar = (struct ProgressData *)clientp;
3653 curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
3654 bar->initial_size; /* expected transfer size */
3655 curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
3656 bar->initial_size; /* we've come this far */
3659 /* we have got more than the expected total! */
3662 bar->calls++; /* simply count invokes */
3665 curl_off_t prevblock = bar->prev / 1024;
3666 curl_off_t thisblock = point / 1024;
3667 while( thisblock > prevblock ) {
3668 fprintf( bar->out, "#" );
3673 frac = (double)point / (double)total;
3674 percent = frac * 100.0f;
3675 barwidth = bar->width - 7;
3676 num = (int) (((double)barwidth) * frac);
3677 for( i = 0; i < num; i++ ) {
3681 snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
3682 snprintf( outline, sizeof(outline), format, line, percent );
3683 fprintf( bar->out, "\r%s", outline );
3692 void progressbarinit(struct ProgressData *bar,
3693 struct Configurable *config)
3701 memset(bar, 0, sizeof(struct ProgressData));
3703 /* pass this through to progress function so
3704 * it can display progress towards total file
3705 * not just the part that's left. (21-may-03, dbyron) */
3706 if(config->use_resume)
3707 bar->initial_size = config->resume_from;
3709 /* TODO: get terminal width through ansi escapes or something similar.
3710 try to update width when xterm is resized... - 19990617 larsa */
3713 * OS/2 users most likely won't have this env var set, and besides that
3714 * we're using our own way to determine screen width */
3715 colp = curlx_getenv("COLUMNS");
3718 long num = strtol(colp, &endptr, 10);
3719 if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0))
3720 bar->width = (int)num;
3729 * We use this emx library call to get the screen width, and subtract
3730 * one from what we got in order to avoid a problem with the cursor
3731 * advancing to the next line if we print a string that is as long as
3732 * the screen is wide. */
3735 bar->width = scr_size[0] - 1;
3738 bar->out = config->errors;
3743 void dump(const char *timebuf, const char *text,
3744 FILE *stream, const unsigned char *ptr, size_t size,
3745 trace tracetype, curl_infotype infotype)
3750 unsigned int width=0x10;
3752 if(tracetype == TRACE_ASCII)
3753 /* without the hex output, we can fit more on screen */
3756 fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
3758 for(i=0; i<size; i+= width) {
3760 fprintf(stream, "%04zx: ", i);
3762 if(tracetype == TRACE_BIN) {
3763 /* hex not disabled, show it */
3764 for(c = 0; c < width; c++)
3766 fprintf(stream, "%02x ", ptr[i+c]);
3771 for(c = 0; (c < width) && (i+c < size); c++) {
3772 /* check for 0D0A; if found, skip past and start a new line of output */
3773 if((tracetype == TRACE_ASCII) &&
3774 (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
3778 #ifdef CURL_DOES_CONVERSIONS
3779 /* repeat the 0D0A check above but use the host encoding for CRLF */
3780 if((tracetype == TRACE_ASCII) &&
3781 (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') {
3785 /* convert to host encoding and print this character */
3786 fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
3789 fprintf(stream, "%c",
3790 (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR);
3791 #endif /* CURL_DOES_CONVERSIONS */
3792 /* check again for 0D0A, to avoid an extra \n if it's at width */
3793 if((tracetype == TRACE_ASCII) &&
3794 (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
3799 fputc('\n', stream); /* newline */
3805 int my_trace(CURL *handle, curl_infotype type,
3806 unsigned char *data, size_t size,
3809 struct Configurable *config = (struct Configurable *)userp;
3810 FILE *output=config->errors;
3816 static time_t epoch_offset;
3817 static int known_offset;
3819 (void)handle; /* prevent compiler warning */
3821 if(config->tracetime) {
3824 epoch_offset = time(NULL) - tv.tv_sec;
3827 secs = epoch_offset + tv.tv_sec;
3828 now = localtime(&secs); /* not thread safe but we don't care */
3829 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
3830 now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
3835 if(!config->trace_stream) {
3836 /* open for append */
3837 if(curlx_strequal("-", config->trace_dump))
3838 config->trace_stream = stdout;
3839 else if(curlx_strequal("%", config->trace_dump))
3840 /* Ok, this is somewhat hackish but we do it undocumented for now */
3841 config->trace_stream = config->errors; /* aka stderr */
3843 config->trace_stream = fopen(config->trace_dump, "w");
3844 config->trace_fopened = TRUE;
3848 if(config->trace_stream)
3849 output = config->trace_stream;
3852 warnf(config, "Failed to create/open output");
3856 if(config->tracetype == TRACE_PLAIN) {
3858 * This is the trace look that is similar to what libcurl makes on its
3861 static const char * const s_infotype[] = {
3862 "*", "<", ">", "{", "}", "{", "}"
3866 static bool newl = FALSE;
3867 static bool traced_data = FALSE;
3870 case CURLINFO_HEADER_OUT:
3871 for(i=0; i<size-1; i++) {
3872 if(data[i] == '\n') { /* LF */
3874 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3876 (void)fwrite(data+st, i-st+1, 1, output);
3882 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3883 (void)fwrite(data+st, i-st+1, 1, output);
3884 newl = (bool)(size && (data[size-1] != '\n'));
3885 traced_data = FALSE;
3888 case CURLINFO_HEADER_IN:
3890 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3891 (void)fwrite(data, size, 1, output);
3892 newl = (bool)(size && (data[size-1] != '\n'));
3893 traced_data = FALSE;
3895 case CURLINFO_DATA_OUT:
3896 case CURLINFO_DATA_IN:
3897 case CURLINFO_SSL_DATA_IN:
3898 case CURLINFO_SSL_DATA_OUT:
3900 /* if the data is output to a tty and we're sending this debug trace
3901 to stderr or stdout, we don't display the alert about the data not
3902 being shown as the data _is_ shown then just not via this
3904 if(!config->isatty ||
3905 ((output != stderr) && (output != stdout))) {
3907 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3908 fprintf(output, "[data not shown]\n");
3916 traced_data = FALSE;
3923 #ifdef CURL_DOES_CONVERSIONS
3924 /* Special processing is needed for CURLINFO_HEADER_OUT blocks
3925 * if they contain both headers and data (separated by CRLFCRLF).
3926 * We dump the header text and then switch type to CURLINFO_DATA_OUT.
3928 if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
3930 for(i = 0; i < size - 4; i++) {
3931 if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
3932 /* dump everthing through the CRLFCRLF as a sent header */
3933 text = "=> Send header";
3934 dump(timebuf, text, output, data, i+4, config->tracetype, type);
3937 type = CURLINFO_DATA_OUT;
3943 #endif /* CURL_DOES_CONVERSIONS */
3947 fprintf(output, "%s== Info: %s", timebuf, data);
3948 default: /* in case a new one is introduced to shock us */
3951 case CURLINFO_HEADER_OUT:
3952 text = "=> Send header";
3954 case CURLINFO_DATA_OUT:
3955 text = "=> Send data";
3957 case CURLINFO_HEADER_IN:
3958 text = "<= Recv header";
3960 case CURLINFO_DATA_IN:
3961 text = "<= Recv data";
3963 case CURLINFO_SSL_DATA_IN:
3964 text = "<= Recv SSL data";
3966 case CURLINFO_SSL_DATA_OUT:
3967 text = "=> Send SSL data";
3971 dump(timebuf, text, output, data, size, config->tracetype, type);
3975 static void free_config_fields(struct Configurable *config)
3977 if(config->random_file)
3978 free(config->random_file);
3979 if(config->egd_file)
3980 free(config->egd_file);
3981 if(config->trace_dump)
3982 free(config->trace_dump);
3983 if(config->cipher_list)
3984 free(config->cipher_list);
3986 free(config->userpwd);
3987 if(config->postfields)
3988 free(config->postfields);
3990 free(config->proxy);
3991 if(config->proxyuserpwd)
3992 free(config->proxyuserpwd);
3994 free(config->noproxy);
3996 free(config->cookie);
3997 if(config->cookiefile)
3998 free(config->cookiefile);
3999 if(config->krblevel)
4000 free(config->krblevel);
4001 if(config->headerfile)
4002 free(config->headerfile);
4004 free(config->ftpport);
4006 free(config->range);
4007 if(config->customrequest)
4008 free(config->customrequest);
4009 if(config->writeout)
4010 free(config->writeout);
4011 if(config->httppost)
4012 curl_formfree(config->httppost);
4016 free(config->cacert);
4017 if(config->cert_type)
4018 free(config->cert_type);
4020 free(config->capath);
4022 free(config->crlfile);
4023 if(config->cookiejar)
4024 free(config->cookiejar);
4025 if(config->ftp_account)
4026 free(config->ftp_account);
4027 if(config->ftp_alternative_to_user)
4028 free(config->ftp_alternative_to_user);
4030 free(config->iface);
4031 if(config->socksproxy)
4032 free(config->socksproxy);
4034 free(config->libcurl);
4035 if(config->key_passwd)
4036 free(config->key_passwd);
4039 if(config->key_type)
4040 free(config->key_type);
4042 free(config->pubkey);
4044 free(config->referer);
4045 if(config->hostpubmd5)
4046 free(config->hostpubmd5);
4047 if(config->mail_from)
4048 free(config->mail_from);
4049 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
4050 if(config->socks5_gssapi_service)
4051 free(config->socks5_gssapi_service);
4054 curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
4055 curl_slist_free_all(config->prequote);
4056 curl_slist_free_all(config->postquote);
4057 curl_slist_free_all(config->headers);
4058 curl_slist_free_all(config->telnet_options);
4059 curl_slist_free_all(config->mail_rcpt);
4060 curl_slist_free_all(config->resolve);
4063 curl_easy_cleanup(config->easy);
4068 /* Function to find CACert bundle on a Win32 platform using SearchPath.
4069 * (SearchPath is already declared via inclusions done in setup header file)
4070 * (Use the ASCII version instead of the unicode one!)
4071 * The order of the directories it searches is:
4072 * 1. application's directory
4073 * 2. current working directory
4074 * 3. Windows System directory (e.g. C:\windows\system32)
4075 * 4. Windows Directory (e.g. C:\windows)
4076 * 5. all directories along %PATH%
4078 static void FindWin32CACert(struct Configurable *config,
4079 const char *bundle_file)
4081 /* only check for cert file if "we" support SSL */
4082 if(curlinfo->features & CURL_VERSION_SSL) {
4085 char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1));
4089 buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
4091 GetStr(&config->cacert, retval);
4099 #define RETRY_SLEEP_DEFAULT 1000 /* ms */
4100 #define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */
4103 output_expected(const char* url, const char* uploadfile)
4106 return TRUE; /* download */
4107 if(checkprefix("http://", url) || checkprefix("https://", url))
4108 return TRUE; /* HTTP(S) upload */
4110 return FALSE; /* non-HTTP upload, probably no output should be expected */
4113 #define my_setopt(x,y,z) _my_setopt(x, FALSE, config, #y, y, z)
4114 #define my_setopt_str(x,y,z) _my_setopt(x, TRUE, config, #y, y, z)
4116 static struct curl_slist *easycode;
4117 static struct curl_slist *easycode_remarks;
4119 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
4120 const char *name, CURLoption tag, ...);
4122 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
4123 const char *name, CURLoption tag, ...)
4134 if(tag < CURLOPTTYPE_OBJECTPOINT) {
4135 long lval = va_arg(arg, long);
4136 snprintf(value, sizeof(value), "%ld", lval);
4137 ret = curl_easy_setopt(curl, tag, lval);
4141 else if(tag < CURLOPTTYPE_OFF_T) {
4142 void *pval = va_arg(arg, void *);
4143 unsigned char *ptr = (unsigned char *)pval;
4145 /* function pointers are never printable */
4146 if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
4148 strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */
4155 else if(pval && str)
4156 snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
4158 strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */
4164 ret = curl_easy_setopt(curl, tag, pval);
4168 curl_off_t oval = va_arg(arg, curl_off_t);
4169 snprintf(value, sizeof(value),
4170 "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
4171 ret = curl_easy_setopt(curl, tag, oval);
4177 if(config->libcurl && !skip) {
4178 /* we only use this for real if --libcurl was used */
4181 bufp = curlx_maprintf("%s set to a %s", name, value);
4183 bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value);
4186 ret = CURLE_OUT_OF_MEMORY;
4188 struct curl_slist *list =
4189 curl_slist_append(remark?easycode_remarks:easycode, bufp);
4192 easycode_remarks = list;
4204 static const char * const srchead[]={
4205 "/********* Sample code generated by the curl command line tool **********",
4206 " * All curl_easy_setopt() options are documented at:",
4207 " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html",
4208 " ************************************************************************/",
4209 "#include <curl/curl.h>",
4211 "int main(int argc, char *argv[])",
4217 static void dumpeasycode(struct Configurable *config)
4219 struct curl_slist *ptr;
4220 char *o = config->libcurl;
4224 bool fopened = FALSE;
4225 if(strcmp(o, "-")) {
4226 out = fopen(o, "wt");
4232 warnf(config, "Failed to open %s to write libcurl code!\n", o);
4237 for(i=0; ((c = srchead[i]) != '\0'); i++)
4238 fprintf(out, "%s\n", c);
4242 fprintf(out, " %s\n", ptr->data);
4246 ptr = easycode_remarks;
4249 "\n /* Here is a list of options the curl code"
4250 " used that cannot get generated\n"
4251 " as source easily. You may select to either"
4252 " not use them or implement\n them yourself.\n"
4255 fprintf(out, " %s\n", ptr->data);
4258 fprintf(out, "\n */\n");
4262 " return (int)ret;\n"
4264 "/**** End of sample code ****/\n");
4269 curl_slist_free_all(easycode);
4272 static bool stdin_upload(const char *uploadfile)
4274 return (bool)(curlx_strequal(uploadfile, "-") ||
4275 curlx_strequal(uploadfile, "."));
4278 /* Adds the file name to the URL if it doesn't already have one.
4279 * url will be freed before return if the returned pointer is different
4281 static char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
4283 /* If no file name part is given in the URL, we add this file name */
4284 char *ptr=strstr(url, "://");
4289 ptr = strrchr(ptr, '/');
4290 if(!ptr || !strlen(++ptr)) {
4291 /* The URL has no file name part, add the local file name. In order
4292 to be able to do so, we have to create a new URL in another
4295 /* We only want the part of the local path that is on the right
4296 side of the rightmost slash and backslash. */
4297 const char *filep = strrchr(filename, '/');
4298 char *file2 = strrchr(filep?filep:filename, '\\');
4308 /* URL encode the file name */
4309 encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
4311 char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
4317 /* there is a trailing slash on the URL */
4318 sprintf(urlbuffer, "%s%s", url, encfile);
4320 /* there is no trailing slash on the URL */
4321 sprintf(urlbuffer, "%s/%s", url, encfile);
4326 url = urlbuffer; /* use our new URL instead! */
4332 /* Extracts the name portion of the URL.
4333 * Returns a heap-allocated string, or NULL if no name part
4335 static char *get_url_file_name(const char *url)
4339 /* Find and get the remote file name */
4340 const char * pc =strstr(url, "://");
4345 pc = strrchr(pc, '/');
4348 /* duplicate the string beyond the slash */
4350 fn = *pc ? strdup(pc): NULL;
4356 parse_filename(char *ptr, size_t len)
4363 /* simple implementation of strndup() */
4364 copy = malloc(len+1);
4367 strncpy(copy, ptr, len);
4371 if(*p == '\'' || *p == '"') {
4372 /* store the starting quote */
4377 /* if the filename contains a path, only use filename portion */
4378 q = strrchr(copy, '/');
4387 /* If the filename contains a backslash, only use filename portion. The idea
4388 is that even systems that don't handle backslashes as path separators
4389 probably want the path removed for convenience. */
4390 q = strrchr(p, '\\');
4400 /* if the file name started with a quote, then scan for the end quote and
4402 q = strrchr(p, quote);
4407 q = NULL; /* no start quote, so no end has been found */
4410 /* make sure the file name doesn't end in \r or \n */
4411 q = strchr(p, '\r');
4415 q = strchr(p, '\n');
4421 memmove(copy, p, strlen(p)+1);
4427 header_callback(void *ptr, size_t size, size_t nmemb, void *stream)
4429 struct OutStruct* outs = (struct OutStruct*)stream;
4430 const char* str = (char*)ptr;
4431 const size_t cb = size*nmemb;
4432 const char* end = (char*)ptr + cb;
4435 if(cb > 20 && checkprefix("Content-disposition:", str)) {
4436 char *p = (char*)str + 20;
4438 /* look for the 'filename=' parameter
4439 (encoded filenames (*=) are not supported) */
4444 while(*p && (p < end) && !ISALPHA(*p))
4449 if(memcmp(p, "filename=", 9)) {
4450 /* no match, find next parameter */
4451 while((p < end) && (*p != ';'))
4456 semi = strchr(p, ';');
4458 /* this expression below typecasts 'cb' only to avoid
4459 warning: signed and unsigned type in conditional expression
4461 len = semi ? (semi - p) : (ssize_t)cb - (p - str);
4462 filename = parse_filename(p, len);
4464 outs->filename = filename;
4474 operate(struct Configurable *config, int argc, argv_item_t argv[])
4476 char errorbuffer[CURL_ERROR_SIZE];
4477 char useragent[256]; /* buah, we don't want a larger default user agent */
4478 struct ProgressData progressbar;
4479 struct getout *urlnode;
4480 struct getout *nextnode;
4482 struct OutStruct outs;
4483 struct OutStruct heads;
4484 struct InStruct input;
4487 URLGlob *inglob=NULL;
4490 char *uploadfile=NULL; /* a single file, never a glob */
4492 curl_off_t uploadfilesize; /* -1 means unknown */
4493 bool stillflags=TRUE;
4495 bool allocuseragent=FALSE;
4497 char *httpgetfields=NULL;
4502 long retry_sleep_default;
4507 memset(&heads, 0, sizeof(struct OutStruct));
4510 /* this sends all memory debug messages to a logfile named memdump */
4511 env = curlx_getenv("CURL_MEMDEBUG");
4513 /* use the value as file name */
4514 char *s = strdup(env);
4518 /* this weird strdup() and stuff here is to make the curl_free() get
4519 called before the memdebug() as otherwise the memdebug tracing will
4520 with tracing a free() without an alloc! */
4522 env = curlx_getenv("CURL_MEMLIMIT");
4525 long num = strtol(env, &endptr, 10);
4526 if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
4532 /* Initialize curl library - do not call any libcurl functions before.
4533 Note that the CURLDEBUG magic above is an exception, but then that's not
4534 part of the official public API.
4536 if(main_init() != CURLE_OK) {
4537 helpf(config->errors, "error initializing curl library\n");
4538 return CURLE_FAILED_INIT;
4542 * Get a curl handle to use for all forthcoming curl transfers. Cleanup
4543 * when all transfers are done.
4545 curl = curl_easy_init();
4547 clean_getout(config);
4548 return CURLE_FAILED_INIT;
4550 config->easy = curl;
4552 memset(&outs,0,sizeof(outs));
4554 config->outs = &outs;
4556 /* we get libcurl info right away */
4557 curlinfo = curl_version_info(CURLVERSION_NOW);
4559 errorbuffer[0]=0; /* prevent junk from being output */
4561 /* setup proper locale from environment */
4562 #ifdef HAVE_SETLOCALE
4563 setlocale(LC_ALL, "");
4567 config->postfieldsize = -1;
4568 config->showerror=TRUE;
4569 config->use_httpget=FALSE;
4570 config->create_dirs=FALSE;
4571 config->maxredirs = DEFAULT_MAXREDIRS;
4572 config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
4573 config->proto_present = FALSE;
4574 config->proto_redir =
4575 CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
4576 config->proto_redir_present = FALSE;
4579 (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
4580 strchr(argv[1], 'q')) {
4582 * The first flag, that is not a verbose name, but a shortname
4583 * and it includes the 'q' flag!
4588 parseconfig(NULL, config); /* ignore possible failure */
4591 if((argc < 2) && !config->url_list) {
4592 helpf(config->errors, NULL);
4593 return CURLE_FAILED_INIT;
4597 for(i = 1; i < argc; i++) {
4599 ('-' == argv[i][0])) {
4602 char *origopt=argv[i];
4604 char *flag = argv[i];
4606 if(curlx_strequal("--", argv[i]))
4607 /* this indicates the end of the flags and thus enables the
4608 following (URL) argument to start with -. */
4611 nextarg= (i < argc - 1)? argv[i+1]: NULL;
4613 res = getparameter(flag, nextarg, &passarg, config);
4615 int retval = CURLE_OK;
4616 if(res != PARAM_HELP_REQUESTED) {
4617 const char *reason = param2text(res);
4618 helpf(config->errors, "option %s: %s\n", origopt, reason);
4619 retval = CURLE_FAILED_INIT;
4621 clean_getout(config);
4625 if(passarg) /* we're supposed to skip this */
4631 /* just add the URL please */
4632 res = getparameter((char *)"--url", argv[i], &used, config);
4638 retry_sleep_default = config->retry_delay?
4639 config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
4640 retry_sleep = retry_sleep_default;
4642 if((!config->url_list || !config->url_list->url) && !config->list_engines) {
4643 clean_getout(config);
4644 helpf(config->errors, "no URL specified!\n");
4645 return CURLE_FAILED_INIT;
4647 if(NULL == config->useragent) {
4648 /* set non-zero default values: */
4649 snprintf(useragent, sizeof(useragent),
4650 CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
4651 config->useragent= useragent;
4654 allocuseragent = TRUE;
4656 /* On WIN32 we can't set the path to curl-ca-bundle.crt
4657 * at compile time. So we look here for the file in two ways:
4658 * 1: look at the environment variable CURL_CA_BUNDLE for a path
4659 * 2: if #1 isn't found, use the windows API function SearchPath()
4660 * to find it along the app's path (includes app's dir and CWD)
4662 * We support the environment variable thing for non-Windows platforms
4663 * too. Just for the sake of it.
4665 if(!config->cacert &&
4667 !config->insecure_ok) {
4668 env = curlx_getenv("CURL_CA_BUNDLE");
4670 GetStr(&config->cacert, env);
4672 env = curlx_getenv("SSL_CERT_DIR");
4674 GetStr(&config->capath, env);
4676 env = curlx_getenv("SSL_CERT_FILE");
4678 GetStr(&config->cacert, env);
4686 FindWin32CACert(config, "curl-ca-bundle.crt");
4690 if(config->postfields) {
4691 if(config->use_httpget) {
4692 /* Use the postfields data for a http get */
4693 httpgetfields = strdup(config->postfields);
4694 free(config->postfields);
4695 config->postfields = NULL;
4696 if(SetHTTPrequest(config,
4697 (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
4698 &config->httpreq)) {
4699 free(httpgetfields);
4700 return PARAM_BAD_USE;
4704 if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
4705 return PARAM_BAD_USE;
4709 /* This is the first entry added to easycode and it initializes the slist */
4710 easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();");
4712 clean_getout(config);
4713 res = CURLE_OUT_OF_MEMORY;
4717 if(config->list_engines) {
4718 struct curl_slist *engines = NULL;
4720 curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
4721 list_engines(engines);
4722 curl_slist_free_all(engines);
4727 /* After this point, we should call curl_easy_cleanup() if we decide to bail
4728 * out from this function! */
4730 urlnode = config->url_list;
4732 if(config->headerfile) {
4733 /* open file for output: */
4734 if(strcmp(config->headerfile,"-")) {
4735 heads.filename = config->headerfile;
4738 heads.stream=stdout;
4739 heads.config = config;
4742 /* loop through the list of given URLs */
4744 int up; /* upload file counter within a single upload glob */
4747 char *infiles; /* might be a glob pattern */
4748 char *outfiles=NULL;
4750 /* get the full URL (it might be NULL) */
4756 /* This node had no URL, skip it and continue to the next */
4757 if(urlnode->outfile)
4758 free(urlnode->outfile);
4760 /* move on to the next URL */
4761 nextnode=urlnode->next;
4762 free(urlnode); /* free the node */
4764 continue; /* next please */
4767 /* default output stream is stdout */
4768 outs.stream = stdout;
4769 outs.config = config;
4770 outs.bytes = 0; /* nothing written yet */
4772 /* save outfile pattern before expansion */
4773 if(urlnode->outfile) {
4774 outfiles = strdup(urlnode->outfile);
4776 clean_getout(config);
4781 infiles = urlnode->infile;
4783 if(!config->globoff && infiles) {
4784 /* Unless explicitly shut off */
4785 res = glob_url(&inglob, infiles, &infilenum,
4786 config->showerror?config->errors:NULL);
4787 if(res != CURLE_OK) {
4788 clean_getout(config);
4795 /* Here's the loop for uploading multiple files within the same
4796 single globbed string. If no upload, we enter the loop once anyway. */
4798 (!up && !infiles) ||
4799 ((uploadfile = inglob?
4800 glob_next_url(inglob):
4801 (!up?strdup(infiles):NULL)) != NULL);
4804 long retry_numretries;
4807 if(!config->globoff) {
4808 /* Unless explicitly shut off, we expand '{...}' and '[...]'
4809 expressions and return total number of URLs in pattern set */
4810 res = glob_url(&urls, dourl, &urlnum,
4811 config->showerror?config->errors:NULL);
4812 if(res != CURLE_OK) {
4817 urlnum = 1; /* without globbing, this is a single URL */
4819 /* if multiple files extracted to stdout, insert separators! */
4820 separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
4822 /* Here's looping around each globbed URL */
4824 ((url = urls?glob_next_url(urls):(i?NULL:strdup(url))) != NULL);
4826 /* NOTE: In the condition expression in the for() statement above, the
4827 'url' variable is only ever strdup()ed if(i == 0) and thus never
4828 when this loops later on. Further down in this function we call
4829 free(url) and then the code loops. Static code parsers may thus get
4830 tricked into believing that we have a potential access-after-free
4831 here. I can however not spot any such case. */
4833 int infd = STDIN_FILENO;
4836 struct timeval retrystart;
4837 outfile = outfiles?strdup(outfiles):NULL;
4839 if((urlnode->flags&GETOUT_USEREMOTE) ||
4840 (outfile && !curlx_strequal("-", outfile)) ) {
4843 * We have specified a file name to store the result in, or we have
4844 * decided we want to use the remote file name.
4848 /* extract the file name from the URL */
4849 outfile = get_url_file_name(url);
4850 if((!outfile || !*outfile) && !config->content_disposition) {
4851 helpf(config->errors, "Remote file name has no length!\n");
4852 res = CURLE_WRITE_ERROR;
4856 #if defined(MSDOS) || defined(WIN32)
4857 /* For DOS and WIN32, we do some major replacing of
4858 bad characters in the file name before using it */
4859 outfile = sanitize_dos_name(outfile);
4861 res = CURLE_OUT_OF_MEMORY;
4864 #endif /* MSDOS || WIN32 */
4867 /* fill '#1' ... '#9' terms from URL pattern */
4868 char *storefile = outfile;
4869 outfile = glob_match_url(storefile, urls);
4873 warnf(config, "bad output glob!\n");
4875 res = CURLE_FAILED_INIT;
4880 /* Create the directory hierarchy, if not pre-existant to a multiple
4883 if(config->create_dirs &&
4884 (-1 == create_dir_hierarchy(outfile, config->errors))) {
4886 res = CURLE_WRITE_ERROR;
4890 if(config->resume_from_current) {
4891 /* We're told to continue from where we are now. Get the
4892 size of the file as it is now and open it for append instead */
4894 struct_stat fileinfo;
4896 /* VMS -- Danger, the filesize is only valid for stream files */
4897 if(0 == stat(outfile, &fileinfo))
4898 /* set offset to current file size: */
4899 config->resume_from = fileinfo.st_size;
4901 /* let offset be 0 */
4902 config->resume_from = 0;
4905 outs.filename = outfile;
4907 if(config->resume_from) {
4908 outs.init = config->resume_from;
4909 /* open file for output: */
4910 outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
4912 helpf(config->errors, "Can't open '%s'!\n", outfile);
4914 res = CURLE_WRITE_ERROR;
4919 outs.stream = NULL; /* open when needed */
4920 outs.bytes = 0; /* reset byte counter */
4924 if(uploadfile && !stdin_upload(uploadfile)) {
4926 * We have specified a file to upload and it isn't "-".
4928 struct_stat fileinfo;
4930 url = add_file_name_to_url(curl, url, uploadfile);
4932 helpf(config->errors, "out of memory\n");
4933 res = CURLE_OUT_OF_MEMORY;
4938 * Reading binary from files can be a problem... Only FIXED, VAR
4939 * etc WITHOUT implied CC will work Others need a \n appended to a
4942 * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
4943 * fixed file with implied CC needs to have a byte added for every
4944 * record processed, this can by derived from Filesize & recordsize
4945 * for VARiable record files the records need to be counted! for
4946 * every record add 1 for linefeed and subtract 2 for the record
4947 * header for VARIABLE header files only the bare record data needs
4948 * to be considered with one appended if implied CC
4951 infd= open(uploadfile, O_RDONLY | O_BINARY);
4952 if((infd == -1) || fstat(infd, &fileinfo)) {
4953 helpf(config->errors, "Can't open '%s'!\n", uploadfile);
4957 /* Free the list of remaining URLs and globbed upload files
4958 * to force curl to exit immediately
4965 glob_cleanup(inglob);
4969 res = CURLE_READ_ERROR;
4974 /* we ignore file size for char/block devices, sockets, etc. */
4975 if(S_ISREG(fileinfo.st_mode))
4976 uploadfilesize=fileinfo.st_size;
4979 else if(uploadfile && stdin_upload(uploadfile)) {
4980 /* count to see if there are more than one auth bit set
4981 in the authtype field */
4984 while(bitcheck < 32) {
4985 if(config->authtype & (1 << bitcheck++)) {
4988 /* more than one, we're done! */
4995 * If the user has also selected --anyauth or --proxy-anyauth
4996 * we should warn him/her.
4998 if(config->proxyanyauth || (authbits>1)) {
5000 "Using --anyauth or --proxy-anyauth with upload from stdin"
5001 " involves a big risk of it not working. Use a temporary"
5002 " file or a fixed auth type instead!\n");
5006 infd = STDIN_FILENO;
5007 if(curlx_strequal(uploadfile, ".")) {
5008 if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
5010 "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
5014 if(uploadfile && config->resume_from_current)
5015 config->resume_from = -1; /* -1 will then force get-it-yourself */
5017 if(output_expected(url, uploadfile)
5018 && outs.stream && isatty(fileno(outs.stream)))
5019 /* we send the output to a tty, therefore we switch off the progress
5021 config->noprogress = config->isatty = TRUE;
5023 if(urlnum > 1 && !(config->mute)) {
5024 fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
5025 i+1, urlnum, url, outfile ? outfile : "<stdout>");
5027 printf("%s%s\n", CURLseparator, url);
5031 /* Find out whether the url contains a file name */
5032 const char *pc =strstr(url, "://");
5039 pc = strrchr(pc, '/'); /* check for a slash */
5042 /* there is a slash present in the URL */
5045 /* Ouch, there's already a question mark in the URL string, we
5046 then append the data with an ampersand separator instead! */
5050 * Then append ? followed by the get fields to the url.
5052 urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
5054 helpf(config->errors, "out of memory\n");
5056 /* Free the list of remaining URLs and globbed upload files
5057 * to force curl to exit immediately
5064 glob_cleanup(inglob);
5068 res = CURLE_OUT_OF_MEMORY;
5072 sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
5074 /* Append / before the ? to create a well-formed url
5075 if the url contains a hostname only
5077 sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
5079 free(url); /* free previous URL */
5080 url = urlbuffer; /* use our new URL instead! */
5084 config->errors = stderr;
5086 if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
5087 /* We get the output to stdout and we have not got the ASCII/text
5088 flag, then set stdout to be binary */
5089 SET_BINMODE(stdout);
5092 if(1 == config->tcp_nodelay)
5093 my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
5095 /* where to store */
5096 my_setopt(curl, CURLOPT_WRITEDATA, &outs);
5097 /* what call to write */
5098 my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
5102 input.config = config;
5103 my_setopt(curl, CURLOPT_READDATA, &input);
5104 /* what call to read */
5105 if((outfile && !curlx_strequal("-", outfile)) ||
5106 !checkprefix("telnet:", url))
5107 my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
5109 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
5110 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
5111 my_setopt(curl, CURLOPT_SEEKDATA, &input);
5112 my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
5114 if(config->recvpersecond)
5115 /* tell libcurl to use a smaller sized buffer as it allows us to
5116 make better sleeps! 7.9.9 stuff! */
5117 my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
5119 /* size of uploaded file: */
5120 if(uploadfilesize != -1)
5121 my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
5122 my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */
5123 my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
5125 my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
5126 my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
5127 if(config->no_body) {
5128 my_setopt(curl, CURLOPT_NOBODY, 1);
5129 my_setopt(curl, CURLOPT_HEADER, 1);
5132 my_setopt(curl, CURLOPT_HEADER, config->include_headers);
5134 my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
5135 my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
5136 my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
5137 my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
5139 if(config->netrc_opt)
5140 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
5141 else if(config->netrc)
5142 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
5144 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
5146 my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
5147 my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth);
5148 my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
5149 my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
5150 my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
5151 my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
5152 my_setopt_str(curl, CURLOPT_RANGE, config->range);
5153 my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
5154 my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
5156 switch(config->httpreq) {
5157 case HTTPREQ_SIMPLEPOST:
5158 my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields);
5159 my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize);
5162 my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
5167 my_setopt_str(curl, CURLOPT_REFERER, config->referer);
5168 my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
5169 my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
5170 my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
5171 my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
5172 config->low_speed_limit);
5173 my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
5174 my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
5175 config->sendpersecond);
5176 my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
5177 config->recvpersecond);
5178 my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
5179 config->use_resume?config->resume_from:0);
5180 my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
5181 my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
5182 my_setopt(curl, CURLOPT_SSLCERT, config->cert);
5183 my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
5184 my_setopt(curl, CURLOPT_SSLKEY, config->key);
5185 my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
5186 my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
5188 /* SSH private key uses the same command-line option as SSL private
5190 my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
5191 my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
5193 /* SSH host key md5 checking allows us to fail if we are
5194 * not talking to who we think we should
5196 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
5197 config->hostpubmd5);
5199 /* default to strict verifyhost */
5200 /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); */
5201 if(config->cacert || config->capath) {
5203 my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
5206 my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
5207 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
5210 my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
5211 if(config->insecure_ok) {
5212 /* new stuff needed for libcurl 7.10 */
5213 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
5214 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
5217 char *home = homedir();
5218 char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
5223 my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
5227 /* Free the list of remaining URLs and globbed upload files
5228 * to force curl to exit immediately
5235 glob_cleanup(inglob);
5239 res = CURLE_OUT_OF_MEMORY;
5244 if(config->no_body || config->remote_time) {
5245 /* no body or use remote time */
5246 my_setopt(curl, CURLOPT_FILETIME, TRUE);
5249 my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
5250 my_setopt(curl, CURLOPT_CRLF, config->crlf);
5251 my_setopt(curl, CURLOPT_QUOTE, config->quote);
5252 my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
5253 my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
5254 my_setopt(curl, CURLOPT_HEADERDATA,
5255 config->headerfile?&heads:NULL);
5256 my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
5257 /* cookie jar was added in 7.9 */
5258 if(config->cookiejar)
5259 my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
5260 /* cookie session added in 7.9.7 */
5261 my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
5263 my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
5264 my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
5265 my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
5266 my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
5267 my_setopt(curl, CURLOPT_STDERR, config->errors);
5269 /* three new ones in libcurl 7.3: */
5270 my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
5271 my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
5272 my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
5274 progressbarinit(&progressbar, config);
5275 if((config->progressmode == CURL_PROGRESS_BAR) &&
5276 !config->noprogress && !config->mute) {
5277 /* we want the alternative style, then we have to implement it
5279 my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
5280 my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
5283 /* new in libcurl 7.6.2: */
5284 my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
5286 /* new in libcurl 7.7: */
5287 my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
5288 my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
5289 my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
5291 if(config->cipher_list)
5292 my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
5294 if(config->httpversion)
5295 my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
5297 /* new in libcurl 7.9.2: */
5298 if(config->disable_epsv)
5300 my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
5302 /* new in libcurl 7.10.5 */
5303 if(config->disable_eprt)
5305 my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
5307 /* new in libcurl 7.10.6 (default is Basic) */
5308 if(config->authtype)
5309 my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
5311 if(config->tracetype != TRACE_NONE) {
5312 my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
5313 my_setopt(curl, CURLOPT_DEBUGDATA, config);
5314 my_setopt(curl, CURLOPT_VERBOSE, TRUE);
5319 /* new in curl ?? */
5320 if(config->engine) {
5321 res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
5322 my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
5328 /* new in curl 7.10 */
5329 my_setopt_str(curl, CURLOPT_ENCODING,
5330 (config->encoding) ? "" : NULL);
5332 /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
5333 my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
5334 config->ftp_create_dirs);
5335 if(config->proxyanyauth)
5336 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
5337 else if(config->proxynegotiate)
5338 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
5339 else if(config->proxyntlm)
5340 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
5341 else if(config->proxydigest)
5342 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
5343 else if(config->proxybasic)
5344 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
5346 /* new in curl 7.10.8 */
5347 if(config->max_filesize)
5348 my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
5349 config->max_filesize);
5351 if(4 == config->ip_version)
5352 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
5353 else if(6 == config->ip_version)
5354 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
5356 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
5358 /* new in curl 7.15.5 */
5359 if(config->ftp_ssl_reqd)
5360 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
5362 /* new in curl 7.11.0 */
5363 else if(config->ftp_ssl)
5364 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
5366 /* new in curl 7.16.0 */
5367 else if(config->ftp_ssl_control)
5368 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
5370 /* new in curl 7.16.1 */
5371 if(config->ftp_ssl_ccc)
5372 my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
5374 /* new in curl 7.11.1, modified in 7.15.2 */
5375 if(config->socksproxy) {
5376 my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
5377 my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
5380 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
5381 /* new in curl 7.19.4 */
5382 if(config->socks5_gssapi_service)
5383 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
5384 config->socks5_gssapi_service);
5386 /* new in curl 7.19.4 */
5387 if(config->socks5_gssapi_nec)
5388 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
5389 config->socks5_gssapi_nec);
5392 my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
5394 my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
5397 my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
5400 my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
5403 if(config->localport) {
5404 my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
5405 my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
5406 config->localportrange);
5410 my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
5411 config->ftp_alternative_to_user);
5414 if(config->disable_sessionid)
5415 my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
5416 !config->disable_sessionid);
5420 my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
5421 my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
5425 if(!config->nokeepalive) {
5426 my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
5427 my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
5430 /* curl 7.19.1 (the 301 version existed in 7.18.2) */
5431 my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
5432 (config->post302 ? CURL_REDIR_POST_302 : FALSE));
5435 if(config->tftp_blksize)
5436 my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
5438 if(config->mail_from)
5439 my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
5441 if(config->mail_rcpt)
5442 my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
5445 if(config->ftp_pret)
5446 my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
5448 if(config->proto_present)
5449 my_setopt(curl, CURLOPT_PROTOCOLS, config->proto);
5450 if(config->proto_redir_present)
5451 my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
5453 if((urlnode->flags & GETOUT_USEREMOTE)
5454 && config->content_disposition) {
5455 my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
5456 my_setopt(curl, CURLOPT_HEADERDATA, &outs);
5461 my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
5463 retry_numretries = config->req_retry;
5465 retrystart = cutil_tvnow();
5468 res = curl_easy_perform(curl);
5469 if(!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
5470 res = CURLE_OUT_OF_MEMORY;
5474 if(config->content_disposition && outs.stream && !config->mute &&
5476 printf("curl: Saved to filename '%s'\n", outs.filename);
5478 /* if retry-max-time is non-zero, make sure we haven't exceeded the
5480 if(retry_numretries &&
5481 (!config->retry_maxtime ||
5482 (cutil_tvdiff(cutil_tvnow(), retrystart)<
5483 config->retry_maxtime*1000)) ) {
5489 RETRY_LAST /* not used */
5492 if(CURLE_OPERATION_TIMEDOUT == res)
5493 /* retry timeout always */
5494 retry = RETRY_TIMEOUT;
5495 else if((CURLE_OK == res) ||
5496 (config->failonerror &&
5497 (CURLE_HTTP_RETURNED_ERROR == res))) {
5498 /* If it returned OK. _or_ failonerror was enabled and it
5499 returned due to such an error, check for HTTP transient
5500 errors to retry on. */
5501 char *this_url=NULL;
5502 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url);
5504 checkprefix("http", this_url)) {
5505 /* This was HTTP(S) */
5506 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5509 case 500: /* Internal Server Error */
5510 case 502: /* Bad Gateway */
5511 case 503: /* Service Unavailable */
5512 case 504: /* Gateway Timeout */
5515 * At this point, we have already written data to the output
5516 * file (or terminal). If we write to a file, we must rewind
5517 * or close/re-open the file so that the next attempt starts
5518 * over from the beginning.
5520 * TODO: similar action for the upload case. We might need
5521 * to start over reading from a previous point if we have
5522 * uploaded something when this was returned.
5529 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5531 if(response/100 == 4)
5533 * This is typically when the FTP server only allows a certain
5534 * amount of users and we are not one of them. All 4xx codes
5541 static const char * const m[]={
5542 NULL, "timeout", "HTTP error", "FTP error"
5544 warnf(config, "Transient problem: %s "
5545 "Will retry in %ld seconds. "
5546 "%ld retries left.\n",
5547 m[retry], retry_sleep/1000, retry_numretries);
5549 go_sleep(retry_sleep);
5551 if(!config->retry_delay) {
5553 if(retry_sleep > RETRY_SLEEP_MAX)
5554 retry_sleep = RETRY_SLEEP_MAX;
5556 if(outs.bytes && outs.filename) {
5557 /* We have written data to a output file, we truncate file
5560 fprintf(config->errors, "Throwing away %"
5561 CURL_FORMAT_CURL_OFF_T " bytes\n",
5563 fflush(outs.stream);
5564 /* truncate file at the position where we started appending */
5565 #ifdef HAVE_FTRUNCATE
5566 if(ftruncate( fileno(outs.stream), outs.init)) {
5567 /* when truncate fails, we can't just append as then we'll
5568 create something strange, bail out */
5570 fprintf(config->errors,
5571 "failed to truncate, exiting\n");
5574 /* now seek to the end of the file, the position where we
5575 just truncated the file in a large file-safe way */
5576 fseek(outs.stream, 0, SEEK_END);
5578 /* ftruncate is not available, so just reposition the file
5579 to the location we would have truncated it. This won't
5580 work properly with large files on 32-bit systems, but
5581 most of those will have ftruncate. */
5582 fseek(outs.stream, (long)outs.init, SEEK_SET);
5584 outs.bytes = 0; /* clear for next round */
5588 } /* if retry_numretries */
5590 /* In all ordinary cases, just break out of loop here */
5591 retry_sleep = retry_sleep_default;
5596 if((config->progressmode == CURL_PROGRESS_BAR) &&
5598 /* if the custom progress bar has been displayed, we output a
5600 fputs("\n", progressbar.out);
5602 if(config->writeout)
5603 ourWriteOut(curl, config->writeout);
5604 #ifdef USE_ENVIRONMENT
5605 if(config->writeenv)
5612 if(is_vms_shell()) {
5613 /* VMS DCL shell behavior */
5614 if(!config->showerror) {
5615 vms_show = VMSSTS_HIDE;
5621 if((res!=CURLE_OK) && config->showerror) {
5622 fprintf(config->errors, "curl: (%d) %s\n", res,
5623 errorbuffer[0]? errorbuffer:
5624 curl_easy_strerror((CURLcode)res));
5625 if(CURLE_SSL_CACERT == res) {
5626 #define CURL_CA_CERT_ERRORMSG1 \
5627 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
5628 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
5629 " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
5630 " bundle file isn't adequate, you can specify an alternate file\n" \
5631 " using the --cacert option.\n"
5633 #define CURL_CA_CERT_ERRORMSG2 \
5634 "If this HTTPS server uses a certificate signed by a CA represented in\n" \
5635 " the bundle, the certificate verification probably failed due to a\n" \
5636 " problem with the certificate (it might be expired, or the name might\n" \
5637 " not match the domain name in the URL).\n" \
5638 "If you'd like to turn off curl's verification of the certificate, use\n" \
5639 " the -k (or --insecure) option.\n"
5641 fprintf(config->errors, "%s%s",
5642 CURL_CA_CERT_ERRORMSG1,
5643 CURL_CA_CERT_ERRORMSG2 );
5647 if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
5651 rc = fwrite_xattr(curl, fileno(outs.stream) );
5653 warnf(config, "Error setting extended attributes: %s\n",
5657 rc = fclose(outs.stream);
5659 /* something went wrong in the writing process */
5660 res = CURLE_WRITE_ERROR;
5661 fprintf(config->errors, "(%d) Failed writing body\n", res);
5666 /* Important that we set the time _after_ the file has been
5667 closed, as is done above here */
5668 if(config->remote_time && outs.filename) {
5669 /* ask libcurl if we got a time. Pretty please */
5671 curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
5673 struct utimbuf times;
5674 times.actime = (time_t)filetime;
5675 times.modtime = (time_t)filetime;
5676 utime(outs.filename, ×); /* set the time we got */
5681 /* Set the url as comment for the file. (up to 80 chars are allowed)
5683 if( strlen(url) > 78 )
5686 SetComment( outs.filename, url);
5699 } /* loop to the next URL */
5702 /* cleanup memory used for URL globbing patterns */
5710 } /* loop to the next globbed upload file */
5713 glob_cleanup(inglob);
5720 /* empty this urlnode struct */
5723 if(urlnode->outfile)
5724 free(urlnode->outfile);
5726 free(urlnode->infile);
5728 /* move on to the next URL */
5729 nextnode=urlnode->next;
5730 free(urlnode); /* free the node */
5733 } /* while-loop through all URLs */
5737 free(httpgetfields);
5740 free(config->engine);
5742 /* cleanup the curl handle! */
5743 curl_easy_cleanup(curl);
5744 config->easy = NULL; /* cleanup now */
5746 curl_slist_append(easycode, "curl_easy_cleanup(hnd);");
5748 if(heads.stream && (heads.stream != stdout))
5749 fclose(heads.stream);
5752 free(config->useragent);
5754 if(config->trace_fopened && config->trace_stream)
5755 fclose(config->trace_stream);
5757 /* Dump the libcurl code if previously enabled.
5758 NOTE: that this function relies on config->errors amongst other things
5759 so not everything can be closed and cleaned before this is called */
5760 dumpeasycode(config);
5762 if(config->errors_fopened)
5763 fclose(config->errors);
5765 main_free(); /* cleanup */
5770 /* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
5771 open before starting to run. Otherwise, the first three network
5772 sockets opened by curl could be used for input sources, downloaded data
5773 or error logs as they will effectively be stdin, stdout and/or stderr.
5775 static void checkfds(void)
5778 int fd[2] = { STDIN_FILENO, STDIN_FILENO };
5779 while( fd[0] == STDIN_FILENO ||
5780 fd[0] == STDOUT_FILENO ||
5781 fd[0] == STDERR_FILENO ||
5782 fd[1] == STDIN_FILENO ||
5783 fd[1] == STDOUT_FILENO ||
5784 fd[1] == STDERR_FILENO )
5786 return; /* Out of handles. This isn't really a big problem now, but
5787 will be when we try to create a socket later. */
5795 int main(int argc, char *argv[])
5798 struct Configurable config;
5800 memset(&config, 0, sizeof(struct Configurable));
5802 config.errors = stderr; /* default errors to stderr */
5806 res = operate(&config, argc, argv);
5807 #ifdef __SYMBIAN32__
5808 if(config.showerror)
5811 free_config_fields(&config);
5813 #ifdef __NOVELL_LIBC__
5814 if(getenv("_IN_NETWARE_BASH_") == NULL)
5818 vms_special_exit(res, vms_show);
5825 * Reads a line from the given file, ensuring is NUL terminated.
5826 * The pointer must be freed by the caller.
5827 * NULL is returned on an out of memory condition.
5829 static char *my_get_line(FILE *fp)
5833 char *retval = NULL;
5836 if(NULL == fgets(buf, sizeof(buf), fp))
5838 if(NULL == retval) {
5839 retval = strdup(buf);
5845 ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
5851 strcat(retval, buf);
5854 while(NULL == (nl = strchr(retval, '\n')));
5862 static void show_dir_errno(FILE *errors, const char *name)
5867 fprintf(errors,"You don't have permission to create %s.\n", name);
5872 fprintf(errors,"The directory name %s is too long.\n", name);
5877 fprintf(errors,"%s resides on a read-only file system.\n", name);
5882 fprintf(errors,"No space left on the file system that will "
5883 "contain the directory %s.\n", name);
5888 fprintf(errors,"Cannot create directory %s because you "
5889 "exceeded your quota.\n", name);
5893 fprintf(errors,"Error creating directory %s.\n", name);
5898 /* Create the needed directory hierarchy recursively in order to save
5899 multi-GETs in file output, ie:
5900 curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
5901 should create all the dir* automagically
5903 static int create_dir_hierarchy(const char *outfile, FILE *errors)
5911 outdup = strdup(outfile);
5915 dirbuildup = malloc(sizeof(char) * strlen(outfile));
5920 dirbuildup[0] = '\0';
5922 tempdir = strtok(outdup, DIR_CHAR);
5924 while(tempdir != NULL) {
5925 tempdir2 = strtok(NULL, DIR_CHAR);
5926 /* since strtok returns a token for the last word even
5927 if not ending with DIR_CHAR, we need to prune it */
5928 if(tempdir2 != NULL) {
5929 size_t dlen = strlen(dirbuildup);
5931 sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
5933 if(0 != strncmp(outdup, DIR_CHAR, 1))
5934 strcpy(dirbuildup, tempdir);
5936 sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
5938 if(access(dirbuildup, F_OK) == -1) {
5939 result = mkdir(dirbuildup,(mode_t)0000750);
5941 show_dir_errno(errors, dirbuildup);
5942 break; /* get out of loop */
5951 return result; /* 0 is fine, -1 is badness */
5954 #if defined(MSDOS) || defined(WIN32)
5956 #ifndef HAVE_BASENAME
5957 /* basename() returns a pointer to the last component of a pathname.
5958 * Ripped from lib/formdata.c.
5960 static char *Curl_basename(char *path)
5962 /* Ignore all the details above for now and make a quick and simple
5963 implementaion here */
5967 s1=strrchr(path, '/');
5968 s2=strrchr(path, '\\');
5971 path = (s1 > s2? s1 : s2)+1;
5980 #define basename(x) Curl_basename((x))
5981 #endif /* HAVE_BASENAME */
5983 /* The following functions are taken with modification from the DJGPP
5984 * port of tar 1.12. They use algorithms originally from DJTAR. */
5987 msdosify (const char *file_name)
5989 static char dos_name[PATH_MAX];
5990 static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
5991 "|<>\\\":?*"; /* illegal in DOS & W95 */
5992 static const char *illegal_chars_w95 = &illegal_chars_dos[8];
5994 const char *s = file_name;
5996 const char * const dlimit = dos_name + sizeof(dos_name) - 1;
5997 const char *illegal_aliens = illegal_chars_dos;
5998 size_t len = sizeof (illegal_chars_dos) - 1;
6000 /* Support for Windows 9X VFAT systems, when available. */
6001 if(_use_lfn (file_name)) {
6002 illegal_aliens = illegal_chars_w95;
6003 len -= (illegal_chars_w95 - illegal_chars_dos);
6006 /* Get past the drive letter, if any. */
6007 if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
6012 for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
6013 if(memchr (illegal_aliens, *s, len)) {
6014 /* Dots are special: DOS doesn't allow them as the leading character,
6015 and a file name cannot have more than a single dot. We leave the
6016 first non-leading dot alone, unless it comes too close to the
6017 beginning of the name: we want sh.lex.c to become sh_lex.c, not
6020 if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
6021 /* Copy "./" and "../" verbatim. */
6029 else if(dot_idx >= 0) {
6030 if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
6031 d[dot_idx - idx] = '_'; /* replace previous dot */
6043 else if(*s == '+' && s[1] == '+') {
6044 if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
6050 memcpy (d, "plus", 4);
6074 rename_if_dos_device_name (char *file_name)
6076 /* We could have a file whose name is a device on MS-DOS. Trying to
6077 * retrieve such a file would fail at best and wedge us at worst. We need
6078 * to rename such files. */
6081 char fname[PATH_MAX];
6083 strncpy(fname, file_name, PATH_MAX-1);
6084 fname[PATH_MAX-1] = 0;
6085 base = basename(fname);
6086 if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
6087 size_t blen = strlen (base);
6089 if(strlen(fname) >= PATH_MAX-1) {
6090 /* Make room for the '_' */
6094 /* Prepend a '_'. */
6095 memmove (base + 1, base, blen + 1);
6097 strcpy (file_name, fname);
6102 /* Replace bad characters in the file name before using it.
6103 * fn will always be freed before return
6104 * The returned pointer must be freed by the caller if not NULL
6106 static char *sanitize_dos_name(char *fn)
6108 char tmpfn[PATH_MAX];
6109 if(strlen(fn) >= PATH_MAX)
6110 fn[PATH_MAX-1]=0; /* truncate it */
6111 strcpy(tmpfn, msdosify(fn));
6113 return strdup(rename_if_dos_device_name(tmpfn));
6115 #endif /* MSDOS || WIN32 */