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;
481 curl_off_t resume_from;
483 curl_off_t postfieldsize;
488 curl_off_t max_filesize;
494 unsigned short porttouse;
496 long low_speed_limit;
502 int proxyver; /* set to CURLPROXY_HTTP* define */
505 struct curl_slist *mail_rcpt;
507 bool ftp_append; /* APPE on ftp */
508 bool mute; /* shutup */
509 bool use_ascii; /* select ascii or text transfer */
510 bool autoreferer; /* automatically set referer */
511 bool failonerror; /* fail on (HTTP) errors */
512 bool include_headers; /* send headers to data output */
513 bool no_body; /* don't get the body */
514 bool dirlistonly; /* only get the FTP dir list */
515 bool followlocation; /* follow http redirects */
516 bool unrestricted_auth; /* Continue to send authentication (user+password)
517 when following ocations, even when hostname
522 bool isatty; /* updated internally only if the output is a tty */
523 struct getout *url_list; /* point to the first node */
524 struct getout *url_last; /* point to the last/current node */
525 struct getout *url_get; /* point to the node to fill in URL */
526 struct getout *url_out; /* point to the node to fill in outfile */
543 char *trace_dump; /* file to dump the network trace to, or NULL */
547 bool tracetime; /* include timestamp? */
551 bool readbusy; /* set when reading input returns EAGAIN */
554 bool insecure_ok; /* set TRUE to allow insecure SSL connects */
556 bool ftp_create_dirs;
563 char *writeout; /* %-styled format string to output */
564 bool writeenv; /* write results to environment, if available */
565 FILE *errors; /* if stderr redirect is requested */
567 struct curl_slist *quote;
568 struct curl_slist *postquote;
569 struct curl_slist *prequote;
572 curl_TimeCond timecond;
574 struct curl_slist *headers;
575 struct curl_httppost *httppost;
576 struct curl_httppost *last_post;
577 struct curl_slist *telnet_options;
580 /* for bandwidth limiting features: */
581 curl_off_t sendpersecond; /* send to peer */
582 curl_off_t recvpersecond; /* receive from peer */
586 bool ftp_ssl_control;
588 int ftp_ssl_ccc_mode;
590 char *socksproxy; /* set to server string */
591 int socksver; /* set to CURLPROXY_SOCKS* define */
592 char *socks5_gssapi_service; /* set service name for gssapi principal
594 int socks5_gssapi_nec ; /* The NEC reference server does not protect
595 * the encryption type exchange */
598 long req_retry; /* number of retries */
599 long retry_delay; /* delay between retries (in seconds) */
600 long retry_maxtime; /* maximum time to keep retrying */
602 char *ftp_account; /* for ACCT */
603 char *ftp_alternative_to_user; /* send command if USER/PASS fails */
605 long tftp_blksize; /* TFTP BLKSIZE option */
606 bool ignorecl; /* --ignore-content-length */
607 bool disable_sessionid;
609 char *libcurl; /* output libcurl code to this file name */
613 bool nokeepalive; /* for keepalive needs */
615 bool content_disposition; /* use Content-disposition filename */
617 int default_node_flags; /* default flags to seach for each 'node', which is
618 basically each given URL to transfer */
619 struct OutStruct *outs;
622 #define WARN_PREFIX "Warning: "
623 #define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
624 /* produce this text message to the user unless mute was selected */
625 static void warnf(struct Configurable *config, const char *fmt, ...)
631 char print_buffer[256];
634 len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
639 fputs(WARN_PREFIX, config->errors);
641 if(len > (int)WARN_TEXTWIDTH) {
642 int cut = WARN_TEXTWIDTH-1;
644 while(!ISSPACE(ptr[cut]) && cut) {
648 /* not a single cutting position was found, just cut it at the
649 max text width then! */
650 cut = WARN_TEXTWIDTH-1;
652 (void)fwrite(ptr, cut + 1, 1, config->errors);
653 fputs("\n", config->errors);
654 ptr += cut+1; /* skip the space too */
658 fputs(ptr, config->errors);
666 * This is the main global constructor for the app. Call this before
667 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
668 * used, or havoc may be the result.
670 static CURLcode main_init(void)
673 /* stop stat() wasting time */
674 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
677 return curl_global_init(CURL_GLOBAL_DEFAULT);
681 * This is the main global destructor for the app. Call this after
682 * _all_ libcurl usage is done.
684 static void main_free(void)
686 curl_global_cleanup();
687 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
688 /* close iconv conversion descriptor */
689 if(inbound_cd != (iconv_t)-1)
690 iconv_close(inbound_cd);
691 if(outbound_cd != (iconv_t)-1)
692 iconv_close(outbound_cd);
693 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
696 static int SetHTTPrequest(struct Configurable *config,
697 HttpReq req, HttpReq *store)
699 if((*store == HTTPREQ_UNSPEC) ||
704 warnf(config, "You can only select one HTTP request!\n");
708 static void helpf(FILE *errors, const char *fmt, ...)
713 fputs("curl: ", errors); /* prefix it */
714 vfprintf(errors, fmt, ap);
717 fprintf(errors, "curl: try 'curl --help' "
719 "or 'curl --manual' "
721 "for more information\n");
725 * A chain of these nodes contain URL to get and where to put the URL's
729 struct getout *next; /* next one */
730 char *url; /* the URL we deal with */
731 char *outfile; /* where to store the output */
732 char *infile; /* file to upload, if GETOUT_UPLOAD is set */
733 int flags; /* options */
735 #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
736 #define GETOUT_URL (1<<1) /* set when URL is deemed done */
737 #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
738 #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
739 #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
741 static void help(void)
744 /* A few of these source lines are >80 columns wide, but that's only because
745 breaking the strings narrower makes this chunk look even worse!
747 Starting with 7.18.0, this list of command line options is sorted based
748 on the long option name. It is not done automatically, although a command
749 line like the following can help out:
751 curl --help | cut -c5- | grep "^-" | sort
753 static const char * const helptext[]={
754 "Usage: curl [options...] <url>",
755 "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
756 " --anyauth Pick \"any\" authentication method (H)",
757 " -a/--append Append to target file when uploading (F/SFTP)",
758 " --basic Use HTTP Basic Authentication (H)",
759 " --cacert <file> CA certificate to verify peer against (SSL)",
760 " --capath <directory> CA directory to verify peer against (SSL)",
761 " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
762 " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
763 " --ciphers <list> SSL ciphers to use (SSL)",
764 " --compressed Request compressed response (using deflate or gzip)",
765 " -K/--config <file> Specify which config file to read",
766 " --connect-timeout <seconds> Maximum time allowed for connection",
767 " -C/--continue-at <offset> Resumed transfer offset",
768 " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
769 " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
770 " --create-dirs Create necessary local directory hierarchy",
771 " --crlf Convert LF to CRLF in upload",
772 " --crlfile <file> Get a CRL list in PEM format from the given file",
773 " -d/--data <data> HTTP POST data (H)",
774 " --data-ascii <data> HTTP POST ASCII data (H)",
775 " --data-binary <data> HTTP POST binary data (H)",
776 " --data-urlencode <name=data/name@filename> HTTP POST data url encoded (H)",
777 " --digest Use HTTP Digest Authentication (H)",
778 " --disable-eprt Inhibit using EPRT or LPRT (F)",
779 " --disable-epsv Inhibit using EPSV (F)",
780 " -D/--dump-header <file> Write the headers to this file",
781 " --egd-file <file> EGD socket path for random data (SSL)",
782 " --engine <eng> Crypto engine to use (SSL). \"--engine list\" for list",
783 #ifdef USE_ENVIRONMENT
784 " --environment Write results to environment variables (RISC OS)",
786 " -f/--fail Fail silently (no output at all) on HTTP errors (H)",
787 " -F/--form <name=content> Specify HTTP multipart POST data (H)",
788 " --form-string <name=string> Specify HTTP multipart POST data (H)",
789 " --ftp-account <data> Account data to send when requested by server (F)",
790 " --ftp-alternative-to-user <cmd> String to replace \"USER [name]\" (F)",
791 " --ftp-create-dirs Create the remote dirs if not present (F)",
792 " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
793 " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
794 " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
795 " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
796 " --ftp-pret Send PRET before PASV (for drftpd) (F)",
797 " --ftp-ssl-ccc Send CCC after authenticating (F)",
798 " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
799 " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
800 " -G/--get Send the -d data with a HTTP GET (H)",
801 " -g/--globoff Disable URL sequences and ranges using {} and []",
802 " -H/--header <line> Custom header to pass to server (H)",
803 " -I/--head Show document info only",
804 " -h/--help This help text",
805 " --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
806 " -0/--http1.0 Use HTTP 1.0 (H)",
807 " --ignore-content-length Ignore the HTTP Content-Length header",
808 " -i/--include Include protocol headers in the output (H/F)",
809 " -k/--insecure Allow connections to SSL sites without certs (H)",
810 " --interface <interface> Specify network interface/address to use",
811 " -4/--ipv4 Resolve name to IPv4 address",
812 " -6/--ipv6 Resolve name to IPv6 address",
813 " -j/--junk-session-cookies Ignore session cookies read from file (H)",
814 " --keepalive-time <seconds> Interval between keepalive probes",
815 " --key <key> Private key file name (SSL/SSH)",
816 " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
817 " --krb <level> Enable Kerberos with specified security level (F)",
818 " --libcurl <file> Dump libcurl equivalent code of this command line",
819 " --limit-rate <rate> Limit transfer speed to this rate",
820 " -J/--remote-header-name Use the header-provided filename (H)",
821 " -l/--list-only List only names of an FTP directory (F)",
822 " --local-port <num>[-num] Force use of these local port numbers",
823 " -L/--location Follow Location: hints (H)",
824 " --location-trusted Follow Location: and send auth to other hosts (H)",
825 " -M/--manual Display the full manual",
826 " --mail-from <from> Mail from this address",
827 " --mail-rcpt <to> Mail to this receiver(s)",
828 " --max-filesize <bytes> Maximum file size to download (H/F)",
829 " --max-redirs <num> Maximum number of redirects allowed (H)",
830 " -m/--max-time <seconds> Maximum time allowed for the transfer",
831 " --negotiate Use HTTP Negotiate Authentication (H)",
832 " -n/--netrc Must read .netrc for user name and password",
833 " --netrc-optional Use either .netrc or URL; overrides -n",
834 " -N/--no-buffer Disable buffering of the output stream",
835 " --no-keepalive Disable keepalive use on the connection",
836 " --no-sessionid Disable SSL session-ID reusing (SSL)",
837 " --noproxy Comma-separated list of hosts which do not use proxy",
838 " --ntlm Use HTTP NTLM authentication (H)",
839 " -o/--output <file> Write output to <file> instead of stdout",
840 " --pass <pass> Pass phrase for the private key (SSL/SSH)",
841 " --post301 Do not switch to GET after following a 301 redirect (H)",
842 " --post302 Do not switch to GET after following a 302 redirect (H)",
843 " -#/--progress-bar Display transfer progress as a progress bar",
844 " -x/--proxy <host[:port]> Use HTTP proxy on given port",
845 " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
846 " --proxy-basic Use Basic authentication on the proxy (H)",
847 " --proxy-digest Use Digest authentication on the proxy (H)",
848 " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
849 " --proxy-ntlm Use NTLM authentication on the proxy (H)",
850 " -U/--proxy-user <user[:password]> Set proxy user and password",
851 " --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port",
852 " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
853 " --pubkey <key> Public key file name (SSH)",
854 " -Q/--quote <cmd> Send command(s) to server before file transfer (F/SFTP)",
855 " --random-file <file> File for reading random data from (SSL)",
856 " -r/--range <range> Retrieve only the bytes within a range",
857 " --raw Pass HTTP \"raw\", without any transfer decoding (H)",
858 " -e/--referer Referer URL (H)",
859 " -O/--remote-name Write output to a file named as the remote file",
860 " --remote-name-all Use the remote file name for all URLs",
861 " -R/--remote-time Set the remote file's time on the local output",
862 " -X/--request <command> Specify request command to use",
863 " --retry <num> Retry request <num> times if transient problems occur",
864 " --retry-delay <seconds> When retrying, wait this many seconds between each",
865 " --retry-max-time <seconds> Retry only within this period",
866 " -S/--show-error Show error. With -s, make curl show errors when they occur",
867 " -s/--silent Silent mode. Don't output anything",
868 " --socks4 <host[:port]> SOCKS4 proxy on given host + port",
869 " --socks4a <host[:port]> SOCKS4a proxy on given host + port",
870 " --socks5 <host[:port]> SOCKS5 proxy on given host + port",
871 " --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy",
872 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
873 " --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi",
874 " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
876 " -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
877 " -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
878 " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
879 " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
880 " -2/--sslv2 Use SSLv2 (SSL)",
881 " -3/--sslv3 Use SSLv3 (SSL)",
882 " --stderr <file> Where to redirect stderr. - means stdout",
883 " --tcp-nodelay Use the TCP_NODELAY option",
884 " -t/--telnet-option <OPT=val> Set telnet option",
885 " --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)",
886 " -z/--time-cond <time> Transfer based on a time condition",
887 " -1/--tlsv1 Use TLSv1 (SSL)",
888 " --trace <file> Write a debug trace to the given file",
889 " --trace-ascii <file> Like --trace but without the hex output",
890 " --trace-time Add time stamps to trace/verbose output",
891 " -T/--upload-file <file> Transfer <file> to remote site",
892 " --url <URL> Set URL to work with",
893 " -B/--use-ascii Use ASCII/text transfer",
894 " -u/--user <user[:password]> Set server user and password",
895 " -A/--user-agent <string> User-Agent to send to server (H)",
896 " -v/--verbose Make the operation more talkative",
897 " -V/--version Show version number and quit",
900 " --wdebug Turn on Watt-32 debugging",
902 " -w/--write-out <format> What to output after completion",
903 " -q If used as the first parameter disables .curlrc",
906 for(i=0; helptext[i]; i++) {
908 #ifdef PRINT_LINES_PAUSE
909 if (i && ((i % PRINT_LINES_PAUSE) == 0))
921 /* global variable to hold info about libcurl */
922 static curl_version_info_data *curlinfo;
924 static int parseconfig(const char *filename,
925 struct Configurable *config);
926 static char *my_get_line(FILE *fp);
927 static int create_dir_hierarchy(const char *outfile, FILE *errors);
929 static void GetStr(char **string,
935 *string = strdup(value);
940 static void clean_getout(struct Configurable *config)
942 struct getout *node=config->url_list;
955 node = next; /* GOTO next */
959 static struct getout *new_getout(struct Configurable *config)
961 struct getout *node =malloc(sizeof(struct getout));
962 struct getout *last= config->url_last;
964 /* clear the struct */
965 memset(node, 0, sizeof(struct getout));
967 /* append this new node last in the list */
971 config->url_list = node; /* first node */
973 /* move the last pointer */
974 config->url_last = node;
976 node->flags = config->default_node_flags;
981 /* Structure for storing the information needed to build a multiple files
985 struct curl_forms form;
986 struct multi_files *next;
989 /* Add a new list entry possibly with a type_name
991 static struct multi_files *
992 AddMultiFiles (const char *file_name,
993 const char *type_name,
994 const char *show_filename,
995 struct multi_files **multi_start,
996 struct multi_files **multi_current)
998 struct multi_files *multi;
999 struct multi_files *multi_type = NULL;
1000 struct multi_files *multi_name = NULL;
1001 multi = malloc(sizeof(struct multi_files));
1003 memset(multi, 0, sizeof(struct multi_files));
1004 multi->form.option = CURLFORM_FILE;
1005 multi->form.value = file_name;
1011 *multi_start = multi;
1014 multi_type = malloc(sizeof(struct multi_files));
1016 memset(multi_type, 0, sizeof(struct multi_files));
1017 multi_type->form.option = CURLFORM_CONTENTTYPE;
1018 multi_type->form.value = type_name;
1019 multi->next = multi_type;
1028 if (show_filename) {
1029 multi_name = malloc(sizeof(struct multi_files));
1031 memset(multi_name, 0, sizeof(struct multi_files));
1032 multi_name->form.option = CURLFORM_FILENAME;
1033 multi_name->form.value = show_filename;
1034 multi->next = multi_name;
1045 (*multi_current)->next = multi;
1047 *multi_current = multi;
1049 return *multi_current;
1052 /* Free the items of the list.
1054 static void FreeMultiInfo (struct multi_files *multi_start)
1056 struct multi_files *multi;
1057 while (multi_start) {
1058 multi = multi_start;
1059 multi_start = multi_start->next;
1064 /* Print list of OpenSSL engines supported.
1066 static void list_engines (const struct curl_slist *engines)
1068 puts ("Build-time engines:");
1073 for ( ; engines; engines = engines->next)
1074 printf (" %s\n", engines->data);
1077 /***************************************************************************
1081 * Reads a 'name=value' parameter and builds the appropriate linked list.
1083 * Specify files to upload with 'name=@filename'. Supports specified
1084 * given Content-Type of the files. Such as ';type=<content-type>'.
1086 * If literal_value is set, any initial '@' or '<' in the value string
1087 * loses its special meaning, as does any embedded ';type='.
1089 * You may specify more than one file for a single name (field). Specify
1090 * multiple files by writing it like:
1092 * 'name=@filename,filename2,filename3'
1094 * If you want content-types specified for each too, write them like:
1096 * 'name=@filename;type=image/gif,filename2,filename3'
1098 * If you want custom headers added for a single part, write them in a separate
1099 * file and do like this:
1101 * 'name=foo;headers=@headerfile' or why not
1102 * 'name=@filemame;headers=@headerfile'
1104 * To upload a file, but to fake the file name that will be included in the
1105 * formpost, do like this:
1107 * 'name=@filename;filename=/dev/null'
1109 * This function uses curl_formadd to fulfill it's job. Is heavily based on
1110 * the old curl_formparse code.
1112 ***************************************************************************/
1114 #define FORM_FILE_SEPARATOR ','
1115 #define FORM_TYPE_SEPARATOR ';'
1117 static int formparse(struct Configurable *config,
1119 struct curl_httppost **httppost,
1120 struct curl_httppost **last_post,
1123 /* nextarg MUST be a string in the format 'name=contents' and we'll
1124 build a linked list with the info */
1130 const char *type = NULL;
1134 if((1 == sscanf(input, "%255[^=]=", name)) &&
1135 (contp = strchr(input, '='))) {
1136 /* the input was using the correct format */
1138 /* Allocate the contents */
1139 contents = strdup(contp+1);
1141 fprintf(config->errors, "out of memory\n");
1146 if('@' == contp[0] && !literal_value) {
1147 struct multi_files *multi_start = NULL, *multi_current = NULL;
1148 /* we use the @-letter to indicate file name(s) */
1151 multi_start = multi_current=NULL;
1154 /* since this was a file, it may have a content-type specifier
1155 at the end too, or a filename. Or both. */
1157 char *filename=NULL;
1159 sep=strchr(contp, FORM_TYPE_SEPARATOR);
1160 sep2=strchr(contp, FORM_FILE_SEPARATOR);
1162 /* pick the closest */
1163 if(sep2 && (sep2 < sep)) {
1166 /* no type was specified! */
1173 /* if we got here on a comma, don't do much */
1174 if(FORM_FILE_SEPARATOR == *sep)
1179 *sep=0; /* terminate file name at separator */
1181 while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
1183 /* pass all white spaces */
1184 while(ISSPACE(*ptr))
1187 if(curlx_strnequal("type=", ptr, 5)) {
1188 /* set type pointer */
1191 /* verify that this is a fine type specifier */
1192 if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
1194 warnf(config, "Illegally formatted content-type field!\n");
1196 FreeMultiInfo (multi_start);
1197 return 2; /* illegal content-type syntax! */
1199 /* now point beyond the content-type specifier */
1200 sep = (char *)type + strlen(major)+strlen(minor)+1;
1203 *sep=0; /* zero terminate type string */
1208 ptr = NULL; /* end */
1210 else if(curlx_strnequal("filename=", ptr, 9)) {
1212 ptr=strchr(filename, FORM_TYPE_SEPARATOR);
1214 ptr=strchr(filename, FORM_FILE_SEPARATOR);
1217 *ptr=0; /* zero terminate */
1222 /* confusion, bail out of loop */
1225 /* find the following comma */
1227 sep=strchr(ptr, FORM_FILE_SEPARATOR);
1232 sep=strchr(contp, FORM_FILE_SEPARATOR);
1235 /* the next file name starts here */
1239 /* if type == NULL curl_formadd takes care of the problem */
1241 if (!AddMultiFiles (contp, type, filename, &multi_start,
1243 warnf(config, "Error building form post!\n");
1245 FreeMultiInfo (multi_start);
1248 contp = sep; /* move the contents pointer to after the separator */
1250 } while(sep && *sep); /* loop if there's another file name */
1252 /* now we add the multiple files section */
1254 struct curl_forms *forms = NULL;
1255 struct multi_files *ptr = multi_start;
1256 unsigned int i, count = 0;
1261 forms = malloc((count+1)*sizeof(struct curl_forms));
1264 fprintf(config->errors, "Error building form post!\n");
1266 FreeMultiInfo (multi_start);
1269 for (i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
1271 forms[i].option = ptr->form.option;
1272 forms[i].value = ptr->form.value;
1274 forms[count].option = CURLFORM_END;
1275 FreeMultiInfo (multi_start);
1276 if (curl_formadd(httppost, last_post,
1277 CURLFORM_COPYNAME, name,
1278 CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
1279 warnf(config, "curl_formadd failed!\n");
1288 struct curl_forms info[4];
1290 char *ct = literal_value? NULL: strstr(contp, ";type=");
1292 info[i].option = CURLFORM_COPYNAME;
1293 info[i].value = name;
1297 info[i].option = CURLFORM_CONTENTTYPE;
1298 info[i].value = &ct[6];
1300 ct[0]=0; /* zero terminate here */
1303 if( contp[0]=='<' && !literal_value) {
1304 info[i].option = CURLFORM_FILECONTENT;
1305 info[i].value = contp+1;
1307 info[i].option = CURLFORM_END;
1309 if (curl_formadd(httppost, last_post,
1310 CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
1311 warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
1318 #ifdef CURL_DOES_CONVERSIONS
1319 convert_to_network(contp, strlen(contp));
1321 info[i].option = CURLFORM_COPYCONTENTS;
1322 info[i].value = contp;
1324 info[i].option = CURLFORM_END;
1325 if (curl_formadd(httppost, last_post,
1326 CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
1327 warnf(config, "curl_formadd failed!\n");
1336 warnf(config, "Illegally formatted input field!\n");
1346 PARAM_OPTION_AMBIGUOUS,
1347 PARAM_OPTION_UNKNOWN,
1348 PARAM_REQUIRES_PARAMETER,
1350 PARAM_HELP_REQUESTED,
1351 PARAM_GOT_EXTRA_PARAMETER,
1353 PARAM_LIBCURL_DOESNT_SUPPORT,
1358 static const char *param2text(int res)
1360 ParameterError error = (ParameterError)res;
1362 case PARAM_GOT_EXTRA_PARAMETER:
1363 return "had unsupported trailing garbage";
1364 case PARAM_OPTION_UNKNOWN:
1365 return "is unknown";
1366 case PARAM_OPTION_AMBIGUOUS:
1367 return "is ambiguous";
1368 case PARAM_REQUIRES_PARAMETER:
1369 return "requires parameter";
1371 return "is badly used here";
1372 case PARAM_BAD_NUMERIC:
1373 return "expected a proper numerical parameter";
1374 case PARAM_LIBCURL_DOESNT_SUPPORT:
1375 return "the installed libcurl version doesn't support this";
1377 return "out of memory";
1379 return "unknown error";
1383 static ParameterError file2string(char **bufp, FILE *file)
1387 char *string = NULL;
1388 size_t stringlen = 0;
1392 while(fgets(buffer, sizeof(buffer), file)) {
1393 if((ptr = strchr(buffer, '\r')) != NULL)
1395 if((ptr = strchr(buffer, '\n')) != NULL)
1397 buflen = strlen(buffer);
1398 if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
1401 return PARAM_NO_MEM;
1404 strcpy(string+stringlen, buffer);
1405 stringlen += buflen;
1412 static ParameterError file2memory(char **bufp, size_t *size, FILE *file)
1415 char *buffer = NULL;
1422 if(!buffer || (alloc == nused)) {
1423 /* size_t overflow detection for huge files */
1424 if(alloc+1 > ((size_t)-1)/2) {
1427 return PARAM_NO_MEM;
1430 /* allocate an extra char, reserved space, for null termination */
1431 if((newbuf = realloc(buffer, alloc+1)) == NULL) {
1434 return PARAM_NO_MEM;
1438 nread = fread(buffer+nused, 1, alloc-nused, file);
1441 /* null terminate the buffer in case it's used as a string later */
1442 buffer[nused] = '\0';
1443 /* free trailing slack space, if possible */
1444 if(alloc != nused) {
1445 if((newbuf = realloc(buffer, nused+1)) != NULL)
1448 /* discard buffer if nothing was read */
1451 buffer = NULL; /* no string */
1459 static void cleanarg(char *str)
1461 #ifdef HAVE_WRITABLE_ARGV
1462 /* now that GetStr has copied the contents of nextarg, wipe the next
1463 * argument out so that the username:password isn't displayed in the
1464 * system process list */
1466 size_t len = strlen(str);
1467 memset(str, ' ', len);
1475 * Parse the string and write the integer in the given address. Return
1476 * non-zero on failure, zero on success.
1478 * The string must start with a digit to be valid.
1480 * Since this function gets called with the 'nextarg' pointer from within the
1481 * getparameter a lot, we must check it for NULL before accessing the str
1485 static int str2num(long *val, const char *str)
1488 if(str && ISDIGIT(*str))
1491 retcode = 1; /* badness */
1496 * Parses the given string looking for an offset (which may be
1497 * a larger-than-integer value).
1499 * @param val the offset to populate
1500 * @param str the buffer containing the offset
1501 * @return zero if successful, non-zero if failure.
1503 static int str2offset(curl_off_t *val, const char *str)
1505 #if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
1506 *val = curlx_strtoofft(str, NULL, 0);
1507 if((*val == CURL_LLONG_MAX || *val == CURL_LLONG_MIN) && (ERRNO == ERANGE))
1510 *val = strtol(str, NULL, 0);
1511 if ((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
1517 static void checkpasswd(const char *kind, /* for what purpose */
1518 char **userpwd) /* pointer to allocated string */
1524 ptr = strchr(*userpwd, ':');
1526 /* no password present, prompt for one */
1527 char passwd[256]="";
1530 size_t userlen = strlen(*userpwd);
1533 /* build a nice-looking prompt */
1534 curlx_msnprintf(prompt, sizeof(prompt),
1535 "Enter %s password for user '%s':",
1539 getpass_r(prompt, passwd, sizeof(passwd));
1540 passwdlen = strlen(passwd);
1542 /* extend the allocated memory area to fit the password too */
1543 passptr = realloc(*userpwd,
1544 passwdlen + 1 + /* an extra for the colon */
1545 userlen + 1); /* an extra for the zero */
1548 /* append the password separated with a colon */
1549 passptr[userlen]=':';
1550 memcpy(&passptr[userlen+1], passwd, passwdlen+1);
1556 static ParameterError add2list(struct curl_slist **list,
1559 struct curl_slist *newlist = curl_slist_append(*list, ptr);
1563 return PARAM_NO_MEM;
1568 static int ftpfilemethod(struct Configurable *config, const char *str)
1570 if(curlx_raw_equal("singlecwd", str))
1571 return CURLFTPMETHOD_SINGLECWD;
1572 if(curlx_raw_equal("nocwd", str))
1573 return CURLFTPMETHOD_NOCWD;
1574 if(curlx_raw_equal("multicwd", str))
1575 return CURLFTPMETHOD_MULTICWD;
1576 warnf(config, "unrecognized ftp file method '%s', using default\n", str);
1577 return CURLFTPMETHOD_MULTICWD;
1580 static int ftpcccmethod(struct Configurable *config, const char *str)
1582 if(curlx_raw_equal("passive", str))
1583 return CURLFTPSSL_CCC_PASSIVE;
1584 if(curlx_raw_equal("active", str))
1585 return CURLFTPSSL_CCC_ACTIVE;
1586 warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
1587 return CURLFTPSSL_CCC_PASSIVE;
1591 static int sockoptcallback(void *clientp, curl_socket_t curlfd,
1592 curlsocktype purpose)
1594 struct Configurable *config = (struct Configurable *)clientp;
1595 int onoff = 1; /* this callback is only used if we ask for keepalives on the
1597 #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
1598 int keepidle = (int)config->alivetime;
1602 case CURLSOCKTYPE_IPCXN:
1603 if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
1604 sizeof(onoff)) < 0) {
1605 /* don't abort operation, just issue a warning */
1607 warnf(clientp, "Could not set SO_KEEPALIVE!\n");
1611 if (config->alivetime) {
1613 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
1614 sizeof(keepidle)) < 0) {
1615 /* don't abort operation, just issue a warning */
1617 warnf(clientp, "Could not set TCP_KEEPIDLE!\n");
1621 #ifdef TCP_KEEPINTVL
1622 if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
1623 sizeof(keepidle)) < 0) {
1624 /* don't abort operation, just issue a warning */
1626 warnf(clientp, "Could not set TCP_KEEPINTVL!\n");
1641 static ParameterError getparameter(char *flag, /* f or -long-flag */
1642 char *nextarg, /* NULL if unset */
1643 bool *usedarg, /* set to TRUE if the arg
1645 struct Configurable *config)
1648 char subletter=0; /* subletters can only occur on long options */
1649 int rc; /* generic return code variable */
1650 const char *parse=NULL;
1655 bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
1657 bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled
1658 by using --OPTION or --no-OPTION */
1662 boolean whether it takes an additional argument
1664 static const struct LongShort aliases[]= {
1665 /* all these ones, starting with "*" or "$" as a short-option have *no*
1666 short option to mention. */
1668 {"*a", "random-file", TRUE},
1669 {"*b", "egd-file", TRUE},
1670 {"*c", "connect-timeout", TRUE},
1671 {"*d", "ciphers", TRUE},
1672 {"*e", "disable-epsv", FALSE},
1673 {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to
1674 work although --disable-epsv is the documented
1676 #ifdef USE_ENVIRONMENT
1677 {"*f", "environment", FALSE},
1679 {"*g", "trace", TRUE},
1680 {"*h", "trace-ascii", TRUE},
1681 {"*i", "limit-rate", TRUE},
1682 {"*j", "compressed", FALSE}, /* might take an arg someday */
1683 {"*k", "digest", FALSE},
1684 {"*l", "negotiate", FALSE},
1685 {"*m", "ntlm", FALSE},
1686 {"*n", "basic", FALSE},
1687 {"*o", "anyauth", FALSE},
1689 {"*p", "wdebug", FALSE},
1691 {"*q", "ftp-create-dirs", FALSE},
1692 {"*r", "create-dirs", FALSE},
1693 {"*s", "max-redirs", TRUE},
1694 {"*t", "proxy-ntlm", FALSE},
1695 {"*u", "crlf", FALSE},
1696 {"*v", "stderr", TRUE},
1697 {"*w", "interface", TRUE},
1698 {"*x", "krb" , TRUE},
1699 {"*x", "krb4" , TRUE}, /* this is the previous name */
1700 {"*y", "max-filesize", TRUE},
1701 {"*z", "disable-eprt", FALSE},
1702 {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to
1703 work although --disable-eprt is the documented
1705 {"$a", "ftp-ssl", FALSE}, /* deprecated name since 7.20.0 */
1706 {"$a", "ssl", FALSE}, /* new option name in 7.20.0, previously this
1708 {"$b", "ftp-pasv", FALSE},
1709 {"$c", "socks5", TRUE},
1710 {"$c", "socks", TRUE}, /* this is how the option once was documented
1711 but we prefer the --socks5 version for
1713 {"$d", "tcp-nodelay",FALSE},
1714 {"$e", "proxy-digest", FALSE},
1715 {"$f", "proxy-basic", FALSE},
1716 {"$g", "retry", TRUE},
1717 {"$h", "retry-delay", TRUE},
1718 {"$i", "retry-max-time", TRUE},
1719 {"$k", "proxy-negotiate", FALSE},
1720 {"$m", "ftp-account", TRUE},
1721 {"$n", "proxy-anyauth", FALSE},
1722 {"$o", "trace-time", FALSE},
1723 {"$p", "ignore-content-length", FALSE},
1724 {"$q", "ftp-skip-pasv-ip", FALSE},
1725 {"$r", "ftp-method", TRUE},
1726 {"$s", "local-port", TRUE},
1727 {"$t", "socks4", TRUE},
1728 {"$T", "socks4a", TRUE},
1729 {"$u", "ftp-alternative-to-user", TRUE},
1730 {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */
1731 {"$v", "ssl-reqd", FALSE}, /* new option name in 7.20.0, previously this
1733 {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */
1734 {"$x", "ftp-ssl-control", FALSE},
1735 {"$y", "ftp-ssl-ccc", FALSE},
1736 {"$j", "ftp-ssl-ccc-mode", TRUE},
1737 {"$z", "libcurl", TRUE},
1738 {"$#", "raw", FALSE},
1739 {"$0", "post301", FALSE},
1740 {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
1741 {"$2", "socks5-hostname", TRUE},
1742 {"$3", "keepalive-time", TRUE},
1743 {"$4", "post302", FALSE},
1744 {"$5", "noproxy", TRUE},
1746 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1747 {"$6", "socks5-gssapi-service", TRUE},
1748 {"$7", "socks5-gssapi-nec", FALSE},
1750 {"$8", "proxy1.0", TRUE},
1751 {"$9", "tftp-blksize", TRUE},
1752 {"$A", "mail-from", TRUE},
1753 {"$B", "mail-rcpt", TRUE},
1754 {"$C", "ftp-pret", FALSE},
1755 {"0", "http1.0", FALSE},
1756 {"1", "tlsv1", FALSE},
1757 {"2", "sslv2", FALSE},
1758 {"3", "sslv3", FALSE},
1759 {"4", "ipv4", FALSE},
1760 {"6", "ipv6", FALSE},
1761 {"a", "append", FALSE},
1762 {"A", "user-agent", TRUE},
1763 {"b", "cookie", TRUE},
1764 {"B", "use-ascii", FALSE},
1765 {"c", "cookie-jar", TRUE},
1766 {"C", "continue-at", TRUE},
1767 {"d", "data", TRUE},
1768 {"da", "data-ascii", TRUE},
1769 {"db", "data-binary", TRUE},
1770 {"de", "data-urlencode", TRUE},
1771 {"D", "dump-header", TRUE},
1772 {"e", "referer", TRUE},
1773 {"E", "cert", TRUE},
1774 {"Ea", "cacert", TRUE},
1775 {"Eb","cert-type", TRUE},
1777 {"Ed","key-type", TRUE},
1778 {"Ee","pass", TRUE},
1779 {"Ef","engine", TRUE},
1780 {"Eg","capath ", TRUE},
1781 {"Eh","pubkey", TRUE},
1782 {"Ei", "hostpubmd5", TRUE},
1783 {"Ej","crlfile", TRUE},
1784 {"f", "fail", FALSE},
1785 {"F", "form", TRUE},
1786 {"Fs","form-string", TRUE},
1787 {"g", "globoff", FALSE},
1788 {"G", "get", FALSE},
1789 {"h", "help", FALSE},
1790 {"H", "header", TRUE},
1791 {"i", "include", FALSE},
1792 {"I", "head", FALSE},
1793 {"j", "junk-session-cookies", FALSE},
1794 {"J", "remote-header-name", FALSE},
1795 {"k", "insecure", FALSE},
1796 {"K", "config", TRUE},
1797 {"l", "list-only", FALSE},
1798 {"L", "location", FALSE},
1799 {"Lt", "location-trusted", FALSE},
1800 {"m", "max-time", TRUE},
1801 {"M", "manual", FALSE},
1802 {"n", "netrc", FALSE},
1803 {"no", "netrc-optional", FALSE},
1804 {"N", "buffer", FALSE}, /* listed as --no-buffer in the help */
1805 {"o", "output", TRUE},
1806 {"O", "remote-name", FALSE},
1807 {"Oa", "remote-name-all", FALSE},
1808 {"p", "proxytunnel", FALSE},
1809 {"P", "ftpport", TRUE}, /* older version */
1810 {"P", "ftp-port", TRUE},
1811 {"q", "disable", FALSE},
1812 {"Q", "quote", TRUE},
1813 {"r", "range", TRUE},
1814 {"R", "remote-time", FALSE},
1815 {"s", "silent", FALSE},
1816 {"S", "show-error", FALSE},
1817 {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */
1818 {"T", "upload-file", TRUE},
1819 {"u", "user", TRUE},
1820 {"U", "proxy-user", TRUE},
1821 {"v", "verbose", FALSE},
1822 {"V", "version", FALSE},
1823 {"w", "write-out", TRUE},
1824 {"x", "proxy", TRUE},
1825 {"X", "request", TRUE},
1826 {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
1827 {"Y", "speed-limit", TRUE},
1828 {"y", "speed-time", TRUE},
1829 {"z", "time-cond", TRUE},
1830 {"#", "progress-bar",FALSE},
1833 if(('-' != flag[0]) ||
1834 (('-' == flag[0]) && ('-' == flag[1]))) {
1835 /* this should be a long name */
1836 char *word=('-' == flag[0])?flag+2:flag;
1837 size_t fnam=strlen(word);
1840 if(!strncmp(word, "no-", 3)) {
1841 /* disable this option but ignore the "no-" part when looking for it */
1846 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1847 if(curlx_strnequal(aliases[j].lname, word, fnam)) {
1850 if(curlx_raw_equal(aliases[j].lname, word)) {
1851 parse = aliases[j].letter;
1853 numhits = 1; /* a single unique hit */
1856 parse = aliases[j].letter;
1861 /* this is at least the second match! */
1862 return PARAM_OPTION_AMBIGUOUS;
1865 return PARAM_OPTION_UNKNOWN;
1869 flag++; /* prefixed with one dash, pass it */
1875 /* we can loop here if we have multiple single-letters */
1879 letter = (char)*parse;
1888 subletter = parse[1];
1890 *usedarg = FALSE; /* default is that we don't use the arg */
1893 for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1894 if(letter == aliases[j].letter[0]) {
1900 return PARAM_OPTION_UNKNOWN;
1904 if(aliases[hit].extraparam) {
1905 /* this option requires an extra parameter */
1906 if(!longopt && parse[1]) {
1907 nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
1908 singleopt=TRUE; /* don't loop anymore after this */
1911 return PARAM_REQUIRES_PARAMETER;
1913 *usedarg = TRUE; /* mark it as used */
1917 case '*': /* options without a short option */
1919 case 'a': /* random-file */
1920 GetStr(&config->random_file, nextarg);
1922 case 'b': /* egd-file */
1923 GetStr(&config->egd_file, nextarg);
1925 case 'c': /* connect-timeout */
1926 if(str2num(&config->connecttimeout, nextarg))
1927 return PARAM_BAD_NUMERIC;
1929 case 'd': /* ciphers */
1930 GetStr(&config->cipher_list, nextarg);
1932 case 'e': /* --disable-epsv */
1933 config->disable_epsv = toggle;
1935 case 'E': /* --epsv */
1936 config->disable_epsv = (bool)(!toggle);
1938 #ifdef USE_ENVIRONMENT
1940 config->writeenv = toggle;
1943 case 'g': /* --trace */
1944 GetStr(&config->trace_dump, nextarg);
1945 if(config->tracetype && (config->tracetype != TRACE_BIN))
1946 warnf(config, "--trace overrides an earlier trace/verbose option\n");
1947 config->tracetype = TRACE_BIN;
1949 case 'h': /* --trace-ascii */
1950 GetStr(&config->trace_dump, nextarg);
1951 if(config->tracetype && (config->tracetype != TRACE_ASCII))
1953 "--trace-ascii overrides an earlier trace/verbose option\n");
1954 config->tracetype = TRACE_ASCII;
1956 case 'i': /* --limit-rate */
1958 /* We support G, M, K too */
1960 curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
1964 else if(strlen(unit) > 1)
1965 unit=(char *)"w"; /* unsupported */
1970 value *= 1024*1024*1024;
1982 /* for plain bytes, leave as-is */
1985 warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
1986 return PARAM_BAD_USE;
1988 config->recvpersecond = value;
1989 config->sendpersecond = value;
1993 case 'j': /* --compressed */
1994 config->encoding = toggle;
1997 case 'k': /* --digest */
1999 config->authtype |= CURLAUTH_DIGEST;
2001 config->authtype &= ~CURLAUTH_DIGEST;
2004 case 'l': /* --negotiate */
2006 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2007 config->authtype |= CURLAUTH_GSSNEGOTIATE;
2009 return PARAM_LIBCURL_DOESNT_SUPPORT;
2012 config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
2015 case 'm': /* --ntlm */
2017 if(curlinfo->features & CURL_VERSION_NTLM)
2018 config->authtype |= CURLAUTH_NTLM;
2020 return PARAM_LIBCURL_DOESNT_SUPPORT;
2023 config->authtype &= ~CURLAUTH_NTLM;
2026 case 'n': /* --basic for completeness */
2028 config->authtype |= CURLAUTH_BASIC;
2030 config->authtype &= ~CURLAUTH_BASIC;
2033 case 'o': /* --anyauth, let libcurl pick it */
2035 config->authtype = CURLAUTH_ANY;
2036 /* --no-anyauth simply doesn't touch it */
2040 case 'p': /* --wdebug */
2044 case 'q': /* --ftp-create-dirs */
2045 config->ftp_create_dirs = toggle;
2048 case 'r': /* --create-dirs */
2049 config->create_dirs = TRUE;
2052 case 's': /* --max-redirs */
2053 /* specified max no of redirects (http(s)) */
2054 if(str2num(&config->maxredirs, nextarg))
2055 return PARAM_BAD_NUMERIC;
2058 case 't': /* --proxy-ntlm */
2059 if(curlinfo->features & CURL_VERSION_NTLM)
2060 config->proxyntlm = toggle;
2062 return PARAM_LIBCURL_DOESNT_SUPPORT;
2065 case 'u': /* --crlf */
2066 /* LF -> CRLF conversion? */
2067 config->crlf = TRUE;
2070 case 'v': /* --stderr */
2071 if(strcmp(nextarg, "-")) {
2072 FILE *newfile = fopen(nextarg, "wt");
2074 warnf(config, "Failed to open %s!\n", nextarg);
2076 if(config->errors_fopened)
2077 fclose(config->errors);
2078 config->errors = newfile;
2079 config->errors_fopened = TRUE;
2083 config->errors = stdout;
2085 case 'w': /* --interface */
2087 GetStr(&config->iface, nextarg);
2089 case 'x': /* --krb */
2090 /* kerberos level string */
2091 if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
2092 CURL_VERSION_GSSNEGOTIATE))
2093 GetStr(&config->krblevel, nextarg);
2095 return PARAM_LIBCURL_DOESNT_SUPPORT;
2097 case 'y': /* --max-filesize */
2098 if(str2offset(&config->max_filesize, nextarg))
2099 return PARAM_BAD_NUMERIC;
2101 case 'z': /* --disable-eprt */
2102 config->disable_eprt = toggle;
2104 case 'Z': /* --eprt */
2105 config->disable_eprt = (bool)(!toggle);
2108 default: /* the URL! */
2111 if(config->url_get || (config->url_get=config->url_list)) {
2112 /* there's a node here, if it already is filled-in continue to find
2114 while(config->url_get && (config->url_get->flags&GETOUT_URL))
2115 config->url_get = config->url_get->next;
2118 /* now there might or might not be an available node to fill in! */
2122 url = config->url_get;
2124 /* there was no free node, create one! */
2125 url=new_getout(config);
2128 /* fill in the URL */
2129 GetStr(&url->url, nextarg);
2130 url->flags |= GETOUT_URL;
2135 case '$': /* more options without a short option */
2137 case 'a': /* --ftp-ssl */
2138 config->ftp_ssl = toggle;
2140 case 'b': /* --ftp-pasv */
2142 free(config->ftpport);
2143 config->ftpport = NULL;
2145 case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
2146 the name locally and passes on the resolved address */
2147 GetStr(&config->socksproxy, nextarg);
2148 config->socksver = CURLPROXY_SOCKS5;
2150 case 't': /* --socks4 specifies a socks4 proxy to use */
2151 GetStr(&config->socksproxy, nextarg);
2152 config->socksver = CURLPROXY_SOCKS4;
2154 case 'T': /* --socks4a specifies a socks4a proxy to use */
2155 GetStr(&config->socksproxy, nextarg);
2156 config->socksver = CURLPROXY_SOCKS4A;
2158 case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
2159 resolving with the proxy */
2160 GetStr(&config->socksproxy, nextarg);
2161 config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
2163 case 'd': /* --tcp-nodelay option */
2164 config->tcp_nodelay = toggle;
2166 case 'e': /* --proxy-digest */
2167 config->proxydigest = toggle;
2169 case 'f': /* --proxy-basic */
2170 config->proxybasic = toggle;
2172 case 'g': /* --retry */
2173 if(str2num(&config->req_retry, nextarg))
2174 return PARAM_BAD_NUMERIC;
2176 case 'h': /* --retry-delay */
2177 if(str2num(&config->retry_delay, nextarg))
2178 return PARAM_BAD_NUMERIC;
2180 case 'i': /* --retry-max-time */
2181 if(str2num(&config->retry_maxtime, nextarg))
2182 return PARAM_BAD_NUMERIC;
2185 case 'k': /* --proxy-negotiate */
2186 if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
2187 config->proxynegotiate = toggle;
2189 return PARAM_LIBCURL_DOESNT_SUPPORT;
2191 case 'm': /* --ftp-account */
2192 GetStr(&config->ftp_account, nextarg);
2194 case 'n': /* --proxy-anyauth */
2195 config->proxyanyauth = toggle;
2197 case 'o': /* --trace-time */
2198 config->tracetime = toggle;
2200 case 'p': /* --ignore-content-length */
2201 config->ignorecl = toggle;
2203 case 'q': /* --ftp-skip-pasv-ip */
2204 config->ftp_skip_ip = toggle;
2206 case 'r': /* --ftp-method (undocumented at this point) */
2207 config->ftp_filemethod = ftpfilemethod(config, nextarg);
2209 case 's': /* --local-port */
2210 rc = sscanf(nextarg, "%d - %d",
2212 &config->localportrange);
2214 return PARAM_BAD_USE;
2216 config->localportrange = 1; /* default number of ports to try */
2218 config->localportrange -= config->localport;
2219 if(config->localportrange < 1) {
2220 warnf(config, "bad range input\n");
2221 return PARAM_BAD_USE;
2225 case 'u': /* --ftp-alternative-to-user */
2226 GetStr(&config->ftp_alternative_to_user, nextarg);
2228 case 'v': /* --ftp-ssl-reqd */
2229 config->ftp_ssl_reqd = toggle;
2231 case 'w': /* --no-sessionid */
2232 config->disable_sessionid = (bool)(!toggle);
2234 case 'x': /* --ftp-ssl-control */
2235 config->ftp_ssl_control = toggle;
2237 case 'y': /* --ftp-ssl-ccc */
2238 config->ftp_ssl_ccc = toggle;
2239 if(!config->ftp_ssl_ccc_mode)
2240 config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
2242 case 'j': /* --ftp-ssl-ccc-mode */
2243 config->ftp_ssl_ccc = TRUE;
2244 config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
2246 case 'z': /* --libcurl */
2247 GetStr(&config->libcurl, nextarg);
2249 case '#': /* --raw */
2250 config->raw = toggle;
2252 case '0': /* --post301 */
2253 config->post301 = toggle;
2255 case '1': /* --no-keepalive */
2256 config->nokeepalive = (bool)(!toggle);
2258 case '3': /* --keepalive-time */
2259 if(str2num(&config->alivetime, nextarg))
2260 return PARAM_BAD_NUMERIC;
2262 case '4': /* --post302 */
2263 config->post302 = toggle;
2265 case '5': /* --noproxy */
2266 /* This specifies the noproxy list */
2267 GetStr(&config->noproxy, nextarg);
2269 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
2270 case '6': /* --socks5-gssapi-service */
2271 GetStr(&config->socks5_gssapi_service, nextarg);
2273 case '7': /* --socks5-gssapi-nec*/
2274 config->socks5_gssapi_nec = TRUE;
2277 case '8': /* --proxy1.0 */
2278 /* http 1.0 proxy */
2279 GetStr(&config->proxy, nextarg);
2280 config->proxyver = CURLPROXY_HTTP_1_0;
2282 case '9': /* --tftp-blksize */
2283 str2num(&config->tftp_blksize, nextarg);
2285 case 'A': /* --mail-from */
2286 GetStr(&config->mail_from, nextarg);
2288 case 'B': /* --mail-rcpt */
2289 /* append receiver to a list */
2290 err = add2list(&config->mail_rcpt, nextarg);
2294 case 'C': /* --ftp-pret */
2295 config->ftp_pret = toggle;
2299 case '#': /* --progress-bar */
2301 config->progressmode = CURL_PROGRESS_BAR;
2303 config->progressmode = CURL_PROGRESS_STATS;
2306 /* HTTP version 1.0 */
2307 config->httpversion = CURL_HTTP_VERSION_1_0;
2311 config->ssl_version = CURL_SSLVERSION_TLSv1;
2315 config->ssl_version = CURL_SSLVERSION_SSLv2;
2319 config->ssl_version = CURL_SSLVERSION_SSLv3;
2323 config->ip_version = 4;
2327 config->ip_version = 6;
2330 /* This makes the FTP sessions use APPE instead of STOR */
2331 config->ftp_append = toggle;
2334 /* This specifies the User-Agent name */
2335 GetStr(&config->useragent, nextarg);
2337 case 'b': /* cookie string coming up: */
2338 if(nextarg[0] == '@') {
2341 else if(strchr(nextarg, '=')) {
2342 /* A cookie string must have a =-letter */
2343 GetStr(&config->cookie, nextarg);
2346 /* We have a cookie file to read from! */
2347 GetStr(&config->cookiefile, nextarg);
2350 /* use ASCII/text when transfering */
2351 config->use_ascii = toggle;
2354 /* get the file name to dump all cookies in */
2355 GetStr(&config->cookiejar, nextarg);
2358 /* This makes us continue an ftp transfer at given position */
2359 if(!curlx_strequal(nextarg, "-")) {
2360 if(str2offset(&config->resume_from, nextarg))
2361 return PARAM_BAD_NUMERIC;
2362 config->resume_from_current = FALSE;
2365 config->resume_from_current = TRUE;
2366 config->resume_from = 0;
2368 config->use_resume=TRUE;
2371 /* postfield data */
2373 char *postdata=NULL;
2376 if(subletter == 'e') { /* --data-urlencode*/
2377 /* [name]=[content], we encode the content part only
2378 * [name]@[file name]
2380 * Case 2: we first load the file using that name and then encode
2383 const char *p = strchr(nextarg, '=');
2388 /* there was no '=' letter, check for a '@' instead */
2389 p = strchr(nextarg, '@');
2391 nlen = p - nextarg; /* length of the name part */
2392 is_file = *p++; /* pass the separator */
2395 /* neither @ nor =, so no name and it isn't a file */
2399 if('@' == is_file) {
2400 /* a '@' letter, it means that a file name or - (stdin) follows */
2402 if(curlx_strequal("-", p)) {
2407 file = fopen(p, "rb");
2410 "Couldn't read data from file \"%s\", this makes "
2411 "an empty POST.\n", nextarg);
2414 err = file2memory(&postdata, &size, file);
2416 if(file && (file != stdin))
2422 GetStr(&postdata, p);
2423 size = strlen(postdata);
2427 /* no data from the file, point to a zero byte string to make this
2428 get sent as a POST anyway */
2429 postdata=strdup("");
2432 char *enc = curl_easy_escape(config->easy, postdata, (int)size);
2433 free(postdata); /* no matter if it worked or not */
2435 /* now make a string with the name from above and append the
2437 size_t outlen = nlen + strlen(enc) + 2;
2438 char *n = malloc(outlen);
2441 return PARAM_NO_MEM;
2443 if (nlen > 0) /* only append '=' if we have a name */
2444 snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
2451 return PARAM_NO_MEM;
2454 else if('@' == *nextarg) {
2456 /* the data begins with a '@' letter, it means that a file name
2457 or - (stdin) follows */
2458 nextarg++; /* pass the @ */
2460 if(curlx_strequal("-", nextarg)) {
2462 if(subletter == 'b') /* forced data-binary */
2466 file = fopen(nextarg, "rb");
2468 warnf(config, "Couldn't read data from file \"%s\", this makes "
2469 "an empty POST.\n", nextarg);
2472 if(subletter == 'b') {
2474 err = file2memory(&postdata, &size, file);
2475 config->postfieldsize = (curl_off_t)size;
2478 err = file2string(&postdata, file);
2480 if(file && (file != stdin))
2486 /* no data from the file, point to a zero byte string to make this
2487 get sent as a POST anyway */
2488 postdata=strdup("");
2492 GetStr(&postdata, nextarg);
2495 #ifdef CURL_DOES_CONVERSIONS
2496 if(subletter != 'b') { /* NOT forced binary, convert to ASCII */
2497 convert_to_network(postdata, strlen(postdata));
2501 if(config->postfields) {
2502 /* we already have a string, we append this one
2503 with a separating &-letter */
2504 char *oldpost=config->postfields;
2505 size_t newlen = strlen(oldpost) + strlen(postdata) + 2;
2506 config->postfields=malloc(newlen);
2507 if(!config->postfields) {
2509 return PARAM_NO_MEM;
2511 /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
2512 snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata);
2517 config->postfields=postdata;
2520 We can't set the request type here, as this data might be used in
2521 a simple GET if -G is used. Already or soon.
2523 if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
2524 return PARAM_BAD_USE;
2528 /* dump-header to given file name */
2529 GetStr(&config->headerfile, nextarg);
2533 char *ptr = strstr(nextarg, ";auto");
2535 /* Automatic referer requested, this may be combined with a
2537 config->autoreferer = TRUE;
2538 *ptr = 0; /* zero terminate here */
2541 config->autoreferer = FALSE;
2542 GetStr(&config->referer, nextarg);
2547 case 'a': /* CA info PEM file */
2548 /* CA info PEM file */
2549 GetStr(&config->cacert, nextarg);
2551 case 'b': /* cert file type */
2552 GetStr(&config->cert_type, nextarg);
2554 case 'c': /* private key file */
2555 GetStr(&config->key, nextarg);
2557 case 'd': /* private key file type */
2558 GetStr(&config->key_type, nextarg);
2560 case 'e': /* private key passphrase */
2561 GetStr(&config->key_passwd, nextarg);
2564 case 'f': /* crypto engine */
2565 GetStr(&config->engine, nextarg);
2566 if (config->engine && curlx_raw_equal(config->engine,"list"))
2567 config->list_engines = TRUE;
2569 case 'g': /* CA info PEM file */
2570 /* CA cert directory */
2571 GetStr(&config->capath, nextarg);
2573 case 'h': /* --pubkey public key file */
2574 GetStr(&config->pubkey, nextarg);
2576 case 'i': /* --hostpubmd5 md5 of the host public key */
2577 GetStr(&config->hostpubmd5, nextarg);
2578 if (!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
2579 return PARAM_BAD_USE;
2581 case 'j': /* CRL info PEM file */
2583 GetStr(&config->crlfile, nextarg);
2585 default: /* certificate file */
2587 char *ptr = strchr(nextarg, ':');
2588 /* Since we live in a world of weirdness and confusion, the win32
2589 dudes can use : when using drive letters and thus
2590 c:\file:password needs to work. In order not to break
2591 compatibility, we still use : as separator, but we try to detect
2592 when it is used for a file name! On windows. */
2595 (ptr == &nextarg[1]) &&
2596 (nextarg[2] == '\\' || nextarg[2] == '/') &&
2597 (ISALPHA(nextarg[0])) )
2598 /* colon in the second column, followed by a backslash, and the
2599 first character is an alphabetic letter:
2601 this is a drive letter colon */
2602 ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
2605 /* we have a password too */
2608 GetStr(&config->key_passwd, ptr);
2610 GetStr(&config->cert, nextarg);
2616 /* fail hard on errors */
2617 config->failonerror = toggle;
2620 /* "form data" simulation, this is a little advanced so lets do our best
2621 to sort this out slowly and carefully */
2622 if(formparse(config,
2626 (bool) (subletter=='s'))) /* 's' means literal string */
2627 return PARAM_BAD_USE;
2628 if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
2629 return PARAM_BAD_USE;
2632 case 'g': /* g disables URLglobbing */
2633 config->globoff = toggle;
2636 case 'G': /* HTTP GET */
2637 config->use_httpget = TRUE;
2640 case 'h': /* h for help */
2643 return PARAM_HELP_REQUESTED;
2645 /* we now actually support --no-help too! */
2648 /* A custom header to append to a list */
2649 err = add2list(&config->headers, nextarg);
2654 config->include_headers = toggle; /* include the headers as well in the
2655 general output stream */
2658 config->cookiesession = toggle;
2662 * no_body will imply include_headers later on
2664 config->no_body = toggle;
2665 if(SetHTTPrequest(config,
2666 (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
2668 return PARAM_BAD_USE;
2670 case 'J': /* --remote-header-name */
2671 if (config->include_headers) {
2673 "--include and --remote-header-name cannot be combined.\n");
2674 return PARAM_BAD_USE;
2676 config->content_disposition = toggle;
2678 case 'k': /* allow insecure SSL connects */
2679 config->insecure_ok = toggle;
2681 case 'K': /* parse config file */
2682 if(parseconfig(nextarg, config))
2683 warnf(config, "error trying read config from the '%s' file\n",
2687 config->dirlistonly = toggle; /* only list the names of the FTP dir */
2690 config->followlocation = toggle; /* Follow Location: HTTP headers */
2691 switch (subletter) {
2693 /* Continue to send authentication (user+password) when following
2694 * locations, even when hostname changed */
2695 config->unrestricted_auth = toggle;
2700 /* specified max time */
2701 if(str2num(&config->timeout, nextarg))
2702 return PARAM_BAD_NUMERIC;
2704 case 'M': /* M for manual, huge help */
2705 if(toggle) { /* --no-manual shows no manual... */
2708 return PARAM_HELP_REQUESTED;
2711 "built-in manual was disabled at build-time!\n");
2712 return PARAM_OPTION_UNKNOWN;
2718 case 'o': /* CA info PEM file */
2719 /* use .netrc or URL */
2720 config->netrc_opt = toggle;
2723 /* pick info from .netrc, if this is used for http, curl will
2724 automatically enfore user+password with the request */
2725 config->netrc = toggle;
2730 /* disable the output I/O buffering. note that the option is called
2731 --buffer but is mostly used in the negative form: --no-buffer */
2733 config->nobuffer = (bool)(!toggle);
2735 config->nobuffer = toggle;
2737 case 'O': /* --remote-name */
2738 if(subletter == 'a') { /* --remote-name-all */
2739 config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
2743 case 'o': /* --output */
2747 if(config->url_out || (config->url_out=config->url_list)) {
2748 /* there's a node here, if it already is filled-in continue to find
2750 while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
2751 config->url_out = config->url_out->next;
2754 /* now there might or might not be an available node to fill in! */
2758 url = config->url_out;
2760 /* there was no free node, create one! */
2761 url=new_getout(config);
2764 /* fill in the outfile */
2766 GetStr(&url->outfile, nextarg);
2767 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2770 url->outfile=NULL; /* leave it */
2772 url->flags |= GETOUT_USEREMOTE; /* switch on */
2774 url->flags &= ~GETOUT_USEREMOTE; /* switch off */
2776 url->flags |= GETOUT_OUTFILE;
2781 /* This makes the FTP sessions use PORT instead of PASV */
2782 /* use <eth0> or <192.168.10.10> style addresses. Anything except
2783 this will make us try to get the "default" address.
2784 NOTE: this is a changed behaviour since the released 4.1!
2786 GetStr(&config->ftpport, nextarg);
2789 /* proxy tunnel for non-http protocols */
2790 config->proxytunnel = toggle;
2793 case 'q': /* if used first, already taken care of, we do it like
2794 this so we don't cause an error! */
2797 /* QUOTE command to send to FTP server */
2798 switch(nextarg[0]) {
2800 /* prefixed with a dash makes it a POST TRANSFER one */
2802 err = add2list(&config->postquote, nextarg);
2805 /* prefixed with a plus makes it a just-before-transfer one */
2807 err = add2list(&config->prequote, nextarg);
2810 err = add2list(&config->quote, nextarg);
2817 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2818 (and won't actually be range by definition). The man page previously
2819 claimed that to be a good way, why this code is added to work-around
2821 if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
2825 "A specified range MUST include at least one dash (-). "
2826 "Appending one for you!\n");
2827 off = curlx_strtoofft(nextarg, NULL, 10);
2828 snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
2829 GetStr(&config->range, buffer);
2832 /* byte range requested */
2835 while(*tmp_range != '\0') {
2836 if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') {
2837 warnf(config,"Invalid character is found in given range. "
2838 "A specified range MUST have only digits in "
2839 "\'start\'-\'stop\'. The server's response to this "
2840 "request is uncertain.\n");
2845 /* byte range requested */
2846 GetStr(&config->range, nextarg);
2850 /* use remote file's time */
2851 config->remote_time = toggle;
2854 /* don't show progress meter, don't show errors : */
2856 config->mute = config->noprogress = TRUE;
2858 config->mute = config->noprogress = FALSE;
2859 config->showerror = (bool)(!toggle); /* toggle off */
2863 config->showerror = toggle; /* toggle on if used with -s */
2866 /* Telnet options */
2867 err = add2list(&config->telnet_options, nextarg);
2872 /* we are uploading */
2875 if(config->url_out || (config->url_out=config->url_list)) {
2876 /* there's a node here, if it already is filled-in continue to find
2878 while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
2879 config->url_out = config->url_out->next;
2882 /* now there might or might not be an available node to fill in! */
2886 url = config->url_out;
2888 /* there was no free node, create one! */
2889 url=new_getout(config);
2892 url->flags |= GETOUT_UPLOAD; /* mark -T used */
2894 url->flags |= GETOUT_NOUPLOAD;
2896 /* "-" equals stdin, but keep the string around for now */
2897 GetStr(&url->infile, nextarg);
2904 GetStr(&config->userpwd, nextarg);
2906 checkpasswd("host", &config->userpwd);
2909 /* Proxy user:password */
2910 GetStr(&config->proxyuserpwd, nextarg);
2912 checkpasswd("proxy", &config->proxyuserpwd);
2916 /* the '%' thing here will cause the trace get sent to stderr */
2917 GetStr(&config->trace_dump, (char *)"%");
2918 if(config->tracetype && (config->tracetype != TRACE_PLAIN))
2920 "-v/--verbose overrides an earlier trace/verbose option\n");
2921 config->tracetype = TRACE_PLAIN;
2924 /* verbose is disabled here */
2925 config->tracetype = TRACE_NONE;
2929 const char * const *proto;
2932 /* --no-version yields no output! */
2935 printf(CURL_ID "%s\n", curl_version());
2936 if (curlinfo->protocols) {
2937 printf("Protocols: ");
2938 for (proto=curlinfo->protocols; *proto; ++proto) {
2939 printf("%s ", *proto);
2941 puts(""); /* newline */
2943 if(curlinfo->features) {
2949 static const struct feat feats[] = {
2950 {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
2951 {"Debug", CURL_VERSION_DEBUG},
2952 {"TrackMemory", CURL_VERSION_CURLDEBUG},
2953 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
2954 {"IDN", CURL_VERSION_IDN},
2955 {"IPv6", CURL_VERSION_IPV6},
2956 {"Largefile", CURL_VERSION_LARGEFILE},
2957 {"NTLM", CURL_VERSION_NTLM},
2958 {"SPNEGO", CURL_VERSION_SPNEGO},
2959 {"SSL", CURL_VERSION_SSL},
2960 {"SSPI", CURL_VERSION_SSPI},
2961 {"krb4", CURL_VERSION_KERBEROS4},
2962 {"libz", CURL_VERSION_LIBZ},
2963 {"CharConv", CURL_VERSION_CONV}
2965 printf("Features: ");
2966 for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
2967 if(curlinfo->features & feats[i].bitmask)
2968 printf("%s ", feats[i].name);
2970 puts(""); /* newline */
2973 return PARAM_HELP_REQUESTED;
2975 /* get the output string */
2976 if('@' == *nextarg) {
2977 /* the data begins with a '@' letter, it means that a file name
2978 or - (stdin) follows */
2981 nextarg++; /* pass the @ */
2982 if(curlx_strequal("-", nextarg)) {
2988 file = fopen(nextarg, "r");
2990 err = file2string(&config->writeout, file);
2991 if(file && (file != stdin))
2995 if(!config->writeout)
2996 warnf(config, "Failed to read %s", fname);
2999 GetStr(&config->writeout, nextarg);
3003 GetStr(&config->proxy, nextarg);
3004 config->proxyver = CURLPROXY_HTTP;
3007 /* set custom request */
3008 GetStr(&config->customrequest, nextarg);
3011 /* low speed time */
3012 if(str2num(&config->low_speed_time, nextarg))
3013 return PARAM_BAD_NUMERIC;
3014 if(!config->low_speed_limit)
3015 config->low_speed_limit = 1;
3018 /* low speed limit */
3019 if(str2num(&config->low_speed_limit, nextarg))
3020 return PARAM_BAD_NUMERIC;
3021 if(!config->low_speed_time)
3022 config->low_speed_time=30;
3024 case 'z': /* time condition coming up */
3029 /* If-Modified-Since: (section 14.28 in RFC2068) */
3030 config->timecond = CURL_TIMECOND_IFMODSINCE;
3033 /* If-Unmodified-Since: (section 14.24 in RFC2068) */
3034 config->timecond = CURL_TIMECOND_IFUNMODSINCE;
3038 /* Last-Modified: (section 14.29 in RFC2068) */
3039 config->timecond = CURL_TIMECOND_LASTMOD;
3044 config->condtime=curl_getdate(nextarg, &now);
3045 if(-1 == (int)config->condtime) {
3046 /* now let's see if it is a file name to get the time from instead! */
3047 struct_stat statbuf;
3048 if(-1 == stat(nextarg, &statbuf)) {
3049 /* failed, remove time condition */
3050 config->timecond = CURL_TIMECOND_NONE;
3052 "Illegal date format for -z/--timecond (and not "
3053 "a file name). Disabling time condition. "
3054 "See curl_getdate(3) for valid date syntax.\n");
3057 /* pull the time out from the file */
3058 config->condtime = statbuf.st_mtime;
3062 default: /* unknown flag */
3063 return PARAM_OPTION_UNKNOWN;
3067 } while(!longopt && !singleopt && *++parse && !*usedarg);
3073 * Copies the string from line to the buffer at param, unquoting
3074 * backslash-quoted characters and NUL-terminating the output string.
3075 * Stops at the first non-backslash-quoted double quote character or the
3076 * end of the input string. param must be at least as long as the input
3077 * string. Returns the pointer after the last handled input character.
3079 static const char *unslashquote(const char *line, char *param)
3081 while(*line && (*line != '\"')) {
3086 /* default is to output the letter after the backslash */
3087 switch(out = *line) {
3089 continue; /* this'll break out of the loop */
3109 *param=0; /* always zero terminate */
3113 /* return 0 on everything-is-fine, and non-zero otherwise */
3114 static int parseconfig(const char *filename,
3115 struct Configurable *config)
3119 char filebuffer[512];
3124 if(!filename || !*filename) {
3125 /* NULL or no file name attempts to load .curlrc from the homedir! */
3127 #define CURLRC DOT_CHAR "curlrc"
3130 filename = CURLRC; /* sensible default */
3131 home = homedir(); /* portable homedir finder */
3133 if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
3134 snprintf(filebuffer, sizeof(filebuffer),
3135 "%s%s%s", home, DIR_CHAR, CURLRC);
3138 /* Check if the file exists - if not, try CURLRC in the same
3139 * directory as our executable
3141 file = fopen(filebuffer, "r");
3144 filename = filebuffer;
3147 /* Get the filename of our executable. GetModuleFileName is
3148 * already declared via inclusions done in setup header file.
3149 * We assume that we are using the ASCII version here.
3151 int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
3152 if (n > 0 && n < (int)sizeof(filebuffer)) {
3153 /* We got a valid filename - get the directory part */
3154 char *lastdirchar = strrchr(filebuffer, '\\');
3158 /* If we have enough space, build the RC filename */
3159 remaining = sizeof(filebuffer) - strlen(filebuffer);
3160 if (strlen(CURLRC) < remaining - 1) {
3161 snprintf(lastdirchar, remaining,
3162 "%s%s", DIR_CHAR, CURLRC);
3163 /* Don't bother checking if it exists - we do
3166 filename = filebuffer;
3172 filename = filebuffer;
3175 free(home); /* we've used it, now free it */
3178 # else /* __AMIGA__ */
3179 /* On AmigaOS all the config files are into env:
3181 filename = "ENV:" CURLRC;
3186 if(strcmp(filename,"-"))
3187 file = fopen(filename, "r");
3199 #define ISSEP(x) (((x)=='=') || ((x) == ':'))
3201 while (NULL != (aline = my_get_line(file))) {
3204 alloced_param=FALSE;
3206 /* line with # in the first non-blank column is a comment! */
3207 while(*line && ISSPACE(*line))
3221 /* the option keywords starts here */
3223 while(*line && !ISSPACE(*line) && !ISSEP(*line))
3225 /* ... and has ended here */
3228 *line++=0; /* zero terminate, we have a local copy of the data */
3231 fprintf(stderr, "GOT: %s\n", option);
3234 /* pass spaces and separator(s) */
3235 while(*line && (ISSPACE(*line) || ISSEP(*line)))
3238 /* the parameter starts here (unless quoted) */
3240 /* quoted parameter, do the quote dance */
3242 param=malloc(strlen(line)+1); /* parameter */
3250 (void)unslashquote(line, param);
3253 param=line; /* parameter starts here */
3254 while(*line && !ISSPACE(*line))
3256 *line=0; /* zero terminate */
3259 if (param && !*param) {
3260 /* do this so getparameter can check for required parameters.
3261 Otherwise it always thinks there's a parameter. */
3268 fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
3270 res = getparameter(option, param, &usedarg, config);
3272 if (param && *param && !usedarg)
3273 /* we passed in a parameter that wasn't used! */
3274 res = PARAM_GOT_EXTRA_PARAMETER;
3276 if(res != PARAM_OK) {
3277 /* the help request isn't really an error */
3278 if(!strcmp(filename, "-")) {
3279 filename=(char *)"<stdin>";
3281 if(PARAM_HELP_REQUESTED != res) {
3282 const char *reason = param2text(res);
3283 warnf(config, "%s:%d: warning: '%s' %s\n",
3284 filename, lineno, option, reason);
3300 rc = 1; /* couldn't open the file */
3304 static void go_sleep(long ms)
3306 #ifdef HAVE_POLL_FINE
3307 /* portable subsecond "sleep" */
3308 poll((void *)0, 0, (int)ms);
3310 /* systems without poll() need other solutions */
3313 /* Windows offers a millisecond sleep */
3315 #elif defined(MSDOS)
3318 /* Other systems must use select() for this */
3319 struct timeval timeout;
3321 timeout.tv_sec = ms/1000;
3323 timeout.tv_usec = ms * 1000;
3325 select(0, NULL, NULL, NULL, &timeout);
3331 static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
3334 struct OutStruct *out=(struct OutStruct *)stream;
3335 struct Configurable *config = out->config;
3338 * Once that libcurl has called back my_fwrite() the returned value
3339 * is checked against the amount that was intended to be written, if
3340 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
3341 * point returning a value different from sz*nmemb indicates failure.
3343 const size_t err_rc = (sz * nmemb) ? 0 : 1;
3346 if (!out->filename) {
3347 warnf(config, "Remote filename has no length!\n");
3348 return err_rc; /* Failure */
3351 if (config->content_disposition) {
3352 /* don't overwrite existing files */
3353 FILE* f = fopen(out->filename, "r");
3356 warnf(config, "Refusing to overwrite %s: %s\n", out->filename,
3358 return err_rc; /* Failure */
3362 /* open file for writing */
3363 out->stream=fopen(out->filename, "wb");
3365 warnf(config, "Failed to create the file %s: %s\n", out->filename,
3367 return err_rc; /* failure */
3371 rc = fwrite(buffer, sz, nmemb, out->stream);
3373 if((sz * nmemb) == rc) {
3374 /* we added this amount of data to the output */
3375 out->bytes += (sz * nmemb);
3378 if(config->readbusy) {
3379 config->readbusy = FALSE;
3380 curl_easy_pause(config->easy, CURLPAUSE_CONT);
3383 if(config->nobuffer) {
3384 /* disable output buffering */
3385 int res = fflush(out->stream);
3387 /* return a value that isn't the same as sz * nmemb */
3388 return err_rc; /* failure */
3397 struct Configurable *config;
3400 #define MAX_SEEK 2147483647
3403 * my_seek() is the CURLOPT_SEEKFUNCTION we use
3405 static int my_seek(void *stream, curl_off_t offset, int whence)
3407 struct InStruct *in=(struct InStruct *)stream;
3409 #if (CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
3410 /* The offset check following here is only interesting if curl_off_t is
3411 larger than off_t and we are not using the WIN32 large file support
3412 macros that provide the support to do 64bit seeks correctly */
3414 if(offset > MAX_SEEK) {
3415 /* Some precaution code to work around problems with different data sizes
3416 to allow seeking >32bit even if off_t is 32bit. Should be very rare and
3417 is really valid on weirdo-systems. */
3418 curl_off_t left = offset;
3420 if(whence != SEEK_SET)
3421 /* this code path doesn't support other types */
3424 if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
3425 /* couldn't rewind to beginning */
3429 long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
3430 if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
3431 /* couldn't seek forwards the desired amount */
3438 if(LSEEK_ERROR == lseek(in->fd, offset, whence))
3439 /* couldn't rewind, the reason is in errno but errno is just not portable
3440 enough and we don't actually care that much why we failed. We'll let
3441 libcurl know that it may try other means if it wants to. */
3442 return CURL_SEEKFUNC_CANTSEEK;
3447 static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
3450 struct InStruct *in=(struct InStruct *)userp;
3452 rc = read(in->fd, buffer, sz*nmemb);
3454 if(errno == EAGAIN) {
3456 in->config->readbusy = TRUE;
3457 return CURL_READFUNC_PAUSE;
3459 /* since size_t is unsigned we can't return negative values fine */
3462 in->config->readbusy = FALSE;
3466 struct ProgressData {
3470 FILE *out; /* where to write everything to */
3471 curl_off_t initial_size;
3474 static int myprogress (void *clientp,
3480 /* The original progress-bar source code was written for curl by Lars Aas,
3481 and this new edition inherits some of his concepts. */
3492 struct ProgressData *bar = (struct ProgressData *)clientp;
3493 curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
3494 bar->initial_size; /* expected transfer size */
3495 curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
3496 bar->initial_size; /* we've come this far */
3499 /* we have got more than the expected total! */
3502 bar->calls++; /* simply count invokes */
3505 curl_off_t prevblock = bar->prev / 1024;
3506 curl_off_t thisblock = point / 1024;
3507 while ( thisblock > prevblock ) {
3508 fprintf( bar->out, "#" );
3513 frac = (double)point / (double)total;
3514 percent = frac * 100.0f;
3515 barwidth = bar->width - 7;
3516 num = (int) (((double)barwidth) * frac);
3517 for ( i = 0; i < num; i++ ) {
3521 snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
3522 snprintf( outline, sizeof(outline), format, line, percent );
3523 fprintf( bar->out, "\r%s", outline );
3532 void progressbarinit(struct ProgressData *bar,
3533 struct Configurable *config)
3541 memset(bar, 0, sizeof(struct ProgressData));
3543 /* pass this through to progress function so
3544 * it can display progress towards total file
3545 * not just the part that's left. (21-may-03, dbyron) */
3546 if (config->use_resume)
3547 bar->initial_size = config->resume_from;
3549 /* TODO: get terminal width through ansi escapes or something similar.
3550 try to update width when xterm is resized... - 19990617 larsa */
3553 * OS/2 users most likely won't have this env var set, and besides that
3554 * we're using our own way to determine screen width */
3555 colp = curlx_getenv("COLUMNS");
3557 bar->width = atoi(colp);
3564 * We use this emx library call to get the screen width, and subtract
3565 * one from what we got in order to avoid a problem with the cursor
3566 * advancing to the next line if we print a string that is as long as
3567 * the screen is wide. */
3570 bar->width = scr_size[0] - 1;
3573 bar->out = config->errors;
3578 void dump(const char *timebuf, const char *text,
3579 FILE *stream, const unsigned char *ptr, size_t size,
3580 trace tracetype, curl_infotype infotype)
3585 unsigned int width=0x10;
3587 if(tracetype == TRACE_ASCII)
3588 /* without the hex output, we can fit more on screen */
3591 fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
3593 for(i=0; i<size; i+= width) {
3595 fprintf(stream, "%04zx: ", i);
3597 if(tracetype == TRACE_BIN) {
3598 /* hex not disabled, show it */
3599 for(c = 0; c < width; c++)
3601 fprintf(stream, "%02x ", ptr[i+c]);
3606 for(c = 0; (c < width) && (i+c < size); c++) {
3607 /* check for 0D0A; if found, skip past and start a new line of output */
3608 if ((tracetype == TRACE_ASCII) &&
3609 (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
3613 #ifdef CURL_DOES_CONVERSIONS
3614 /* repeat the 0D0A check above but use the host encoding for CRLF */
3615 if ((tracetype == TRACE_ASCII) &&
3616 (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') {
3620 /* convert to host encoding and print this character */
3621 fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
3624 fprintf(stream, "%c",
3625 (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR);
3626 #endif /* CURL_DOES_CONVERSIONS */
3627 /* check again for 0D0A, to avoid an extra \n if it's at width */
3628 if ((tracetype == TRACE_ASCII) &&
3629 (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
3634 fputc('\n', stream); /* newline */
3640 int my_trace(CURL *handle, curl_infotype type,
3641 unsigned char *data, size_t size,
3644 struct Configurable *config = (struct Configurable *)userp;
3645 FILE *output=config->errors;
3651 static time_t epoch_offset;
3652 static int known_offset;
3654 (void)handle; /* prevent compiler warning */
3656 if(config->tracetime) {
3659 epoch_offset = time(NULL) - tv.tv_sec;
3662 secs = epoch_offset + tv.tv_sec;
3663 now = localtime(&secs); /* not thread safe but we don't care */
3664 snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
3665 now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
3670 if(!config->trace_stream) {
3671 /* open for append */
3672 if(curlx_strequal("-", config->trace_dump))
3673 config->trace_stream = stdout;
3674 else if(curlx_strequal("%", config->trace_dump))
3675 /* Ok, this is somewhat hackish but we do it undocumented for now */
3676 config->trace_stream = config->errors; /* aka stderr */
3678 config->trace_stream = fopen(config->trace_dump, "w");
3679 config->trace_fopened = TRUE;
3683 if(config->trace_stream)
3684 output = config->trace_stream;
3687 warnf(config, "Failed to create/open output");
3691 if(config->tracetype == TRACE_PLAIN) {
3693 * This is the trace look that is similar to what libcurl makes on its
3696 static const char * const s_infotype[] = {
3697 "*", "<", ">", "{", "}", "{", "}"
3701 static bool newl = FALSE;
3702 static bool traced_data = FALSE;
3705 case CURLINFO_HEADER_OUT:
3706 for(i=0; i<size-1; i++) {
3707 if(data[i] == '\n') { /* LF */
3709 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3711 (void)fwrite(data+st, i-st+1, 1, output);
3717 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3718 (void)fwrite(data+st, i-st+1, 1, output);
3719 newl = (bool)(size && (data[size-1] != '\n'));
3720 traced_data = FALSE;
3723 case CURLINFO_HEADER_IN:
3725 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3726 (void)fwrite(data, size, 1, output);
3727 newl = (bool)(size && (data[size-1] != '\n'));
3728 traced_data = FALSE;
3730 case CURLINFO_DATA_OUT:
3731 case CURLINFO_DATA_IN:
3732 case CURLINFO_SSL_DATA_IN:
3733 case CURLINFO_SSL_DATA_OUT:
3735 /* if the data is output to a tty and we're sending this debug trace
3736 to stderr or stdout, we don't display the alert about the data not
3737 being shown as the data _is_ shown then just not via this
3739 if(!config->isatty ||
3740 ((output != stderr) && (output != stdout))) {
3742 fprintf(output, "%s%s ", timebuf, s_infotype[type]);
3743 fprintf(output, "[data not shown]\n");
3751 traced_data = FALSE;
3758 #ifdef CURL_DOES_CONVERSIONS
3759 /* Special processing is needed for CURLINFO_HEADER_OUT blocks
3760 * if they contain both headers and data (separated by CRLFCRLF).
3761 * We dump the header text and then switch type to CURLINFO_DATA_OUT.
3763 if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
3765 for(i = 0; i < size - 4; i++) {
3766 if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
3767 /* dump everthing through the CRLFCRLF as a sent header */
3768 text = "=> Send header";
3769 dump(timebuf, text, output, data, i+4, config->tracetype, type);
3772 type = CURLINFO_DATA_OUT;
3778 #endif /* CURL_DOES_CONVERSIONS */
3782 fprintf(output, "%s== Info: %s", timebuf, data);
3783 default: /* in case a new one is introduced to shock us */
3786 case CURLINFO_HEADER_OUT:
3787 text = "=> Send header";
3789 case CURLINFO_DATA_OUT:
3790 text = "=> Send data";
3792 case CURLINFO_HEADER_IN:
3793 text = "<= Recv header";
3795 case CURLINFO_DATA_IN:
3796 text = "<= Recv data";
3798 case CURLINFO_SSL_DATA_IN:
3799 text = "<= Recv SSL data";
3801 case CURLINFO_SSL_DATA_OUT:
3802 text = "=> Send SSL data";
3806 dump(timebuf, text, output, data, size, config->tracetype, type);
3810 static void free_config_fields(struct Configurable *config)
3812 if(config->random_file)
3813 free(config->random_file);
3814 if(config->egd_file)
3815 free(config->egd_file);
3816 if(config->trace_dump)
3817 free(config->trace_dump);
3818 if(config->cipher_list)
3819 free(config->cipher_list);
3821 free(config->userpwd);
3822 if(config->postfields)
3823 free(config->postfields);
3825 free(config->proxy);
3826 if(config->proxyuserpwd)
3827 free(config->proxyuserpwd);
3829 free(config->noproxy);
3831 free(config->cookie);
3832 if(config->cookiefile)
3833 free(config->cookiefile);
3834 if(config->krblevel)
3835 free(config->krblevel);
3836 if(config->headerfile)
3837 free(config->headerfile);
3839 free(config->ftpport);
3841 free(config->range);
3842 if(config->customrequest)
3843 free(config->customrequest);
3844 if(config->writeout)
3845 free(config->writeout);
3846 if(config->httppost)
3847 curl_formfree(config->httppost);
3851 free(config->cacert);
3852 if (config->cert_type)
3853 free(config->cert_type);
3855 free(config->capath);
3857 free(config->crlfile);
3858 if(config->cookiejar)
3859 free(config->cookiejar);
3860 if(config->ftp_account)
3861 free(config->ftp_account);
3862 if(config->ftp_alternative_to_user)
3863 free(config->ftp_alternative_to_user);
3865 free(config->iface);
3866 if(config->socksproxy)
3867 free(config->socksproxy);
3869 free(config->libcurl);
3870 if (config->key_passwd)
3871 free(config->key_passwd);
3874 if (config->key_type)
3875 free(config->key_type);
3877 free(config->pubkey);
3878 if (config->referer)
3879 free(config->referer);
3880 if (config->hostpubmd5)
3881 free(config->hostpubmd5);
3882 if(config->mail_from)
3883 free(config->mail_from);
3884 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
3885 if(config->socks5_gssapi_service)
3886 free(config->socks5_gssapi_service);
3889 curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
3890 curl_slist_free_all(config->prequote);
3891 curl_slist_free_all(config->postquote);
3892 curl_slist_free_all(config->headers);
3893 curl_slist_free_all(config->telnet_options);
3894 curl_slist_free_all(config->mail_rcpt);
3897 curl_easy_cleanup(config->easy);
3902 /* Function to find CACert bundle on a Win32 platform using SearchPath.
3903 * (SearchPath is already declared via inclusions done in setup header file)
3904 * (Use the ASCII version instead of the unicode one!)
3905 * The order of the directories it searches is:
3906 * 1. application's directory
3907 * 2. current working directory
3908 * 3. Windows System directory (e.g. C:\windows\system32)
3909 * 4. Windows Directory (e.g. C:\windows)
3910 * 5. all directories along %PATH%
3912 static void FindWin32CACert(struct Configurable *config,
3913 const char *bundle_file)
3915 /* only check for cert file if "we" support SSL */
3916 if(curlinfo->features & CURL_VERSION_SSL) {
3919 char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1));
3923 buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
3925 GetStr(&config->cacert, retval);
3933 #define RETRY_SLEEP_DEFAULT 1000 /* ms */
3934 #define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */
3937 output_expected(const char* url, const char* uploadfile)
3940 return TRUE; /* download */
3941 if(checkprefix("http://", url) || checkprefix("https://", url))
3942 return TRUE; /* HTTP(S) upload */
3944 return FALSE; /* non-HTTP upload, probably no output should be expected */
3947 #define my_setopt(x,y,z) _my_setopt(x, 0, config, #y, y, z)
3948 #define my_setopt_str(x,y,z) _my_setopt(x, 1, config, #y, y, z)
3950 static struct curl_slist *easycode;
3952 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
3953 const char *name, CURLoption tag, ...);
3955 static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
3956 const char *name, CURLoption tag, ...)
3966 if(tag < CURLOPTTYPE_OBJECTPOINT) {
3967 long lval = va_arg(arg, long);
3968 snprintf(value, sizeof(value), "%ld", lval);
3969 ret = curl_easy_setopt(curl, tag, lval);
3972 else if(tag < CURLOPTTYPE_OFF_T) {
3973 void *pval = va_arg(arg, void *);
3974 unsigned char *ptr = (unsigned char *)pval;
3976 /* function pointers are never printable */
3977 if (tag >= CURLOPTTYPE_FUNCTIONPOINT) {
3979 snprintf(value, sizeof(value), "%p", pval);
3983 strcpy(value, "NULL");
3986 else if(pval && str)
3987 snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
3989 snprintf(value, sizeof(value), "%p", pval);
3993 strcpy(value, "NULL"); /* value fits more than 5 bytes */
3995 ret = curl_easy_setopt(curl, tag, pval);
3999 curl_off_t oval = va_arg(arg, curl_off_t);
4000 snprintf(value, sizeof(value), "%" CURL_FORMAT_CURL_OFF_T, oval);
4001 ret = curl_easy_setopt(curl, tag, oval);
4004 if(config->libcurl) {
4005 /* we only use this for real if --libcurl was used */
4007 bufp = curlx_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s",
4008 remark?"/* ":"", name, value,
4009 remark?" [REMARK] */":"");
4011 if (!bufp || !curl_slist_append(easycode, bufp))
4012 ret = CURLE_OUT_OF_MEMORY;
4021 static const char * const srchead[]={
4022 "/********* Sample code generated by the curl command line tool **********",
4023 " * Lines with [REMARK] below might need to be modified to make this code ",
4024 " * usable. Add error code checking where appropriate.",
4025 " * Compile this with a suitable header include path. Then link with ",
4027 " * If you use any *_LARGE options, make sure your compiler figure",
4028 " * out the correct size for the curl_off_t variable.",
4029 " * Read the details for all curl_easy_setopt() options online on:",
4030 " * http://curlm.haxx.se/libcurl/c/curl_easy_setopt.html",
4031 " ************************************************************************/",
4033 "#include <curl/curl.h>",
4035 "int main(int argc, char *argv[])",
4041 static void dumpeasycode(struct Configurable *config)
4043 struct curl_slist *ptr = easycode;
4044 char *o = config->libcurl;
4048 bool fopened = FALSE;
4049 if(strcmp(o, "-")) {
4050 out = fopen(o, "wt");
4056 warnf(config, "Failed to open %s to write libcurl code!\n", o);
4061 for(i=0; (c = srchead[i]); i++) {
4062 if(!memcmp((char *)c, "[m]", 3)) {
4063 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS > 32)
4064 fprintf(out, "#define _FILE_OFFSET_BITS %d "
4065 "/* for pre libcurl 7.19.0 curl_off_t magic */\n",
4070 fprintf(out, "%s\n", c);
4074 fprintf(out, " %s\n", ptr->data);
4078 " return (int)ret;\n"
4080 "/**** End of sample code ****/\n");
4085 curl_slist_free_all(easycode);
4088 static bool stdin_upload(const char *uploadfile)
4090 return (bool)(curlx_strequal(uploadfile, "-") ||
4091 curlx_strequal(uploadfile, "."));
4094 /* Adds the file name to the URL if it doesn't already have one.
4095 * url will be freed before return if the returned pointer is different
4097 static char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
4099 /* If no file name part is given in the URL, we add this file name */
4100 char *ptr=strstr(url, "://");
4105 ptr = strrchr(ptr, '/');
4106 if(!ptr || !strlen(++ptr)) {
4107 /* The URL has no file name part, add the local file name. In order
4108 to be able to do so, we have to create a new URL in another
4111 /* We only want the part of the local path that is on the right
4112 side of the rightmost slash and backslash. */
4113 const char *filep = strrchr(filename, '/');
4114 char *file2 = strrchr(filep?filep:filename, '\\');
4124 /* URL encode the file name */
4125 encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
4127 char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
4133 /* there is a trailing slash on the URL */
4134 sprintf(urlbuffer, "%s%s", url, encfile);
4136 /* there is no trailing slash on the URL */
4137 sprintf(urlbuffer, "%s/%s", url, encfile);
4142 url = urlbuffer; /* use our new URL instead! */
4148 /* Extracts the name portion of the URL.
4149 * Returns a heap-allocated string, or NULL if no name part
4151 static char *get_url_file_name(const char *url)
4155 /* Find and get the remote file name */
4156 const char * pc =strstr(url, "://");
4161 pc = strrchr(pc, '/');
4164 /* duplicate the string beyond the slash */
4166 fn = *pc ? strdup(pc): NULL;
4172 parse_filename(char *ptr, size_t len)
4179 /* simple implementation of strndup() */
4180 copy = malloc(len+1);
4183 strncpy(copy, ptr, len);
4187 if (*p == '\'' || *p == '"') {
4188 /* store the starting quote */
4193 /* if the filename contains a path, only use filename portion */
4194 q = strrchr(copy, '/');
4204 /* if the file name started with a quote, then scan for the end quote and
4206 q = strrchr(p, quote);
4211 q = NULL; /* no start quote, so no end has been found */
4214 /* make sure the file name doesn't end in \r or \n */
4215 q = strchr(p, '\r');
4219 q = strchr(p, '\n');
4225 memmove(copy, p, strlen(p)+1);
4231 header_callback(void *ptr, size_t size, size_t nmemb, void *stream)
4233 struct OutStruct* outs = (struct OutStruct*)stream;
4234 const char* str = (char*)ptr;
4235 const size_t cb = size*nmemb;
4236 const char* end = (char*)ptr + cb;
4238 if (cb > 20 && curlx_strnequal(str, "Content-disposition:", 20)) {
4239 char *p = (char*)str + 20;
4241 /* look for the 'filename=' parameter
4242 (encoded filenames (*=) are not supported) */
4246 while (*p && (p < end) && !ISALPHA(*p))
4251 if (memcmp(p, "filename=", 9)) {
4252 /* no match, find next parameter */
4253 while ((p < end) && (*p != ';'))
4258 filename = parse_filename(p, cb - (p - str));
4260 outs->filename = filename;
4270 operate(struct Configurable *config, int argc, argv_item_t argv[])
4272 char errorbuffer[CURL_ERROR_SIZE];
4273 char useragent[256]; /* buah, we don't want a larger default user agent */
4274 struct ProgressData progressbar;
4275 struct getout *urlnode;
4276 struct getout *nextnode;
4278 struct OutStruct outs;
4279 struct OutStruct heads;
4280 struct InStruct input;
4283 URLGlob *inglob=NULL;
4286 char *uploadfile=NULL; /* a single file, never a glob */
4288 curl_off_t uploadfilesize; /* -1 means unknown */
4289 bool stillflags=TRUE;
4291 bool allocuseragent=FALSE;
4293 char *httpgetfields=NULL;
4298 long retry_sleep_default;
4303 memset(&heads, 0, sizeof(struct OutStruct));
4306 /* this sends all memory debug messages to a logfile named memdump */
4307 env = curlx_getenv("CURL_MEMDEBUG");
4309 /* use the value as file name */
4310 char *s = strdup(env);
4314 /* this weird strdup() and stuff here is to make the curl_free() get
4315 called before the memdebug() as otherwise the memdebug tracing will
4316 with tracing a free() without an alloc! */
4318 env = curlx_getenv("CURL_MEMLIMIT");
4320 curl_memlimit(atoi(env));
4325 /* Initialize curl library - do not call any libcurl functions before.
4326 Note that the CURLDEBUG magic above is an exception, but then that's not
4327 part of the official public API.
4329 if (main_init() != CURLE_OK) {
4330 helpf(config->errors, "error initializing curl library\n");
4331 return CURLE_FAILED_INIT;
4335 * Get a curl handle to use for all forthcoming curl transfers. Cleanup
4336 * when all transfers are done.
4338 curl = curl_easy_init();
4340 clean_getout(config);
4341 return CURLE_FAILED_INIT;
4343 config->easy = curl;
4345 memset(&outs,0,sizeof(outs));
4347 config->outs = &outs;
4349 /* we get libcurl info right away */
4350 curlinfo = curl_version_info(CURLVERSION_NOW);
4352 errorbuffer[0]=0; /* prevent junk from being output */
4354 /* setup proper locale from environment */
4355 #ifdef HAVE_SETLOCALE
4356 setlocale(LC_ALL, "");
4360 config->postfieldsize = -1;
4361 config->showerror=TRUE;
4362 config->use_httpget=FALSE;
4363 config->create_dirs=FALSE;
4364 config->maxredirs = DEFAULT_MAXREDIRS;
4367 (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
4368 strchr(argv[1], 'q')) {
4370 * The first flag, that is not a verbose name, but a shortname
4371 * and it includes the 'q' flag!
4376 parseconfig(NULL, config); /* ignore possible failure */
4379 if ((argc < 2) && !config->url_list) {
4380 helpf(config->errors, NULL);
4381 return CURLE_FAILED_INIT;
4385 for (i = 1; i < argc; i++) {
4387 ('-' == argv[i][0])) {
4390 char *origopt=argv[i];
4392 char *flag = argv[i];
4394 if(curlx_strequal("--", argv[i]))
4395 /* this indicates the end of the flags and thus enables the
4396 following (URL) argument to start with -. */
4399 nextarg= (i < argc - 1)? argv[i+1]: NULL;
4401 res = getparameter(flag, nextarg, &passarg, config);
4403 int retval = CURLE_OK;
4404 if(res != PARAM_HELP_REQUESTED) {
4405 const char *reason = param2text(res);
4406 helpf(config->errors, "option %s: %s\n", origopt, reason);
4407 retval = CURLE_FAILED_INIT;
4409 clean_getout(config);
4413 if(passarg) /* we're supposed to skip this */
4419 /* just add the URL please */
4420 res = getparameter((char *)"--url", argv[i], &used, config);
4426 retry_sleep_default = config->retry_delay?
4427 config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
4428 retry_sleep = retry_sleep_default;
4430 if((!config->url_list || !config->url_list->url) && !config->list_engines) {
4431 clean_getout(config);
4432 helpf(config->errors, "no URL specified!\n");
4433 return CURLE_FAILED_INIT;
4435 if(NULL == config->useragent) {
4436 /* set non-zero default values: */
4437 snprintf(useragent, sizeof(useragent),
4438 CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
4439 config->useragent= useragent;
4442 allocuseragent = TRUE;
4444 /* On WIN32 we can't set the path to curl-ca-bundle.crt
4445 * at compile time. So we look here for the file in two ways:
4446 * 1: look at the environment variable CURL_CA_BUNDLE for a path
4447 * 2: if #1 isn't found, use the windows API function SearchPath()
4448 * to find it along the app's path (includes app's dir and CWD)
4450 * We support the environment variable thing for non-Windows platforms
4451 * too. Just for the sake of it.
4453 if (!config->cacert &&
4455 !config->insecure_ok) {
4456 env = curlx_getenv("CURL_CA_BUNDLE");
4458 GetStr(&config->cacert, env);
4460 env = curlx_getenv("SSL_CERT_DIR");
4462 GetStr(&config->capath, env);
4464 env = curlx_getenv("SSL_CERT_FILE");
4466 GetStr(&config->cacert, env);
4474 FindWin32CACert(config, "curl-ca-bundle.crt");
4478 if (config->postfields) {
4479 if (config->use_httpget) {
4480 /* Use the postfields data for a http get */
4481 httpgetfields = strdup(config->postfields);
4482 free(config->postfields);
4483 config->postfields = NULL;
4484 if(SetHTTPrequest(config,
4485 (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
4486 &config->httpreq)) {
4487 free(httpgetfields);
4488 return PARAM_BAD_USE;
4492 if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
4493 return PARAM_BAD_USE;
4497 /* This is the first entry added to easycode and it initializes the slist */
4498 easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();");
4500 clean_getout(config);
4501 res = CURLE_OUT_OF_MEMORY;
4505 if (config->list_engines) {
4506 struct curl_slist *engines = NULL;
4508 curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
4509 list_engines(engines);
4510 curl_slist_free_all(engines);
4515 /* After this point, we should call curl_easy_cleanup() if we decide to bail
4516 * out from this function! */
4518 urlnode = config->url_list;
4520 if(config->headerfile) {
4521 /* open file for output: */
4522 if(strcmp(config->headerfile,"-")) {
4523 heads.filename = config->headerfile;
4526 heads.stream=stdout;
4527 heads.config = config;
4530 /* loop through the list of given URLs */
4532 int up; /* upload file counter within a single upload glob */
4535 char *infiles; /* might be a glob pattern */
4536 char *outfiles=NULL;
4538 /* get the full URL (it might be NULL) */
4544 /* This node had no URL, skip it and continue to the next */
4545 if(urlnode->outfile)
4546 free(urlnode->outfile);
4548 /* move on to the next URL */
4549 nextnode=urlnode->next;
4550 free(urlnode); /* free the node */
4552 continue; /* next please */
4555 /* default output stream is stdout */
4556 outs.stream = stdout;
4557 outs.config = config;
4558 outs.bytes = 0; /* nothing written yet */
4560 /* save outfile pattern before expansion */
4561 if (urlnode->outfile) {
4562 outfiles = strdup(urlnode->outfile);
4564 clean_getout(config);
4569 infiles = urlnode->infile;
4571 if(!config->globoff && infiles) {
4572 /* Unless explicitly shut off */
4573 res = glob_url(&inglob, infiles, &infilenum,
4574 config->showerror?config->errors:NULL);
4575 if(res != CURLE_OK) {
4576 clean_getout(config);
4583 /* Here's the loop for uploading multiple files within the same
4584 single globbed string. If no upload, we enter the loop once anyway. */
4586 (!up && !infiles) ||
4587 (uploadfile = inglob?
4588 glob_next_url(inglob):
4589 (!up?strdup(infiles):NULL));
4592 long retry_numretries;
4595 if(!config->globoff) {
4596 /* Unless explicitly shut off, we expand '{...}' and '[...]'
4597 expressions and return total number of URLs in pattern set */
4598 res = glob_url(&urls, dourl, &urlnum,
4599 config->showerror?config->errors:NULL);
4600 if(res != CURLE_OK) {
4605 urlnum = 1; /* without globbing, this is a single URL */
4607 /* if multiple files extracted to stdout, insert separators! */
4608 separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
4610 /* Here's looping around each globbed URL */
4612 (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
4614 /* NOTE: In the condition expression in the for() statement above, the
4615 'url' variable is only ever strdup()ed if (i == 0) and thus never
4616 when this loops later on. Further down in this function we call
4617 free(url) and then the code loops. Static code parsers may thus get
4618 tricked into believing that we have a potential access-after-free
4619 here. I can however not spot any such case. */
4621 int infd = STDIN_FILENO;
4624 struct timeval retrystart;
4625 outfile = outfiles?strdup(outfiles):NULL;
4627 if((urlnode->flags&GETOUT_USEREMOTE) ||
4628 (outfile && !curlx_strequal("-", outfile)) ) {
4631 * We have specified a file name to store the result in, or we have
4632 * decided we want to use the remote file name.
4636 /* extract the file name from the URL */
4637 outfile = get_url_file_name(url);
4638 if((!outfile || !*outfile) && !config->content_disposition) {
4639 helpf(config->errors, "Remote file name has no length!\n");
4640 res = CURLE_WRITE_ERROR;
4644 #if defined(MSDOS) || defined(WIN32)
4645 /* For DOS and WIN32, we do some major replacing of
4646 bad characters in the file name before using it */
4647 outfile = sanitize_dos_name(outfile);
4649 res = CURLE_OUT_OF_MEMORY;
4652 #endif /* MSDOS || WIN32 */
4655 /* fill '#1' ... '#9' terms from URL pattern */
4656 char *storefile = outfile;
4657 outfile = glob_match_url(storefile, urls);
4661 warnf(config, "bad output glob!\n");
4663 res = CURLE_FAILED_INIT;
4668 /* Create the directory hierarchy, if not pre-existant to a multiple
4671 if(config->create_dirs &&
4672 (-1 == create_dir_hierarchy(outfile, config->errors))) {
4674 res = CURLE_WRITE_ERROR;
4678 if(config->resume_from_current) {
4679 /* We're told to continue from where we are now. Get the
4680 size of the file as it is now and open it for append instead */
4682 struct_stat fileinfo;
4684 /* VMS -- Danger, the filesize is only valid for stream files */
4685 if(0 == stat(outfile, &fileinfo))
4686 /* set offset to current file size: */
4687 config->resume_from = fileinfo.st_size;
4689 /* let offset be 0 */
4690 config->resume_from = 0;
4693 outs.filename = outfile;
4695 if(config->resume_from) {
4696 outs.init = config->resume_from;
4697 /* open file for output: */
4698 outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
4700 helpf(config->errors, "Can't open '%s'!\n", outfile);
4702 res = CURLE_WRITE_ERROR;
4707 outs.stream = NULL; /* open when needed */
4711 if(uploadfile && !stdin_upload(uploadfile)) {
4713 * We have specified a file to upload and it isn't "-".
4715 struct_stat fileinfo;
4717 url = add_file_name_to_url(curl, url, uploadfile);
4719 helpf(config->errors, "out of memory\n");
4720 res = CURLE_OUT_OF_MEMORY;
4725 * Reading binary from files can be a problem... Only FIXED, VAR
4726 * etc WITHOUT implied CC will work Others need a \n appended to a
4729 * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
4730 * fixed file with implied CC needs to have a byte added for every
4731 * record processed, this can by derived from Filesize & recordsize
4732 * for VARiable record files the records need to be counted! for
4733 * every record add 1 for linefeed and subtract 2 for the record
4734 * header for VARIABLE header files only the bare record data needs
4735 * to be considered with one appended if implied CC
4738 infd= open(uploadfile, O_RDONLY | O_BINARY);
4739 if ((infd == -1) || fstat(infd, &fileinfo)) {
4740 helpf(config->errors, "Can't open '%s'!\n", uploadfile);
4744 /* Free the list of remaining URLs and globbed upload files
4745 * to force curl to exit immediately
4752 glob_cleanup(inglob);
4756 res = CURLE_READ_ERROR;
4760 uploadfilesize=fileinfo.st_size;
4763 else if(uploadfile && stdin_upload(uploadfile)) {
4765 infd = STDIN_FILENO;
4766 if (curlx_strequal(uploadfile, ".")) {
4767 if (curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
4769 "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
4773 if(uploadfile && config->resume_from_current)
4774 config->resume_from = -1; /* -1 will then force get-it-yourself */
4776 if(output_expected(url, uploadfile)
4777 && outs.stream && isatty(fileno(outs.stream)))
4778 /* we send the output to a tty, therefore we switch off the progress
4780 config->noprogress = config->isatty = TRUE;
4782 if (urlnum > 1 && !(config->mute)) {
4783 fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
4784 i+1, urlnum, url, outfile ? outfile : "<stdout>");
4786 printf("%s%s\n", CURLseparator, url);
4788 if (httpgetfields) {
4790 /* Find out whether the url contains a file name */
4791 const char *pc =strstr(url, "://");
4798 pc = strrchr(pc, '/'); /* check for a slash */
4801 /* there is a slash present in the URL */
4804 /* Ouch, there's already a question mark in the URL string, we
4805 then append the data with an ampersand separator instead! */
4809 * Then append ? followed by the get fields to the url.
4811 urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
4813 helpf(config->errors, "out of memory\n");
4815 /* Free the list of remaining URLs and globbed upload files
4816 * to force curl to exit immediately
4823 glob_cleanup(inglob);
4827 res = CURLE_OUT_OF_MEMORY;
4831 sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
4833 /* Append / before the ? to create a well-formed url
4834 if the url contains a hostname only
4836 sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
4838 free(url); /* free previous URL */
4839 url = urlbuffer; /* use our new URL instead! */
4843 config->errors = stderr;
4845 if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
4846 /* We get the output to stdout and we have not got the ASCII/text
4847 flag, then set stdout to be binary */
4848 SET_BINMODE(stdout);
4851 if(1 == config->tcp_nodelay)
4852 my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
4854 /* where to store */
4855 my_setopt(curl, CURLOPT_WRITEDATA, &outs);
4856 /* what call to write */
4857 my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
4861 input.config = config;
4862 my_setopt(curl, CURLOPT_READDATA, &input);
4863 /* what call to read */
4864 my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
4866 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
4867 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
4868 my_setopt(curl, CURLOPT_SEEKDATA, &input);
4869 my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
4871 if(config->recvpersecond)
4872 /* tell libcurl to use a smaller sized buffer as it allows us to
4873 make better sleeps! 7.9.9 stuff! */
4874 my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
4876 /* size of uploaded file: */
4877 my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
4878 my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */
4879 my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
4881 my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
4882 my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
4883 if(config->no_body) {
4884 my_setopt(curl, CURLOPT_NOBODY, 1);
4885 my_setopt(curl, CURLOPT_HEADER, 1);
4888 my_setopt(curl, CURLOPT_HEADER, config->include_headers);
4890 my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
4891 my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
4892 my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
4893 my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
4895 if (config->netrc_opt)
4896 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
4897 else if (config->netrc)
4898 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
4900 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
4902 my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
4903 my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth);
4904 my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
4905 my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
4906 my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
4907 my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
4908 my_setopt_str(curl, CURLOPT_RANGE, config->range);
4909 my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
4910 my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
4912 switch(config->httpreq) {
4913 case HTTPREQ_SIMPLEPOST:
4914 my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields);
4915 my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize);
4918 my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
4923 my_setopt_str(curl, CURLOPT_REFERER, config->referer);
4924 my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
4925 my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
4926 my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
4927 my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
4928 config->low_speed_limit);
4929 my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
4930 my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
4931 config->sendpersecond);
4932 my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
4933 config->recvpersecond);
4934 my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
4935 config->use_resume?config->resume_from:0);
4936 my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
4937 my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
4938 my_setopt(curl, CURLOPT_SSLCERT, config->cert);
4939 my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
4940 my_setopt(curl, CURLOPT_SSLKEY, config->key);
4941 my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
4942 my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
4944 /* SSH private key uses the same command-line option as SSL private
4946 my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
4947 my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
4949 /* SSH host key md5 checking allows us to fail if we are
4950 * not talking to who we think we should
4952 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
4953 config->hostpubmd5);
4955 /* default to strict verifyhost */
4956 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
4957 if(config->cacert || config->capath) {
4959 my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
4962 my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
4963 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
4965 if (config->crlfile)
4966 my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
4967 if(config->insecure_ok) {
4968 /* new stuff needed for libcurl 7.10 */
4969 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
4970 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
4973 char *home = homedir();
4974 char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
4979 my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
4983 /* Free the list of remaining URLs and globbed upload files
4984 * to force curl to exit immediately
4991 glob_cleanup(inglob);
4995 res = CURLE_OUT_OF_MEMORY;
5000 if(config->no_body || config->remote_time) {
5001 /* no body or use remote time */
5002 my_setopt(curl, CURLOPT_FILETIME, TRUE);
5005 my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
5006 my_setopt(curl, CURLOPT_CRLF, config->crlf);
5007 my_setopt(curl, CURLOPT_QUOTE, config->quote);
5008 my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
5009 my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
5010 my_setopt(curl, CURLOPT_HEADERDATA,
5011 config->headerfile?&heads:NULL);
5012 my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
5013 /* cookie jar was added in 7.9 */
5014 if(config->cookiejar)
5015 my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
5016 /* cookie session added in 7.9.7 */
5017 my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
5019 my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
5020 my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
5021 my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
5022 my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
5023 my_setopt(curl, CURLOPT_STDERR, config->errors);
5025 /* three new ones in libcurl 7.3: */
5026 my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
5027 my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
5028 my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
5030 progressbarinit(&progressbar, config);
5031 if((config->progressmode == CURL_PROGRESS_BAR) &&
5032 !config->noprogress && !config->mute) {
5033 /* we want the alternative style, then we have to implement it
5035 my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
5036 my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
5039 /* new in libcurl 7.6.2: */
5040 my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
5042 /* new in libcurl 7.7: */
5043 my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
5044 my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
5045 my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
5047 if(config->cipher_list)
5048 my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
5050 if(config->httpversion)
5051 my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
5053 /* new in libcurl 7.9.2: */
5054 if(config->disable_epsv)
5056 my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
5058 /* new in libcurl 7.10.5 */
5059 if(config->disable_eprt)
5061 my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
5063 /* new in libcurl 7.10.6 (default is Basic) */
5064 if(config->authtype)
5065 my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
5067 if(config->tracetype != TRACE_NONE) {
5068 my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
5069 my_setopt(curl, CURLOPT_DEBUGDATA, config);
5070 my_setopt(curl, CURLOPT_VERBOSE, TRUE);
5075 /* new in curl ?? */
5076 if (config->engine) {
5077 res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
5078 my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
5081 if (res != CURLE_OK)
5084 /* new in curl 7.10 */
5085 my_setopt_str(curl, CURLOPT_ENCODING,
5086 (config->encoding) ? "" : NULL);
5088 /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
5089 my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
5090 config->ftp_create_dirs);
5091 if(config->proxyanyauth)
5092 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
5093 else if(config->proxynegotiate)
5094 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
5095 else if(config->proxyntlm)
5096 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
5097 else if(config->proxydigest)
5098 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
5099 else if(config->proxybasic)
5100 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
5102 /* new in curl 7.10.8 */
5103 if(config->max_filesize)
5104 my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
5105 config->max_filesize);
5107 if(4 == config->ip_version)
5108 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
5109 else if(6 == config->ip_version)
5110 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
5112 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
5114 /* new in curl 7.15.5 */
5115 if(config->ftp_ssl_reqd)
5116 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
5118 /* new in curl 7.11.0 */
5119 else if(config->ftp_ssl)
5120 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
5122 /* new in curl 7.16.0 */
5123 else if(config->ftp_ssl_control)
5124 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
5126 /* new in curl 7.16.1 */
5127 if(config->ftp_ssl_ccc)
5128 my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
5130 /* new in curl 7.11.1, modified in 7.15.2 */
5131 if(config->socksproxy) {
5132 my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
5133 my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
5136 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
5137 /* new in curl 7.19.4 */
5138 if(config->socks5_gssapi_service)
5139 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
5140 config->socks5_gssapi_service);
5142 /* new in curl 7.19.4 */
5143 if(config->socks5_gssapi_nec)
5144 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
5145 config->socks5_gssapi_nec);
5148 my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
5150 my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
5153 my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
5156 my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
5159 if(config->localport) {
5160 my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
5161 my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
5162 config->localportrange);
5166 my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
5167 config->ftp_alternative_to_user);
5170 my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
5171 !config->disable_sessionid);
5175 my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
5176 my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
5180 if (!config->nokeepalive) {
5181 my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
5182 my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
5185 /* curl 7.19.1 (the 301 version existed in 7.18.2) */
5186 my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
5187 (config->post302 ? CURL_REDIR_POST_302 : FALSE));
5190 if(config->tftp_blksize)
5191 my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
5193 if(config->mail_from)
5194 my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
5196 if(config->mail_rcpt)
5197 my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
5200 if(config->ftp_pret)
5201 my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
5203 if ((urlnode->flags & GETOUT_USEREMOTE)
5204 && config->content_disposition) {
5205 my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
5206 my_setopt(curl, CURLOPT_HEADERDATA, &outs);
5209 retry_numretries = config->req_retry;
5211 retrystart = cutil_tvnow();
5214 res = curl_easy_perform(curl);
5215 if (!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
5216 res = CURLE_OUT_OF_MEMORY;
5220 if (config->content_disposition && outs.stream && !config->mute)
5221 printf("curl: Saved to filename '%s'\n", outs.filename);
5223 /* if retry-max-time is non-zero, make sure we haven't exceeded the
5225 if(retry_numretries &&
5226 (!config->retry_maxtime ||
5227 (cutil_tvdiff(cutil_tvnow(), retrystart)<
5228 config->retry_maxtime*1000)) ) {
5234 RETRY_LAST /* not used */
5237 if(CURLE_OPERATION_TIMEDOUT == res)
5238 /* retry timeout always */
5239 retry = RETRY_TIMEOUT;
5240 else if(CURLE_OK == res) {
5241 /* Check for HTTP transient errors */
5242 char *this_url=NULL;
5243 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url);
5245 curlx_strnequal(this_url, "http", 4)) {
5246 /* This was HTTP(S) */
5247 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5250 case 500: /* Internal Server Error */
5251 case 502: /* Bad Gateway */
5252 case 503: /* Service Unavailable */
5253 case 504: /* Gateway Timeout */
5256 * At this point, we have already written data to the output
5257 * file (or terminal). If we write to a file, we must rewind
5258 * or close/re-open the file so that the next attempt starts
5259 * over from the beginning.
5261 * TODO: similar action for the upload case. We might need
5262 * to start over reading from a previous point if we have
5263 * uploaded something when this was returned.
5270 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
5272 if(response/100 == 4)
5274 * This is typically when the FTP server only allows a certain
5275 * amount of users and we are not one of them. All 4xx codes
5282 static const char * const m[]={
5283 NULL, "timeout", "HTTP error", "FTP error"
5285 warnf(config, "Transient problem: %s "
5286 "Will retry in %ld seconds. "
5287 "%ld retries left.\n",
5288 m[retry], retry_sleep/1000, retry_numretries);
5290 go_sleep(retry_sleep);
5292 if(!config->retry_delay) {
5294 if(retry_sleep > RETRY_SLEEP_MAX)
5295 retry_sleep = RETRY_SLEEP_MAX;
5297 if(outs.bytes && outs.filename) {
5298 /* We have written data to a output file, we truncate file
5301 fprintf(config->errors, "Throwing away %"
5302 CURL_FORMAT_CURL_OFF_T " bytes\n",
5304 fflush(outs.stream);
5305 /* truncate file at the position where we started appending */
5306 #ifdef HAVE_FTRUNCATE
5307 if(ftruncate( fileno(outs.stream), outs.init)) {
5308 /* when truncate fails, we can't just append as then we'll
5309 create something strange, bail out */
5311 fprintf(config->errors,
5312 "failed to truncate, exiting\n");
5315 /* now seek to the end of the file, the position where we
5316 just truncated the file in a large file-safe way */
5317 fseek(outs.stream, 0, SEEK_END);
5319 /* ftruncate is not available, so just reposition the file
5320 to the location we would have truncated it. This won't
5321 work properly with large files on 32-bit systems, but
5322 most of those will have ftruncate. */
5323 fseek(outs.stream, (long)outs.init, SEEK_SET);
5325 outs.bytes = 0; /* clear for next round */
5329 } /* if retry_numretries */
5331 /* In all ordinary cases, just break out of loop here */
5332 retry_sleep = retry_sleep_default;
5337 if((config->progressmode == CURL_PROGRESS_BAR) &&
5339 /* if the custom progress bar has been displayed, we output a
5341 fputs("\n", progressbar.out);
5343 if(config->writeout)
5344 ourWriteOut(curl, config->writeout);
5345 #ifdef USE_ENVIRONMENT
5346 if (config->writeenv)
5353 if(is_vms_shell()) {
5354 /* VMS DCL shell behavior */
5355 if(!config->showerror) {
5356 vms_show = VMSSTS_HIDE;
5362 if((res!=CURLE_OK) && config->showerror) {
5363 fprintf(config->errors, "curl: (%d) %s\n", res,
5364 errorbuffer[0]? errorbuffer:
5365 curl_easy_strerror((CURLcode)res));
5366 if(CURLE_SSL_CACERT == res) {
5367 #define CURL_CA_CERT_ERRORMSG1 \
5368 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
5369 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
5370 " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
5371 " bundle file isn't adequate, you can specify an alternate file\n" \
5372 " using the --cacert option.\n"
5374 #define CURL_CA_CERT_ERRORMSG2 \
5375 "If this HTTPS server uses a certificate signed by a CA represented in\n" \
5376 " the bundle, the certificate verification probably failed due to a\n" \
5377 " problem with the certificate (it might be expired, or the name might\n" \
5378 " not match the domain name in the URL).\n" \
5379 "If you'd like to turn off curl's verification of the certificate, use\n" \
5380 " the -k (or --insecure) option.\n"
5382 fprintf(config->errors, "%s%s",
5383 CURL_CA_CERT_ERRORMSG1,
5384 CURL_CA_CERT_ERRORMSG2 );
5389 if (outfile && !curlx_strequal(outfile, "-") && outs.stream) {
5390 int rc = fclose(outs.stream);
5392 /* something went wrong in the writing process */
5393 res = CURLE_WRITE_ERROR;
5394 fprintf(config->errors, "(%d) Failed writing body\n", res);
5399 /* Important that we set the time _after_ the file has been
5400 closed, as is done above here */
5401 if(config->remote_time && outs.filename) {
5402 /* ask libcurl if we got a time. Pretty please */
5404 curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
5406 struct utimbuf times;
5407 times.actime = (time_t)filetime;
5408 times.modtime = (time_t)filetime;
5409 utime(outs.filename, ×); /* set the time we got */
5414 /* Set the url as comment for the file. (up to 80 chars are allowed)
5416 if( strlen(url) > 78 )
5419 SetComment( outs.filename, url);
5432 } /* loop to the next URL */
5435 /* cleanup memory used for URL globbing patterns */
5443 } /* loop to the next globbed upload file */
5446 glob_cleanup(inglob);
5453 /* empty this urlnode struct */
5456 if(urlnode->outfile)
5457 free(urlnode->outfile);
5459 free(urlnode->infile);
5461 /* move on to the next URL */
5462 nextnode=urlnode->next;
5463 free(urlnode); /* free the node */
5466 } /* while-loop through all URLs */
5470 free(httpgetfields);
5473 free(config->engine);
5475 /* cleanup the curl handle! */
5476 curl_easy_cleanup(curl);
5477 config->easy = NULL; /* cleanup now */
5479 curl_slist_append(easycode, "curl_easy_cleanup(hnd);");
5481 if(heads.stream && (heads.stream != stdout))
5482 fclose(heads.stream);
5485 free(config->useragent);
5487 if(config->trace_fopened && config->trace_stream)
5488 fclose(config->trace_stream);
5490 /* Dump the libcurl code if previously enabled.
5491 NOTE: that this function relies on config->errors amongst other things
5492 so not everything can be closed and cleaned before this is called */
5493 dumpeasycode(config);
5495 if(config->errors_fopened)
5496 fclose(config->errors);
5498 main_free(); /* cleanup */
5503 /* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
5504 open before starting to run. Otherwise, the first three network
5505 sockets opened by curl could be used for input sources, downloaded data
5506 or error logs as they will effectively be stdin, stdout and/or stderr.
5508 static void checkfds(void)
5511 int fd[2] = { STDIN_FILENO, STDIN_FILENO };
5512 while( fd[0] == STDIN_FILENO ||
5513 fd[0] == STDOUT_FILENO ||
5514 fd[0] == STDERR_FILENO ||
5515 fd[1] == STDIN_FILENO ||
5516 fd[1] == STDOUT_FILENO ||
5517 fd[1] == STDERR_FILENO )
5519 return; /* Out of handles. This isn't really a big problem now, but
5520 will be when we try to create a socket later. */
5528 int main(int argc, char *argv[])
5531 struct Configurable config;
5533 memset(&config, 0, sizeof(struct Configurable));
5535 config.errors = stderr; /* default errors to stderr */
5539 res = operate(&config, argc, argv);
5540 #ifdef __SYMBIAN32__
5541 if (config.showerror)
5544 free_config_fields(&config);
5546 #ifdef __NOVELL_LIBC__
5547 if (getenv("_IN_NETWARE_BASH_") == NULL)
5551 vms_special_exit(res, vms_show);
5558 * Reads a line from the given file, ensuring is NUL terminated.
5559 * The pointer must be freed by the caller.
5560 * NULL is returned on an out of memory condition.
5562 static char *my_get_line(FILE *fp)
5566 char *retval = NULL;
5569 if (NULL == fgets(buf, sizeof(buf), fp))
5571 if (NULL == retval) {
5572 retval = strdup(buf);
5578 ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
5584 strcat(retval, buf);
5587 while (NULL == (nl = strchr(retval, '\n')));
5595 static void show_dir_errno(FILE *errors, const char *name)
5600 fprintf(errors,"You don't have permission to create %s.\n", name);
5605 fprintf(errors,"The directory name %s is too long.\n", name);
5610 fprintf(errors,"%s resides on a read-only file system.\n", name);
5615 fprintf(errors,"No space left on the file system that will "
5616 "contain the directory %s.\n", name);
5621 fprintf(errors,"Cannot create directory %s because you "
5622 "exceeded your quota.\n", name);
5626 fprintf(errors,"Error creating directory %s.\n", name);
5631 /* Create the needed directory hierarchy recursively in order to save
5632 multi-GETs in file output, ie:
5633 curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
5634 should create all the dir* automagically
5636 static int create_dir_hierarchy(const char *outfile, FILE *errors)
5644 outdup = strdup(outfile);
5648 dirbuildup = malloc(sizeof(char) * strlen(outfile));
5653 dirbuildup[0] = '\0';
5655 tempdir = strtok(outdup, DIR_CHAR);
5657 while (tempdir != NULL) {
5658 tempdir2 = strtok(NULL, DIR_CHAR);
5659 /* since strtok returns a token for the last word even
5660 if not ending with DIR_CHAR, we need to prune it */
5661 if (tempdir2 != NULL) {
5662 size_t dlen = strlen(dirbuildup);
5664 sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
5666 if (0 != strncmp(outdup, DIR_CHAR, 1))
5667 strcpy(dirbuildup, tempdir);
5669 sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
5671 if (access(dirbuildup, F_OK) == -1) {
5672 result = mkdir(dirbuildup,(mode_t)0000750);
5674 show_dir_errno(errors, dirbuildup);
5675 break; /* get out of loop */
5684 return result; /* 0 is fine, -1 is badness */
5687 #if defined(MSDOS) || defined(WIN32)
5689 #ifndef HAVE_BASENAME
5690 /* basename() returns a pointer to the last component of a pathname.
5691 * Ripped from lib/formdata.c.
5693 static char *Curl_basename(char *path)
5695 /* Ignore all the details above for now and make a quick and simple
5696 implementaion here */
5700 s1=strrchr(path, '/');
5701 s2=strrchr(path, '\\');
5704 path = (s1 > s2? s1 : s2)+1;
5713 #define basename(x) Curl_basename((x))
5714 #endif /* HAVE_BASENAME */
5716 /* The following functions are taken with modification from the DJGPP
5717 * port of tar 1.12. They use algorithms originally from DJTAR. */
5720 msdosify (const char *file_name)
5722 static char dos_name[PATH_MAX];
5723 static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
5724 "|<>\\\":?*"; /* illegal in DOS & W95 */
5725 static const char *illegal_chars_w95 = &illegal_chars_dos[8];
5727 const char *s = file_name;
5729 const char * const dlimit = dos_name + sizeof(dos_name) - 1;
5730 const char *illegal_aliens = illegal_chars_dos;
5731 size_t len = sizeof (illegal_chars_dos) - 1;
5733 /* Support for Windows 9X VFAT systems, when available. */
5734 if (_use_lfn (file_name)) {
5735 illegal_aliens = illegal_chars_w95;
5736 len -= (illegal_chars_w95 - illegal_chars_dos);
5739 /* Get past the drive letter, if any. */
5740 if (s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
5745 for (idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
5746 if (memchr (illegal_aliens, *s, len)) {
5747 /* Dots are special: DOS doesn't allow them as the leading character,
5748 and a file name cannot have more than a single dot. We leave the
5749 first non-leading dot alone, unless it comes too close to the
5750 beginning of the name: we want sh.lex.c to become sh_lex.c, not
5753 if (idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
5754 /* Copy "./" and "../" verbatim. */
5762 else if (dot_idx >= 0) {
5763 if (dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
5764 d[dot_idx - idx] = '_'; /* replace previous dot */
5776 else if (*s == '+' && s[1] == '+') {
5777 if (idx - 2 == dot_idx) { /* .c++, .h++ etc. */
5783 memcpy (d, "plus", 4);
5807 rename_if_dos_device_name (char *file_name)
5809 /* We could have a file whose name is a device on MS-DOS. Trying to
5810 * retrieve such a file would fail at best and wedge us at worst. We need
5811 * to rename such files. */
5814 char fname[PATH_MAX];
5816 strncpy(fname, file_name, PATH_MAX-1);
5817 fname[PATH_MAX-1] = 0;
5818 base = basename(fname);
5819 if (((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
5820 size_t blen = strlen (base);
5822 if (strlen(fname) >= PATH_MAX-1) {
5823 /* Make room for the '_' */
5827 /* Prepend a '_'. */
5828 memmove (base + 1, base, blen + 1);
5830 strcpy (file_name, fname);
5835 /* Replace bad characters in the file name before using it.
5836 * fn will always be freed before return
5837 * The returned pointer must be freed by the caller if not NULL
5839 static char *sanitize_dos_name(char *fn)
5841 char tmpfn[PATH_MAX];
5842 if(strlen(fn) >= PATH_MAX)
5843 fn[PATH_MAX-1]=0; /* truncate it */
5844 strcpy(tmpfn, msdosify(fn));
5846 return strdup(rename_if_dos_device_name(tmpfn));
5848 #endif /* MSDOS || WIN32 */