1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, 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 * $Id: main.c,v 1.479 2008-08-28 22:41:35 yangtse Exp $
22 ***************************************************************************/
29 #include <sys/types.h>
34 #include <curl/curl.h>
44 #ifdef USE_ENVIRONMENT
48 #define CURLseparator "--_curl_--"
51 #ifdef __NOVELL_LIBC__
55 #define mkdir mkdir_510
61 #ifdef HAVE_IO_H /* typical win32 habit */
76 #ifdef HAVE_SYS_UTIME_H
77 #include <sys/utime.h>
80 #endif /* HAVE_UTIME_H */
86 #ifdef HAVE_SYS_POLL_H
88 #elif defined(HAVE_POLL_H)
93 #include <locale.h> /* for setlocale() */
96 #define ENABLE_CURLX_PRINTF
97 /* make the curlx header define all printf() functions to use the curlx_*
99 #include <curlx.h> /* header from the libcurl directory */
101 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
103 /* set default codesets for iconv */
104 #ifndef CURL_ICONV_CODESET_OF_NETWORK
105 #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
107 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
109 #ifdef HAVE_NETINET_IN_H
110 #include <netinet/in.h> /* for IPPROTO_TCP */
112 #ifdef HAVE_NETINET_TCP_H
113 #include <netinet/tcp.h> /* for TCP_KEEPIDLE, TCP_KEEPINTVL */
116 /* The last #include file should be: */
118 #ifndef CURLTOOLDEBUG
119 #define MEMDEBUG_NODEFINES
121 /* This is low-level hard-hacking memory leak tracking and similar. Using
122 the library level code from this client-side is ugly, but we do this
123 anyway for convenience. */
124 #include "memdebug.h"
128 #define PRINT_LINES_PAUSE 23
131 #if defined(__SYMBIAN32__)
132 #define PRINT_LINES_PAUSE 16
133 #define pressanykey() getchar()
136 #define DEFAULT_MAXREDIRS 50L
138 #if defined(O_BINARY) && defined(HAVE_SETMODE)
140 #define SET_BINMODE(file) _setmode(file,O_BINARY)
142 #define SET_BINMODE(file) setmode(fileno(file),O_BINARY)
145 #define SET_BINMODE(file) ((void)0)
149 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
150 source code but yet it doesn't ruin anything */
157 static const char *msdosify(const char *);
158 static char *rename_if_dos_device_name(char *);
161 /* we want to glob our own argv[] */
162 char **__crt0_glob_function (char *arg
)
167 #endif /* __DJGPP__ */
171 #define STDIN_FILENO fileno(stdin)
174 #ifndef STDOUT_FILENO
175 #define STDOUT_FILENO fileno(stdout)
178 #ifndef STDERR_FILENO
179 #define STDERR_FILENO fileno(stderr)
182 #define CURL_PROGRESS_STATS 0 /* default progress display */
183 #define CURL_PROGRESS_BAR 1
190 #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
206 #define mkdir(x,y) (mkdir)(x)
210 #include "curlmsg_vms.h"
214 * Large file support (>2Gb) using WIN32 functions.
217 #ifdef USE_WIN32_LARGE_FILES
219 # include <sys/types.h>
220 # include <sys/stat.h>
221 # define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
222 # define fstat(fdes,stp) _fstati64(fdes, stp)
223 # define stat(fname,stp) _stati64(fname, stp)
224 # define struct_stat struct _stati64
228 * Small file support (<2Gb) using WIN32 functions.
231 #ifdef USE_WIN32_SMALL_FILES
233 # include <sys/types.h>
234 # include <sys/stat.h>
235 # define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
236 # define fstat(fdes,stp) _fstat(fdes, stp)
237 # define stat(fname,stp) _stat(fname, stp)
238 # define struct_stat struct _stat
242 # define struct_stat struct stat
246 * Default sizeof(off_t) in case it hasn't been defined in config file.
250 # if defined(__VMS) && (defined(__alpha) || defined(__ia64))
251 # if defined(_LARGEFILE)
252 # define SIZEOF_OFF_T 8
254 # elif defined(__OS400__) && defined(__ILEC400__)
255 # if defined(_LARGE_FILES)
256 # define SIZEOF_OFF_T 8
258 # elif defined(__MVS__) && defined(__IBMC__)
259 # if defined(_LP64) || defined(_LARGE_FILES)
260 # define SIZEOF_OFF_T 8
262 # elif defined(__370__) && defined(__IBMC__)
263 # if defined(_LP64) || defined(_LARGE_FILES)
264 # define SIZEOF_OFF_T 8
267 # ifndef SIZEOF_OFF_T
268 # define SIZEOF_OFF_T 4
272 #ifdef CURL_DOES_CONVERSIONS
274 iconv_t inbound_cd
= (iconv_t
)-1;
275 iconv_t outbound_cd
= (iconv_t
)-1;
278 * convert_to_network() is an internal function to convert
279 * from the host encoding to ASCII on non-ASCII platforms.
282 convert_to_network(char *buffer
, size_t length
)
286 /* translate from the host encoding to the network encoding */
287 char *input_ptr
, *output_ptr
;
288 size_t in_bytes
, out_bytes
;
290 /* open an iconv conversion descriptor if necessary */
291 if(outbound_cd
== (iconv_t
)-1) {
292 outbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_NETWORK
,
293 CURL_ICONV_CODESET_OF_HOST
);
294 if(outbound_cd
== (iconv_t
)-1) {
295 return CURLE_CONV_FAILED
;
299 input_ptr
= output_ptr
= buffer
;
300 in_bytes
= out_bytes
= length
;
301 rc
= iconv(outbound_cd
, &input_ptr
, &in_bytes
,
302 &output_ptr
, &out_bytes
);
303 if ((rc
== -1) || (in_bytes
!= 0)) {
304 return CURLE_CONV_FAILED
;
311 * convert_from_network() is an internal function
312 * for performing ASCII conversions on non-ASCII platforms.
315 convert_from_network(char *buffer
, size_t length
)
319 /* translate from the network encoding to the host encoding */
320 char *input_ptr
, *output_ptr
;
321 size_t in_bytes
, out_bytes
;
323 /* open an iconv conversion descriptor if necessary */
324 if(inbound_cd
== (iconv_t
)-1) {
325 inbound_cd
= iconv_open(CURL_ICONV_CODESET_OF_HOST
,
326 CURL_ICONV_CODESET_OF_NETWORK
);
327 if(inbound_cd
== (iconv_t
)-1) {
328 return CURLE_CONV_FAILED
;
332 input_ptr
= output_ptr
= buffer
;
333 in_bytes
= out_bytes
= length
;
334 rc
= iconv(inbound_cd
, &input_ptr
, &in_bytes
,
335 &output_ptr
, &out_bytes
);
336 if ((rc
== -1) || (in_bytes
!= 0)) {
337 return CURLE_CONV_FAILED
;
342 #endif /* HAVE_ICONV */
345 char convert_char(curl_infotype infotype
, char this_char
)
347 /* determine how this specific character should be displayed */
349 case CURLINFO_DATA_IN
:
350 case CURLINFO_DATA_OUT
:
351 case CURLINFO_SSL_DATA_IN
:
352 case CURLINFO_SSL_DATA_OUT
:
353 /* data, treat as ASCII */
354 if ((this_char
>= 0x20) && (this_char
< 0x7f)) {
355 /* printable ASCII hex value: convert to host encoding */
356 convert_from_network(&this_char
, 1);
359 /* non-printable ASCII, use a replacement character */
360 return UNPRINTABLE_CHAR
;
362 /* fall through to default */
364 /* treat as host encoding */
365 if (ISPRINT(this_char
)
366 && (this_char
!= '\t')
367 && (this_char
!= '\r')
368 && (this_char
!= '\n')) {
369 /* printable characters excluding tabs and line end characters */
374 /* non-printable, use a replacement character */
375 return UNPRINTABLE_CHAR
;
377 #endif /* CURL_DOES_CONVERSIONS */
381 * Truncate a file handle at a 64-bit position 'where'.
382 * Borland doesn't even support 64-bit types.
385 #define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
388 #ifndef HAVE_FTRUNCATE
389 #define HAVE_FTRUNCATE 1
392 static int ftruncate64 (int fd
, curl_off_t where
)
394 if(_lseeki64(fd
, where
, SEEK_SET
) < 0)
397 if(!SetEndOfFile((HANDLE
)_get_osfhandle(fd
)))
402 #define ftruncate(fd,where) ftruncate64(fd,where)
406 TRACE_NONE
, /* no trace/verbose output at all! */
407 TRACE_BIN
, /* tcpdump inspired look */
408 TRACE_ASCII
, /* like *BIN but without the hex output */
409 TRACE_PLAIN
/* -v/--verbose type */
415 struct Configurable
*config
;
416 curl_off_t bytes
; /* amount written so far */
417 curl_off_t init
; /* original size (non-zero when appending) */
420 struct Configurable
{
421 CURL
*easy
; /* once we have one, we keep it here */
426 char *cookie
; /* single line with specified cookies */
427 char *cookiejar
; /* write to this file */
428 char *cookiefile
; /* read from this file */
429 bool cookiesession
; /* new session? */
430 bool encoding
; /* Accept-Encoding please */
431 long authtype
; /* auth bitmask */
433 bool resume_from_current
;
436 curl_off_t resume_from
;
438 curl_off_t postfieldsize
;
443 curl_off_t max_filesize
;
449 unsigned short porttouse
;
451 long low_speed_limit
;
458 bool ftp_append
; /* APPE on ftp */
459 bool mute
; /* shutup */
460 bool use_ascii
; /* select ascii or text transfer */
461 bool autoreferer
; /* automatically set referer */
462 bool failonerror
; /* fail on (HTTP) errors */
463 bool include_headers
; /* send headers to data output */
464 bool no_body
; /* don't get the body */
465 bool dirlistonly
; /* only get the FTP dir list */
466 bool followlocation
; /* follow http redirects */
467 bool unrestricted_auth
; /* Continue to send authentication (user+password)
468 when following ocations, even when hostname
473 bool isatty
; /* updated internally only if the output is a tty */
474 struct getout
*url_list
; /* point to the first node */
475 struct getout
*url_last
; /* point to the last/current node */
476 struct getout
*url_get
; /* point to the node to fill in URL */
477 struct getout
*url_out
; /* point to the node to fill in outfile */
493 char *trace_dump
; /* file to dump the network trace to, or NULL */
497 bool tracetime
; /* include timestamp? */
503 bool insecure_ok
; /* set TRUE to allow insecure SSL connects */
505 bool ftp_create_dirs
;
512 char *writeout
; /* %-styled format string to output */
513 bool writeenv
; /* write results to environment, if available */
514 FILE *errors
; /* if stderr redirect is requested */
516 struct curl_slist
*quote
;
517 struct curl_slist
*postquote
;
518 struct curl_slist
*prequote
;
521 curl_TimeCond timecond
;
523 struct curl_slist
*headers
;
524 struct curl_httppost
*httppost
;
525 struct curl_httppost
*last_post
;
526 struct curl_slist
*telnet_options
;
529 /* for bandwidth limiting features: */
530 curl_off_t sendpersecond
; /* send to peer */
531 curl_off_t recvpersecond
; /* receive from peer */
532 struct timeval lastsendtime
;
534 struct timeval lastrecvtime
;
538 bool ftp_ssl_control
;
540 int ftp_ssl_ccc_mode
;
542 char *socksproxy
; /* set to server string */
543 int socksver
; /* set to CURLPROXY_SOCKS* define */
546 long req_retry
; /* number of retries */
547 long retry_delay
; /* delay between retries (in seconds) */
548 long retry_maxtime
; /* maximum time to keep retrying */
550 char *ftp_account
; /* for ACCT */
551 char *ftp_alternative_to_user
; /* send command if USER/PASS fails */
554 bool ignorecl
; /* --ignore-content-length */
555 bool disable_sessionid
;
557 char *libcurl
; /* output libcurl code to this file name */
560 bool nokeepalive
; /* for keepalive needs */
563 int default_node_flags
; /* default flags to seach for each 'node', which is
564 basically each given URL to transfer */
565 struct OutStruct
*outs
;
568 #define WARN_PREFIX "Warning: "
569 #define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
570 /* produce this text message to the user unless mute was selected */
571 static void warnf(struct Configurable
*config
, const char *fmt
, ...)
577 char print_buffer
[256];
581 len
= vsnprintf(print_buffer
, sizeof(print_buffer
), fmt
, ap
);
586 fputs(WARN_PREFIX
, config
->errors
);
588 if(len
> (int)WARN_TEXTWIDTH
) {
589 int cut
= WARN_TEXTWIDTH
-1;
591 while(!ISSPACE(ptr
[cut
]) && cut
) {
595 /* not a single cutting position was found, just cut it at the
596 max text width then! */
597 cut
= WARN_TEXTWIDTH
-1;
599 fwrite(ptr
, cut
+ 1, 1, config
->errors
);
600 fputs("\n", config
->errors
);
601 ptr
+= cut
+1; /* skip the space too */
605 fputs(ptr
, config
->errors
);
613 * This is the main global constructor for the app. Call this before
614 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
615 * used, or havoc may be the result.
617 static CURLcode
main_init(void)
620 /* stop stat() wasting time */
621 _djstat_flags
|= _STAT_INODE
| _STAT_EXEC_MAGIC
| _STAT_DIRSIZE
;
623 return curl_global_init(CURL_GLOBAL_DEFAULT
);
627 * This is the main global destructor for the app. Call this after
628 * _all_ libcurl usage is done.
630 static void main_free(void)
632 curl_global_cleanup();
633 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
634 /* close iconv conversion descriptor */
635 if(inbound_cd
!= (iconv_t
)-1)
636 iconv_close(inbound_cd
);
637 if(outbound_cd
!= (iconv_t
)-1)
638 iconv_close(outbound_cd
);
639 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
642 static int SetHTTPrequest(struct Configurable
*config
,
643 HttpReq req
, HttpReq
*store
)
645 if((*store
== HTTPREQ_UNSPEC
) ||
650 warnf(config
, "You can only select one HTTP request!\n");
654 static void helpf(FILE *errors
, const char *fmt
, ...)
659 fputs("curl: ", errors
); /* prefix it */
660 vfprintf(errors
, fmt
, ap
);
663 fprintf(errors
, "curl: try 'curl --help' "
665 "or 'curl --manual' "
667 "for more information\n");
671 * A chain of these nodes contain URL to get and where to put the URL's
675 struct getout
*next
; /* next one */
676 char *url
; /* the URL we deal with */
677 char *outfile
; /* where to store the output */
678 char *infile
; /* file to upload, if GETOUT_UPLOAD is set */
679 int flags
; /* options */
681 #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
682 #define GETOUT_URL (1<<1) /* set when URL is deemed done */
683 #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
684 #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
685 #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
687 static void help(void)
690 /* A few of these source lines are >80 columns wide, but that's only because
691 breaking the strings narrower makes this chunk look even worse!
693 Starting with 7.18.0, this list of command line options is sorted based
694 on the long option name. It is not done automatically, although a command
695 line like the following can help out:
697 curl --help | cut -c5- | grep "^-" | sort
699 static const char * const helptext
[]={
700 "Usage: curl [options...] <url>",
701 "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
702 " --anyauth Pick \"any\" authentication method (H)",
703 " -a/--append Append to target file when uploading (F/SFTP)",
704 " --basic Use HTTP Basic Authentication (H)",
705 " --cacert <file> CA certificate to verify peer against (SSL)",
706 " --capath <directory> CA directory to verify peer against (SSL)",
707 " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
708 " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
709 " --ciphers <list> SSL ciphers to use (SSL)",
710 " --compressed Request compressed response (using deflate or gzip)",
711 " -K/--config <file> Specify which config file to read",
712 " --connect-timeout <seconds> Maximum time allowed for connection",
713 " -C/--continue-at <offset> Resumed transfer offset",
714 " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
715 " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
716 " --create-dirs Create necessary local directory hierarchy",
717 " --crlf Convert LF to CRLF in upload",
718 " -d/--data <data> HTTP POST data (H)",
719 " --data-ascii <data> HTTP POST ASCII data (H)",
720 " --data-binary <data> HTTP POST binary data (H)",
721 " --data-urlencode <name=data/name@filename> HTTP POST data url encoded (H)",
722 " --digest Use HTTP Digest Authentication (H)",
723 " --disable-eprt Inhibit using EPRT or LPRT (F)",
724 " --disable-epsv Inhibit using EPSV (F)",
725 " -D/--dump-header <file> Write the headers to this file",
726 " --egd-file <file> EGD socket path for random data (SSL)",
727 " --engine <eng> Crypto engine to use (SSL). \"--engine list\" for list",
728 #ifdef USE_ENVIRONMENT
729 " --environment Write results to environment variables (RISC OS)",
731 " -f/--fail Fail silently (no output at all) on HTTP errors (H)",
732 " -F/--form <name=content> Specify HTTP multipart POST data (H)",
733 " --form-string <name=string> Specify HTTP multipart POST data (H)",
734 " --ftp-account <data> Account data to send when requested by server (F)",
735 " --ftp-alternative-to-user <cmd> String to replace \"USER [name]\" (F)",
736 " --ftp-create-dirs Create the remote dirs if not present (F)",
737 " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
738 " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
739 " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
740 " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
741 " --ftp-ssl Try SSL/TLS for ftp transfer (F)",
742 " --ftp-ssl-ccc Send CCC after authenticating (F)",
743 " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
744 " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
745 " --ftp-ssl-reqd Require SSL/TLS for ftp transfer (F)",
746 " -G/--get Send the -d data with a HTTP GET (H)",
747 " -g/--globoff Disable URL sequences and ranges using {} and []",
748 " -H/--header <line> Custom header to pass to server (H)",
749 " -I/--head Show document info only",
750 " -h/--help This help text",
751 " --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
752 " -0/--http1.0 Use HTTP 1.0 (H)",
753 " --ignore-content-length Ignore the HTTP Content-Length header",
754 " -i/--include Include protocol headers in the output (H/F)",
755 " -k/--insecure Allow connections to SSL sites without certs (H)",
756 " --interface <interface> Specify network interface/address to use",
757 " -4/--ipv4 Resolve name to IPv4 address",
758 " -6/--ipv6 Resolve name to IPv6 address",
759 " -j/--junk-session-cookies Ignore session cookies read from file (H)",
760 " --keepalive-time <seconds> Interval between keepalive probes",
761 " --key <key> Private key file name (SSL/SSH)",
762 " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
763 " --krb <level> Enable Kerberos with specified security level (F)",
764 " --libcurl <file> Dump libcurl equivalent code of this command line",
765 " --limit-rate <rate> Limit transfer speed to this rate",
766 " -l/--list-only List only names of an FTP directory (F)",
767 " --local-port <num>[-num] Force use of these local port numbers",
768 " -L/--location Follow Location: hints (H)",
769 " --location-trusted Follow Location: and send auth to other hosts (H)",
770 " -M/--manual Display the full manual",
771 " --max-filesize <bytes> Maximum file size to download (H/F)",
772 " --max-redirs <num> Maximum number of redirects allowed (H)",
773 " -m/--max-time <seconds> Maximum time allowed for the transfer",
774 " --negotiate Use HTTP Negotiate Authentication (H)",
775 " -n/--netrc Must read .netrc for user name and password",
776 " --netrc-optional Use either .netrc or URL; overrides -n",
777 " -N/--no-buffer Disable buffering of the output stream",
778 " --no-keepalive Disable keepalive use on the connection",
779 " --no-sessionid Disable SSL session-ID reusing (SSL)",
780 " --ntlm Use HTTP NTLM authentication (H)",
781 " -o/--output <file> Write output to <file> instead of stdout",
782 " --pass <pass> Pass phrase for the private key (SSL/SSH)",
783 " --post301 Do not switch to GET after following a 301 redirect (H)",
784 " -#/--progress-bar Display transfer progress as a progress bar",
785 " -x/--proxy <host[:port]> Use HTTP proxy on given port",
786 " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
787 " --proxy-basic Use Basic authentication on the proxy (H)",
788 " --proxy-digest Use Digest authentication on the proxy (H)",
789 " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
790 " --proxy-ntlm Use NTLM authentication on the proxy (H)",
791 " -U/--proxy-user <user[:password]> Set proxy user and password",
792 " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
793 " --pubkey <key> Public key file name (SSH)",
794 " -Q/--quote <cmd> Send command(s) to server before file transfer (F/SFTP)",
795 " --random-file <file> File for reading random data from (SSL)",
796 " -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server",
797 " --raw Pass HTTP \"raw\", without any transfer decoding (H)",
798 " -e/--referer Referer URL (H)",
799 " -O/--remote-name Write output to a file named as the remote file",
800 " --remote-name-all Use the remote file name for all URLs",
801 " -R/--remote-time Set the remote file's time on the local output",
802 " -X/--request <command> Specify request command to use",
803 " --retry <num> Retry request <num> times if transient problems occur",
804 " --retry-delay <seconds> When retrying, wait this many seconds between each",
805 " --retry-max-time <seconds> Retry only within this period",
806 " -S/--show-error Show error. With -s, make curl show errors when they occur",
807 " -s/--silent Silent mode. Don't output anything",
808 " --socks4 <host[:port]> SOCKS4 proxy on given host + port",
809 " --socks4a <host[:port]> SOCKS4a proxy on given host + port",
810 " --socks5 <host[:port]> SOCKS5 proxy on given host + port",
811 " --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy",
812 " -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
813 " -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
814 " -2/--sslv2 Use SSLv2 (SSL)",
815 " -3/--sslv3 Use SSLv3 (SSL)",
816 " --stderr <file> Where to redirect stderr. - means stdout",
817 " --tcp-nodelay Use the TCP_NODELAY option",
818 " -t/--telnet-option <OPT=val> Set telnet option",
819 " -z/--time-cond <time> Transfer based on a time condition",
820 " -1/--tlsv1 Use TLSv1 (SSL)",
821 " --trace <file> Write a debug trace to the given file",
822 " --trace-ascii <file> Like --trace but without the hex output",
823 " --trace-time Add time stamps to trace/verbose output",
824 " -T/--upload-file <file> Transfer <file> to remote site",
825 " --url <URL> Set URL to work with",
826 " -B/--use-ascii Use ASCII/text transfer",
827 " -u/--user <user[:password]> Set server user and password",
828 " -A/--user-agent <string> User-Agent to send to server (H)",
829 " -v/--verbose Make the operation more talkative",
830 " -V/--version Show version number and quit",
833 " --wdebug Turn on Watt-32 debugging under DJGPP",
835 " -w/--write-out <format> What to output after completion",
836 " -q If used as the first parameter disables .curlrc",
839 for(i
=0; helptext
[i
]; i
++) {
841 #ifdef PRINT_LINES_PAUSE
842 if (i
&& ((i
% PRINT_LINES_PAUSE
) == 0))
854 /* global variable to hold info about libcurl */
855 static curl_version_info_data
*curlinfo
;
857 static int parseconfig(const char *filename
,
858 struct Configurable
*config
);
859 static char *my_get_line(FILE *fp
);
860 static int create_dir_hierarchy(const char *outfile
, FILE *errors
);
862 static void GetStr(char **string
,
868 *string
= strdup(value
);
873 static void clean_getout(struct Configurable
*config
)
875 struct getout
*node
=config
->url_list
;
888 node
= next
; /* GOTO next */
892 static struct getout
*new_getout(struct Configurable
*config
)
894 struct getout
*node
=malloc(sizeof(struct getout
));
895 struct getout
*last
= config
->url_last
;
897 /* clear the struct */
898 memset(node
, 0, sizeof(struct getout
));
900 /* append this new node last in the list */
904 config
->url_list
= node
; /* first node */
906 /* move the last pointer */
907 config
->url_last
= node
;
909 node
->flags
= config
->default_node_flags
;
914 /* Structure for storing the information needed to build a multiple files
918 struct curl_forms form
;
919 struct multi_files
*next
;
922 /* Add a new list entry possibly with a type_name
924 static struct multi_files
*
925 AddMultiFiles (const char *file_name
,
926 const char *type_name
,
927 const char *show_filename
,
928 struct multi_files
**multi_start
,
929 struct multi_files
**multi_current
)
931 struct multi_files
*multi
;
932 struct multi_files
*multi_type
= NULL
;
933 struct multi_files
*multi_name
= NULL
;
934 multi
= (struct multi_files
*)malloc(sizeof(struct multi_files
));
936 memset(multi
, 0, sizeof(struct multi_files
));
937 multi
->form
.option
= CURLFORM_FILE
;
938 multi
->form
.value
= file_name
;
944 *multi_start
= multi
;
947 multi_type
= (struct multi_files
*)malloc(sizeof(struct multi_files
));
949 memset(multi_type
, 0, sizeof(struct multi_files
));
950 multi_type
->form
.option
= CURLFORM_CONTENTTYPE
;
951 multi_type
->form
.value
= type_name
;
952 multi
->next
= multi_type
;
962 multi_name
= (struct multi_files
*)malloc(sizeof(struct multi_files
));
964 memset(multi_name
, 0, sizeof(struct multi_files
));
965 multi_name
->form
.option
= CURLFORM_FILENAME
;
966 multi_name
->form
.value
= show_filename
;
967 multi
->next
= multi_name
;
978 (*multi_current
)->next
= multi
;
980 *multi_current
= multi
;
982 return *multi_current
;
985 /* Free the items of the list.
987 static void FreeMultiInfo (struct multi_files
*multi_start
)
989 struct multi_files
*multi
;
990 while (multi_start
) {
992 multi_start
= multi_start
->next
;
997 /* Print list of OpenSSL engines supported.
999 static void list_engines (const struct curl_slist
*engines
)
1001 puts ("Build-time engines:");
1006 for ( ; engines
; engines
= engines
->next
)
1007 printf (" %s\n", engines
->data
);
1010 /***************************************************************************
1014 * Reads a 'name=value' parameter and builds the appropriate linked list.
1016 * Specify files to upload with 'name=@filename'. Supports specified
1017 * given Content-Type of the files. Such as ';type=<content-type>'.
1019 * If literal_value is set, any initial '@' or '<' in the value string
1020 * loses its special meaning, as does any embedded ';type='.
1022 * You may specify more than one file for a single name (field). Specify
1023 * multiple files by writing it like:
1025 * 'name=@filename,filename2,filename3'
1027 * If you want content-types specified for each too, write them like:
1029 * 'name=@filename;type=image/gif,filename2,filename3'
1031 * If you want custom headers added for a single part, write them in a separate
1032 * file and do like this:
1034 * 'name=foo;headers=@headerfile' or why not
1035 * 'name=@filemame;headers=@headerfile'
1037 * To upload a file, but to fake the file name that will be included in the
1038 * formpost, do like this:
1040 * 'name=@filename;filename=/dev/null'
1042 * This function uses curl_formadd to fulfill it's job. Is heavily based on
1043 * the old curl_formparse code.
1045 ***************************************************************************/
1047 #define FORM_FILE_SEPARATOR ','
1048 #define FORM_TYPE_SEPARATOR ';'
1050 static int formparse(struct Configurable
*config
,
1052 struct curl_httppost
**httppost
,
1053 struct curl_httppost
**last_post
,
1056 /* nextarg MUST be a string in the format 'name=contents' and we'll
1057 build a linked list with the info */
1063 const char *type
= NULL
;
1067 if((1 == sscanf(input
, "%255[^=]=", name
)) &&
1068 (contp
= strchr(input
, '='))) {
1069 /* the input was using the correct format */
1071 /* Allocate the contents */
1072 contents
= strdup(contp
+1);
1074 fprintf(config
->errors
, "out of memory\n");
1079 if('@' == contp
[0] && !literal_value
) {
1080 struct multi_files
*multi_start
= NULL
, *multi_current
= NULL
;
1081 /* we use the @-letter to indicate file name(s) */
1084 multi_start
= multi_current
=NULL
;
1087 /* since this was a file, it may have a content-type specifier
1088 at the end too, or a filename. Or both. */
1090 char *filename
=NULL
;
1092 sep
=strchr(contp
, FORM_TYPE_SEPARATOR
);
1093 sep2
=strchr(contp
, FORM_FILE_SEPARATOR
);
1095 /* pick the closest */
1096 if(sep2
&& (sep2
< sep
)) {
1099 /* no type was specified! */
1106 /* if we got here on a comma, don't do much */
1107 if(FORM_FILE_SEPARATOR
== *sep
)
1112 *sep
=0; /* terminate file name at separator */
1114 while(ptr
&& (FORM_FILE_SEPARATOR
!= *ptr
)) {
1116 /* pass all white spaces */
1117 while(ISSPACE(*ptr
))
1120 if(curlx_strnequal("type=", ptr
, 5)) {
1121 /* set type pointer */
1124 /* verify that this is a fine type specifier */
1125 if(2 != sscanf(type
, "%127[^/]/%127[^;,\n]",
1127 warnf(config
, "Illegally formatted content-type field!\n");
1129 FreeMultiInfo (multi_start
);
1130 return 2; /* illegal content-type syntax! */
1132 /* now point beyond the content-type specifier */
1133 sep
= (char *)type
+ strlen(major
)+strlen(minor
)+1;
1136 *sep
=0; /* zero terminate type string */
1141 ptr
= NULL
; /* end */
1143 else if(curlx_strnequal("filename=", ptr
, 9)) {
1145 ptr
=strchr(filename
, FORM_TYPE_SEPARATOR
);
1147 ptr
=strchr(filename
, FORM_FILE_SEPARATOR
);
1150 *ptr
=0; /* zero terminate */
1155 /* confusion, bail out of loop */
1158 /* find the following comma */
1160 sep
=strchr(ptr
, FORM_FILE_SEPARATOR
);
1165 sep
=strchr(contp
, FORM_FILE_SEPARATOR
);
1168 /* the next file name starts here */
1172 /* if type == NULL curl_formadd takes care of the problem */
1174 if (!AddMultiFiles (contp
, type
, filename
, &multi_start
,
1176 warnf(config
, "Error building form post!\n");
1178 FreeMultiInfo (multi_start
);
1181 contp
= sep
; /* move the contents pointer to after the separator */
1183 } while(sep
&& *sep
); /* loop if there's another file name */
1185 /* now we add the multiple files section */
1187 struct curl_forms
*forms
= NULL
;
1188 struct multi_files
*ptr
= multi_start
;
1189 unsigned int i
, count
= 0;
1195 (struct curl_forms
*)malloc((count
+1)*sizeof(struct curl_forms
));
1198 fprintf(config
->errors
, "Error building form post!\n");
1200 FreeMultiInfo (multi_start
);
1203 for (i
= 0, ptr
= multi_start
; i
< count
; ++i
, ptr
= ptr
->next
)
1205 forms
[i
].option
= ptr
->form
.option
;
1206 forms
[i
].value
= ptr
->form
.value
;
1208 forms
[count
].option
= CURLFORM_END
;
1209 FreeMultiInfo (multi_start
);
1210 if (curl_formadd(httppost
, last_post
,
1211 CURLFORM_COPYNAME
, name
,
1212 CURLFORM_ARRAY
, forms
, CURLFORM_END
) != 0) {
1213 warnf(config
, "curl_formadd failed!\n");
1222 struct curl_forms info
[4];
1224 char *ct
= literal_value
? NULL
: strstr(contp
, ";type=");
1226 info
[i
].option
= CURLFORM_COPYNAME
;
1227 info
[i
].value
= name
;
1231 info
[i
].option
= CURLFORM_CONTENTTYPE
;
1232 info
[i
].value
= &ct
[6];
1234 ct
[0]=0; /* zero terminate here */
1237 if( contp
[0]=='<' && !literal_value
) {
1238 info
[i
].option
= CURLFORM_FILECONTENT
;
1239 info
[i
].value
= contp
+1;
1241 info
[i
].option
= CURLFORM_END
;
1243 if (curl_formadd(httppost
, last_post
,
1244 CURLFORM_ARRAY
, info
, CURLFORM_END
) != 0) {
1245 warnf(config
, "curl_formadd failed, possibly the file %s is bad!\n",
1252 #ifdef CURL_DOES_CONVERSIONS
1253 convert_to_network(contp
, strlen(contp
));
1255 info
[i
].option
= CURLFORM_COPYCONTENTS
;
1256 info
[i
].value
= contp
;
1258 info
[i
].option
= CURLFORM_END
;
1259 if (curl_formadd(httppost
, last_post
,
1260 CURLFORM_ARRAY
, info
, CURLFORM_END
) != 0) {
1261 warnf(config
, "curl_formadd failed!\n");
1270 warnf(config
, "Illegally formatted input field!\n");
1280 PARAM_OPTION_AMBIGUOUS
,
1281 PARAM_OPTION_UNKNOWN
,
1282 PARAM_REQUIRES_PARAMETER
,
1284 PARAM_HELP_REQUESTED
,
1285 PARAM_GOT_EXTRA_PARAMETER
,
1287 PARAM_LIBCURL_DOESNT_SUPPORT
,
1292 static const char *param2text(int res
)
1294 ParameterError error
= (ParameterError
)res
;
1296 case PARAM_GOT_EXTRA_PARAMETER
:
1297 return "had unsupported trailing garbage";
1298 case PARAM_OPTION_UNKNOWN
:
1299 return "is unknown";
1300 case PARAM_OPTION_AMBIGUOUS
:
1301 return "is ambiguous";
1302 case PARAM_REQUIRES_PARAMETER
:
1303 return "requires parameter";
1305 return "is badly used here";
1306 case PARAM_BAD_NUMERIC
:
1307 return "expected a proper numerical parameter";
1308 case PARAM_LIBCURL_DOESNT_SUPPORT
:
1309 return "the installed libcurl version doesn't support this";
1311 return "out of memory";
1313 return "unknown error";
1317 static ParameterError
file2string(char **bufp
, FILE *file
)
1321 char *string
= NULL
;
1322 size_t stringlen
= 0;
1326 while(fgets(buffer
, sizeof(buffer
), file
)) {
1327 if((ptr
= strchr(buffer
, '\r')) != NULL
)
1329 if((ptr
= strchr(buffer
, '\n')) != NULL
)
1331 buflen
= strlen(buffer
);
1332 if((ptr
= realloc(string
, stringlen
+buflen
+1)) == NULL
) {
1335 return PARAM_NO_MEM
;
1338 strcpy(string
+stringlen
, buffer
);
1339 stringlen
+= buflen
;
1346 static ParameterError
file2memory(char **bufp
, size_t *size
, FILE *file
)
1349 char *buffer
= NULL
;
1356 if(!buffer
|| (alloc
== nused
)) {
1357 /* size_t overflow detection for huge files */
1358 if(alloc
+1 > ((size_t)-1)/2) {
1361 return PARAM_NO_MEM
;
1364 /* allocate an extra char, reserved space, for null termination */
1365 if((newbuf
= realloc(buffer
, alloc
+1)) == NULL
) {
1368 return PARAM_NO_MEM
;
1372 nread
= fread(buffer
+nused
, 1, alloc
-nused
, file
);
1375 /* null terminate the buffer in case it's used as a string later */
1376 buffer
[nused
] = '\0';
1377 /* free trailing slack space, if possible */
1378 if(alloc
!= nused
) {
1379 if((newbuf
= realloc(buffer
, nused
+1)) != NULL
)
1382 /* discard buffer if nothing was read */
1385 buffer
= NULL
; /* no string */
1393 static void cleanarg(char *str
)
1395 #ifdef HAVE_WRITABLE_ARGV
1396 /* now that GetStr has copied the contents of nextarg, wipe the next
1397 * argument out so that the username:password isn't displayed in the
1398 * system process list */
1400 size_t len
= strlen(str
);
1401 memset(str
, ' ', len
);
1409 * Parse the string and write the integer in the given address. Return
1410 * non-zero on failure, zero on success.
1412 * The string must start with a digit to be valid.
1414 * Since this function gets called with the 'nextarg' pointer from within the
1415 * getparameter a lot, we must check it for NULL before accessing the str
1419 static int str2num(long *val
, const char *str
)
1422 if(str
&& ISDIGIT(*str
))
1425 retcode
= 1; /* badness */
1430 * Parses the given string looking for an offset (which may be
1431 * a larger-than-integer value).
1433 * @param val the offset to populate
1434 * @param str the buffer containing the offset
1435 * @return zero if successful, non-zero if failure.
1437 static int str2offset(curl_off_t
*val
, const char *str
)
1439 #if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
1440 *val
= curlx_strtoofft(str
, NULL
, 0);
1441 if((*val
== CURL_LLONG_MAX
|| *val
== CURL_LLONG_MIN
) && (ERRNO
== ERANGE
))
1444 *val
= strtol(str
, NULL
, 0);
1445 if ((*val
== LONG_MIN
|| *val
== LONG_MAX
) && ERRNO
== ERANGE
)
1451 static void checkpasswd(const char *kind
, /* for what purpose */
1452 char **userpwd
) /* pointer to allocated string */
1458 ptr
= strchr(*userpwd
, ':');
1460 /* no password present, prompt for one */
1461 char passwd
[256]="";
1464 size_t userlen
= strlen(*userpwd
);
1467 /* build a nice-looking prompt */
1468 curlx_msnprintf(prompt
, sizeof(prompt
),
1469 "Enter %s password for user '%s':",
1473 getpass_r(prompt
, passwd
, sizeof(passwd
));
1474 passwdlen
= strlen(passwd
);
1476 /* extend the allocated memory area to fit the password too */
1477 passptr
= realloc(*userpwd
,
1478 passwdlen
+ 1 + /* an extra for the colon */
1479 userlen
+ 1); /* an extra for the zero */
1482 /* append the password separated with a colon */
1483 passptr
[userlen
]=':';
1484 memcpy(&passptr
[userlen
+1], passwd
, passwdlen
+1);
1490 static ParameterError
add2list(struct curl_slist
**list
,
1493 struct curl_slist
*newlist
= curl_slist_append(*list
, ptr
);
1497 return PARAM_NO_MEM
;
1502 static int ftpfilemethod(struct Configurable
*config
, const char *str
)
1504 if(curlx_strequal("singlecwd", str
))
1505 return CURLFTPMETHOD_SINGLECWD
;
1506 if(curlx_strequal("nocwd", str
))
1507 return CURLFTPMETHOD_NOCWD
;
1508 if(curlx_strequal("multicwd", str
))
1509 return CURLFTPMETHOD_MULTICWD
;
1510 warnf(config
, "unrecognized ftp file method '%s', using default\n", str
);
1511 return CURLFTPMETHOD_MULTICWD
;
1514 static int ftpcccmethod(struct Configurable
*config
, const char *str
)
1516 if(curlx_strequal("passive", str
))
1517 return CURLFTPSSL_CCC_PASSIVE
;
1518 if(curlx_strequal("active", str
))
1519 return CURLFTPSSL_CCC_ACTIVE
;
1520 warnf(config
, "unrecognized ftp CCC method '%s', using default\n", str
);
1521 return CURLFTPSSL_CCC_PASSIVE
;
1525 static int sockoptcallback(void *clientp
, curl_socket_t curlfd
,
1526 curlsocktype purpose
)
1528 struct Configurable
*config
= (struct Configurable
*)clientp
;
1529 int onoff
= 1; /* this callback is only used if we ask for keepalives on the
1531 #if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
1532 int keepidle
= (int)config
->alivetime
;
1536 case CURLSOCKTYPE_IPCXN
:
1537 if(setsockopt(curlfd
, SOL_SOCKET
, SO_KEEPALIVE
, (void *)&onoff
,
1538 sizeof(onoff
)) < 0) {
1539 /* don't abort operation, just issue a warning */
1541 warnf(clientp
, "Could not set SO_KEEPALIVE!\n");
1545 if (config
->alivetime
) {
1547 if(setsockopt(curlfd
, IPPROTO_TCP
, TCP_KEEPIDLE
, (void *)&keepidle
,
1548 sizeof(keepidle
)) < 0) {
1549 /* don't abort operation, just issue a warning */
1551 warnf(clientp
, "Could not set TCP_KEEPIDLE!\n");
1555 #ifdef TCP_KEEPINTVL
1556 if(setsockopt(curlfd
, IPPROTO_TCP
, TCP_KEEPINTVL
, (void *)&keepidle
,
1557 sizeof(keepidle
)) < 0) {
1558 /* don't abort operation, just issue a warning */
1560 warnf(clientp
, "Could not set TCP_KEEPINTVL!\n");
1575 static ParameterError
getparameter(char *flag
, /* f or -long-flag */
1576 char *nextarg
, /* NULL if unset */
1577 bool *usedarg
, /* set to TRUE if the arg
1579 struct Configurable
*config
)
1582 char subletter
=0; /* subletters can only occur on long options */
1583 int rc
; /* generic return code variable */
1584 const char *parse
=NULL
;
1589 bool singleopt
=FALSE
; /* when true means '-o foo' used '-ofoo' */
1591 bool toggle
=TRUE
; /* how to switch boolean options, on or off. Controlled
1592 by using --OPTION or --no-OPTION */
1596 boolean whether it takes an additional argument
1598 static const struct LongShort aliases
[]= {
1599 /* all these ones, starting with "*" or "$" as a short-option have *no*
1600 short option to mention. */
1602 {"*a", "random-file", TRUE
},
1603 {"*b", "egd-file", TRUE
},
1604 {"*c", "connect-timeout", TRUE
},
1605 {"*d", "ciphers", TRUE
},
1606 {"*e", "disable-epsv", FALSE
},
1607 {"*E", "epsv", FALSE
}, /* made like this to make --no-epsv and --epsv to
1608 work although --disable-epsv is the documented
1610 #ifdef USE_ENVIRONMENT
1611 {"*f", "environment", FALSE
},
1613 {"*g", "trace", TRUE
},
1614 {"*h", "trace-ascii", TRUE
},
1615 {"*i", "limit-rate", TRUE
},
1616 {"*j", "compressed", FALSE
}, /* might take an arg someday */
1617 {"*k", "digest", FALSE
},
1618 {"*l", "negotiate", FALSE
},
1619 {"*m", "ntlm", FALSE
},
1620 {"*n", "basic", FALSE
},
1621 {"*o", "anyauth", FALSE
},
1623 {"*p", "wdebug", FALSE
},
1625 {"*q", "ftp-create-dirs", FALSE
},
1626 {"*r", "create-dirs", FALSE
},
1627 {"*s", "max-redirs", TRUE
},
1628 {"*t", "proxy-ntlm", FALSE
},
1629 {"*u", "crlf", FALSE
},
1630 {"*v", "stderr", TRUE
},
1631 {"*w", "interface", TRUE
},
1632 {"*x", "krb" , TRUE
},
1633 {"*x", "krb4" , TRUE
}, /* this is the previous name */
1634 {"*y", "max-filesize", TRUE
},
1635 {"*z", "disable-eprt", FALSE
},
1636 {"*Z", "eprt", FALSE
}, /* made like this to make --no-eprt and --eprt to
1637 work although --disable-eprt is the documented
1639 {"$a", "ftp-ssl", FALSE
},
1640 {"$b", "ftp-pasv", FALSE
},
1641 {"$c", "socks5", TRUE
},
1642 {"$c", "socks", TRUE
}, /* this is how the option once was documented
1643 but we prefer the --socks5 version for
1645 {"$d", "tcp-nodelay",FALSE
},
1646 {"$e", "proxy-digest", FALSE
},
1647 {"$f", "proxy-basic", FALSE
},
1648 {"$g", "retry", TRUE
},
1649 {"$h", "retry-delay", TRUE
},
1650 {"$i", "retry-max-time", TRUE
},
1651 {"$k", "proxy-negotiate", FALSE
},
1652 {"$m", "ftp-account", TRUE
},
1653 {"$n", "proxy-anyauth", FALSE
},
1654 {"$o", "trace-time", FALSE
},
1655 {"$p", "ignore-content-length", FALSE
},
1656 {"$q", "ftp-skip-pasv-ip", FALSE
},
1657 {"$r", "ftp-method", TRUE
},
1658 {"$s", "local-port", TRUE
},
1659 {"$t", "socks4", TRUE
},
1660 {"$T", "socks4a", TRUE
},
1661 {"$u", "ftp-alternative-to-user", TRUE
},
1662 {"$v", "ftp-ssl-reqd", FALSE
},
1663 {"$w", "sessionid", FALSE
}, /* listed as --no-sessionid in the help */
1664 {"$x", "ftp-ssl-control", FALSE
},
1665 {"$y", "ftp-ssl-ccc", FALSE
},
1666 {"$j", "ftp-ssl-ccc-mode", TRUE
},
1667 {"$z", "libcurl", TRUE
},
1668 {"$#", "raw", FALSE
},
1669 {"$0", "post301", FALSE
},
1670 {"$1", "keepalive", FALSE
}, /* listed as --no-keepalive in the help */
1671 {"$2", "socks5-hostname", TRUE
},
1672 {"$3", "keepalive-time", TRUE
},
1674 {"0", "http1.0", FALSE
},
1675 {"1", "tlsv1", FALSE
},
1676 {"2", "sslv2", FALSE
},
1677 {"3", "sslv3", FALSE
},
1678 {"4", "ipv4", FALSE
},
1679 {"6", "ipv6", FALSE
},
1680 {"a", "append", FALSE
},
1681 {"A", "user-agent", TRUE
},
1682 {"b", "cookie", TRUE
},
1683 {"B", "use-ascii", FALSE
},
1684 {"c", "cookie-jar", TRUE
},
1685 {"C", "continue-at", TRUE
},
1686 {"d", "data", TRUE
},
1687 {"da", "data-ascii", TRUE
},
1688 {"db", "data-binary", TRUE
},
1689 {"de", "data-urlencode", TRUE
},
1690 {"D", "dump-header", TRUE
},
1691 {"e", "referer", TRUE
},
1692 {"E", "cert", TRUE
},
1693 {"Ea", "cacert", TRUE
},
1694 {"Eb","cert-type", TRUE
},
1696 {"Ed","key-type", TRUE
},
1697 {"Ee","pass", TRUE
},
1698 {"Ef","engine", TRUE
},
1699 {"Eg","capath ", TRUE
},
1700 {"Eh","pubkey", TRUE
},
1701 {"Ei", "hostpubmd5", TRUE
},
1702 {"f", "fail", FALSE
},
1703 {"F", "form", TRUE
},
1704 {"Fs","form-string", TRUE
},
1705 {"g", "globoff", FALSE
},
1706 {"G", "get", FALSE
},
1707 {"h", "help", FALSE
},
1708 {"H", "header", TRUE
},
1709 {"i", "include", FALSE
},
1710 {"I", "head", FALSE
},
1711 {"j", "junk-session-cookies", FALSE
},
1712 {"k", "insecure", FALSE
},
1713 {"K", "config", TRUE
},
1714 {"l", "list-only", FALSE
},
1715 {"L", "location", FALSE
},
1716 {"Lt", "location-trusted", FALSE
},
1717 {"m", "max-time", TRUE
},
1718 {"M", "manual", FALSE
},
1719 {"n", "netrc", FALSE
},
1720 {"no", "netrc-optional", FALSE
},
1721 {"N", "buffer", FALSE
}, /* listed as --no-buffer in the help */
1722 {"o", "output", TRUE
},
1723 {"O", "remote-name", FALSE
},
1724 {"Oa", "remote-name-all", FALSE
},
1725 {"p", "proxytunnel", FALSE
},
1726 {"P", "ftpport", TRUE
}, /* older version */
1727 {"P", "ftp-port", TRUE
},
1728 {"q", "disable", FALSE
},
1729 {"Q", "quote", TRUE
},
1730 {"r", "range", TRUE
},
1731 {"R", "remote-time", FALSE
},
1732 {"s", "silent", FALSE
},
1733 {"S", "show-error", FALSE
},
1734 {"t", "telnet-options", TRUE
}, /* this is documented as telnet-option */
1735 {"T", "upload-file", TRUE
},
1736 {"u", "user", TRUE
},
1737 {"U", "proxy-user", TRUE
},
1738 {"v", "verbose", FALSE
},
1739 {"V", "version", FALSE
},
1740 {"w", "write-out", TRUE
},
1741 {"x", "proxy", TRUE
},
1742 {"X", "request", TRUE
},
1743 {"X", "http-request", TRUE
}, /* OBSOLETE VERSION */
1744 {"Y", "speed-limit", TRUE
},
1745 {"y", "speed-time", TRUE
},
1746 {"z", "time-cond", TRUE
},
1747 {"#", "progress-bar",FALSE
},
1750 if(('-' != flag
[0]) ||
1751 (('-' == flag
[0]) && ('-' == flag
[1]))) {
1752 /* this should be a long name */
1753 char *word
=('-' == flag
[0])?flag
+2:flag
;
1754 size_t fnam
=strlen(word
);
1757 if(!strncmp(word
, "no-", 3)) {
1758 /* disable this option but ignore the "no-" part when looking for it */
1763 for(j
=0; j
< sizeof(aliases
)/sizeof(aliases
[0]); j
++) {
1764 if(curlx_strnequal(aliases
[j
].lname
, word
, fnam
)) {
1767 if(curlx_strequal(aliases
[j
].lname
, word
)) {
1768 parse
= aliases
[j
].letter
;
1770 numhits
= 1; /* a single unique hit */
1773 parse
= aliases
[j
].letter
;
1778 /* this is at least the second match! */
1779 return PARAM_OPTION_AMBIGUOUS
;
1782 return PARAM_OPTION_UNKNOWN
;
1786 flag
++; /* prefixed with one dash, pass it */
1792 /* we can loop here if we have multiple single-letters */
1796 letter
= (char)*parse
;
1805 subletter
= parse
[1];
1807 *usedarg
= FALSE
; /* default is that we don't use the arg */
1810 for(j
=0; j
< sizeof(aliases
)/sizeof(aliases
[0]); j
++) {
1811 if(letter
== aliases
[j
].letter
[0]) {
1817 return PARAM_OPTION_UNKNOWN
;
1821 return PARAM_OPTION_UNKNOWN
;
1823 if(aliases
[hit
].extraparam
) {
1824 /* this option requires an extra parameter */
1825 if(!longopt
&& parse
[1]) {
1826 nextarg
=(char *)&parse
[1]; /* this is the actual extra parameter */
1827 singleopt
=TRUE
; /* don't loop anymore after this */
1830 return PARAM_REQUIRES_PARAMETER
;
1832 *usedarg
= TRUE
; /* mark it as used */
1836 case '*': /* options without a short option */
1838 case 'a': /* random-file */
1839 GetStr(&config
->random_file
, nextarg
);
1841 case 'b': /* egd-file */
1842 GetStr(&config
->egd_file
, nextarg
);
1844 case 'c': /* connect-timeout */
1845 if(str2num(&config
->connecttimeout
, nextarg
))
1846 return PARAM_BAD_NUMERIC
;
1848 case 'd': /* ciphers */
1849 GetStr(&config
->cipher_list
, nextarg
);
1851 case 'e': /* --disable-epsv */
1852 config
->disable_epsv
= toggle
;
1854 case 'E': /* --epsv */
1855 config
->disable_epsv
= !toggle
;
1857 #ifdef USE_ENVIRONMENT
1859 config
->writeenv
= toggle
;
1862 case 'g': /* --trace */
1863 GetStr(&config
->trace_dump
, nextarg
);
1864 if(config
->tracetype
&& (config
->tracetype
!= TRACE_BIN
))
1865 warnf(config
, "--trace overrides an earlier trace/verbose option\n");
1866 config
->tracetype
= TRACE_BIN
;
1868 case 'h': /* --trace-ascii */
1869 GetStr(&config
->trace_dump
, nextarg
);
1870 if(config
->tracetype
&& (config
->tracetype
!= TRACE_ASCII
))
1872 "--trace-ascii overrides an earlier trace/verbose option\n");
1873 config
->tracetype
= TRACE_ASCII
;
1875 case 'i': /* --limit-rate */
1877 /* We support G, M, K too */
1879 curl_off_t value
= curlx_strtoofft(nextarg
, &unit
, 0);
1883 else if(strlen(unit
) > 1)
1884 unit
=(char *)"w"; /* unsupported */
1889 value
*= 1024*1024*1024;
1901 /* for plain bytes, leave as-is */
1904 warnf(config
, "unsupported rate unit. Use G, M, K or B!\n");
1905 return PARAM_BAD_USE
;
1907 config
->recvpersecond
= value
;
1908 config
->sendpersecond
= value
;
1912 case 'j': /* --compressed */
1913 config
->encoding
= toggle
;
1916 case 'k': /* --digest */
1918 config
->authtype
|= CURLAUTH_DIGEST
;
1920 config
->authtype
&= ~CURLAUTH_DIGEST
;
1923 case 'l': /* --negotiate */
1925 if(curlinfo
->features
& CURL_VERSION_GSSNEGOTIATE
)
1926 config
->authtype
|= CURLAUTH_GSSNEGOTIATE
;
1928 return PARAM_LIBCURL_DOESNT_SUPPORT
;
1931 config
->authtype
&= ~CURLAUTH_GSSNEGOTIATE
;
1934 case 'm': /* --ntlm */
1936 if(curlinfo
->features
& CURL_VERSION_NTLM
)
1937 config
->authtype
|= CURLAUTH_NTLM
;
1939 return PARAM_LIBCURL_DOESNT_SUPPORT
;
1942 config
->authtype
&= ~CURLAUTH_NTLM
;
1945 case 'n': /* --basic for completeness */
1947 config
->authtype
|= CURLAUTH_BASIC
;
1949 config
->authtype
&= ~CURLAUTH_BASIC
;
1952 case 'o': /* --anyauth, let libcurl pick it */
1954 config
->authtype
= CURLAUTH_ANY
;
1955 /* --no-anyauth simply doesn't touch it */
1959 case 'p': /* --wdebug */
1963 case 'q': /* --ftp-create-dirs */
1964 config
->ftp_create_dirs
= toggle
;
1967 case 'r': /* --create-dirs */
1968 config
->create_dirs
= TRUE
;
1971 case 's': /* --max-redirs */
1972 /* specified max no of redirects (http(s)) */
1973 if(str2num(&config
->maxredirs
, nextarg
))
1974 return PARAM_BAD_NUMERIC
;
1977 case 't': /* --proxy-ntlm */
1978 if(curlinfo
->features
& CURL_VERSION_NTLM
)
1979 config
->proxyntlm
= toggle
;
1981 return PARAM_LIBCURL_DOESNT_SUPPORT
;
1984 case 'u': /* --crlf */
1985 /* LF -> CRLF conversion? */
1986 config
->crlf
= TRUE
;
1989 case 'v': /* --stderr */
1990 if(strcmp(nextarg
, "-")) {
1991 FILE *newfile
= fopen(nextarg
, "wt");
1993 warnf(config
, "Failed to open %s!\n", nextarg
);
1995 if(config
->errors_fopened
)
1996 fclose(config
->errors
);
1997 config
->errors
= newfile
;
1998 config
->errors_fopened
= TRUE
;
2002 config
->errors
= stdout
;
2004 case 'w': /* --interface */
2006 GetStr(&config
->iface
, nextarg
);
2008 case 'x': /* --krb */
2009 /* kerberos level string */
2010 if(curlinfo
->features
& (CURL_VERSION_KERBEROS4
|
2011 CURL_VERSION_GSSNEGOTIATE
))
2012 GetStr(&config
->krblevel
, nextarg
);
2014 return PARAM_LIBCURL_DOESNT_SUPPORT
;
2016 case 'y': /* --max-filesize */
2017 if(str2offset(&config
->max_filesize
, nextarg
))
2018 return PARAM_BAD_NUMERIC
;
2020 case 'z': /* --disable-eprt */
2021 config
->disable_eprt
= toggle
;
2023 case 'Z': /* --eprt */
2024 config
->disable_eprt
= !toggle
;
2027 default: /* the URL! */
2030 if(config
->url_get
|| (config
->url_get
=config
->url_list
)) {
2031 /* there's a node here, if it already is filled-in continue to find
2033 while(config
->url_get
&& (config
->url_get
->flags
&GETOUT_URL
))
2034 config
->url_get
= config
->url_get
->next
;
2037 /* now there might or might not be an available node to fill in! */
2041 url
= config
->url_get
;
2043 /* there was no free node, create one! */
2044 url
=new_getout(config
);
2047 /* fill in the URL */
2048 GetStr(&url
->url
, nextarg
);
2049 url
->flags
|= GETOUT_URL
;
2054 case '$': /* more options without a short option */
2056 case 'a': /* --ftp-ssl */
2057 config
->ftp_ssl
= toggle
;
2059 case 'b': /* --ftp-pasv */
2061 free(config
->ftpport
);
2062 config
->ftpport
= NULL
;
2064 case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
2065 the name locally and passes on the resolved address */
2066 GetStr(&config
->socksproxy
, nextarg
);
2067 config
->socksver
= CURLPROXY_SOCKS5
;
2069 case 't': /* --socks4 specifies a socks4 proxy to use */
2070 GetStr(&config
->socksproxy
, nextarg
);
2071 config
->socksver
= CURLPROXY_SOCKS4
;
2073 case 'T': /* --socks4a specifies a socks4a proxy to use */
2074 GetStr(&config
->socksproxy
, nextarg
);
2075 config
->socksver
= CURLPROXY_SOCKS4A
;
2077 case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
2078 resolving with the proxy */
2079 GetStr(&config
->socksproxy
, nextarg
);
2080 config
->socksver
= CURLPROXY_SOCKS5_HOSTNAME
;
2082 case 'd': /* --tcp-nodelay option */
2083 config
->tcp_nodelay
= toggle
;
2085 case 'e': /* --proxy-digest */
2086 config
->proxydigest
= toggle
;
2088 case 'f': /* --proxy-basic */
2089 config
->proxybasic
= toggle
;
2091 case 'g': /* --retry */
2092 if(str2num(&config
->req_retry
, nextarg
))
2093 return PARAM_BAD_NUMERIC
;
2095 case 'h': /* --retry-delay */
2096 if(str2num(&config
->retry_delay
, nextarg
))
2097 return PARAM_BAD_NUMERIC
;
2099 case 'i': /* --retry-max-time */
2100 if(str2num(&config
->retry_maxtime
, nextarg
))
2101 return PARAM_BAD_NUMERIC
;
2104 case 'k': /* --proxy-negotiate */
2105 if(curlinfo
->features
& CURL_VERSION_GSSNEGOTIATE
)
2106 config
->proxynegotiate
= toggle
;
2108 return PARAM_LIBCURL_DOESNT_SUPPORT
;
2110 case 'm': /* --ftp-account */
2111 GetStr(&config
->ftp_account
, nextarg
);
2113 case 'n': /* --proxy-anyauth */
2114 config
->proxyanyauth
= toggle
;
2116 case 'o': /* --trace-time */
2117 config
->tracetime
= toggle
;
2119 case 'p': /* --ignore-content-length */
2120 config
->ignorecl
= toggle
;
2122 case 'q': /* --ftp-skip-pasv-ip */
2123 config
->ftp_skip_ip
= toggle
;
2125 case 'r': /* --ftp-method (undocumented at this point) */
2126 config
->ftp_filemethod
= ftpfilemethod(config
, nextarg
);
2128 case 's': /* --local-port */
2129 rc
= sscanf(nextarg
, "%d - %d",
2131 &config
->localportrange
);
2133 return PARAM_BAD_USE
;
2135 config
->localportrange
= 1; /* default number of ports to try */
2137 config
->localportrange
-= config
->localport
;
2138 if(config
->localportrange
< 1) {
2139 warnf(config
, "bad range input\n");
2140 return PARAM_BAD_USE
;
2144 case 'u': /* --ftp-alternative-to-user */
2145 GetStr(&config
->ftp_alternative_to_user
, nextarg
);
2147 case 'v': /* --ftp-ssl-reqd */
2148 config
->ftp_ssl_reqd
= toggle
;
2150 case 'w': /* --no-sessionid */
2151 config
->disable_sessionid
= !toggle
;
2153 case 'x': /* --ftp-ssl-control */
2154 config
->ftp_ssl_control
= toggle
;
2156 case 'y': /* --ftp-ssl-ccc */
2157 config
->ftp_ssl_ccc
= toggle
;
2158 if(!config
->ftp_ssl_ccc_mode
)
2159 config
->ftp_ssl_ccc_mode
= CURLFTPSSL_CCC_PASSIVE
;
2161 case 'j': /* --ftp-ssl-ccc-mode */
2162 config
->ftp_ssl_ccc
= TRUE
;
2163 config
->ftp_ssl_ccc_mode
= ftpcccmethod(config
, nextarg
);
2165 case 'z': /* --libcurl */
2166 GetStr(&config
->libcurl
, nextarg
);
2168 case '#': /* --raw */
2169 config
->raw
= toggle
;
2171 case '0': /* --post301 */
2172 config
->post301
= toggle
;
2174 case '1': /* --no-keepalive */
2175 config
->nokeepalive
= !toggle
;
2177 case '3': /* --keepalive-time */
2178 if(str2num(&config
->alivetime
, nextarg
))
2179 return PARAM_BAD_NUMERIC
;
2183 case '#': /* --progress-bar */
2184 config
->progressmode
= toggle
?CURL_PROGRESS_BAR
:0;
2187 /* HTTP version 1.0 */
2188 config
->httpversion
= CURL_HTTP_VERSION_1_0
;
2192 config
->ssl_version
= CURL_SSLVERSION_TLSv1
;
2196 config
->ssl_version
= CURL_SSLVERSION_SSLv2
;
2200 config
->ssl_version
= CURL_SSLVERSION_SSLv3
;
2204 config
->ip_version
= 4;
2208 config
->ip_version
= 6;
2211 /* This makes the FTP sessions use APPE instead of STOR */
2212 config
->ftp_append
= toggle
;
2215 /* This specifies the User-Agent name */
2216 GetStr(&config
->useragent
, nextarg
);
2218 case 'b': /* cookie string coming up: */
2219 if(nextarg
[0] == '@') {
2222 else if(strchr(nextarg
, '=')) {
2223 /* A cookie string must have a =-letter */
2224 GetStr(&config
->cookie
, nextarg
);
2227 /* We have a cookie file to read from! */
2228 GetStr(&config
->cookiefile
, nextarg
);
2231 /* use ASCII/text when transfering */
2232 config
->use_ascii
= toggle
;
2235 /* get the file name to dump all cookies in */
2236 GetStr(&config
->cookiejar
, nextarg
);
2239 /* This makes us continue an ftp transfer at given position */
2240 if(!curlx_strequal(nextarg
, "-")) {
2241 if(str2offset(&config
->resume_from
, nextarg
))
2242 return PARAM_BAD_NUMERIC
;
2243 config
->resume_from_current
= FALSE
;
2246 config
->resume_from_current
= TRUE
;
2247 config
->resume_from
= 0;
2249 config
->use_resume
=TRUE
;
2252 /* postfield data */
2254 char *postdata
=NULL
;
2257 if(subletter
== 'e') { /* --data-urlencode*/
2258 /* [name]=[content], we encode the content part only
2259 * [name]@[file name]
2261 * Case 2: we first load the file using that name and then encode
2264 const char *p
= strchr(nextarg
, '=');
2269 /* there was no '=' letter, check for a '@' instead */
2270 p
= strchr(nextarg
, '@');
2272 nlen
= p
- nextarg
; /* length of the name part */
2273 is_file
= *p
++; /* pass the separator */
2276 /* neither @ nor =, so no name and it isn't a file */
2280 if('@' == is_file
) {
2281 /* a '@' letter, it means that a file name or - (stdin) follows */
2283 if(curlx_strequal("-", p
)) {
2288 file
= fopen(p
, "rb");
2291 "Couldn't read data from file \"%s\", this makes "
2292 "an empty POST.\n", nextarg
);
2295 err
= file2memory(&postdata
, &size
, file
);
2297 if(file
&& (file
!= stdin
))
2303 GetStr(&postdata
, p
);
2304 size
= strlen(postdata
);
2308 /* no data from the file, point to a zero byte string to make this
2309 get sent as a POST anyway */
2310 postdata
=strdup("");
2313 char *enc
= curl_easy_escape(config
->easy
, postdata
, size
);
2315 /* now make a string with the name from above and append the
2317 size_t outlen
= nlen
+ strlen(enc
) + 2;
2318 char *n
= malloc(outlen
);
2320 return PARAM_NO_MEM
;
2321 if (nlen
> 0) /* only append '=' if we have a name */
2322 snprintf(n
, outlen
, "%.*s=%s", nlen
, nextarg
, enc
);
2331 return PARAM_NO_MEM
;
2334 return PARAM_NO_MEM
;
2337 else if('@' == *nextarg
) {
2339 /* the data begins with a '@' letter, it means that a file name
2340 or - (stdin) follows */
2341 nextarg
++; /* pass the @ */
2343 if(curlx_strequal("-", nextarg
)) {
2345 if(subletter
== 'b') /* forced data-binary */
2349 file
= fopen(nextarg
, "rb");
2351 warnf(config
, "Couldn't read data from file \"%s\", this makes "
2352 "an empty POST.\n", nextarg
);
2355 if(subletter
== 'b') {
2357 err
= file2memory(&postdata
, &size
, file
);
2358 config
->postfieldsize
= (curl_off_t
)size
;
2361 err
= file2string(&postdata
, file
);
2363 if(file
&& (file
!= stdin
))
2369 /* no data from the file, point to a zero byte string to make this
2370 get sent as a POST anyway */
2371 postdata
=strdup("");
2375 GetStr(&postdata
, nextarg
);
2378 #ifdef CURL_DOES_CONVERSIONS
2379 if(subletter
!= 'b') { /* NOT forced binary, convert to ASCII */
2380 convert_to_network(postdata
, strlen(postdata
));
2384 if(config
->postfields
) {
2385 /* we already have a string, we append this one
2386 with a separating &-letter */
2387 char *oldpost
=config
->postfields
;
2388 size_t newlen
= strlen(oldpost
) + strlen(postdata
) + 2;
2389 config
->postfields
=malloc(newlen
);
2390 if(!config
->postfields
) {
2392 return PARAM_NO_MEM
;
2394 /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
2395 snprintf(config
->postfields
, newlen
, "%s\x26%s", oldpost
, postdata
);
2400 config
->postfields
=postdata
;
2403 We can't set the request type here, as this data might be used in
2404 a simple GET if -G is used. Already or soon.
2406 if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
2407 return PARAM_BAD_USE;
2411 /* dump-header to given file name */
2412 GetStr(&config
->headerfile
, nextarg
);
2416 char *ptr
= strstr(nextarg
, ";auto");
2418 /* Automatic referer requested, this may be combined with a
2420 config
->autoreferer
= TRUE
;
2421 *ptr
= 0; /* zero terminate here */
2424 config
->autoreferer
= FALSE
;
2425 GetStr(&config
->referer
, nextarg
);
2430 case 'a': /* CA info PEM file */
2431 /* CA info PEM file */
2432 GetStr(&config
->cacert
, nextarg
);
2434 case 'b': /* cert file type */
2435 GetStr(&config
->cert_type
, nextarg
);
2437 case 'c': /* private key file */
2438 GetStr(&config
->key
, nextarg
);
2440 case 'd': /* private key file type */
2441 GetStr(&config
->key_type
, nextarg
);
2443 case 'e': /* private key passphrase */
2444 GetStr(&config
->key_passwd
, nextarg
);
2447 case 'f': /* crypto engine */
2448 GetStr(&config
->engine
, nextarg
);
2449 if (config
->engine
&& curlx_strequal(config
->engine
,"list"))
2450 config
->list_engines
= TRUE
;
2452 case 'g': /* CA info PEM file */
2453 /* CA cert directory */
2454 GetStr(&config
->capath
, nextarg
);
2456 case 'h': /* --pubkey public key file */
2457 GetStr(&config
->pubkey
, nextarg
);
2459 case 'i': /* --hostpubmd5 md5 of the host public key */
2460 GetStr(&config
->hostpubmd5
, nextarg
);
2461 if (!config
->hostpubmd5
|| strlen(config
->hostpubmd5
) != 32)
2462 return PARAM_BAD_USE
;
2464 default: /* certificate file */
2466 char *ptr
= strchr(nextarg
, ':');
2467 /* Since we live in a world of weirdness and confusion, the win32
2468 dudes can use : when using drive letters and thus
2469 c:\file:password needs to work. In order not to break
2470 compatibility, we still use : as separator, but we try to detect
2471 when it is used for a file name! On windows. */
2474 (ptr
== &nextarg
[1]) &&
2475 (nextarg
[2] == '\\' || nextarg
[2] == '/') &&
2476 (ISALPHA(nextarg
[0])) )
2477 /* colon in the second column, followed by a backslash, and the
2478 first character is an alphabetic letter:
2480 this is a drive letter colon */
2481 ptr
= strchr(&nextarg
[3], ':'); /* find the next one instead */
2484 /* we have a password too */
2487 GetStr(&config
->key_passwd
, ptr
);
2489 GetStr(&config
->cert
, nextarg
);
2495 /* fail hard on errors */
2496 config
->failonerror
= toggle
;
2499 /* "form data" simulation, this is a little advanced so lets do our best
2500 to sort this out slowly and carefully */
2501 if(formparse(config
,
2505 (bool) (subletter
=='s'))) /* 's' means literal string */
2506 return PARAM_BAD_USE
;
2507 if(SetHTTPrequest(config
, HTTPREQ_POST
, &config
->httpreq
))
2508 return PARAM_BAD_USE
;
2511 case 'g': /* g disables URLglobbing */
2512 config
->globoff
= toggle
;
2515 case 'G': /* HTTP GET */
2516 config
->use_httpget
= TRUE
;
2519 case 'h': /* h for help */
2522 return PARAM_HELP_REQUESTED
;
2524 /* we now actually support --no-help too! */
2527 /* A custom header to append to a list */
2528 err
= add2list(&config
->headers
, nextarg
);
2533 config
->include_headers
= toggle
; /* include the headers as well in the
2534 general output stream */
2537 config
->cookiesession
= toggle
;
2541 * no_body will imply include_headers later on
2543 config
->no_body
= toggle
;
2544 if(SetHTTPrequest(config
,
2545 (config
->no_body
)?HTTPREQ_HEAD
:HTTPREQ_GET
,
2547 return PARAM_BAD_USE
;
2549 case 'k': /* allow insecure SSL connects */
2550 config
->insecure_ok
= toggle
;
2552 case 'K': /* parse config file */
2553 if(parseconfig(nextarg
, config
))
2554 warnf(config
, "error trying read config from the '%s' file\n",
2558 config
->dirlistonly
= toggle
; /* only list the names of the FTP dir */
2561 config
->followlocation
= toggle
; /* Follow Location: HTTP headers */
2562 switch (subletter
) {
2564 /* Continue to send authentication (user+password) when following
2565 * locations, even when hostname changed */
2566 config
->unrestricted_auth
= toggle
;
2571 /* specified max time */
2572 if(str2num(&config
->timeout
, nextarg
))
2573 return PARAM_BAD_NUMERIC
;
2575 case 'M': /* M for manual, huge help */
2576 if(toggle
) { /* --no-manual shows no manual... */
2579 return PARAM_HELP_REQUESTED
;
2582 "built-in manual was disabled at build-time!\n");
2583 return PARAM_OPTION_UNKNOWN
;
2589 case 'o': /* CA info PEM file */
2590 /* use .netrc or URL */
2591 config
->netrc_opt
= toggle
;
2594 /* pick info from .netrc, if this is used for http, curl will
2595 automatically enfore user+password with the request */
2596 config
->netrc
= toggle
;
2601 /* disable the output I/O buffering */
2602 config
->nobuffer
= !toggle
;
2604 case 'O': /* --remote-name */
2605 if(subletter
== 'a') { /* --remote-name-all */
2606 config
->default_node_flags
= toggle
?GETOUT_USEREMOTE
:0;
2610 case 'o': /* --output */
2614 if(config
->url_out
|| (config
->url_out
=config
->url_list
)) {
2615 /* there's a node here, if it already is filled-in continue to find
2617 while(config
->url_out
&& (config
->url_out
->flags
&GETOUT_OUTFILE
))
2618 config
->url_out
= config
->url_out
->next
;
2621 /* now there might or might not be an available node to fill in! */
2625 url
= config
->url_out
;
2627 /* there was no free node, create one! */
2628 url
=new_getout(config
);
2631 /* fill in the outfile */
2633 GetStr(&url
->outfile
, nextarg
);
2634 url
->flags
&= ~GETOUT_USEREMOTE
; /* switch off */
2637 url
->outfile
=NULL
; /* leave it */
2639 url
->flags
|= GETOUT_USEREMOTE
; /* switch on */
2641 url
->flags
&= ~GETOUT_USEREMOTE
; /* switch off */
2643 url
->flags
|= GETOUT_OUTFILE
;
2648 /* This makes the FTP sessions use PORT instead of PASV */
2649 /* use <eth0> or <192.168.10.10> style addresses. Anything except
2650 this will make us try to get the "default" address.
2651 NOTE: this is a changed behaviour since the released 4.1!
2653 GetStr(&config
->ftpport
, nextarg
);
2656 /* proxy tunnel for non-http protocols */
2657 config
->proxytunnel
= toggle
;
2660 case 'q': /* if used first, already taken care of, we do it like
2661 this so we don't cause an error! */
2664 /* QUOTE command to send to FTP server */
2666 switch(nextarg
[0]) {
2668 /* prefixed with a dash makes it a POST TRANSFER one */
2670 err
= add2list(&config
->postquote
, nextarg
);
2673 /* prefixed with a plus makes it a just-before-transfer one */
2675 err
= add2list(&config
->prequote
, nextarg
);
2678 err
= add2list(&config
->quote
, nextarg
);
2685 /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
2686 (and won't actually be range by definition). The man page previously
2687 claimed that to be a good way, why this code is added to work-around
2689 if(ISDIGIT(*nextarg
) && !strchr(nextarg
, '-')) {
2693 "A specified range MUST include at least one dash (-). "
2694 "Appending one for you!\n");
2695 off
= curlx_strtoofft(nextarg
, NULL
, 10);
2696 snprintf(buffer
, sizeof(buffer
), "%Od-", off
);
2697 GetStr(&config
->range
, buffer
);
2700 /* byte range requested */
2703 while(*tmp_range
!= '\0') {
2704 if(!ISDIGIT(*tmp_range
)&&*tmp_range
!='-'&&*tmp_range
!=',') {
2705 warnf(config
,"Invalid character is found in given range. "
2706 "A specified range MUST have only digits in "
2707 "\'start\'-\'stop\'. The server's response to this "
2708 "request is uncertain.\n");
2713 /* byte range requested */
2714 GetStr(&config
->range
, nextarg
);
2718 /* use remote file's time */
2719 config
->remote_time
= toggle
;
2722 /* don't show progress meter, don't show errors : */
2724 config
->mute
= config
->noprogress
= TRUE
;
2726 config
->mute
= config
->noprogress
= FALSE
;
2727 config
->showerror
= !toggle
; /* toggle off */
2731 config
->showerror
= toggle
; /* toggle on if used with -s */
2734 /* Telnet options */
2735 err
= add2list(&config
->telnet_options
, nextarg
);
2740 /* we are uploading */
2743 if(config
->url_out
|| (config
->url_out
=config
->url_list
)) {
2744 /* there's a node here, if it already is filled-in continue to find
2746 while(config
->url_out
&& (config
->url_out
->flags
&GETOUT_UPLOAD
))
2747 config
->url_out
= config
->url_out
->next
;
2750 /* now there might or might not be an available node to fill in! */
2754 url
= config
->url_out
;
2756 /* there was no free node, create one! */
2757 url
=new_getout(config
);
2760 url
->flags
|= GETOUT_UPLOAD
; /* mark -T used */
2762 url
->flags
|= GETOUT_NOUPLOAD
;
2764 /* "-" equals stdin, but keep the string around for now */
2765 GetStr(&url
->infile
, nextarg
);
2772 GetStr(&config
->userpwd
, nextarg
);
2774 checkpasswd("host", &config
->userpwd
);
2777 /* Proxy user:password */
2778 GetStr(&config
->proxyuserpwd
, nextarg
);
2780 checkpasswd("proxy", &config
->proxyuserpwd
);
2784 /* the '%' thing here will cause the trace get sent to stderr */
2785 GetStr(&config
->trace_dump
, (char *)"%");
2786 if(config
->tracetype
&& (config
->tracetype
!= TRACE_PLAIN
))
2788 "-v/--verbose overrides an earlier trace/verbose option\n");
2789 config
->tracetype
= TRACE_PLAIN
;
2792 /* verbose is disabled here */
2793 config
->tracetype
= TRACE_NONE
;
2797 const char * const *proto
;
2800 /* --no-version yields no output! */
2803 printf(CURL_ID
"%s\n", curl_version());
2804 if (curlinfo
->protocols
) {
2805 printf("Protocols: ");
2806 for (proto
=curlinfo
->protocols
; *proto
; ++proto
) {
2807 printf("%s ", *proto
);
2809 puts(""); /* newline */
2811 if(curlinfo
->features
) {
2817 static const struct feat feats
[] = {
2818 {"AsynchDNS", CURL_VERSION_ASYNCHDNS
},
2819 {"Debug", CURL_VERSION_DEBUG
},
2820 {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE
},
2821 {"IDN", CURL_VERSION_IDN
},
2822 {"IPv6", CURL_VERSION_IPV6
},
2823 {"Largefile", CURL_VERSION_LARGEFILE
},
2824 {"NTLM", CURL_VERSION_NTLM
},
2825 {"SPNEGO", CURL_VERSION_SPNEGO
},
2826 {"SSL", CURL_VERSION_SSL
},
2827 {"SSPI", CURL_VERSION_SSPI
},
2828 {"krb4", CURL_VERSION_KERBEROS4
},
2829 {"libz", CURL_VERSION_LIBZ
},
2830 {"CharConv", CURL_VERSION_CONV
}
2832 printf("Features: ");
2833 for(i
=0; i
<sizeof(feats
)/sizeof(feats
[0]); i
++) {
2834 if(curlinfo
->features
& feats
[i
].bitmask
)
2835 printf("%s ", feats
[i
].name
);
2837 puts(""); /* newline */
2840 return PARAM_HELP_REQUESTED
;
2842 /* get the output string */
2843 if('@' == *nextarg
) {
2844 /* the data begins with a '@' letter, it means that a file name
2845 or - (stdin) follows */
2847 nextarg
++; /* pass the @ */
2848 if(curlx_strequal("-", nextarg
))
2851 file
= fopen(nextarg
, "r");
2852 err
= file2string(&config
->writeout
, file
);
2853 if(file
&& (file
!= stdin
))
2857 if(!config
->writeout
)
2858 warnf(config
, "Failed to read %s", file
);
2861 GetStr(&config
->writeout
, nextarg
);
2865 GetStr(&config
->proxy
, nextarg
);
2868 /* set custom request */
2869 GetStr(&config
->customrequest
, nextarg
);
2872 /* low speed time */
2873 if(str2num(&config
->low_speed_time
, nextarg
))
2874 return PARAM_BAD_NUMERIC
;
2875 if(!config
->low_speed_limit
)
2876 config
->low_speed_limit
= 1;
2879 /* low speed limit */
2880 if(str2num(&config
->low_speed_limit
, nextarg
))
2881 return PARAM_BAD_NUMERIC
;
2882 if(!config
->low_speed_time
)
2883 config
->low_speed_time
=30;
2885 case 'z': /* time condition coming up */
2890 /* If-Modified-Since: (section 14.28 in RFC2068) */
2891 config
->timecond
= CURL_TIMECOND_IFMODSINCE
;
2894 /* If-Unmodified-Since: (section 14.24 in RFC2068) */
2895 config
->timecond
= CURL_TIMECOND_IFUNMODSINCE
;
2899 /* Last-Modified: (section 14.29 in RFC2068) */
2900 config
->timecond
= CURL_TIMECOND_LASTMOD
;
2905 config
->condtime
=curl_getdate(nextarg
, &now
);
2906 if(-1 == (int)config
->condtime
) {
2907 /* now let's see if it is a file name to get the time from instead! */
2908 struct_stat statbuf
;
2909 if(-1 == stat(nextarg
, &statbuf
)) {
2910 /* failed, remove time condition */
2911 config
->timecond
= CURL_TIMECOND_NONE
;
2913 "Illegal date format for -z/--timecond (and not "
2914 "a file name). Disabling time condition. "
2915 "See curl_getdate(3) for valid date syntax.\n");
2918 /* pull the time out from the file */
2919 config
->condtime
= statbuf
.st_mtime
;
2923 default: /* unknown flag */
2924 return PARAM_OPTION_UNKNOWN
;
2928 } while(!longopt
&& !singleopt
&& *++parse
&& !*usedarg
);
2934 * Copies the string from line to the buffer at param, unquoting
2935 * backslash-quoted characters and NUL-terminating the output string.
2936 * Stops at the first non-backslash-quoted double quote character or the
2937 * end of the input string. param must be at least as long as the input
2938 * string. Returns the pointer after the last handled input character.
2940 static const char *unslashquote(const char *line
, char *param
)
2942 while(*line
&& (*line
!= '\"')) {
2947 /* default is to output the letter after the backslash */
2948 switch(out
= *line
) {
2950 continue; /* this'll break out of the loop */
2970 *param
=0; /* always zero terminate */
2974 /* return 0 on everything-is-fine, and non-zero otherwise */
2975 static int parseconfig(const char *filename
,
2976 struct Configurable
*config
)
2980 char filebuffer
[512];
2985 if(!filename
|| !*filename
) {
2986 /* NULL or no file name attempts to load .curlrc from the homedir! */
2988 #define CURLRC DOT_CHAR "curlrc"
2991 filename
= CURLRC
; /* sensible default */
2992 home
= homedir(); /* portable homedir finder */
2994 if(strlen(home
)<(sizeof(filebuffer
)-strlen(CURLRC
))) {
2995 snprintf(filebuffer
, sizeof(filebuffer
),
2996 "%s%s%s", home
, DIR_CHAR
, CURLRC
);
2999 /* Check if the file exists - if not, try CURLRC in the same
3000 * directory as our executable
3002 file
= fopen(filebuffer
, "r");
3005 filename
= filebuffer
;
3008 /* Get the filename of our executable. GetModuleFileName is
3009 * already declared via inclusions done in setup header file.
3010 * We assume that we are using the ASCII version here.
3012 int n
= GetModuleFileName(0, filebuffer
, sizeof(filebuffer
));
3013 if (n
> 0 && n
< (int)sizeof(filebuffer
)) {
3014 /* We got a valid filename - get the directory part */
3015 char *lastdirchar
= strrchr(filebuffer
, '\\');
3019 /* If we have enough space, build the RC filename */
3020 remaining
= sizeof(filebuffer
) - strlen(filebuffer
);
3021 if ((int)strlen(CURLRC
) < remaining
- 1) {
3022 snprintf(lastdirchar
, remaining
,
3023 "%s%s", DIR_CHAR
, CURLRC
);
3024 /* Don't bother checking if it exists - we do
3027 filename
= filebuffer
;
3033 filename
= filebuffer
;
3036 free(home
); /* we've used it, now free it */
3039 # else /* __AMIGA__ */
3040 /* On AmigaOS all the config files are into env:
3042 filename
= "ENV:" CURLRC
;
3047 if(strcmp(filename
,"-"))
3048 file
= fopen(filename
, "r");
3060 #define ISSEP(x) (((x)=='=') || ((x) == ':'))
3062 while (NULL
!= (aline
= my_get_line(file
))) {
3065 alloced_param
=FALSE
;
3067 /* line with # in the first non-blank column is a comment! */
3068 while(*line
&& ISSPACE(*line
))
3082 /* the option keywords starts here */
3084 while(*line
&& !ISSPACE(*line
) && !ISSEP(*line
))
3086 /* ... and has ended here */
3089 *line
++=0; /* zero terminate, we have a local copy of the data */
3092 fprintf(stderr
, "GOT: %s\n", option
);
3095 /* pass spaces and separator(s) */
3096 while(*line
&& (ISSPACE(*line
) || ISSEP(*line
)))
3099 /* the parameter starts here (unless quoted) */
3101 /* quoted parameter, do the quote dance */
3103 param
=malloc(strlen(line
)+1); /* parameter */
3111 line
= (char*) unslashquote(line
, param
);
3114 param
=line
; /* parameter starts here */
3115 while(*line
&& !ISSPACE(*line
))
3117 *line
=0; /* zero terminate */
3120 if (param
&& !*param
) {
3121 /* do this so getparameter can check for required parameters.
3122 Otherwise it always thinks there's a parameter. */
3129 fprintf(stderr
, "PARAM: \"%s\"\n",(param
? param
: "(null)"));
3131 res
= getparameter(option
, param
, &usedarg
, config
);
3133 if (param
&& *param
&& !usedarg
)
3134 /* we passed in a parameter that wasn't used! */
3135 res
= PARAM_GOT_EXTRA_PARAMETER
;
3137 if(res
!= PARAM_OK
) {
3138 /* the help request isn't really an error */
3139 if(!strcmp(filename
, "-")) {
3140 filename
=(char *)"<stdin>";
3142 if(PARAM_HELP_REQUESTED
!= res
) {
3143 const char *reason
= param2text(res
);
3144 warnf(config
, "%s:%d: warning: '%s' %s\n",
3145 filename
, lineno
, option
, reason
);
3161 rc
= 1; /* couldn't open the file */
3165 static void go_sleep(long ms
)
3167 #ifdef HAVE_POLL_FINE
3168 /* portable subsecond "sleep" */
3169 poll((void *)0, 0, (int)ms
);
3171 /* systems without poll() need other solutions */
3174 /* Windows offers a millisecond sleep */
3176 #elif defined(MSDOS)
3179 /* Other systems must use select() for this */
3180 struct timeval timeout
;
3182 timeout
.tv_sec
= ms
/1000;
3184 timeout
.tv_usec
= ms
* 1000;
3186 select(0, NULL
, NULL
, NULL
, &timeout
);
3192 static size_t my_fwrite(void *buffer
, size_t sz
, size_t nmemb
, void *stream
)
3195 struct OutStruct
*out
=(struct OutStruct
*)stream
;
3196 struct Configurable
*config
= out
->config
;
3199 /* open file for writing */
3200 out
->stream
=fopen(out
->filename
, "wb");
3202 warnf(config
, "Failed to create the file %s\n", out
->filename
);
3204 * Once that libcurl has called back my_fwrite() the returned value
3205 * is checked against the amount that was intended to be written, if
3206 * it does not match then it fails with CURLE_WRITE_ERROR. So at this
3207 * point returning a value different from sz*nmemb indicates failure.
3209 rc
= (0 == (sz
* nmemb
)) ? 1 : 0;
3210 return rc
; /* failure */
3214 rc
= fwrite(buffer
, sz
, nmemb
, out
->stream
);
3216 if((sz
* nmemb
) == rc
) {
3217 /* we added this amount of data to the output */
3218 out
->bytes
+= (sz
* nmemb
);
3221 if(config
->nobuffer
)
3222 /* disable output buffering */
3223 fflush(out
->stream
);
3230 struct Configurable
*config
;
3233 #define MAX_SEEK 2147483647
3236 * my_seek() is the CURLOPT_SEEKFUNCTION we use
3238 static int my_seek(void *stream
, curl_off_t offset
, int whence
)
3240 struct InStruct
*in
=(struct InStruct
*)stream
;
3242 #if (CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
3243 /* The offset check following here is only interesting if curl_off_t is
3244 larger than off_t and we are not using the WIN32 large file support
3245 macros that provide the support to do 64bit seeks correctly */
3247 if(offset
> MAX_SEEK
) {
3248 /* Some precaution code to work around problems with different data sizes
3249 to allow seeking >32bit even if off_t is 32bit. Should be very rare and
3250 is really valid on weirdo-systems. */
3251 curl_off_t left
= offset
;
3253 if(whence
!= SEEK_SET
)
3254 /* this code path doesn't support other types */
3257 if(-1 == lseek(in
->fd
, 0, SEEK_SET
))
3258 /* couldn't rewind to beginning */
3262 long step
= (left
>MAX_SEEK
? MAX_SEEK
: (long)left
);
3263 if(-1 == lseek(in
->fd
, step
, SEEK_CUR
))
3264 /* couldn't seek forwards the desired amount */
3271 if(-1 == lseek(in
->fd
, offset
, whence
))
3272 /* couldn't rewind, the reason is in errno but errno is just not
3273 portable enough and we don't actually care that much why we failed. */
3279 static size_t my_fread(void *buffer
, size_t sz
, size_t nmemb
, void *userp
)
3282 struct InStruct
*in
=(struct InStruct
*)userp
;
3284 rc
= read(in
->fd
, buffer
, sz
*nmemb
);
3286 /* since size_t is unsigned we can't return negative values fine */
3291 struct ProgressData
{
3295 FILE *out
; /* where to write everything to */
3296 curl_off_t initial_size
;
3299 static int myprogress (void *clientp
,
3305 /* The original progress-bar source code was written for curl by Lars Aas,
3306 and this new edition inherits some of his concepts. */
3317 struct ProgressData
*bar
= (struct ProgressData
*)clientp
;
3318 curl_off_t total
= (curl_off_t
)dltotal
+ (curl_off_t
)ultotal
+
3319 bar
->initial_size
; /* expected transfer size */
3320 curl_off_t point
= (curl_off_t
)dlnow
+ (curl_off_t
)ulnow
+
3321 bar
->initial_size
; /* we've come this far */
3324 /* we have got more than the expected total! */
3327 bar
->calls
++; /* simply count invokes */
3330 curl_off_t prevblock
= bar
->prev
/ 1024;
3331 curl_off_t thisblock
= point
/ 1024;
3332 while ( thisblock
> prevblock
) {
3333 fprintf( bar
->out
, "#" );
3338 frac
= (double)point
/ (double)total
;
3339 percent
= frac
* 100.0f
;
3340 barwidth
= bar
->width
- 7;
3341 num
= (int) (((double)barwidth
) * frac
);
3343 for ( i
= 0; i
< num
; i
++ ) {
3347 snprintf( format
, sizeof(format
), "%%-%ds %%5.1f%%%%", barwidth
);
3348 snprintf( outline
, sizeof(outline
), format
, line
, percent
);
3349 fprintf( bar
->out
, "\r%s", outline
);
3358 void progressbarinit(struct ProgressData
*bar
,
3359 struct Configurable
*config
)
3367 memset(bar
, 0, sizeof(struct ProgressData
));
3369 /* pass this through to progress function so
3370 * it can display progress towards total file
3371 * not just the part that's left. (21-may-03, dbyron) */
3372 if (config
->use_resume
)
3373 bar
->initial_size
= config
->resume_from
;
3375 /* TODO: get terminal width through ansi escapes or something similar.
3376 try to update width when xterm is resized... - 19990617 larsa */
3379 * OS/2 users most likely won't have this env var set, and besides that
3380 * we're using our own way to determine screen width */
3381 colp
= curlx_getenv("COLUMNS");
3383 bar
->width
= atoi(colp
);
3390 * We use this emx library call to get the screen width, and subtract
3391 * one from what we got in order to avoid a problem with the cursor
3392 * advancing to the next line if we print a string that is as long as
3393 * the screen is wide. */
3396 bar
->width
= scr_size
[0] - 1;
3399 bar
->out
= config
->errors
;
3404 void dump(const char *timebuf
, const char *text
,
3405 FILE *stream
, const unsigned char *ptr
, size_t size
,
3406 trace tracetype
, curl_infotype infotype
)
3411 unsigned int width
=0x10;
3413 if(tracetype
== TRACE_ASCII
)
3414 /* without the hex output, we can fit more on screen */
3417 fprintf(stream
, "%s%s, %zd bytes (0x%zx)\n", timebuf
, text
, size
, size
);
3419 for(i
=0; i
<size
; i
+= width
) {
3421 fprintf(stream
, "%04zx: ", i
);
3423 if(tracetype
== TRACE_BIN
) {
3424 /* hex not disabled, show it */
3425 for(c
= 0; c
< width
; c
++)
3427 fprintf(stream
, "%02x ", ptr
[i
+c
]);
3432 for(c
= 0; (c
< width
) && (i
+c
< size
); c
++) {
3433 /* check for 0D0A; if found, skip past and start a new line of output */
3434 if ((tracetype
== TRACE_ASCII
) &&
3435 (i
+c
+1 < size
) && ptr
[i
+c
]==0x0D && ptr
[i
+c
+1]==0x0A) {
3439 #ifdef CURL_DOES_CONVERSIONS
3440 /* repeat the 0D0A check above but use the host encoding for CRLF */
3441 if ((tracetype
== TRACE_ASCII
) &&
3442 (i
+c
+1 < size
) && ptr
[i
+c
]=='\r' && ptr
[i
+c
+1]=='\n') {
3446 /* convert to host encoding and print this character */
3447 fprintf(stream
, "%c", convert_char(infotype
, ptr
[i
+c
]));
3450 fprintf(stream
, "%c",
3451 (ptr
[i
+c
]>=0x20) && (ptr
[i
+c
]<0x80)?ptr
[i
+c
]:UNPRINTABLE_CHAR
);
3452 #endif /* CURL_DOES_CONVERSIONS */
3453 /* check again for 0D0A, to avoid an extra \n if it's at width */
3454 if ((tracetype
== TRACE_ASCII
) &&
3455 (i
+c
+2 < size
) && ptr
[i
+c
+1]==0x0D && ptr
[i
+c
+2]==0x0A) {
3460 fputc('\n', stream
); /* newline */
3466 int my_trace(CURL
*handle
, curl_infotype type
,
3467 unsigned char *data
, size_t size
,
3470 struct Configurable
*config
= (struct Configurable
*)userp
;
3471 FILE *output
=config
->errors
;
3478 (void)handle
; /* prevent compiler warning */
3482 now
= localtime(&secs
); /* not multithread safe but we don't care */
3483 if(config
->tracetime
)
3484 snprintf(timebuf
, sizeof(timebuf
), "%02d:%02d:%02d.%06d ",
3485 now
->tm_hour
, now
->tm_min
, now
->tm_sec
, tv
.tv_usec
);
3489 if(!config
->trace_stream
) {
3490 /* open for append */
3491 if(curlx_strequal("-", config
->trace_dump
))
3492 config
->trace_stream
= stdout
;
3493 else if(curlx_strequal("%", config
->trace_dump
))
3494 /* Ok, this is somewhat hackish but we do it undocumented for now */
3495 config
->trace_stream
= config
->errors
; /* aka stderr */
3497 config
->trace_stream
= fopen(config
->trace_dump
, "w");
3498 config
->trace_fopened
= TRUE
;
3502 if(config
->trace_stream
)
3503 output
= config
->trace_stream
;
3505 if(config
->tracetype
== TRACE_PLAIN
) {
3507 * This is the trace look that is similar to what libcurl makes on its
3510 static const char * const s_infotype
[] = {
3511 "*", "<", ">", "{", "}", "{", "}"
3515 static bool newl
= FALSE
;
3516 static bool traced_data
= FALSE
;
3519 case CURLINFO_HEADER_OUT
:
3520 for(i
=0; i
<size
-1; i
++) {
3521 if(data
[i
] == '\n') { /* LF */
3523 fprintf(config
->trace_stream
, "%s%s ",
3524 timebuf
, s_infotype
[type
]);
3526 fwrite(data
+st
, i
-st
+1, 1, config
->trace_stream
);
3532 fprintf(config
->trace_stream
, "%s%s ", timebuf
, s_infotype
[type
]);
3533 fwrite(data
+st
, i
-st
+1, 1, config
->trace_stream
);
3534 newl
= (bool)(size
&& (data
[size
-1] != '\n'));
3535 traced_data
= FALSE
;
3538 case CURLINFO_HEADER_IN
:
3540 fprintf(config
->trace_stream
, "%s%s ", timebuf
, s_infotype
[type
]);
3541 fwrite(data
, size
, 1, config
->trace_stream
);
3542 newl
= (bool)(size
&& (data
[size
-1] != '\n'));
3543 traced_data
= FALSE
;
3545 case CURLINFO_DATA_OUT
:
3546 case CURLINFO_DATA_IN
:
3547 case CURLINFO_SSL_DATA_IN
:
3548 case CURLINFO_SSL_DATA_OUT
:
3550 /* if the data is output to a tty and we're sending this debug trace
3551 to stderr or stdout, we don't display the alert about the data not
3552 being shown as the data _is_ shown then just not via this
3554 if(!config
->isatty
||
3555 ((config
->trace_stream
!= stderr
) &&
3556 (config
->trace_stream
!= stdout
))) {
3558 fprintf(config
->trace_stream
, "%s%s ", timebuf
, s_infotype
[type
]);
3559 fprintf(config
->trace_stream
, "[data not shown]\n");
3567 traced_data
= FALSE
;
3574 #ifdef CURL_DOES_CONVERSIONS
3575 /* Special processing is needed for CURLINFO_HEADER_OUT blocks
3576 * if they contain both headers and data (separated by CRLFCRLF).
3577 * We dump the header text and then switch type to CURLINFO_DATA_OUT.
3579 if((type
== CURLINFO_HEADER_OUT
) && (size
> 4)) {
3581 for(i
= 0; i
< size
- 4; i
++) {
3582 if(memcmp(&data
[i
], "\r\n\r\n", 4) == 0) {
3583 /* dump everthing through the CRLFCRLF as a sent header */
3584 text
= "=> Send header";
3585 dump(timebuf
, text
, output
, data
, i
+4, config
->tracetype
, type
);
3588 type
= CURLINFO_DATA_OUT
;
3594 #endif /* CURL_DOES_CONVERSIONS */
3598 fprintf(output
, "%s== Info: %s", timebuf
, data
);
3599 default: /* in case a new one is introduced to shock us */
3602 case CURLINFO_HEADER_OUT
:
3603 text
= "=> Send header";
3605 case CURLINFO_DATA_OUT
:
3606 text
= "=> Send data";
3608 case CURLINFO_HEADER_IN
:
3609 text
= "<= Recv header";
3611 case CURLINFO_DATA_IN
:
3612 text
= "<= Recv data";
3614 case CURLINFO_SSL_DATA_IN
:
3615 text
= "<= Recv SSL data";
3617 case CURLINFO_SSL_DATA_OUT
:
3618 text
= "=> Send SSL data";
3622 dump(timebuf
, text
, output
, data
, size
, config
->tracetype
, type
);
3626 static void free_config_fields(struct Configurable
*config
)
3628 if(config
->random_file
)
3629 free(config
->random_file
);
3630 if(config
->egd_file
)
3631 free(config
->egd_file
);
3632 if(config
->trace_dump
)
3633 free(config
->trace_dump
);
3634 if(config
->cipher_list
)
3635 free(config
->cipher_list
);
3637 free(config
->userpwd
);
3638 if(config
->postfields
)
3639 free(config
->postfields
);
3641 free(config
->proxy
);
3642 if(config
->proxyuserpwd
)
3643 free(config
->proxyuserpwd
);
3645 free(config
->cookie
);
3646 if(config
->cookiefile
)
3647 free(config
->cookiefile
);
3648 if(config
->krblevel
)
3649 free(config
->krblevel
);
3650 if(config
->headerfile
)
3651 free(config
->headerfile
);
3653 free(config
->ftpport
);
3655 free(config
->range
);
3656 if(config
->customrequest
)
3657 free(config
->customrequest
);
3658 if(config
->writeout
)
3659 free(config
->writeout
);
3660 if(config
->httppost
)
3661 curl_formfree(config
->httppost
);
3665 free(config
->cacert
);
3666 if (config
->cert_type
)
3667 free(config
->cert_type
);
3669 free(config
->capath
);
3670 if(config
->cookiejar
)
3671 free(config
->cookiejar
);
3672 if(config
->ftp_account
)
3673 free(config
->ftp_account
);
3674 if(config
->ftp_alternative_to_user
)
3675 free(config
->ftp_alternative_to_user
);
3677 free(config
->iface
);
3678 if(config
->socksproxy
)
3679 free(config
->socksproxy
);
3681 free(config
->libcurl
);
3682 if (config
->key_passwd
)
3683 free(config
->key_passwd
);
3686 if (config
->key_type
)
3687 free(config
->key_type
);
3689 free(config
->pubkey
);
3690 if (config
->referer
)
3691 free(config
->referer
);
3692 if (config
->hostpubmd5
)
3693 free(config
->hostpubmd5
);
3695 curl_slist_free_all(config
->quote
); /* checks for config->quote == NULL */
3696 curl_slist_free_all(config
->prequote
);
3697 curl_slist_free_all(config
->postquote
);
3698 curl_slist_free_all(config
->headers
);
3699 curl_slist_free_all(config
->telnet_options
);
3702 curl_easy_cleanup(config
->easy
);
3707 /* Function to find CACert bundle on a Win32 platform using SearchPath.
3708 * (SearchPath is already declared via inclusions done in setup header file)
3709 * (Use the ASCII version instead of the unicode one!)
3710 * The order of the directories it searches is:
3711 * 1. application's directory
3712 * 2. current working directory
3713 * 3. Windows System directory (e.g. C:\windows\system32)
3714 * 4. Windows Directory (e.g. C:\windows)
3715 * 5. all directories along %PATH%
3717 static void FindWin32CACert(struct Configurable
*config
,
3718 const char *bundle_file
)
3720 /* only check for cert file if "we" support SSL */
3721 if(curlinfo
->features
& CURL_VERSION_SSL
) {
3724 char *retval
= (char *) malloc(sizeof (TCHAR
) * (MAX_PATH
+ 1));
3728 buflen
= SearchPathA(NULL
, bundle_file
, NULL
, MAX_PATH
+2, retval
, &ptr
);
3730 GetStr(&config
->cacert
, retval
);
3738 #define RETRY_SLEEP_DEFAULT 1000 /* ms */
3739 #define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */
3742 output_expected(const char* url
, const char* uploadfile
)
3745 return TRUE
; /* download */
3746 if(checkprefix("http://", url
) || checkprefix("https://", url
))
3747 return TRUE
; /* HTTP(S) upload */
3749 return FALSE
; /* non-HTTP upload, probably no output should be expected */
3752 #define my_setopt(x,y,z) _my_setopt(x, config, #y, y, z)
3754 static struct curl_slist
*easycode
;
3756 CURLcode
_my_setopt(CURL
*curl
, struct Configurable
*config
, const char *name
,
3757 CURLoption tag
, ...);
3759 CURLcode
_my_setopt(CURL
*curl
, struct Configurable
*config
, const char *name
,
3760 CURLoption tag
, ...)
3770 if(tag
< CURLOPTTYPE_OBJECTPOINT
) {
3771 long lval
= va_arg(arg
, long);
3772 snprintf(value
, sizeof(value
), "%ld", lval
);
3773 ret
= curl_easy_setopt(curl
, tag
, lval
);
3776 else if(tag
< CURLOPTTYPE_OFF_T
) {
3777 void *pval
= va_arg(arg
, void *);
3778 unsigned char *ptr
= (unsigned char *)pval
;
3780 /* function pointers are never printable */
3781 if (tag
>= CURLOPTTYPE_FUNCTIONPOINT
) {
3783 snprintf(value
, sizeof(value
), "%p", pval
);
3787 strcpy(value
, "NULL");
3789 /* attempt to figure out if it is a string (since the tag numerical doesn't
3790 offer this info) and then output it as a string if so */
3791 else if(pval
&& ISGRAPH(ptr
[0]) && ISGRAPH(ptr
[1]) && ISGRAPH(ptr
[2]))
3792 snprintf(value
, sizeof(value
), "\"%s\"", (char *)ptr
);
3794 snprintf(value
, sizeof(value
), "%p", pval
);
3798 strcpy(value
, "NULL"); /* value fits more than 5 bytes */
3800 ret
= curl_easy_setopt(curl
, tag
, pval
);
3804 curl_off_t oval
= va_arg(arg
, curl_off_t
);
3805 snprintf(value
, sizeof(value
), "(curl_off_t)%Od", oval
);
3806 ret
= curl_easy_setopt(curl
, tag
, oval
);
3809 if(config
->libcurl
) {
3810 /* we only use this for real if --libcurl was used */
3812 bufp
= curlx_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s",
3813 remark
?"/* ":"", name
, value
,
3814 remark
?" [REMARK] */":"");
3816 if (!bufp
|| !curl_slist_append(easycode
, bufp
))
3817 ret
= CURLE_OUT_OF_MEMORY
;
3826 static const char * const srchead
[]={
3827 "/********* Sample code generated by the curl command line tool **********",
3828 " * Lines with [REMARK] below might need to be modified to make this code ",
3829 " * usable. Add error code checking where appropriate.",
3830 " * Compile this with a suitable header include path. Then link with ",
3832 " * If you use any *_LARGE options, make sure your compiler figure",
3833 " * out the correct size for the curl_off_t variable.",
3834 " * Read the details for all curl_easy_setopt() options online on:",
3835 " * http://curlm.haxx.se/libcurl/c/curl_easy_setopt.html",
3836 " ************************************************************************/",
3838 "#include <curl/curl.h>",
3840 "int main(int argc, char *argv[])",
3846 static void dumpeasycode(struct Configurable
*config
)
3848 struct curl_slist
*ptr
= easycode
;
3849 char *o
= config
->libcurl
;
3853 bool fopened
= FALSE
;
3854 if(strcmp(o
, "-")) {
3855 out
= fopen(o
, "wt");
3861 warnf(config
, "Failed to open %s to write libcurl code!\n", o
);
3866 for(i
=0; (c
= srchead
[i
]); i
++) {
3867 if(!memcmp((char *)c
, "[m]", 3)) {
3868 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS > 32)
3869 fprintf(out
, "#define _FILE_OFFSET_BITS %d "
3870 "/* for curl_off_t magic */\n",
3875 fprintf(out
, "%s\n", c
);
3879 fprintf(out
, " %s\n", ptr
->data
);
3883 " return (int)ret;\n"
3885 "/**** End of sample code ****/\n");
3890 curl_slist_free_all(easycode
);
3895 operate(struct Configurable
*config
, int argc
, argv_item_t argv
[])
3897 char errorbuffer
[CURL_ERROR_SIZE
];
3898 char useragent
[256]; /* buah, we don't want a larger default user agent */
3899 struct ProgressData progressbar
;
3900 struct getout
*urlnode
;
3901 struct getout
*nextnode
;
3903 struct OutStruct outs
;
3904 struct OutStruct heads
;
3905 struct InStruct input
;
3908 URLGlob
*inglob
=NULL
;
3911 char *uploadfile
=NULL
; /* a single file, never a glob */
3913 curl_off_t uploadfilesize
; /* -1 means unknown */
3914 bool stillflags
=TRUE
;
3916 bool allocuseragent
=FALSE
;
3918 char *httpgetfields
=NULL
;
3923 long retry_sleep_default
;
3928 memset(&heads
, 0, sizeof(struct OutStruct
));
3931 /* this sends all memory debug messages to a logfile named memdump */
3932 env
= curlx_getenv("CURL_MEMDEBUG");
3934 /* use the value as file name */
3935 char *s
= strdup(env
);
3939 /* this weird strdup() and stuff here is to make the curl_free() get
3940 called before the memdebug() as otherwise the memdebug tracing will
3941 with tracing a free() without an alloc! */
3943 env
= curlx_getenv("CURL_MEMLIMIT");
3945 curl_memlimit(atoi(env
));
3951 * Get a curl handle to use for all forthcoming curl transfers. Cleanup
3952 * when all transfers are done.
3954 curl
= curl_easy_init();
3956 clean_getout(config
);
3957 return CURLE_FAILED_INIT
;
3959 config
->easy
= curl
;
3961 memset(&outs
,0,sizeof(outs
));
3963 config
->outs
= &outs
;
3965 /* we get libcurl info right away */
3966 curlinfo
= curl_version_info(CURLVERSION_NOW
);
3968 errorbuffer
[0]=0; /* prevent junk from being output */
3970 /* setup proper locale from environment */
3971 #ifdef HAVE_SETLOCALE
3972 setlocale(LC_ALL
, "");
3976 if (main_init() != CURLE_OK
) {
3977 helpf(config
->errors
, "error initializing curl library\n");
3978 return CURLE_FAILED_INIT
;
3980 config
->postfieldsize
= -1;
3981 config
->showerror
=TRUE
;
3982 config
->use_httpget
=FALSE
;
3983 config
->create_dirs
=FALSE
;
3984 config
->lastrecvtime
= cutil_tvnow();
3985 config
->lastsendtime
= cutil_tvnow();
3986 config
->maxredirs
= DEFAULT_MAXREDIRS
;
3989 (!curlx_strnequal("--", argv
[1], 2) && (argv
[1][0] == '-')) &&
3990 strchr(argv
[1], 'q')) {
3992 * The first flag, that is not a verbose name, but a shortname
3993 * and it includes the 'q' flag!
3998 parseconfig(NULL
, config
); /* ignore possible failure */
4001 if ((argc
< 2) && !config
->url_list
) {
4002 helpf(config
->errors
, NULL
);
4003 return CURLE_FAILED_INIT
;
4007 for (i
= 1; i
< argc
; i
++) {
4009 ('-' == argv
[i
][0])) {
4012 char *origopt
=argv
[i
];
4014 char *flag
= argv
[i
];
4016 if(curlx_strequal("--", argv
[i
]))
4017 /* this indicates the end of the flags and thus enables the
4018 following (URL) argument to start with -. */
4021 nextarg
= (i
< argc
- 1)? argv
[i
+1]: NULL
;
4023 res
= getparameter(flag
, nextarg
, &passarg
, config
);
4025 int retval
= CURLE_OK
;
4026 if(res
!= PARAM_HELP_REQUESTED
) {
4027 const char *reason
= param2text(res
);
4028 helpf(config
->errors
, "option %s: %s\n", origopt
, reason
);
4029 retval
= CURLE_FAILED_INIT
;
4031 clean_getout(config
);
4035 if(passarg
) /* we're supposed to skip this */
4041 /* just add the URL please */
4042 res
= getparameter((char *)"--url", argv
[i
], &used
, config
);
4048 retry_sleep_default
= config
->retry_delay
?
4049 config
->retry_delay
*1000:RETRY_SLEEP_DEFAULT
; /* ms */
4050 retry_sleep
= retry_sleep_default
;
4052 if((!config
->url_list
|| !config
->url_list
->url
) && !config
->list_engines
) {
4053 clean_getout(config
);
4054 helpf(config
->errors
, "no URL specified!\n");
4055 return CURLE_FAILED_INIT
;
4057 if(NULL
== config
->useragent
) {
4058 /* set non-zero default values: */
4059 snprintf(useragent
, sizeof(useragent
),
4060 CURL_NAME
"/" CURL_VERSION
" (" OS
") " "%s", curl_version());
4061 config
->useragent
= useragent
;
4064 allocuseragent
= TRUE
;
4066 /* On WIN32 we can't set the path to curl-ca-bundle.crt
4067 * at compile time. So we look here for the file in two ways:
4068 * 1: look at the environment variable CURL_CA_BUNDLE for a path
4069 * 2: if #1 isn't found, use the windows API function SearchPath()
4070 * to find it along the app's path (includes app's dir and CWD)
4072 * We support the environment variable thing for non-Windows platforms
4073 * too. Just for the sake of it.
4075 if (!config
->cacert
&&
4077 !config
->insecure_ok
) {
4078 env
= curlx_getenv("CURL_CA_BUNDLE");
4080 GetStr(&config
->cacert
, env
);
4082 env
= curlx_getenv("SSL_CERT_DIR");
4084 GetStr(&config
->capath
, env
);
4086 env
= curlx_getenv("SSL_CERT_FILE");
4088 GetStr(&config
->cacert
, env
);
4096 FindWin32CACert(config
, "curl-ca-bundle.crt");
4100 if (config
->postfields
) {
4101 if (config
->use_httpget
) {
4102 /* Use the postfields data for a http get */
4103 httpgetfields
= strdup(config
->postfields
);
4104 free(config
->postfields
);
4105 config
->postfields
= NULL
;
4106 if(SetHTTPrequest(config
,
4107 (config
->no_body
?HTTPREQ_HEAD
:HTTPREQ_GET
),
4108 &config
->httpreq
)) {
4109 free(httpgetfields
);
4110 return PARAM_BAD_USE
;
4114 if(SetHTTPrequest(config
, HTTPREQ_SIMPLEPOST
, &config
->httpreq
))
4115 return PARAM_BAD_USE
;
4119 /* This is the first entry added to easycode and it initializes the slist */
4120 easycode
= curl_slist_append(easycode
, "CURL *hnd = curl_easy_init();");
4122 clean_getout(config
);
4123 res
= CURLE_OUT_OF_MEMORY
;
4127 if (config
->list_engines
) {
4128 struct curl_slist
*engines
= NULL
;
4130 curl_easy_getinfo(curl
, CURLINFO_SSL_ENGINES
, &engines
);
4131 list_engines(engines
);
4132 curl_slist_free_all(engines
);
4137 /* After this point, we should call curl_easy_cleanup() if we decide to bail
4138 * out from this function! */
4140 urlnode
= config
->url_list
;
4142 if(config
->headerfile
) {
4143 /* open file for output: */
4144 if(strcmp(config
->headerfile
,"-")) {
4145 heads
.filename
= config
->headerfile
;
4148 heads
.stream
=stdout
;
4149 heads
.config
= config
;
4152 /* loop through the list of given URLs */
4154 int up
; /* upload file counter within a single upload glob */
4157 char *infiles
; /* might be a glob pattern */
4158 char *outfiles
=NULL
;
4160 /* get the full URL (it might be NULL) */
4166 /* This node had no URL, skip it and continue to the next */
4167 if(urlnode
->outfile
)
4168 free(urlnode
->outfile
);
4170 /* move on to the next URL */
4171 nextnode
=urlnode
->next
;
4172 free(urlnode
); /* free the node */
4174 continue; /* next please */
4177 /* default output stream is stdout */
4178 outs
.stream
= stdout
;
4179 outs
.config
= config
;
4180 outs
.bytes
= 0; /* nothing written yet */
4182 /* save outfile pattern before expansion */
4183 if (urlnode
->outfile
) {
4184 outfiles
= strdup(urlnode
->outfile
);
4186 clean_getout(config
);
4191 infiles
= urlnode
->infile
;
4193 if(!config
->globoff
&& infiles
) {
4194 /* Unless explicitly shut off */
4195 res
= glob_url(&inglob
, infiles
, &infilenum
,
4196 config
->showerror
?config
->errors
:NULL
);
4197 if(res
!= CURLE_OK
) {
4198 clean_getout(config
);
4205 /* Here's the loop for uploading multiple files within the same
4206 single globbed string. If no upload, we enter the loop once anyway. */
4208 (!up
&& !infiles
) ||
4209 (uploadfile
= inglob
?
4210 glob_next_url(inglob
):
4211 (!up
?strdup(infiles
):NULL
));
4214 long retry_numretries
;
4217 if(!config
->globoff
) {
4218 /* Unless explicitly shut off, we expand '{...}' and '[...]'
4219 expressions and return total number of URLs in pattern set */
4220 res
= glob_url(&urls
, dourl
, &urlnum
,
4221 config
->showerror
?config
->errors
:NULL
);
4222 if(res
!= CURLE_OK
) {
4227 urlnum
= 1; /* without globbing, this is a single URL */
4229 /* if multiple files extracted to stdout, insert separators! */
4230 separator
= ((!outfiles
|| curlx_strequal(outfiles
, "-")) && urlnum
> 1);
4232 /* Here's looping around each globbed URL */
4234 (url
= urls
?glob_next_url(urls
):(i
?NULL
:strdup(url
)));
4236 int infd
= STDIN_FILENO
;
4239 struct timeval retrystart
;
4240 outfile
= outfiles
?strdup(outfiles
):NULL
;
4242 if((urlnode
->flags
&GETOUT_USEREMOTE
) ||
4243 (outfile
&& !curlx_strequal("-", outfile
)) ) {
4246 * We have specified a file name to store the result in, or we have
4247 * decided we want to use the remote file name.
4251 /* Find and get the remote file name */
4252 char * pc
=strstr(url
, "://");
4257 pc
= strrchr(pc
, '/');
4260 /* duplicate the string beyond the slash */
4262 outfile
= *pc
? strdup(pc
): NULL
;
4264 if(!outfile
|| !*outfile
) {
4265 helpf(config
->errors
, "Remote file name has no length!\n");
4266 res
= CURLE_WRITE_ERROR
;
4272 /* This is for DOS, and then we do some major replacing of
4273 bad characters in the file name before using it */
4274 char file1
[PATH_MAX
];
4276 strcpy(file1
, msdosify(outfile
));
4278 outfile
= strdup (rename_if_dos_device_name(file1
));
4283 /* fill '#1' ... '#9' terms from URL pattern */
4284 char *storefile
= outfile
;
4285 outfile
= glob_match_url(storefile
, urls
);
4289 warnf(config
, "bad output glob!\n");
4291 res
= CURLE_FAILED_INIT
;
4296 /* Create the directory hierarchy, if not pre-existant to a multiple
4299 if(config
->create_dirs
&&
4300 (-1 == create_dir_hierarchy(outfile
, config
->errors
)))
4301 return CURLE_WRITE_ERROR
;
4303 if(config
->resume_from_current
) {
4304 /* We're told to continue from where we are now. Get the
4305 size of the file as it is now and open it for append instead */
4307 struct_stat fileinfo
;
4309 /* VMS -- Danger, the filesize is only valid for stream files */
4310 if(0 == stat(outfile
, &fileinfo
))
4311 /* set offset to current file size: */
4312 config
->resume_from
= fileinfo
.st_size
;
4314 /* let offset be 0 */
4315 config
->resume_from
= 0;
4318 outs
.filename
= outfile
;
4320 if(config
->resume_from
) {
4321 outs
.init
= config
->resume_from
;
4322 /* open file for output: */
4323 outs
.stream
=(FILE *) fopen(outfile
, config
->resume_from
?"ab":"wb");
4325 helpf(config
->errors
, "Can't open '%s'!\n", outfile
);
4326 return CURLE_WRITE_ERROR
;
4330 outs
.stream
= NULL
; /* open when needed */
4334 if(uploadfile
&& !curlx_strequal(uploadfile
, "-")) {
4336 * We have specified a file to upload and it isn't "-".
4338 struct_stat fileinfo
;
4340 /* If no file name part is given in the URL, we add this file name */
4341 char *ptr
=strstr(url
, "://");
4346 ptr
= strrchr(ptr
, '/');
4347 if(!ptr
|| !strlen(++ptr
)) {
4348 /* The URL has no file name part, add the local file name. In order
4349 to be able to do so, we have to create a new URL in another
4352 /* We only want the part of the local path that is on the right
4353 side of the rightmost slash and backslash. */
4354 char *filep
= strrchr(uploadfile
, '/');
4355 char *file2
= strrchr(filep
?filep
:uploadfile
, '\\');
4364 /* URL encode the file name */
4365 filep
= curl_easy_escape(curl
, filep
, 0 /* use strlen */);
4368 char *urlbuffer
=(char *)malloc(strlen(url
) + strlen(filep
) + 3);
4370 helpf(config
->errors
, "out of memory\n");
4371 return CURLE_OUT_OF_MEMORY
;
4374 /* there is a trailing slash on the URL */
4375 sprintf(urlbuffer
, "%s%s", url
, filep
);
4377 /* thers is no trailing slash on the URL */
4378 sprintf(urlbuffer
, "%s/%s", url
, filep
);
4383 url
= urlbuffer
; /* use our new URL instead! */
4388 * Reading binary from files can be a problem... Only FIXED, VAR
4389 * etc WITHOUT implied CC will work Others need a \n appended to a
4392 * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
4393 * fixed file with implied CC needs to have a byte added for every
4394 * record processed, this can by derived from Filesize & recordsize
4395 * for VARiable record files the records need to be counted! for
4396 * every record add 1 for linefeed and subtract 2 for the record
4397 * header for VARIABLE header files only the bare record data needs
4398 * to be considered with one appended if implied CC
4401 infd
= open(uploadfile
, O_RDONLY
| O_BINARY
);
4402 if ((infd
== -1) || stat(uploadfile
, &fileinfo
)) {
4403 helpf(config
->errors
, "Can't open '%s'!\n", uploadfile
);
4407 /* Free the list of remaining URLs and globbed upload files
4408 * to force curl to exit immediately
4415 glob_cleanup(inglob
);
4419 res
= CURLE_READ_ERROR
;
4423 uploadfilesize
=fileinfo
.st_size
;
4426 else if(uploadfile
&& curlx_strequal(uploadfile
, "-")) {
4428 infd
= STDIN_FILENO
;
4431 if(uploadfile
&& config
->resume_from_current
)
4432 config
->resume_from
= -1; /* -1 will then force get-it-yourself */
4434 if(output_expected(url
, uploadfile
)
4435 && outs
.stream
&& isatty(fileno(outs
.stream
)))
4436 /* we send the output to a tty, therefore we switch off the progress
4438 config
->noprogress
= config
->isatty
= TRUE
;
4440 if (urlnum
> 1 && !(config
->mute
)) {
4441 fprintf(config
->errors
, "\n[%d/%d]: %s --> %s\n",
4442 i
+1, urlnum
, url
, outfile
? outfile
: "<stdout>");
4444 printf("%s%s\n", CURLseparator
, url
);
4446 if (httpgetfields
) {
4448 /* Find out whether the url contains a file name */
4449 const char *pc
=strstr(url
, "://");
4456 pc
= strrchr(pc
, '/'); /* check for a slash */
4459 /* there is a slash present in the URL */
4462 /* Ouch, there's already a question mark in the URL string, we
4463 then append the data with an ampersand separator instead! */
4467 * Then append ? followed by the get fields to the url.
4469 urlbuffer
=(char *)malloc(strlen(url
) + strlen(httpgetfields
) + 3);
4471 helpf(config
->errors
, "out of memory\n");
4472 return CURLE_OUT_OF_MEMORY
;
4475 sprintf(urlbuffer
, "%s%c%s", url
, sep
, httpgetfields
);
4477 /* Append / before the ? to create a well-formed url
4478 if the url contains a hostname only
4480 sprintf(urlbuffer
, "%s/?%s", url
, httpgetfields
);
4482 free(url
); /* free previous URL */
4483 url
= urlbuffer
; /* use our new URL instead! */
4487 config
->errors
= stderr
;
4489 if(!outfile
&& !config
->use_ascii
) {
4490 /* We get the output to stdout and we have not got the ASCII/text
4491 flag, then set stdout to be binary */
4492 SET_BINMODE(stdout
);
4495 if(1 == config
->tcp_nodelay
)
4496 my_setopt(curl
, CURLOPT_TCP_NODELAY
, 1);
4498 /* where to store */
4499 my_setopt(curl
, CURLOPT_WRITEDATA
, (FILE *)&outs
);
4500 /* what call to write */
4501 my_setopt(curl
, CURLOPT_WRITEFUNCTION
, my_fwrite
);
4505 input
.config
= config
;
4506 my_setopt(curl
, CURLOPT_READDATA
, &input
);
4507 /* what call to read */
4508 my_setopt(curl
, CURLOPT_READFUNCTION
, my_fread
);
4510 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
4511 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
4512 my_setopt(curl
, CURLOPT_SEEKDATA
, &input
);
4513 my_setopt(curl
, CURLOPT_SEEKFUNCTION
, my_seek
);
4515 if(config
->recvpersecond
)
4516 /* tell libcurl to use a smaller sized buffer as it allows us to
4517 make better sleeps! 7.9.9 stuff! */
4518 my_setopt(curl
, CURLOPT_BUFFERSIZE
, config
->recvpersecond
);
4520 /* size of uploaded file: */
4521 my_setopt(curl
, CURLOPT_INFILESIZE_LARGE
, uploadfilesize
);
4522 my_setopt(curl
, CURLOPT_URL
, url
); /* what to fetch */
4523 my_setopt(curl
, CURLOPT_PROXY
, config
->proxy
); /* proxy to use */
4524 my_setopt(curl
, CURLOPT_NOPROGRESS
, config
->noprogress
);
4525 if(config
->no_body
) {
4526 my_setopt(curl
, CURLOPT_NOBODY
, 1);
4527 my_setopt(curl
, CURLOPT_HEADER
, 1);
4530 my_setopt(curl
, CURLOPT_HEADER
, config
->include_headers
);
4532 my_setopt(curl
, CURLOPT_FAILONERROR
, config
->failonerror
);
4533 my_setopt(curl
, CURLOPT_UPLOAD
, uploadfile
?TRUE
:FALSE
);
4534 my_setopt(curl
, CURLOPT_DIRLISTONLY
, config
->dirlistonly
);
4535 my_setopt(curl
, CURLOPT_APPEND
, config
->ftp_append
);
4537 if (config
->netrc_opt
)
4538 my_setopt(curl
, CURLOPT_NETRC
, CURL_NETRC_OPTIONAL
);
4539 else if (config
->netrc
)
4540 my_setopt(curl
, CURLOPT_NETRC
, CURL_NETRC_REQUIRED
);
4542 my_setopt(curl
, CURLOPT_NETRC
, CURL_NETRC_IGNORED
);
4544 my_setopt(curl
, CURLOPT_FOLLOWLOCATION
, config
->followlocation
);
4545 my_setopt(curl
, CURLOPT_UNRESTRICTED_AUTH
, config
->unrestricted_auth
);
4546 my_setopt(curl
, CURLOPT_TRANSFERTEXT
, config
->use_ascii
);
4547 my_setopt(curl
, CURLOPT_USERPWD
, config
->userpwd
);
4548 my_setopt(curl
, CURLOPT_PROXYUSERPWD
, config
->proxyuserpwd
);
4549 my_setopt(curl
, CURLOPT_RANGE
, config
->range
);
4550 my_setopt(curl
, CURLOPT_ERRORBUFFER
, errorbuffer
);
4551 my_setopt(curl
, CURLOPT_TIMEOUT
, config
->timeout
);
4553 switch(config
->httpreq
) {
4554 case HTTPREQ_SIMPLEPOST
:
4555 my_setopt(curl
, CURLOPT_POSTFIELDS
, config
->postfields
);
4556 my_setopt(curl
, CURLOPT_POSTFIELDSIZE_LARGE
, config
->postfieldsize
);
4559 my_setopt(curl
, CURLOPT_HTTPPOST
, config
->httppost
);
4564 my_setopt(curl
, CURLOPT_REFERER
, config
->referer
);
4565 my_setopt(curl
, CURLOPT_AUTOREFERER
, config
->autoreferer
);
4566 my_setopt(curl
, CURLOPT_USERAGENT
, config
->useragent
);
4567 my_setopt(curl
, CURLOPT_FTPPORT
, config
->ftpport
);
4568 my_setopt(curl
, CURLOPT_LOW_SPEED_LIMIT
,
4569 config
->low_speed_limit
);
4570 my_setopt(curl
, CURLOPT_LOW_SPEED_TIME
, config
->low_speed_time
);
4571 my_setopt(curl
, CURLOPT_MAX_SEND_SPEED_LARGE
,
4572 config
->sendpersecond
);
4573 my_setopt(curl
, CURLOPT_MAX_RECV_SPEED_LARGE
,
4574 config
->recvpersecond
);
4575 my_setopt(curl
, CURLOPT_RESUME_FROM_LARGE
,
4576 config
->use_resume
?config
->resume_from
:0);
4577 my_setopt(curl
, CURLOPT_COOKIE
, config
->cookie
);
4578 my_setopt(curl
, CURLOPT_HTTPHEADER
, config
->headers
);
4579 my_setopt(curl
, CURLOPT_SSLCERT
, config
->cert
);
4580 my_setopt(curl
, CURLOPT_SSLCERTTYPE
, config
->cert_type
);
4581 my_setopt(curl
, CURLOPT_SSLKEY
, config
->key
);
4582 my_setopt(curl
, CURLOPT_SSLKEYTYPE
, config
->key_type
);
4583 my_setopt(curl
, CURLOPT_KEYPASSWD
, config
->key_passwd
);
4585 /* SSH private key uses the same command-line option as SSL private
4587 my_setopt(curl
, CURLOPT_SSH_PRIVATE_KEYFILE
, config
->key
);
4588 my_setopt(curl
, CURLOPT_SSH_PUBLIC_KEYFILE
, config
->pubkey
);
4590 /* SSH host key md5 checking allows us to fail if we are
4591 * not talking to who we think we should
4593 my_setopt(curl
, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
, config
->hostpubmd5
);
4596 /* default to strict verifyhost */
4597 my_setopt(curl
, CURLOPT_SSL_VERIFYHOST
, 2);
4598 if(config
->cacert
|| config
->capath
) {
4600 my_setopt(curl
, CURLOPT_CAINFO
, config
->cacert
);
4603 my_setopt(curl
, CURLOPT_CAPATH
, config
->capath
);
4604 my_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, TRUE
);
4606 if(config
->insecure_ok
) {
4607 /* new stuff needed for libcurl 7.10 */
4608 my_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, FALSE
);
4609 my_setopt(curl
, CURLOPT_SSL_VERIFYHOST
, 1);
4612 if(config
->no_body
|| config
->remote_time
) {
4613 /* no body or use remote time */
4614 my_setopt(curl
, CURLOPT_FILETIME
, TRUE
);
4617 my_setopt(curl
, CURLOPT_MAXREDIRS
, config
->maxredirs
);
4618 my_setopt(curl
, CURLOPT_CRLF
, config
->crlf
);
4619 my_setopt(curl
, CURLOPT_QUOTE
, config
->quote
);
4620 my_setopt(curl
, CURLOPT_POSTQUOTE
, config
->postquote
);
4621 my_setopt(curl
, CURLOPT_PREQUOTE
, config
->prequote
);
4622 my_setopt(curl
, CURLOPT_WRITEHEADER
,
4623 config
->headerfile
?&heads
:NULL
);
4624 my_setopt(curl
, CURLOPT_COOKIEFILE
, config
->cookiefile
);
4625 /* cookie jar was added in 7.9 */
4626 if(config
->cookiejar
)
4627 my_setopt(curl
, CURLOPT_COOKIEJAR
, config
->cookiejar
);
4628 /* cookie session added in 7.9.7 */
4629 my_setopt(curl
, CURLOPT_COOKIESESSION
, config
->cookiesession
);
4631 my_setopt(curl
, CURLOPT_SSLVERSION
, config
->ssl_version
);
4632 my_setopt(curl
, CURLOPT_TIMECONDITION
, config
->timecond
);
4633 my_setopt(curl
, CURLOPT_TIMEVALUE
, config
->condtime
);
4634 my_setopt(curl
, CURLOPT_CUSTOMREQUEST
, config
->customrequest
);
4635 my_setopt(curl
, CURLOPT_STDERR
, config
->errors
);
4637 /* three new ones in libcurl 7.3: */
4638 my_setopt(curl
, CURLOPT_HTTPPROXYTUNNEL
, config
->proxytunnel
);
4639 my_setopt(curl
, CURLOPT_INTERFACE
, config
->iface
);
4640 my_setopt(curl
, CURLOPT_KRBLEVEL
, config
->krblevel
);
4642 progressbarinit(&progressbar
, config
);
4643 if((config
->progressmode
== CURL_PROGRESS_BAR
) &&
4644 !config
->noprogress
&& !config
->mute
) {
4645 /* we want the alternative style, then we have to implement it
4647 my_setopt(curl
, CURLOPT_PROGRESSFUNCTION
, myprogress
);
4648 my_setopt(curl
, CURLOPT_PROGRESSDATA
, &progressbar
);
4651 /* new in libcurl 7.6.2: */
4652 my_setopt(curl
, CURLOPT_TELNETOPTIONS
, config
->telnet_options
);
4654 /* new in libcurl 7.7: */
4655 my_setopt(curl
, CURLOPT_RANDOM_FILE
, config
->random_file
);
4656 my_setopt(curl
, CURLOPT_EGDSOCKET
, config
->egd_file
);
4657 my_setopt(curl
, CURLOPT_CONNECTTIMEOUT
, config
->connecttimeout
);
4659 if(config
->cipher_list
)
4660 my_setopt(curl
, CURLOPT_SSL_CIPHER_LIST
, config
->cipher_list
);
4662 if(config
->httpversion
)
4663 my_setopt(curl
, CURLOPT_HTTP_VERSION
, config
->httpversion
);
4665 /* new in libcurl 7.9.2: */
4666 if(config
->disable_epsv
)
4668 my_setopt(curl
, CURLOPT_FTP_USE_EPSV
, FALSE
);
4670 /* new in libcurl 7.10.5 */
4671 if(config
->disable_eprt
)
4673 my_setopt(curl
, CURLOPT_FTP_USE_EPRT
, FALSE
);
4675 /* new in libcurl 7.10.6 (default is Basic) */
4676 if(config
->authtype
)
4677 my_setopt(curl
, CURLOPT_HTTPAUTH
, config
->authtype
);
4679 if(config
->tracetype
!= TRACE_NONE
) {
4680 my_setopt(curl
, CURLOPT_DEBUGFUNCTION
, my_trace
);
4681 my_setopt(curl
, CURLOPT_DEBUGDATA
, config
);
4682 my_setopt(curl
, CURLOPT_VERBOSE
, TRUE
);
4687 /* new in curl ?? */
4688 if (config
->engine
) {
4689 res
= my_setopt(curl
, CURLOPT_SSLENGINE
, config
->engine
);
4690 my_setopt(curl
, CURLOPT_SSLENGINE_DEFAULT
, 1);
4693 if (res
!= CURLE_OK
)
4696 /* new in curl 7.10 */
4697 my_setopt(curl
, CURLOPT_ENCODING
,
4698 (config
->encoding
) ? "" : NULL
);
4700 /* new in curl 7.10.7 */
4701 my_setopt(curl
, CURLOPT_FTP_CREATE_MISSING_DIRS
,
4702 config
->ftp_create_dirs
);
4703 if(config
->proxyanyauth
)
4704 my_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_ANY
);
4705 else if(config
->proxynegotiate
)
4706 my_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_GSSNEGOTIATE
);
4707 else if(config
->proxyntlm
)
4708 my_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_NTLM
);
4709 else if(config
->proxydigest
)
4710 my_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_DIGEST
);
4711 else if(config
->proxybasic
)
4712 my_setopt(curl
, CURLOPT_PROXYAUTH
, CURLAUTH_BASIC
);
4714 /* new in curl 7.10.8 */
4715 if(config
->max_filesize
)
4716 my_setopt(curl
, CURLOPT_MAXFILESIZE_LARGE
,
4717 config
->max_filesize
);
4719 if(4 == config
->ip_version
)
4720 my_setopt(curl
, CURLOPT_IPRESOLVE
, CURL_IPRESOLVE_V4
);
4721 else if(6 == config
->ip_version
)
4722 my_setopt(curl
, CURLOPT_IPRESOLVE
, CURL_IPRESOLVE_V6
);
4724 my_setopt(curl
, CURLOPT_IPRESOLVE
, CURL_IPRESOLVE_WHATEVER
);
4726 /* new in curl 7.15.5 */
4727 if(config
->ftp_ssl_reqd
)
4728 my_setopt(curl
, CURLOPT_USE_SSL
, CURLUSESSL_ALL
);
4730 /* new in curl 7.11.0 */
4731 else if(config
->ftp_ssl
)
4732 my_setopt(curl
, CURLOPT_USE_SSL
, CURLUSESSL_TRY
);
4734 /* new in curl 7.16.0 */
4735 else if(config
->ftp_ssl_control
)
4736 my_setopt(curl
, CURLOPT_USE_SSL
, CURLUSESSL_CONTROL
);
4738 /* new in curl 7.16.1 */
4739 if(config
->ftp_ssl_ccc
)
4740 my_setopt(curl
, CURLOPT_FTP_SSL_CCC
, config
->ftp_ssl_ccc_mode
);
4742 /* new in curl 7.11.1, modified in 7.15.2 */
4743 if(config
->socksproxy
) {
4744 my_setopt(curl
, CURLOPT_PROXY
, config
->socksproxy
);
4745 my_setopt(curl
, CURLOPT_PROXYTYPE
, config
->socksver
);
4749 my_setopt(curl
, CURLOPT_FTP_ACCOUNT
, config
->ftp_account
);
4751 my_setopt(curl
, CURLOPT_IGNORE_CONTENT_LENGTH
, config
->ignorecl
);
4754 my_setopt(curl
, CURLOPT_FTP_SKIP_PASV_IP
, config
->ftp_skip_ip
);
4757 my_setopt(curl
, CURLOPT_FTP_FILEMETHOD
, config
->ftp_filemethod
);
4760 if(config
->localport
) {
4761 my_setopt(curl
, CURLOPT_LOCALPORT
, config
->localport
);
4762 my_setopt(curl
, CURLOPT_LOCALPORTRANGE
,
4763 config
->localportrange
);
4767 my_setopt(curl
, CURLOPT_FTP_ALTERNATIVE_TO_USER
,
4768 config
->ftp_alternative_to_user
);
4771 my_setopt(curl
, CURLOPT_SSL_SESSIONID_CACHE
,
4772 !config
->disable_sessionid
);
4776 my_setopt(curl
, CURLOPT_HTTP_CONTENT_DECODING
, FALSE
);
4777 my_setopt(curl
, CURLOPT_HTTP_TRANSFER_DECODING
, FALSE
);
4781 my_setopt(curl
, CURLOPT_POST301
, config
->post301
);
4782 if (!config
->nokeepalive
) {
4783 my_setopt(curl
, CURLOPT_SOCKOPTFUNCTION
, sockoptcallback
);
4784 my_setopt(curl
, CURLOPT_SOCKOPTDATA
, config
);
4787 retry_numretries
= config
->req_retry
;
4789 retrystart
= cutil_tvnow();
4792 res
= curl_easy_perform(curl
);
4793 if (!curl_slist_append(easycode
, "ret = curl_easy_perform(hnd);")) {
4794 res
= CURLE_OUT_OF_MEMORY
;
4798 /* if retry-max-time is non-zero, make sure we haven't exceeded the
4800 if(retry_numretries
&&
4801 (!config
->retry_maxtime
||
4802 (cutil_tvdiff(cutil_tvnow(), retrystart
)<
4803 config
->retry_maxtime
*1000)) ) {
4809 RETRY_LAST
/* not used */
4812 if(CURLE_OPERATION_TIMEDOUT
== res
)
4813 /* retry timeout always */
4814 retry
= RETRY_TIMEOUT
;
4815 else if(CURLE_OK
== res
) {
4816 /* Check for HTTP transient errors */
4817 char *this_url
=NULL
;
4818 curl_easy_getinfo(curl
, CURLINFO_EFFECTIVE_URL
, &this_url
);
4820 curlx_strnequal(this_url
, "http", 4)) {
4821 /* This was HTTP(S) */
4822 curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &response
);
4825 case 500: /* Internal Server Error */
4826 case 502: /* Bad Gateway */
4827 case 503: /* Service Unavailable */
4828 case 504: /* Gateway Timeout */
4831 * At this point, we have already written data to the output
4832 * file (or terminal). If we write to a file, we must rewind
4833 * or close/re-open the file so that the next attempt starts
4834 * over from the beginning.
4836 * TODO: similar action for the upload case. We might need
4837 * to start over reading from a previous point if we have
4838 * uploaded something when this was returned.
4844 else if(CURLE_LOGIN_DENIED
== res
) {
4845 curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &response
);
4847 if(response
/100 == 5)
4849 * This is typically when the FTP server only allows a certain
4850 * amount of users and we are not one of them. It mostly
4851 * returns 530 in this case, but all 5xx codes are transient.
4857 static const char * const m
[]={NULL
,
4862 warnf(config
, "Transient problem: %s "
4863 "Will retry in %ld seconds. "
4864 "%ld retries left.\n",
4869 go_sleep(retry_sleep
);
4871 if(!config
->retry_delay
) {
4873 if(retry_sleep
> RETRY_SLEEP_MAX
)
4874 retry_sleep
= RETRY_SLEEP_MAX
;
4876 if(outs
.bytes
&& outs
.filename
) {
4877 /* We have written data to a output file, we truncate file
4880 fprintf(config
->errors
, "Throwing away %Od bytes\n",
4882 fflush(outs
.stream
);
4883 /* truncate file at the position where we started appending */
4884 #ifdef HAVE_FTRUNCATE
4885 ftruncate( fileno(outs
.stream
), outs
.init
);
4886 /* now seek to the end of the file, the position where we
4887 just truncated the file in a large file-safe way */
4888 fseek(outs
.stream
, 0, SEEK_END
);
4890 /* ftruncate is not available, so just reposition the file
4891 to the location we would have truncated it. This won't
4892 work properly with large files on 32-bit systems, but
4893 most of those will have ftruncate. */
4894 fseek(outs
.stream
, (long)outs
.init
, SEEK_SET
);
4896 outs
.bytes
= 0; /* clear for next round */
4900 } /* if retry_numretries */
4902 /* In all ordinary cases, just break out of loop here */
4903 retry_sleep
= retry_sleep_default
;
4908 if((config
->progressmode
== CURL_PROGRESS_BAR
) &&
4909 progressbar
.calls
) {
4910 /* if the custom progress bar has been displayed, we output a
4912 fputs("\n", progressbar
.out
);
4915 if(config
->writeout
) {
4916 ourWriteOut(curl
, config
->writeout
);
4918 #ifdef USE_ENVIRONMENT
4919 if (config
->writeenv
)
4926 if (!config
->showerror
) {
4927 vms_show
= VMSSTS_HIDE
;
4930 if((res
!=CURLE_OK
) && config
->showerror
) {
4931 fprintf(config
->errors
, "curl: (%d) %s\n", (int)res
,
4932 errorbuffer
[0]? errorbuffer
:
4933 curl_easy_strerror((CURLcode
)res
));
4934 if(CURLE_SSL_CACERT
== res
) {
4935 #define CURL_CA_CERT_ERRORMSG1 \
4936 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
4937 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
4938 " of Certificate Authority (CA) public keys (CA certs). The default\n" \
4939 " bundle is named curl-ca-bundle.crt; you can specify an alternate file\n" \
4940 " using the --cacert option.\n"
4942 #define CURL_CA_CERT_ERRORMSG2 \
4943 "If this HTTPS server uses a certificate signed by a CA represented in\n" \
4944 " the bundle, the certificate verification probably failed due to a\n" \
4945 " problem with the certificate (it might be expired, or the name might\n" \
4946 " not match the domain name in the URL).\n" \
4947 "If you'd like to turn off curl's verification of the certificate, use\n" \
4948 " the -k (or --insecure) option.\n"
4950 fprintf(config
->errors
, "%s%s",
4951 CURL_CA_CERT_ERRORMSG1
,
4952 CURL_CA_CERT_ERRORMSG2
);
4957 if (outfile
&& !curlx_strequal(outfile
, "-") && outs
.stream
)
4958 fclose(outs
.stream
);
4961 /* Important that we set the time _after_ the file has been
4962 closed, as is done above here */
4963 if(config
->remote_time
&& outs
.filename
) {
4964 /* ask libcurl if we got a time. Pretty please */
4966 curl_easy_getinfo(curl
, CURLINFO_FILETIME
, &filetime
);
4968 struct utimbuf times
;
4969 times
.actime
= (time_t)filetime
;
4970 times
.modtime
= (time_t)filetime
;
4971 utime(outs
.filename
, ×
); /* set the time we got */
4976 /* Set the url as comment for the file. (up to 80 chars are allowed)
4978 if( strlen(url
) > 78 )
4981 SetComment( outs
.filename
, url
);
4994 } /* loop to the next URL */
4997 /* cleanup memory used for URL globbing patterns */
5005 } /* loop to the next globbed upload file */
5008 glob_cleanup(inglob
);
5015 /* empty this urlnode struct */
5018 if(urlnode
->outfile
)
5019 free(urlnode
->outfile
);
5021 free(urlnode
->infile
);
5023 /* move on to the next URL */
5024 nextnode
=urlnode
->next
;
5025 free(urlnode
); /* free the node */
5028 } /* while-loop through all URLs */
5032 free(httpgetfields
);
5035 free(config
->engine
);
5037 /* cleanup the curl handle! */
5038 curl_easy_cleanup(curl
);
5039 config
->easy
= NULL
; /* cleanup now */
5041 curl_slist_append(easycode
, "curl_easy_cleanup(hnd);");
5043 if(heads
.stream
&& (heads
.stream
!= stdout
))
5044 fclose(heads
.stream
);
5047 free(config
->useragent
);
5049 if(config
->trace_fopened
&& config
->trace_stream
)
5050 fclose(config
->trace_stream
);
5052 if(config
->errors_fopened
)
5053 fclose(config
->errors
);
5055 main_free(); /* cleanup */
5057 dumpeasycode(config
);
5062 /* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
5063 open before starting to run. Otherwise, the first three network
5064 sockets opened by curl could be used for input sources, downloaded data
5065 or error logs as they will effectively be stdin, stdout and/or stderr.
5067 static void checkfds(void)
5070 int fd
[2] = { STDIN_FILENO
, STDIN_FILENO
};
5071 while( fd
[0] == STDIN_FILENO
||
5072 fd
[0] == STDOUT_FILENO
||
5073 fd
[0] == STDERR_FILENO
||
5074 fd
[1] == STDIN_FILENO
||
5075 fd
[1] == STDOUT_FILENO
||
5076 fd
[1] == STDERR_FILENO
)
5078 return; /* Out of handles. This isn't really a big problem now, but
5079 will be when we try to create a socket later. */
5087 int main(int argc
, char *argv
[])
5090 struct Configurable config
;
5092 memset(&config
, 0, sizeof(struct Configurable
));
5094 config
.errors
= stderr
; /* default errors to stderr */
5098 res
= operate(&config
, argc
, argv
);
5099 #ifdef __SYMBIAN32__
5100 if (config
.showerror
)
5103 free_config_fields(&config
);
5105 #ifdef __NOVELL_LIBC__
5109 if (res
> CURL_LAST
) res
= CURL_LAST
; /* If CURL_LAST exceeded then */
5110 return (vms_cond
[res
]|vms_show
); /* curlmsg.h is out of sync. */
5117 * Reads a line from the given file, ensuring is NUL terminated.
5118 * The pointer must be freed by the caller.
5119 * NULL is returned on an out of memory condition.
5121 static char *my_get_line(FILE *fp
)
5125 char *retval
= NULL
;
5128 if (NULL
== fgets(buf
, sizeof(buf
), fp
))
5131 retval
= strdup(buf
);
5133 if (NULL
== (retval
= realloc(retval
,
5134 strlen(retval
) + strlen(buf
) + 1)))
5136 strcat(retval
, buf
);
5139 while (NULL
== (nl
= strchr(retval
, '\n')));
5147 static void show_dir_errno(FILE *errors
, const char *name
)
5152 fprintf(errors
,"You don't have permission to create %s.\n", name
);
5157 fprintf(errors
,"The directory name %s is too long.\n", name
);
5162 fprintf(errors
,"%s resides on a read-only file system.\n", name
);
5167 fprintf(errors
,"No space left on the file system that will "
5168 "contain the directory %s.\n", name
);
5173 fprintf(errors
,"Cannot create directory %s because you "
5174 "exceeded your quota.\n", name
);
5178 fprintf(errors
,"Error creating directory %s.\n", name
);
5183 /* Create the needed directory hierarchy recursively in order to save
5184 multi-GETs in file output, ie:
5185 curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
5186 should create all the dir* automagically
5188 static int create_dir_hierarchy(const char *outfile
, FILE *errors
)
5196 outdup
= strdup(outfile
);
5200 dirbuildup
= malloc(sizeof(char) * strlen(outfile
));
5205 dirbuildup
[0] = '\0';
5207 tempdir
= strtok(outdup
, DIR_CHAR
);
5209 while (tempdir
!= NULL
) {
5210 tempdir2
= strtok(NULL
, DIR_CHAR
);
5211 /* since strtok returns a token for the last word even
5212 if not ending with DIR_CHAR, we need to prune it */
5213 if (tempdir2
!= NULL
) {
5214 if (strlen(dirbuildup
) > 0)
5215 sprintf(dirbuildup
,"%s%s%s",dirbuildup
, DIR_CHAR
, tempdir
);
5217 if (0 != strncmp(outdup
, DIR_CHAR
, 1))
5218 sprintf(dirbuildup
,"%s",tempdir
);
5220 sprintf(dirbuildup
,"%s%s", DIR_CHAR
, tempdir
);
5222 if (access(dirbuildup
, F_OK
) == -1) {
5223 result
= mkdir(dirbuildup
,(mode_t
)0000750);
5225 show_dir_errno(errors
, dirbuildup
);
5226 break; /* get out of loop */
5235 return result
; /* 0 is fine, -1 is badness */
5240 #ifndef HAVE_BASENAME
5241 /* basename() returns a pointer to the last component of a pathname.
5242 * Ripped from lib/formdata.c.
5244 static char *basename(char *path
)
5246 /* Ignore all the details above for now and make a quick and simple
5247 implementaion here */
5251 s1
=strrchr(path
, '/');
5252 s2
=strrchr(path
, '\\');
5255 path
= (s1
> s2
? s1
: s2
)+1;
5264 #endif /* HAVE_BASENAME */
5266 /* The following functions are taken with modification from the DJGPP
5267 * port of tar 1.12. They use algorithms originally from DJTAR. */
5270 msdosify (const char *file_name
)
5272 static char dos_name
[PATH_MAX
*2];
5273 static const char illegal_chars_dos
[] = ".+, ;=[]|<>\\\":?*";
5274 static const char *illegal_chars_w95
= &illegal_chars_dos
[8];
5276 const char *s
= file_name
;
5278 const char *illegal_aliens
= illegal_chars_dos
;
5279 size_t len
= sizeof (illegal_chars_dos
) - 1;
5283 /* Support for Windows 9X VFAT systems, when available (djgpp only). */
5284 if (_use_lfn (file_name
))
5288 illegal_aliens
= illegal_chars_w95
;
5289 len
-= (illegal_chars_w95
- illegal_chars_dos
);
5292 /* Get past the drive letter, if any. */
5293 if (s
[0] >= 'A' && s
[0] <= 'z' && s
[1] == ':') {
5298 for (idx
= 0, dot_idx
= -1; *s
; s
++, d
++) {
5299 if (memchr (illegal_aliens
, *s
, len
)) {
5300 /* Dots are special: DOS doesn't allow them as the leading character,
5301 and a file name cannot have more than a single dot. We leave the
5302 first non-leading dot alone, unless it comes too close to the
5303 beginning of the name: we want sh.lex.c to become sh_lex.c, not
5306 if (idx
== 0 && (s
[1] == '/' || (s
[1] == '.' && s
[2] == '/'))) {
5307 /* Copy "./" and "../" verbatim. */
5315 else if (dot_idx
>= 0) {
5316 if (dot_idx
< 5) { /* 5 is a heuristic ad-hoc'ery */
5317 d
[dot_idx
- idx
] = '_'; /* replace previous dot */
5329 else if (*s
== '+' && s
[1] == '+') {
5330 if (idx
- 2 == dot_idx
) { /* .c++, .h++ etc. */
5336 memcpy (d
, "plus", 4);
5360 rename_if_dos_device_name (char *file_name
)
5362 /* We could have a file whose name is a device on MS-DOS. Trying to
5363 * retrieve such a file would fail at best and wedge us at worst. We need
5364 * to rename such files. */
5367 char fname
[PATH_MAX
];
5369 strncpy(fname
, file_name
, PATH_MAX
-1);
5370 fname
[PATH_MAX
-2] = 0; /* Leave room for an extra _ */
5371 base
= basename (fname
);
5372 if (((stat(base
, &st_buf
)) == 0) && (S_ISCHR(st_buf
.st_mode
))) {
5373 size_t blen
= strlen (base
);
5375 /* Prepend a '_'. */
5376 memmove (base
+ 1, base
, blen
+ 1);
5378 strcpy (file_name
, fname
);