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
54 #define CURLseparator "--_curl_--"
57 #ifdef __NOVELL_LIBC__
61 #define mkdir mkdir_510
67 #ifdef HAVE_IO_H /* typical win32 habit */
82 #ifdef HAVE_SYS_UTIME_H
83 #include <sys/utime.h>
86 #endif /* HAVE_UTIME_H */
92 #ifdef HAVE_SYS_POLL_H
94 #elif defined(HAVE_POLL_H)
99 #include <locale.h> /* for setlocale() */
102 #define ENABLE_CURLX_PRINTF
103 /* make the curlx header define all printf() functions to use the curlx_*
105 #include "curlx.h" /* header from the libcurl directory */
107 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
109 /* set default codesets for iconv */
110 #ifndef CURL_ICONV_CODESET_OF_NETWORK
111 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
113 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
115 #ifdef HAVE_NETINET_IN_H
116 #include <netinet/in.h> /* for IPPROTO_TCP */
118 #ifdef HAVE_NETINET_TCP_H
119 #include <netinet/tcp.h> /* for TCP_KEEPIDLE, TCP_KEEPINTVL */
122 #include "os-specific.h"
124 /* The last #include file should be: */
126 #ifndef CURLTOOLDEBUG
127 #define MEMDEBUG_NODEFINES
129 /* This is low-level hard-hacking memory leak tracking and similar. Using
130 the library level code from this client-side is ugly, but we do this
131 anyway for convenience. */
132 #include "memdebug.h"
136 static int vms_show = 0;
140 #define PRINT_LINES_PAUSE 23
143 #if defined(__SYMBIAN32__)
144 #define PRINT_LINES_PAUSE 16
145 #define pressanykey() getchar()
148 #define DEFAULT_MAXREDIRS 50L
150 #if defined(O_BINARY) && defined(HAVE_SETMODE)
152 #define SET_BINMODE(file) _setmode(file,O_BINARY)
154 #define SET_BINMODE(file) setmode(fileno(file),O_BINARY)
157 #define SET_BINMODE(file) ((void)0)
161 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
162 source code but yet it doesn't ruin anything */
166 #if defined(MSDOS) || defined(WIN32)
168 static const char *msdosify(const char *);
169 static char *rename_if_dos_device_name(char *);
170 static char *sanitize_dos_name(char *);
174 # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
176 # define S_ISCHR(m) (0) /* cannot tell if file is a device */
181 # define _use_lfn(f) (1) /* long file names always available */
182 #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
183 # define _use_lfn(f) (0) /* long file names never available */
186 #endif /* MSDOS || WIN32 */
193 /* we want to glob our own argv[] */
194 char **__crt0_glob_function (char *arg)
199 #endif /* __DJGPP__ */
203 #define STDIN_FILENO fileno(stdin)
206 #ifndef STDOUT_FILENO
207 #define STDOUT_FILENO fileno(stdout)
210 #ifndef STDERR_FILENO
211 #define STDERR_FILENO fileno(stderr)
214 #define CURL_PROGRESS_STATS 0 /* default progress display */
215 #define CURL_PROGRESS_BAR 1
228 * Large file support (>2Gb) using WIN32 functions.
231 #ifdef USE_WIN32_LARGE_FILES
233 # include <sys/types.h>
234 # include <sys/stat.h>
235 # define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
236 # define fstat(fdes,stp) _fstati64(fdes, stp)
237 # define stat(fname,stp) _stati64(fname, stp)
238 # define struct_stat struct _stati64
239 # define LSEEK_ERROR (__int64)-1
243 * Small file support (<2Gb) using WIN32 functions.
246 #ifdef USE_WIN32_SMALL_FILES
248 # include <sys/types.h>
249 # include <sys/stat.h>
250 # define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
251 # define fstat(fdes,stp) _fstat(fdes, stp)
252 # define stat(fname,stp) _stat(fname, stp)
253 # define struct_stat struct _stat
254 # define LSEEK_ERROR (long)-1
258 # define struct_stat struct stat
262 # define LSEEK_ERROR (off_t)-1
267 # define mkdir(x,y) (mkdir)(x)
269 # define PATH_MAX MAX_PATH
276 * Default sizeof(off_t) in case it hasn't been defined in config file.
280 # if defined(__VMS) && !defined(__VAX)
281 # if defined(_LARGEFILE)
282 # define SIZEOF_OFF_T 8
284 # elif defined(__OS400__) && defined(__ILEC400__)
285 # if defined(_LARGE_FILES)
286 # define SIZEOF_OFF_T 8
288 # elif defined(__MVS__) && defined(__IBMC__)
289 # if defined(_LP64) || defined(_LARGE_FILES)
290 # define SIZEOF_OFF_T 8
292 # elif defined(__370__) && defined(__IBMC__)
293 # if defined(_LP64) || defined(_LARGE_FILES)
294 # define SIZEOF_OFF_T 8
297 # define SIZEOF_OFF_T 8
299 # ifndef SIZEOF_OFF_T
300 # define SIZEOF_OFF_T 4
304 #ifdef CURL_DOES_CONVERSIONS
306 iconv_t inbound_cd = (iconv_t)-1;
307 iconv_t outbound_cd = (iconv_t)-1;
310 * convert_to_network() is an internal function to convert
311 * from the host encoding to ASCII on non-ASCII platforms.
314 convert_to_network(char *buffer, size_t length)
318 /* translate from the host encoding to the network encoding */
319 char *input_ptr, *output_ptr;
320 size_t in_bytes, out_bytes;
322 /* open an iconv conversion descriptor if necessary */
323 if(outbound_cd == (iconv_t)-1) {
324 outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
325 CURL_ICONV_CODESET_OF_HOST);
326 if(outbound_cd == (iconv_t)-1) {
327 return CURLE_CONV_FAILED;
331 input_ptr = output_ptr = buffer;
332 in_bytes = out_bytes = length;
333 rc = iconv(outbound_cd, &input_ptr, &in_bytes,
334 &output_ptr, &out_bytes);
335 if ((rc == -1) || (in_bytes != 0)) {
336 return CURLE_CONV_FAILED;
343 * convert_from_network() is an internal function
344 * for performing ASCII conversions on non-ASCII platforms.
347 convert_from_network(char *buffer, size_t length)
351 /* translate from the network encoding to the host encoding */
352 char *input_ptr, *output_ptr;
353 size_t in_bytes, out_bytes;
355 /* open an iconv conversion descriptor if necessary */
356 if(inbound_cd == (iconv_t)-1) {
357 inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
358 CURL_ICONV_CODESET_OF_NETWORK);
359 if(inbound_cd == (iconv_t)-1) {
360 return CURLE_CONV_FAILED;
364 input_ptr = output_ptr = buffer;
365 in_bytes = out_bytes = length;
366 rc = iconv(inbound_cd, &input_ptr, &in_bytes,
367 &output_ptr, &out_bytes);
368 if ((rc == -1) || (in_bytes != 0)) {
369 return CURLE_CONV_FAILED;
374 #endif /* HAVE_ICONV */
377 char convert_char(curl_infotype infotype, char this_char)
379 /* determine how this specific character should be displayed */
381 case CURLINFO_DATA_IN:
382 case CURLINFO_DATA_OUT:
383 case CURLINFO_SSL_DATA_IN:
384 case CURLINFO_SSL_DATA_OUT:
385 /* data, treat as ASCII */
386 if ((this_char >= 0x20) && (this_char < 0x7f)) {
387 /* printable ASCII hex value: convert to host encoding */
388 convert_from_network(&this_char, 1);
391 /* non-printable ASCII, use a replacement character */
392 return UNPRINTABLE_CHAR;
394 /* fall through to default */
396 /* treat as host encoding */
397 if (ISPRINT(this_char)
398 && (this_char != '\t')
399 && (this_char != '\r')
400 && (this_char != '\n')) {
401 /* printable characters excluding tabs and line end characters */
406 /* non-printable, use a replacement character */
407 return UNPRINTABLE_CHAR;
409 #endif /* CURL_DOES_CONVERSIONS */
414 /* 64-bit lseek-like function unavailable */
415 # define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
419 # if (__POCC__ < 450)
420 /* 64-bit lseek-like function unavailable */
421 # define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
423 # define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
427 #ifndef HAVE_FTRUNCATE
428 #define HAVE_FTRUNCATE 1
432 * Truncate a file handle at a 64-bit position 'where'.
435 static int ftruncate64 (int fd, curl_off_t where)
437 if(_lseeki64(fd, where, SEEK_SET) < 0)
440 if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
445 #define ftruncate(fd,where) ftruncate64(fd,where)
450 TRACE_NONE, /* no trace/verbose output at all! */
451 TRACE_BIN, /* tcpdump inspired look */
452 TRACE_ASCII, /* like *BIN but without the hex output */
453 TRACE_PLAIN /* -v/--verbose type */
459 struct Configurable *config;
460 curl_off_t bytes; /* amount written so far */
461 curl_off_t init; /* original size (non-zero when appending) */
464 struct Configurable {
465 CURL *easy; /* once we have one, we keep it here */
470 char *cookie; /* single line with specified cookies */
471 char *cookiejar; /* write to this file */
472 char *cookiefile; /* read from this file */
473 bool cookiesession; /* new session? */
474 bool encoding; /* Accept-Encoding please */
475 long authtype; /* auth bitmask */
477 bool resume_from_current;
484 bool proto_redir_present;
485 curl_off_t resume_from;
487 curl_off_t postfieldsize;
492 curl_off_t max_filesize;
498 unsigned short porttouse;
500 long low_speed_limit;
506 int proxyver; /* set to CURLPROXY_HTTP* define */
509 struct curl_slist *mail_rcpt;
511 bool ftp_append; /* APPE on ftp */
512 bool mute; /* shutup */
513 bool use_ascii; /* select ascii or text transfer */
514 bool autoreferer; /* automatically set referer */
515 bool failonerror; /* fail on (HTTP) errors */
516 bool include_headers; /* send headers to data output */
517 bool no_body; /* don't get the body */
518 bool dirlistonly; /* only get the FTP dir list */
519 bool followlocation; /* follow http redirects */
520 bool unrestricted_auth; /* Continue to send authentication (user+password)
521 when following ocations, even when hostname
526 bool isatty; /* updated internally only if the output is a tty */
527 struct getout *url_list; /* point to the first node */
528 struct getout *url_last; /* point to the last/current node */
529 struct getout *url_get; /* point to the node to fill in URL */
530 struct getout *url_out; /* point to the node to fill in outfile */
547 char *trace_dump; /* file to dump the network trace to, or NULL */
551 bool tracetime; /* include timestamp? */
555 bool readbusy; /* set when reading input returns EAGAIN */
558 bool insecure_ok; /* set TRUE to allow insecure SSL connects */
560 bool ftp_create_dirs;
567 char *writeout; /* %-styled format string to output */
568 bool writeenv; /* write results to environment, if available */
569 FILE *errors; /* if stderr redirect is requested */
571 struct curl_slist *quote;
572 struct curl_slist *postquote;
573 struct curl_slist *prequote;
576 curl_TimeCond timecond;
578 struct curl_slist *headers;
579 struct curl_httppost *httppost;
580 struct curl_httppost *last_post;
581 struct curl_slist *telnet_options;
584 /* for bandwidth limiting features: */
585 curl_off_t sendpersecond; /* send to peer */
586 curl_off_t recvpersecond; /* receive from peer */
590 bool ftp_ssl_control;
592 int ftp_ssl_ccc_mode;
594 char *socksproxy; /* set to server string */
595 int socksver; /* set to CURLPROXY_SOCKS* define */
596 char *socks5_gssapi_service; /* set service name for gssapi principal
598 int socks5_gssapi_nec ; /* The NEC reference server does not protect
599 * the encryption type exchange */
602 long req_retry; /* number of retries */
603 long retry_delay; /* delay between retries (in seconds) */
604 long retry_maxtime; /* maximum time to keep retrying */
606 char *ftp_account; /* for ACCT */
607 char *ftp_alternative_to_user; /* send command if USER/PASS fails */
609 long tftp_blksize; /* TFTP BLKSIZE option */
610 bool ignorecl; /* --ignore-content-length */
611 bool disable_sessionid;
613 char *libcurl; /* output libcurl code to this file name */
617 bool nokeepalive; /* for keepalive needs */
619 bool content_disposition; /* use Content-disposition filename */
621 int default_node_flags; /* default flags to seach for each 'node', which is
622 basically each given URL to transfer */
623 struct OutStruct *outs;
626 #define WARN_PREFIX "Warning: "
627 #define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
628 /* produce this text message to the user unless mute was selected */
629 static void warnf(struct Configurable *config, const char *fmt, ...)
635 char print_buffer[256];
638 len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
643 fputs(WARN_PREFIX, config->errors);
645 if(len > (int)WARN_TEXTWIDTH) {
646 int cut = WARN_TEXTWIDTH-1;
648 while(!ISSPACE(ptr[cut]) && cut) {
652 /* not a single cutting position was found, just cut it at the
653 max text width then! */
654 cut = WARN_TEXTWIDTH-1;
656 (void)fwrite(ptr, cut + 1, 1, config->errors);
657 fputs("\n", config->errors);
658 ptr += cut+1; /* skip the space too */
662 fputs(ptr, config->errors);
670 * This is the main global constructor for the app. Call this before
671 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
672 * used, or havoc may be the result.
674 static CURLcode main_init(void)
677 /* stop stat() wasting time */
678 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
681 return curl_global_init(CURL_GLOBAL_DEFAULT);
685 * This is the main global destructor for the app. Call this after
686 * _all_ libcurl usage is done.
688 static void main_free(void)
690 curl_global_cleanup();
691 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
692 /* close iconv conversion descriptor */
693 if(inbound_cd != (iconv_t)-1)
694 iconv_close(inbound_cd);
695 if(outbound_cd != (iconv_t)-1)
696 iconv_close(outbound_cd);
697 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
700 static int SetHTTPrequest(struct Configurable *config,
701 HttpReq req, HttpReq *store)
703 if((*store == HTTPREQ_UNSPEC) ||
708 warnf(config, "You can only select one HTTP request!\n");
712 static void helpf(FILE *errors, const char *fmt, ...)
717 fputs("curl: ", errors); /* prefix it */
718 vfprintf(errors, fmt, ap);
721 fprintf(errors, "curl: try 'curl --help' "
723 "or 'curl --manual' "
725 "for more information\n");
729 * A chain of these nodes contain URL to get and where to put the URL's
733 struct getout *next; /* next one */
734 char *url; /* the URL we deal with */
735 char *outfile; /* where to store the output */
736 char *infile; /* file to upload, if GETOUT_UPLOAD is set */
737 int flags; /* options */
739 #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
740 #define GETOUT_URL (1<<1) /* set when URL is deemed done */
741 #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
742 #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
743 #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
745 static void help(void)
748 /* A few of these source lines are >80 columns wide, but that's only because
749 breaking the strings narrower makes this chunk look even worse!
751 Starting with 7.18.0, this list of command line options is sorted based
752 on the long option name. It is not done automatically, although a command
753 line like the following can help out:
755 curl --help | cut -c5- | grep "^-" | sort
757 static const char * const helptext[]={
758 "Usage: curl [options...] <url>",
759 "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
760 " --anyauth Pick \"any\" authentication method (H)",
761 " -a/--append Append to target file when uploading (F/SFTP)",
762 " --basic Use HTTP Basic Authentication (H)",
763 " --cacert <file> CA certificate to verify peer against (SSL)",
764 " --capath <directory> CA directory to verify peer against (SSL)",
765 " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
766 " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
767 " --ciphers <list> SSL ciphers to use (SSL)",
768 " --compressed Request compressed response (using deflate or gzip)",
769 " -K/--config <file> Specify which config file to read",
770 " --connect-timeout <seconds> Maximum time allowed for connection",
771 " -C/--continue-at <offset> Resumed transfer offset",
772 " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
773 " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
774 " --create-dirs Create necessary local directory hierarchy",
775 " --crlf Convert LF to CRLF in upload",
776 " --crlfile <file> Get a CRL list in PEM format from the given file",
777 " -d/--data <data> HTTP POST data (H)",
778 " --data-ascii <data> HTTP POST ASCII data (H)",
779 " --data-binary <data> HTTP POST binary data (H)",
780 " --data-urlencode <name=data/name@filename> HTTP POST data url encoded (H)",
781 " --digest Use HTTP Digest Authentication (H)",
782 " --disable-eprt Inhibit using EPRT or LPRT (F)",
783 " --disable-epsv Inhibit using EPSV (F)",
784 " -D/--dump-header <file> Write the headers to this file",
785 " --egd-file <file> EGD socket path for random data (SSL)",
786 " --engine <eng> Crypto engine to use (SSL). \"--engine list\" for list",
787 #ifdef USE_ENVIRONMENT
788 " --environment Write results to environment variables (RISC OS)",
790 " -f/--fail Fail silently (no output at all) on HTTP errors (H)",
791 " -F/--form <name=content> Specify HTTP multipart POST data (H)",
792 " --form-string <name=string> Specify HTTP multipart POST data (H)",
793 " --ftp-account <data> Account data to send when requested by server (F)",
794 " --ftp-alternative-to-user <cmd> String to replace \"USER [name]\" (F)",
795 " --ftp-create-dirs Create the remote dirs if not present (F)",
796 " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
797 " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
798 " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
799 " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
800 " --ftp-pret Send PRET before PASV (for drftpd) (F)",
801 " --ftp-ssl-ccc Send CCC after authenticating (F)",
802 " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
803 " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
804 " -G/--get Send the -d data with a HTTP GET (H)",
805 " -g/--globoff Disable URL sequences and ranges using {} and []",
806 " -H/--header <line> Custom header to pass to server (H)",
807 " -I/--head Show document info only",
808 " -h/--help This help text",
809 " --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
810 " -0/--http1.0 Use HTTP 1.0 (H)",
811 " --ignore-content-length Ignore the HTTP Content-Length header",
812 " -i/--include Include protocol headers in the output (H/F)",
813 " -k/--insecure Allow connections to SSL sites without certs (H)",
814 " --interface <interface> Specify network interface/address to use",
815 " -4/--ipv4 Resolve name to IPv4 address",
816 " -6/--ipv6 Resolve name to IPv6 address",
817 " -j/--junk-session-cookies Ignore session cookies read from file (H)",
818 " --keepalive-time <seconds> Interval between keepalive probes",
819 " --key <key> Private key file name (SSL/SSH)",
820 " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
821 " --krb <level> Enable Kerberos with specified security level (F)",
822 " --libcurl <file> Dump libcurl equivalent code of this command line",
823 " --limit-rate <rate> Limit transfer speed to this rate",
824 " -J/--remote-header-name Use the header-provided filename (H)",
825 " -l/--list-only List only names of an FTP directory (F)",
826 " --local-port <num>[-num] Force use of these local port numbers",
827 " -L/--location Follow Location: hints (H)",
828 " --location-trusted Follow Location: and send auth to other hosts (H)",
829 " -M/--manual Display the full manual",
830 " --mail-from <from> Mail from this address",
831 " --mail-rcpt <to> Mail to this receiver(s)",
832 " --max-filesize <bytes> Maximum file size to download (H/F)",
833 " --max-redirs <num> Maximum number of redirects allowed (H)",
834 " -m/--max-time <seconds> Maximum time allowed for the transfer",
835 " --negotiate Use HTTP Negotiate Authentication (H)",
836 " -n/--netrc Must read .netrc for user name and password",
837 " --netrc-optional Use either .netrc or URL; overrides -n",
838 " -N/--no-buffer Disable buffering of the output stream",
839 " --no-keepalive Disable keepalive use on the connection",
840 " --no-sessionid Disable SSL session-ID reusing (SSL)",
841 " --noproxy Comma-separated list of hosts which do not use proxy",
842 " --ntlm Use HTTP NTLM authentication (H)",
843 " -o/--output <file> Write output to <file> instead of stdout",
844 " --pass <pass> Pass phrase for the private key (SSL/SSH)",
845 " --post301 Do not switch to GET after following a 301 redirect (H)",
846 " --post302 Do not switch to GET after following a 302 redirect (H)",
847 " -#/--progress-bar Display transfer progress as a progress bar",
848 " --proto <protocols> Enable/disable specified protocols",
849 " --proto-redir <protocols> Enable/disable specified protocols on redirect",
850 " -x/--proxy <host[:port]> Use HTTP proxy on given port",
851 " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
852 " --proxy-basic Use Basic authentication on the proxy (H)",
853 " --proxy-digest Use Digest authentication on the proxy (H)",
854 " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
855 " --proxy-ntlm Use NTLM authentication on the proxy (H)",
856 " -U/--proxy-user <user[:password]> Set proxy user and password",
857 " --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port",
858 " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
859 " --pubkey <key> Public key file name (SSH)",
860 " -Q/--quote <cmd> Send command(s) to server before file transfer (F/SFTP)",
861 " --random-file <file> File for reading random data from (SSL)",
862 " -r/--range <range> Retrieve only the bytes within a range",
863 " --raw Pass HTTP \"raw\", without any transfer decoding (H)",
864 " -e/--referer Referer URL (H)",
865 " -O/--remote-name Write output to a file named as the remote file",
866 " --remote-name-all Use the remote file name for all URLs",
867 " -R/--remote-time Set the remote file's time on the local output",
868 " -X/--request <command> Specify request command to use",
869 " --retry <num> Retry request <num> times if transient problems occur",
870 " --retry-delay <seconds> When retrying, wait this many seconds between each",
871 " --retry-max-time <seconds> Retry only within this period",
872 " -S/--show-error Show error. With -s, make curl show errors when they occur",
873 " -s/--silent Silent mode. Don't output anything",
874 " --socks4 <host[:port]> SOCKS4 proxy on given host + port",
875 " --socks4a <host[:port]> SOCKS4a proxy on given host + port",
876 " --socks5 <host[:port]> SOCKS5 proxy on given host + port",
877 " --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy",
878 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
879 " --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi",
880 " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
882 " -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
883 " -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
884 " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
885 " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
886 " -2/--sslv2 Use SSLv2 (SSL)",
887 " -3/--sslv3 Use SSLv3 (SSL)",
888 " --stderr <file> Where to redirect stderr. - means stdout",
889 " --tcp-nodelay Use the TCP_NODELAY option",
890 " -t/--telnet-option <OPT=val> Set telnet option",
891 " --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)",
892 " -z/--time-cond <time> Transfer based on a time condition",
893 " -1/--tlsv1 Use TLSv1 (SSL)",
894 " --trace <file> Write a debug trace to the given file",
895 " --trace-ascii <file> Like --trace but without the hex output",
896 " --trace-time Add time stamps to trace/verbose output",
897 " -T/--upload-file <file> Transfer <file> to remote site",
898 " --url <URL> Set URL to work with",
899 " -B/--use-ascii Use ASCII/text transfer",
900 " -u/--user <user[:password]> Set server user and password",
901 " -A/--user-agent <string> User-Agent to send to server (H)",
902 " -v/--verbose Make the operation more talkative",
903 " -V/--version Show version number and quit",
906 " --wdebug Turn on Watt-32 debugging",
908 " -w/--write-out <format> What to output after completion",
909 " -q If used as the first parameter disables .curlrc",
912 for(i=0; helptext[i]; i++) {
914 #ifdef PRINT_LINES_PAUSE
915 if (i && ((i % PRINT_LINES_PAUSE) == 0))
927 /* global variable to hold info about libcurl */
928 static curl_version_info_data *curlinfo;
930 static int parseconfig(const char *filename,
931 struct Configurable *config);
932 static char *my_get_line(FILE *fp);
933 static int create_dir_hierarchy(const char *outfile, FILE *errors);
935 static void GetStr(char **string,
941 *string = strdup(value);
946 static void clean_getout(struct Configurable *config)
948 struct getout *node=config->url_list;
961 node = next; /* GOTO next */
965 static struct getout *new_getout(struct Configurable *config)
967 struct getout *node =malloc(sizeof(struct getout));
968 struct getout *last= config->url_last;
970 /* clear the struct */
971 memset(node, 0, sizeof(struct getout));
973 /* append this new node last in the list */
977 config->url_list = node; /* first node */
979 /* move the last pointer */
980 config->url_last = node;
982 node->flags = config->default_node_flags;
987 /* Structure for storing the information needed to build a multiple files
991 struct curl_forms form;
992 struct multi_files *next;
995 /* Add a new list entry possibly with a type_name
997 static struct multi_files *
998 AddMultiFiles (const char *file_name,
999 const char *type_name,
1000 const char *show_filename,
1001 struct multi_files **multi_start,
1002 struct multi_files **multi_current)
1004 struct multi_files *multi;
1005 struct multi_files *multi_type = NULL;
1006 struct multi_files *multi_name = NULL;
1007 multi = malloc(sizeof(struct multi_files));
1009 memset(multi, 0, sizeof(struct multi_files));
1010 multi->form.option = CURLFORM_FILE;
1011 multi->form.value = file_name;
1017 *multi_start = multi;
1020 multi_type = malloc(sizeof(struct multi_files));
1022 memset(multi_type, 0, sizeof(struct multi_files));
1023 multi_type->form.option = CURLFORM_CONTENTTYPE;
1024 multi_type->form.value = type_name;
1025 multi->next = multi_type;
1034 if (show_filename) {
1035 multi_name = malloc(sizeof(struct multi_files));
1037 memset(multi_name, 0, sizeof(struct multi_files));
1038 multi_name->form.option = CURLFORM_FILENAME;
1039 multi_name->form.value = show_filename;
1040 multi->next = multi_name;
1051 (*multi_current)->next = multi;
1053 *multi_current = multi;
1055 return *multi_current;
1058 /* Free the items of the list.
1060 static void FreeMultiInfo (struct multi_files *multi_start)
1062 struct multi_files *multi;
1063 while (multi_start) {
1064 multi = multi_start;
1065 multi_start = multi_start->next;
1070 /* Print list of OpenSSL engines supported.
1072 static void list_engines (const struct curl_slist *engines)
1074 puts ("Build-time engines:");
1079 for ( ; engines; engines = engines->next)
1080 printf (" %s\n", engines->data);
1083 /***************************************************************************
1087 * Reads a 'name=value' parameter and builds the appropriate linked list.
1089 * Specify files to upload with 'name=@filename'. Supports specified
1090 * given Content-Type of the files. Such as ';type=<content-type>'.
1092 * If literal_value is set, any initial '@' or '<' in the value string
1093 * loses its special meaning, as does any embedded ';type='.
1095 * You may specify more than one file for a single name (field). Specify
1096 * multiple files by writing it like:
1098 * 'name=@filename,filename2,filename3'
1100 * If you want content-types specified for each too, write them like:
1102 * 'name=@filename;type=image/gif,filename2,filename3'
1104 * If you want custom headers added for a single part, write them in a separate
1105 * file and do like this:
1107 * 'name=foo;headers=@headerfile' or why not
1108 * 'name=@filemame;headers=@headerfile'
1110 * To upload a file, but to fake the file name that will be included in the
1111 * formpost, do like this:
1113 * 'name=@filename;filename=/dev/null'
1115 * This function uses curl_formadd to fulfill it's job. Is heavily based on
1116 * the old curl_formparse code.
1118 ***************************************************************************/
1120 #define FORM_FILE_SEPARATOR ','
1121 #define FORM_TYPE_SEPARATOR ';'
1123 static int formparse(struct Configurable *config,
1125 struct curl_httppost **httppost,
1126 struct curl_httppost **last_post,
1129 /* nextarg MUST be a string in the format 'name=contents' and we'll
1130 build a linked list with the info */
1136 const char *type = NULL;
1140 if((1 == sscanf(input, "%255[^=]=", name)) &&
1141 (contp = strchr(input, '='))) {
1142 /* the input was using the correct format */
1144 /* Allocate the contents */
1145 contents = strdup(contp+1);
1147 fprintf(config->errors, "out of memory\n");
1152 if('@' == contp[0] && !literal_value) {
1153 struct multi_files *multi_start = NULL, *multi_current = NULL;
1154 /* we use the @-letter to indicate file name(s) */
1157 multi_start = multi_current=NULL;
1160 /* since this was a file, it may have a content-type specifier
1161 at the end too, or a filename. Or both. */
1163 char *filename=NULL;
1165 sep=strchr(contp, FORM_TYPE_SEPARATOR);
1166 sep2=strchr(contp, FORM_FILE_SEPARATOR);
1168 /* pick the closest */
1169 if(sep2 && (sep2 < sep)) {
1172 /* no type was specified! */
1179 /* if we got here on a comma, don't do much */
1180 if(FORM_FILE_SEPARATOR == *sep)
1185 *sep=0; /* terminate file name at separator */
1187 while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
1189 /* pass all white spaces */
1190 while(ISSPACE(*ptr))
1193 if(curlx_strnequal("type=", ptr, 5)) {
1194 /* set type pointer */
1197 /* verify that this is a fine type specifier */
1198 if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
1200 warnf(config, "Illegally formatted content-type field!\n");
1202 FreeMultiInfo (multi_start);
1203 return 2; /* illegal content-type syntax! */
1205 /* now point beyond the content-type specifier */
1206 sep = (char *)type + strlen(major)+strlen(minor)+1;
1209 *sep=0; /* zero terminate type string */
1214 ptr = NULL; /* end */
1216 else if(curlx_strnequal("filename=", ptr, 9)) {
1218 ptr=strchr(filename, FORM_TYPE_SEPARATOR);
1220 ptr=strchr(filename, FORM_FILE_SEPARATOR);
1223 *ptr=0; /* zero terminate */
1228 /* confusion, bail out of loop */
1231 /* find the following comma */
1233 sep=strchr(ptr, FORM_FILE_SEPARATOR);
1238 sep=strchr(contp, FORM_FILE_SEPARATOR);
1241 /* the next file name starts here */
1245 /* if type == NULL curl_formadd takes care of the problem */
1247 if (!AddMultiFiles (contp, type, filename, &multi_start,
1249 warnf(config, "Error building form post!\n");
1251 FreeMultiInfo (multi_start);
1254 contp = sep; /* move the contents pointer to after the separator */
1256 } while(sep && *sep); /* loop if there's another file name */
1258 /* now we add the multiple files section */
1260 struct curl_forms *forms = NULL;
1261 struct multi_files *ptr = multi_start;
1262 unsigned int i, count = 0;
1267 forms = malloc((count+1)*sizeof(struct curl_forms));
1270 fprintf(config->errors, "Error building form post!\n");
1272 FreeMultiInfo (multi_start);
1275 for (i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
1277 forms[i].option = ptr->form.option;
1278 forms[i].value = ptr->form.value;
1280 forms[count].option = CURLFORM_END;
1281 FreeMultiInfo (multi_start);
1282 if (curl_formadd(httppost, last_post,
1283 CURLFORM_COPYNAME, name,
1284 CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
1285 warnf(config, "curl_formadd failed!\n");
1294 struct curl_forms info[4];
1296 char *ct = literal_value? NULL: strstr(contp, ";type=");
1298 info[i].option = CURLFORM_COPYNAME;
1299 info[i].value = name;
1303 info[i].option = CURLFORM_CONTENTTYPE;
1304 info[i].value = &ct[6];
1306 ct[0]=0; /* zero terminate here */
1309 if( contp[0]=='<' && !literal_value) {
1310 info[i].option = CURLFORM_FILECONTENT;
1311 info[i].value = contp+1;
1313 info[i].option = CURLFORM_END;
1315 if (curl_formadd(httppost, last_post,
1316 CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
1317 warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
1324 #ifdef CURL_DOES_CONVERSIONS
1325 convert_to_network(contp, strlen(contp));
1327 info[i].option = CURLFORM_COPYCONTENTS;
1328 info[i].value = contp;
1330 info[i].option = CURLFORM_END;
1331 if (curl_formadd(httppost, last_post,
1332 CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
1333 warnf(config, "curl_formadd failed!\n");
1342 warnf(config, "Illegally formatted input field!\n");
1352 PARAM_OPTION_AMBIGUOUS,
1353 PARAM_OPTION_UNKNOWN,
1354 PARAM_REQUIRES_PARAMETER,
1356 PARAM_HELP_REQUESTED,
1357 PARAM_GOT_EXTRA_PARAMETER,
1359 PARAM_LIBCURL_DOESNT_SUPPORT,
1364 static const char *param2text(int res)
1366 ParameterError error = (ParameterError)res;
1368 case PARAM_GOT_EXTRA_PARAMETER:
1369 return "had unsupported trailing garbage";
1370 case PARAM_OPTION_UNKNOWN:
1371 return "is unknown";
1372 case PARAM_OPTION_AMBIGUOUS:
1373 return "is ambiguous";
1374 case PARAM_REQUIRES_PARAMETER:
1375 return "requires parameter";
1377 return "is badly used here";
1378 case PARAM_BAD_NUMERIC:
1379 return "expected a proper numerical parameter";
1380 case PARAM_LIBCURL_DOESNT_SUPPORT:
1381 return "the installed libcurl version doesn't support this";
1383 return "out of memory";
1385 return "unknown error";
1389 static ParameterError file2string(char **bufp, FILE *file)
1393 char *string = NULL;
1394 size_t stringlen = 0;
1398 while(fgets(buffer, sizeof(buffer), file)) {
1399 if((ptr = strchr(buffer, '\r')) != NULL)
1401 if((ptr = strchr(buffer, '\n')) != NULL)
1403 buflen = strlen(buffer);
1404 if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
1407 return PARAM_NO_MEM;
1410 strcpy(string+stringlen, buffer);
1411 stringlen += buflen;
1418 static ParameterError file2memory(char **bufp, size_t *size, FILE *file)
1421 char *buffer = NULL;
1428 if(!buffer || (alloc == nused)) {
1429 /* size_t overflow detection for huge files */
1430 if(alloc+1 > ((size_t)-1)/2) {
1433 return PARAM_NO_MEM;
1436 /* allocate an extra char, reserved space, for null termination */
1437 if((newbuf = realloc(buffer, alloc+1)) == NULL) {
1440 return PARAM_NO_MEM;
1444 nread = fread(buffer+nused, 1, alloc-nused, file);
1447 /* null terminate the buffer in case it's used as a string later */
1448 buffer[nused] = '\0';
1449 /* free trailing slack space, if possible */
1450 if(alloc != nused) {
1451 if((newbuf = realloc(buffer, nused+1)) != NULL)
1454 /* discard buffer if nothing was read */
1457 buffer = NULL; /* no string */
1465 static void cleanarg(char *str)
1467 #ifdef HAVE_WRITABLE_ARGV
1468 /* now that GetStr has copied the contents of nextarg, wipe the next
1469 * argument out so that the username:password isn't displayed in the
1470 * system process list */
1472 size_t len = strlen(str);
1473 memset(str, ' ', len);
1481 * Parse the string and write the integer in the given address. Return
1482 * non-zero on failure, zero on success.
1484 * The string must start with a digit to be valid.
1486 * Since this function gets called with the 'nextarg' pointer from within the
1487 * getparameter a lot, we must check it for NULL before accessing the str
1491 static int str2num(long *val, const char *str)
1494 if(str && ISDIGIT(*str))
1497 retcode = 1; /* badness */
1502 * Parse the string and modify the long in the given address. Return
1503 * non-zero on failure, zero on success.
1505 * The string is a list of protocols
1507 * Since this function gets called with the 'nextarg' pointer from within the
1508 * getparameter a lot, we must check it for NULL before accessing the str
1512 static long proto2num(struct Configurable *config, long *val, const char *str)
1515 const char *sep = ",";
1518 static struct sprotos {
1521 } const protos[] = {
1522 { "all", CURLPROTO_ALL },
1523 { "http", CURLPROTO_HTTP },
1524 { "https", CURLPROTO_HTTPS },
1525 { "ftp", CURLPROTO_FTP },
1526 { "ftps", CURLPROTO_FTPS },
1527 { "scp", CURLPROTO_SCP },
1528 { "sftp", CURLPROTO_SFTP },
1529 { "telnet", CURLPROTO_TELNET },
1530 { "ldap", CURLPROTO_LDAP },
1531 { "ldaps", CURLPROTO_LDAPS },
1532 { "dict", CURLPROTO_DICT },
1533 { "file", CURLPROTO_FILE },
1534 { "tftp", CURLPROTO_TFTP },
1535 { "imap", CURLPROTO_IMAP },
1536 { "imaps", CURLPROTO_IMAPS },
1537 { "pop3", CURLPROTO_POP3 },
1538 { "pop3s", CURLPROTO_POP3S },
1539 { "smtp", CURLPROTO_SMTP },
1540 { "smtps", CURLPROTO_SMTPS },
1541 { "rtsp", CURLPROTO_RTSP },
1548 buffer = strdup(str); /* because strtok corrupts it */
1550 for (token = strtok(buffer, sep);
1552 token = strtok(NULL, sep)) {
1553 enum e_action { allow, deny, set } action = allow;
1555 struct sprotos const *pp;
1557 /* Process token modifiers */
1558 while (!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
1569 default: /* Includes case of terminating NULL */
1575 for (pp=protos; pp->name; pp++) {
1576 if (curlx_raw_equal(token, pp->name)) {
1592 if (!(pp->name)) { /* unknown protocol */
1593 /* If they have specified only this protocol, we say treat it as
1594 if no protocols are allowed */
1597 warnf(config, "unrecognized protocol '%s'\n", token);
1605 * Parses the given string looking for an offset (which may be
1606 * a larger-than-integer value).
1608 * @param val the offset to populate
1609 * @param str the buffer containing the offset
1610 * @return zero if successful, non-zero if failure.
1612 static int str2offset(curl_off_t *val, const char *str)
1614 #if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
1615 *val = curlx_strtoofft(str, NULL, 0);
1616 if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
1619 *val = strtol(str, NULL, 0);
1620 if ((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
1626 static void checkpasswd(const char *kind, /* for what purpose */
1627 char **userpwd) /* pointer to allocated string */
1633 ptr = strchr(*userpwd, ':');
1635 /* no password present, prompt for one */
1636 char passwd[256]="";
1639 size_t userlen = strlen(*userpwd);
1642 /* build a nice-looking prompt */
1643 curlx_msnprintf(prompt, sizeof(prompt),
1644 "Enter %s password for user '%s':",
1648 getpass_r(prompt, passwd, sizeof(passwd));
1649 passwdlen = strlen(passwd);
1651 /* extend the allocated memory area to fit the password too */
1652 passptr = realloc(*userpwd,
1653 passwdlen + 1 + /* an extra for the colon */
1654 userlen + 1); /* an extra for the zero */
1657 /* append the password separated with a colon */
1658 passptr[userlen]=':';
1659 memcpy(&passptr[userlen+1], passwd, passwdlen+1);
1665 static ParameterError add2list(struct curl_slist **list,
1668 struct curl_slist *newlist = curl_slist_append(*list, ptr);
1672 return PARAM_NO_MEM;
1677 static int ftpfilemethod(struct Configurable *config, const char *str)
1679 if(curlx_raw_equal("singlecwd", str))
1680 return CURLFTPMETHOD_SINGLECWD;
1681 if(curlx_raw_equal("nocwd", str))
1682 return CURLFTPMETHOD_NOCWD;
1683 if(curlx_raw_equal("multicwd", str))
1684 return CURLFTPMETHOD_MULTICWD;
1685 warnf(config, "unrecognized ftp file method '%s', using default\n", str);
1686 return CURLFTPMETHOD_MULTICWD;
1689 static int ftpcccmethod(struct Configurable *config, const char *str)
1691 if(curlx_raw_equal("passive", str))
1692 return CURLFTPSSL_CCC_PASSIVE;
1693 if(curlx_raw_equal("active", str))
1694 return CURLFTPSSL_CCC_ACTIVE;
1695 warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
1696 return CURLFTPSSL_CCC_PASSIVE;
1700 static int sockoptcallback(void *clientp, curl_socket_t curlfd,
1701 curlsocktype purpose)
1703 struct Configurable *config = (struct Configurable *)clientp;
1704 int onoff = 1; /* this callback is only used if we ask for keepalives on the
1706 #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
1707 int keepidle = (int)config->alivetime;
1711 case CURLSOCKTYPE_IPCXN:
1712 if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
1713 sizeof(onoff)) < 0) {
1714 /* don't abort operation, just issue a warning */
1716 warnf(clientp, "Could not set SO_KEEPALIVE!\n");
1720 if (config->alivetime) {
1722 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
1723 sizeof(keepidle)) < 0) {
1724 /* don't abort operation, just issue a warning */
1726 warnf(clientp, "Could not set TCP_KEEPIDLE!\n");
1730 #ifdef TCP_KEEPINTVL
1731 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
1732 sizeof(keepidle)) < 0) {
1733 /* don't abort operation, just issue a warning */
1735 warnf(clientp, "Could not set TCP_KEEPINTVL!\n");
1750 static ParameterError getparameter(char *flag, /* f or -long-flag */
1751 char *nextarg, /* NULL if unset */
1752 bool *usedarg, /* set to TRUE if the arg
1754 struct Configurable *config)
1757 char subletter=0; /* subletters can only occur on long options */
1758 int rc; /* generic return code variable */
1759 const char *parse=NULL;
1764 bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
1766 bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled
1767 by using --OPTION or --no-OPTION */
1771 boolean whether it takes an additional argument
1773 static const struct LongShort aliases[]= {
1774 /* all these ones, starting with "*" or "$" as a short-option have *no*
1775 short option to mention. */
1777 {"*a", "random-file", TRUE},
1778 {"*b", "egd-file", TRUE},
1779 {"*c", "connect-timeout", TRUE},
1780 {"*d", "ciphers", TRUE},
1781 {"*e", "disable-epsv", FALSE},
1782 {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to
1783 work although --disable-epsv is the documented
1785 #ifdef USE_ENVIRONMENT
1786 {"*f", "environment", FALSE},
1788 {"*g", "trace", TRUE},
1789 {"*h", "trace-ascii", TRUE},
1790 {"*i", "limit-rate", TRUE},
1791 {"*j", "compressed", FALSE}, /* might take an arg someday */
1792 {"*k", "digest", FALSE},
1793 {"*l", "negotiate", FALSE},
1794 {"*m", "ntlm", FALSE},
1795 {"*n", "basic", FALSE},
1796 {"*o", "anyauth", FALSE},
1798 {"*p", "wdebug", FALSE},
1800 {"*q", "ftp-create-dirs", FALSE},
1801 {"*r", "create-dirs", FALSE},
1802 {"*s", "max-redirs", TRUE},
1803 {"*t", "proxy-ntlm", FALSE},
1804 {"*u", "crlf", FALSE},
1805 {"*v", "stderr", TRUE},
1806 {"*w", "interface", TRUE},
1807 {"*x", "krb" , TRUE},
1808 {"*x", "krb4" , TRUE}, /* this is the previous name */
1809 {"*y", "max-filesize", TRUE},
1810 {"*z", "disable-eprt", FALSE},
1811 {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to
1812 work although --disable-eprt is the documented
1814 {"$a", "ftp-ssl", FALSE}, /* deprecated name since 7.20.0 */
1815 {"$a", "ssl", FALSE}, /* new option name in 7.20.0, previously this
1817 {"$b", "ftp-pasv", FALSE},
1818 {"$c", "socks5", TRUE},
1819 {"$c", "socks", TRUE}, /* this is how the option once was documented
1820 but we prefer the --socks5 version for
1822 {"$d", "tcp-nodelay",FALSE},
1823 {"$e", "proxy-digest", FALSE},
1824 {"$f", "proxy-basic", FALSE},
1825 {"$g", "retry", TRUE},
1826 {"$h", "retry-delay", TRUE},
1827 {"$i", "retry-max-time", TRUE},
1828 {"$k", "proxy-negotiate", FALSE},
1829 {"$m", "ftp-account", TRUE},
1830 {"$n", "proxy-anyauth", FALSE},
1831 {"$o", "trace-time", FALSE},
1832 {"$p", "ignore-content-length", FALSE},
1833 {"$q", "ftp-skip-pasv-ip", FALSE},
1834 {"$r", "ftp-method", TRUE},
1835 {"$s", "local-port", TRUE},
1836 {"$t", "socks4", TRUE},
1837 {"$T", "socks4a", TRUE},
1838 {"$u", "ftp-alternative-to-user", TRUE},
1839 {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */
1840 {"$v", "ssl-reqd", FALSE}, /* new option name in 7.20.0, previously this
1842 {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */
1843 {"$x", "ftp-ssl-control", FALSE},
1844 {"$y", "ftp-ssl-ccc", FALSE},
1845 {"$j", "ftp-ssl-ccc-mode", TRUE},
1846 {"$z", "libcurl", TRUE},
1847 {"$#", "raw", FALSE},
1848 {"$0", "post301", FALSE},
1849 {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
1850 {"$2", "socks5-hostname", TRUE},
1851 {"$3", "keepalive-time", TRUE},
1852 {"$4", "post302", FALSE},
1853 {"$5", "noproxy", TRUE},
1855 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1856 {"$6", "socks5-gssapi-service", TRUE},
1857 {"$7", "socks5-gssapi-nec", FALSE},
1859 {"$8", "proxy1.0", TRUE},
1860 {"$9", "tftp-blksize", TRUE},
1861 {"$A", "mail-from", TRUE},
1862 {"$B", "mail-rcpt", TRUE},
1863 {"$C", "ftp-pret", FALSE},
1864 {"$D", "proto", TRUE},
1865 {"$E", "proto-redir", TRUE},
1866 {"0", "http1.0", FALSE},
1867 {"1", "tlsv1", FALSE},
1868 {"2", "sslv2", FALSE},
1869 {"3", "sslv3", FALSE},
1870 {"4", "ipv4", FALSE},
1871 {"6", "ipv6", FALSE},
1872 {"a", "append", FALSE},
1873 {"A", "user-agent", TRUE},
1874 {"b", "cookie", TRUE},
1875 {"B", "use-ascii", FALSE},
1876 {"c", "cookie-jar", TRUE},
1877 {"C", "continue-at", TRUE},
1878 {"d", "data", TRUE},
1879 {"da", "data-ascii", TRUE},
1880 {"db", "data-binary", TRUE},
1881 {"de", "data-urlencode", TRUE},
1882 {"D", "dump-header", TRUE},
1883 {"e", "referer", TRUE},
1884 {"E", "cert", TRUE},
1885 {"Ea", "cacert", TRUE},
1886 {"Eb","cert-type", TRUE},
1888 {"Ed","key-type", TRUE},
1889 {"Ee","pass", TRUE},
1890 {"Ef","engine", TRUE},
1891 {"Eg","capath ", TRUE},
1892 {"Eh","pubkey", TRUE},
1893 {"Ei", "hostpubmd5", TRUE},
1894 {"Ej","crlfile", TRUE},
1895 {"f", "fail", FALSE},
1896 {"F", "form", TRUE},
1897 {"Fs","form-string", TRUE},
1898 {"g", "globoff", FALSE},
1899 {"G", "get", FALSE},
1900 {"h", "help", FALSE},
1901 {"H", "header", TRUE},
1902 {"i", "include", FALSE},
1903 {"I", "head", FALSE},
1904 {"j", "junk-session-cookies", FALSE},
1905 {"J", "remote-header-name", FALSE},
1906 {"k", "insecure", FALSE},
1907 {"K", "config", TRUE},
1908 {"l", "list-only", FALSE},
1909 {"L", "location", FALSE},
1910 {"Lt", "location-trusted", FALSE},
1911 {"m", "max-time", TRUE},
1912 {"M", "manual", FALSE},
1913 {"n", "netrc", FALSE},
1914 {"no", "netrc-optional", FALSE},
1915 {"N", "buffer", FALSE}, /* listed as --no-buffer in the help */
1916 {"o", "output", TRUE},
1917 {"O", "remote-name", FALSE},
1918 {"Oa", "remote-name-all", FALSE},
1919 {"p", "proxytunnel", FALSE},
1920 {"P", "ftpport", TRUE}, /* older version */
1921 {"P", "ftp-port", TRUE},
1922 {"q", "disable", FALSE},
1923 {"Q", "quote", TRUE},
1924 {"r", "range", TRUE},
1925 {"R", "remote-time", FALSE},
1926 {"s", "silent", FALSE},
1927 {"S", "show-error", FALSE},
1928 {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */
1929 {"T", "upload-file", TRUE},
1930 {"u", "user", TRUE},
1931 {"U", "proxy-user", TRUE},
1932 {"v", "verbose", FALSE},
1933 {"V", "version", FALSE},
1934 {"w", "write-out", TRUE},
1935 {"x", "proxy", TRUE},
1936 {"X", "request", TRUE},
1937 {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
1938 {"Y", "speed-limit", TRUE},
1939 {"y", "speed-time", TRUE},
1940 {"z", "time-cond", TRUE},
1941 {"#", "progress-bar",FALSE},
1944 if(('-' != flag[0]) ||
1945 (('-' == flag[0]) && ('-' == flag[1]))) {
1946 /* this should be a long name */
1947 char *word=('-' == flag[0])?flag+2:flag;
1948 size_t fnam=strlen(word);
1951 if(!strncmp(word, "no-", 3)) {
1952 /* disable this option but ignore the "no-" part when looking for it */
1957 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1958 if(curlx_strnequal(aliases[j].lname, word, fnam)) {
1961 if(curlx_raw_equal(aliases[j].lname, word)) {
1962 parse = aliases[j].letter;
1964 numhits = 1; /* a single unique hit */
1967 parse = aliases[j].letter;
1972 /* this is at least the second match! */
1973 return PARAM_OPTION_AMBIGUOUS;
1976 return PARAM_OPTION_UNKNOWN;
1980 flag++; /* prefixed with one dash, pass it */
1986 /* we can loop here if we have multiple single-letters */
1990 letter = (char)*parse;
1999 subletter = parse[1];
2001 *usedarg = FALSE; /* default is that we don't use the arg */
2004 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
2005 if(letter == aliases[j].letter[0]) {
2011 return PARAM_OPTION_UNKNOWN;
2015 if(aliases[hit].extraparam) {
2016 /* this option requires an extra parameter */
2017 if(!longopt && parse[1]) {
2018 nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
2019 singleopt=TRUE; /* don't loop anymore after this */
2022 return PARAM_REQUIRES_PARAMETER;
2024 *usedarg = TRUE; /* mark it as used */
2028 case '*': /* options without a short option */
2030 case 'a': /* random-file */
2031 GetStr(&config->random_file, nextarg);
2033 case 'b': /* egd-file */
2034 GetStr(&config->egd_file, nextarg);
2036 case 'c': /* connect-timeout */
2037 if(str2num(&config->connecttimeout, nextarg))
2038 return PARAM_BAD_NUMERIC;
2040 case 'd': /* ciphers */
2041 GetStr(&config->cipher_list, nextarg);
2043 case 'e': /* --disable-epsv */
2044 config->disable_epsv = toggle;
2046 case 'E': /* --epsv */
2047 config->disable_epsv = (bool)(!toggle);
2049 #ifdef USE_ENVIRONMENT
2051 config->writeenv = toggle;
2054 case 'g': /* --trace */
2055 GetStr(&config->trace_dump, nextarg);
2056 if(config->tracetype && (config->tracetype != TRACE_BIN))
2057 warnf(config, "--trace overrides an earlier trace/verbose option\n");
2058 config->tracetype = TRACE_BIN;
2060 case 'h': /* --trace-ascii */
2061 GetStr(&config->trace_dump, nextarg);
2062 if(config->tracetype && (config->tracetype != TRACE_ASCII))
2064 "--trace-ascii overrides an earlier trace/verbose option\n");
2065 config->tracetype = TRACE_ASCII;
2067 case 'i': /* --limit-rate */
2069 /* We support G, M, K too */
2071 curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
2075 else if(strlen(unit) > 1)
2076 unit=(char *)"w"; /* unsupported */
2081 value *= 1024*1024*1024;
2093 /* for plain bytes, leave as-is */
2096 warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
2097 return PARAM_BAD_USE;
2099 config->recvpersecond = value;
2100 config->sendpersecond = value;
2104 case 'j': /* --compressed */
2105 config->encoding = toggle;
2108 case 'k': /* --digest */
2110 config->authtype |= CURLAUTH_DIGEST;
2112 config->authtype &= ~CURLAUTH_DIGEST;
2115 case 'l': /* --negotiate */
2117 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2118 config->authtype |= CURLAUTH_GSSNEGOTIATE;
2120 return PARAM_LIBCURL_DOESNT_SUPPORT;
2123 config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
2126 case 'm': /* --ntlm */
2128 if(curlinfo->features & CURL_VERSION_NTLM)
2129 config->authtype |= CURLAUTH_NTLM;
2131 return PARAM_LIBCURL_DOESNT_SUPPORT;
2134 config->authtype &= ~CURLAUTH_NTLM;
2137 case 'n': /* --basic for completeness */
2139 config->authtype |= CURLAUTH_BASIC;
2141 config->authtype &= ~CURLAUTH_BASIC;
2144 case 'o': /* --anyauth, let libcurl pick it */
2146 config->authtype = CURLAUTH_ANY;
2147 /* --no-anyauth simply doesn't touch it */
2151 case 'p': /* --wdebug */
2155 case 'q': /* --ftp-create-dirs */
2156 config->ftp_create_dirs = toggle;
2159 case 'r': /* --create-dirs */
2160 config->create_dirs = TRUE;
2163 case 's': /* --max-redirs */
2164 /* specified max no of redirects (http(s)) */
2165 if(str2num(&config->maxredirs, nextarg))
2166 return PARAM_BAD_NUMERIC;
2169 case 't': /* --proxy-ntlm */
2170 if(curlinfo->features & CURL_VERSION_NTLM)
2171 config->proxyntlm = toggle;
2173 return PARAM_LIBCURL_DOESNT_SUPPORT;
2176 case 'u': /* --crlf */
2177 /* LF -> CRLF conversion? */
2178 config->crlf = TRUE;
2181 case 'v': /* --stderr */
2182 if(strcmp(nextarg, "-")) {
2183 FILE *newfile = fopen(nextarg, "wt");
2185 warnf(config, "Failed to open %s!\n", nextarg);
2187 if(config->errors_fopened)
2188 fclose(config->errors);
2189 config->errors = newfile;
2190 config->errors_fopened = TRUE;
2194 config->errors = stdout;
2196 case 'w': /* --interface */
2198 GetStr(&config->iface, nextarg);
2200 case 'x': /* --krb */
2201 /* kerberos level string */
2202 if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
2203 CURL_VERSION_GSSNEGOTIATE))
2204 GetStr(&config->krblevel, nextarg);
2206 return PARAM_LIBCURL_DOESNT_SUPPORT;
2208 case 'y': /* --max-filesize */
2209 if(str2offset(&config->max_filesize, nextarg))
2210 return PARAM_BAD_NUMERIC;
2212 case 'z': /* --disable-eprt */
2213 config->disable_eprt = toggle;
2215 case 'Z': /* --eprt */
2216 config->disable_eprt = (bool)(!toggle);
2219 default: /* the URL! */
2222 if(config->url_get || (config->url_get=config->url_list)) {
2223 /* there's a node here, if it already is filled-in continue to find
2225 while(config->url_get && (config->url_get->flags&GETOUT_URL))
2226 config->url_get = config->url_get->next;
2229 /* now there might or might not be an available node to fill in! */
2233 url = config->url_get;
2235 /* there was no free node, create one! */
2236 url=new_getout(config);
2239 /* fill in the URL */
2240 GetStr(&url->url, nextarg);
2241 url->flags |= GETOUT_URL;
2246 case '$': /* more options without a short option */
2248 case 'a': /* --ftp-ssl */
2249 config->ftp_ssl = toggle;
2251 case 'b': /* --ftp-pasv */
2253 free(config->ftpport);
2254 config->ftpport = NULL;
2256 case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
2257 the name locally and passes on the resolved address */
2258 GetStr(&config->socksproxy, nextarg);
2259 config->socksver = CURLPROXY_SOCKS5;
2261 case 't': /* --socks4 specifies a socks4 proxy to use */
2262 GetStr(&config->socksproxy, nextarg);
2263 config->socksver = CURLPROXY_SOCKS4;
2265 case 'T': /* --socks4a specifies a socks4a proxy to use */
2266 GetStr(&config->socksproxy, nextarg);
2267 config->socksver = CURLPROXY_SOCKS4A;
2269 case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
2270 resolving with the proxy */
2271 GetStr(&config->socksproxy, nextarg);
2272 config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
2274 case 'd': /* --tcp-nodelay option */
2275 config->tcp_nodelay = toggle;
2277 case 'e': /* --proxy-digest */
2278 config->proxydigest = toggle;
2280 case 'f': /* --proxy-basic */
2281 config->proxybasic = toggle;
2283 case 'g': /* --retry */
2284 if(str2num(&config->req_retry, nextarg))
2285 return PARAM_BAD_NUMERIC;
2287 case 'h': /* --retry-delay */
2288 if(str2num(&config->retry_delay, nextarg))
2289 return PARAM_BAD_NUMERIC;
2291 case 'i': /* --retry-max-time */
2292 if(str2num(&config->retry_maxtime, nextarg))
2293 return PARAM_BAD_NUMERIC;
2296 case 'k': /* --proxy-negotiate */
2297 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2298 config->proxynegotiate = toggle;
2300 return PARAM_LIBCURL_DOESNT_SUPPORT;
2302 case 'm': /* --ftp-account */
2303 GetStr(&config->ftp_account, nextarg);
2305 case 'n': /* --proxy-anyauth */
2306 config->proxyanyauth = toggle;
2308 case 'o': /* --trace-time */
2309 config->tracetime = toggle;
2311 case 'p': /* --ignore-content-length */
2312 config->ignorecl = toggle;
2314 case 'q': /* --ftp-skip-pasv-ip */
2315 config->ftp_skip_ip = toggle;
2317 case 'r': /* --ftp-method (undocumented at this point) */
2318 config->ftp_filemethod = ftpfilemethod(config, nextarg);
2320 case 's': /* --local-port */
2321 rc = sscanf(nextarg, "%d - %d",
2323 &config->localportrange);
2325 return PARAM_BAD_USE;
2327 config->localportrange = 1; /* default number of ports to try */
2329 config->localportrange -= config->localport;
2330 if(config->localportrange < 1) {
2331 warnf(config, "bad range input\n");
2332 return PARAM_BAD_USE;
2336 case 'u': /* --ftp-alternative-to-user */
2337 GetStr(&config->ftp_alternative_to_user, nextarg);
2339 case 'v': /* --ftp-ssl-reqd */
2340 config->ftp_ssl_reqd = toggle;
2342 case 'w': /* --no-sessionid */
2343 config->disable_sessionid = (bool)(!toggle);
2345 case 'x': /* --ftp-ssl-control */
2346 config->ftp_ssl_control = toggle;
2348 case 'y': /* --ftp-ssl-ccc */
2349 config->ftp_ssl_ccc = toggle;
2350 if(!config->ftp_ssl_ccc_mode)
2351 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
2353 case 'j': /* --ftp-ssl-ccc-mode */
2354 config->ftp_ssl_ccc = TRUE;
2355 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
2357 case 'z': /* --libcurl */
2358 GetStr(&config->libcurl, nextarg);
2360 case '#': /* --raw */
2361 config->raw = toggle;
2363 case '0': /* --post301 */
2364 config->post301 = toggle;
2366 case '1': /* --no-keepalive */
2367 config->nokeepalive = (bool)(!toggle);
2369 case '3': /* --keepalive-time */
2370 if(str2num(&config->alivetime, nextarg))
2371 return PARAM_BAD_NUMERIC;
2373 case '4': /* --post302 */
2374 config->post302 = toggle;
2376 case '5': /* --noproxy */
2377 /* This specifies the noproxy list */
2378 GetStr(&config->noproxy, nextarg);
2380 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
2381 case '6': /* --socks5-gssapi-service */
2382 GetStr(&config->socks5_gssapi_service, nextarg);
2384 case '7': /* --socks5-gssapi-nec*/
2385 config->socks5_gssapi_nec = TRUE;
2388 case '8': /* --proxy1.0 */
2389 /* http 1.0 proxy */
2390 GetStr(&config->proxy, nextarg);
2391 config->proxyver = CURLPROXY_HTTP_1_0;
2393 case '9': /* --tftp-blksize */
2394 str2num(&config->tftp_blksize, nextarg);
2396 case 'A': /* --mail-from */
2397 GetStr(&config->mail_from, nextarg);
2399 case 'B': /* --mail-rcpt */
2400 /* append receiver to a list */
2401 err = add2list(&config->mail_rcpt, nextarg);
2405 case 'C': /* --ftp-pret */
2406 config->ftp_pret = toggle;
2408 case 'D': /* --proto */
2409 config->proto_present = 1;
2410 if(proto2num(config, &config->proto, nextarg))
2411 return PARAM_BAD_USE;
2413 case 'E': /* --proto-redir */
2414 config->proto_redir_present = 1;
2415 if(proto2num(config, &config->proto_redir, nextarg))
2416 return PARAM_BAD_USE;
2420 case '#': /* --progress-bar */
2422 config->progressmode = CURL_PROGRESS_BAR;
2424 config->progressmode = CURL_PROGRESS_STATS;
2427 /* HTTP version 1.0 */
2428 config->httpversion = CURL_HTTP_VERSION_1_0;
2432 config->ssl_version = CURL_SSLVERSION_TLSv1;
2436 config->ssl_version = CURL_SSLVERSION_SSLv2;
2440 config->ssl_version = CURL_SSLVERSION_SSLv3;
2444 config->ip_version = 4;
2448 config->ip_version = 6;
2451 /* This makes the FTP sessions use APPE instead of STOR */
2452 config->ftp_append = toggle;
2455 /* This specifies the User-Agent name */
2456 GetStr(&config->useragent, nextarg);
2458 case 'b': /* cookie string coming up: */
2459 if(nextarg[0] == '@') {
2462 else if(strchr(nextarg, '=')) {
2463 /* A cookie string must have a =-letter */
2464 GetStr(&config->cookie, nextarg);
2467 /* We have a cookie file to read from! */
2468 GetStr(&config->cookiefile, nextarg);
2471 /* use ASCII/text when transfering */
2472 config->use_ascii = toggle;
2475 /* get the file name to dump all cookies in */
2476 GetStr(&config->cookiejar, nextarg);
2479 /* This makes us continue an ftp transfer at given position */
2480 if(!curlx_strequal(nextarg, "-")) {
2481 if(str2offset(&config->resume_from, nextarg))
2482 return PARAM_BAD_NUMERIC;
2483 config->resume_from_current = FALSE;
2486 config->resume_from_current = TRUE;
2487 config->resume_from = 0;
2489 config->use_resume=TRUE;
2492 /* postfield data */
2494 char *postdata=NULL;
2497 if(subletter == 'e') { /* --data-urlencode*/
2498 /* [name]=[content], we encode the content part only
2499 * [name]@[file name]
2501 * Case 2: we first load the file using that name and then encode
2504 const char *p = strchr(nextarg, '=');
2509 /* there was no '=' letter, check for a '@' instead */
2510 p = strchr(nextarg, '@');
2512 nlen = p - nextarg; /* length of the name part */
2513 is_file = *p++; /* pass the separator */
2516 /* neither @ nor =, so no name and it isn't a file */
2520 if('@' == is_file) {
2521 /* a '@' letter, it means that a file name or - (stdin) follows */
2523 if(curlx_strequal("-", p)) {
2528 file = fopen(p, "rb");
2531 "Couldn't read data from file \"%s\", this makes "
2532 "an empty POST.\n", nextarg);
2535 err = file2memory(&postdata, &size, file);
2537 if(file && (file != stdin))
2543 GetStr(&postdata, p);
2544 size = strlen(postdata);
2548 /* no data from the file, point to a zero byte string to make this
2549 get sent as a POST anyway */
2550 postdata=strdup("");
2553 char *enc = curl_easy_escape(config->easy, postdata, (int)size);
2554 free(postdata); /* no matter if it worked or not */
2556 /* now make a string with the name from above and append the
2558 size_t outlen = nlen + strlen(enc) + 2;
2559 char *n = malloc(outlen);
2562 return PARAM_NO_MEM;
2564 if (nlen > 0) /* only append '=' if we have a name */
2565 snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
2572 return PARAM_NO_MEM;
2575 else if('@' == *nextarg) {
2577 /* the data begins with a '@' letter, it means that a file name
2578 or - (stdin) follows */
2579 nextarg++; /* pass the @ */
2581 if(curlx_strequal("-", nextarg)) {
2583 if(subletter == 'b') /* forced data-binary */
2587 file = fopen(nextarg, "rb");
2589 warnf(config, "Couldn't read data from file \"%s\", this makes "
2590 "an empty POST.\n", nextarg);
2593 if(subletter == 'b') {
2595 err = file2memory(&postdata, &size, file);
2596 config->postfieldsize = (curl_off_t)size;
2599 err = file2string(&postdata, file);
2601 if(file && (file != stdin))
2607 /* no data from the file, point to a zero byte string to make this
2608 get sent as a POST anyway */
2609 postdata=strdup("");
2613 GetStr(&postdata, nextarg);
2616 #ifdef CURL_DOES_CONVERSIONS
2617 if(subletter != 'b') { /* NOT forced binary, convert to ASCII */
2618 convert_to_network(postdata, strlen(postdata));
2622 if(config->postfields) {
2623 /* we already have a string, we append this one
2624 with a separating &-letter */
2625 char *oldpost=config->postfields;
2626 size_t newlen = strlen(oldpost) + strlen(postdata) + 2;
2627 config->postfields=malloc(newlen);
2628 if(!config->postfields) {
2630 return PARAM_NO_MEM;
2632 /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
2633 snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata);
2638 config->postfields=postdata;
2641 We can't set the request type here, as this data might be used in
2642 a simple GET if -G is used. Already or soon.
2644 if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
2645 return PARAM_BAD_USE;
2649 /* dump-header to given file name */
2650 GetStr(&config->headerfile, nextarg);
2654 char *ptr = strstr(nextarg, ";auto");
2656 /* Automatic referer requested, this may be combined with a
2658 config->autoreferer = TRUE;
2659 *ptr = 0; /* zero terminate here */
2662 config->autoreferer = FALSE;
2663 GetStr(&config->referer, nextarg);
2668 case 'a': /* CA info PEM file */
2669 /* CA info PEM file */
2670 GetStr(&config->cacert, nextarg);
2672 case 'b': /* cert file type */
2673 GetStr(&config->cert_type, nextarg);
2675 case 'c': /* private key file */
2676 GetStr(&config->key, nextarg);
2678 case 'd': /* private key file type */
2679 GetStr(&config->key_type, nextarg);
2681 case 'e': /* private key passphrase */
2682 GetStr(&config->key_passwd, nextarg);
2685 case 'f': /* crypto engine */
2686 GetStr(&config->engine, nextarg);
2687 if (config->engine && curlx_raw_equal(config->engine,"list"))
2688 config->list_engines = TRUE;
2690 case 'g': /* CA info PEM file */
2691 /* CA cert directory */
2692 GetStr(&config->capath, nextarg);
2694 case 'h': /* --pubkey public key file */
2695 GetStr(&config->pubkey, nextarg);
2697 case 'i': /* --hostpubmd5 md5 of the host public key */
2698 GetStr(&config->hostpubmd5, nextarg);
2699 if (!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
2700 return PARAM_BAD_USE;
2702 case 'j': /* CRL info PEM file */
2704 GetStr(&config->crlfile, nextarg);
2706 default: /* certificate file */
2708 char *ptr = strchr(nextarg, ':');
2709 /* Since we live in a world of weirdness and confusion, the win32
2710 dudes can use : when using drive letters and thus
2711 c:\file:password needs to work. In order not to break
2712 compatibility, we still use : as separator, but we try to detect
2713 when it is used for a file name! On windows. */
2716 (ptr == &nextarg[1]) &&
2717 (nextarg[2] == '\\' || nextarg[2] == '/') &&
2718 (ISALPHA(nextarg[0])) )
2719 /* colon in the second column, followed by a backslash, and the
2720 first character is an alphabetic letter:
2722 this is a drive letter colon */
2723 ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
2726 /* we have a password too */
2729 GetStr(&config->key_passwd, ptr);
2731 GetStr(&config->cert, nextarg);
2737 /* fail hard on errors */
2738 config->failonerror = toggle;
2741 /* "form data" simulation, this is a little advanced so lets do our best
2742 to sort this out slowly and carefully */
2743 if(formparse(config,
2747 (bool) (subletter=='s'))) /* 's' means literal string */
2748 return PARAM_BAD_USE;
2749 if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
2750 return PARAM_BAD_USE;
2753 case 'g': /* g disables URLglobbing */
2754 config->globoff = toggle;
2757 case 'G': /* HTTP GET */
2758 config->use_httpget = TRUE;
2761 case 'h': /* h for help */
2764 return PARAM_HELP_REQUESTED;
2766 /* we now actually support --no-help too! */
2769 /* A custom header to append to a list */
2770 err = add2list(&config->headers, nextarg);
2775 config->include_headers = toggle; /* include the headers as well in the
2776 general output stream */
2779 config->cookiesession = toggle;
2783 * no_body will imply include_headers later on
2785 config->no_body = toggle;
2786 if(SetHTTPrequest(config,
2787 (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
2789 return PARAM_BAD_USE;
2791 case 'J': /* --remote-header-name */
2792 if (config->include_headers) {
2794 "--include and --remote-header-name cannot be combined.\n");
2795 return PARAM_BAD_USE;
2797 config->content_disposition = toggle;
2799 case 'k': /* allow insecure SSL connects */
2800 config->insecure_ok = toggle;
2802 case 'K': /* parse config file */
2803 if(parseconfig(nextarg, config))
2804 warnf(config, "error trying read config from the '%s' file\n",
2808 config->dirlistonly = toggle; /* only list the names of the FTP dir */
2811 config->followlocation = toggle; /* Follow Location: HTTP headers */
2812 switch (subletter) {
2814 /* Continue to send authentication (user+password) when following
2815 * locations, even when hostname changed */
2816 config->unrestricted_auth = toggle;
2821 /* specified max time */
2822 if(str2num(&config->timeout, nextarg))
2823 return PARAM_BAD_NUMERIC;
2825 case 'M': /* M for manual, huge help */
2826 if(toggle) { /* --no-manual shows no manual... */
2829 return PARAM_HELP_REQUESTED;
2832 "built-in manual was disabled at build-time!\n");
2833 return PARAM_OPTION_UNKNOWN;
2839 case 'o': /* CA info PEM file */
2840 /* use .netrc or URL */
2841 config->netrc_opt = toggle;
2844 /* pick info from .netrc, if this is used for http, curl will
2845 automatically enfore user+password with the request */
2846 config->netrc = toggle;
2851 /* disable the output I/O buffering. note that the option is called
2852 --buffer but is mostly used in the negative form: --no-buffer */
2854 config->nobuffer = (bool)(!toggle);
2856 config->nobuffer = toggle;
2858 case 'O': /* --remote-name */
2859 if(subletter == 'a') { /* --remote-name-all */
2860 config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
2864 case 'o': /* --output */
2868 if(config->url_out || (config->url_out=config->url_list)) {
2869 /* there's a node here, if it already is filled-in continue to find
2871 while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
2872 config->url_out = config->url_out->next;
2875 /* now there might or might not be an available node to fill in! */
2879 url = config->url_out;
2881 /* there was no free node, create one! */
2882 url=new_getout(config);
2885 /* fill in the outfile */
2887 GetStr(&url->outfile, nextarg);
2888 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2891 url->outfile=NULL; /* leave it */
2893 url->flags |= GETOUT_USEREMOTE; /* switch on */
2895 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2897 url->flags |= GETOUT_OUTFILE;
2902 /* This makes the FTP sessions use PORT instead of PASV */
2903 /* use <eth0> or <192.168.10.10> style addresses. Anything except
2904 this will make us try to get the "default" address.
2905 NOTE: this is a changed behaviour since the released 4.1!
2907 GetStr(&config->ftpport, nextarg);
2910 /* proxy tunnel for non-http protocols */
2911 config->proxytunnel = toggle;
2914 case 'q': /* if used first, already taken care of, we do it like
2915 this so we don't cause an error! */
2918 /* QUOTE command to send to FTP server */
2919 switch(nextarg[0]) {
2921 /* prefixed with a dash makes it a POST TRANSFER one */
2923 err = add2list(&config->postquote, nextarg);
2926 /* prefixed with a plus makes it a just-before-transfer one */
2928 err = add2list(&config->prequote, nextarg);
2931 err = add2list(&config->quote, nextarg);
2938 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2939 (and won't actually be range by definition). The man page previously
2940 claimed that to be a good way, why this code is added to work-around
2942 if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
2946 "A specified range MUST include at least one dash (-). "
2947 "Appending one for you!\n");
2948 off = curlx_strtoofft(nextarg, NULL, 10);
2949 snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
2950 GetStr(&config->range, buffer);
2953 /* byte range requested */
2956 while(*tmp_range != '\0') {
2957 if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') {
2958 warnf(config,"Invalid character is found in given range. "
2959 "A specified range MUST have only digits in "
2960 "\'start\'-\'stop\'. The server's response to this "
2961 "request is uncertain.\n");
2966 /* byte range requested */
2967 GetStr(&config->range, nextarg);
2971 /* use remote file's time */
2972 config->remote_time = toggle;
2975 /* don't show progress meter, don't show errors : */
2977 config->mute = config->noprogress = TRUE;
2979 config->mute = config->noprogress = FALSE;
2980 config->showerror = (bool)(!toggle); /* toggle off */
2984 config->showerror = toggle; /* toggle on if used with -s */
2987 /* Telnet options */
2988 err = add2list(&config->telnet_options, nextarg);
2993 /* we are uploading */
2996 if(config->url_out || (config->url_out=config->url_list)) {
2997 /* there's a node here, if it already is filled-in continue to find
2999 while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
3000 config->url_out = config->url_out->next;
3003 /* now there might or might not be an available node to fill in! */
3007 url = config->url_out;
3009 /* there was no free node, create one! */
3010 url=new_getout(config);
3013 url->flags |= GETOUT_UPLOAD; /* mark -T used */
3015 url->flags |= GETOUT_NOUPLOAD;
3017 /* "-" equals stdin, but keep the string around for now */
3018 GetStr(&url->infile, nextarg);
3025 GetStr(&config->userpwd, nextarg);
3027 checkpasswd("host", &config->userpwd);
3030 /* Proxy user:password */
3031 GetStr(&config->proxyuserpwd, nextarg);
3033 checkpasswd("proxy", &config->proxyuserpwd);
3037 /* the '%' thing here will cause the trace get sent to stderr */
3038 GetStr(&config->trace_dump, (char *)"%");
3039 if(config->tracetype && (config->tracetype != TRACE_PLAIN))
3041 "-v/--verbose overrides an earlier trace/verbose option\n");
3042 config->tracetype = TRACE_PLAIN;
3045 /* verbose is disabled here */
3046 config->tracetype = TRACE_NONE;
3050 const char * const *proto;
3053 /* --no-version yields no output! */
3056 printf(CURL_ID "%s\n", curl_version());
3057 if (curlinfo->protocols) {
3058 printf("Protocols: ");
3059 for (proto=curlinfo->protocols; *proto; ++proto) {
3060 printf("%s ", *proto);
3062 puts(""); /* newline */
3064 if(curlinfo->features) {
3070 static const struct feat feats[] = {
3071 {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
3072 {"Debug", CURL_VERSION_DEBUG},
3073 {"TrackMemory", CURL_VERSION_CURLDEBUG},
3074 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
3075 {"IDN", CURL_VERSION_IDN},
3076 {"IPv6", CURL_VERSION_IPV6},
3077 {"Largefile", CURL_VERSION_LARGEFILE},
3078 {"NTLM", CURL_VERSION_NTLM},
3079 {"SPNEGO", CURL_VERSION_SPNEGO},
3080 {"SSL", CURL_VERSION_SSL},
3081 {"SSPI", CURL_VERSION_SSPI},
3082 {"krb4", CURL_VERSION_KERBEROS4},
3083 {"libz", CURL_VERSION_LIBZ},
3084 {"CharConv", CURL_VERSION_CONV}
3086 printf("Features: ");
3087 for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
3088 if(curlinfo->features & feats[i].bitmask)
3089 printf("%s ", feats[i].name);
3091 puts(""); /* newline */
3094 return PARAM_HELP_REQUESTED;
3096 /* get the output string */
3097 if('@' == *nextarg) {
3098 /* the data begins with a '@' letter, it means that a file name
3099 or - (stdin) follows */
3102 nextarg++; /* pass the @ */
3103 if(curlx_strequal("-", nextarg)) {
3109 file = fopen(nextarg, "r");
3111 err = file2string(&config->writeout, file);
3112 if(file && (file != stdin))
3116 if(!config->writeout)
3117 warnf(config, "Failed to read %s", fname);
3120 GetStr(&config->writeout, nextarg);
3124 GetStr(&config->proxy, nextarg);
3125 config->proxyver = CURLPROXY_HTTP;
3128 /* set custom request */
3129 GetStr(&config->customrequest, nextarg);
3132 /* low speed time */
3133 if(str2num(&config->low_speed_time, nextarg))
3134 return PARAM_BAD_NUMERIC;
3135 if(!config->low_speed_limit)
3136 config->low_speed_limit = 1;
3139 /* low speed limit */
3140 if(str2num(&config->low_speed_limit, nextarg))
3141 return PARAM_BAD_NUMERIC;
3142 if(!config->low_speed_time)
3143 config->low_speed_time=30;
3145 case 'z': /* time condition coming up */
3150 /* If-Modified-Since: (section 14.28 in RFC2068) */
3151 config->timecond = CURL_TIMECOND_IFMODSINCE;
3154 /* If-Unmodified-Since: (section 14.24 in RFC2068) */
3155 config->timecond = CURL_TIMECOND_IFUNMODSINCE;
3159 /* Last-Modified: (section 14.29 in RFC2068) */
3160 config->timecond = CURL_TIMECOND_LASTMOD;
3165 config->condtime=curl_getdate(nextarg, &now);
3166 if(-1 == (int)config->condtime) {
3167 /* now let's see if it is a file name to get the time from instead! */
3168 struct_stat statbuf;
3169 if(-1 == stat(nextarg, &statbuf)) {
3170 /* failed, remove time condition */
3171 config->timecond = CURL_TIMECOND_NONE;
3173 "Illegal date format for -z/--timecond (and not "
3174 "a file name). Disabling time condition. "
3175 "See curl_getdate(3) for valid date syntax.\n");
3178 /* pull the time out from the file */
3179 config->condtime = statbuf.st_mtime;
3183 default: /* unknown flag */
3184 return PARAM_OPTION_UNKNOWN;
3188 } while(!longopt && !singleopt && *++parse && !*usedarg);
3194 * Copies the string from line to the buffer at param, unquoting
3195 * backslash-quoted characters and NUL-terminating the output string.
3196 * Stops at the first non-backslash-quoted double quote character or the
3197 * end of the input string. param must be at least as long as the input
3198 * string. Returns the pointer after the last handled input character.
3200 static const char *unslashquote(const char *line, char *param)
3202 while(*line && (*line != '\"')) {
3207 /* default is to output the letter after the backslash */
3208 switch(out = *line) {
3210 continue; /* this'll break out of the loop */
3230 *param=0; /* always zero terminate */
3234 /* return 0 on everything-is-fine, and non-zero otherwise */
3235 static int parseconfig(const char *filename,
3236 struct Configurable *config)
3240 char filebuffer[512];
3245 if(!filename || !*filename) {
3246 /* NULL or no file name attempts to load .curlrc from the homedir! */
3248 #define CURLRC DOT_CHAR "curlrc"
3251 filename = CURLRC; /* sensible default */
3252 home = homedir(); /* portable homedir finder */
3254 if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
3255 snprintf(filebuffer, sizeof(filebuffer),
3256 "%s%s%s", home, DIR_CHAR, CURLRC);
3259 /* Check if the file exists - if not, try CURLRC in the same
3260 * directory as our executable
3262 file = fopen(filebuffer, "r");
3265 filename = filebuffer;
3268 /* Get the filename of our executable. GetModuleFileName is
3269 * already declared via inclusions done in setup header file.
3270 * We assume that we are using the ASCII version here.
3272 int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
3273 if (n > 0 && n < (int)sizeof(filebuffer)) {
3274 /* We got a valid filename - get the directory part */
3275 char *lastdirchar = strrchr(filebuffer, '\\');
3279 /* If we have enough space, build the RC filename */
3280 remaining = sizeof(filebuffer) - strlen(filebuffer);
3281 if (strlen(CURLRC) < remaining - 1) {
3282 snprintf(lastdirchar, remaining,
3283 "%s%s", DIR_CHAR, CURLRC);
3284 /* Don't bother checking if it exists - we do
3287 filename = filebuffer;
3293 filename = filebuffer;
3296 free(home); /* we've used it, now free it */
3299 # else /* __AMIGA__ */
3300 /* On AmigaOS all the config files are into env:
3302 filename = "ENV:" CURLRC;
3307 if(strcmp(filename,"-"))
3308 file = fopen(filename, "r");
3320 #define ISSEP(x) (((x)=='=') || ((x) == ':'))
3322 while (NULL != (aline = my_get_line(file))) {
3325 alloced_param=FALSE;
3327 /* line with # in the first non-blank column is a comment! */
3328 while(*line && ISSPACE(*line))
3342 /* the option keywords starts here */
3344 while(*line && !ISSPACE(*line) && !ISSEP(*line))
3346 /* ... and has ended here */
3349 *line++=0; /* zero terminate, we have a local copy of the data */
3352 fprintf(stderr, "GOT: %s\n", option);
3355 /* pass spaces and separator(s) */
3356 while(*line && (ISSPACE(*line) || ISSEP(*line)))
3359 /* the parameter starts here (unless quoted) */
3361 /* quoted parameter, do the quote dance */
3363 param=malloc(strlen(line)+1); /* parameter */
3371 (void)unslashquote(line, param);
3374 param=line; /* parameter starts here */
3375 while(*line && !ISSPACE(*line))
3377 *line=0; /* zero terminate */
3380 if (param && !*param) {
3381 /* do this so getparameter can check for required parameters.
3382 Otherwise it always thinks there's a parameter. */
3389 fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
3391 res = getparameter(option, param, &usedarg, config);
3393 if (param && *param && !usedarg)
3394 /* we passed in a parameter that wasn't used! */
3395 res = PARAM_GOT_EXTRA_PARAMETER;
3397 if(res != PARAM_OK) {
3398 /* the help request isn't really an error */
3399 if(!strcmp(filename, "-")) {
3400 filename=(char *)"<stdin>";
3402 if(PARAM_HELP_REQUESTED != res) {
3403 const char *reason = param2text(res);
3404 warnf(config, "%s:%d: warning: '%s' %s\n",
3405 filename, lineno, option, reason);
3421 rc = 1; /* couldn't open the file */
3425 static void go_sleep(long ms)
3427 #ifdef HAVE_POLL_FINE
3428 /* portable subsecond "sleep" */
3429 poll((void *)0, 0, (int)ms);
3431 /* systems without poll() need other solutions */
3434 /* Windows offers a millisecond sleep */
3436 #elif defined(MSDOS)
3439 /* Other systems must use select() for this */
3440 struct timeval timeout;
3442 timeout.tv_sec = ms/1000;
3444 timeout.tv_usec = ms * 1000;
3446 select(0, NULL, NULL, NULL, &timeout);
3452 static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
3455 struct OutStruct *out=(struct OutStruct *)stream;
3456 struct Configurable *config = out->config;
3459 * Once that libcurl has called back my_fwrite() the returned value
3460 * is checked against the amount that was intended to be written, if
3461 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
3462 * point returning a value different from sz*nmemb indicates failure.
3464 const size_t err_rc = (sz * nmemb) ? 0 : 1;
3467 if (!out->filename) {
3468 warnf(config, "Remote filename has no length!\n");
3469 return err_rc; /* Failure */
3472 if (config->content_disposition) {
3473 /* don't overwrite existing files */
3474 FILE* f = fopen(out->filename, "r");
3477 warnf(config, "Refusing to overwrite %s: %s\n", out->filename,
3479 return err_rc; /* Failure */
3483 /* open file for writing */
3484 out->stream=fopen(out->filename, "wb");
3486 warnf(config, "Failed to create the file %s: %s\n", out->filename,
3488 return err_rc; /* failure */
3492 rc = fwrite(buffer, sz, nmemb, out->stream);
3494 if((sz * nmemb) == rc) {
3495 /* we added this amount of data to the output */
3496 out->bytes += (sz * nmemb);
3499 if(config->readbusy) {
3500 config->readbusy = FALSE;
3501 curl_easy_pause(config->easy, CURLPAUSE_CONT);
3504 if(config->nobuffer) {
3505 /* disable output buffering */
3506 int res = fflush(out->stream);
3508 /* return a value that isn't the same as sz * nmemb */
3509 return err_rc; /* failure */
3518 struct Configurable *config;
3521 #define MAX_SEEK 2147483647
3524 * my_seek() is the CURLOPT_SEEKFUNCTION we use
3526 static int my_seek(void *stream, curl_off_t offset, int whence)
3528 struct InStruct *in=(struct InStruct *)stream;
3530 #if (CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
3531 /* The offset check following here is only interesting if curl_off_t is
3532 larger than off_t and we are not using the WIN32 large file support
3533 macros that provide the support to do 64bit seeks correctly */
3535 if(offset > MAX_SEEK) {
3536 /* Some precaution code to work around problems with different data sizes
3537 to allow seeking >32bit even if off_t is 32bit. Should be very rare and
3538 is really valid on weirdo-systems. */
3539 curl_off_t left = offset;
3541 if(whence != SEEK_SET)
3542 /* this code path doesn't support other types */
3545 if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
3546 /* couldn't rewind to beginning */
3550 long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
3551 if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
3552 /* couldn't seek forwards the desired amount */
3559 if(LSEEK_ERROR == lseek(in->fd, offset, whence))
3560 /* couldn't rewind, the reason is in errno but errno is just not portable
3561 enough and we don't actually care that much why we failed. We'll let
3562 libcurl know that it may try other means if it wants to. */
3563 return CURL_SEEKFUNC_CANTSEEK;
3568 static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
3571 struct InStruct *in=(struct InStruct *)userp;
3573 rc = read(in->fd, buffer, sz*nmemb);
3575 if(errno == EAGAIN) {
3577 in->config->readbusy = TRUE;
3578 return CURL_READFUNC_PAUSE;
3580 /* since size_t is unsigned we can't return negative values fine */
3583 in->config->readbusy = FALSE;
3587 struct ProgressData {
3591 FILE *out; /* where to write everything to */
3592 curl_off_t initial_size;
3595 static int myprogress (void *clientp,
3601 /* The original progress-bar source code was written for curl by Lars Aas,
3602 and this new edition inherits some of his concepts. */
3613 struct ProgressData *bar = (struct ProgressData *)clientp;
3614 curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
3615 bar->initial_size; /* expected transfer size */
3616 curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
3617 bar->initial_size; /* we've come this far */
3620 /* we have got more than the expected total! */
3623 bar->calls++; /* simply count invokes */
3626 curl_off_t prevblock = bar->prev / 1024;
3627 curl_off_t thisblock = point / 1024;
3628 while ( thisblock > prevblock ) {
3629 fprintf( bar->out, "#" );
3634 frac = (double)point / (double)total;
3635 percent = frac * 100.0f;
3636 barwidth = bar->width - 7;
3637 num = (int) (((double)barwidth) * frac);
3638 for ( i = 0; i < num; i++ ) {
3642 snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
3643 snprintf( outline, sizeof(outline), format, line, percent );
3644 fprintf( bar->out, "\r%s", outline );
3653 void progressbarinit(struct ProgressData *bar,
3654 struct Configurable *config)
3662 memset(bar, 0, sizeof(struct ProgressData));
3664 /* pass this through to progress function so
3665 * it can display progress towards total file
3666 * not just the part that's left. (21-may-03, dbyron) */
3667 if (config->use_resume)
3668 bar->initial_size = config->resume_from;
3670 /* TODO: get terminal width through ansi escapes or something similar.
3671 try to update width when xterm is resized... - 19990617 larsa */
3674 * OS/2 users most likely won't have this env var set, and besides that
3675 * we're using our own way to determine screen width */
3676 colp = curlx_getenv("COLUMNS");
3678 bar->width = atoi(colp);
3685 * We use this emx library call to get the screen width, and subtract
3686 * one from what we got in order to avoid a problem with the cursor
3687 * advancing to the next line if we print a string that is as long as
3688 * the screen is wide. */
3691 bar->width = scr_size[0] - 1;
3694 bar->out = config->errors;
3699 void dump(const char *timebuf, const char *text,
3700 FILE *stream, const unsigned char *ptr, size_t size,
3701 trace tracetype, curl_infotype infotype)
3706 unsigned int width=0x10;
3708 if(tracetype == TRACE_ASCII)
3709 /* without the hex output, we can fit more on screen */
3712 fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
3714 for(i=0; i<size; i+= width) {
3716 fprintf(stream, "%04zx: ", i);
3718 if(tracetype == TRACE_BIN) {
3719 /* hex not disabled, show it */
3720 for(c = 0; c < width; c++)
3722 fprintf(stream, "%02x ", ptr[i+c]);
3727 for(c = 0; (c < width) && (i+c < size); c++) {
3728 /* check for 0D0A; if found, skip past and start a new line of output */
3729 if ((tracetype == TRACE_ASCII) &&
3730 (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
3734 #ifdef CURL_DOES_CONVERSIONS
3735 /* repeat the 0D0A check above but use the host encoding for CRLF */
3736 if ((tracetype == TRACE_ASCII) &&
3737 (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') {
3741 /* convert to host encoding and print this character */
3742 fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
3745 fprintf(stream, "%c",
3746 (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR);
3747 #endif /* CURL_DOES_CONVERSIONS */
3748 /* check again for 0D0A, to avoid an extra \n if it's at width */
3749 if ((tracetype == TRACE_ASCII) &&
3750 (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
3755 fputc('\n', stream); /* newline */
3761 int my_trace(CURL *handle, curl_infotype type,
3762 unsigned char *data, size_t size,
3765 struct Configurable *config = (struct Configurable *)userp;
3766 FILE *output=config->errors;
3772 static time_t epoch_offset;
3773 static int known_offset;
3775 (void)handle; /* prevent compiler warning */
3777 if(config->tracetime) {
3780 epoch_offset = time(NULL) - tv.tv_sec;
3783 secs = epoch_offset + tv.tv_sec;
3784 now = localtime(&secs); /* not thread safe but we don't care */
3785 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
3786 now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
3791 if(!config->trace_stream) {
3792 /* open for append */
3793 if(curlx_strequal("-", config->trace_dump))
3794 config->trace_stream = stdout;
3795 else if(curlx_strequal("%", config->trace_dump))
3796 /* Ok, this is somewhat hackish but we do it undocumented for now */
3797 config->trace_stream = config->errors; /* aka stderr */
3799 config->trace_stream = fopen(config->trace_dump, "w");
3800 config->trace_fopened = TRUE;
3804 if(config->trace_stream)
3805 output = config->trace_stream;
3808 warnf(config, "Failed to create/open output");
3812 if(config->tracetype == TRACE_PLAIN) {
3814 * This is the trace look that is similar to what libcurl makes on its
3817 static const char * const s_infotype[] = {
3818 "*", "<", ">", "{", "}", "{", "}"
3822 static bool newl = FALSE;
3823 static bool traced_data = FALSE;
3826 case CURLINFO_HEADER_OUT:
3827 for(i=0; i<size-1; i++) {
3828 if(data[i] == '\n') { /* LF */
3830 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3832 (void)fwrite(data+st, i-st+1, 1, output);
3838 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3839 (void)fwrite(data+st, i-st+1, 1, output);
3840 newl = (bool)(size && (data[size-1] != '\n'));
3841 traced_data = FALSE;
3844 case CURLINFO_HEADER_IN:
3846 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3847 (void)fwrite(data, size, 1, output);
3848 newl = (bool)(size && (data[size-1] != '\n'));
3849 traced_data = FALSE;
3851 case CURLINFO_DATA_OUT:
3852 case CURLINFO_DATA_IN:
3853 case CURLINFO_SSL_DATA_IN:
3854 case CURLINFO_SSL_DATA_OUT:
3856 /* if the data is output to a tty and we're sending this debug trace
3857 to stderr or stdout, we don't display the alert about the data not
3858 being shown as the data _is_ shown then just not via this
3860 if(!config->isatty ||
3861 ((output != stderr) && (output != stdout))) {
3863 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3864 fprintf(output, "[data not shown]\n");
3872 traced_data = FALSE;
3879 #ifdef CURL_DOES_CONVERSIONS
3880 /* Special processing is needed for CURLINFO_HEADER_OUT blocks
3881 * if they contain both headers and data (separated by CRLFCRLF).
3882 * We dump the header text and then switch type to CURLINFO_DATA_OUT.
3884 if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
3886 for(i = 0; i < size - 4; i++) {
3887 if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
3888 /* dump everthing through the CRLFCRLF as a sent header */
3889 text = "=> Send header";
3890 dump(timebuf, text, output, data, i+4, config->tracetype, type);
3893 type = CURLINFO_DATA_OUT;
3899 #endif /* CURL_DOES_CONVERSIONS */
3903 fprintf(output, "%s== Info: %s", timebuf, data);
3904 default: /* in case a new one is introduced to shock us */
3907 case CURLINFO_HEADER_OUT:
3908 text = "=> Send header";
3910 case CURLINFO_DATA_OUT:
3911 text = "=> Send data";
3913 case CURLINFO_HEADER_IN:
3914 text = "<= Recv header";
3916 case CURLINFO_DATA_IN:
3917 text = "<= Recv data";
3919 case CURLINFO_SSL_DATA_IN:
3920 text = "<= Recv SSL data";
3922 case CURLINFO_SSL_DATA_OUT:
3923 text = "=> Send SSL data";
3927 dump(timebuf, text, output, data, size, config->tracetype, type);
3931 static void free_config_fields(struct Configurable *config)
3933 if(config->random_file)
3934 free(config->random_file);
3935 if(config->egd_file)
3936 free(config->egd_file);
3937 if(config->trace_dump)
3938 free(config->trace_dump);
3939 if(config->cipher_list)
3940 free(config->cipher_list);
3942 free(config->userpwd);
3943 if(config->postfields)
3944 free(config->postfields);
3946 free(config->proxy);
3947 if(config->proxyuserpwd)
3948 free(config->proxyuserpwd);
3950 free(config->noproxy);
3952 free(config->cookie);
3953 if(config->cookiefile)
3954 free(config->cookiefile);
3955 if(config->krblevel)
3956 free(config->krblevel);
3957 if(config->headerfile)
3958 free(config->headerfile);
3960 free(config->ftpport);
3962 free(config->range);
3963 if(config->customrequest)
3964 free(config->customrequest);
3965 if(config->writeout)
3966 free(config->writeout);
3967 if(config->httppost)
3968 curl_formfree(config->httppost);
3972 free(config->cacert);
3973 if (config->cert_type)
3974 free(config->cert_type);
3976 free(config->capath);
3978 free(config->crlfile);
3979 if(config->cookiejar)
3980 free(config->cookiejar);
3981 if(config->ftp_account)
3982 free(config->ftp_account);
3983 if(config->ftp_alternative_to_user)
3984 free(config->ftp_alternative_to_user);
3986 free(config->iface);
3987 if(config->socksproxy)
3988 free(config->socksproxy);
3990 free(config->libcurl);
3991 if (config->key_passwd)
3992 free(config->key_passwd);
3995 if (config->key_type)
3996 free(config->key_type);
3998 free(config->pubkey);
3999 if (config->referer)
4000 free(config->referer);
4001 if (config->hostpubmd5)
4002 free(config->hostpubmd5);
4003 if(config->mail_from)
4004 free(config->mail_from);
4005 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
4006 if(config->socks5_gssapi_service)
4007 free(config->socks5_gssapi_service);
4010 curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
4011 curl_slist_free_all(config->prequote);
4012 curl_slist_free_all(config->postquote);
4013 curl_slist_free_all(config->headers);
4014 curl_slist_free_all(config->telnet_options);
4015 curl_slist_free_all(config->mail_rcpt);
4018 curl_easy_cleanup(config->easy);
4023 /* Function to find CACert bundle on a Win32 platform using SearchPath.
4024 * (SearchPath is already declared via inclusions done in setup header file)
4025 * (Use the ASCII version instead of the unicode one!)
4026 * The order of the directories it searches is:
4027 * 1. application's directory
4028 * 2. current working directory
4029 * 3. Windows System directory (e.g. C:\windows\system32)
4030 * 4. Windows Directory (e.g. C:\windows)
4031 * 5. all directories along %PATH%
4033 static void FindWin32CACert(struct Configurable *config,
4034 const char *bundle_file)
4036 /* only check for cert file if "we" support SSL */
4037 if(curlinfo->features & CURL_VERSION_SSL) {
4040 char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1));
4044 buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
4046 GetStr(&config->cacert, retval);
4054 #define RETRY_SLEEP_DEFAULT 1000 /* ms */
4055 #define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */
4058 output_expected(const char* url, const char* uploadfile)
4061 return TRUE; /* download */
4062 if(checkprefix("http://", url) || checkprefix("https://", url))
4063 return TRUE; /* HTTP(S) upload */
4065 return FALSE; /* non-HTTP upload, probably no output should be expected */
4068 #define my_setopt(x,y,z) _my_setopt(x, FALSE, config, #y, y, z)
4069 #define my_setopt_str(x,y,z) _my_setopt(x, TRUE, config, #y, y, z)
4071 static struct curl_slist *easycode;
4073 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
4074 const char *name, CURLoption tag, ...);
4076 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
4077 const char *name, CURLoption tag, ...)
4087 if(tag < CURLOPTTYPE_OBJECTPOINT) {
4088 long lval = va_arg(arg, long);
4089 snprintf(value, sizeof(value), "%ld", lval);
4090 ret = curl_easy_setopt(curl, tag, lval);
4093 else if(tag < CURLOPTTYPE_OFF_T) {
4094 void *pval = va_arg(arg, void *);
4095 unsigned char *ptr = (unsigned char *)pval;
4097 /* function pointers are never printable */
4098 if (tag >= CURLOPTTYPE_FUNCTIONPOINT) {
4100 snprintf(value, sizeof(value), "%p", pval);
4104 strcpy(value, "NULL");
4107 else if(pval && str)
4108 snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
4110 snprintf(value, sizeof(value), "%p", pval);
4114 strcpy(value, "NULL"); /* value fits more than 5 bytes */
4116 ret = curl_easy_setopt(curl, tag, pval);
4120 curl_off_t oval = va_arg(arg, curl_off_t);
4121 snprintf(value, sizeof(value), "%" CURL_FORMAT_CURL_OFF_T, oval);
4122 ret = curl_easy_setopt(curl, tag, oval);
4125 if(config->libcurl) {
4126 /* we only use this for real if --libcurl was used */
4128 bufp = curlx_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s",
4129 remark?"/* ":"", name, value,
4130 remark?" [REMARK] */":"");
4132 if (!bufp || !curl_slist_append(easycode, bufp))
4133 ret = CURLE_OUT_OF_MEMORY;
4142 static const char * const srchead[]={
4143 "/********* Sample code generated by the curl command line tool **********",
4144 " * Lines with [REMARK] below might need to be modified to make this code ",
4145 " * usable. Add error code checking where appropriate.",
4146 " * Compile this with a suitable header include path. Then link with ",
4148 " * If you use any *_LARGE options, make sure your compiler figure",
4149 " * out the correct size for the curl_off_t variable.",
4150 " * Read the details for all curl_easy_setopt() options online on:",
4151 " * http://curlm.haxx.se/libcurl/c/curl_easy_setopt.html",
4152 " ************************************************************************/",
4154 "#include <curl/curl.h>",
4156 "int main(int argc, char *argv[])",
4162 static void dumpeasycode(struct Configurable *config)
4164 struct curl_slist *ptr = easycode;
4165 char *o = config->libcurl;
4169 bool fopened = FALSE;
4170 if(strcmp(o, "-")) {
4171 out = fopen(o, "wt");
4177 warnf(config, "Failed to open %s to write libcurl code!\n", o);
4182 for(i=0; (c = srchead[i]); i++) {
4183 if(!memcmp((char *)c, "[m]", 3)) {
4184 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS > 32)
4185 fprintf(out, "#define _FILE_OFFSET_BITS %d "
4186 "/* for pre libcurl 7.19.0 curl_off_t magic */\n",
4191 fprintf(out, "%s\n", c);
4195 fprintf(out, " %s\n", ptr->data);
4199 " return (int)ret;\n"
4201 "/**** End of sample code ****/\n");
4206 curl_slist_free_all(easycode);
4209 static bool stdin_upload(const char *uploadfile)
4211 return (bool)(curlx_strequal(uploadfile, "-") ||
4212 curlx_strequal(uploadfile, "."));
4215 /* Adds the file name to the URL if it doesn't already have one.
4216 * url will be freed before return if the returned pointer is different
4218 static char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
4220 /* If no file name part is given in the URL, we add this file name */
4221 char *ptr=strstr(url, "://");
4226 ptr = strrchr(ptr, '/');
4227 if(!ptr || !strlen(++ptr)) {
4228 /* The URL has no file name part, add the local file name. In order
4229 to be able to do so, we have to create a new URL in another
4232 /* We only want the part of the local path that is on the right
4233 side of the rightmost slash and backslash. */
4234 const char *filep = strrchr(filename, '/');
4235 char *file2 = strrchr(filep?filep:filename, '\\');
4245 /* URL encode the file name */
4246 encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
4248 char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
4254 /* there is a trailing slash on the URL */
4255 sprintf(urlbuffer, "%s%s", url, encfile);
4257 /* there is no trailing slash on the URL */
4258 sprintf(urlbuffer, "%s/%s", url, encfile);
4263 url = urlbuffer; /* use our new URL instead! */
4269 /* Extracts the name portion of the URL.
4270 * Returns a heap-allocated string, or NULL if no name part
4272 static char *get_url_file_name(const char *url)
4276 /* Find and get the remote file name */
4277 const char * pc =strstr(url, "://");
4282 pc = strrchr(pc, '/');
4285 /* duplicate the string beyond the slash */
4287 fn = *pc ? strdup(pc): NULL;
4293 parse_filename(char *ptr, size_t len)
4300 /* simple implementation of strndup() */
4301 copy = malloc(len+1);
4304 strncpy(copy, ptr, len);
4308 if (*p == '\'' || *p == '"') {
4309 /* store the starting quote */
4314 /* if the filename contains a path, only use filename portion */
4315 q = strrchr(copy, '/');
4325 /* if the file name started with a quote, then scan for the end quote and
4327 q = strrchr(p, quote);
4332 q = NULL; /* no start quote, so no end has been found */
4335 /* make sure the file name doesn't end in \r or \n */
4336 q = strchr(p, '\r');
4340 q = strchr(p, '\n');
4346 memmove(copy, p, strlen(p)+1);
4352 header_callback(void *ptr, size_t size, size_t nmemb, void *stream)
4354 struct OutStruct* outs = (struct OutStruct*)stream;
4355 const char* str = (char*)ptr;
4356 const size_t cb = size*nmemb;
4357 const char* end = (char*)ptr + cb;
4359 if (cb > 20 && curlx_strnequal(str, "Content-disposition:", 20)) {
4360 char *p = (char*)str + 20;
4362 /* look for the 'filename=' parameter
4363 (encoded filenames (*=) are not supported) */
4367 while (*p && (p < end) && !ISALPHA(*p))
4372 if (memcmp(p, "filename=", 9)) {
4373 /* no match, find next parameter */
4374 while ((p < end) && (*p != ';'))
4379 filename = parse_filename(p, cb - (p - str));
4381 outs->filename = filename;
4391 operate(struct Configurable *config, int argc, argv_item_t argv[])
4393 char errorbuffer[CURL_ERROR_SIZE];
4394 char useragent[256]; /* buah, we don't want a larger default user agent */
4395 struct ProgressData progressbar;
4396 struct getout *urlnode;
4397 struct getout *nextnode;
4399 struct OutStruct outs;
4400 struct OutStruct heads;
4401 struct InStruct input;
4404 URLGlob *inglob=NULL;
4407 char *uploadfile=NULL; /* a single file, never a glob */
4409 curl_off_t uploadfilesize; /* -1 means unknown */
4410 bool stillflags=TRUE;
4412 bool allocuseragent=FALSE;
4414 char *httpgetfields=NULL;
4419 long retry_sleep_default;
4424 memset(&heads, 0, sizeof(struct OutStruct));
4427 /* this sends all memory debug messages to a logfile named memdump */
4428 env = curlx_getenv("CURL_MEMDEBUG");
4430 /* use the value as file name */
4431 char *s = strdup(env);
4435 /* this weird strdup() and stuff here is to make the curl_free() get
4436 called before the memdebug() as otherwise the memdebug tracing will
4437 with tracing a free() without an alloc! */
4439 env = curlx_getenv("CURL_MEMLIMIT");
4441 curl_memlimit(atoi(env));
4446 /* Initialize curl library - do not call any libcurl functions before.
4447 Note that the CURLDEBUG magic above is an exception, but then that's not
4448 part of the official public API.
4450 if (main_init() != CURLE_OK) {
4451 helpf(config->errors, "error initializing curl library\n");
4452 return CURLE_FAILED_INIT;
4456 * Get a curl handle to use for all forthcoming curl transfers. Cleanup
4457 * when all transfers are done.
4459 curl = curl_easy_init();
4461 clean_getout(config);
4462 return CURLE_FAILED_INIT;
4464 config->easy = curl;
4466 memset(&outs,0,sizeof(outs));
4468 config->outs = &outs;
4470 /* we get libcurl info right away */
4471 curlinfo = curl_version_info(CURLVERSION_NOW);
4473 errorbuffer[0]=0; /* prevent junk from being output */
4475 /* setup proper locale from environment */
4476 #ifdef HAVE_SETLOCALE
4477 setlocale(LC_ALL, "");
4481 config->postfieldsize = -1;
4482 config->showerror=TRUE;
4483 config->use_httpget=FALSE;
4484 config->create_dirs=FALSE;
4485 config->maxredirs = DEFAULT_MAXREDIRS;
4486 config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
4487 config->proto_present = FALSE;
4488 config->proto_redir =
4489 CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
4490 config->proto_redir_present = FALSE;
4493 (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
4494 strchr(argv[1], 'q')) {
4496 * The first flag, that is not a verbose name, but a shortname
4497 * and it includes the 'q' flag!
4502 parseconfig(NULL, config); /* ignore possible failure */
4505 if ((argc < 2) && !config->url_list) {
4506 helpf(config->errors, NULL);
4507 return CURLE_FAILED_INIT;
4511 for (i = 1; i < argc; i++) {
4513 ('-' == argv[i][0])) {
4516 char *origopt=argv[i];
4518 char *flag = argv[i];
4520 if(curlx_strequal("--", argv[i]))
4521 /* this indicates the end of the flags and thus enables the
4522 following (URL) argument to start with -. */
4525 nextarg= (i < argc - 1)? argv[i+1]: NULL;
4527 res = getparameter(flag, nextarg, &passarg, config);
4529 int retval = CURLE_OK;
4530 if(res != PARAM_HELP_REQUESTED) {
4531 const char *reason = param2text(res);
4532 helpf(config->errors, "option %s: %s\n", origopt, reason);
4533 retval = CURLE_FAILED_INIT;
4535 clean_getout(config);
4539 if(passarg) /* we're supposed to skip this */
4545 /* just add the URL please */
4546 res = getparameter((char *)"--url", argv[i], &used, config);
4552 retry_sleep_default = config->retry_delay?
4553 config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
4554 retry_sleep = retry_sleep_default;
4556 if((!config->url_list || !config->url_list->url) && !config->list_engines) {
4557 clean_getout(config);
4558 helpf(config->errors, "no URL specified!\n");
4559 return CURLE_FAILED_INIT;
4561 if(NULL == config->useragent) {
4562 /* set non-zero default values: */
4563 snprintf(useragent, sizeof(useragent),
4564 CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
4565 config->useragent= useragent;
4568 allocuseragent = TRUE;
4570 /* On WIN32 we can't set the path to curl-ca-bundle.crt
4571 * at compile time. So we look here for the file in two ways:
4572 * 1: look at the environment variable CURL_CA_BUNDLE for a path
4573 * 2: if #1 isn't found, use the windows API function SearchPath()
4574 * to find it along the app's path (includes app's dir and CWD)
4576 * We support the environment variable thing for non-Windows platforms
4577 * too. Just for the sake of it.
4579 if (!config->cacert &&
4581 !config->insecure_ok) {
4582 env = curlx_getenv("CURL_CA_BUNDLE");
4584 GetStr(&config->cacert, env);
4586 env = curlx_getenv("SSL_CERT_DIR");
4588 GetStr(&config->capath, env);
4590 env = curlx_getenv("SSL_CERT_FILE");
4592 GetStr(&config->cacert, env);
4600 FindWin32CACert(config, "curl-ca-bundle.crt");
4604 if (config->postfields) {
4605 if (config->use_httpget) {
4606 /* Use the postfields data for a http get */
4607 httpgetfields = strdup(config->postfields);
4608 free(config->postfields);
4609 config->postfields = NULL;
4610 if(SetHTTPrequest(config,
4611 (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
4612 &config->httpreq)) {
4613 free(httpgetfields);
4614 return PARAM_BAD_USE;
4618 if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
4619 return PARAM_BAD_USE;
4623 /* This is the first entry added to easycode and it initializes the slist */
4624 easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();");
4626 clean_getout(config);
4627 res = CURLE_OUT_OF_MEMORY;
4631 if (config->list_engines) {
4632 struct curl_slist *engines = NULL;
4634 curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
4635 list_engines(engines);
4636 curl_slist_free_all(engines);
4641 /* After this point, we should call curl_easy_cleanup() if we decide to bail
4642 * out from this function! */
4644 urlnode = config->url_list;
4646 if(config->headerfile) {
4647 /* open file for output: */
4648 if(strcmp(config->headerfile,"-")) {
4649 heads.filename = config->headerfile;
4652 heads.stream=stdout;
4653 heads.config = config;
4656 /* loop through the list of given URLs */
4658 int up; /* upload file counter within a single upload glob */
4661 char *infiles; /* might be a glob pattern */
4662 char *outfiles=NULL;
4664 /* get the full URL (it might be NULL) */
4670 /* This node had no URL, skip it and continue to the next */
4671 if(urlnode->outfile)
4672 free(urlnode->outfile);
4674 /* move on to the next URL */
4675 nextnode=urlnode->next;
4676 free(urlnode); /* free the node */
4678 continue; /* next please */
4681 /* default output stream is stdout */
4682 outs.stream = stdout;
4683 outs.config = config;
4684 outs.bytes = 0; /* nothing written yet */
4686 /* save outfile pattern before expansion */
4687 if (urlnode->outfile) {
4688 outfiles = strdup(urlnode->outfile);
4690 clean_getout(config);
4695 infiles = urlnode->infile;
4697 if(!config->globoff && infiles) {
4698 /* Unless explicitly shut off */
4699 res = glob_url(&inglob, infiles, &infilenum,
4700 config->showerror?config->errors:NULL);
4701 if(res != CURLE_OK) {
4702 clean_getout(config);
4709 /* Here's the loop for uploading multiple files within the same
4710 single globbed string. If no upload, we enter the loop once anyway. */
4712 (!up && !infiles) ||
4713 (uploadfile = inglob?
4714 glob_next_url(inglob):
4715 (!up?strdup(infiles):NULL));
4718 long retry_numretries;
4721 if(!config->globoff) {
4722 /* Unless explicitly shut off, we expand '{...}' and '[...]'
4723 expressions and return total number of URLs in pattern set */
4724 res = glob_url(&urls, dourl, &urlnum,
4725 config->showerror?config->errors:NULL);
4726 if(res != CURLE_OK) {
4731 urlnum = 1; /* without globbing, this is a single URL */
4733 /* if multiple files extracted to stdout, insert separators! */
4734 separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
4736 /* Here's looping around each globbed URL */
4738 (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
4740 /* NOTE: In the condition expression in the for() statement above, the
4741 'url' variable is only ever strdup()ed if (i == 0) and thus never
4742 when this loops later on. Further down in this function we call
4743 free(url) and then the code loops. Static code parsers may thus get
4744 tricked into believing that we have a potential access-after-free
4745 here. I can however not spot any such case. */
4747 int infd = STDIN_FILENO;
4750 struct timeval retrystart;
4751 outfile = outfiles?strdup(outfiles):NULL;
4753 if((urlnode->flags&GETOUT_USEREMOTE) ||
4754 (outfile && !curlx_strequal("-", outfile)) ) {
4757 * We have specified a file name to store the result in, or we have
4758 * decided we want to use the remote file name.
4762 /* extract the file name from the URL */
4763 outfile = get_url_file_name(url);
4764 if((!outfile || !*outfile) && !config->content_disposition) {
4765 helpf(config->errors, "Remote file name has no length!\n");
4766 res = CURLE_WRITE_ERROR;
4770 #if defined(MSDOS) || defined(WIN32)
4771 /* For DOS and WIN32, we do some major replacing of
4772 bad characters in the file name before using it */
4773 outfile = sanitize_dos_name(outfile);
4775 res = CURLE_OUT_OF_MEMORY;
4778 #endif /* MSDOS || WIN32 */
4781 /* fill '#1' ... '#9' terms from URL pattern */
4782 char *storefile = outfile;
4783 outfile = glob_match_url(storefile, urls);
4787 warnf(config, "bad output glob!\n");
4789 res = CURLE_FAILED_INIT;
4794 /* Create the directory hierarchy, if not pre-existant to a multiple
4797 if(config->create_dirs &&
4798 (-1 == create_dir_hierarchy(outfile, config->errors))) {
4800 res = CURLE_WRITE_ERROR;
4804 if(config->resume_from_current) {
4805 /* We're told to continue from where we are now. Get the
4806 size of the file as it is now and open it for append instead */
4808 struct_stat fileinfo;
4810 /* VMS -- Danger, the filesize is only valid for stream files */
4811 if(0 == stat(outfile, &fileinfo))
4812 /* set offset to current file size: */
4813 config->resume_from = fileinfo.st_size;
4815 /* let offset be 0 */
4816 config->resume_from = 0;
4819 outs.filename = outfile;
4821 if(config->resume_from) {
4822 outs.init = config->resume_from;
4823 /* open file for output: */
4824 outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
4826 helpf(config->errors, "Can't open '%s'!\n", outfile);
4828 res = CURLE_WRITE_ERROR;
4833 outs.stream = NULL; /* open when needed */
4837 if(uploadfile && !stdin_upload(uploadfile)) {
4839 * We have specified a file to upload and it isn't "-".
4841 struct_stat fileinfo;
4843 url = add_file_name_to_url(curl, url, uploadfile);
4845 helpf(config->errors, "out of memory\n");
4846 res = CURLE_OUT_OF_MEMORY;
4851 * Reading binary from files can be a problem... Only FIXED, VAR
4852 * etc WITHOUT implied CC will work Others need a \n appended to a
4855 * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
4856 * fixed file with implied CC needs to have a byte added for every
4857 * record processed, this can by derived from Filesize & recordsize
4858 * for VARiable record files the records need to be counted! for
4859 * every record add 1 for linefeed and subtract 2 for the record
4860 * header for VARIABLE header files only the bare record data needs
4861 * to be considered with one appended if implied CC
4864 infd= open(uploadfile, O_RDONLY | O_BINARY);
4865 if ((infd == -1) || fstat(infd, &fileinfo)) {
4866 helpf(config->errors, "Can't open '%s'!\n", uploadfile);
4870 /* Free the list of remaining URLs and globbed upload files
4871 * to force curl to exit immediately
4878 glob_cleanup(inglob);
4882 res = CURLE_READ_ERROR;
4886 uploadfilesize=fileinfo.st_size;
4889 else if(uploadfile && stdin_upload(uploadfile)) {
4891 infd = STDIN_FILENO;
4892 if (curlx_strequal(uploadfile, ".")) {
4893 if (curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
4895 "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
4899 if(uploadfile && config->resume_from_current)
4900 config->resume_from = -1; /* -1 will then force get-it-yourself */
4902 if(output_expected(url, uploadfile)
4903 && outs.stream && isatty(fileno(outs.stream)))
4904 /* we send the output to a tty, therefore we switch off the progress
4906 config->noprogress = config->isatty = TRUE;
4908 if (urlnum > 1 && !(config->mute)) {
4909 fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
4910 i+1, urlnum, url, outfile ? outfile : "<stdout>");
4912 printf("%s%s\n", CURLseparator, url);
4914 if (httpgetfields) {
4916 /* Find out whether the url contains a file name */
4917 const char *pc =strstr(url, "://");
4924 pc = strrchr(pc, '/'); /* check for a slash */
4927 /* there is a slash present in the URL */
4930 /* Ouch, there's already a question mark in the URL string, we
4931 then append the data with an ampersand separator instead! */
4935 * Then append ? followed by the get fields to the url.
4937 urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
4939 helpf(config->errors, "out of memory\n");
4941 /* Free the list of remaining URLs and globbed upload files
4942 * to force curl to exit immediately
4949 glob_cleanup(inglob);
4953 res = CURLE_OUT_OF_MEMORY;
4957 sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
4959 /* Append / before the ? to create a well-formed url
4960 if the url contains a hostname only
4962 sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
4964 free(url); /* free previous URL */
4965 url = urlbuffer; /* use our new URL instead! */
4969 config->errors = stderr;
4971 if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
4972 /* We get the output to stdout and we have not got the ASCII/text
4973 flag, then set stdout to be binary */
4974 SET_BINMODE(stdout);
4977 if(1 == config->tcp_nodelay)
4978 my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
4980 /* where to store */
4981 my_setopt(curl, CURLOPT_WRITEDATA, &outs);
4982 /* what call to write */
4983 my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
4987 input.config = config;
4988 my_setopt(curl, CURLOPT_READDATA, &input);
4989 /* what call to read */
4990 if ((outfile && !curlx_strequal("-", outfile)) ||
4991 !curlx_strnequal(url, "telnet:", 7))
4992 my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
4994 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
4995 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
4996 my_setopt(curl, CURLOPT_SEEKDATA, &input);
4997 my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
4999 if(config->recvpersecond)
5000 /* tell libcurl to use a smaller sized buffer as it allows us to
5001 make better sleeps! 7.9.9 stuff! */
5002 my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
5004 /* size of uploaded file: */
5005 my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
5006 my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */
5007 my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
5009 my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
5010 my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
5011 if(config->no_body) {
5012 my_setopt(curl, CURLOPT_NOBODY, 1);
5013 my_setopt(curl, CURLOPT_HEADER, 1);
5016 my_setopt(curl, CURLOPT_HEADER, config->include_headers);
5018 my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
5019 my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
5020 my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
5021 my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
5023 if (config->netrc_opt)
5024 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
5025 else if (config->netrc)
5026 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
5028 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
5030 my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
5031 my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth);
5032 my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
5033 my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
5034 my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
5035 my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
5036 my_setopt_str(curl, CURLOPT_RANGE, config->range);
5037 my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
5038 my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
5040 switch(config->httpreq) {
5041 case HTTPREQ_SIMPLEPOST:
5042 my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields);
5043 my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize);
5046 my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
5051 my_setopt_str(curl, CURLOPT_REFERER, config->referer);
5052 my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
5053 my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
5054 my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
5055 my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
5056 config->low_speed_limit);
5057 my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
5058 my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
5059 config->sendpersecond);
5060 my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
5061 config->recvpersecond);
5062 my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
5063 config->use_resume?config->resume_from:0);
5064 my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
5065 my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
5066 my_setopt(curl, CURLOPT_SSLCERT, config->cert);
5067 my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
5068 my_setopt(curl, CURLOPT_SSLKEY, config->key);
5069 my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
5070 my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
5072 /* SSH private key uses the same command-line option as SSL private
5074 my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
5075 my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
5077 /* SSH host key md5 checking allows us to fail if we are
5078 * not talking to who we think we should
5080 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
5081 config->hostpubmd5);
5083 /* default to strict verifyhost */
5084 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
5085 if(config->cacert || config->capath) {
5087 my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
5090 my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
5091 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
5093 if (config->crlfile)
5094 my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
5095 if(config->insecure_ok) {
5096 /* new stuff needed for libcurl 7.10 */
5097 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
5098 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
5101 char *home = homedir();
5102 char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
5107 my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
5111 /* Free the list of remaining URLs and globbed upload files
5112 * to force curl to exit immediately
5119 glob_cleanup(inglob);
5123 res = CURLE_OUT_OF_MEMORY;
5128 if(config->no_body || config->remote_time) {
5129 /* no body or use remote time */
5130 my_setopt(curl, CURLOPT_FILETIME, TRUE);
5133 my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
5134 my_setopt(curl, CURLOPT_CRLF, config->crlf);
5135 my_setopt(curl, CURLOPT_QUOTE, config->quote);
5136 my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
5137 my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
5138 my_setopt(curl, CURLOPT_HEADERDATA,
5139 config->headerfile?&heads:NULL);
5140 my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
5141 /* cookie jar was added in 7.9 */
5142 if(config->cookiejar)
5143 my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
5144 /* cookie session added in 7.9.7 */
5145 my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
5147 my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
5148 my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
5149 my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
5150 my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
5151 my_setopt(curl, CURLOPT_STDERR, config->errors);
5153 /* three new ones in libcurl 7.3: */
5154 my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
5155 my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
5156 my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
5158 progressbarinit(&progressbar, config);
5159 if((config->progressmode == CURL_PROGRESS_BAR) &&
5160 !config->noprogress && !config->mute) {
5161 /* we want the alternative style, then we have to implement it
5163 my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
5164 my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
5167 /* new in libcurl 7.6.2: */
5168 my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
5170 /* new in libcurl 7.7: */
5171 my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
5172 my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
5173 my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
5175 if(config->cipher_list)
5176 my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
5178 if(config->httpversion)
5179 my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
5181 /* new in libcurl 7.9.2: */
5182 if(config->disable_epsv)
5184 my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
5186 /* new in libcurl 7.10.5 */
5187 if(config->disable_eprt)
5189 my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
5191 /* new in libcurl 7.10.6 (default is Basic) */
5192 if(config->authtype)
5193 my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
5195 if(config->tracetype != TRACE_NONE) {
5196 my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
5197 my_setopt(curl, CURLOPT_DEBUGDATA, config);
5198 my_setopt(curl, CURLOPT_VERBOSE, TRUE);
5203 /* new in curl ?? */
5204 if (config->engine) {
5205 res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
5206 my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
5209 if (res != CURLE_OK)
5212 /* new in curl 7.10 */
5213 my_setopt_str(curl, CURLOPT_ENCODING,
5214 (config->encoding) ? "" : NULL);
5216 /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
5217 my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
5218 config->ftp_create_dirs);
5219 if(config->proxyanyauth)
5220 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
5221 else if(config->proxynegotiate)
5222 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
5223 else if(config->proxyntlm)
5224 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
5225 else if(config->proxydigest)
5226 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
5227 else if(config->proxybasic)
5228 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
5230 /* new in curl 7.10.8 */
5231 if(config->max_filesize)
5232 my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
5233 config->max_filesize);
5235 if(4 == config->ip_version)
5236 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
5237 else if(6 == config->ip_version)
5238 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
5240 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
5242 /* new in curl 7.15.5 */
5243 if(config->ftp_ssl_reqd)
5244 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
5246 /* new in curl 7.11.0 */
5247 else if(config->ftp_ssl)
5248 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
5250 /* new in curl 7.16.0 */
5251 else if(config->ftp_ssl_control)
5252 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
5254 /* new in curl 7.16.1 */
5255 if(config->ftp_ssl_ccc)
5256 my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
5258 /* new in curl 7.11.1, modified in 7.15.2 */
5259 if(config->socksproxy) {
5260 my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
5261 my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
5264 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
5265 /* new in curl 7.19.4 */
5266 if(config->socks5_gssapi_service)
5267 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
5268 config->socks5_gssapi_service);
5270 /* new in curl 7.19.4 */
5271 if(config->socks5_gssapi_nec)
5272 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
5273 config->socks5_gssapi_nec);
5276 my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
5278 my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
5281 my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
5284 my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
5287 if(config->localport) {
5288 my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
5289 my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
5290 config->localportrange);
5294 my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
5295 config->ftp_alternative_to_user);
5298 my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
5299 !config->disable_sessionid);
5303 my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
5304 my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
5308 if (!config->nokeepalive) {
5309 my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
5310 my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
5313 /* curl 7.19.1 (the 301 version existed in 7.18.2) */
5314 my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
5315 (config->post302 ? CURL_REDIR_POST_302 : FALSE));
5318 if(config->tftp_blksize)
5319 my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
5321 if(config->mail_from)
5322 my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
5324 if(config->mail_rcpt)
5325 my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
5328 if(config->ftp_pret)
5329 my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
5331 if (config->proto_present)
5332 my_setopt(curl, CURLOPT_PROTOCOLS, config->proto);
5333 if (config->proto_redir_present)
5334 my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
5336 if ((urlnode->flags & GETOUT_USEREMOTE)
5337 && config->content_disposition) {
5338 my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
5339 my_setopt(curl, CURLOPT_HEADERDATA, &outs);
5342 retry_numretries = config->req_retry;
5344 retrystart = cutil_tvnow();
5347 res = curl_easy_perform(curl);
5348 if (!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
5349 res = CURLE_OUT_OF_MEMORY;
5353 if (config->content_disposition && outs.stream && !config->mute)
5354 printf("curl: Saved to filename '%s'\n", outs.filename);
5356 /* if retry-max-time is non-zero, make sure we haven't exceeded the
5358 if(retry_numretries &&
5359 (!config->retry_maxtime ||
5360 (cutil_tvdiff(cutil_tvnow(), retrystart)<
5361 config->retry_maxtime*1000)) ) {
5367 RETRY_LAST /* not used */
5370 if(CURLE_OPERATION_TIMEDOUT == res)
5371 /* retry timeout always */
5372 retry = RETRY_TIMEOUT;
5373 else if(CURLE_OK == res) {
5374 /* Check for HTTP transient errors */
5375 char *this_url=NULL;
5376 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url);
5378 curlx_strnequal(this_url, "http", 4)) {
5379 /* This was HTTP(S) */
5380 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5383 case 500: /* Internal Server Error */
5384 case 502: /* Bad Gateway */
5385 case 503: /* Service Unavailable */
5386 case 504: /* Gateway Timeout */
5389 * At this point, we have already written data to the output
5390 * file (or terminal). If we write to a file, we must rewind
5391 * or close/re-open the file so that the next attempt starts
5392 * over from the beginning.
5394 * TODO: similar action for the upload case. We might need
5395 * to start over reading from a previous point if we have
5396 * uploaded something when this was returned.
5403 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5405 if(response/100 == 4)
5407 * This is typically when the FTP server only allows a certain
5408 * amount of users and we are not one of them. All 4xx codes
5415 static const char * const m[]={
5416 NULL, "timeout", "HTTP error", "FTP error"
5418 warnf(config, "Transient problem: %s "
5419 "Will retry in %ld seconds. "
5420 "%ld retries left.\n",
5421 m[retry], retry_sleep/1000, retry_numretries);
5423 go_sleep(retry_sleep);
5425 if(!config->retry_delay) {
5427 if(retry_sleep > RETRY_SLEEP_MAX)
5428 retry_sleep = RETRY_SLEEP_MAX;
5430 if(outs.bytes && outs.filename) {
5431 /* We have written data to a output file, we truncate file
5434 fprintf(config->errors, "Throwing away %"
5435 CURL_FORMAT_CURL_OFF_T " bytes\n",
5437 fflush(outs.stream);
5438 /* truncate file at the position where we started appending */
5439 #ifdef HAVE_FTRUNCATE
5440 if(ftruncate( fileno(outs.stream), outs.init)) {
5441 /* when truncate fails, we can't just append as then we'll
5442 create something strange, bail out */
5444 fprintf(config->errors,
5445 "failed to truncate, exiting\n");
5448 /* now seek to the end of the file, the position where we
5449 just truncated the file in a large file-safe way */
5450 fseek(outs.stream, 0, SEEK_END);
5452 /* ftruncate is not available, so just reposition the file
5453 to the location we would have truncated it. This won't
5454 work properly with large files on 32-bit systems, but
5455 most of those will have ftruncate. */
5456 fseek(outs.stream, (long)outs.init, SEEK_SET);
5458 outs.bytes = 0; /* clear for next round */
5462 } /* if retry_numretries */
5464 /* In all ordinary cases, just break out of loop here */
5465 retry_sleep = retry_sleep_default;
5470 if((config->progressmode == CURL_PROGRESS_BAR) &&
5472 /* if the custom progress bar has been displayed, we output a
5474 fputs("\n", progressbar.out);
5476 if(config->writeout)
5477 ourWriteOut(curl, config->writeout);
5478 #ifdef USE_ENVIRONMENT
5479 if (config->writeenv)
5486 if(is_vms_shell()) {
5487 /* VMS DCL shell behavior */
5488 if(!config->showerror) {
5489 vms_show = VMSSTS_HIDE;
5495 if((res!=CURLE_OK) && config->showerror) {
5496 fprintf(config->errors, "curl: (%d) %s\n", res,
5497 errorbuffer[0]? errorbuffer:
5498 curl_easy_strerror((CURLcode)res));
5499 if(CURLE_SSL_CACERT == res) {
5500 #define CURL_CA_CERT_ERRORMSG1 \
5501 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
5502 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
5503 " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
5504 " bundle file isn't adequate, you can specify an alternate file\n" \
5505 " using the --cacert option.\n"
5507 #define CURL_CA_CERT_ERRORMSG2 \
5508 "If this HTTPS server uses a certificate signed by a CA represented in\n" \
5509 " the bundle, the certificate verification probably failed due to a\n" \
5510 " problem with the certificate (it might be expired, or the name might\n" \
5511 " not match the domain name in the URL).\n" \
5512 "If you'd like to turn off curl's verification of the certificate, use\n" \
5513 " the -k (or --insecure) option.\n"
5515 fprintf(config->errors, "%s%s",
5516 CURL_CA_CERT_ERRORMSG1,
5517 CURL_CA_CERT_ERRORMSG2 );
5522 if (outfile && !curlx_strequal(outfile, "-") && outs.stream) {
5523 int rc = fclose(outs.stream);
5525 /* something went wrong in the writing process */
5526 res = CURLE_WRITE_ERROR;
5527 fprintf(config->errors, "(%d) Failed writing body\n", res);
5532 /* Important that we set the time _after_ the file has been
5533 closed, as is done above here */
5534 if(config->remote_time && outs.filename) {
5535 /* ask libcurl if we got a time. Pretty please */
5537 curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
5539 struct utimbuf times;
5540 times.actime = (time_t)filetime;
5541 times.modtime = (time_t)filetime;
5542 utime(outs.filename, ×); /* set the time we got */
5547 /* Set the url as comment for the file. (up to 80 chars are allowed)
5549 if( strlen(url) > 78 )
5552 SetComment( outs.filename, url);
5565 } /* loop to the next URL */
5568 /* cleanup memory used for URL globbing patterns */
5576 } /* loop to the next globbed upload file */
5579 glob_cleanup(inglob);
5586 /* empty this urlnode struct */
5589 if(urlnode->outfile)
5590 free(urlnode->outfile);
5592 free(urlnode->infile);
5594 /* move on to the next URL */
5595 nextnode=urlnode->next;
5596 free(urlnode); /* free the node */
5599 } /* while-loop through all URLs */
5603 free(httpgetfields);
5606 free(config->engine);
5608 /* cleanup the curl handle! */
5609 curl_easy_cleanup(curl);
5610 config->easy = NULL; /* cleanup now */
5612 curl_slist_append(easycode, "curl_easy_cleanup(hnd);");
5614 if(heads.stream && (heads.stream != stdout))
5615 fclose(heads.stream);
5618 free(config->useragent);
5620 if(config->trace_fopened && config->trace_stream)
5621 fclose(config->trace_stream);
5623 /* Dump the libcurl code if previously enabled.
5624 NOTE: that this function relies on config->errors amongst other things
5625 so not everything can be closed and cleaned before this is called */
5626 dumpeasycode(config);
5628 if(config->errors_fopened)
5629 fclose(config->errors);
5631 main_free(); /* cleanup */
5636 /* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
5637 open before starting to run. Otherwise, the first three network
5638 sockets opened by curl could be used for input sources, downloaded data
5639 or error logs as they will effectively be stdin, stdout and/or stderr.
5641 static void checkfds(void)
5644 int fd[2] = { STDIN_FILENO, STDIN_FILENO };
5645 while( fd[0] == STDIN_FILENO ||
5646 fd[0] == STDOUT_FILENO ||
5647 fd[0] == STDERR_FILENO ||
5648 fd[1] == STDIN_FILENO ||
5649 fd[1] == STDOUT_FILENO ||
5650 fd[1] == STDERR_FILENO )
5652 return; /* Out of handles. This isn't really a big problem now, but
5653 will be when we try to create a socket later. */
5661 int main(int argc, char *argv[])
5664 struct Configurable config;
5666 memset(&config, 0, sizeof(struct Configurable));
5668 config.errors = stderr; /* default errors to stderr */
5672 res = operate(&config, argc, argv);
5673 #ifdef __SYMBIAN32__
5674 if (config.showerror)
5677 free_config_fields(&config);
5679 #ifdef __NOVELL_LIBC__
5680 if (getenv("_IN_NETWARE_BASH_") == NULL)
5684 vms_special_exit(res, vms_show);
5691 * Reads a line from the given file, ensuring is NUL terminated.
5692 * The pointer must be freed by the caller.
5693 * NULL is returned on an out of memory condition.
5695 static char *my_get_line(FILE *fp)
5699 char *retval = NULL;
5702 if (NULL == fgets(buf, sizeof(buf), fp))
5704 if (NULL == retval) {
5705 retval = strdup(buf);
5711 ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
5717 strcat(retval, buf);
5720 while (NULL == (nl = strchr(retval, '\n')));
5728 static void show_dir_errno(FILE *errors, const char *name)
5733 fprintf(errors,"You don't have permission to create %s.\n", name);
5738 fprintf(errors,"The directory name %s is too long.\n", name);
5743 fprintf(errors,"%s resides on a read-only file system.\n", name);
5748 fprintf(errors,"No space left on the file system that will "
5749 "contain the directory %s.\n", name);
5754 fprintf(errors,"Cannot create directory %s because you "
5755 "exceeded your quota.\n", name);
5759 fprintf(errors,"Error creating directory %s.\n", name);
5764 /* Create the needed directory hierarchy recursively in order to save
5765 multi-GETs in file output, ie:
5766 curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
5767 should create all the dir* automagically
5769 static int create_dir_hierarchy(const char *outfile, FILE *errors)
5777 outdup = strdup(outfile);
5781 dirbuildup = malloc(sizeof(char) * strlen(outfile));
5786 dirbuildup[0] = '\0';
5788 tempdir = strtok(outdup, DIR_CHAR);
5790 while (tempdir != NULL) {
5791 tempdir2 = strtok(NULL, DIR_CHAR);
5792 /* since strtok returns a token for the last word even
5793 if not ending with DIR_CHAR, we need to prune it */
5794 if (tempdir2 != NULL) {
5795 size_t dlen = strlen(dirbuildup);
5797 sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
5799 if (0 != strncmp(outdup, DIR_CHAR, 1))
5800 strcpy(dirbuildup, tempdir);
5802 sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
5804 if (access(dirbuildup, F_OK) == -1) {
5805 result = mkdir(dirbuildup,(mode_t)0000750);
5807 show_dir_errno(errors, dirbuildup);
5808 break; /* get out of loop */
5817 return result; /* 0 is fine, -1 is badness */
5820 #if defined(MSDOS) || defined(WIN32)
5822 #ifndef HAVE_BASENAME
5823 /* basename() returns a pointer to the last component of a pathname.
5824 * Ripped from lib/formdata.c.
5826 static char *Curl_basename(char *path)
5828 /* Ignore all the details above for now and make a quick and simple
5829 implementaion here */
5833 s1=strrchr(path, '/');
5834 s2=strrchr(path, '\\');
5837 path = (s1 > s2? s1 : s2)+1;
5846 #define basename(x) Curl_basename((x))
5847 #endif /* HAVE_BASENAME */
5849 /* The following functions are taken with modification from the DJGPP
5850 * port of tar 1.12. They use algorithms originally from DJTAR. */
5853 msdosify (const char *file_name)
5855 static char dos_name[PATH_MAX];
5856 static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
5857 "|<>\\\":?*"; /* illegal in DOS & W95 */
5858 static const char *illegal_chars_w95 = &illegal_chars_dos[8];
5860 const char *s = file_name;
5862 const char * const dlimit = dos_name + sizeof(dos_name) - 1;
5863 const char *illegal_aliens = illegal_chars_dos;
5864 size_t len = sizeof (illegal_chars_dos) - 1;
5866 /* Support for Windows 9X VFAT systems, when available. */
5867 if (_use_lfn (file_name)) {
5868 illegal_aliens = illegal_chars_w95;
5869 len -= (illegal_chars_w95 - illegal_chars_dos);
5872 /* Get past the drive letter, if any. */
5873 if (s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
5878 for (idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
5879 if (memchr (illegal_aliens, *s, len)) {
5880 /* Dots are special: DOS doesn't allow them as the leading character,
5881 and a file name cannot have more than a single dot. We leave the
5882 first non-leading dot alone, unless it comes too close to the
5883 beginning of the name: we want sh.lex.c to become sh_lex.c, not
5886 if (idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
5887 /* Copy "./" and "../" verbatim. */
5895 else if (dot_idx >= 0) {
5896 if (dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
5897 d[dot_idx - idx] = '_'; /* replace previous dot */
5909 else if (*s == '+' && s[1] == '+') {
5910 if (idx - 2 == dot_idx) { /* .c++, .h++ etc. */
5916 memcpy (d, "plus", 4);
5940 rename_if_dos_device_name (char *file_name)
5942 /* We could have a file whose name is a device on MS-DOS. Trying to
5943 * retrieve such a file would fail at best and wedge us at worst. We need
5944 * to rename such files. */
5947 char fname[PATH_MAX];
5949 strncpy(fname, file_name, PATH_MAX-1);
5950 fname[PATH_MAX-1] = 0;
5951 base = basename(fname);
5952 if (((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
5953 size_t blen = strlen (base);
5955 if (strlen(fname) >= PATH_MAX-1) {
5956 /* Make room for the '_' */
5960 /* Prepend a '_'. */
5961 memmove (base + 1, base, blen + 1);
5963 strcpy (file_name, fname);
5968 /* Replace bad characters in the file name before using it.
5969 * fn will always be freed before return
5970 * The returned pointer must be freed by the caller if not NULL
5972 static char *sanitize_dos_name(char *fn)
5974 char tmpfn[PATH_MAX];
5975 if(strlen(fn) >= PATH_MAX)
5976 fn[PATH_MAX-1]=0; /* truncate it */
5977 strcpy(tmpfn, msdosify(fn));
5979 return strdup(rename_if_dos_device_name(tmpfn));
5981 #endif /* MSDOS || WIN32 */