aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore2
-rw-r--r--src/Makefile.Watcom2
-rw-r--r--src/Makefile.am13
-rw-r--r--src/Makefile.inc83
-rw-r--r--src/Makefile.m3290
-rw-r--r--src/Makefile.netware60
-rw-r--r--src/Makefile.vc6277
-rw-r--r--src/config-amigaos.h3
-rw-r--r--src/config-mac.h1
-rw-r--r--src/config-riscos.h3
-rw-r--r--src/config-win32.h439
-rw-r--r--src/curl.rc2
-rw-r--r--src/hugehelp.c.cvs3
-rw-r--r--src/hugehelp.h4
-rw-r--r--src/main.c6207
-rw-r--r--src/mkhelp.pl21
-rw-r--r--src/setup.h70
-rw-r--r--src/tool_binmode.c52
-rw-r--r--src/tool_binmode.h37
-rw-r--r--src/tool_bname.c50
-rw-r--r--src/tool_bname.h35
-rw-r--r--src/tool_cb_dbg.c275
-rw-r--r--src/tool_cb_dbg.h35
-rw-r--r--src/tool_cb_hdr.c207
-rw-r--r--src/tool_cb_hdr.h33
-rw-r--r--src/tool_cb_prg.c146
-rw-r--r--src/tool_cb_prg.h49
-rw-r--r--src/tool_cb_rea.c61
-rw-r--r--src/tool_cb_rea.h33
-rw-r--r--src/tool_cb_see.c129
-rw-r--r--src/tool_cb_see.h45
-rw-r--r--src/tool_cb_skt.c97
-rw-r--r--src/tool_cb_skt.h35
-rw-r--r--src/tool_cb_wrt.c146
-rw-r--r--src/tool_cb_wrt.h33
-rw-r--r--src/tool_cfgable.c131
-rw-r--r--src/tool_cfgable.h204
-rw-r--r--src/tool_convert.c152
-rw-r--r--src/tool_convert.h45
-rw-r--r--src/tool_dirhie.c151
-rw-r--r--src/tool_dirhie.h29
-rw-r--r--src/tool_doswin.c300
-rw-r--r--src/tool_doswin.h45
-rw-r--r--src/tool_easysrc.c112
-rw-r--r--src/tool_easysrc.h34
-rw-r--r--src/tool_formparse.c321
-rw-r--r--src/tool_formparse.h33
-rw-r--r--src/tool_getparam.c1634
-rw-r--r--src/tool_getparam.h46
-rw-r--r--src/tool_getpass.c (renamed from src/getpass.c)111
-rw-r--r--src/tool_getpass.h (renamed from src/getpass.h)12
-rw-r--r--src/tool_help.c238
-rw-r--r--src/tool_help.h (renamed from src/writeenv.h)12
-rw-r--r--src/tool_helpers.c78
-rw-r--r--src/tool_helpers.h31
-rw-r--r--src/tool_homedir.c (renamed from src/homedir.c)22
-rw-r--r--src/tool_homedir.h (renamed from src/homedir.h)9
-rw-r--r--src/tool_libinfo.c102
-rw-r--r--src/tool_libinfo.h34
-rw-r--r--src/tool_main.c112
-rw-r--r--src/tool_main.h44
-rw-r--r--src/tool_mfiles.c129
-rw-r--r--src/tool_mfiles.h46
-rw-r--r--src/tool_msgs.c100
-rw-r--r--src/tool_msgs.h31
-rw-r--r--src/tool_operate.c1559
-rw-r--r--src/tool_operate.h29
-rw-r--r--src/tool_operhlp.c238
-rw-r--r--src/tool_operhlp.h51
-rw-r--r--src/tool_panykey.c48
-rw-r--r--src/tool_panykey.h37
-rw-r--r--src/tool_paramhlp.c387
-rw-r--r--src/tool_paramhlp.h51
-rw-r--r--src/tool_parsecfg.c308
-rw-r--r--src/tool_parsecfg.h30
-rw-r--r--src/tool_sdecls.h141
-rw-r--r--src/tool_setopt.c125
-rw-r--r--src/tool_setopt.h50
-rw-r--r--src/tool_sleep.c62
-rw-r--r--src/tool_sleep.h29
-rw-r--r--src/tool_urlglob.c (renamed from src/urlglob.c)271
-rw-r--r--src/tool_urlglob.h (renamed from src/urlglob.h)25
-rw-r--r--src/tool_util.c (renamed from src/curlutil.c)23
-rw-r--r--src/tool_util.h (renamed from src/curlutil.h)29
-rw-r--r--src/tool_version.h (renamed from src/version.h)9
-rw-r--r--src/tool_vms.c (renamed from src/os-specific.c)22
-rw-r--r--src/tool_vms.h (renamed from src/os-specific.h)10
-rw-r--r--src/tool_writeenv.c (renamed from src/writeenv.c)14
-rw-r--r--src/tool_writeenv.h35
-rw-r--r--src/tool_writeout.c (renamed from src/writeout.c)35
-rw-r--r--src/tool_writeout.h (renamed from src/writeout.h)9
-rw-r--r--src/tool_xattr.c (renamed from src/xattr.c)25
-rw-r--r--src/tool_xattr.h (renamed from src/xattr.h)10
-rw-r--r--src/vc6curlsrc.dsp286
94 files changed, 9991 insertions, 7083 deletions
diff --git a/src/.gitignore b/src/.gitignore
index 17de5c6a7..d99cc3f7c 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -6,4 +6,6 @@ stamp-h2
Makefile.vc8.dist
Makefile.vc9.dist
version.h.dist
+tool_version.h.dist
Makefile.vc10.dist
+config-win32.h
diff --git a/src/Makefile.Watcom b/src/Makefile.Watcom
index 66c97ef45..f0477fd46 100644
--- a/src/Makefile.Watcom
+++ b/src/Makefile.Watcom
@@ -78,7 +78,7 @@ ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.5
!ifdef %libssh2_root
LIBSSH2_ROOT = $(%libssh2_root)
!else
-LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.2.8
+LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.3.0
!endif
!ifdef %librtmp_root
diff --git a/src/Makefile.am b/src/Makefile.am
index d697e78ea..a181f06bc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -51,8 +51,8 @@ CFLAGS += @CURL_CFLAG_EXTRAS@
curl_LDADD = $(top_builddir)/lib/libcurl.la @CURL_LIBS@
curl_DEPENDENCIES = $(top_builddir)/lib/libcurl.la
-BUILT_SOURCES = hugehelp.c
-CLEANFILES = hugehelp.c
+BUILT_SOURCES = hugehelp.c config-win32.h
+CLEANFILES = hugehelp.c config-win32.h
# Use the C locale to ensure that only ASCII characters appear in the
# embedded text.
NROFF=env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script
@@ -68,6 +68,11 @@ MANPAGE=$(top_srcdir)/docs/curl.1
README=$(top_srcdir)/docs/MANUAL
MKHELP=$(top_srcdir)/src/mkhelp.pl
HUGE=hugehelp.c
+CFGWIN32=config-win32.h
+
+$(CFGWIN32): $(top_srcdir)/lib/config-win32.h
+ echo "creating $(CFGWIN32)"
+ @(cp $(top_srcdir)/lib/config-win32.h $(CFGWIN32))
if USE_MANUAL
# Here are the stuff to create a built-in manual
@@ -97,9 +102,9 @@ $(HUGE):
endif
# ignore hugehelp.c since it is generated source code and it plays by slightly
-# different rules!
+# different rules! config-win32.h already checked in lib subdir.
checksrc:
- @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/src -Whugehelp.c $(curl_SOURCES)
+ @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/src -Whugehelp.c -Wconfig-win32.h $(curl_SOURCES)
if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
diff --git a/src/Makefile.inc b/src/Makefile.inc
index 058c6d28d..1660bc403 100644
--- a/src/Makefile.inc
+++ b/src/Makefile.inc
@@ -14,13 +14,86 @@ CURLX_ONES = $(top_srcdir)/lib/strtoofft.c \
$(top_srcdir)/lib/rawstr.c \
$(top_srcdir)/lib/nonblock.c
-CURL_CFILES = main.c hugehelp.c urlglob.c writeout.c writeenv.c \
- getpass.c homedir.c curlutil.c os-specific.c xattr.c
+CURL_CFILES = hugehelp.c \
+ tool_binmode.c \
+ tool_bname.c \
+ tool_cb_dbg.c \
+ tool_cb_hdr.c \
+ tool_cb_prg.c \
+ tool_cb_rea.c \
+ tool_cb_see.c \
+ tool_cb_skt.c \
+ tool_cb_wrt.c \
+ tool_cfgable.c \
+ tool_convert.c \
+ tool_dirhie.c \
+ tool_doswin.c \
+ tool_easysrc.c \
+ tool_formparse.c \
+ tool_getparam.c \
+ tool_getpass.c \
+ tool_help.c \
+ tool_helpers.c \
+ tool_homedir.c \
+ tool_libinfo.c \
+ tool_main.c \
+ tool_mfiles.c \
+ tool_msgs.c \
+ tool_operate.c \
+ tool_operhlp.c \
+ tool_panykey.c \
+ tool_paramhlp.c \
+ tool_parsecfg.c \
+ tool_setopt.c \
+ tool_sleep.c \
+ tool_urlglob.c \
+ tool_util.c \
+ tool_vms.c \
+ tool_writeenv.c \
+ tool_writeout.c \
+ tool_xattr.c
CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \
- config-riscos.h urlglob.h version.h os-specific.h \
- writeout.h writeenv.h getpass.h homedir.h curlutil.h \
- xattr.h
+ config-riscos.h \
+ tool_binmode.h \
+ tool_bname.h \
+ tool_cb_dbg.h \
+ tool_cb_hdr.h \
+ tool_cb_prg.h \
+ tool_cb_rea.h \
+ tool_cb_see.h \
+ tool_cb_skt.h \
+ tool_cb_wrt.h \
+ tool_cfgable.h \
+ tool_convert.h \
+ tool_dirhie.h \
+ tool_doswin.h \
+ tool_easysrc.h \
+ tool_formparse.h \
+ tool_getparam.h \
+ tool_getpass.h \
+ tool_help.h \
+ tool_helpers.h \
+ tool_homedir.h \
+ tool_libinfo.h \
+ tool_main.h \
+ tool_mfiles.h \
+ tool_msgs.h \
+ tool_operate.h \
+ tool_operhlp.h \
+ tool_panykey.h \
+ tool_paramhlp.h \
+ tool_parsecfg.h \
+ tool_sdecls.h \
+ tool_setopt.h \
+ tool_sleep.h \
+ tool_urlglob.h \
+ tool_util.h \
+ tool_version.h \
+ tool_vms.h \
+ tool_writeenv.h \
+ tool_writeout.h \
+ tool_xattr.h
curl_SOURCES = $(CURL_CFILES) $(CURLX_ONES) $(CURL_HFILES)
diff --git a/src/Makefile.m32 b/src/Makefile.m32
index 3cafae7bb..0822e3a8e 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -1,7 +1,7 @@
-#########################################################################
+###########################################################################
#
-## Makefile for building curl.exe with MingW32 (GCC-3.2 or later)
-## and optionally OpenSSL (0.9.8), libssh2 (1.2), zlib (1.2.5), librtmp (2.3)
+## Makefile for building curl.exe with MingW (GCC-3.2 or later)
+## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3)
##
## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...]
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn
@@ -9,10 +9,8 @@
## Hint: you can also set environment vars to control the build, f.e.:
## set ZLIB_PATH=c:/zlib-1.2.5
## set ZLIB=1
-##
-## Comments to: Troy Engel <tengel@sonic.net> or
-## Joern Hartroth <hartroth@acm.org>
-#########################################################################
+#
+###########################################################################
# Edit the path below to point to the base of your Zlib sources.
ifndef ZLIB_PATH
@@ -22,9 +20,15 @@ endif
ifndef OPENSSL_PATH
OPENSSL_PATH = ../../openssl-0.9.8r
endif
+ifndef OPENSSL_LIBPATH
+OPENSSL_LIBPATH = $(OPENSSL_PATH)/out
+endif
+ifndef OPENSSL_LIBS
+OPENSSL_LIBS = -leay32 -lssl32
+endif
# Edit the path below to point to the base of your LibSSH2 package.
ifndef LIBSSH2_PATH
-LIBSSH2_PATH = ../../libssh2-1.2.8
+LIBSSH2_PATH = ../../libssh2-1.3.0
endif
# Edit the path below to point to the base of your librtmp package.
ifndef LIBRTMP_PATH
@@ -45,17 +49,29 @@ ifndef LDAP_SDK
LDAP_SDK = c:/novell/ndk/cldapsdk/win32
endif
+PROOT = ..
+
# Edit the path below to point to the base of your c-ares package.
ifndef LIBCARES_PATH
-LIBCARES_PATH = ../ares
+LIBCARES_PATH = $(PROOT)/ares
+endif
+
+# Edit the var below to set to your architecture or set environment var.
+ifndef ARCH
+ARCH = w32
endif
CC = gcc
CFLAGS = -g -O2 -Wall
+CFLAGS += -fno-strict-aliasing
+ifeq ($(ARCH),w64)
+CFLAGS += -D_AMD64_
+endif
# comment LDFLAGS below to keep debug info
LDFLAGS = -s
RC = windres
-RCFLAGS = --include-dir=../include -O COFF -i
+RCFLAGS = --include-dir=$(PROOT)/include -O COFF -i
+
RM = del /q /f 2>NUL
CP = copy
@@ -97,6 +113,9 @@ endif
ifeq ($(findstring -sspi,$(CFG)),-sspi)
SSPI = 1
endif
+ifeq ($(findstring -spnego,$(CFG)),-spnego)
+SPNEGO = 1
+endif
ifeq ($(findstring -ldaps,$(CFG)),-ldaps)
LDAPS = 1
endif
@@ -105,15 +124,13 @@ IPV6 = 1
endif
INCLUDES = -I. -I.. -I../include -I../lib
-LINK = $(CC) $(LDFLAGS) -o $@
-curl_PROGRAMS = curl.exe
ifdef DYN
- curl_DEPENDENCIES = ../lib/libcurldll.a ../lib/libcurl.dll
- curl_LDADD = -L../lib -lcurldll
+ curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll
+ curl_LDADD = -L$(PROOT)/lib -lcurldll
else
- curl_DEPENDENCIES = ../lib/libcurl.a
- curl_LDADD = -L../lib -lcurl
+ curl_DEPENDENCIES = $(PROOT)/lib/libcurl.a
+ curl_LDADD = -L$(PROOT)/lib -lcurl
CFLAGS += -DCURL_STATICLIB
endif
ifdef ARES
@@ -121,7 +138,7 @@ ifdef ARES
curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a
endif
CFLAGS += -DUSE_ARES
- curl_LDADD += -L$(LIBCARES_PATH) -lcares
+ curl_LDADD += -L"$(LIBCARES_PATH)" -lcares
endif
ifdef RTMP
CFLAGS += -DUSE_LIBRTMP
@@ -129,32 +146,34 @@ ifdef RTMP
endif
ifdef SSH2
CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H
- curl_LDADD += -L$(LIBSSH2_PATH)/win32 -lssh2
+ curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
endif
ifdef SSL
CFLAGS += -DUSE_SSLEAY -DHAVE_OPENSSL_ENGINE_H
- curl_LDADD += -L$(OPENSSL_PATH)/out -leay32 -lssl32
+ curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
endif
ifdef ZLIB
INCLUDES += -I"$(ZLIB_PATH)"
CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
- curl_LDADD += -L$(ZLIB_PATH) -lz
+ curl_LDADD += -L"$(ZLIB_PATH)" -lz
endif
ifdef IDN
- INCLUDES += -I"$(LIBIDN_PATH)/include"
CFLAGS += -DUSE_LIBIDN
- curl_LDADD += -L$(LIBIDN_PATH)/lib -lidn
+ curl_LDADD += -L"$(LIBIDN_PATH)/lib" -lidn
else
ifdef WINIDN
CFLAGS += -DUSE_WIN32_IDN
- DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz
+ curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz
endif
endif
ifdef SSPI
CFLAGS += -DUSE_WINDOWS_SSPI
endif
+ifdef SPNEGO
+ CFLAGS += -DHAVE_SPNEGO
+endif
ifdef IPV6
- CFLAGS += -DENABLE_IPV6
+ CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501
endif
ifdef LDAPS
CFLAGS += -DHAVE_LDAP_SSL
@@ -173,48 +192,47 @@ curl_LDADD += -lwldap32
endif
endif
curl_LDADD += -lws2_32
-COMPILE = $(CC) $(INCLUDES) $(CFLAGS)
# Makefile.inc provides the CSOURCES and HHEADERS defines
include Makefile.inc
+curl_PROGRAMS = curl.exe
curl_OBJECTS := $(patsubst %.c,%.o,$(strip $(CURL_CFILES)))
-ifdef DYN
curlx_OBJECTS := $(patsubst %.c,%.o,$(notdir $(strip $(CURLX_ONES))))
+ifdef DYN
curl_OBJECTS += $(curlx_OBJECTS)
-vpath %.c ../lib
+vpath %.c $(PROOT)/lib
endif
RESOURCE = curl.res
-.SUFFIXES: .rc .res
-all: curl.exe
+all: $(curl_PROGRAMS)
curl.exe: $(RESOURCE) $(curl_OBJECTS) $(curl_DEPENDENCIES)
-$(RM) $@
- $(LINK) $< $(curl_OBJECTS) $(curl_LDADD)
+ $(CC) $(LDFLAGS) -o $@ $< $(curl_OBJECTS) $(curl_LDADD)
# We don't have nroff normally under win32
-# hugehelp.c: ../README.curl ../curl.1 mkhelp.pl
+# hugehelp.c: $(PROOT)/README.curl $(PROOT)/curl.1 mkhelp.pl
# -$(RM) hugehelp.c
-# $(NROFF) -man ../curl.1 | $(PERL) mkhelp.pl ../README.curl > hugehelp.c
+# $(NROFF) -man $(PROOT)/curl.1 | $(PERL) mkhelp.pl $(PROOT)/README.curl > hugehelp.c
hugehelp.c:
@echo Creating $@
@$(CP) hugehelp.c.cvs $@
-.c.o:
- $(COMPILE) -c $<
+%.o: %.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c $<
-.rc.res:
+%.res: %.rc
$(RC) $(RCFLAGS) $< -o $@
clean:
ifeq "$(wildcard hugehelp.c.cvs)" "hugehelp.c.cvs"
-$(RM) hugehelp.c
endif
- -$(RM) $(curl_OBJECTS) $(RESOURCE)
+ -$(RM) $(curl_OBJECTS) $(curlx_OBJECTS) $(RESOURCE)
distclean vclean: clean
-$(RM) $(curl_PROGRAMS)
diff --git a/src/Makefile.netware b/src/Makefile.netware
index 85e0c92ee..8e66f7919 100644
--- a/src/Makefile.netware
+++ b/src/Makefile.netware
@@ -24,7 +24,7 @@ endif
# Edit the path below to point to the base of your LibSSH2 package.
ifndef LIBSSH2_PATH
-LIBSSH2_PATH = ../../libssh2-1.2.8
+LIBSSH2_PATH = ../../libssh2-1.3.0
endif
# Edit the path below to point to the base of your axTLS package.
@@ -42,6 +42,11 @@ ifndef LIBRTMP_PATH
LIBRTMP_PATH = ../../librtmp-2.3
endif
+# Edit the path below to point to the base of your fbopenssl package.
+ifndef FBOPENSSL_PATH
+FBOPENSSL_PATH = ../../fbopenssl-0.4
+endif
+
# Edit the path below to point to the base of your c-ares package.
ifndef LIBCARES_PATH
LIBCARES_PATH = ../ares
@@ -96,7 +101,7 @@ else
endif
PERL = perl
# Here you can find a native Win32 binary of the original awk:
-# http://www.gknw.net/development/prgtools/awk-20070501.zip
+# http://www.gknw.net/development/prgtools/awk-20100523.zip
AWK = awk
CP = cp -afv
MKDIR = mkdir
@@ -176,6 +181,43 @@ CURL_LIB = ../lib
INCLUDES = -I$(CURL_INC) -I$(CURL_LIB)
+ifeq ($(findstring -static,$(CFG)),-static)
+LINK_STATIC = 1
+endif
+ifeq ($(findstring -ares,$(CFG)),-ares)
+WITH_ARES = 1
+endif
+ifeq ($(findstring -rtmp,$(CFG)),-rtmp)
+WITH_RTMP = 1
+WITH_SSL = 1
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -ssh2,$(CFG)),-ssh2)
+WITH_SSH2 = 1
+WITH_SSL = 1
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -axtls,$(CFG)),-axtls)
+WITH_AXTLS = 1
+WITH_SSL =
+else
+ifeq ($(findstring -ssl,$(CFG)),-ssl)
+WITH_SSL = 1
+endif
+endif
+ifeq ($(findstring -zlib,$(CFG)),-zlib)
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -idn,$(CFG)),-idn)
+WITH_IDN = 1
+endif
+ifeq ($(findstring -spnego,$(CFG)),-spnego)
+WITH_SPNEGO = 1
+endif
+ifeq ($(findstring -ipv6,$(CFG)),-ipv6)
+ENABLE_IPV6 = 1
+endif
+
ifdef LINK_STATIC
LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT)
ifdef WITH_ARES
@@ -186,7 +228,7 @@ else
IMPORTS = @$(CURL_LIB)/libcurl.imp
endif
ifdef WITH_SSH2
- INCLUDES += -I$(LIBSSH2_PATH)/include
+ # INCLUDES += -I$(LIBSSH2_PATH)/include
ifdef LINK_STATIC
LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT)
else
@@ -201,13 +243,17 @@ ifdef LINK_STATIC
endif
endif
ifdef WITH_SSL
- INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
+ # INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT)
LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT)
IMPORTS += GetProcessSwitchCount RunningProcess
+ifdef WITH_SPNEGO
+ # INCLUDES += -I$(FBOPENSSL_PATH)/include
+ LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT)
+endif
else
ifdef WITH_AXTLS
- INCLUDES += -I$(AXTLS_PATH)/inc
+ # INCLUDES += -I$(AXTLS_PATH)/inc
ifdef LINK_STATIC
LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT)
else
@@ -491,6 +537,7 @@ endif
@echo $(DL)#define USE_MANUAL 1$(DL) >> $@
@echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@
@echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
+ @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@
@echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@
@echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@
@echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@
@@ -576,6 +623,9 @@ ifdef WITH_SSL
@echo $(DL)#define HAVE_LIBSSL 1$(DL) >> $@
@echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@
@echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@
+ifdef WITH_SPNEGO
+ @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@
+endif
else
ifdef WITH_AXTLS
@echo $(DL)#define USE_AXTLS 1$(DL) >> $@
diff --git a/src/Makefile.vc6 b/src/Makefile.vc6
index a25680be2..dbd32f175 100644
--- a/src/Makefile.vc6
+++ b/src/Makefile.vc6
@@ -20,6 +20,11 @@
#
#***************************************************************************
+# All files in the Makefile.vc* series are generated automatically from the
+# one made for MSVC version 6. Alas, if you want to do changes to any of the
+# fiels and send back to the project, edit the version six, make your diff and
+# mail curl-users.
+
#############################################################
#
## Makefile for building curl.exe with MSVC6
@@ -37,7 +42,7 @@ PROGRAM_NAME = curl.exe
# Verify that current subdir is curl's 'src'
# -------------------------------------------
-!IF ! EXIST(.\main.c)
+!IF ! EXIST(.\tool_main.c)
! MESSAGE Can not process this makefile from outside of curl's 'src' subdirectory.
! MESSAGE Change to curl's 'src' subdirectory, and try again.
! ERROR See previous message.
@@ -128,33 +133,91 @@ CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include
!ENDIF
RELEASE_OBJS= \
- curlutilr.obj \
- getpassr.obj \
- homedirr.obj \
hugehelpr.obj \
- mainr.obj \
nonblockr.obj \
- os-specificr.obj \
rawstrr.obj \
strtoofftr.obj \
- urlglobr.obj \
- writeoutr.obj \
- xattrr.obj \
+ tool_binmoder.obj \
+ tool_bnamer.obj \
+ tool_cb_dbgr.obj \
+ tool_cb_hdrr.obj \
+ tool_cb_prgr.obj \
+ tool_cb_rear.obj \
+ tool_cb_seer.obj \
+ tool_cb_sktr.obj \
+ tool_cb_wrtr.obj \
+ tool_cfgabler.obj \
+ tool_convertr.obj \
+ tool_dirhier.obj \
+ tool_doswinr.obj \
+ tool_easysrcr.obj \
+ tool_formparser.obj \
+ tool_getparamr.obj \
+ tool_getpassr.obj \
+ tool_helpr.obj \
+ tool_helpersr.obj \
+ tool_homedirr.obj \
+ tool_libinfor.obj \
+ tool_mainr.obj \
+ tool_mfilesr.obj \
+ tool_msgsr.obj \
+ tool_operater.obj \
+ tool_operhlpr.obj \
+ tool_panykeyr.obj \
+ tool_paramhlpr.obj \
+ tool_parsecfgr.obj \
+ tool_setoptr.obj \
+ tool_sleepr.obj \
+ tool_urlglobr.obj \
+ tool_utilr.obj \
+ tool_vmsr.obj \
+ tool_writeenvr.obj \
+ tool_writeoutr.obj \
+ tool_xattrr.obj \
curlr.res
DEBUG_OBJS= \
- curlutild.obj \
- getpassd.obj \
- homedird.obj \
hugehelpd.obj \
- maind.obj \
nonblockd.obj \
- os-specificd.obj \
rawstrd.obj \
strtoofftd.obj \
- urlglobd.obj \
- writeoutd.obj \
- xattrd.obj \
+ tool_binmoded.obj \
+ tool_bnamed.obj \
+ tool_cb_dbgd.obj \
+ tool_cb_hdrd.obj \
+ tool_cb_prgd.obj \
+ tool_cb_read.obj \
+ tool_cb_seed.obj \
+ tool_cb_sktd.obj \
+ tool_cb_wrtd.obj \
+ tool_cfgabled.obj \
+ tool_convertd.obj \
+ tool_dirhied.obj \
+ tool_doswind.obj \
+ tool_easysrcd.obj \
+ tool_formparsed.obj \
+ tool_getparamd.obj \
+ tool_getpassd.obj \
+ tool_helpd.obj \
+ tool_helpersd.obj \
+ tool_homedird.obj \
+ tool_libinfod.obj \
+ tool_maind.obj \
+ tool_mfilesd.obj \
+ tool_msgsd.obj \
+ tool_operated.obj \
+ tool_operhlpd.obj \
+ tool_panykeyd.obj \
+ tool_paramhlpd.obj \
+ tool_parsecfgd.obj \
+ tool_setoptd.obj \
+ tool_sleepd.obj \
+ tool_urlglobd.obj \
+ tool_utild.obj \
+ tool_vmsd.obj \
+ tool_writeenvd.obj \
+ tool_writeoutd.obj \
+ tool_xattrd.obj \
curld.res
#################################################
@@ -279,56 +342,172 @@ debug: $(DEBUG_OBJS)
## Release
hugehelpr.obj: hugehelp.c
$(CCR) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
-writeoutr.obj: writeout.c
- $(CCR) $(CFLAGS) /Fo"$@" writeout.c
-urlglobr.obj: urlglob.c
- $(CCR) $(CFLAGS) /Fo"$@" urlglob.c
-getpassr.obj: getpass.c
- $(CCR) $(CFLAGS) /Fo"$@" getpass.c
-homedirr.obj: homedir.c
- $(CCR) $(CFLAGS) /Fo"$@" homedir.c
-curlutilr.obj: curlutil.c
- $(CCR) $(CFLAGS) /Fo"$@" curlutil.c
-os-specificr.obj: os-specific.c
- $(CCR) $(CFLAGS) /Fo"$@" os-specific.c
nonblockr.obj: ../lib/nonblock.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
rawstrr.obj: ../lib/rawstr.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
strtoofftr.obj: ../lib/strtoofft.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
-xattrr.obj: xattr.c
- $(CCR) $(CFLAGS) /Fo"$@" xattr.c
-mainr.obj: main.c
- $(CCR) $(CFLAGS) /Fo"$@" main.c
+tool_binmoder.obj: tool_binmode.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamer.obj: tool_bname.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgr.obj: tool_cb_dbg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrr.obj: tool_cb_hdr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgr.obj: tool_cb_prg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_rear.obj: tool_cb_rea.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seer.obj: tool_cb_see.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_sktr.obj: tool_cb_skt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_skt.c
+tool_cb_wrtr.obj: tool_cb_wrt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabler.obj: tool_cfgable.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertr.obj: tool_convert.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhier.obj: tool_dirhie.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswinr.obj: tool_doswin.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcr.obj: tool_easysrc.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparser.obj: tool_formparse.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamr.obj: tool_getparam.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassr.obj: tool_getpass.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpr.obj: tool_help.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersr.obj: tool_helpers.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedirr.obj: tool_homedir.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfor.obj: tool_libinfo.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_mainr.obj: tool_main.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_main.c
+tool_mfilesr.obj: tool_mfiles.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsr.obj: tool_msgs.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operater.obj: tool_operate.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpr.obj: tool_operhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyr.obj: tool_panykey.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpr.obj: tool_paramhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgr.obj: tool_parsecfg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptr.obj: tool_setopt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepr.obj: tool_sleep.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobr.obj: tool_urlglob.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utilr.obj: tool_util.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsr.obj: tool_vms.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvr.obj: tool_writeenv.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutr.obj: tool_writeout.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrr.obj: tool_xattr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_xattr.c
curlr.res : curl.rc
$(RCR) $(RESFLAGS) /Fo"$@" curl.rc
## Debug
hugehelpd.obj: hugehelp.c
$(CCD) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
-writeoutd.obj: writeout.c
- $(CCD) $(CFLAGS) /Fo"$@" writeout.c
-urlglobd.obj: urlglob.c
- $(CCD) $(CFLAGS) /Fo"$@" urlglob.c
-getpassd.obj: getpass.c
- $(CCD) $(CFLAGS) /Fo"$@" getpass.c
-homedird.obj: homedir.c
- $(CCD) $(CFLAGS) /Fo"$@" homedir.c
-curlutild.obj: curlutil.c
- $(CCD) $(CFLAGS) /Fo"$@" curlutil.c
-os-specificd.obj: os-specific.c
- $(CCD) $(CFLAGS) /Fo"$@" os-specific.c
nonblockd.obj: ../lib/nonblock.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
rawstrd.obj: ../lib/rawstr.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
strtoofftd.obj: ../lib/strtoofft.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
-xattrd.obj: xattr.c
- $(CCD) $(CFLAGS) /Fo"$@" xattr.c
-maind.obj: main.c
- $(CCD) $(CFLAGS) /Fo"$@" main.c
+tool_binmoded.obj: tool_binmode.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamed.obj: tool_bname.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgd.obj: tool_cb_dbg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrd.obj: tool_cb_hdr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgd.obj: tool_cb_prg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_read.obj: tool_cb_rea.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seed.obj: tool_cb_see.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_sktd.obj: tool_cb_skt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_skt.c
+tool_cb_wrtd.obj: tool_cb_wrt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabled.obj: tool_cfgable.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertd.obj: tool_convert.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhied.obj: tool_dirhie.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswind.obj: tool_doswin.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcd.obj: tool_easysrc.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparsed.obj: tool_formparse.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamd.obj: tool_getparam.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassd.obj: tool_getpass.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpd.obj: tool_help.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersd.obj: tool_helpers.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedird.obj: tool_homedir.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfod.obj: tool_libinfo.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_maind.obj: tool_main.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_main.c
+tool_mfilesd.obj: tool_mfiles.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsd.obj: tool_msgs.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operated.obj: tool_operate.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpd.obj: tool_operhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyd.obj: tool_panykey.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpd.obj: tool_paramhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgd.obj: tool_parsecfg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptd.obj: tool_setopt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepd.obj: tool_sleep.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobd.obj: tool_urlglob.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utild.obj: tool_util.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsd.obj: tool_vms.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvd.obj: tool_writeenv.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutd.obj: tool_writeout.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrd.obj: tool_xattr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_xattr.c
curld.res : curl.rc
$(RCD) $(RESFLAGS) /Fo"$@" curl.rc
diff --git a/src/config-amigaos.h b/src/config-amigaos.h
index fba875dab..7f8e0a869 100644
--- a/src/config-amigaos.h
+++ b/src/config-amigaos.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -30,6 +30,7 @@
#define OS "AmigaOS"
#define HAVE_CLOSESOCKET_CAMEL 1
+#define HAVE_ERRNO_H 1
#define HAVE_UNISTD_H 1
#define HAVE_STRDUP 1
#define HAVE_UTIME 1
diff --git a/src/config-mac.h b/src/config-mac.h
index f8aeb7a66..19c24c760 100644
--- a/src/config-mac.h
+++ b/src/config-mac.h
@@ -32,6 +32,7 @@
#define USE_MANUAL 1
#define HAVE_UNISTD_H 1
+#define HAVE_ERRNO_H 1
#define HAVE_FCNTL_H 1
#define HAVE_UTIME_H 1
#define HAVE_SYS_UTIME_H 1
diff --git a/src/config-riscos.h b/src/config-riscos.h
index 7816bab13..c9aa7bcc0 100644
--- a/src/config-riscos.h
+++ b/src/config-riscos.h
@@ -91,6 +91,9 @@
/* Define if you have the <des.h> header file. */
#undef HAVE_DES_H
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H
+
/* Define if you have the <err.h> header file. */
#undef HAVE_ERR_H
diff --git a/src/config-win32.h b/src/config-win32.h
deleted file mode 100644
index 38a329826..000000000
--- a/src/config-win32.h
+++ /dev/null
@@ -1,439 +0,0 @@
-#ifndef __SRC_CONFIG_WIN32_H
-#define __SRC_CONFIG_WIN32_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/* ================================================================ */
-/* src/config-win32.h - Hand crafted config file for windows */
-/* ================================================================ */
-
-/* ---------------------------------------------------------------- */
-/* HEADER FILES */
-/* ---------------------------------------------------------------- */
-
-/* Define if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define if you have the <io.h> header file. */
-#define HAVE_IO_H 1
-
-/* Define if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define if you have the <locale.h> header file. */
-#define HAVE_LOCALE_H 1
-
-/* Define if you need the malloc.h header file even with stdlib.h */
-#if !defined(__SALFORDC__) && !defined(__POCC__)
-#define NEED_MALLOC_H 1
-#endif
-
-/* Define if you have the <signal.h> header file. */
-#define HAVE_SIGNAL_H 1
-
-/* Define if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define if you have the <sys/time.h> header file */
-/* #define HAVE_SYS_TIME_H 1 */
-
-/* Define if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define if you have the <sys/utime.h> header file. */
-#ifndef __BORLANDC__
-#define HAVE_SYS_UTIME_H 1
-#endif
-
-/* Define if you have the <time.h> header file. */
-#define HAVE_TIME_H 1
-
-/* Define if you have the <unistd.h> header file. */
-#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \
- defined(__POCC__)
-#define HAVE_UNISTD_H 1
-#endif
-
-/* Define if you have the <windows.h> header file. */
-#define HAVE_WINDOWS_H 1
-
-/* Define if you have the <winsock.h> header file. */
-#define HAVE_WINSOCK_H 1
-
-/* Define if you have the <winsock2.h> header file. */
-#ifndef __SALFORDC__
-#define HAVE_WINSOCK2_H 1
-#endif
-
-/* Define if you have the <ws2tcpip.h> header file. */
-#ifndef __SALFORDC__
-#define HAVE_WS2TCPIP_H 1
-#endif
-
-/* ---------------------------------------------------------------- */
-/* OTHER HEADER INFO */
-/* ---------------------------------------------------------------- */
-
-/* Define if sig_atomic_t is an available typedef. */
-#define HAVE_SIG_ATOMIC_T 1
-
-/* Define if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define if you can safely include both <sys/time.h> and <time.h>. */
-/* #define TIME_WITH_SYS_TIME 1 */
-
-/* ---------------------------------------------------------------- */
-/* FUNCTIONS */
-/* ---------------------------------------------------------------- */
-
-/* Define if you have the ftruncate function. */
-#define HAVE_FTRUNCATE 1
-
-/* Define if you have the ioctlsocket function. */
-#define HAVE_IOCTLSOCKET 1
-
-/* Define if you have a working ioctlsocket FIONBIO function. */
-#define HAVE_IOCTLSOCKET_FIONBIO 1
-
-/* Define if you have the setlocale function. */
-#define HAVE_SETLOCALE 1
-
-/* Define if you have the setmode function. */
-#define HAVE_SETMODE 1
-
-/* Define if you have the strcasecmp function. */
-/* #define HAVE_STRCASECMP 1 */
-
-/* Define if you have the strdup function. */
-#define HAVE_STRDUP 1
-
-/* Define if you have the stricmp function. */
-#define HAVE_STRICMP 1
-
-/* Define if you have the strncasecmp function. */
-/* #define HAVE_STRNCASECMP 1 */
-
-/* Define if you have the strnicmp function. */
-#define HAVE_STRNICMP 1
-
-/* Define if you have the utime function */
-#ifndef __BORLANDC__
-#define HAVE_UTIME 1
-#endif
-
-/* Define if you have the recv function. */
-#define HAVE_RECV 1
-
-/* Define to the type of arg 1 for recv. */
-#define RECV_TYPE_ARG1 SOCKET
-
-/* Define to the type of arg 2 for recv. */
-#define RECV_TYPE_ARG2 char *
-
-/* Define to the type of arg 3 for recv. */
-#define RECV_TYPE_ARG3 int
-
-/* Define to the type of arg 4 for recv. */
-#define RECV_TYPE_ARG4 int
-
-/* Define to the function return type for recv. */
-#define RECV_TYPE_RETV int
-
-/* Define if you have the recvfrom function. */
-#define HAVE_RECVFROM 1
-
-/* Define to the type of arg 1 for recvfrom. */
-#define RECVFROM_TYPE_ARG1 SOCKET
-
-/* Define to the type pointed by arg 2 for recvfrom. */
-#define RECVFROM_TYPE_ARG2 char
-
-/* Define to the type of arg 3 for recvfrom. */
-#define RECVFROM_TYPE_ARG3 int
-
-/* Define to the type of arg 4 for recvfrom. */
-#define RECVFROM_TYPE_ARG4 int
-
-/* Define to the type pointed by arg 5 for recvfrom. */
-#define RECVFROM_TYPE_ARG5 struct sockaddr
-
-/* Define to the type pointed by arg 6 for recvfrom. */
-#define RECVFROM_TYPE_ARG6 int
-
-/* Define to the function return type for recvfrom. */
-#define RECVFROM_TYPE_RETV int
-
-/* Define if you have the send function. */
-#define HAVE_SEND 1
-
-/* Define to the type of arg 1 for send. */
-#define SEND_TYPE_ARG1 SOCKET
-
-/* Define to the type qualifier of arg 2 for send. */
-#define SEND_QUAL_ARG2 const
-
-/* Define to the type of arg 2 for send. */
-#define SEND_TYPE_ARG2 char *
-
-/* Define to the type of arg 3 for send. */
-#define SEND_TYPE_ARG3 int
-
-/* Define to the type of arg 4 for send. */
-#define SEND_TYPE_ARG4 int
-
-/* Define to the function return type for send. */
-#define SEND_TYPE_RETV int
-
-/* ---------------------------------------------------------------- */
-/* TYPEDEF REPLACEMENTS */
-/* ---------------------------------------------------------------- */
-
-/* Define this if in_addr_t is not an available 'typedefed' type */
-#define in_addr_t unsigned long
-
-/* Define as the return type of signal handlers (int or void). */
-#define RETSIGTYPE void
-
-/* Define ssize_t if it is not an available 'typedefed' type */
-#ifndef _SSIZE_T_DEFINED
-# if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \
- defined(__POCC__) || \
- defined(__MINGW32__)
-# elif defined(_WIN64)
-# define _SSIZE_T_DEFINED
-# define ssize_t __int64
-# else
-# define _SSIZE_T_DEFINED
-# define ssize_t int
-# endif
-#endif
-
-/* ---------------------------------------------------------------- */
-/* TYPE SIZES */
-/* ---------------------------------------------------------------- */
-
-/* The size of `int', as computed by sizeof. */
-#define SIZEOF_INT 4
-
-/* The size of `long double', as computed by sizeof. */
-#define SIZEOF_LONG_DOUBLE 16
-
-/* The size of `long long', as computed by sizeof. */
-/* #define SIZEOF_LONG_LONG 8 */
-
-/* The size of `short', as computed by sizeof. */
-#define SIZEOF_SHORT 2
-
-/* ---------------------------------------------------------------- */
-/* STRUCT RELATED */
-/* ---------------------------------------------------------------- */
-
-/* Define this if you have struct sockaddr_storage */
-#if !defined(__SALFORDC__) && !defined(__BORLANDC__)
-#define HAVE_STRUCT_SOCKADDR_STORAGE 1
-#endif
-
-/* Define this if you have struct timeval */
-#define HAVE_STRUCT_TIMEVAL 1
-
-/* Define this if struct sockaddr_in6 has the sin6_scope_id member */
-#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
-
-/* ---------------------------------------------------------------- */
-/* Watt-32 tcp/ip SPECIFIC */
-/* ---------------------------------------------------------------- */
-
-#ifdef USE_WATT32
- #include <tcp.h>
- #undef byte
- #undef word
- #undef USE_WINSOCK
- #undef HAVE_WINSOCK_H
- #undef HAVE_WINSOCK2_H
- #undef HAVE_WS2TCPIP_H
- #define HAVE_GETADDRINFO
- #define HAVE_GETNAMEINFO
- #define HAVE_SYS_IOCTL_H
- #define HAVE_SYS_SOCKET_H
- #define HAVE_NETINET_IN_H
- #define HAVE_NETDB_H
- #define HAVE_ARPA_INET_H
- #define HAVE_FREEADDRINFO
- #define SOCKET int
-#endif
-
-
-/* ---------------------------------------------------------------- */
-/* COMPILER SPECIFIC */
-/* ---------------------------------------------------------------- */
-
-/* Undef keyword 'const' if it does not work. */
-/* #undef const */
-
-/* Windows should not have HAVE_GMTIME_R defined */
-/* #undef HAVE_GMTIME_R */
-
-/* Define if the compiler supports C99 variadic macro style. */
-#if defined(_MSC_VER) && (_MSC_VER >= 1400)
-#define HAVE_VARIADIC_MACROS_C99 1
-#endif
-
-/* Define if the compiler supports the 'long long' data type. */
-#if defined(__MINGW32__) || defined(__WATCOMC__)
-#define HAVE_LONGLONG 1
-#endif
-
-/* Define to avoid VS2005 complaining about portable C functions */
-#if defined(_MSC_VER) && (_MSC_VER >= 1400)
-#define _CRT_SECURE_NO_DEPRECATE 1
-#define _CRT_NONSTDC_NO_DEPRECATE 1
-#endif
-
-/* VS2005 and later dafault size for time_t is 64-bit, unless */
-/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
-#if defined(_MSC_VER) && (_MSC_VER >= 1400)
-# ifndef _USE_32BIT_TIME_T
-# define SIZEOF_TIME_T 8
-# else
-# define SIZEOF_TIME_T 4
-# endif
-#endif
-
-/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows
- 2000 as a supported build target. VS2008 default installations provide an
- embedded Windows SDK v6.0A along with the claim that Windows 2000 is a
- valid build target for VS2008. Popular belief is that binaries built using
- Windows SDK versions 6.X and Windows 2000 as a build target are
- functional */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-# define VS2008_MINIMUM_TARGET 0x0500
-#endif
-
-/* When no build target is specified VS2008 default build target is Windows
- Vista, which leaves out even Winsows XP. If no build target has been given
- for VS2008 we will target the minimum Officially supported build target,
- which happens to be Windows XP. */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-# define VS2008_DEFAULT_TARGET 0x0501
-#endif
-
-/* VS2008 default target settings and minimum build target check */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT VS2008_DEFAULT_TARGET
-# endif
-# ifndef WINVER
-# define WINVER VS2008_DEFAULT_TARGET
-# endif
-# if (_WIN32_WINNT < VS2008_MINIMUM_TARGET) || \
- (WINVER < VS2008_MINIMUM_TARGET)
-# error VS2008 does not support Windows build targets prior to Windows 2000
-# endif
-#endif
-
-/* When no build target is specified Pelles C 5.00 and later default build
- target is Windows Vista. We override default target to be Windows 2000. */
-#if defined(__POCC__) && (__POCC__ >= 500)
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0500
-# endif
-# ifndef WINVER
-# define WINVER 0x0500
-# endif
-#endif
-
-/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is
- quite convoluted, compiler dependent and even build target dependent. */
-#if defined(HAVE_WS2TCPIP_H)
-# if defined(__POCC__)
-# define HAVE_FREEADDRINFO 1
-# define HAVE_GETADDRINFO 1
-# define HAVE_GETADDRINFO_THREADSAFE 1
-# define HAVE_GETNAMEINFO 1
-# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
-# define HAVE_FREEADDRINFO 1
-# define HAVE_GETADDRINFO 1
-# define HAVE_GETADDRINFO_THREADSAFE 1
-# define HAVE_GETNAMEINFO 1
-# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
-# define HAVE_FREEADDRINFO 1
-# define HAVE_GETADDRINFO 1
-# define HAVE_GETADDRINFO_THREADSAFE 1
-# define HAVE_GETNAMEINFO 1
-# endif
-#endif
-
-#if defined(__POCC__)
-# ifndef _MSC_VER
-# error Microsoft extensions /Ze compiler option is required
-# endif
-# ifndef __POCC__OLDNAMES
-# error Compatibility names /Go compiler option is required
-# endif
-#endif
-
-/* ---------------------------------------------------------------- */
-/* LARGE FILE SUPPORT */
-/* ---------------------------------------------------------------- */
-
-#if defined(_MSC_VER) && !defined(_WIN32_WCE)
-# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
-# define USE_WIN32_LARGE_FILES
-# else
-# define USE_WIN32_SMALL_FILES
-# endif
-#endif
-
-#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
-# define USE_WIN32_LARGE_FILES
-#endif
-
-#if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES)
-# define USE_WIN32_LARGE_FILES
-#endif
-
-#if defined(__POCC__)
-# undef USE_WIN32_LARGE_FILES
-#endif
-
-#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
-# define USE_WIN32_SMALL_FILES
-#endif
-
-/* ---------------------------------------------------------------- */
-/* ADDITIONAL DEFINITIONS */
-/* ---------------------------------------------------------------- */
-
-/* Define cpu-machine-OS */
-#ifndef OS
-#define OS "i386-pc-win32"
-#endif
-
-/* Define to 1 if you want the built-in manual */
-#define USE_MANUAL 1
-
-#if defined(__POCC__)
-# define ENABLE_IPV6 1
-#endif
-
-#endif /* __SRC_CONFIG_WIN32_H */
diff --git a/src/curl.rc b/src/curl.rc
index 58e439d3b..3db59bd3c 100644
--- a/src/curl.rc
+++ b/src/curl.rc
@@ -20,7 +20,7 @@
*
***************************************************************************/
#include <winver.h>
-#include "version.h"
+#include "tool_version.h"
LANGUAGE 0x09,0x01
diff --git a/src/hugehelp.c.cvs b/src/hugehelp.c.cvs
index ac9f0ff87..1eb2fa537 100644
--- a/src/hugehelp.c.cvs
+++ b/src/hugehelp.c.cvs
@@ -1,4 +1,5 @@
-#include <stdio.h>
+#include "setup.h"
+#include "hugehelp.h"
void hugehelp(void)
{
puts ( "This is a silly replacement for the actual file.");
diff --git a/src/hugehelp.h b/src/hugehelp.h
index b84be17f5..842836dda 100644
--- a/src/hugehelp.h
+++ b/src/hugehelp.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,6 +21,8 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
+
void hugehelp(void);
#endif /* HEADER_CURL_HUGEHELP_H */
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 463996444..000000000
--- a/src/main.c
+++ /dev/null
@@ -1,6207 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "setup.h"
-
-#include <curl/curl.h>
-
-/*
-** system headers
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <errno.h>
-
-#if defined(MSDOS) || defined(WIN32)
-# if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
-# include <libgen.h>
-# endif
-#endif
-
-#ifdef NETWARE
-# ifdef __NOVELL_LIBC__
-# include <screen.h>
-# else
-# include <nwconio.h>
-# define mkdir mkdir_510
-# endif
-#endif
-
-#ifdef HAVE_IO_H
-# include <io.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-
-#ifdef HAVE_UTIME_H
-# include <utime.h>
-#elif defined(HAVE_SYS_UTIME_H)
-# include <sys/utime.h>
-#endif
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#elif defined(HAVE_POLL_H)
-# include <poll.h>
-#endif
-
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#ifdef HAVE_NETINET_TCP_H
-# include <netinet/tcp.h>
-#endif
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
-# include <iconv.h>
-/* set default codesets for iconv */
-# ifndef CURL_ICONV_CODESET_OF_NETWORK
-# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
-# endif
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-
-#ifdef MSDOS
-# include <dos.h>
-#endif
-
-#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#ifdef WIN32
-# include <direct.h>
-#endif
-
-/*
-** src subdirectory headers
-*/
-
-#include "urlglob.h"
-#include "writeout.h"
-#include "getpass.h"
-#include "homedir.h"
-#include "curlutil.h"
-#include "os-specific.h"
-#include "version.h"
-#include "xattr.h"
-#ifdef USE_MANUAL
-# include "hugehelp.h"
-#endif
-#ifdef USE_ENVIRONMENT
-# include "writeenv.h"
-#endif
-
-/*
-** libcurl subdirectory headers
-*/
-
-#include "rawstr.h"
-
-#define ENABLE_CURLX_PRINTF
-/* make the curlx header define all printf() functions to use the curlx_*
- versions instead */
-#include "curlx.h"
-
-/* The last #include file should be: */
-#ifdef CURLDEBUG
-#ifndef CURLTOOLDEBUG
-#define MEMDEBUG_NODEFINES
-#endif
-/* This is low-level hard-hacking memory leak tracking and similar. Using
- the library level code from this client-side is ugly, but we do this
- anyway for convenience. */
-#include "memdebug.h"
-#endif
-
-#ifdef __VMS
-static int vms_show = 0;
-#endif
-
-#if defined(NETWARE)
-#define PRINT_LINES_PAUSE 23
-#endif
-
-#if defined(__SYMBIAN32__)
-#define PRINT_LINES_PAUSE 16
-#define pressanykey() getchar()
-#endif
-
-#define DEFAULT_MAXREDIRS 50L
-
-#if defined(O_BINARY) && defined(HAVE_SETMODE)
-#ifdef __HIGHC__
-#define SET_BINMODE(file) _setmode(file,O_BINARY)
-#else
-#define SET_BINMODE(file) setmode(fileno(file),O_BINARY)
-#endif
-#else
-#define SET_BINMODE(file) ((void)0)
-#endif
-
-#ifndef O_BINARY
-/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
- source code but yet it doesn't ruin anything */
-#define O_BINARY 0
-#endif
-
-#if defined(MSDOS) || defined(WIN32)
-
-static const char *msdosify(const char *);
-static char *rename_if_dos_device_name(char *);
-static char *sanitize_dos_name(char *);
-
-#ifndef S_ISCHR
-# ifdef S_IFCHR
-# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-# else
-# define S_ISCHR(m) (0) /* cannot tell if file is a device */
-# endif
-#endif
-
-#ifdef WIN32
-# define _use_lfn(f) (1) /* long file names always available */
-#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
-# define _use_lfn(f) (0) /* long file names never available */
-#endif
-
-#endif /* MSDOS || WIN32 */
-
-#ifdef MSDOS
-#define USE_WATT32
-#ifdef DJGPP
-/* we want to glob our own argv[] */
-char **__crt0_glob_function (char *arg)
-{
- (void)arg;
- return (char**)0;
-}
-#endif /* __DJGPP__ */
-#endif /* MSDOS */
-
-#ifndef STDIN_FILENO
-#define STDIN_FILENO fileno(stdin)
-#endif
-
-#ifndef STDOUT_FILENO
-#define STDOUT_FILENO fileno(stdout)
-#endif
-
-#ifndef STDERR_FILENO
-#define STDERR_FILENO fileno(stderr)
-#endif
-
-#define CURLseparator "--_curl_--"
-
-#define CURL_PROGRESS_STATS 0 /* default progress display */
-#define CURL_PROGRESS_BAR 1
-
-typedef enum {
- HTTPREQ_UNSPEC,
- HTTPREQ_GET,
- HTTPREQ_HEAD,
- HTTPREQ_POST,
- HTTPREQ_SIMPLEPOST,
- HTTPREQ_CUSTOM,
- HTTPREQ_LAST
-} HttpReq;
-
-/*
- * Large file support (>2Gb) using WIN32 functions.
- */
-
-#ifdef USE_WIN32_LARGE_FILES
-# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
-# define fstat(fdes,stp) _fstati64(fdes, stp)
-# define stat(fname,stp) _stati64(fname, stp)
-# define struct_stat struct _stati64
-# define LSEEK_ERROR (__int64)-1
-#endif
-
-/*
- * Small file support (<2Gb) using WIN32 functions.
- */
-
-#ifdef USE_WIN32_SMALL_FILES
-# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
-# define fstat(fdes,stp) _fstat(fdes, stp)
-# define stat(fname,stp) _stat(fname, stp)
-# define struct_stat struct _stat
-# define LSEEK_ERROR (long)-1
-#endif
-
-#ifndef struct_stat
-# define struct_stat struct stat
-#endif
-
-#ifndef LSEEK_ERROR
-# define LSEEK_ERROR (off_t)-1
-#endif
-
-#ifdef WIN32
-# define mkdir(x,y) (mkdir)(x)
-# undef PATH_MAX
-# define PATH_MAX MAX_PATH
-# ifndef __POCC__
-# define F_OK 0
-# endif
-#endif
-
-/*
- * Default sizeof(off_t) in case it hasn't been defined in config file.
- */
-
-#ifndef SIZEOF_OFF_T
-# if defined(__VMS) && !defined(__VAX)
-# if defined(_LARGEFILE)
-# define SIZEOF_OFF_T 8
-# endif
-# elif defined(__OS400__) && defined(__ILEC400__)
-# if defined(_LARGE_FILES)
-# define SIZEOF_OFF_T 8
-# endif
-# elif defined(__MVS__) && defined(__IBMC__)
-# if defined(_LP64) || defined(_LARGE_FILES)
-# define SIZEOF_OFF_T 8
-# endif
-# elif defined(__370__) && defined(__IBMC__)
-# if defined(_LP64) || defined(_LARGE_FILES)
-# define SIZEOF_OFF_T 8
-# endif
-# elif defined(TPF)
-# define SIZEOF_OFF_T 8
-# endif
-# ifndef SIZEOF_OFF_T
-# define SIZEOF_OFF_T 4
-# endif
-#endif
-
-#define CURL_CA_CERT_ERRORMSG1 \
- "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
- "curl performs SSL certificate verification by default, " \
- "using a \"bundle\"\n" \
- " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
- " bundle file isn't adequate, you can specify an alternate file\n" \
- " using the --cacert option.\n"
-
-#define CURL_CA_CERT_ERRORMSG2 \
- "If this HTTPS server uses a certificate signed by a CA represented in\n" \
- " the bundle, the certificate verification probably failed due to a\n" \
- " problem with the certificate (it might be expired, or the name might\n" \
- " not match the domain name in the URL).\n" \
- "If you'd like to turn off curl's verification of the certificate, use\n" \
- " the -k (or --insecure) option.\n"
-
-#ifdef CURL_DOES_CONVERSIONS
-#ifdef HAVE_ICONV
-iconv_t inbound_cd = (iconv_t)-1;
-iconv_t outbound_cd = (iconv_t)-1;
-
-/*
- * convert_to_network() is an internal function to convert
- * from the host encoding to ASCII on non-ASCII platforms.
- */
-static CURLcode
-convert_to_network(char *buffer, size_t length)
-{
- CURLcode rc;
-
- /* translate from the host encoding to the network encoding */
- char *input_ptr, *output_ptr;
- size_t in_bytes, out_bytes;
-
- /* open an iconv conversion descriptor if necessary */
- if(outbound_cd == (iconv_t)-1) {
- outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
- CURL_ICONV_CODESET_OF_HOST);
- if(outbound_cd == (iconv_t)-1) {
- return CURLE_CONV_FAILED;
- }
- }
- /* call iconv */
- input_ptr = output_ptr = buffer;
- in_bytes = out_bytes = length;
- rc = iconv(outbound_cd, &input_ptr, &in_bytes,
- &output_ptr, &out_bytes);
- if((rc == -1) || (in_bytes != 0)) {
- return CURLE_CONV_FAILED;
- }
-
- return CURLE_OK;
-}
-
-/*
- * convert_from_network() is an internal function
- * for performing ASCII conversions on non-ASCII platforms.
- */
-static CURLcode
-convert_from_network(char *buffer, size_t length)
-{
- CURLcode rc;
-
- /* translate from the network encoding to the host encoding */
- char *input_ptr, *output_ptr;
- size_t in_bytes, out_bytes;
-
- /* open an iconv conversion descriptor if necessary */
- if(inbound_cd == (iconv_t)-1) {
- inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_OF_NETWORK);
- if(inbound_cd == (iconv_t)-1) {
- return CURLE_CONV_FAILED;
- }
- }
- /* call iconv */
- input_ptr = output_ptr = buffer;
- in_bytes = out_bytes = length;
- rc = iconv(inbound_cd, &input_ptr, &in_bytes,
- &output_ptr, &out_bytes);
- if((rc == -1) || (in_bytes != 0)) {
- return CURLE_CONV_FAILED;
- }
-
- return CURLE_OK;
-}
-#endif /* HAVE_ICONV */
-
-static
-char convert_char(curl_infotype infotype, char this_char)
-{
-/* determine how this specific character should be displayed */
- switch(infotype) {
- case CURLINFO_DATA_IN:
- case CURLINFO_DATA_OUT:
- case CURLINFO_SSL_DATA_IN:
- case CURLINFO_SSL_DATA_OUT:
- /* data, treat as ASCII */
- if((this_char >= 0x20) && (this_char < 0x7f)) {
- /* printable ASCII hex value: convert to host encoding */
- convert_from_network(&this_char, 1);
- }
- else {
- /* non-printable ASCII, use a replacement character */
- return UNPRINTABLE_CHAR;
- }
- /* fall through to default */
- default:
- /* treat as host encoding */
- if(ISPRINT(this_char)
- && (this_char != '\t')
- && (this_char != '\r')
- && (this_char != '\n')) {
- /* printable characters excluding tabs and line end characters */
- return this_char;
- }
- break;
- }
- /* non-printable, use a replacement character */
- return UNPRINTABLE_CHAR;
-}
-#endif /* CURL_DOES_CONVERSIONS */
-
-#ifdef WIN32
-
-#ifdef __BORLANDC__
-/* 64-bit lseek-like function unavailable */
-# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
-#endif
-
-#ifdef __POCC__
-# if(__POCC__ < 450)
-/* 64-bit lseek-like function unavailable */
-# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
-# else
-# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
-# endif
-#endif
-
-#ifndef HAVE_FTRUNCATE
-#define HAVE_FTRUNCATE 1
-#endif
-
-/*
- * Truncate a file handle at a 64-bit position 'where'.
- */
-
-static int ftruncate64(int fd, curl_off_t where)
-{
- if(_lseeki64(fd, where, SEEK_SET) < 0)
- return -1;
-
- if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
- return -1;
-
- return 0;
-}
-#define ftruncate(fd,where) ftruncate64(fd,where)
-
-#endif /* WIN32 */
-
-typedef enum {
- TRACE_NONE, /* no trace/verbose output at all! */
- TRACE_BIN, /* tcpdump inspired look */
- TRACE_ASCII, /* like *BIN but without the hex output */
- TRACE_PLAIN /* -v/--verbose type */
-} trace;
-
-struct OutStruct {
- char *filename;
- FILE *stream;
- struct Configurable *config;
- curl_off_t bytes; /* amount written so far */
- curl_off_t init; /* original size (non-zero when appending) */
-};
-
-struct Configurable {
- CURL *easy; /* once we have one, we keep it here */
- bool remote_time;
- char *random_file;
- char *egd_file;
- char *useragent;
- char *cookie; /* single line with specified cookies */
- char *cookiejar; /* write to this file */
- char *cookiefile; /* read from this file */
- bool cookiesession; /* new session? */
- bool encoding; /* Accept-Encoding please */
- bool tr_encoding; /* Transfer-Encoding please */
- long authtype; /* auth bitmask */
- bool use_resume;
- bool resume_from_current;
- bool disable_epsv;
- bool disable_eprt;
- bool ftp_pret;
- long proto;
- bool proto_present;
- long proto_redir;
- bool proto_redir_present;
- curl_off_t resume_from;
- char *postfields;
- curl_off_t postfieldsize;
- char *referer;
- long timeout;
- long connecttimeout;
- long maxredirs;
- curl_off_t max_filesize;
- char *headerfile;
- char *ftpport;
- char *iface;
- int localport;
- int localportrange;
- unsigned short porttouse;
- char *range;
- long low_speed_limit;
- long low_speed_time;
- bool showerror;
- char *userpwd;
- char *tls_username;
- char *tls_password;
- char *tls_authtype;
- char *proxyuserpwd;
- char *proxy;
- int proxyver; /* set to CURLPROXY_HTTP* define */
- char *noproxy;
- char *mail_from;
- struct curl_slist *mail_rcpt;
- bool proxytunnel;
- bool ftp_append; /* APPE on ftp */
- bool mute; /* shutup */
- bool use_ascii; /* select ascii or text transfer */
- bool autoreferer; /* automatically set referer */
- bool failonerror; /* fail on (HTTP) errors */
- bool include_headers; /* send headers to data output */
- bool no_body; /* don't get the body */
- bool dirlistonly; /* only get the FTP dir list */
- bool followlocation; /* follow http redirects */
- bool unrestricted_auth; /* Continue to send authentication (user+password)
- when following ocations, even when hostname
- changed */
- bool netrc_opt;
- bool netrc;
- char *netrc_file;
- bool noprogress;
- bool isatty; /* updated internally only if the output is a tty */
- struct getout *url_list; /* point to the first node */
- struct getout *url_last; /* point to the last/current node */
- struct getout *url_get; /* point to the node to fill in URL */
- struct getout *url_out; /* point to the node to fill in outfile */
- char *cipher_list;
- char *cert;
- char *cert_type;
- char *cacert;
- char *capath;
- char *crlfile;
- char *key;
- char *key_type;
- char *key_passwd;
- char *pubkey;
- char *hostpubmd5;
- char *engine;
- bool list_engines;
- bool crlf;
- char *customrequest;
- char *krblevel;
- char *trace_dump; /* file to dump the network trace to, or NULL */
- FILE *trace_stream;
- bool trace_fopened;
- trace tracetype;
- bool tracetime; /* include timestamp? */
- long httpversion;
- int progressmode;
- bool nobuffer;
- bool readbusy; /* set when reading input returns EAGAIN */
- bool globoff;
- bool use_httpget;
- bool insecure_ok; /* set TRUE to allow insecure SSL connects */
- bool create_dirs;
- bool ftp_create_dirs;
- bool ftp_skip_ip;
- bool proxynegotiate;
- bool proxyntlm;
- bool proxydigest;
- bool proxybasic;
- bool proxyanyauth;
- char *writeout; /* %-styled format string to output */
- bool writeenv; /* write results to environment, if available */
- FILE *errors; /* if stderr redirect is requested */
- bool errors_fopened;
- struct curl_slist *quote;
- struct curl_slist *postquote;
- struct curl_slist *prequote;
- long ssl_version;
- long ip_version;
- curl_TimeCond timecond;
- time_t condtime;
- struct curl_slist *headers;
- struct curl_httppost *httppost;
- struct curl_httppost *last_post;
- struct curl_slist *telnet_options;
- struct curl_slist *resolve;
- HttpReq httpreq;
-
- /* for bandwidth limiting features: */
- curl_off_t sendpersecond; /* send to peer */
- curl_off_t recvpersecond; /* receive from peer */
-
- bool ftp_ssl;
- bool ftp_ssl_reqd;
- bool ftp_ssl_control;
- bool ftp_ssl_ccc;
- int ftp_ssl_ccc_mode;
-
- char *socksproxy; /* set to server string */
- int socksver; /* set to CURLPROXY_SOCKS* define */
- char *socks5_gssapi_service; /* set service name for gssapi principal
- * default rcmd */
- int socks5_gssapi_nec ; /* The NEC reference server does not protect
- * the encryption type exchange */
-
- bool tcp_nodelay;
- long req_retry; /* number of retries */
- long retry_delay; /* delay between retries (in seconds) */
- long retry_maxtime; /* maximum time to keep retrying */
-
- char *ftp_account; /* for ACCT */
- char *ftp_alternative_to_user; /* send command if USER/PASS fails */
- int ftp_filemethod;
- long tftp_blksize; /* TFTP BLKSIZE option */
- bool ignorecl; /* --ignore-content-length */
- bool disable_sessionid;
-
- char *libcurl; /* output libcurl code to this file name */
- bool raw;
- bool post301;
- bool post302;
- bool nokeepalive; /* for keepalive needs */
- long alivetime;
- bool content_disposition; /* use Content-disposition filename */
-
- int default_node_flags; /* default flags to search for each 'node', which is
- basically each given URL to transfer */
- struct OutStruct *outs;
- bool xattr; /* store metadata in extended attributes */
-};
-
-#define WARN_PREFIX "Warning: "
-#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
-/* produce this text message to the user unless mute was selected */
-static void warnf(struct Configurable *config, const char *fmt, ...)
-{
- if(!config->mute) {
- va_list ap;
- int len;
- char *ptr;
- char print_buffer[256];
-
- va_start(ap, fmt);
- len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
- va_end(ap);
-
- ptr = print_buffer;
- while(len > 0) {
- fputs(WARN_PREFIX, config->errors);
-
- if(len > (int)WARN_TEXTWIDTH) {
- int cut = WARN_TEXTWIDTH-1;
-
- while(!ISSPACE(ptr[cut]) && cut) {
- cut--;
- }
- if(0 == cut)
- /* not a single cutting position was found, just cut it at the
- max text width then! */
- cut = WARN_TEXTWIDTH-1;
-
- (void)fwrite(ptr, cut + 1, 1, config->errors);
- fputs("\n", config->errors);
- ptr += cut+1; /* skip the space too */
- len -= cut;
- }
- else {
- fputs(ptr, config->errors);
- len = 0;
- }
- }
- }
-}
-
-/*
- * This is the main global constructor for the app. Call this before
- * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
- * used, or havoc may be the result.
- */
-static CURLcode main_init(void)
-{
-#ifdef DJGPP
- /* stop stat() wasting time */
- _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
-#endif
-
- return curl_global_init(CURL_GLOBAL_DEFAULT);
-}
-
-/*
- * This is the main global destructor for the app. Call this after
- * _all_ libcurl usage is done.
- */
-static void main_free(void)
-{
- curl_global_cleanup();
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
- /* close iconv conversion descriptor */
- if(inbound_cd != (iconv_t)-1)
- iconv_close(inbound_cd);
- if(outbound_cd != (iconv_t)-1)
- iconv_close(outbound_cd);
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-}
-
-static int SetHTTPrequest(struct Configurable *config,
- HttpReq req, HttpReq *store)
-{
- if((*store == HTTPREQ_UNSPEC) ||
- (*store == req)) {
- *store = req;
- return 0;
- }
- warnf(config, "You can only select one HTTP request!\n");
- return 1;
-}
-
-static void helpf(FILE *errors, const char *fmt, ...)
-{
- va_list ap;
- if(fmt) {
- va_start(ap, fmt);
- fputs("curl: ", errors); /* prefix it */
- vfprintf(errors, fmt, ap);
- va_end(ap);
- }
- fprintf(errors, "curl: try 'curl --help' "
-#ifdef USE_MANUAL
- "or 'curl --manual' "
-#endif
- "for more information\n");
-}
-
-/*
- * A chain of these nodes contain URL to get and where to put the URL's
- * contents.
- */
-struct getout {
- struct getout *next; /* next one */
- char *url; /* the URL we deal with */
- char *outfile; /* where to store the output */
- char *infile; /* file to upload, if GETOUT_UPLOAD is set */
- int flags; /* options */
-};
-#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
-#define GETOUT_URL (1<<1) /* set when URL is deemed done */
-#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
-#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
-#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
-
-static void help(void)
-{
- int i;
- /* A few of these source lines are >80 columns wide, but that's only because
- breaking the strings narrower makes this chunk look even worse!
-
- Starting with 7.18.0, this list of command line options is sorted based
- on the long option name. It is not done automatically, although a command
- line like the following can help out:
-
- curl --help | cut -c5- | grep "^-" | sort
- */
- static const char * const helptext[]={
- "Usage: curl [options...] <url>",
- "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
- " --anyauth Pick \"any\" authentication method (H)",
- " -a/--append Append to target file when uploading (F/SFTP)",
- " --basic Use HTTP Basic Authentication (H)",
- " --cacert <file> CA certificate to verify peer against (SSL)",
- " --capath <directory> CA directory to verify peer against (SSL)",
- " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
- " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
- " --ciphers <list> SSL ciphers to use (SSL)",
- " --compressed Request compressed response (using deflate or gzip)",
- " -K/--config <file> Specify which config file to read",
- " --connect-timeout <seconds> Maximum time allowed for connection",
- " -C/--continue-at <offset> Resumed transfer offset",
- " -b/--cookie <name=string/file> String or file to read cookies from (H)",
- " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
- " --create-dirs Create necessary local directory hierarchy",
- " --crlf Convert LF to CRLF in upload",
- " --crlfile <file> Get a CRL list in PEM format from the given file",
- " -d/--data <data> HTTP POST data (H)",
- " --data-ascii <data> HTTP POST ASCII data (H)",
- " --data-binary <data> HTTP POST binary data (H)",
- " --data-urlencode <name=data/name@filename> "
- "HTTP POST data url encoded (H)",
- " --digest Use HTTP Digest Authentication (H)",
- " --disable-eprt Inhibit using EPRT or LPRT (F)",
- " --disable-epsv Inhibit using EPSV (F)",
- " -D/--dump-header <file> Write the headers to this file",
- " --egd-file <file> EGD socket path for random data (SSL)",
- " --engine <eng> Crypto engine (SSL). \"--engine list\" for list",
-#ifdef USE_ENVIRONMENT
- " --environment Write results to environment variables (RISC OS)",
-#endif
- " -f/--fail Fail silently (no output at all) on HTTP errors (H)",
- " -F/--form <name=content> Specify HTTP multipart POST data (H)",
- " --form-string <name=string> Specify HTTP multipart POST data (H)",
- " --ftp-account <data> Account data string (F)",
- " --ftp-alternative-to-user <cmd> "
- "String to replace \"USER [name]\" (F)",
- " --ftp-create-dirs Create the remote dirs if not present (F)",
- " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
- " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
- " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
- " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
- " --ftp-pret Send PRET before PASV (for drftpd) (F)",
- " --ftp-ssl-ccc Send CCC after authenticating (F)",
- " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
- " --ftp-ssl-control Require SSL/TLS for ftp login, "
- "clear for transfer (F)",
- " -G/--get Send the -d data with a HTTP GET (H)",
- " -g/--globoff Disable URL sequences and ranges using {} and []",
- " -H/--header <line> Custom header to pass to server (H)",
- " -I/--head Show document info only",
- " -h/--help This help text",
- " --hostpubmd5 <md5> "
- "Hex encoded MD5 string of the host public key. (SSH)",
- " -0/--http1.0 Use HTTP 1.0 (H)",
- " --ignore-content-length Ignore the HTTP Content-Length header",
- " -i/--include Include protocol headers in the output (H/F)",
- " -k/--insecure Allow connections to SSL sites without certs (H)",
- " --interface <interface> Specify network interface/address to use",
- " -4/--ipv4 Resolve name to IPv4 address",
- " -6/--ipv6 Resolve name to IPv6 address",
- " -j/--junk-session-cookies Ignore session cookies read from file (H)",
- " --keepalive-time <seconds> Interval between keepalive probes",
- " --key <key> Private key file name (SSL/SSH)",
- " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
- " --krb <level> Enable Kerberos with specified security level (F)",
- " --libcurl <file> Dump libcurl equivalent code of this command line",
- " --limit-rate <rate> Limit transfer speed to this rate",
- " -J/--remote-header-name Use the header-provided filename (H)",
- " -l/--list-only List only names of an FTP directory (F)",
- " --local-port <num>[-num] Force use of these local port numbers",
- " -L/--location Follow Location: hints (H)",
- " --location-trusted Follow Location: and send auth to other hosts (H)",
- " -M/--manual Display the full manual",
- " --mail-from <from> Mail from this address",
- " --mail-rcpt <to> Mail to this receiver(s)",
- " --max-filesize <bytes> Maximum file size to download (H/F)",
- " --max-redirs <num> Maximum number of redirects allowed (H)",
- " -m/--max-time <seconds> Maximum time allowed for the transfer",
- " --negotiate Use HTTP Negotiate Authentication (H)",
- " -n/--netrc Must read .netrc for user name and password",
- " --netrc-optional Use either .netrc or URL; overrides -n",
- " --netrc-file <file> Set up the netrc filename to use",
- " -N/--no-buffer Disable buffering of the output stream",
- " --no-keepalive Disable keepalive use on the connection",
- " --no-sessionid Disable SSL session-ID reusing (SSL)",
- " --noproxy Comma-separated list of hosts which do not use proxy",
- " --ntlm Use HTTP NTLM authentication (H)",
- " -o/--output <file> Write output to <file> instead of stdout",
- " --pass <pass> Pass phrase for the private key (SSL/SSH)",
- " --post301 "
- "Do not switch to GET after following a 301 redirect (H)",
- " --post302 "
- "Do not switch to GET after following a 302 redirect (H)",
- " -#/--progress-bar Display transfer progress as a progress bar",
- " --proto <protocols> Enable/disable specified protocols",
- " --proto-redir <protocols> "
- "Enable/disable specified protocols on redirect",
- " -x/--proxy <host[:port]> Use HTTP proxy on given port",
- " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
- " --proxy-basic Use Basic authentication on the proxy (H)",
- " --proxy-digest Use Digest authentication on the proxy (H)",
- " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
- " --proxy-ntlm Use NTLM authentication on the proxy (H)",
- " -U/--proxy-user <user[:password]> Set proxy user and password",
- " --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port",
- " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
- " --pubkey <key> Public key file name (SSH)",
- " -Q/--quote <cmd> Send command(s) to server before transfer (F/SFTP)",
- " --random-file <file> File for reading random data from (SSL)",
- " -r/--range <range> Retrieve only the bytes within a range",
- " --raw Pass HTTP \"raw\", without any transfer decoding (H)",
- " -e/--referer Referer URL (H)",
- " -O/--remote-name Write output to a file named as the remote file",
- " --remote-name-all Use the remote file name for all URLs",
- " -R/--remote-time Set the remote file's time on the local output",
- " -X/--request <command> Specify request command to use",
- " --resolve <host:port:address> Force resolve of HOST:PORT to ADDRESS",
- " --retry <num> "
- "Retry request <num> times if transient problems occur",
- " --retry-delay <seconds> "
- "When retrying, wait this many seconds between each",
- " --retry-max-time <seconds> Retry only within this period",
- " -S/--show-error "
- "Show error. With -s, make curl show errors when they occur",
- " -s/--silent Silent mode. Don't output anything",
- " --socks4 <host[:port]> SOCKS4 proxy on given host + port",
- " --socks4a <host[:port]> SOCKS4a proxy on given host + port",
- " --socks5 <host[:port]> SOCKS5 proxy on given host + port",
- " --socks5-hostname <host[:port]> "
- "SOCKS5 proxy, pass host name to proxy",
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- " --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi",
- " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
-#endif
- " -Y/--speed-limit "
- "Stop transfer if below speed-limit for 'speed-time' secs",
- " -y/--speed-time "
- "Time needed to trig speed-limit abort. Defaults to 30",
- " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
- " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
- " -2/--sslv2 Use SSLv2 (SSL)",
- " -3/--sslv3 Use SSLv3 (SSL)",
- " --stderr <file> Where to redirect stderr. - means stdout",
- " --tcp-nodelay Use the TCP_NODELAY option",
- " -t/--telnet-option <OPT=val> Set telnet option",
- " --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)",
- " -z/--time-cond <time> Transfer based on a time condition",
- " -1/--tlsv1 Use TLSv1 (SSL)",
- " --trace <file> Write a debug trace to the given file",
- " --trace-ascii <file> Like --trace but without the hex output",
- " --trace-time Add time stamps to trace/verbose output",
- " --tr-encoding Request compressed transfer encoding (H)",
- " -T/--upload-file <file> Transfer <file> to remote site",
- " --url <URL> Set URL to work with",
- " -B/--use-ascii Use ASCII/text transfer",
- " -u/--user <user[:password]> Set server user and password",
- " --tlsuser <user> Set TLS username",
- " --tlspassword <string> Set TLS password",
- " --tlsauthtype <string> Set TLS authentication type (default SRP)",
- " -A/--user-agent <string> User-Agent to send to server (H)",
- " -v/--verbose Make the operation more talkative",
- " -V/--version Show version number and quit",
-
-#ifdef USE_WATT32
- " --wdebug Turn on Watt-32 debugging",
-#endif
- " -w/--write-out <format> What to output after completion",
- " --xattr Store metadata in extended file attributes",
- " -q If used as the first parameter disables .curlrc",
- NULL
- };
- for(i=0; helptext[i]; i++) {
- puts(helptext[i]);
-#ifdef PRINT_LINES_PAUSE
- if(i && ((i % PRINT_LINES_PAUSE) == 0))
- pressanykey();
-#endif
- }
-}
-
-struct LongShort {
- const char *letter;
- const char *lname;
- bool extraparam;
-};
-
-/* global variable to hold info about libcurl */
-static curl_version_info_data *curlinfo;
-
-static int parseconfig(const char *filename,
- struct Configurable *config);
-static char *my_get_line(FILE *fp);
-static int create_dir_hierarchy(const char *outfile, FILE *errors);
-
-static void GetStr(char **string,
- const char *value)
-{
- if(*string)
- free(*string);
- if(value)
- *string = strdup(value);
- else
- *string = NULL;
-}
-
-static void clean_getout(struct Configurable *config)
-{
- struct getout *node=config->url_list;
- struct getout *next;
-
- while(node) {
- next = node->next;
- if(node->url)
- free(node->url);
- if(node->outfile)
- free(node->outfile);
- if(node->infile)
- free(node->infile);
- free(node);
-
- node = next; /* GOTO next */
- }
-}
-
-static struct getout *new_getout(struct Configurable *config)
-{
- struct getout *node =malloc(sizeof(struct getout));
- struct getout *last= config->url_last;
- if(node) {
- /* clear the struct */
- memset(node, 0, sizeof(struct getout));
-
- /* append this new node last in the list */
- if(last)
- last->next = node;
- else
- config->url_list = node; /* first node */
-
- /* move the last pointer */
- config->url_last = node;
-
- node->flags = config->default_node_flags;
- }
- return node;
-}
-
-/* Structure for storing the information needed to build a multiple files
- * section
- */
-struct multi_files {
- struct curl_forms form;
- struct multi_files *next;
-};
-
-/* Add a new list entry possibly with a type_name
- */
-static struct multi_files *
-AddMultiFiles(const char *file_name,
- const char *type_name,
- const char *show_filename,
- struct multi_files **multi_start,
- struct multi_files **multi_current)
-{
- struct multi_files *multi;
- struct multi_files *multi_type = NULL;
- struct multi_files *multi_name = NULL;
- multi = malloc(sizeof(struct multi_files));
- if(multi) {
- memset(multi, 0, sizeof(struct multi_files));
- multi->form.option = CURLFORM_FILE;
- multi->form.value = file_name;
- }
- else
- return NULL;
-
- if(!*multi_start)
- *multi_start = multi;
-
- if(type_name) {
- multi_type = malloc(sizeof(struct multi_files));
- if(multi_type) {
- memset(multi_type, 0, sizeof(struct multi_files));
- multi_type->form.option = CURLFORM_CONTENTTYPE;
- multi_type->form.value = type_name;
- multi->next = multi_type;
-
- multi = multi_type;
- }
- else {
- free(multi);
- return NULL;
- }
- }
- if(show_filename) {
- multi_name = malloc(sizeof(struct multi_files));
- if(multi_name) {
- memset(multi_name, 0, sizeof(struct multi_files));
- multi_name->form.option = CURLFORM_FILENAME;
- multi_name->form.value = show_filename;
- multi->next = multi_name;
-
- multi = multi_name;
- }
- else {
- free(multi);
- return NULL;
- }
- }
-
- if(*multi_current)
- (*multi_current)->next = multi;
-
- *multi_current = multi;
-
- return *multi_current;
-}
-
-/* Free the items of the list.
- */
-static void FreeMultiInfo(struct multi_files *multi_start)
-{
- struct multi_files *multi;
- while(multi_start) {
- multi = multi_start;
- multi_start = multi_start->next;
- free(multi);
- }
-}
-
-/* Print list of OpenSSL engines supported.
- */
-static void list_engines(const struct curl_slist *engines)
-{
- puts("Build-time engines:");
- if(!engines) {
- puts(" <none>");
- return;
- }
- for(; engines; engines = engines->next)
- printf(" %s\n", engines->data);
-}
-
-/***************************************************************************
- *
- * formparse()
- *
- * Reads a 'name=value' parameter and builds the appropriate linked list.
- *
- * Specify files to upload with 'name=@filename'. Supports specified
- * given Content-Type of the files. Such as ';type=<content-type>'.
- *
- * If literal_value is set, any initial '@' or '<' in the value string
- * loses its special meaning, as does any embedded ';type='.
- *
- * You may specify more than one file for a single name (field). Specify
- * multiple files by writing it like:
- *
- * 'name=@filename,filename2,filename3'
- *
- * If you want content-types specified for each too, write them like:
- *
- * 'name=@filename;type=image/gif,filename2,filename3'
- *
- * If you want custom headers added for a single part, write them in a separate
- * file and do like this:
- *
- * 'name=foo;headers=@headerfile' or why not
- * 'name=@filemame;headers=@headerfile'
- *
- * To upload a file, but to fake the file name that will be included in the
- * formpost, do like this:
- *
- * 'name=@filename;filename=/dev/null'
- *
- * This function uses curl_formadd to fulfill it's job. Is heavily based on
- * the old curl_formparse code.
- *
- ***************************************************************************/
-
-#define FORM_FILE_SEPARATOR ','
-#define FORM_TYPE_SEPARATOR ';'
-
-static int formparse(struct Configurable *config,
- const char *input,
- struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- bool literal_value)
-{
- /* nextarg MUST be a string in the format 'name=contents' and we'll
- build a linked list with the info */
- char name[256];
- char *contents;
- char major[128];
- char minor[128];
- char *contp;
- const char *type = NULL;
- char *sep;
- char *sep2;
-
- if((1 == sscanf(input, "%255[^=]=", name)) &&
- ((contp = strchr(input, '=')) != NULL)) {
- /* the input was using the correct format */
-
- /* Allocate the contents */
- contents = strdup(contp+1);
- if(!contents) {
- fprintf(config->errors, "out of memory\n");
- return 1;
- }
- contp = contents;
-
- if('@' == contp[0] && !literal_value) {
- struct multi_files *multi_start = NULL, *multi_current = NULL;
- /* we use the @-letter to indicate file name(s) */
- contp++;
-
- multi_start = multi_current=NULL;
-
- do {
- /* since this was a file, it may have a content-type specifier
- at the end too, or a filename. Or both. */
- char *ptr;
- char *filename=NULL;
-
- sep=strchr(contp, FORM_TYPE_SEPARATOR);
- sep2=strchr(contp, FORM_FILE_SEPARATOR);
-
- /* pick the closest */
- if(sep2 && (sep2 < sep)) {
- sep = sep2;
-
- /* no type was specified! */
- }
-
- type = NULL;
-
- if(sep) {
-
- /* if we got here on a comma, don't do much */
- if(FORM_FILE_SEPARATOR == *sep)
- ptr = NULL;
- else
- ptr = sep+1;
-
- *sep=0; /* terminate file name at separator */
-
- while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
-
- /* pass all white spaces */
- while(ISSPACE(*ptr))
- ptr++;
-
- if(checkprefix("type=", ptr)) {
- /* set type pointer */
- type = &ptr[5];
-
- /* verify that this is a fine type specifier */
- if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
- major, minor)) {
- warnf(config, "Illegally formatted content-type field!\n");
- free(contents);
- FreeMultiInfo(multi_start);
- return 2; /* illegal content-type syntax! */
- }
-
- /* now point beyond the content-type specifier */
- sep = (char *)type + strlen(major)+strlen(minor)+1;
-
- /* there's a semicolon following - we check if it is a filename
- specified and if not we simply assume that it is text that
- the user wants included in the type and include that too up
- to the next zero or semicolon. */
- if((*sep==';') && !checkprefix(";filename=", sep)) {
- sep2 = strchr(sep+1, ';');
- if(sep2)
- sep = sep2;
- else
- sep = sep+strlen(sep); /* point to end of string */
- }
-
- if(*sep) {
- *sep=0; /* zero terminate type string */
-
- ptr=sep+1;
- }
- else
- ptr = NULL; /* end */
- }
- else if(checkprefix("filename=", ptr)) {
- filename = &ptr[9];
- ptr=strchr(filename, FORM_TYPE_SEPARATOR);
- if(!ptr) {
- ptr=strchr(filename, FORM_FILE_SEPARATOR);
- }
- if(ptr) {
- *ptr=0; /* zero terminate */
- ptr++;
- }
- }
- else
- /* confusion, bail out of loop */
- break;
- }
- /* find the following comma */
- if(ptr)
- sep=strchr(ptr, FORM_FILE_SEPARATOR);
- else
- sep=NULL;
- }
- else {
- sep=strchr(contp, FORM_FILE_SEPARATOR);
- }
- if(sep) {
- /* the next file name starts here */
- *sep =0;
- sep++;
- }
- /* if type == NULL curl_formadd takes care of the problem */
-
- if(!AddMultiFiles(contp, type, filename, &multi_start,
- &multi_current)) {
- warnf(config, "Error building form post!\n");
- free(contents);
- FreeMultiInfo(multi_start);
- return 3;
- }
- contp = sep; /* move the contents pointer to after the separator */
-
- } while(sep && *sep); /* loop if there's another file name */
-
- /* now we add the multiple files section */
- if(multi_start) {
- struct curl_forms *forms = NULL;
- struct multi_files *ptr = multi_start;
- unsigned int i, count = 0;
- while(ptr) {
- ptr = ptr->next;
- ++count;
- }
- forms = malloc((count+1)*sizeof(struct curl_forms));
- if(!forms) {
- fprintf(config->errors, "Error building form post!\n");
- free(contents);
- FreeMultiInfo(multi_start);
- return 4;
- }
- for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) {
- forms[i].option = ptr->form.option;
- forms[i].value = ptr->form.value;
- }
- forms[count].option = CURLFORM_END;
- FreeMultiInfo(multi_start);
- if(curl_formadd(httppost, last_post,
- CURLFORM_COPYNAME, name,
- CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
- warnf(config, "curl_formadd failed!\n");
- free(forms);
- free(contents);
- return 5;
- }
- free(forms);
- }
- }
- else {
- struct curl_forms info[4];
- int i = 0;
- char *ct = literal_value? NULL: strstr(contp, ";type=");
-
- info[i].option = CURLFORM_COPYNAME;
- info[i].value = name;
- i++;
-
- if(ct) {
- info[i].option = CURLFORM_CONTENTTYPE;
- info[i].value = &ct[6];
- i++;
- ct[0]=0; /* zero terminate here */
- }
-
- if(contp[0]=='<' && !literal_value) {
- info[i].option = CURLFORM_FILECONTENT;
- info[i].value = contp+1;
- i++;
- info[i].option = CURLFORM_END;
-
- if(curl_formadd(httppost, last_post,
- CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
- warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
- contp+1);
- free(contents);
- return 6;
- }
- }
- else {
-#ifdef CURL_DOES_CONVERSIONS
- convert_to_network(contp, strlen(contp));
-#endif
- info[i].option = CURLFORM_COPYCONTENTS;
- info[i].value = contp;
- i++;
- info[i].option = CURLFORM_END;
- if(curl_formadd(httppost, last_post,
- CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
- warnf(config, "curl_formadd failed!\n");
- free(contents);
- return 7;
- }
- }
- }
-
- }
- else {
- warnf(config, "Illegally formatted input field!\n");
- return 1;
- }
- free(contents);
- return 0;
-}
-
-
-typedef enum {
- PARAM_OK,
- PARAM_OPTION_AMBIGUOUS,
- PARAM_OPTION_UNKNOWN,
- PARAM_REQUIRES_PARAMETER,
- PARAM_BAD_USE,
- PARAM_HELP_REQUESTED,
- PARAM_GOT_EXTRA_PARAMETER,
- PARAM_BAD_NUMERIC,
- PARAM_LIBCURL_DOESNT_SUPPORT,
- PARAM_NO_MEM,
- PARAM_LAST
-} ParameterError;
-
-static const char *param2text(int res)
-{
- ParameterError error = (ParameterError)res;
- switch(error) {
- case PARAM_GOT_EXTRA_PARAMETER:
- return "had unsupported trailing garbage";
- case PARAM_OPTION_UNKNOWN:
- return "is unknown";
- case PARAM_OPTION_AMBIGUOUS:
- return "is ambiguous";
- case PARAM_REQUIRES_PARAMETER:
- return "requires parameter";
- case PARAM_BAD_USE:
- return "is badly used here";
- case PARAM_BAD_NUMERIC:
- return "expected a proper numerical parameter";
- case PARAM_LIBCURL_DOESNT_SUPPORT:
- return "the installed libcurl version doesn't support this";
- case PARAM_NO_MEM:
- return "out of memory";
- default:
- return "unknown error";
- }
-}
-
-static ParameterError file2string(char **bufp, FILE *file)
-{
- char buffer[256];
- char *ptr;
- char *string = NULL;
- size_t stringlen = 0;
- size_t buflen;
-
- if(file) {
- while(fgets(buffer, sizeof(buffer), file)) {
- if((ptr = strchr(buffer, '\r')) != NULL)
- *ptr = '\0';
- if((ptr = strchr(buffer, '\n')) != NULL)
- *ptr = '\0';
- buflen = strlen(buffer);
- if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
- if(string)
- free(string);
- return PARAM_NO_MEM;
- }
- string = ptr;
- strcpy(string+stringlen, buffer);
- stringlen += buflen;
- }
- }
- *bufp = string;
- return PARAM_OK;
-}
-
-static ParameterError file2memory(char **bufp, size_t *size, FILE *file)
-{
- char *newbuf;
- char *buffer = NULL;
- size_t alloc = 512;
- size_t nused = 0;
- size_t nread;
-
- if(file) {
- do {
- if(!buffer || (alloc == nused)) {
- /* size_t overflow detection for huge files */
- if(alloc+1 > ((size_t)-1)/2) {
- if(buffer)
- free(buffer);
- return PARAM_NO_MEM;
- }
- alloc *= 2;
- /* allocate an extra char, reserved space, for null termination */
- if((newbuf = realloc(buffer, alloc+1)) == NULL) {
- if(buffer)
- free(buffer);
- return PARAM_NO_MEM;
- }
- buffer = newbuf;
- }
- nread = fread(buffer+nused, 1, alloc-nused, file);
- nused += nread;
- } while(nread);
- /* null terminate the buffer in case it's used as a string later */
- buffer[nused] = '\0';
- /* free trailing slack space, if possible */
- if(alloc != nused) {
- if((newbuf = realloc(buffer, nused+1)) != NULL)
- buffer = newbuf;
- }
- /* discard buffer if nothing was read */
- if(!nused) {
- free(buffer);
- buffer = NULL; /* no string */
- }
- }
- *size = nused;
- *bufp = buffer;
- return PARAM_OK;
-}
-
-static void cleanarg(char *str)
-{
-#ifdef HAVE_WRITABLE_ARGV
- /* now that GetStr has copied the contents of nextarg, wipe the next
- * argument out so that the username:password isn't displayed in the
- * system process list */
- if(str) {
- size_t len = strlen(str);
- memset(str, ' ', len);
- }
-#else
- (void)str;
-#endif
-}
-
-/*
- * Parse the string and write the integer in the given address. Return
- * non-zero on failure, zero on success.
- *
- * The string must start with a digit to be valid.
- *
- * Since this function gets called with the 'nextarg' pointer from within the
- * getparameter a lot, we must check it for NULL before accessing the str
- * data.
- */
-
-static int str2num(long *val, const char *str)
-{
- if(str && ISDIGIT(*str)) {
- char *endptr;
- long num = strtol(str, &endptr, 10);
- if((endptr != str) && (endptr == str + strlen(str))) {
- *val = num;
- return 0; /* Ok */
- }
- }
- return 1; /* badness */
-}
-
-/*
- * Parse the string and modify the long in the given address. Return
- * non-zero on failure, zero on success.
- *
- * The string is a list of protocols
- *
- * Since this function gets called with the 'nextarg' pointer from within the
- * getparameter a lot, we must check it for NULL before accessing the str
- * data.
- */
-
-static long proto2num(struct Configurable *config, long *val, const char *str)
-{
- char *buffer;
- const char *sep = ",";
- char *token;
-
- static struct sprotos {
- const char *name;
- long bit;
- } const protos[] = {
- { "all", CURLPROTO_ALL },
- { "http", CURLPROTO_HTTP },
- { "https", CURLPROTO_HTTPS },
- { "ftp", CURLPROTO_FTP },
- { "ftps", CURLPROTO_FTPS },
- { "scp", CURLPROTO_SCP },
- { "sftp", CURLPROTO_SFTP },
- { "telnet", CURLPROTO_TELNET },
- { "ldap", CURLPROTO_LDAP },
- { "ldaps", CURLPROTO_LDAPS },
- { "dict", CURLPROTO_DICT },
- { "file", CURLPROTO_FILE },
- { "tftp", CURLPROTO_TFTP },
- { "imap", CURLPROTO_IMAP },
- { "imaps", CURLPROTO_IMAPS },
- { "pop3", CURLPROTO_POP3 },
- { "pop3s", CURLPROTO_POP3S },
- { "smtp", CURLPROTO_SMTP },
- { "smtps", CURLPROTO_SMTPS },
- { "rtsp", CURLPROTO_RTSP },
- { "gopher", CURLPROTO_GOPHER },
- { NULL, 0 }
- };
-
- if(!str)
- return 1;
-
- buffer = strdup(str); /* because strtok corrupts it */
-
- for(token = strtok(buffer, sep);
- token;
- token = strtok(NULL, sep)) {
- enum e_action { allow, deny, set } action = allow;
-
- struct sprotos const *pp;
-
- /* Process token modifiers */
- while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
- switch (*token++) {
- case '=':
- action = set;
- break;
- case '-':
- action = deny;
- break;
- case '+':
- action = allow;
- break;
- default: /* Includes case of terminating NULL */
- free(buffer);
- return 1;
- }
- }
-
- for(pp=protos; pp->name; pp++) {
- if(curlx_raw_equal(token, pp->name)) {
- switch (action) {
- case deny:
- *val &= ~(pp->bit);
- break;
- case allow:
- *val |= pp->bit;
- break;
- case set:
- *val = pp->bit;
- break;
- }
- break;
- }
- }
-
- if(!(pp->name)) { /* unknown protocol */
- /* If they have specified only this protocol, we say treat it as
- if no protocols are allowed */
- if(action == set)
- *val = 0;
- warnf(config, "unrecognized protocol '%s'\n", token);
- }
- }
- free(buffer);
- return 0;
-}
-
-/**
- * Parses the given string looking for an offset (which may be
- * a larger-than-integer value).
- *
- * @param val the offset to populate
- * @param str the buffer containing the offset
- * @return zero if successful, non-zero if failure.
- */
-static int str2offset(curl_off_t *val, const char *str)
-{
-#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
- *val = curlx_strtoofft(str, NULL, 0);
- if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
- return 1;
-#else
- *val = strtol(str, NULL, 0);
- if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
- return 1;
-#endif
- return 0;
-}
-
-static void checkpasswd(const char *kind, /* for what purpose */
- char **userpwd) /* pointer to allocated string */
-{
- char *ptr;
- if(!*userpwd)
- return;
-
- ptr = strchr(*userpwd, ':');
- if(!ptr) {
- /* no password present, prompt for one */
- char passwd[256]="";
- char prompt[256];
- size_t passwdlen;
- size_t userlen = strlen(*userpwd);
- char *passptr;
-
- /* build a nice-looking prompt */
- curlx_msnprintf(prompt, sizeof(prompt),
- "Enter %s password for user '%s':",
- kind, *userpwd);
-
- /* get password */
- getpass_r(prompt, passwd, sizeof(passwd));
- passwdlen = strlen(passwd);
-
- /* extend the allocated memory area to fit the password too */
- passptr = realloc(*userpwd,
- passwdlen + 1 + /* an extra for the colon */
- userlen + 1); /* an extra for the zero */
-
- if(passptr) {
- /* append the password separated with a colon */
- passptr[userlen]=':';
- memcpy(&passptr[userlen+1], passwd, passwdlen+1);
- *userpwd = passptr;
- }
- }
-}
-
-static ParameterError add2list(struct curl_slist **list,
- const char *ptr)
-{
- struct curl_slist *newlist = curl_slist_append(*list, ptr);
- if(newlist)
- *list = newlist;
- else
- return PARAM_NO_MEM;
-
- return PARAM_OK;
-}
-
-static int ftpfilemethod(struct Configurable *config, const char *str)
-{
- if(curlx_raw_equal("singlecwd", str))
- return CURLFTPMETHOD_SINGLECWD;
- if(curlx_raw_equal("nocwd", str))
- return CURLFTPMETHOD_NOCWD;
- if(curlx_raw_equal("multicwd", str))
- return CURLFTPMETHOD_MULTICWD;
- warnf(config, "unrecognized ftp file method '%s', using default\n", str);
- return CURLFTPMETHOD_MULTICWD;
-}
-
-static int ftpcccmethod(struct Configurable *config, const char *str)
-{
- if(curlx_raw_equal("passive", str))
- return CURLFTPSSL_CCC_PASSIVE;
- if(curlx_raw_equal("active", str))
- return CURLFTPSSL_CCC_ACTIVE;
- warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
- return CURLFTPSSL_CCC_PASSIVE;
-}
-
-
-static int sockoptcallback(void *clientp, curl_socket_t curlfd,
- curlsocktype purpose)
-{
- struct Configurable *config = (struct Configurable *)clientp;
- int onoff = 1; /* this callback is only used if we ask for keepalives on the
- connection */
-#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
- int keepidle = (int)config->alivetime;
-#endif
-
- switch(purpose) {
- case CURLSOCKTYPE_IPCXN:
- if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
- sizeof(onoff)) < 0) {
- /* don't abort operation, just issue a warning */
- SET_SOCKERRNO(0);
- warnf(clientp, "Could not set SO_KEEPALIVE!\n");
- return 0;
- }
- else {
- if(config->alivetime) {
-#ifdef TCP_KEEPIDLE
- if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
- sizeof(keepidle)) < 0) {
- /* don't abort operation, just issue a warning */
- SET_SOCKERRNO(0);
- warnf(clientp, "Could not set TCP_KEEPIDLE!\n");
- return 0;
- }
-#endif
-#ifdef TCP_KEEPINTVL
- if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
- sizeof(keepidle)) < 0) {
- /* don't abort operation, just issue a warning */
- SET_SOCKERRNO(0);
- warnf(clientp, "Could not set TCP_KEEPINTVL!\n");
- return 0;
- }
-#endif
-#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL)
- warnf(clientp, "Keep-alive functionality somewhat crippled due to "
- "missing support in your operating system!\n");
-#endif
- }
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-
-static ParameterError getparameter(char *flag, /* f or -long-flag */
- char *nextarg, /* NULL if unset */
- bool *usedarg, /* set to TRUE if the arg
- has been used */
- struct Configurable *config)
-{
- char letter;
- char subletter=0; /* subletters can only occur on long options */
- int rc; /* generic return code variable */
- const char *parse=NULL;
- unsigned int j;
- time_t now;
- int hit=-1;
- bool longopt=FALSE;
- bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
- ParameterError err;
- bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled
- by using --OPTION or --no-OPTION */
-
- /* single-letter,
- long-name,
- boolean whether it takes an additional argument
- */
- static const struct LongShort aliases[]= {
- /* all these ones, starting with "*" or "$" as a short-option have *no*
- short option to mention. */
- {"*", "url", TRUE},
- {"*a", "random-file", TRUE},
- {"*b", "egd-file", TRUE},
- {"*c", "connect-timeout", TRUE},
- {"*d", "ciphers", TRUE},
- {"*e", "disable-epsv", FALSE},
- {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to
- work although --disable-epsv is the documented
- option */
-#ifdef USE_ENVIRONMENT
- {"*f", "environment", FALSE},
-#endif
- {"*g", "trace", TRUE},
- {"*h", "trace-ascii", TRUE},
- {"*i", "limit-rate", TRUE},
- {"*j", "compressed", FALSE},
- {"*J", "tr-encoding", FALSE},
- {"*k", "digest", FALSE},
- {"*l", "negotiate", FALSE},
- {"*m", "ntlm", FALSE},
- {"*n", "basic", FALSE},
- {"*o", "anyauth", FALSE},
-#ifdef USE_WATT32
- {"*p", "wdebug", FALSE},
-#endif
- {"*q", "ftp-create-dirs", FALSE},
- {"*r", "create-dirs", FALSE},
- {"*s", "max-redirs", TRUE},
- {"*t", "proxy-ntlm", FALSE},
- {"*u", "crlf", FALSE},
- {"*v", "stderr", TRUE},
- {"*w", "interface", TRUE},
- {"*x", "krb" , TRUE},
- {"*x", "krb4" , TRUE}, /* this is the previous name */
- {"*y", "max-filesize", TRUE},
- {"*z", "disable-eprt", FALSE},
- {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to
- work although --disable-eprt is the documented
- option */
- {"$a", "ftp-ssl", FALSE}, /* deprecated name since 7.20.0 */
- {"$a", "ssl", FALSE}, /* new option name in 7.20.0, previously this
- was ftp-ssl */
- {"$b", "ftp-pasv", FALSE},
- {"$c", "socks5", TRUE},
- {"$c", "socks", TRUE}, /* this is how the option once was documented
- but we prefer the --socks5 version for
- explicit version */
- {"$d", "tcp-nodelay",FALSE},
- {"$e", "proxy-digest", FALSE},
- {"$f", "proxy-basic", FALSE},
- {"$g", "retry", TRUE},
- {"$h", "retry-delay", TRUE},
- {"$i", "retry-max-time", TRUE},
- {"$k", "proxy-negotiate", FALSE},
- {"$m", "ftp-account", TRUE},
- {"$n", "proxy-anyauth", FALSE},
- {"$o", "trace-time", FALSE},
- {"$p", "ignore-content-length", FALSE},
- {"$q", "ftp-skip-pasv-ip", FALSE},
- {"$r", "ftp-method", TRUE},
- {"$s", "local-port", TRUE},
- {"$t", "socks4", TRUE},
- {"$T", "socks4a", TRUE},
- {"$u", "ftp-alternative-to-user", TRUE},
- {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */
- {"$v", "ssl-reqd", FALSE}, /* new option name in 7.20.0, previously this
- was ftp-ssl-reqd */
- {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */
- {"$x", "ftp-ssl-control", FALSE},
- {"$y", "ftp-ssl-ccc", FALSE},
- {"$j", "ftp-ssl-ccc-mode", TRUE},
- {"$z", "libcurl", TRUE},
- {"$#", "raw", FALSE},
- {"$0", "post301", FALSE},
- {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */
- {"$2", "socks5-hostname", TRUE},
- {"$3", "keepalive-time", TRUE},
- {"$4", "post302", FALSE},
- {"$5", "noproxy", TRUE},
-
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- {"$6", "socks5-gssapi-service", TRUE},
- {"$7", "socks5-gssapi-nec", FALSE},
-#endif
- {"$8", "proxy1.0", TRUE},
- {"$9", "tftp-blksize", TRUE},
- {"$A", "mail-from", TRUE},
- {"$B", "mail-rcpt", TRUE},
- {"$C", "ftp-pret", FALSE},
- {"$D", "proto", TRUE},
- {"$E", "proto-redir", TRUE},
- {"$F", "resolve", TRUE},
- {"0", "http1.0", FALSE},
- {"1", "tlsv1", FALSE},
- {"2", "sslv2", FALSE},
- {"3", "sslv3", FALSE},
- {"4", "ipv4", FALSE},
- {"6", "ipv6", FALSE},
- {"a", "append", FALSE},
- {"A", "user-agent", TRUE},
- {"b", "cookie", TRUE},
- {"B", "use-ascii", FALSE},
- {"c", "cookie-jar", TRUE},
- {"C", "continue-at", TRUE},
- {"d", "data", TRUE},
- {"da", "data-ascii", TRUE},
- {"db", "data-binary", TRUE},
- {"de", "data-urlencode", TRUE},
- {"D", "dump-header", TRUE},
- {"e", "referer", TRUE},
- {"E", "cert", TRUE},
- {"Ea", "cacert", TRUE},
- {"Eb","cert-type", TRUE},
- {"Ec","key", TRUE},
- {"Ed","key-type", TRUE},
- {"Ee","pass", TRUE},
- {"Ef","engine", TRUE},
- {"Eg","capath ", TRUE},
- {"Eh","pubkey", TRUE},
- {"Ei", "hostpubmd5", TRUE},
- {"Ej","crlfile", TRUE},
- {"Ek","tlsuser", TRUE},
- {"El","tlspassword", TRUE},
- {"Em","tlsauthtype", TRUE},
- {"f", "fail", FALSE},
- {"F", "form", TRUE},
- {"Fs","form-string", TRUE},
- {"g", "globoff", FALSE},
- {"G", "get", FALSE},
- {"h", "help", FALSE},
- {"H", "header", TRUE},
- {"i", "include", FALSE},
- {"I", "head", FALSE},
- {"j", "junk-session-cookies", FALSE},
- {"J", "remote-header-name", FALSE},
- {"k", "insecure", FALSE},
- {"K", "config", TRUE},
- {"l", "list-only", FALSE},
- {"L", "location", FALSE},
- {"Lt", "location-trusted", FALSE},
- {"m", "max-time", TRUE},
- {"M", "manual", FALSE},
- {"n", "netrc", FALSE},
- {"no", "netrc-optional", FALSE},
- {"ne", "netrc-file", TRUE},
- {"N", "buffer", FALSE}, /* listed as --no-buffer in the help */
- {"o", "output", TRUE},
- {"O", "remote-name", FALSE},
- {"Oa", "remote-name-all", FALSE},
- {"p", "proxytunnel", FALSE},
- {"P", "ftpport", TRUE}, /* older version */
- {"P", "ftp-port", TRUE},
- {"q", "disable", FALSE},
- {"Q", "quote", TRUE},
- {"r", "range", TRUE},
- {"R", "remote-time", FALSE},
- {"s", "silent", FALSE},
- {"S", "show-error", FALSE},
- {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */
- {"T", "upload-file", TRUE},
- {"u", "user", TRUE},
- {"U", "proxy-user", TRUE},
- {"v", "verbose", FALSE},
- {"V", "version", FALSE},
- {"w", "write-out", TRUE},
- {"x", "proxy", TRUE},
- {"X", "request", TRUE},
- {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
- {"Y", "speed-limit", TRUE},
- {"y", "speed-time", TRUE},
- {"z", "time-cond", TRUE},
- {"#", "progress-bar",FALSE},
- {"~", "xattr",FALSE},
- };
-
- if(('-' != flag[0]) ||
- (('-' == flag[0]) && ('-' == flag[1]))) {
- /* this should be a long name */
- char *word=('-' == flag[0])?flag+2:flag;
- size_t fnam=strlen(word);
- int numhits=0;
-
- if(!strncmp(word, "no-", 3)) {
- /* disable this option but ignore the "no-" part when looking for it */
- word += 3;
- toggle = FALSE;
- }
-
- for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
- if(curlx_strnequal(aliases[j].lname, word, fnam)) {
- longopt = TRUE;
- numhits++;
- if(curlx_raw_equal(aliases[j].lname, word)) {
- parse = aliases[j].letter;
- hit = j;
- numhits = 1; /* a single unique hit */
- break;
- }
- parse = aliases[j].letter;
- hit = j;
- }
- }
- if(numhits>1) {
- /* this is at least the second match! */
- return PARAM_OPTION_AMBIGUOUS;
- }
- if(hit < 0) {
- return PARAM_OPTION_UNKNOWN;
- }
- }
- else {
- flag++; /* prefixed with one dash, pass it */
- hit=-1;
- parse = flag;
- }
-
- do {
- /* we can loop here if we have multiple single-letters */
-
- if(!longopt) {
- if(NULL != parse) {
- letter = (char)*parse;
- }
- else {
- letter = '\0';
- }
- subletter='\0';
- }
- else {
- letter = parse[0];
- subletter = parse[1];
- }
- *usedarg = FALSE; /* default is that we don't use the arg */
-
- if(hit < 0) {
- for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
- if(letter == aliases[j].letter[0]) {
- hit = j;
- break;
- }
- }
- if(hit < 0) {
- return PARAM_OPTION_UNKNOWN;
- }
- }
-
- if(aliases[hit].extraparam) {
- /* this option requires an extra parameter */
- if(!longopt && parse[1]) {
- nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
- singleopt=TRUE; /* don't loop anymore after this */
- }
- else if(!nextarg)
- return PARAM_REQUIRES_PARAMETER;
- else
- *usedarg = TRUE; /* mark it as used */
- }
-
- switch(letter) {
- case '*': /* options without a short option */
- switch(subletter) {
- case 'a': /* random-file */
- GetStr(&config->random_file, nextarg);
- break;
- case 'b': /* egd-file */
- GetStr(&config->egd_file, nextarg);
- break;
- case 'c': /* connect-timeout */
- if(str2num(&config->connecttimeout, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case 'd': /* ciphers */
- GetStr(&config->cipher_list, nextarg);
- break;
- case 'e': /* --disable-epsv */
- config->disable_epsv = toggle;
- break;
- case 'E': /* --epsv */
- config->disable_epsv = (bool)(!toggle);
- break;
-#ifdef USE_ENVIRONMENT
- case 'f':
- config->writeenv = toggle;
- break;
-#endif
- case 'g': /* --trace */
- GetStr(&config->trace_dump, nextarg);
- if(config->tracetype && (config->tracetype != TRACE_BIN))
- warnf(config, "--trace overrides an earlier trace/verbose option\n");
- config->tracetype = TRACE_BIN;
- break;
- case 'h': /* --trace-ascii */
- GetStr(&config->trace_dump, nextarg);
- if(config->tracetype && (config->tracetype != TRACE_ASCII))
- warnf(config,
- "--trace-ascii overrides an earlier trace/verbose option\n");
- config->tracetype = TRACE_ASCII;
- break;
- case 'i': /* --limit-rate */
- {
- /* We support G, M, K too */
- char *unit;
- curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
-
- if(!*unit)
- unit=(char *)"b";
- else if(strlen(unit) > 1)
- unit=(char *)"w"; /* unsupported */
-
- switch(*unit) {
- case 'G':
- case 'g':
- value *= 1024*1024*1024;
- break;
- case 'M':
- case 'm':
- value *= 1024*1024;
- break;
- case 'K':
- case 'k':
- value *= 1024;
- break;
- case 'b':
- case 'B':
- /* for plain bytes, leave as-is */
- break;
- default:
- warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
- return PARAM_BAD_USE;
- }
- config->recvpersecond = value;
- config->sendpersecond = value;
- }
- break;
-
- case 'j': /* --compressed */
- if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ))
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- config->encoding = toggle;
- break;
-
- case 'J': /* --tr-encoding */
- config->tr_encoding = toggle;
- break;
-
- case 'k': /* --digest */
- if(toggle)
- config->authtype |= CURLAUTH_DIGEST;
- else
- config->authtype &= ~CURLAUTH_DIGEST;
- break;
-
- case 'l': /* --negotiate */
- if(toggle) {
- if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
- config->authtype |= CURLAUTH_GSSNEGOTIATE;
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- }
- else
- config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
- break;
-
- case 'm': /* --ntlm */
- if(toggle) {
- if(curlinfo->features & CURL_VERSION_NTLM)
- config->authtype |= CURLAUTH_NTLM;
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- }
- else
- config->authtype &= ~CURLAUTH_NTLM;
- break;
-
- case 'n': /* --basic for completeness */
- if(toggle)
- config->authtype |= CURLAUTH_BASIC;
- else
- config->authtype &= ~CURLAUTH_BASIC;
- break;
-
- case 'o': /* --anyauth, let libcurl pick it */
- if(toggle)
- config->authtype = CURLAUTH_ANY;
- /* --no-anyauth simply doesn't touch it */
- break;
-
-#ifdef USE_WATT32
- case 'p': /* --wdebug */
- dbug_init();
- break;
-#endif
- case 'q': /* --ftp-create-dirs */
- config->ftp_create_dirs = toggle;
- break;
-
- case 'r': /* --create-dirs */
- config->create_dirs = TRUE;
- break;
-
- case 's': /* --max-redirs */
- /* specified max no of redirects (http(s)) */
- if(str2num(&config->maxredirs, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
-
- case 't': /* --proxy-ntlm */
- if(curlinfo->features & CURL_VERSION_NTLM)
- config->proxyntlm = toggle;
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
-
- case 'u': /* --crlf */
- /* LF -> CRLF conversion? */
- config->crlf = TRUE;
- break;
-
- case 'v': /* --stderr */
- if(strcmp(nextarg, "-")) {
- FILE *newfile = fopen(nextarg, "wt");
- if(!newfile)
- warnf(config, "Failed to open %s!\n", nextarg);
- else {
- if(config->errors_fopened)
- fclose(config->errors);
- config->errors = newfile;
- config->errors_fopened = TRUE;
- }
- }
- else
- config->errors = stdout;
- break;
- case 'w': /* --interface */
- /* interface */
- GetStr(&config->iface, nextarg);
- break;
- case 'x': /* --krb */
- /* kerberos level string */
- if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
- CURL_VERSION_GSSNEGOTIATE))
- GetStr(&config->krblevel, nextarg);
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case 'y': /* --max-filesize */
- if(str2offset(&config->max_filesize, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case 'z': /* --disable-eprt */
- config->disable_eprt = toggle;
- break;
- case 'Z': /* --eprt */
- config->disable_eprt = (bool)(!toggle);
- break;
-
- default: /* the URL! */
- {
- struct getout *url;
- if(config->url_get || ((config->url_get = config->url_list) != NULL)) {
- /* there's a node here, if it already is filled-in continue to find
- an "empty" node */
- while(config->url_get && (config->url_get->flags&GETOUT_URL))
- config->url_get = config->url_get->next;
- }
-
- /* now there might or might not be an available node to fill in! */
-
- if(config->url_get)
- /* existing node */
- url = config->url_get;
- else
- /* there was no free node, create one! */
- url=new_getout(config);
-
- if(url) {
- /* fill in the URL */
- GetStr(&url->url, nextarg);
- url->flags |= GETOUT_URL;
- }
- }
- }
- break;
- case '$': /* more options without a short option */
- switch(subletter) {
- case 'a': /* --ftp-ssl */
- if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- config->ftp_ssl = toggle;
- break;
- case 'b': /* --ftp-pasv */
- if(config->ftpport)
- free(config->ftpport);
- config->ftpport = NULL;
- break;
- case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
- the name locally and passes on the resolved address */
- GetStr(&config->socksproxy, nextarg);
- config->socksver = CURLPROXY_SOCKS5;
- break;
- case 't': /* --socks4 specifies a socks4 proxy to use */
- GetStr(&config->socksproxy, nextarg);
- config->socksver = CURLPROXY_SOCKS4;
- break;
- case 'T': /* --socks4a specifies a socks4a proxy to use */
- GetStr(&config->socksproxy, nextarg);
- config->socksver = CURLPROXY_SOCKS4A;
- break;
- case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
- resolving with the proxy */
- GetStr(&config->socksproxy, nextarg);
- config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
- break;
- case 'd': /* --tcp-nodelay option */
- config->tcp_nodelay = toggle;
- break;
- case 'e': /* --proxy-digest */
- config->proxydigest = toggle;
- break;
- case 'f': /* --proxy-basic */
- config->proxybasic = toggle;
- break;
- case 'g': /* --retry */
- if(str2num(&config->req_retry, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case 'h': /* --retry-delay */
- if(str2num(&config->retry_delay, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case 'i': /* --retry-max-time */
- if(str2num(&config->retry_maxtime, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
-
- case 'k': /* --proxy-negotiate */
- if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
- config->proxynegotiate = toggle;
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case 'm': /* --ftp-account */
- GetStr(&config->ftp_account, nextarg);
- break;
- case 'n': /* --proxy-anyauth */
- config->proxyanyauth = toggle;
- break;
- case 'o': /* --trace-time */
- config->tracetime = toggle;
- break;
- case 'p': /* --ignore-content-length */
- config->ignorecl = toggle;
- break;
- case 'q': /* --ftp-skip-pasv-ip */
- config->ftp_skip_ip = toggle;
- break;
- case 'r': /* --ftp-method (undocumented at this point) */
- config->ftp_filemethod = ftpfilemethod(config, nextarg);
- break;
- case 's': /* --local-port */
- rc = sscanf(nextarg, "%d - %d",
- &config->localport,
- &config->localportrange);
- if(!rc)
- return PARAM_BAD_USE;
- else if(rc == 1)
- config->localportrange = 1; /* default number of ports to try */
- else {
- config->localportrange -= config->localport;
- if(config->localportrange < 1) {
- warnf(config, "bad range input\n");
- return PARAM_BAD_USE;
- }
- }
- break;
- case 'u': /* --ftp-alternative-to-user */
- GetStr(&config->ftp_alternative_to_user, nextarg);
- break;
- case 'v': /* --ftp-ssl-reqd */
- if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- config->ftp_ssl_reqd = toggle;
- break;
- case 'w': /* --no-sessionid */
- config->disable_sessionid = (bool)(!toggle);
- break;
- case 'x': /* --ftp-ssl-control */
- if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- config->ftp_ssl_control = toggle;
- break;
- case 'y': /* --ftp-ssl-ccc */
- config->ftp_ssl_ccc = toggle;
- if(!config->ftp_ssl_ccc_mode)
- config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
- break;
- case 'j': /* --ftp-ssl-ccc-mode */
- config->ftp_ssl_ccc = TRUE;
- config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
- break;
- case 'z': /* --libcurl */
- GetStr(&config->libcurl, nextarg);
- break;
- case '#': /* --raw */
- config->raw = toggle;
- break;
- case '0': /* --post301 */
- config->post301 = toggle;
- break;
- case '1': /* --no-keepalive */
- config->nokeepalive = (bool)(!toggle);
- break;
- case '3': /* --keepalive-time */
- if(str2num(&config->alivetime, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case '4': /* --post302 */
- config->post302 = toggle;
- break;
- case '5': /* --noproxy */
- /* This specifies the noproxy list */
- GetStr(&config->noproxy, nextarg);
- break;
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- case '6': /* --socks5-gssapi-service */
- GetStr(&config->socks5_gssapi_service, nextarg);
- break;
- case '7': /* --socks5-gssapi-nec*/
- config->socks5_gssapi_nec = TRUE;
- break;
-#endif
- case '8': /* --proxy1.0 */
- /* http 1.0 proxy */
- GetStr(&config->proxy, nextarg);
- config->proxyver = CURLPROXY_HTTP_1_0;
- break;
- case '9': /* --tftp-blksize */
- str2num(&config->tftp_blksize, nextarg);
- break;
- case 'A': /* --mail-from */
- GetStr(&config->mail_from, nextarg);
- break;
- case 'B': /* --mail-rcpt */
- /* append receiver to a list */
- err = add2list(&config->mail_rcpt, nextarg);
- if(err)
- return err;
- break;
- case 'C': /* --ftp-pret */
- config->ftp_pret = toggle;
- break;
- case 'D': /* --proto */
- config->proto_present = TRUE;
- if(proto2num(config, &config->proto, nextarg))
- return PARAM_BAD_USE;
- break;
- case 'E': /* --proto-redir */
- config->proto_redir_present = TRUE;
- if(proto2num(config, &config->proto_redir, nextarg))
- return PARAM_BAD_USE;
- break;
- case 'F': /* --resolve */
- err = add2list(&config->resolve, nextarg);
- if(err)
- return err;
- break;
- }
- break;
- case '#': /* --progress-bar */
- if(toggle)
- config->progressmode = CURL_PROGRESS_BAR;
- else
- config->progressmode = CURL_PROGRESS_STATS;
- break;
- case '~': /* --xattr */
- config->xattr = toggle;
- break;
- case '0':
- /* HTTP version 1.0 */
- config->httpversion = CURL_HTTP_VERSION_1_0;
- break;
- case '1':
- /* TLS version 1 */
- config->ssl_version = CURL_SSLVERSION_TLSv1;
- break;
- case '2':
- /* SSL version 2 */
- config->ssl_version = CURL_SSLVERSION_SSLv2;
- break;
- case '3':
- /* SSL version 3 */
- config->ssl_version = CURL_SSLVERSION_SSLv3;
- break;
- case '4':
- /* IPv4 */
- config->ip_version = 4;
- break;
- case '6':
- /* IPv6 */
- config->ip_version = 6;
- break;
- case 'a':
- /* This makes the FTP sessions use APPE instead of STOR */
- config->ftp_append = toggle;
- break;
- case 'A':
- /* This specifies the User-Agent name */
- GetStr(&config->useragent, nextarg);
- break;
- case 'b': /* cookie string coming up: */
- if(nextarg[0] == '@') {
- nextarg++;
- }
- else if(strchr(nextarg, '=')) {
- /* A cookie string must have a =-letter */
- GetStr(&config->cookie, nextarg);
- break;
- }
- /* We have a cookie file to read from! */
- GetStr(&config->cookiefile, nextarg);
- break;
- case 'B':
- /* use ASCII/text when transferring */
- config->use_ascii = toggle;
- break;
- case 'c':
- /* get the file name to dump all cookies in */
- GetStr(&config->cookiejar, nextarg);
- break;
- case 'C':
- /* This makes us continue an ftp transfer at given position */
- if(!curlx_strequal(nextarg, "-")) {
- if(str2offset(&config->resume_from, nextarg))
- return PARAM_BAD_NUMERIC;
- config->resume_from_current = FALSE;
- }
- else {
- config->resume_from_current = TRUE;
- config->resume_from = 0;
- }
- config->use_resume=TRUE;
- break;
- case 'd':
- /* postfield data */
- {
- char *postdata=NULL;
- FILE *file;
-
- if(subletter == 'e') { /* --data-urlencode*/
- /* [name]=[content], we encode the content part only
- * [name]@[file name]
- *
- * Case 2: we first load the file using that name and then encode
- * the content.
- */
- const char *p = strchr(nextarg, '=');
- size_t size = 0;
- size_t nlen;
- char is_file;
- if(!p)
- /* there was no '=' letter, check for a '@' instead */
- p = strchr(nextarg, '@');
- if(p) {
- nlen = p - nextarg; /* length of the name part */
- is_file = *p++; /* pass the separator */
- }
- else {
- /* neither @ nor =, so no name and it isn't a file */
- nlen = is_file = 0;
- p = nextarg;
- }
- if('@' == is_file) {
- /* a '@' letter, it means that a file name or - (stdin) follows */
-
- if(curlx_strequal("-", p)) {
- file = stdin;
- SET_BINMODE(stdin);
- }
- else {
- file = fopen(p, "rb");
- if(!file)
- warnf(config,
- "Couldn't read data from file \"%s\", this makes "
- "an empty POST.\n", nextarg);
- }
-
- err = file2memory(&postdata, &size, file);
-
- if(file && (file != stdin))
- fclose(file);
- if(err)
- return err;
- }
- else {
- GetStr(&postdata, p);
- size = strlen(postdata);
- }
-
- if(!postdata) {
- /* no data from the file, point to a zero byte string to make this
- get sent as a POST anyway */
- postdata=strdup("");
- }
- else {
- char *enc = curl_easy_escape(config->easy, postdata, (int)size);
- free(postdata); /* no matter if it worked or not */
- if(enc) {
- /* now make a string with the name from above and append the
- encoded string */
- size_t outlen = nlen + strlen(enc) + 2;
- char *n = malloc(outlen);
- if(!n) {
- curl_free(enc);
- return PARAM_NO_MEM;
- }
- if(nlen > 0) /* only append '=' if we have a name */
- snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
- else
- strcpy(n, enc);
- curl_free(enc);
- postdata = n;
- }
- else
- return PARAM_NO_MEM;
- }
- }
- else if('@' == *nextarg) {
- size_t size = 0;
- /* the data begins with a '@' letter, it means that a file name
- or - (stdin) follows */
- nextarg++; /* pass the @ */
-
- if(curlx_strequal("-", nextarg)) {
- file = stdin;
- if(subletter == 'b') /* forced data-binary */
- SET_BINMODE(stdin);
- }
- else {
- file = fopen(nextarg, "rb");
- if(!file)
- warnf(config, "Couldn't read data from file \"%s\", this makes "
- "an empty POST.\n", nextarg);
- }
-
- if(subletter == 'b') {
- /* forced binary */
- err = file2memory(&postdata, &size, file);
- config->postfieldsize = (curl_off_t)size;
- }
- else
- err = file2string(&postdata, file);
-
- if(file && (file != stdin))
- fclose(file);
- if(err)
- return err;
-
- if(!postdata) {
- /* no data from the file, point to a zero byte string to make this
- get sent as a POST anyway */
- postdata=strdup("");
- }
- }
- else {
- GetStr(&postdata, nextarg);
- }
-
-#ifdef CURL_DOES_CONVERSIONS
- if(subletter != 'b') { /* NOT forced binary, convert to ASCII */
- convert_to_network(postdata, strlen(postdata));
- }
-#endif
-
- if(config->postfields) {
- /* we already have a string, we append this one
- with a separating &-letter */
- char *oldpost=config->postfields;
- size_t newlen = strlen(oldpost) + strlen(postdata) + 2;
- config->postfields=malloc(newlen);
- if(!config->postfields) {
- free(postdata);
- return PARAM_NO_MEM;
- }
- /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
- snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata);
- free(oldpost);
- free(postdata);
- }
- else
- config->postfields=postdata;
- }
- /*
- We can't set the request type here, as this data might be used in
- a simple GET if -G is used. Already or soon.
-
- if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
- return PARAM_BAD_USE;
- */
- break;
- case 'D':
- /* dump-header to given file name */
- GetStr(&config->headerfile, nextarg);
- break;
- case 'e':
- {
- char *ptr = strstr(nextarg, ";auto");
- if(ptr) {
- /* Automatic referer requested, this may be combined with a
- set initial one */
- config->autoreferer = TRUE;
- *ptr = 0; /* zero terminate here */
- }
- else
- config->autoreferer = FALSE;
- GetStr(&config->referer, nextarg);
- }
- break;
- case 'E':
- switch(subletter) {
- case 'a': /* CA info PEM file */
- /* CA info PEM file */
- GetStr(&config->cacert, nextarg);
- break;
- case 'b': /* cert file type */
- GetStr(&config->cert_type, nextarg);
- break;
- case 'c': /* private key file */
- GetStr(&config->key, nextarg);
- break;
- case 'd': /* private key file type */
- GetStr(&config->key_type, nextarg);
- break;
- case 'e': /* private key passphrase */
- GetStr(&config->key_passwd, nextarg);
- cleanarg(nextarg);
- break;
- case 'f': /* crypto engine */
- GetStr(&config->engine, nextarg);
- if(config->engine && curlx_raw_equal(config->engine,"list"))
- config->list_engines = TRUE;
- break;
- case 'g': /* CA info PEM file */
- /* CA cert directory */
- GetStr(&config->capath, nextarg);
- break;
- case 'h': /* --pubkey public key file */
- GetStr(&config->pubkey, nextarg);
- break;
- case 'i': /* --hostpubmd5 md5 of the host public key */
- GetStr(&config->hostpubmd5, nextarg);
- if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
- return PARAM_BAD_USE;
- break;
- case 'j': /* CRL info PEM file */
- /* CRL file */
- GetStr(&config->crlfile, nextarg);
- break;
- case 'k': /* TLS username */
- if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
- GetStr(&config->tls_username, nextarg);
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case 'l': /* TLS password */
- if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
- GetStr(&config->tls_password, nextarg);
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case 'm': /* TLS authentication type */
- if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
- GetStr(&config->tls_authtype, nextarg);
- if(!strequal(config->tls_authtype, "SRP"))
- return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
- }
- else
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- default: /* certificate file */
- {
- char *ptr = strchr(nextarg, ':');
- /* Since we live in a world of weirdness and confusion, the win32
- dudes can use : when using drive letters and thus
- c:\file:password needs to work. In order not to break
- compatibility, we still use : as separator, but we try to detect
- when it is used for a file name! On windows. */
-#ifdef WIN32
- if(ptr &&
- (ptr == &nextarg[1]) &&
- (nextarg[2] == '\\' || nextarg[2] == '/') &&
- (ISALPHA(nextarg[0])) )
- /* colon in the second column, followed by a backslash, and the
- first character is an alphabetic letter:
-
- this is a drive letter colon */
- ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
-#endif
- if(ptr) {
- /* we have a password too */
- *ptr=0;
- ptr++;
- GetStr(&config->key_passwd, ptr);
- }
- GetStr(&config->cert, nextarg);
- cleanarg(nextarg);
- }
- }
- break;
- case 'f':
- /* fail hard on errors */
- config->failonerror = toggle;
- break;
- case 'F':
- /* "form data" simulation, this is a little advanced so lets do our best
- to sort this out slowly and carefully */
- if(formparse(config,
- nextarg,
- &config->httppost,
- &config->last_post,
- (bool) (subletter=='s'))) /* 's' means literal string */
- return PARAM_BAD_USE;
- if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
- return PARAM_BAD_USE;
- break;
-
- case 'g': /* g disables URLglobbing */
- config->globoff = toggle;
- break;
-
- case 'G': /* HTTP GET */
- config->use_httpget = TRUE;
- break;
-
- case 'h': /* h for help */
- if(toggle) {
- help();
- return PARAM_HELP_REQUESTED;
- }
- /* we now actually support --no-help too! */
- break;
- case 'H':
- /* A custom header to append to a list */
- err = add2list(&config->headers, nextarg);
- if(err)
- return err;
- break;
- case 'i':
- config->include_headers = toggle; /* include the headers as well in the
- general output stream */
- break;
- case 'j':
- config->cookiesession = toggle;
- break;
- case 'I':
- /*
- * no_body will imply include_headers later on
- */
- config->no_body = toggle;
- if(SetHTTPrequest(config,
- (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
- &config->httpreq))
- return PARAM_BAD_USE;
- break;
- case 'J': /* --remote-header-name */
- if(config->include_headers) {
- warnf(config,
- "--include and --remote-header-name cannot be combined.\n");
- return PARAM_BAD_USE;
- }
- config->content_disposition = toggle;
- break;
- case 'k': /* allow insecure SSL connects */
- config->insecure_ok = toggle;
- break;
- case 'K': /* parse config file */
- if(parseconfig(nextarg, config))
- warnf(config, "error trying read config from the '%s' file\n",
- nextarg);
- break;
- case 'l':
- config->dirlistonly = toggle; /* only list the names of the FTP dir */
- break;
- case 'L':
- config->followlocation = toggle; /* Follow Location: HTTP headers */
- switch (subletter) {
- case 't':
- /* Continue to send authentication (user+password) when following
- * locations, even when hostname changed */
- config->unrestricted_auth = toggle;
- break;
- }
- break;
- case 'm':
- /* specified max time */
- if(str2num(&config->timeout, nextarg))
- return PARAM_BAD_NUMERIC;
- break;
- case 'M': /* M for manual, huge help */
- if(toggle) { /* --no-manual shows no manual... */
-#ifdef USE_MANUAL
- hugehelp();
- return PARAM_HELP_REQUESTED;
-#else
- warnf(config,
- "built-in manual was disabled at build-time!\n");
- return PARAM_OPTION_UNKNOWN;
-#endif
- }
- break;
- case 'n':
- switch(subletter) {
- case 'o': /* CA info PEM file */
- /* use .netrc or URL */
- config->netrc_opt = toggle;
- break;
- case 'e': /* netrc-file */
- GetStr(&config->netrc_file, nextarg);
- break;
- default:
- /* pick info from .netrc, if this is used for http, curl will
- automatically enfore user+password with the request */
- config->netrc = toggle;
- break;
- }
- break;
- case 'N':
- /* disable the output I/O buffering. note that the option is called
- --buffer but is mostly used in the negative form: --no-buffer */
- if(longopt)
- config->nobuffer = (bool)(!toggle);
- else
- config->nobuffer = toggle;
- break;
- case 'O': /* --remote-name */
- if(subletter == 'a') { /* --remote-name-all */
- config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
- break;
- }
- /* fall-through! */
- case 'o': /* --output */
- /* output file */
- {
- struct getout *url;
- if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
- /* there's a node here, if it already is filled-in continue to find
- an "empty" node */
- while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
- config->url_out = config->url_out->next;
- }
-
- /* now there might or might not be an available node to fill in! */
-
- if(config->url_out)
- /* existing node */
- url = config->url_out;
- else
- /* there was no free node, create one! */
- url=new_getout(config);
-
- if(url) {
- /* fill in the outfile */
- if('o' == letter) {
- GetStr(&url->outfile, nextarg);
- url->flags &= ~GETOUT_USEREMOTE; /* switch off */
- }
- else {
- url->outfile=NULL; /* leave it */
- if(toggle)
- url->flags |= GETOUT_USEREMOTE; /* switch on */
- else
- url->flags &= ~GETOUT_USEREMOTE; /* switch off */
- }
- url->flags |= GETOUT_OUTFILE;
- }
- }
- break;
- case 'P':
- /* This makes the FTP sessions use PORT instead of PASV */
- /* use <eth0> or <192.168.10.10> style addresses. Anything except
- this will make us try to get the "default" address.
- NOTE: this is a changed behaviour since the released 4.1!
- */
- GetStr(&config->ftpport, nextarg);
- break;
- case 'p':
- /* proxy tunnel for non-http protocols */
- config->proxytunnel = toggle;
- break;
-
- case 'q': /* if used first, already taken care of, we do it like
- this so we don't cause an error! */
- break;
- case 'Q':
- /* QUOTE command to send to FTP server */
- switch(nextarg[0]) {
- case '-':
- /* prefixed with a dash makes it a POST TRANSFER one */
- nextarg++;
- err = add2list(&config->postquote, nextarg);
- break;
- case '+':
- /* prefixed with a plus makes it a just-before-transfer one */
- nextarg++;
- err = add2list(&config->prequote, nextarg);
- break;
- default:
- err = add2list(&config->quote, nextarg);
- break;
- }
- if(err)
- return err;
- break;
- case 'r':
- /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
- (and won't actually be range by definition). The man page previously
- claimed that to be a good way, why this code is added to work-around
- it. */
- if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
- char buffer[32];
- curl_off_t off;
- warnf(config,
- "A specified range MUST include at least one dash (-). "
- "Appending one for you!\n");
- off = curlx_strtoofft(nextarg, NULL, 10);
- snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
- GetStr(&config->range, buffer);
- }
- {
- /* byte range requested */
- char* tmp_range;
- tmp_range=nextarg;
- while(*tmp_range != '\0') {
- if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') {
- warnf(config,"Invalid character is found in given range. "
- "A specified range MUST have only digits in "
- "\'start\'-\'stop\'. The server's response to this "
- "request is uncertain.\n");
- break;
- }
- tmp_range++;
- }
- /* byte range requested */
- GetStr(&config->range, nextarg);
- }
- break;
- case 'R':
- /* use remote file's time */
- config->remote_time = toggle;
- break;
- case 's':
- /* don't show progress meter, don't show errors : */
- if(toggle)
- config->mute = config->noprogress = TRUE;
- else
- config->mute = config->noprogress = FALSE;
- config->showerror = (bool)(!toggle); /* toggle off */
- break;
- case 'S':
- /* show errors */
- config->showerror = toggle; /* toggle on if used with -s */
- break;
- case 't':
- /* Telnet options */
- err = add2list(&config->telnet_options, nextarg);
- if(err)
- return err;
- break;
- case 'T':
- /* we are uploading */
- {
- struct getout *url;
- if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
- /* there's a node here, if it already is filled-in continue to find
- an "empty" node */
- while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
- config->url_out = config->url_out->next;
- }
-
- /* now there might or might not be an available node to fill in! */
-
- if(config->url_out)
- /* existing node */
- url = config->url_out;
- else
- /* there was no free node, create one! */
- url=new_getout(config);
-
- if(url) {
- url->flags |= GETOUT_UPLOAD; /* mark -T used */
- if(!*nextarg)
- url->flags |= GETOUT_NOUPLOAD;
- else {
- /* "-" equals stdin, but keep the string around for now */
- GetStr(&url->infile, nextarg);
- }
- }
- }
- break;
- case 'u':
- /* user:password */
- GetStr(&config->userpwd, nextarg);
- cleanarg(nextarg);
- checkpasswd("host", &config->userpwd);
- break;
- case 'U':
- /* Proxy user:password */
- GetStr(&config->proxyuserpwd, nextarg);
- cleanarg(nextarg);
- checkpasswd("proxy", &config->proxyuserpwd);
- break;
- case 'v':
- if(toggle) {
- /* the '%' thing here will cause the trace get sent to stderr */
- GetStr(&config->trace_dump, (char *)"%");
- if(config->tracetype && (config->tracetype != TRACE_PLAIN))
- warnf(config,
- "-v/--verbose overrides an earlier trace/verbose option\n");
- config->tracetype = TRACE_PLAIN;
- }
- else
- /* verbose is disabled here */
- config->tracetype = TRACE_NONE;
- break;
- case 'V':
- {
- const char * const *proto;
-
- if(!toggle)
- /* --no-version yields no output! */
- break;
-
- printf(CURL_ID "%s\n", curl_version());
- if(curlinfo->protocols) {
- printf("Protocols: ");
- for(proto=curlinfo->protocols; *proto; ++proto) {
- printf("%s ", *proto);
- }
- puts(""); /* newline */
- }
- if(curlinfo->features) {
- unsigned int i;
- struct feat {
- const char *name;
- int bitmask;
- };
- static const struct feat feats[] = {
- {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
- {"Debug", CURL_VERSION_DEBUG},
- {"TrackMemory", CURL_VERSION_CURLDEBUG},
- {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
- {"IDN", CURL_VERSION_IDN},
- {"IPv6", CURL_VERSION_IPV6},
- {"Largefile", CURL_VERSION_LARGEFILE},
- {"NTLM", CURL_VERSION_NTLM},
- {"SPNEGO", CURL_VERSION_SPNEGO},
- {"SSL", CURL_VERSION_SSL},
- {"SSPI", CURL_VERSION_SSPI},
- {"krb4", CURL_VERSION_KERBEROS4},
- {"libz", CURL_VERSION_LIBZ},
- {"CharConv", CURL_VERSION_CONV},
- {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}
- };
- printf("Features: ");
- for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
- if(curlinfo->features & feats[i].bitmask)
- printf("%s ", feats[i].name);
- }
- puts(""); /* newline */
- }
- }
- return PARAM_HELP_REQUESTED;
- case 'w':
- /* get the output string */
- if('@' == *nextarg) {
- /* the data begins with a '@' letter, it means that a file name
- or - (stdin) follows */
- FILE *file;
- const char *fname;
- nextarg++; /* pass the @ */
- if(curlx_strequal("-", nextarg)) {
- fname = "<stdin>";
- file = stdin;
- }
- else {
- fname = nextarg;
- file = fopen(nextarg, "r");
- }
- err = file2string(&config->writeout, file);
- if(file && (file != stdin))
- fclose(file);
- if(err)
- return err;
- if(!config->writeout)
- warnf(config, "Failed to read %s", fname);
- }
- else
- GetStr(&config->writeout, nextarg);
- break;
- case 'x':
- /* proxy */
- GetStr(&config->proxy, nextarg);
- config->proxyver = CURLPROXY_HTTP;
- break;
- case 'X':
- /* set custom request */
- GetStr(&config->customrequest, nextarg);
- break;
- case 'y':
- /* low speed time */
- if(str2num(&config->low_speed_time, nextarg))
- return PARAM_BAD_NUMERIC;
- if(!config->low_speed_limit)
- config->low_speed_limit = 1;
- break;
- case 'Y':
- /* low speed limit */
- if(str2num(&config->low_speed_limit, nextarg))
- return PARAM_BAD_NUMERIC;
- if(!config->low_speed_time)
- config->low_speed_time=30;
- break;
- case 'z': /* time condition coming up */
- switch(*nextarg) {
- case '+':
- nextarg++;
- default:
- /* If-Modified-Since: (section 14.28 in RFC2068) */
- config->timecond = CURL_TIMECOND_IFMODSINCE;
- break;
- case '-':
- /* If-Unmodified-Since: (section 14.24 in RFC2068) */
- config->timecond = CURL_TIMECOND_IFUNMODSINCE;
- nextarg++;
- break;
- case '=':
- /* Last-Modified: (section 14.29 in RFC2068) */
- config->timecond = CURL_TIMECOND_LASTMOD;
- nextarg++;
- break;
- }
- now=time(NULL);
- config->condtime=curl_getdate(nextarg, &now);
- if(-1 == (int)config->condtime) {
- /* now let's see if it is a file name to get the time from instead! */
- struct_stat statbuf;
- if(-1 == stat(nextarg, &statbuf)) {
- /* failed, remove time condition */
- config->timecond = CURL_TIMECOND_NONE;
- warnf(config,
- "Illegal date format for -z/--timecond (and not "
- "a file name). Disabling time condition. "
- "See curl_getdate(3) for valid date syntax.\n");
- }
- else {
- /* pull the time out from the file */
- config->condtime = statbuf.st_mtime;
- }
- }
- break;
- default: /* unknown flag */
- return PARAM_OPTION_UNKNOWN;
- }
- hit = -1;
-
- } while(!longopt && !singleopt && *++parse && !*usedarg);
-
- return PARAM_OK;
-}
-
-/*
- * Copies the string from line to the buffer at param, unquoting
- * backslash-quoted characters and NUL-terminating the output string.
- * Stops at the first non-backslash-quoted double quote character or the
- * end of the input string. param must be at least as long as the input
- * string. Returns the pointer after the last handled input character.
- */
-static const char *unslashquote(const char *line, char *param)
-{
- while(*line && (*line != '\"')) {
- if(*line == '\\') {
- char out;
- line++;
-
- /* default is to output the letter after the backslash */
- switch(out = *line) {
- case '\0':
- continue; /* this'll break out of the loop */
- case 't':
- out='\t';
- break;
- case 'n':
- out='\n';
- break;
- case 'r':
- out='\r';
- break;
- case 'v':
- out='\v';
- break;
- }
- *param++=out;
- line++;
- }
- else
- *param++=*line++;
- }
- *param=0; /* always zero terminate */
- return line;
-}
-
-/* return 0 on everything-is-fine, and non-zero otherwise */
-static int parseconfig(const char *filename,
- struct Configurable *config)
-{
- int res;
- FILE *file;
- char filebuffer[512];
- bool usedarg;
- char *home;
- int rc = 0;
-
- if(!filename || !*filename) {
- /* NULL or no file name attempts to load .curlrc from the homedir! */
-
-#define CURLRC DOT_CHAR "curlrc"
-
-#ifndef __AMIGA__
- filename = CURLRC; /* sensible default */
- home = homedir(); /* portable homedir finder */
- if(home) {
- if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
- snprintf(filebuffer, sizeof(filebuffer),
- "%s%s%s", home, DIR_CHAR, CURLRC);
-
-#ifdef WIN32
- /* Check if the file exists - if not, try CURLRC in the same
- * directory as our executable
- */
- file = fopen(filebuffer, "r");
- if(file != NULL) {
- fclose(file);
- filename = filebuffer;
- }
- else {
- /* Get the filename of our executable. GetModuleFileName is
- * already declared via inclusions done in setup header file.
- * We assume that we are using the ASCII version here.
- */
- int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
- if(n > 0 && n < (int)sizeof(filebuffer)) {
- /* We got a valid filename - get the directory part */
- char *lastdirchar = strrchr(filebuffer, '\\');
- if(lastdirchar) {
- size_t remaining;
- *lastdirchar = 0;
- /* If we have enough space, build the RC filename */
- remaining = sizeof(filebuffer) - strlen(filebuffer);
- if(strlen(CURLRC) < remaining - 1) {
- snprintf(lastdirchar, remaining,
- "%s%s", DIR_CHAR, CURLRC);
- /* Don't bother checking if it exists - we do
- * that later
- */
- filename = filebuffer;
- }
- }
- }
- }
-#else /* WIN32 */
- filename = filebuffer;
-#endif /* WIN32 */
- }
- free(home); /* we've used it, now free it */
- }
-
-# else /* __AMIGA__ */
- /* On AmigaOS all the config files are into env:
- */
- filename = "ENV:" CURLRC;
-
-#endif
- }
-
- if(strcmp(filename,"-"))
- file = fopen(filename, "r");
- else
- file = stdin;
-
- if(file) {
- char *line;
- char *aline;
- char *option;
- char *param;
- int lineno=0;
- bool alloced_param;
-
-#define ISSEP(x) (((x)=='=') || ((x) == ':'))
-
- while(NULL != (aline = my_get_line(file))) {
- lineno++;
- line = aline;
- alloced_param=FALSE;
-
- /* line with # in the first non-blank column is a comment! */
- while(*line && ISSPACE(*line))
- line++;
-
- switch(*line) {
- case '#':
- case '/':
- case '\r':
- case '\n':
- case '*':
- case '\0':
- free(aline);
- continue;
- }
-
- /* the option keywords starts here */
- option = line;
- while(*line && !ISSPACE(*line) && !ISSEP(*line))
- line++;
- /* ... and has ended here */
-
- if(*line)
- *line++=0; /* zero terminate, we have a local copy of the data */
-
-#ifdef DEBUG_CONFIG
- fprintf(stderr, "GOT: %s\n", option);
-#endif
-
- /* pass spaces and separator(s) */
- while(*line && (ISSPACE(*line) || ISSEP(*line)))
- line++;
-
- /* the parameter starts here (unless quoted) */
- if(*line == '\"') {
- /* quoted parameter, do the quote dance */
- line++;
- param=malloc(strlen(line)+1); /* parameter */
- if(!param) {
- /* out of memory */
- free(aline);
- rc = 1;
- break;
- }
- alloced_param=TRUE;
- (void)unslashquote(line, param);
- }
- else {
- param=line; /* parameter starts here */
- while(*line && !ISSPACE(*line))
- line++;
- *line=0; /* zero terminate */
- }
-
- if(param && !*param) {
- /* do this so getparameter can check for required parameters.
- Otherwise it always thinks there's a parameter. */
- if(alloced_param)
- free(param);
- param = NULL;
- }
-
-#ifdef DEBUG_CONFIG
- fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
-#endif
- res = getparameter(option, param, &usedarg, config);
-
- if(param && *param && !usedarg)
- /* we passed in a parameter that wasn't used! */
- res = PARAM_GOT_EXTRA_PARAMETER;
-
- if(res != PARAM_OK) {
- /* the help request isn't really an error */
- if(!strcmp(filename, "-")) {
- filename=(char *)"<stdin>";
- }
- if(PARAM_HELP_REQUESTED != res) {
- const char *reason = param2text(res);
- warnf(config, "%s:%d: warning: '%s' %s\n",
- filename, lineno, option, reason);
- }
- }
-
- if(alloced_param) {
- free(param);
- param = NULL;
- }
-
- free(aline);
- }
- if(file != stdin)
- fclose(file);
- }
- else
- rc = 1; /* couldn't open the file */
- return rc;
-}
-
-static void go_sleep(long ms)
-{
-#ifdef HAVE_POLL_FINE
- /* portable subsecond "sleep" */
- poll((void *)0, 0, (int)ms);
-#else
- /* systems without poll() need other solutions */
-
-#ifdef WIN32
- /* Windows offers a millisecond sleep */
- Sleep(ms);
-#elif defined(MSDOS)
- delay(ms);
-#else
- /* Other systems must use select() for this */
- struct timeval timeout;
-
- timeout.tv_sec = ms/1000;
- ms = ms%1000;
- timeout.tv_usec = ms * 1000;
-
- select(0, NULL, NULL, NULL, &timeout);
-#endif
-
-#endif
-}
-
-static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
-{
- size_t rc;
- struct OutStruct *out=(struct OutStruct *)stream;
- struct Configurable *config = out->config;
-
- /*
- * Once that libcurl has called back my_fwrite() the returned value
- * is checked against the amount that was intended to be written, if
- * it does not match then it fails with CURLE_WRITE_ERROR. So at this
- * point returning a value different from sz*nmemb indicates failure.
- */
- const size_t err_rc = (sz * nmemb) ? 0 : 1;
-
- if(!out->stream) {
- out->bytes = 0; /* nothing written yet */
- if(!out->filename) {
- warnf(config, "Remote filename has no length!\n");
- return err_rc; /* Failure */
- }
-
- if(config->content_disposition) {
- /* don't overwrite existing files */
- FILE* f = fopen(out->filename, "r");
- if(f) {
- fclose(f);
- warnf(config, "Refusing to overwrite %s: %s\n", out->filename,
- strerror(EEXIST));
- return err_rc; /* Failure */
- }
- }
-
- /* open file for writing */
- out->stream=fopen(out->filename, "wb");
- if(!out->stream) {
- warnf(config, "Failed to create the file %s: %s\n", out->filename,
- strerror(errno));
- return err_rc; /* failure */
- }
- }
-
- rc = fwrite(buffer, sz, nmemb, out->stream);
-
- if((sz * nmemb) == rc)
- /* we added this amount of data to the output */
- out->bytes += (sz * nmemb);
-
- if(config->readbusy) {
- config->readbusy = FALSE;
- curl_easy_pause(config->easy, CURLPAUSE_CONT);
- }
-
- if(config->nobuffer) {
- /* disable output buffering */
- int res = fflush(out->stream);
- if(res) {
- /* return a value that isn't the same as sz * nmemb */
- return err_rc; /* failure */
- }
- }
-
- return rc;
-}
-
-struct InStruct {
- int fd;
- struct Configurable *config;
-};
-
-#define MAX_SEEK 2147483647
-
-/*
- * my_seek() is the CURLOPT_SEEKFUNCTION we use
- */
-static int my_seek(void *stream, curl_off_t offset, int whence)
-{
- struct InStruct *in=(struct InStruct *)stream;
-
-#if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
- /* The offset check following here is only interesting if curl_off_t is
- larger than off_t and we are not using the WIN32 large file support
- macros that provide the support to do 64bit seeks correctly */
-
- if(offset > MAX_SEEK) {
- /* Some precaution code to work around problems with different data sizes
- to allow seeking >32bit even if off_t is 32bit. Should be very rare and
- is really valid on weirdo-systems. */
- curl_off_t left = offset;
-
- if(whence != SEEK_SET)
- /* this code path doesn't support other types */
- return 1;
-
- if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
- /* couldn't rewind to beginning */
- return 1;
-
- while(left) {
- long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
- if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
- /* couldn't seek forwards the desired amount */
- return 1;
- left -= step;
- }
- return 0;
- }
-#endif
- if(LSEEK_ERROR == lseek(in->fd, offset, whence))
- /* couldn't rewind, the reason is in errno but errno is just not portable
- enough and we don't actually care that much why we failed. We'll let
- libcurl know that it may try other means if it wants to. */
- return CURL_SEEKFUNC_CANTSEEK;
-
- return 0;
-}
-
-static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
-{
- ssize_t rc;
- struct InStruct *in=(struct InStruct *)userp;
-
- rc = read(in->fd, buffer, sz*nmemb);
- if(rc < 0) {
- if(errno == EAGAIN) {
- errno = 0;
- in->config->readbusy = TRUE;
- return CURL_READFUNC_PAUSE;
- }
- /* since size_t is unsigned we can't return negative values fine */
- rc = 0;
- }
- in->config->readbusy = FALSE;
- return (size_t)rc;
-}
-
-struct ProgressData {
- int calls;
- curl_off_t prev;
- int width;
- FILE *out; /* where to write everything to */
- curl_off_t initial_size;
-};
-
-static int myprogress (void *clientp,
- double dltotal,
- double dlnow,
- double ultotal,
- double ulnow)
-{
- /* The original progress-bar source code was written for curl by Lars Aas,
- and this new edition inherits some of his concepts. */
-
- char line[256];
- char outline[256];
- char format[40];
- double frac;
- double percent;
- int barwidth;
- int num;
- int i;
-
- struct ProgressData *bar = (struct ProgressData *)clientp;
- curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
- bar->initial_size; /* expected transfer size */
- curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
- bar->initial_size; /* we've come this far */
-
- if(point > total)
- /* we have got more than the expected total! */
- total = point;
-
- bar->calls++; /* simply count invokes */
-
- if(total < 1) {
- curl_off_t prevblock = bar->prev / 1024;
- curl_off_t thisblock = point / 1024;
- while(thisblock > prevblock) {
- fprintf( bar->out, "#" );
- prevblock++;
- }
- }
- else {
- frac = (double)point / (double)total;
- percent = frac * 100.0f;
- barwidth = bar->width - 7;
- num = (int) (((double)barwidth) * frac);
- for(i = 0; i < num; i++)
- line[i] = '#';
- line[i] = '\0';
- snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
- snprintf( outline, sizeof(outline), format, line, percent );
- fprintf( bar->out, "\r%s", outline );
- }
- fflush(bar->out);
- bar->prev = point;
-
- return 0;
-}
-
-static
-void progressbarinit(struct ProgressData *bar,
- struct Configurable *config)
-{
-#ifdef __EMX__
- /* 20000318 mgs */
- int scr_size [2];
-#endif
- char *colp;
-
- memset(bar, 0, sizeof(struct ProgressData));
-
- /* pass this through to progress function so
- * it can display progress towards total file
- * not just the part that's left. (21-may-03, dbyron) */
- if(config->use_resume)
- bar->initial_size = config->resume_from;
-
-/* TODO: get terminal width through ansi escapes or something similar.
- try to update width when xterm is resized... - 19990617 larsa */
-#ifndef __EMX__
- /* 20000318 mgs
- * OS/2 users most likely won't have this env var set, and besides that
- * we're using our own way to determine screen width */
- colp = curlx_getenv("COLUMNS");
- if(colp != NULL) {
- char *endptr;
- long num = strtol(colp, &endptr, 10);
- if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0))
- bar->width = (int)num;
- else
- bar->width = 79;
- curl_free(colp);
- }
- else
- bar->width = 79;
-#else
- /* 20000318 mgs
- * We use this emx library call to get the screen width, and subtract
- * one from what we got in order to avoid a problem with the cursor
- * advancing to the next line if we print a string that is as long as
- * the screen is wide. */
-
- _scrsize(scr_size);
- bar->width = scr_size[0] - 1;
-#endif
-
- bar->out = config->errors;
-}
-
-
-static
-void dump(const char *timebuf, const char *text,
- FILE *stream, const unsigned char *ptr, size_t size,
- trace tracetype, curl_infotype infotype)
-{
- size_t i;
- size_t c;
-
- unsigned int width=0x10;
-
- if(tracetype == TRACE_ASCII)
- /* without the hex output, we can fit more on screen */
- width = 0x40;
-
- fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
-
- for(i=0; i<size; i+= width) {
-
- fprintf(stream, "%04zx: ", i);
-
- if(tracetype == TRACE_BIN) {
- /* hex not disabled, show it */
- for(c = 0; c < width; c++)
- if(i+c < size)
- fprintf(stream, "%02x ", ptr[i+c]);
- else
- fputs(" ", stream);
- }
-
- for(c = 0; (c < width) && (i+c < size); c++) {
- /* check for 0D0A; if found, skip past and start a new line of output */
- if((tracetype == TRACE_ASCII) &&
- (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
- i+=(c+2-width);
- break;
- }
-#ifdef CURL_DOES_CONVERSIONS
- /* repeat the 0D0A check above but use the host encoding for CRLF */
- if((tracetype == TRACE_ASCII) &&
- (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') {
- i+=(c+2-width);
- break;
- }
- /* convert to host encoding and print this character */
- fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
-#else
- (void)infotype;
- fprintf(stream, "%c",
- (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR);
-#endif /* CURL_DOES_CONVERSIONS */
- /* check again for 0D0A, to avoid an extra \n if it's at width */
- if((tracetype == TRACE_ASCII) &&
- (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
- i+=(c+3-width);
- break;
- }
- }
- fputc('\n', stream); /* newline */
- }
- fflush(stream);
-}
-
-static
-int my_trace(CURL *handle, curl_infotype type,
- unsigned char *data, size_t size,
- void *userp)
-{
- struct Configurable *config = (struct Configurable *)userp;
- FILE *output=config->errors;
- const char *text;
- struct timeval tv;
- struct tm *now;
- char timebuf[20];
- time_t secs;
- static time_t epoch_offset;
- static int known_offset;
-
- (void)handle; /* prevent compiler warning */
-
- if(config->tracetime) {
- tv = cutil_tvnow();
- if(!known_offset) {
- epoch_offset = time(NULL) - tv.tv_sec;
- known_offset = 1;
- }
- secs = epoch_offset + tv.tv_sec;
- now = localtime(&secs); /* not thread safe but we don't care */
- snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
- now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
- }
- else
- timebuf[0]=0;
-
- if(!config->trace_stream) {
- /* open for append */
- if(curlx_strequal("-", config->trace_dump))
- config->trace_stream = stdout;
- else if(curlx_strequal("%", config->trace_dump))
- /* Ok, this is somewhat hackish but we do it undocumented for now */
- config->trace_stream = config->errors; /* aka stderr */
- else {
- config->trace_stream = fopen(config->trace_dump, "w");
- config->trace_fopened = TRUE;
- }
- }
-
- if(config->trace_stream)
- output = config->trace_stream;
-
- if(!output) {
- warnf(config, "Failed to create/open output");
- return 0;
- }
-
- if(config->tracetype == TRACE_PLAIN) {
- /*
- * This is the trace look that is similar to what libcurl makes on its
- * own.
- */
- static const char * const s_infotype[] = {
- "*", "<", ">", "{", "}", "{", "}"
- };
- size_t i;
- size_t st=0;
- static bool newl = FALSE;
- static bool traced_data = FALSE;
-
- switch(type) {
- case CURLINFO_HEADER_OUT:
- for(i=0; i<size-1; i++) {
- if(data[i] == '\n') { /* LF */
- if(!newl) {
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- }
- (void)fwrite(data+st, i-st+1, 1, output);
- st = i+1;
- newl = FALSE;
- }
- }
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- (void)fwrite(data+st, i-st+1, 1, output);
- newl = (bool)(size && (data[size-1] != '\n'));
- traced_data = FALSE;
- break;
- case CURLINFO_TEXT:
- case CURLINFO_HEADER_IN:
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- (void)fwrite(data, size, 1, output);
- newl = (bool)(size && (data[size-1] != '\n'));
- traced_data = FALSE;
- break;
- case CURLINFO_DATA_OUT:
- case CURLINFO_DATA_IN:
- case CURLINFO_SSL_DATA_IN:
- case CURLINFO_SSL_DATA_OUT:
- if(!traced_data) {
- /* if the data is output to a tty and we're sending this debug trace
- to stderr or stdout, we don't display the alert about the data not
- being shown as the data _is_ shown then just not via this
- function */
- if(!config->isatty ||
- ((output != stderr) && (output != stdout))) {
- if(!newl)
- fprintf(output, "%s%s ", timebuf, s_infotype[type]);
- fprintf(output, "[data not shown]\n");
- newl = FALSE;
- traced_data = TRUE;
- }
- }
- break;
- default: /* nada */
- newl = FALSE;
- traced_data = FALSE;
- break;
- }
-
- return 0;
- }
-
-#ifdef CURL_DOES_CONVERSIONS
- /* Special processing is needed for CURLINFO_HEADER_OUT blocks
- * if they contain both headers and data (separated by CRLFCRLF).
- * We dump the header text and then switch type to CURLINFO_DATA_OUT.
- */
- if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
- size_t i;
- for(i = 0; i < size - 4; i++) {
- if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
- /* dump everything through the CRLFCRLF as a sent header */
- text = "=> Send header";
- dump(timebuf, text, output, data, i+4, config->tracetype, type);
- data += i + 3;
- size -= i + 4;
- type = CURLINFO_DATA_OUT;
- data += 1;
- break;
- }
- }
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- switch (type) {
- case CURLINFO_TEXT:
- fprintf(output, "%s== Info: %s", timebuf, data);
- default: /* in case a new one is introduced to shock us */
- return 0;
-
- case CURLINFO_HEADER_OUT:
- text = "=> Send header";
- break;
- case CURLINFO_DATA_OUT:
- text = "=> Send data";
- break;
- case CURLINFO_HEADER_IN:
- text = "<= Recv header";
- break;
- case CURLINFO_DATA_IN:
- text = "<= Recv data";
- break;
- case CURLINFO_SSL_DATA_IN:
- text = "<= Recv SSL data";
- break;
- case CURLINFO_SSL_DATA_OUT:
- text = "=> Send SSL data";
- break;
- }
-
- dump(timebuf, text, output, data, size, config->tracetype, type);
- return 0;
-}
-
-static void free_config_fields(struct Configurable *config)
-{
- if(config->random_file)
- free(config->random_file);
- if(config->egd_file)
- free(config->egd_file);
- if(config->trace_dump)
- free(config->trace_dump);
- if(config->cipher_list)
- free(config->cipher_list);
- if(config->userpwd)
- free(config->userpwd);
- if(config->postfields)
- free(config->postfields);
- if(config->proxy)
- free(config->proxy);
- if(config->proxyuserpwd)
- free(config->proxyuserpwd);
- if(config->noproxy)
- free(config->noproxy);
- if(config->cookie)
- free(config->cookie);
- if(config->cookiefile)
- free(config->cookiefile);
- if(config->krblevel)
- free(config->krblevel);
- if(config->headerfile)
- free(config->headerfile);
- if(config->ftpport)
- free(config->ftpport);
- if(config->range)
- free(config->range);
- if(config->customrequest)
- free(config->customrequest);
- if(config->writeout)
- free(config->writeout);
- if(config->httppost)
- curl_formfree(config->httppost);
- if(config->netrc_file)
- free(config->netrc_file);
- if(config->cert)
- free(config->cert);
- if(config->cacert)
- free(config->cacert);
- if(config->cert_type)
- free(config->cert_type);
- if(config->capath)
- free(config->capath);
- if(config->crlfile)
- free(config->crlfile);
- if(config->cookiejar)
- free(config->cookiejar);
- if(config->ftp_account)
- free(config->ftp_account);
- if(config->ftp_alternative_to_user)
- free(config->ftp_alternative_to_user);
- if(config->iface)
- free(config->iface);
- if(config->socksproxy)
- free(config->socksproxy);
- if(config->libcurl)
- free(config->libcurl);
- if(config->key_passwd)
- free(config->key_passwd);
- if(config->key)
- free(config->key);
- if(config->key_type)
- free(config->key_type);
- if(config->pubkey)
- free(config->pubkey);
- if(config->referer)
- free(config->referer);
- if(config->hostpubmd5)
- free(config->hostpubmd5);
- if(config->mail_from)
- free(config->mail_from);
-#ifdef USE_TLS_SRP
- if(config->tls_authtype)
- free(config->tls_authtype);
- if(config->tls_username)
- free(config->tls_username);
- if(config->tls_password)
- free(config->tls_password);
-#endif
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- if(config->socks5_gssapi_service)
- free(config->socks5_gssapi_service);
-#endif
-
- curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
- curl_slist_free_all(config->prequote);
- curl_slist_free_all(config->postquote);
- curl_slist_free_all(config->headers);
- curl_slist_free_all(config->telnet_options);
- curl_slist_free_all(config->mail_rcpt);
- curl_slist_free_all(config->resolve);
-
- if(config->easy)
- curl_easy_cleanup(config->easy);
-}
-
-#ifdef WIN32
-
-/* Function to find CACert bundle on a Win32 platform using SearchPath.
- * (SearchPath is already declared via inclusions done in setup header file)
- * (Use the ASCII version instead of the unicode one!)
- * The order of the directories it searches is:
- * 1. application's directory
- * 2. current working directory
- * 3. Windows System directory (e.g. C:\windows\system32)
- * 4. Windows Directory (e.g. C:\windows)
- * 5. all directories along %PATH%
- */
-static void FindWin32CACert(struct Configurable *config,
- const char *bundle_file)
-{
- /* only check for cert file if "we" support SSL */
- if(curlinfo->features & CURL_VERSION_SSL) {
- DWORD buflen;
- char *ptr = NULL;
- char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1));
- if(!retval)
- return;
- retval[0] = '\0';
- buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
- if(buflen > 0) {
- GetStr(&config->cacert, retval);
- }
- free(retval);
- }
-}
-
-#endif
-
-#define RETRY_SLEEP_DEFAULT 1000 /* ms */
-#define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */
-
-static bool
-output_expected(const char* url, const char* uploadfile)
-{
- if(!uploadfile)
- return TRUE; /* download */
- if(checkprefix("http://", url) || checkprefix("https://", url))
- return TRUE; /* HTTP(S) upload */
-
- return FALSE; /* non-HTTP upload, probably no output should be expected */
-}
-
-#define my_setopt(x,y,z) _my_setopt(x, FALSE, config, #y, y, z)
-#define my_setopt_str(x,y,z) _my_setopt(x, TRUE, config, #y, y, z)
-
-static struct curl_slist *easycode;
-static struct curl_slist *easycode_remarks;
-
-static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
- const char *name, CURLoption tag, ...);
-
-static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
- const char *name, CURLoption tag, ...)
-{
- va_list arg;
- CURLcode ret;
- char *bufp;
- char value[256];
- bool remark=FALSE;
- bool skip=FALSE;
-
- va_start(arg, tag);
-
- if(tag < CURLOPTTYPE_OBJECTPOINT) {
- long lval = va_arg(arg, long);
- snprintf(value, sizeof(value), "%ldL", lval);
- ret = curl_easy_setopt(curl, tag, lval);
- if(!lval)
- skip = TRUE;
- }
- else if(tag < CURLOPTTYPE_OFF_T) {
- void *pval = va_arg(arg, void *);
- unsigned char *ptr = (unsigned char *)pval;
-
- /* function pointers are never printable */
- if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
- if(pval) {
- strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */
- remark = TRUE;
- }
- else
- skip = TRUE;
- }
-
- else if(pval && str)
- snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
- else if(pval) {
- strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */
- remark = TRUE;
- }
- else
- skip = TRUE;
-
- ret = curl_easy_setopt(curl, tag, pval);
-
- }
- else {
- curl_off_t oval = va_arg(arg, curl_off_t);
- snprintf(value, sizeof(value),
- "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
- ret = curl_easy_setopt(curl, tag, oval);
-
- if(!oval)
- skip = TRUE;
- }
-
- if(config->libcurl && !skip) {
- /* we only use this for real if --libcurl was used */
-
- if(remark)
- bufp = curlx_maprintf("%s set to a %s", name, value);
- else
- bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value);
-
- if(!bufp)
- ret = CURLE_OUT_OF_MEMORY;
- else {
- struct curl_slist *list =
- curl_slist_append(remark?easycode_remarks:easycode, bufp);
-
- if(remark)
- easycode_remarks = list;
- else
- easycode = list;
- }
- if(bufp)
- curl_free(bufp);
- }
- va_end(arg);
-
- return ret;
-}
-
-static const char * const srchead[]={
- "/********* Sample code generated by the curl command line tool **********",
- " * All curl_easy_setopt() options are documented at:",
- " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html",
- " ************************************************************************/",
- "#include <curl/curl.h>",
- "",
- "int main(int argc, char *argv[])",
- "{",
- " CURLcode ret;",
- NULL
-};
-
-static void dumpeasycode(struct Configurable *config)
-{
- struct curl_slist *ptr;
- char *o = config->libcurl;
-
- if(o) {
- FILE *out;
- bool fopened = FALSE;
- if(strcmp(o, "-")) {
- out = fopen(o, "wt");
- fopened = TRUE;
- }
- else
- out= stdout;
- if(!out)
- warnf(config, "Failed to open %s to write libcurl code!\n", o);
- else {
- int i;
- const char *c;
-
- for(i=0; ((c = srchead[i]) != '\0'); i++)
- fprintf(out, "%s\n", c);
-
- ptr = easycode;
- while(ptr) {
- fprintf(out, " %s\n", ptr->data);
- ptr = ptr->next;
- }
-
- ptr = easycode_remarks;
- if(ptr) {
- fprintf(out,
- "\n /* Here is a list of options the curl code"
- " used that cannot get generated\n"
- " as source easily. You may select to either"
- " not use them or implement\n them yourself.\n"
- "\n");
- while(ptr) {
- fprintf(out, " %s\n", ptr->data);
- ptr = ptr->next;
- }
- fprintf(out, "\n */\n");
- }
-
- fprintf(out,
- " return (int)ret;\n"
- "}\n"
- "/**** End of sample code ****/\n");
- if(fopened)
- fclose(out);
- }
- }
- curl_slist_free_all(easycode);
-}
-
-static bool stdin_upload(const char *uploadfile)
-{
- return (bool)(curlx_strequal(uploadfile, "-") ||
- curlx_strequal(uploadfile, "."));
-}
-
-/* Adds the file name to the URL if it doesn't already have one.
- * url will be freed before return if the returned pointer is different
- */
-static char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
-{
- /* If no file name part is given in the URL, we add this file name */
- char *ptr=strstr(url, "://");
- if(ptr)
- ptr+=3;
- else
- ptr=url;
- ptr = strrchr(ptr, '/');
- if(!ptr || !strlen(++ptr)) {
- /* The URL has no file name part, add the local file name. In order
- to be able to do so, we have to create a new URL in another
- buffer.*/
-
- /* We only want the part of the local path that is on the right
- side of the rightmost slash and backslash. */
- const char *filep = strrchr(filename, '/');
- char *file2 = strrchr(filep?filep:filename, '\\');
- char *encfile;
-
- if(file2)
- filep = file2+1;
- else if(filep)
- filep++;
- else
- filep = filename;
-
- /* URL encode the file name */
- encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
- if(encfile) {
- char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
- if(!urlbuffer) {
- free(url);
- return NULL;
- }
- if(ptr)
- /* there is a trailing slash on the URL */
- sprintf(urlbuffer, "%s%s", url, encfile);
- else
- /* there is no trailing slash on the URL */
- sprintf(urlbuffer, "%s/%s", url, encfile);
-
- curl_free(encfile);
-
- free(url);
- url = urlbuffer; /* use our new URL instead! */
- }
- }
- return url;
-}
-
-/* Extracts the name portion of the URL.
- * Returns a heap-allocated string, or NULL if no name part
- */
-static char *get_url_file_name(const char *url)
-{
- char *fn = NULL;
-
- /* Find and get the remote file name */
- const char * pc =strstr(url, "://");
- if(pc)
- pc+=3;
- else
- pc=url;
- pc = strrchr(pc, '/');
-
- if(pc) {
- /* duplicate the string beyond the slash */
- pc++;
- fn = *pc ? strdup(pc): NULL;
- }
- return fn;
-}
-
-static char*
-parse_filename(char *ptr, size_t len)
-{
- char* copy;
- char* p;
- char* q;
- char quote = 0;
-
- /* simple implementation of strndup() */
- copy = malloc(len+1);
- if(!copy)
- return NULL;
- strncpy(copy, ptr, len);
- copy[len] = 0;
-
- p = copy;
- if(*p == '\'' || *p == '"') {
- /* store the starting quote */
- quote = *p;
- p++;
- }
-
- /* if the filename contains a path, only use filename portion */
- q = strrchr(copy, '/');
- if(q) {
- p=q+1;
- if(!*p) {
- free(copy);
- return NULL;
- }
- }
-
- /* If the filename contains a backslash, only use filename portion. The idea
- is that even systems that don't handle backslashes as path separators
- probably want the path removed for convenience. */
- q = strrchr(p, '\\');
- if(q) {
- p = q+1;
- if(!*p) {
- free(copy);
- return NULL;
- }
- }
-
- if(quote) {
- /* if the file name started with a quote, then scan for the end quote and
- stop there */
- q = strrchr(p, quote);
- if(q)
- *q = 0;
- }
- else
- q = NULL; /* no start quote, so no end has been found */
-
- if(!q) {
- /* make sure the file name doesn't end in \r or \n */
- q = strchr(p, '\r');
- if(q)
- *q = 0;
-
- q = strchr(p, '\n');
- if(q)
- *q = 0;
- }
-
- if(copy!=p)
- memmove(copy, p, strlen(p)+1);
-
- return copy;
-}
-
-static size_t
-header_callback(void *ptr, size_t size, size_t nmemb, void *stream)
-{
- struct OutStruct* outs = (struct OutStruct*)stream;
- const char* str = (char*)ptr;
- const size_t cb = size*nmemb;
- const char* end = (char*)ptr + cb;
- size_t len;
-
- if(cb > 20 && checkprefix("Content-disposition:", str)) {
- char *p = (char*)str + 20;
-
- /* look for the 'filename=' parameter
- (encoded filenames (*=) are not supported) */
- for(;;) {
- char *filename;
- char *semi;
-
- while(*p && (p < end) && !ISALPHA(*p))
- p++;
- if(p > end-9)
- break;
-
- if(memcmp(p, "filename=", 9)) {
- /* no match, find next parameter */
- while((p < end) && (*p != ';'))
- p++;
- continue;
- }
- p+=9;
- semi = strchr(p, ';');
-
- /* this expression below typecasts 'cb' only to avoid
- warning: signed and unsigned type in conditional expression
- */
- len = semi ? (semi - p) : (ssize_t)cb - (p - str);
- filename = parse_filename(p, len);
- if(filename) {
- outs->filename = filename;
- break;
- }
- }
- }
-
- return cb;
-}
-
-static int
-operate(struct Configurable *config, int argc, argv_item_t argv[])
-{
- char errorbuffer[CURL_ERROR_SIZE];
- char useragent[256]; /* buah, we don't want a larger default user agent */
- struct ProgressData progressbar;
- struct getout *urlnode;
- struct getout *nextnode;
-
- struct OutStruct outs;
- struct OutStruct heads;
- struct InStruct input;
-
- URLGlob *urls=NULL;
- URLGlob *inglob=NULL;
- int urlnum;
- int infilenum;
- char *uploadfile=NULL; /* a single file, never a glob */
-
- curl_off_t uploadfilesize; /* -1 means unknown */
- bool stillflags=TRUE;
-
- bool allocuseragent=FALSE;
-
- char *httpgetfields=NULL;
-
- CURL *curl;
- int res = 0;
- int i;
- long retry_sleep_default;
- long retry_sleep;
-
- char *env;
-
- memset(&heads, 0, sizeof(struct OutStruct));
-
-#ifdef CURLDEBUG
- /* this sends all memory debug messages to a logfile named memdump */
- env = curlx_getenv("CURL_MEMDEBUG");
- if(env) {
- /* use the value as file name */
- char *s = strdup(env);
- curl_free(env);
- curl_memdebug(s);
- free(s);
- /* this weird strdup() and stuff here is to make the curl_free() get
- called before the memdebug() as otherwise the memdebug tracing will
- with tracing a free() without an alloc! */
- }
- env = curlx_getenv("CURL_MEMLIMIT");
- if(env) {
- char *endptr;
- long num = strtol(env, &endptr, 10);
- if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
- curl_memlimit(num);
- curl_free(env);
- }
-#endif
-
- /* Initialize curl library - do not call any libcurl functions before.
- Note that the CURLDEBUG magic above is an exception, but then that's not
- part of the official public API.
- */
- if(main_init() != CURLE_OK) {
- helpf(config->errors, "error initializing curl library\n");
- return CURLE_FAILED_INIT;
- }
-
- /*
- * Get a curl handle to use for all forthcoming curl transfers. Cleanup
- * when all transfers are done.
- */
- curl = curl_easy_init();
- if(!curl) {
- clean_getout(config);
- return CURLE_FAILED_INIT;
- }
- config->easy = curl;
-
- memset(&outs,0,sizeof(outs));
-
- config->outs = &outs;
-
- /* we get libcurl info right away */
- curlinfo = curl_version_info(CURLVERSION_NOW);
-
- errorbuffer[0]=0; /* prevent junk from being output */
-
- /* setup proper locale from environment */
-#ifdef HAVE_SETLOCALE
- setlocale(LC_ALL, "");
-#endif
-
- /* inits */
- config->postfieldsize = -1;
- config->showerror=TRUE;
- config->use_httpget=FALSE;
- config->create_dirs=FALSE;
- config->maxredirs = DEFAULT_MAXREDIRS;
- config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
- config->proto_present = FALSE;
- config->proto_redir =
- CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
- config->proto_redir_present = FALSE;
-
- if(argc>1 &&
- (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
- strchr(argv[1], 'q')) {
- /*
- * The first flag, that is not a verbose name, but a shortname
- * and it includes the 'q' flag!
- */
- ;
- }
- else {
- parseconfig(NULL, config); /* ignore possible failure */
- }
-
- if((argc < 2) && !config->url_list) {
- helpf(config->errors, NULL);
- return CURLE_FAILED_INIT;
- }
-
- /* Parse options */
- for(i = 1; i < argc; i++) {
- if(stillflags &&
- ('-' == argv[i][0])) {
- char *nextarg;
- bool passarg;
- char *origopt=argv[i];
-
- char *flag = argv[i];
-
- if(curlx_strequal("--", argv[i]))
- /* this indicates the end of the flags and thus enables the
- following (URL) argument to start with -. */
- stillflags=FALSE;
- else {
- nextarg= (i < argc - 1)? argv[i+1]: NULL;
-
- res = getparameter(flag, nextarg, &passarg, config);
- if(res) {
- int retval = CURLE_OK;
- if(res != PARAM_HELP_REQUESTED) {
- const char *reason = param2text(res);
- helpf(config->errors, "option %s: %s\n", origopt, reason);
- retval = CURLE_FAILED_INIT;
- }
- clean_getout(config);
- return retval;
- }
-
- if(passarg) /* we're supposed to skip this */
- i++;
- }
- }
- else {
- bool used;
- /* just add the URL please */
- res = getparameter((char *)"--url", argv[i], &used, config);
- if(res)
- return res;
- }
- }
-
- retry_sleep_default = config->retry_delay?
- config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
- retry_sleep = retry_sleep_default;
-
- if((!config->url_list || !config->url_list->url) && !config->list_engines) {
- clean_getout(config);
- helpf(config->errors, "no URL specified!\n");
- return CURLE_FAILED_INIT;
- }
- if(NULL == config->useragent) {
- /* set non-zero default values: */
- snprintf(useragent, sizeof(useragent),
- CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
- config->useragent= useragent;
- }
- else
- allocuseragent = TRUE;
-
- /* On WIN32 we can't set the path to curl-ca-bundle.crt
- * at compile time. So we look here for the file in two ways:
- * 1: look at the environment variable CURL_CA_BUNDLE for a path
- * 2: if #1 isn't found, use the windows API function SearchPath()
- * to find it along the app's path (includes app's dir and CWD)
- *
- * We support the environment variable thing for non-Windows platforms
- * too. Just for the sake of it.
- */
- if(!config->cacert &&
- !config->capath &&
- !config->insecure_ok) {
- env = curlx_getenv("CURL_CA_BUNDLE");
- if(env)
- GetStr(&config->cacert, env);
- else {
- env = curlx_getenv("SSL_CERT_DIR");
- if(env)
- GetStr(&config->capath, env);
- else {
- env = curlx_getenv("SSL_CERT_FILE");
- if(env)
- GetStr(&config->cacert, env);
- }
- }
-
- if(env)
- curl_free(env);
-#ifdef WIN32
- else
- FindWin32CACert(config, "curl-ca-bundle.crt");
-#endif
- }
-
- if(config->postfields) {
- if(config->use_httpget) {
- /* Use the postfields data for a http get */
- httpgetfields = strdup(config->postfields);
- free(config->postfields);
- config->postfields = NULL;
- if(SetHTTPrequest(config,
- (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
- &config->httpreq)) {
- free(httpgetfields);
- return PARAM_BAD_USE;
- }
- }
- else {
- if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
- return PARAM_BAD_USE;
- }
- }
-
- /* This is the first entry added to easycode and it initializes the slist */
- easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();");
- if(!easycode) {
- clean_getout(config);
- res = CURLE_OUT_OF_MEMORY;
- goto quit_curl;
- }
-
- if(config->list_engines) {
- struct curl_slist *engines = NULL;
-
- curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
- list_engines(engines);
- curl_slist_free_all(engines);
- res = CURLE_OK;
- goto quit_curl;
- }
-
- /* After this point, we should call curl_easy_cleanup() if we decide to bail
- * out from this function! */
-
- urlnode = config->url_list;
-
- if(config->headerfile) {
- /* open file for output: */
- if(strcmp(config->headerfile,"-")) {
- heads.filename = config->headerfile;
- }
- else
- heads.stream=stdout;
- heads.config = config;
- }
-
- /* loop through the list of given URLs */
- while(urlnode) {
- int up; /* upload file counter within a single upload glob */
- char *dourl;
- char *url;
- char *infiles; /* might be a glob pattern */
- char *outfiles=NULL;
-
- /* get the full URL (it might be NULL) */
- dourl=urlnode->url;
-
- url = dourl;
-
- if(NULL == url) {
- /* This node had no URL, skip it and continue to the next */
- if(urlnode->outfile)
- free(urlnode->outfile);
-
- /* move on to the next URL */
- nextnode=urlnode->next;
- free(urlnode); /* free the node */
- urlnode = nextnode;
- continue; /* next please */
- }
-
- /* default output stream is stdout */
- outs.stream = stdout;
- outs.config = config;
- outs.bytes = 0; /* nothing written yet */
-
- /* save outfile pattern before expansion */
- if(urlnode->outfile) {
- outfiles = strdup(urlnode->outfile);
- if(!outfiles) {
- clean_getout(config);
- break;
- }
- }
-
- infiles = urlnode->infile;
-
- if(!config->globoff && infiles) {
- /* Unless explicitly shut off */
- res = glob_url(&inglob, infiles, &infilenum,
- config->showerror?config->errors:NULL);
- if(res != CURLE_OK) {
- clean_getout(config);
- if(outfiles)
- free(outfiles);
- break;
- }
- }
-
- /* Here's the loop for uploading multiple files within the same
- single globbed string. If no upload, we enter the loop once anyway. */
- for(up = 0;
- (!up && !infiles) ||
- ((uploadfile = inglob?
- glob_next_url(inglob):
- (!up?strdup(infiles):NULL)) != NULL);
- up++) {
- int separator = 0;
- long retry_numretries;
- uploadfilesize=-1;
-
- if(!config->globoff) {
- /* Unless explicitly shut off, we expand '{...}' and '[...]'
- expressions and return total number of URLs in pattern set */
- res = glob_url(&urls, dourl, &urlnum,
- config->showerror?config->errors:NULL);
- if(res != CURLE_OK) {
- break;
- }
- }
- else
- urlnum = 1; /* without globbing, this is a single URL */
-
- /* if multiple files extracted to stdout, insert separators! */
- separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
-
- /* Here's looping around each globbed URL */
- for(i = 0;
- ((url = urls?glob_next_url(urls):(i?NULL:strdup(url))) != NULL);
- i++) {
- /* NOTE: In the condition expression in the for() statement above, the
- 'url' variable is only ever strdup()ed if(i == 0) and thus never
- when this loops later on. Further down in this function we call
- free(url) and then the code loops. Static code parsers may thus get
- tricked into believing that we have a potential access-after-free
- here. I can however not spot any such case. */
-
- int infd = STDIN_FILENO;
- bool infdopen;
- char *outfile;
- struct timeval retrystart;
- outfile = outfiles?strdup(outfiles):NULL;
-
- if((urlnode->flags&GETOUT_USEREMOTE) ||
- (outfile && !curlx_strequal("-", outfile)) ) {
-
- /*
- * We have specified a file name to store the result in, or we have
- * decided we want to use the remote file name.
- */
-
- if(!outfile) {
- /* extract the file name from the URL */
- outfile = get_url_file_name(url);
- if((!outfile || !*outfile) && !config->content_disposition) {
- helpf(config->errors, "Remote file name has no length!\n");
- res = CURLE_WRITE_ERROR;
- free(url);
- break;
- }
-#if defined(MSDOS) || defined(WIN32)
- /* For DOS and WIN32, we do some major replacing of
- bad characters in the file name before using it */
- outfile = sanitize_dos_name(outfile);
- if(!outfile) {
- res = CURLE_OUT_OF_MEMORY;
- break;
- }
-#endif /* MSDOS || WIN32 */
- }
- else if(urls) {
- /* fill '#1' ... '#9' terms from URL pattern */
- char *storefile = outfile;
- outfile = glob_match_url(storefile, urls);
- free(storefile);
- if(!outfile) {
- /* bad globbing */
- warnf(config, "bad output glob!\n");
- free(url);
- res = CURLE_FAILED_INIT;
- break;
- }
- }
-
- /* Create the directory hierarchy, if not pre-existent to a multiple
- file output call */
-
- if(config->create_dirs &&
- (-1 == create_dir_hierarchy(outfile, config->errors))) {
- free(url);
- res = CURLE_WRITE_ERROR;
- break;
- }
-
- if(config->resume_from_current) {
- /* We're told to continue from where we are now. Get the
- size of the file as it is now and open it for append instead */
-
- struct_stat fileinfo;
-
- /* VMS -- Danger, the filesize is only valid for stream files */
- if(0 == stat(outfile, &fileinfo))
- /* set offset to current file size: */
- config->resume_from = fileinfo.st_size;
- else
- /* let offset be 0 */
- config->resume_from = 0;
- }
-
- outs.filename = outfile;
-
- if(config->resume_from) {
- outs.init = config->resume_from;
- /* open file for output: */
- outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
- if(!outs.stream) {
- helpf(config->errors, "Can't open '%s'!\n", outfile);
- free(url);
- res = CURLE_WRITE_ERROR;
- break;
- }
- }
- else {
- outs.stream = NULL; /* open when needed */
- outs.bytes = 0; /* reset byte counter */
- }
- }
- infdopen=FALSE;
- if(uploadfile && !stdin_upload(uploadfile)) {
- /*
- * We have specified a file to upload and it isn't "-".
- */
- struct_stat fileinfo;
-
- url = add_file_name_to_url(curl, url, uploadfile);
- if(!url) {
- helpf(config->errors, "out of memory\n");
- res = CURLE_OUT_OF_MEMORY;
- break;
- }
- /* VMS Note:
- *
- * Reading binary from files can be a problem... Only FIXED, VAR
- * etc WITHOUT implied CC will work Others need a \n appended to a
- * line
- *
- * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
- * fixed file with implied CC needs to have a byte added for every
- * record processed, this can by derived from Filesize & recordsize
- * for VARiable record files the records need to be counted! for
- * every record add 1 for linefeed and subtract 2 for the record
- * header for VARIABLE header files only the bare record data needs
- * to be considered with one appended if implied CC
- */
-
- infd= open(uploadfile, O_RDONLY | O_BINARY);
- if((infd == -1) || fstat(infd, &fileinfo)) {
- helpf(config->errors, "Can't open '%s'!\n", uploadfile);
- if(infd != -1)
- close(infd);
-
- /* Free the list of remaining URLs and globbed upload files
- * to force curl to exit immediately
- */
- if(urls) {
- glob_cleanup(urls);
- urls = NULL;
- }
- if(inglob) {
- glob_cleanup(inglob);
- inglob = NULL;
- }
-
- res = CURLE_READ_ERROR;
- goto quit_urls;
- }
- infdopen=TRUE;
-
- /* we ignore file size for char/block devices, sockets, etc. */
- if(S_ISREG(fileinfo.st_mode))
- uploadfilesize=fileinfo.st_size;
-
- }
- else if(uploadfile && stdin_upload(uploadfile)) {
- /* count to see if there are more than one auth bit set
- in the authtype field */
- int authbits = 0;
- int bitcheck = 0;
- while(bitcheck < 32) {
- if(config->authtype & (1 << bitcheck++)) {
- authbits++;
- if(authbits > 1) {
- /* more than one, we're done! */
- break;
- }
- }
- }
-
- /*
- * If the user has also selected --anyauth or --proxy-anyauth
- * we should warn him/her.
- */
- if(config->proxyanyauth || (authbits>1)) {
- warnf(config,
- "Using --anyauth or --proxy-anyauth with upload from stdin"
- " involves a big risk of it not working. Use a temporary"
- " file or a fixed auth type instead!\n");
- }
-
- SET_BINMODE(stdin);
- infd = STDIN_FILENO;
- if(curlx_strequal(uploadfile, ".")) {
- if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
- warnf(config,
- "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
- }
- }
-
- if(uploadfile && config->resume_from_current)
- config->resume_from = -1; /* -1 will then force get-it-yourself */
-
- if(output_expected(url, uploadfile)
- && outs.stream && isatty(fileno(outs.stream)))
- /* we send the output to a tty, therefore we switch off the progress
- meter */
- config->noprogress = config->isatty = TRUE;
-
- if(urlnum > 1 && !(config->mute)) {
- fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
- i+1, urlnum, url, outfile ? outfile : "<stdout>");
- if(separator)
- printf("%s%s\n", CURLseparator, url);
- }
- if(httpgetfields) {
- char *urlbuffer;
- /* Find out whether the url contains a file name */
- const char *pc =strstr(url, "://");
- char sep='?';
- if(pc)
- pc+=3;
- else
- pc=url;
-
- pc = strrchr(pc, '/'); /* check for a slash */
-
- if(pc) {
- /* there is a slash present in the URL */
-
- if(strchr(pc, '?'))
- /* Ouch, there's already a question mark in the URL string, we
- then append the data with an ampersand separator instead! */
- sep='&';
- }
- /*
- * Then append ? followed by the get fields to the url.
- */
- urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
- if(!urlbuffer) {
- helpf(config->errors, "out of memory\n");
-
- /* Free the list of remaining URLs and globbed upload files
- * to force curl to exit immediately
- */
- if(urls) {
- glob_cleanup(urls);
- urls = NULL;
- }
- if(inglob) {
- glob_cleanup(inglob);
- inglob = NULL;
- }
-
- res = CURLE_OUT_OF_MEMORY;
- goto quit_urls;
- }
- if(pc)
- sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
- else
- /* Append / before the ? to create a well-formed url
- if the url contains a hostname only
- */
- sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
-
- free(url); /* free previous URL */
- url = urlbuffer; /* use our new URL instead! */
- }
-
- if(!config->errors)
- config->errors = stderr;
-
- if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
- /* We get the output to stdout and we have not got the ASCII/text
- flag, then set stdout to be binary */
- SET_BINMODE(stdout);
- }
-
- if(1 == config->tcp_nodelay)
- my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
-
- /* where to store */
- my_setopt(curl, CURLOPT_WRITEDATA, &outs);
- /* what call to write */
- my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
-
- /* for uploads */
- input.fd = infd;
- input.config = config;
- my_setopt(curl, CURLOPT_READDATA, &input);
- /* what call to read */
- if((outfile && !curlx_strequal("-", outfile)) ||
- !checkprefix("telnet:", url))
- my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
-
- /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
- CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
- my_setopt(curl, CURLOPT_SEEKDATA, &input);
- my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
-
- if(config->recvpersecond)
- /* tell libcurl to use a smaller sized buffer as it allows us to
- make better sleeps! 7.9.9 stuff! */
- my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
-
- /* size of uploaded file: */
- if(uploadfilesize != -1)
- my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
- my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */
- my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
- if(config->proxy)
- my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
- my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
- if(config->no_body) {
- my_setopt(curl, CURLOPT_NOBODY, 1);
- my_setopt(curl, CURLOPT_HEADER, 1);
- }
- else
- my_setopt(curl, CURLOPT_HEADER, config->include_headers);
-
- my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
- my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
- my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
- my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
-
- if(config->netrc_opt)
- my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
- else if(config->netrc || config->netrc_file)
- my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
- else
- my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
-
- if(config->netrc_file)
- my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file);
-
- my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
- my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth);
- my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
- my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
- my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
- my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
- my_setopt_str(curl, CURLOPT_RANGE, config->range);
- my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
- my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
-
- switch(config->httpreq) {
- case HTTPREQ_SIMPLEPOST:
- my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields);
- my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize);
- break;
- case HTTPREQ_POST:
- my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
- break;
- default:
- break;
- }
- my_setopt_str(curl, CURLOPT_REFERER, config->referer);
- my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
- my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
- my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
- my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
- config->low_speed_limit);
- my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
- my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
- config->sendpersecond);
- my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
- config->recvpersecond);
- my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
- config->use_resume?config->resume_from:0);
- my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
- my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
- my_setopt(curl, CURLOPT_SSLCERT, config->cert);
- my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
- my_setopt(curl, CURLOPT_SSLKEY, config->key);
- my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
- my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
-
- /* SSH private key uses the same command-line option as SSL private
- key */
- my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
- my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
-
- /* SSH host key md5 checking allows us to fail if we are
- * not talking to who we think we should
- */
- my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
- config->hostpubmd5);
-
- /* default to strict verifyhost */
- /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); */
- if(config->cacert || config->capath) {
- if(config->cacert)
- my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
-
- if(config->capath)
- my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
- my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
- }
- if(config->crlfile)
- my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
- if(config->insecure_ok) {
- /* new stuff needed for libcurl 7.10 */
- my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
- my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
- }
- else {
- char *home = homedir();
- char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
- if(home)
- free(home);
-
- if(file) {
- my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
- curl_free(file);
- }
- else {
- /* Free the list of remaining URLs and globbed upload files
- * to force curl to exit immediately
- */
- if(urls) {
- glob_cleanup(urls);
- urls = NULL;
- }
- if(inglob) {
- glob_cleanup(inglob);
- inglob = NULL;
- }
-
- res = CURLE_OUT_OF_MEMORY;
- goto quit_urls;
- }
- }
-
- if(config->no_body || config->remote_time) {
- /* no body or use remote time */
- my_setopt(curl, CURLOPT_FILETIME, TRUE);
- }
-
- my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
- my_setopt(curl, CURLOPT_CRLF, config->crlf);
- my_setopt(curl, CURLOPT_QUOTE, config->quote);
- my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
- my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
- my_setopt(curl, CURLOPT_HEADERDATA,
- config->headerfile?&heads:NULL);
- my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
- /* cookie jar was added in 7.9 */
- if(config->cookiejar)
- my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
- /* cookie session added in 7.9.7 */
- my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
-
- my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
- my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
- my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
- my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
- my_setopt(curl, CURLOPT_STDERR, config->errors);
-
- /* three new ones in libcurl 7.3: */
- my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
- my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
- my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
-
- progressbarinit(&progressbar, config);
- if((config->progressmode == CURL_PROGRESS_BAR) &&
- !config->noprogress && !config->mute) {
- /* we want the alternative style, then we have to implement it
- ourselves! */
- my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
- my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
- }
-
- /* new in libcurl 7.6.2: */
- my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
-
- /* new in libcurl 7.7: */
- my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
- my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
- my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
-
- if(config->cipher_list)
- my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
-
- if(config->httpversion)
- my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
-
- /* new in libcurl 7.9.2: */
- if(config->disable_epsv)
- /* disable it */
- my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
-
- /* new in libcurl 7.10.5 */
- if(config->disable_eprt)
- /* disable it */
- my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
-
- /* new in libcurl 7.10.6 (default is Basic) */
- if(config->authtype)
- my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
-
- if(config->tracetype != TRACE_NONE) {
- my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
- my_setopt(curl, CURLOPT_DEBUGDATA, config);
- my_setopt(curl, CURLOPT_VERBOSE, TRUE);
- }
-
- res = CURLE_OK;
-
- /* new in curl ?? */
- if(config->engine) {
- res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
- my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
- }
-
- if(res != CURLE_OK)
- goto show_error;
-
- if(config->encoding)
- my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
-
- if(config->tr_encoding)
- my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1);
-
- /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
- my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
- config->ftp_create_dirs);
- if(config->proxyanyauth)
- my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
- else if(config->proxynegotiate)
- my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
- else if(config->proxyntlm)
- my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
- else if(config->proxydigest)
- my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
- else if(config->proxybasic)
- my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
-
- /* new in curl 7.10.8 */
- if(config->max_filesize)
- my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
- config->max_filesize);
-
- if(4 == config->ip_version)
- my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- else if(6 == config->ip_version)
- my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
- else
- my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
-
- /* new in curl 7.15.5 */
- if(config->ftp_ssl_reqd)
- my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
-
- /* new in curl 7.11.0 */
- else if(config->ftp_ssl)
- my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
-
- /* new in curl 7.16.0 */
- else if(config->ftp_ssl_control)
- my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
-
- /* new in curl 7.16.1 */
- if(config->ftp_ssl_ccc)
- my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
-
- /* new in curl 7.11.1, modified in 7.15.2 */
- if(config->socksproxy) {
- my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
- my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
- }
-
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- /* new in curl 7.19.4 */
- if(config->socks5_gssapi_service)
- my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
- config->socks5_gssapi_service);
-
- /* new in curl 7.19.4 */
- if(config->socks5_gssapi_nec)
- my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
- config->socks5_gssapi_nec);
-#endif
- /* curl 7.13.0 */
- my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
-
- my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
-
- /* curl 7.14.2 */
- my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
-
- /* curl 7.15.1 */
- my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
-
- /* curl 7.15.2 */
- if(config->localport) {
- my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
- my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
- config->localportrange);
- }
-
- /* curl 7.15.5 */
- my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
- config->ftp_alternative_to_user);
-
- /* curl 7.16.0 */
- if(config->disable_sessionid)
- my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
- !config->disable_sessionid);
-
- /* curl 7.16.2 */
- if(config->raw) {
- my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
- my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
- }
-
- /* curl 7.17.1 */
- if(!config->nokeepalive) {
- my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
- my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
- }
-
- /* curl 7.19.1 (the 301 version existed in 7.18.2) */
- my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
- (config->post302 ? CURL_REDIR_POST_302 : FALSE));
-
- /* curl 7.20.0 */
- if(config->tftp_blksize)
- my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
-
- if(config->mail_from)
- my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
-
- if(config->mail_rcpt)
- my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
-
- /* curl 7.20.x */
- if(config->ftp_pret)
- my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
-
- if(config->proto_present)
- my_setopt(curl, CURLOPT_PROTOCOLS, config->proto);
- if(config->proto_redir_present)
- my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
-
- if((urlnode->flags & GETOUT_USEREMOTE)
- && config->content_disposition) {
- my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
- my_setopt(curl, CURLOPT_HEADERDATA, &outs);
- }
-
- if(config->resolve)
- /* new in 7.21.3 */
- my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
-
- /* TODO: new in ### */
- curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username);
- curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password);
-
- retry_numretries = config->req_retry;
-
- retrystart = cutil_tvnow();
-
- for(;;) {
- res = curl_easy_perform(curl);
- if(!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
- res = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- if(config->content_disposition && outs.stream && !config->mute &&
- outs.filename)
- printf("curl: Saved to filename '%s'\n", outs.filename);
-
- /* if retry-max-time is non-zero, make sure we haven't exceeded the
- time */
- if(retry_numretries &&
- (!config->retry_maxtime ||
- (cutil_tvdiff(cutil_tvnow(), retrystart)<
- config->retry_maxtime*1000)) ) {
- enum {
- RETRY_NO,
- RETRY_TIMEOUT,
- RETRY_HTTP,
- RETRY_FTP,
- RETRY_LAST /* not used */
- } retry = RETRY_NO;
- long response;
- if(CURLE_OPERATION_TIMEDOUT == res)
- /* retry timeout always */
- retry = RETRY_TIMEOUT;
- else if((CURLE_OK == res) ||
- (config->failonerror &&
- (CURLE_HTTP_RETURNED_ERROR == res))) {
- /* If it returned OK. _or_ failonerror was enabled and it
- returned due to such an error, check for HTTP transient
- errors to retry on. */
- char *this_url=NULL;
- curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url);
- if(this_url &&
- checkprefix("http", this_url)) {
- /* This was HTTP(S) */
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
-
- switch(response) {
- case 500: /* Internal Server Error */
- case 502: /* Bad Gateway */
- case 503: /* Service Unavailable */
- case 504: /* Gateway Timeout */
- retry = RETRY_HTTP;
- /*
- * At this point, we have already written data to the output
- * file (or terminal). If we write to a file, we must rewind
- * or close/re-open the file so that the next attempt starts
- * over from the beginning.
- *
- * TODO: similar action for the upload case. We might need
- * to start over reading from a previous point if we have
- * uploaded something when this was returned.
- */
- break;
- }
- }
- } /* if CURLE_OK */
- else if(res) {
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
-
- if(response/100 == 4)
- /*
- * This is typically when the FTP server only allows a certain
- * amount of users and we are not one of them. All 4xx codes
- * are transient.
- */
- retry = RETRY_FTP;
- }
-
- if(retry) {
- static const char * const m[]={
- NULL, "timeout", "HTTP error", "FTP error"
- };
- warnf(config, "Transient problem: %s "
- "Will retry in %ld seconds. "
- "%ld retries left.\n",
- m[retry], retry_sleep/1000, retry_numretries);
-
- go_sleep(retry_sleep);
- retry_numretries--;
- if(!config->retry_delay) {
- retry_sleep *= 2;
- if(retry_sleep > RETRY_SLEEP_MAX)
- retry_sleep = RETRY_SLEEP_MAX;
- }
- if(outs.bytes && outs.filename) {
- /* We have written data to a output file, we truncate file
- */
- if(!config->mute)
- fprintf(config->errors, "Throwing away %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
- outs.bytes);
- fflush(outs.stream);
- /* truncate file at the position where we started appending */
-#ifdef HAVE_FTRUNCATE
- if(ftruncate( fileno(outs.stream), outs.init)) {
- /* when truncate fails, we can't just append as then we'll
- create something strange, bail out */
- if(!config->mute)
- fprintf(config->errors,
- "failed to truncate, exiting\n");
- break;
- }
- /* now seek to the end of the file, the position where we
- just truncated the file in a large file-safe way */
- fseek(outs.stream, 0, SEEK_END);
-#else
- /* ftruncate is not available, so just reposition the file
- to the location we would have truncated it. This won't
- work properly with large files on 32-bit systems, but
- most of those will have ftruncate. */
- fseek(outs.stream, (long)outs.init, SEEK_SET);
-#endif
- outs.bytes = 0; /* clear for next round */
- }
- continue;
- }
- } /* if retry_numretries */
-
- /* In all ordinary cases, just break out of loop here */
- retry_sleep = retry_sleep_default;
- break;
-
- }
-
- if((config->progressmode == CURL_PROGRESS_BAR) &&
- progressbar.calls)
- /* if the custom progress bar has been displayed, we output a
- newline here */
- fputs("\n", progressbar.out);
-
- if(config->writeout)
- ourWriteOut(curl, config->writeout);
-#ifdef USE_ENVIRONMENT
- if(config->writeenv)
- ourWriteEnv(curl);
-#endif
-
- show_error:
-
-#ifdef __VMS
- if(is_vms_shell()) {
- /* VMS DCL shell behavior */
- if(!config->showerror) {
- vms_show = VMSSTS_HIDE;
- }
- }
- else
-#endif
- {
- if((res!=CURLE_OK) && config->showerror) {
- fprintf(config->errors, "curl: (%d) %s\n", res,
- errorbuffer[0]? errorbuffer:
- curl_easy_strerror((CURLcode)res));
- if(CURLE_SSL_CACERT == res) {
- fprintf(config->errors, "%s%s",
- CURL_CA_CERT_ERRORMSG1,
- CURL_CA_CERT_ERRORMSG2 );
- }
- }
- }
- if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
- int rc;
-
- if(config->xattr) {
- rc = fwrite_xattr(curl, fileno(outs.stream) );
- if(rc)
- warnf(config, "Error setting extended attributes: %s\n",
- strerror(errno) );
- }
-
- rc = fclose(outs.stream);
- if(!res && rc) {
- /* something went wrong in the writing process */
- res = CURLE_WRITE_ERROR;
- fprintf(config->errors, "(%d) Failed writing body\n", res);
- }
- }
-
-#ifdef HAVE_UTIME
- /* Important that we set the time _after_ the file has been
- closed, as is done above here */
- if(config->remote_time && outs.filename) {
- /* ask libcurl if we got a time. Pretty please */
- long filetime;
- curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
- if(filetime >= 0) {
- struct utimbuf times;
- times.actime = (time_t)filetime;
- times.modtime = (time_t)filetime;
- utime(outs.filename, &times); /* set the time we got */
- }
- }
-#endif
-#ifdef __AMIGA__
- /* Set the url as comment for the file. (up to 80 chars are allowed)
- */
- if(strlen(url) > 78)
- url[79] = '\0';
-
- SetComment( outs.filename, url);
-#endif
-
- quit_urls:
- if(url)
- free(url);
-
- if(outfile)
- free(outfile);
-
- if(infdopen)
- close(infd);
-
- } /* loop to the next URL */
-
- if(urls) {
- /* cleanup memory used for URL globbing patterns */
- glob_cleanup(urls);
- urls = NULL;
- }
-
- if(uploadfile)
- free(uploadfile);
-
- } /* loop to the next globbed upload file */
-
- if(inglob) {
- glob_cleanup(inglob);
- inglob = NULL;
- }
-
- if(outfiles)
- free(outfiles);
-
- /* empty this urlnode struct */
- if(urlnode->url)
- free(urlnode->url);
- if(urlnode->outfile)
- free(urlnode->outfile);
- if(urlnode->infile)
- free(urlnode->infile);
-
- /* move on to the next URL */
- nextnode=urlnode->next;
- free(urlnode); /* free the node */
- urlnode = nextnode;
-
- } /* while-loop through all URLs */
-
- quit_curl:
- if(httpgetfields)
- free(httpgetfields);
-
- if(config->engine)
- free(config->engine);
-
- /* cleanup the curl handle! */
- curl_easy_cleanup(curl);
- config->easy = NULL; /* cleanup now */
- if(easycode)
- curl_slist_append(easycode, "curl_easy_cleanup(hnd);");
-
- if(heads.stream && (heads.stream != stdout))
- fclose(heads.stream);
-
- if(allocuseragent)
- free(config->useragent);
-
- if(config->trace_fopened && config->trace_stream)
- fclose(config->trace_stream);
-
- /* Dump the libcurl code if previously enabled.
- NOTE: that this function relies on config->errors amongst other things
- so not everything can be closed and cleaned before this is called */
- dumpeasycode(config);
-
- if(config->errors_fopened)
- fclose(config->errors);
-
- main_free(); /* cleanup */
-
- return res;
-}
-
-/* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
- open before starting to run. Otherwise, the first three network
- sockets opened by curl could be used for input sources, downloaded data
- or error logs as they will effectively be stdin, stdout and/or stderr.
-*/
-static void checkfds(void)
-{
-#ifdef HAVE_PIPE
- int fd[2] = { STDIN_FILENO, STDIN_FILENO };
- while(fd[0] == STDIN_FILENO ||
- fd[0] == STDOUT_FILENO ||
- fd[0] == STDERR_FILENO ||
- fd[1] == STDIN_FILENO ||
- fd[1] == STDOUT_FILENO ||
- fd[1] == STDERR_FILENO)
- if(pipe(fd) < 0)
- return; /* Out of handles. This isn't really a big problem now, but
- will be when we try to create a socket later. */
- close(fd[0]);
- close(fd[1]);
-#endif
-}
-
-
-
-int main(int argc, char *argv[])
-{
- int res;
- struct Configurable config;
-
- memset(&config, 0, sizeof(struct Configurable));
-
- config.errors = stderr; /* default errors to stderr */
-
- checkfds();
-
- res = operate(&config, argc, argv);
-#ifdef __SYMBIAN32__
- if(config.showerror)
- pressanykey();
-#endif
- free_config_fields(&config);
-
-#ifdef __NOVELL_LIBC__
- if(getenv("_IN_NETWARE_BASH_") == NULL)
- pressanykey();
-#endif
-#ifdef __VMS
- vms_special_exit(res, vms_show);
-#else
- return res;
-#endif
-}
-
-/*
- * Reads a line from the given file, ensuring is NUL terminated.
- * The pointer must be freed by the caller.
- * NULL is returned on an out of memory condition.
- */
-static char *my_get_line(FILE *fp)
-{
- char buf[4096];
- char *nl = NULL;
- char *retval = NULL;
-
- do {
- if(NULL == fgets(buf, sizeof(buf), fp))
- break;
- if(NULL == retval) {
- retval = strdup(buf);
- if(!retval)
- return NULL;
- }
- else {
- char *ptr;
- ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
- if(NULL == ptr) {
- free(retval);
- return NULL;
- }
- retval = ptr;
- strcat(retval, buf);
- }
- }
- while(NULL == (nl = strchr(retval, '\n')));
-
- if(NULL != nl)
- *nl = '\0';
-
- return retval;
-}
-
-static void show_dir_errno(FILE *errors, const char *name)
-{
- switch (ERRNO) {
-#ifdef EACCES
- case EACCES:
- fprintf(errors,"You don't have permission to create %s.\n", name);
- break;
-#endif
-#ifdef ENAMETOOLONG
- case ENAMETOOLONG:
- fprintf(errors,"The directory name %s is too long.\n", name);
- break;
-#endif
-#ifdef EROFS
- case EROFS:
- fprintf(errors,"%s resides on a read-only file system.\n", name);
- break;
-#endif
-#ifdef ENOSPC
- case ENOSPC:
- fprintf(errors,"No space left on the file system that will "
- "contain the directory %s.\n", name);
- break;
-#endif
-#ifdef EDQUOT
- case EDQUOT:
- fprintf(errors,"Cannot create directory %s because you "
- "exceeded your quota.\n", name);
- break;
-#endif
- default :
- fprintf(errors,"Error creating directory %s.\n", name);
- break;
- }
-}
-
-/* Create the needed directory hierarchy recursively in order to save
- multi-GETs in file output, ie:
- curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
- should create all the dir* automagically
-*/
-static int create_dir_hierarchy(const char *outfile, FILE *errors)
-{
- char *tempdir;
- char *tempdir2;
- char *outdup;
- char *dirbuildup;
- int result=0;
-
- outdup = strdup(outfile);
- if(!outdup)
- return -1;
-
- dirbuildup = malloc(sizeof(char) * strlen(outfile));
- if(!dirbuildup) {
- free(outdup);
- return -1;
- }
- dirbuildup[0] = '\0';
-
- tempdir = strtok(outdup, DIR_CHAR);
-
- while(tempdir != NULL) {
- tempdir2 = strtok(NULL, DIR_CHAR);
- /* since strtok returns a token for the last word even
- if not ending with DIR_CHAR, we need to prune it */
- if(tempdir2 != NULL) {
- size_t dlen = strlen(dirbuildup);
- if(dlen)
- sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
- else {
- if(0 != strncmp(outdup, DIR_CHAR, 1))
- strcpy(dirbuildup, tempdir);
- else
- sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
- }
- if(access(dirbuildup, F_OK) == -1) {
- result = mkdir(dirbuildup,(mode_t)0000750);
- if(-1 == result) {
- show_dir_errno(errors, dirbuildup);
- break; /* get out of loop */
- }
- }
- }
- tempdir = tempdir2;
- }
- free(dirbuildup);
- free(outdup);
-
- return result; /* 0 is fine, -1 is badness */
-}
-
-#if defined(MSDOS) || defined(WIN32)
-
-#ifndef HAVE_BASENAME
-/* basename() returns a pointer to the last component of a pathname.
- * Ripped from lib/formdata.c.
- */
-static char *Curl_basename(char *path)
-{
- /* Ignore all the details above for now and make a quick and simple
- implementaion here */
- char *s1;
- char *s2;
-
- s1=strrchr(path, '/');
- s2=strrchr(path, '\\');
-
- if(s1 && s2) {
- path = (s1 > s2? s1 : s2)+1;
- }
- else if(s1)
- path = s1 + 1;
- else if(s2)
- path = s2 + 1;
-
- return path;
-}
-#define basename(x) Curl_basename((x))
-#endif /* HAVE_BASENAME */
-
-/* The following functions are taken with modification from the DJGPP
- * port of tar 1.12. They use algorithms originally from DJTAR. */
-
-static const char *
-msdosify (const char *file_name)
-{
- static char dos_name[PATH_MAX];
- static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
- "|<>\\\":?*"; /* illegal in DOS & W95 */
- static const char *illegal_chars_w95 = &illegal_chars_dos[8];
- int idx, dot_idx;
- const char *s = file_name;
- char *d = dos_name;
- const char * const dlimit = dos_name + sizeof(dos_name) - 1;
- const char *illegal_aliens = illegal_chars_dos;
- size_t len = sizeof (illegal_chars_dos) - 1;
-
- /* Support for Windows 9X VFAT systems, when available. */
- if(_use_lfn (file_name)) {
- illegal_aliens = illegal_chars_w95;
- len -= (illegal_chars_w95 - illegal_chars_dos);
- }
-
- /* Get past the drive letter, if any. */
- if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
- *d++ = *s++;
- *d++ = *s++;
- }
-
- for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
- if(memchr (illegal_aliens, *s, len)) {
- /* Dots are special: DOS doesn't allow them as the leading character,
- and a file name cannot have more than a single dot. We leave the
- first non-leading dot alone, unless it comes too close to the
- beginning of the name: we want sh.lex.c to become sh_lex.c, not
- sh.lex-c. */
- if(*s == '.') {
- if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
- /* Copy "./" and "../" verbatim. */
- *d++ = *s++;
- if(*s == '.')
- *d++ = *s++;
- *d = *s;
- }
- else if(idx == 0)
- *d = '_';
- else if(dot_idx >= 0) {
- if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
- d[dot_idx - idx] = '_'; /* replace previous dot */
- *d = '.';
- }
- else
- *d = '-';
- }
- else
- *d = '.';
-
- if(*s == '.')
- dot_idx = idx;
- }
- else if(*s == '+' && s[1] == '+') {
- if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
- *d++ = 'x';
- *d = 'x';
- }
- else {
- /* libg++ etc. */
- memcpy (d, "plus", 4);
- d += 3;
- }
- s++;
- idx++;
- }
- else
- *d = '_';
- }
- else
- *d = *s;
- if(*s == '/') {
- idx = 0;
- dot_idx = -1;
- }
- else
- idx++;
- }
-
- *d = '\0';
- return dos_name;
-}
-
-static char *
-rename_if_dos_device_name (char *file_name)
-{
- /* We could have a file whose name is a device on MS-DOS. Trying to
- * retrieve such a file would fail at best and wedge us at worst. We need
- * to rename such files. */
- char *base;
- struct_stat st_buf;
- char fname[PATH_MAX];
-
- strncpy(fname, file_name, PATH_MAX-1);
- fname[PATH_MAX-1] = 0;
- base = basename(fname);
- if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
- size_t blen = strlen (base);
-
- if(strlen(fname) >= PATH_MAX-1) {
- /* Make room for the '_' */
- blen--;
- base[blen] = 0;
- }
- /* Prepend a '_'. */
- memmove (base + 1, base, blen + 1);
- base[0] = '_';
- strcpy (file_name, fname);
- }
- return file_name;
-}
-
-/* Replace bad characters in the file name before using it.
- * fn will always be freed before return
- * The returned pointer must be freed by the caller if not NULL
- */
-static char *sanitize_dos_name(char *fn)
-{
- char tmpfn[PATH_MAX];
- if(strlen(fn) >= PATH_MAX)
- fn[PATH_MAX-1]=0; /* truncate it */
- strcpy(tmpfn, msdosify(fn));
- free(fn);
- return strdup(rename_if_dos_device_name(tmpfn));
-}
-#endif /* MSDOS || WIN32 */
diff --git a/src/mkhelp.pl b/src/mkhelp.pl
index 4d44a9e0f..ff4604155 100644
--- a/src/mkhelp.pl
+++ b/src/mkhelp.pl
@@ -133,16 +133,14 @@ print <<HEAD
* NEVER EVER edit this manually, fix the mkhelp.pl script instead!
* Generation time: $now
*/
-#include "setup.h"
#ifdef USE_MANUAL
#include "hugehelp.h"
-#include <stdio.h>
HEAD
;
if($c) {
print <<HEAD
-#include <stdlib.h>
#include <zlib.h>
+#include "memdebug.h" /* keep this as LAST include */
static const unsigned char hugehelpgz[] = {
/* This mumbo-jumbo is the huge help text compressed with gzip.
Thanks to this operation, the size of this data shrunk from $gzip
@@ -167,6 +165,17 @@ HEAD
print <<EOF
#define BUF_SIZE 0x10000
+static voidpf zalloc_func(voidpf opaque, unsigned int items, unsigned int size)
+{
+ (void) opaque;
+ /* not a typo, keep it calloc() */
+ return (voidpf) calloc(items, size);
+}
+static void zfree_func(voidpf opaque, voidpf ptr)
+{
+ (void) opaque;
+ free(ptr);
+}
/* Decompress and send to stdout a gzip-compressed buffer */
void hugehelp(void)
{
@@ -179,11 +188,11 @@ void hugehelp(void)
return;
headerlen = 10;
+ memset(&z, 0, sizeof(z_stream));
+ z.zalloc = (alloc_func)zalloc_func;
+ z.zfree = (free_func)zfree_func;
z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen);
z.next_in = (unsigned char *)hugehelpgz + headerlen;
- z.zalloc = (alloc_func)Z_NULL;
- z.zfree = (free_func)Z_NULL;
- z.opaque = 0;
if (inflateInit2(&z, -MAX_WBITS) != Z_OK)
return;
diff --git a/src/setup.h b/src/setup.h
index b510fd9b5..414aac73b 100644
--- a/src/setup.h
+++ b/src/setup.h
@@ -135,6 +135,11 @@
# endif
#endif
+#ifdef USE_LWIPSOCK
+# include <lwip/sockets.h>
+# include <lwip/netdb.h>
+#endif
+
#ifdef TPF
# include <sys/socket.h>
/* change which select is used for the curl command line tool */
@@ -144,11 +149,52 @@
#endif
#include <stdio.h>
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
#ifdef __TANDEM
#include <floss.h>
#endif
+/*
+ * Large file (>2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
+# define fstat(fdes,stp) _fstati64(fdes, stp)
+# define stat(fname,stp) _stati64(fname, stp)
+# define struct_stat struct _stati64
+# define LSEEK_ERROR (__int64)-1
+#endif
+
+/*
+ * Small file (<2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
+# define fstat(fdes,stp) _fstat(fdes, stp)
+# define stat(fname,stp) _stat(fname, stp)
+# define struct_stat struct _stat
+# define LSEEK_ERROR (long)-1
+#endif
+
+#ifndef struct_stat
+# define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+# define LSEEK_ERROR (off_t)-1
+#endif
#ifndef OS
#define OS "unknown"
@@ -221,4 +267,28 @@ int fileno( FILE *stream);
#include "setup_once.h"
#endif
+/*
+ * Definition of our NOP statement Object-like macro
+ */
+
+#ifndef Curl_nop_stmt
+# define Curl_nop_stmt do { } WHILE_FALSE
+#endif
+
+/*
+ * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
+ */
+
+#if defined(__LWIP_OPT_H__)
+# if defined(SOCKET) || \
+ defined(USE_WINSOCK) || \
+ defined(HAVE_ERRNO_H) || \
+ defined(HAVE_WINSOCK_H) || \
+ defined(HAVE_WINSOCK2_H) || \
+ defined(HAVE_WS2TCPIP_H)
+# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
+# endif
+#endif
+
#endif /* HEADER_CURL_SRC_SETUP_H */
+
diff --git a/src/tool_binmode.c b/src/tool_binmode.c
new file mode 100644
index 000000000..34422fdef
--- /dev/null
+++ b/src/tool_binmode.c
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef HAVE_SETMODE
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include "tool_binmode.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void set_binmode(FILE *stream)
+{
+#ifdef O_BINARY
+# ifdef __HIGHC__
+ _setmode(stream, O_BINARY);
+# else
+ setmode(fileno(stream), O_BINARY);
+# endif
+#else
+ (void)stream;
+#endif
+}
+
+#endif /* HAVE_SETMODE */
+
diff --git a/src/tool_binmode.h b/src/tool_binmode.h
new file mode 100644
index 000000000..abd22e44d
--- /dev/null
+++ b/src/tool_binmode.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_TOOL_BINMODE_H
+#define HEADER_CURL_TOOL_BINMODE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef HAVE_SETMODE
+
+void set_binmode(FILE *stream);
+
+#else
+
+#define set_binmode(x) Curl_nop_stmt
+
+#endif /* HAVE_SETMODE */
+
+#endif /* HEADER_CURL_TOOL_BINMODE_H */
+
diff --git a/src/tool_bname.c b/src/tool_bname.c
new file mode 100644
index 000000000..2ac6e483b
--- /dev/null
+++ b/src/tool_bname.c
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include "tool_bname.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifndef HAVE_BASENAME
+
+char *tool_basename(char *path)
+{
+ char *s1;
+ char *s2;
+
+ s1 = strrchr(path, '/');
+ s2 = strrchr(path, '\\');
+
+ if(s1 && s2) {
+ path = (s1 > s2) ? s1 + 1 : s2 + 1;
+ }
+ else if(s1)
+ path = s1 + 1;
+ else if(s2)
+ path = s2 + 1;
+
+ return path;
+}
+
+#endif /* HAVE_BASENAME */
+
diff --git a/src/tool_bname.h b/src/tool_bname.h
new file mode 100644
index 000000000..ed7ba0632
--- /dev/null
+++ b/src/tool_bname.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_BNAME_H
+#define HEADER_CURL_TOOL_BNAME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifndef HAVE_BASENAME
+
+char *tool_basename(char *path);
+
+#define basename(x) tool_basename((x))
+
+#endif /* HAVE_BASENAME */
+
+#endif /* HEADER_CURL_TOOL_BNAME_H */
+
diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c
new file mode 100644
index 000000000..7ac9a7339
--- /dev/null
+++ b/src/tool_cb_dbg.c
@@ -0,0 +1,275 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_dbg.h"
+#include "tool_util.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static void dump(const char *timebuf, const char *text,
+ FILE *stream, const unsigned char *ptr, size_t size,
+ trace tracetype, curl_infotype infotype);
+
+/*
+** callback for CURLOPT_DEBUGFUNCTION
+*/
+
+int tool_debug_cb(CURL *handle, curl_infotype type,
+ unsigned char *data, size_t size,
+ void *userdata)
+{
+ struct Configurable *config = userdata;
+ FILE *output = config->errors;
+ const char *text;
+ struct timeval tv;
+ struct tm *now;
+ char timebuf[20];
+ time_t secs;
+ static time_t epoch_offset;
+ static int known_offset;
+
+ (void)handle; /* not used */
+
+ if(config->tracetime) {
+ tv = tvnow();
+ if(!known_offset) {
+ epoch_offset = time(NULL) - tv.tv_sec;
+ known_offset = 1;
+ }
+ secs = epoch_offset + tv.tv_sec;
+ now = localtime(&secs); /* not thread safe but we don't care */
+ snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
+ now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
+ }
+ else
+ timebuf[0] = 0;
+
+ if(!config->trace_stream) {
+ /* open for append */
+ if(curlx_strequal("-", config->trace_dump))
+ config->trace_stream = stdout;
+ else if(curlx_strequal("%", config->trace_dump))
+ /* Ok, this is somewhat hackish but we do it undocumented for now */
+ config->trace_stream = config->errors; /* aka stderr */
+ else {
+ config->trace_stream = fopen(config->trace_dump, "w");
+ config->trace_fopened = TRUE;
+ }
+ }
+
+ if(config->trace_stream)
+ output = config->trace_stream;
+
+ if(!output) {
+ warnf(config, "Failed to create/open output");
+ return 0;
+ }
+
+ if(config->tracetype == TRACE_PLAIN) {
+ /*
+ * This is the trace look that is similar to what libcurl makes on its
+ * own.
+ */
+ static const char * const s_infotype[] = {
+ "*", "<", ">", "{", "}", "{", "}"
+ };
+ size_t i;
+ size_t st = 0;
+ static bool newl = FALSE;
+ static bool traced_data = FALSE;
+
+ switch(type) {
+ case CURLINFO_HEADER_OUT:
+ for(i = 0; i < size - 1; i++) {
+ if(data[i] == '\n') { /* LF */
+ if(!newl) {
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ }
+ (void)fwrite(data + st, i - st + 1, 1, output);
+ st = i + 1;
+ newl = FALSE;
+ }
+ }
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ (void)fwrite(data + st, i - st + 1, 1, output);
+ newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
+ traced_data = FALSE;
+ break;
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_IN:
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ (void)fwrite(data, size, 1, output);
+ newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
+ traced_data = FALSE;
+ break;
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_DATA_IN:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT:
+ if(!traced_data) {
+ /* if the data is output to a tty and we're sending this debug trace
+ to stderr or stdout, we don't display the alert about the data not
+ being shown as the data _is_ shown then just not via this
+ function */
+ if(!config->isatty ||
+ ((output != stderr) && (output != stdout))) {
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ fprintf(output, "[data not shown]\n");
+ newl = FALSE;
+ traced_data = TRUE;
+ }
+ }
+ break;
+ default: /* nada */
+ newl = FALSE;
+ traced_data = FALSE;
+ break;
+ }
+
+ return 0;
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ /* Special processing is needed for CURLINFO_HEADER_OUT blocks
+ * if they contain both headers and data (separated by CRLFCRLF).
+ * We dump the header text and then switch type to CURLINFO_DATA_OUT.
+ */
+ if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
+ size_t i;
+ for(i = 0; i < size - 4; i++) {
+ if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
+ /* dump everything through the CRLFCRLF as a sent header */
+ text = "=> Send header";
+ dump(timebuf, text, output, data, i + 4, config->tracetype, type);
+ data += i + 3;
+ size -= i + 4;
+ type = CURLINFO_DATA_OUT;
+ data += 1;
+ break;
+ }
+ }
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ switch (type) {
+ case CURLINFO_TEXT:
+ fprintf(output, "%s== Info: %s", timebuf, data);
+ default: /* in case a new one is introduced to shock us */
+ return 0;
+
+ case CURLINFO_HEADER_OUT:
+ text = "=> Send header";
+ break;
+ case CURLINFO_DATA_OUT:
+ text = "=> Send data";
+ break;
+ case CURLINFO_HEADER_IN:
+ text = "<= Recv header";
+ break;
+ case CURLINFO_DATA_IN:
+ text = "<= Recv data";
+ break;
+ case CURLINFO_SSL_DATA_IN:
+ text = "<= Recv SSL data";
+ break;
+ case CURLINFO_SSL_DATA_OUT:
+ text = "=> Send SSL data";
+ break;
+ }
+
+ dump(timebuf, text, output, data, size, config->tracetype, type);
+ return 0;
+}
+
+static void dump(const char *timebuf, const char *text,
+ FILE *stream, const unsigned char *ptr, size_t size,
+ trace tracetype, curl_infotype infotype)
+{
+ size_t i;
+ size_t c;
+
+ unsigned int width = 0x10;
+
+ if(tracetype == TRACE_ASCII)
+ /* without the hex output, we can fit more on screen */
+ width = 0x40;
+
+ fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
+
+ for(i = 0; i < size; i += width) {
+
+ fprintf(stream, "%04zx: ", i);
+
+ if(tracetype == TRACE_BIN) {
+ /* hex not disabled, show it */
+ for(c = 0; c < width; c++)
+ if(i+c < size)
+ fprintf(stream, "%02x ", ptr[i+c]);
+ else
+ fputs(" ", stream);
+ }
+
+ for(c = 0; (c < width) && (i+c < size); c++) {
+ /* check for 0D0A; if found, skip past and start a new line of output */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+1 < size) && (ptr[i+c] == 0x0D) && (ptr[i+c+1] == 0x0A)) {
+ i += (c+2-width);
+ break;
+ }
+#ifdef CURL_DOES_CONVERSIONS
+ /* repeat the 0D0A check above but use the host encoding for CRLF */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+1 < size) && (ptr[i+c] == '\r') && (ptr[i+c+1] == '\n')) {
+ i += (c+2-width);
+ break;
+ }
+ /* convert to host encoding and print this character */
+ fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
+#else
+ (void)infotype;
+ fprintf(stream, "%c", ((ptr[i+c] >= 0x20) && (ptr[i+c] < 0x80)) ?
+ ptr[i+c] : UNPRINTABLE_CHAR);
+#endif /* CURL_DOES_CONVERSIONS */
+ /* check again for 0D0A, to avoid an extra \n if it's at width */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+2 < size) && (ptr[i+c+1] == 0x0D) && (ptr[i+c+2] == 0x0A)) {
+ i += (c+3-width);
+ break;
+ }
+ }
+ fputc('\n', stream); /* newline */
+ }
+ fflush(stream);
+}
+
diff --git a/src/tool_cb_dbg.h b/src/tool_cb_dbg.h
new file mode 100644
index 000000000..6d4446da1
--- /dev/null
+++ b/src/tool_cb_dbg.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_CB_DBG_H
+#define HEADER_CURL_TOOL_CB_DBG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+** callback for CURLOPT_DEBUGFUNCTION
+*/
+
+int tool_debug_cb(CURL *handle, curl_infotype type,
+ unsigned char *data, size_t size,
+ void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_DBG_H */
+
diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c
new file mode 100644
index 000000000..06ced4541
--- /dev/null
+++ b/src/tool_cb_hdr.c
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_hdr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static char *parse_filename(const char *ptr, size_t len);
+
+/*
+** callback for CURLOPT_HEADERFUNCTION
+*/
+
+size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ struct OutStruct *outs = userdata;
+ const char *str = ptr;
+ const size_t cb = size * nmemb;
+ const char *end = (char*)ptr + cb;
+
+ /*
+ * Once that libcurl has called back tool_header_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ size_t failure = (size * nmemb) ? 0 : 1;
+
+ if(!outs->config)
+ return failure;
+
+#ifdef DEBUGBUILD
+ if((size * nmemb > (size_t)CURL_MAX_WRITE_SIZE) ||
+ (size * nmemb > (size_t)CURL_MAX_HTTP_HEADER)) {
+ warnf(outs->config, "Header data exceeds single call write limit!\n");
+ return failure;
+ }
+#endif
+
+ if(!outs->filename && (cb > 20) &&
+ checkprefix("Content-disposition:", str)) {
+ const char *p = str + 20;
+
+ /* look for the 'filename=' parameter
+ (encoded filenames (*=) are not supported) */
+ for(;;) {
+ char *filename;
+ size_t len;
+
+ while(*p && (p < end) && !ISALPHA(*p))
+ p++;
+ if(p > end - 9)
+ break;
+
+ if(memcmp(p, "filename=", 9)) {
+ /* no match, find next parameter */
+ while((p < end) && (*p != ';'))
+ p++;
+ continue;
+ }
+ p += 9;
+
+ /* this expression below typecasts 'cb' only to avoid
+ warning: signed and unsigned type in conditional expression
+ */
+ len = (ssize_t)cb - (p - str);
+ filename = parse_filename(p, len);
+ if(filename) {
+ outs->filename = filename;
+ outs->alloc_filename = TRUE;
+ outs->s_isreg = TRUE;
+ outs->fopened = FALSE;
+ outs->stream = NULL;
+ break;
+ }
+ else
+ return failure;
+ }
+ }
+
+ return cb;
+}
+
+/*
+ * Copies a file name part and returns an ALLOCATED data buffer.
+ */
+static char *parse_filename(const char *ptr, size_t len)
+{
+ char *copy;
+ char *p;
+ char *q;
+ char stop = '\0';
+
+ /* simple implementation of strndup() */
+ copy = malloc(len+1);
+ if(!copy)
+ return NULL;
+ memcpy(copy, ptr, len);
+ copy[len] = '\0';
+
+ p = copy;
+ if(*p == '\'' || *p == '"') {
+ /* store the starting quote */
+ stop = *p;
+ p++;
+ }
+ else
+ stop = ';';
+
+ /* if the filename contains a path, only use filename portion */
+ q = strrchr(copy, '/');
+ if(q) {
+ p = q + 1;
+ if(!*p) {
+ Curl_safefree(copy);
+ return NULL;
+ }
+ }
+
+ /* If the filename contains a backslash, only use filename portion. The idea
+ is that even systems that don't handle backslashes as path separators
+ probably want the path removed for convenience. */
+ q = strrchr(p, '\\');
+ if(q) {
+ p = q + 1;
+ if(!*p) {
+ Curl_safefree(copy);
+ return NULL;
+ }
+ }
+
+ /* scan for the end letter and stop there */
+ q = p;
+ while(*q) {
+ if(q[1] && (q[0] == '\\'))
+ q++;
+ else if(q[0] == stop)
+ break;
+ q++;
+ }
+ *q = '\0';
+
+ /* make sure the file name doesn't end in \r or \n */
+ q = strchr(p, '\r');
+ if(q)
+ *q = '\0';
+
+ q = strchr(p, '\n');
+ if(q)
+ *q = '\0';
+
+ if(copy != p)
+ memmove(copy, p, strlen(p) + 1);
+
+ /* in case we built debug enabled, we allow an evironment variable
+ * named CURL_TESTDIR to prefix the given file name to put it into a
+ * specific directory
+ */
+#ifdef DEBUGBUILD
+ {
+ char *tdir = curlx_getenv("CURL_TESTDIR");
+ if(tdir) {
+ char buffer[512]; /* suitably large */
+ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
+ Curl_safefree(copy);
+ copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
+ aprintf() or similar since we want to use the
+ same memory code as the "real" parse_filename
+ function */
+ curl_free(tdir);
+ }
+ }
+#endif
+
+ return copy;
+}
+
diff --git a/src/tool_cb_hdr.h b/src/tool_cb_hdr.h
new file mode 100644
index 000000000..8808a4ae1
--- /dev/null
+++ b/src/tool_cb_hdr.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_CB_HDR_H
+#define HEADER_CURL_TOOL_CB_HDR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+** callback for CURLOPT_HEADERFUNCTION
+*/
+
+size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_HDR_H */
+
diff --git a/src/tool_cb_prg.c b/src/tool_cb_prg.c
new file mode 100644
index 000000000..e141f1e65
--- /dev/null
+++ b/src/tool_cb_prg.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_prg.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_PROGRESSFUNCTION
+*/
+
+int tool_progress_cb(void *clientp,
+ double dltotal, double dlnow,
+ double ultotal, double ulnow)
+{
+ /* The original progress-bar source code was written for curl by Lars Aas,
+ and this new edition inherits some of his concepts. */
+
+ char line[256];
+ char outline[256];
+ char format[40];
+ double frac;
+ double percent;
+ int barwidth;
+ int num;
+ int i;
+
+ struct ProgressData *bar = (struct ProgressData *)clientp;
+
+ /* expected transfer size */
+ curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
+ bar->initial_size;
+
+ /* we've come this far */
+ curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
+ bar->initial_size;
+
+ if(point > total)
+ /* we have got more than the expected total! */
+ total = point;
+
+ /* simply count invokes */
+ bar->calls++;
+
+ if(total < 1) {
+ curl_off_t prevblock = bar->prev / 1024;
+ curl_off_t thisblock = point / 1024;
+ while(thisblock > prevblock) {
+ fprintf(bar->out, "#");
+ prevblock++;
+ }
+ }
+ else {
+ frac = (double)point / (double)total;
+ percent = frac * 100.0f;
+ barwidth = bar->width - 7;
+ num = (int) (((double)barwidth) * frac);
+ for(i = 0; i < num; i++)
+ line[i] = '#';
+ line[i] = '\0';
+ snprintf(format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth);
+ snprintf(outline, sizeof(outline), format, line, percent);
+ fprintf(bar->out, "\r%s", outline);
+ }
+ fflush(bar->out);
+ bar->prev = point;
+
+ return 0;
+}
+
+void progressbarinit(struct ProgressData *bar,
+ struct Configurable *config)
+{
+#ifdef __EMX__
+ /* 20000318 mgs */
+ int scr_size[2];
+#endif
+ char *colp;
+
+ memset(bar, 0, sizeof(struct ProgressData));
+
+ /* pass this through to progress function so
+ * it can display progress towards total file
+ * not just the part that's left. (21-may-03, dbyron) */
+ if(config->use_resume)
+ bar->initial_size = config->resume_from;
+
+/* TODO: get terminal width through ansi escapes or something similar.
+ try to update width when xterm is resized... - 19990617 larsa */
+#ifndef __EMX__
+ /* 20000318 mgs
+ * OS/2 users most likely won't have this env var set, and besides that
+ * we're using our own way to determine screen width */
+ colp = curlx_getenv("COLUMNS");
+ if(colp) {
+ char *endptr;
+ long num = strtol(colp, &endptr, 10);
+ if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0))
+ bar->width = (int)num;
+ else
+ bar->width = 79;
+ curl_free(colp);
+ }
+ else
+ bar->width = 79;
+#else
+ /* 20000318 mgs
+ * We use this emx library call to get the screen width, and subtract
+ * one from what we got in order to avoid a problem with the cursor
+ * advancing to the next line if we print a string that is as long as
+ * the screen is wide. */
+
+ _scrsize(scr_size);
+ bar->width = scr_size[0] - 1;
+#endif
+
+ bar->out = config->errors;
+}
+
diff --git a/src/tool_cb_prg.h b/src/tool_cb_prg.h
new file mode 100644
index 000000000..f64335a3b
--- /dev/null
+++ b/src/tool_cb_prg.h
@@ -0,0 +1,49 @@
+#ifndef HEADER_CURL_TOOL_CB_PRG_H
+#define HEADER_CURL_TOOL_CB_PRG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#define CURL_PROGRESS_STATS 0 /* default progress display */
+#define CURL_PROGRESS_BAR 1
+
+struct ProgressData {
+ int calls;
+ curl_off_t prev;
+ int width;
+ FILE *out; /* where to write everything to */
+ curl_off_t initial_size;
+};
+
+void progressbarinit(struct ProgressData *bar,
+ struct Configurable *config);
+
+/*
+** callback for CURLOPT_PROGRESSFUNCTION
+*/
+
+int tool_progress_cb(void *clientp,
+ double dltotal, double dlnow,
+ double ultotal, double ulnow);
+
+#endif /* HEADER_CURL_TOOL_CB_PRG_H */
+
diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c
new file mode 100644
index 000000000..34edb063b
--- /dev/null
+++ b/src/tool_cb_rea.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_rea.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_READFUNCTION
+*/
+
+size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
+{
+ ssize_t rc;
+ struct InStruct *in = userdata;
+
+ rc = read(in->fd, buffer, sz*nmemb);
+ if(rc < 0) {
+ if(errno == EAGAIN) {
+ errno = 0;
+ in->config->readbusy = TRUE;
+ return CURL_READFUNC_PAUSE;
+ }
+ /* since size_t is unsigned we can't return negative values fine */
+ rc = 0;
+ }
+ in->config->readbusy = FALSE;
+ return (size_t)rc;
+}
+
diff --git a/src/tool_cb_rea.h b/src/tool_cb_rea.h
new file mode 100644
index 000000000..40c61f6f1
--- /dev/null
+++ b/src/tool_cb_rea.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_CB_REA_H
+#define HEADER_CURL_TOOL_CB_REA_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+** callback for CURLOPT_READFUNCTION
+*/
+
+size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_REA_H */
+
diff --git a/src/tool_cb_see.c b/src/tool_cb_see.c
new file mode 100644
index 000000000..5bac4947b
--- /dev/null
+++ b/src/tool_cb_see.c
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_see.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t,
+ both represent the same value. Maximum offset used here when we lseek
+ using a 'long' data type offset */
+
+#define OUR_MAX_SEEK_L 2147483647L - 1L
+#define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1)
+
+/*
+** callback for CURLOPT_SEEKFUNCTION
+**
+** Notice that this is not supposed to return the resulting offset. This
+** shall only return CURL_SEEKFUNC_* return codes.
+*/
+
+int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
+{
+ struct InStruct *in = userdata;
+
+#if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
+
+ /* The offset check following here is only interesting if curl_off_t is
+ larger than off_t and we are not using the WIN32 large file support
+ macros that provide the support to do 64bit seeks correctly */
+
+ if(offset > OUR_MAX_SEEK_O) {
+ /* Some precaution code to work around problems with different data sizes
+ to allow seeking >32bit even if off_t is 32bit. Should be very rare and
+ is really valid on weirdo-systems. */
+ curl_off_t left = offset;
+
+ if(whence != SEEK_SET)
+ /* this code path doesn't support other types */
+ return CURL_SEEKFUNC_FAIL;
+
+ if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
+ /* couldn't rewind to beginning */
+ return CURL_SEEKFUNC_FAIL;
+
+ while(left) {
+ long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
+ if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
+ /* couldn't seek forwards the desired amount */
+ return CURL_SEEKFUNC_FAIL;
+ left -= step;
+ }
+ return CURL_SEEKFUNC_OK;
+ }
+#endif
+
+ if(LSEEK_ERROR == lseek(in->fd, offset, whence))
+ /* couldn't rewind, the reason is in errno but errno is just not portable
+ enough and we don't actually care that much why we failed. We'll let
+ libcurl know that it may try other means if it wants to. */
+ return CURL_SEEKFUNC_CANTSEEK;
+
+ return CURL_SEEKFUNC_OK;
+}
+
+#if defined(WIN32) && !defined(__MINGW64__)
+
+#ifdef __BORLANDC__
+/* 64-bit lseek-like function unavailable */
+# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
+#endif
+
+#ifdef __POCC__
+# if(__POCC__ < 450)
+/* 64-bit lseek-like function unavailable */
+# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
+# else
+# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
+# endif
+#endif
+
+/*
+ * Truncate a file handle at a 64-bit position 'where'.
+ */
+
+int tool_ftruncate64(int fd, curl_off_t where)
+{
+ if(_lseeki64(fd, where, SEEK_SET) < 0)
+ return -1;
+
+ if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
+ return -1;
+
+ return 0;
+}
+
+#endif /* WIN32 && ! __MINGW64__ */
+
diff --git a/src/tool_cb_see.h b/src/tool_cb_see.h
new file mode 100644
index 000000000..530bfacba
--- /dev/null
+++ b/src/tool_cb_see.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_TOOL_CB_SEE_H
+#define HEADER_CURL_TOOL_CB_SEE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#if defined(WIN32) && !defined(__MINGW64__)
+
+int tool_ftruncate64(int fd, curl_off_t where);
+
+#define ftruncate(fd,where) tool_ftruncate64(fd,where)
+
+#ifndef HAVE_FTRUNCATE
+# define HAVE_FTRUNCATE 1
+#endif
+
+#endif /* WIN32 && ! __MINGW64__ */
+
+/*
+** callback for CURLOPT_SEEKFUNCTION
+*/
+
+int tool_seek_cb(void *userdata, curl_off_t offset, int whence);
+
+#endif /* HEADER_CURL_TOOL_CB_SEE_H */
+
diff --git a/src/tool_cb_skt.c b/src/tool_cb_skt.c
new file mode 100644
index 000000000..156c1108e
--- /dev/null
+++ b/src/tool_cb_skt.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_skt.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_SOCKOPTFUNCTION
+*/
+
+int tool_sockopt_cb(void *userdata, curl_socket_t curlfd, curlsocktype purpose)
+{
+ struct Configurable *config = userdata;
+
+ int onoff = 1; /* this callback is only used if we ask for keepalives on the
+ connection */
+
+#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
+ int keepidle = (int)config->alivetime;
+#endif
+
+ switch(purpose) {
+ case CURLSOCKTYPE_IPCXN:
+ if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
+ sizeof(onoff)) < 0) {
+ /* don't abort operation, just issue a warning */
+ SET_SOCKERRNO(0);
+ warnf(config, "Could not set SO_KEEPALIVE!\n");
+ return 0;
+ }
+ else {
+ if(config->alivetime) {
+#ifdef TCP_KEEPIDLE
+ if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
+ sizeof(keepidle)) < 0) {
+ /* don't abort operation, just issue a warning */
+ SET_SOCKERRNO(0);
+ warnf(config, "Could not set TCP_KEEPIDLE!\n");
+ return 0;
+ }
+#endif
+#ifdef TCP_KEEPINTVL
+ if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
+ sizeof(keepidle)) < 0) {
+ /* don't abort operation, just issue a warning */
+ SET_SOCKERRNO(0);
+ warnf(config, "Could not set TCP_KEEPINTVL!\n");
+ return 0;
+ }
+#endif
+#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL)
+ warnf(config, "Keep-alive functionality somewhat crippled due to "
+ "missing support in your operating system!\n");
+#endif
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
diff --git a/src/tool_cb_skt.h b/src/tool_cb_skt.h
new file mode 100644
index 000000000..11bd0c422
--- /dev/null
+++ b/src/tool_cb_skt.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_CB_SKT_H
+#define HEADER_CURL_TOOL_CB_SKT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+** callback for CURLOPT_SOCKOPTFUNCTION
+*/
+
+int tool_sockopt_cb(void *userdata,
+ curl_socket_t curlfd,
+ curlsocktype purpose);
+
+#endif /* HEADER_CURL_TOOL_CB_SKT_H */
+
diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c
new file mode 100644
index 000000000..de94f6e49
--- /dev/null
+++ b/src/tool_cb_wrt.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_wrt.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_WRITEFUNCTION
+*/
+
+size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
+{
+ size_t rc;
+ struct OutStruct *outs = userdata;
+ struct Configurable *config = outs->config;
+
+ /*
+ * Once that libcurl has called back tool_write_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ const size_t failure = (sz * nmemb) ? 0 : 1;
+
+ if(!config)
+ return failure;
+
+#ifdef DEBUGBUILD
+ if(sz * nmemb > (size_t)CURL_MAX_WRITE_SIZE) {
+ warnf(config, "Data size exceeds single call write limit!\n");
+ return failure;
+ }
+
+ {
+ /* Some internal congruency checks on received OutStruct */
+ bool check_fails = FALSE;
+ if(outs->filename) {
+ /* regular file */
+ if(!*outs->filename)
+ check_fails = TRUE;
+ if(!outs->s_isreg)
+ check_fails = TRUE;
+ if(outs->fopened && !outs->stream)
+ check_fails = TRUE;
+ if(!outs->fopened && outs->stream)
+ check_fails = TRUE;
+ if(!outs->fopened && outs->bytes)
+ check_fails = TRUE;
+ }
+ else {
+ /* standard stream */
+ if(!outs->stream || outs->s_isreg || outs->fopened)
+ check_fails = TRUE;
+ if(outs->alloc_filename || outs->init)
+ check_fails = TRUE;
+ }
+ if(check_fails) {
+ warnf(config, "Invalid output struct data for write callback\n");
+ return failure;
+ }
+ }
+#endif
+
+ if(!outs->stream) {
+ FILE *file;
+
+ if(!outs->filename || !*outs->filename) {
+ warnf(config, "Remote filename has no length!\n");
+ return failure;
+ }
+
+ if(config->content_disposition) {
+ /* don't overwrite existing files */
+ file = fopen(outs->filename, "rb");
+ if(file) {
+ fclose(file);
+ warnf(config, "Refusing to overwrite %s: %s\n", outs->filename,
+ strerror(EEXIST));
+ return failure;
+ }
+ }
+
+ /* open file for writing */
+ file = fopen(outs->filename, "wb");
+ if(!file) {
+ warnf(config, "Failed to create the file %s: %s\n", outs->filename,
+ strerror(errno));
+ return failure;
+ }
+ outs->s_isreg = TRUE;
+ outs->fopened = TRUE;
+ outs->stream = file;
+ outs->bytes = 0;
+ outs->init = 0;
+ }
+
+ rc = fwrite(buffer, sz, nmemb, outs->stream);
+
+ if((sz * nmemb) == rc)
+ /* we added this amount of data to the output */
+ outs->bytes += (sz * nmemb);
+
+ if(config->readbusy) {
+ config->readbusy = FALSE;
+ curl_easy_pause(config->easy, CURLPAUSE_CONT);
+ }
+
+ if(config->nobuffer) {
+ /* output buffering disabled */
+ int res = fflush(outs->stream);
+ if(res)
+ return failure;
+ }
+
+ return rc;
+}
+
diff --git a/src/tool_cb_wrt.h b/src/tool_cb_wrt.h
new file mode 100644
index 000000000..a17c14607
--- /dev/null
+++ b/src/tool_cb_wrt.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_CB_WRT_H
+#define HEADER_CURL_TOOL_CB_WRT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+** callback for CURLOPT_WRITEFUNCTION
+*/
+
+size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_WRT_H */
+
diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
new file mode 100644
index 000000000..e74ea4375
--- /dev/null
+++ b/src/tool_cfgable.c
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "tool_cfgable.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* TODO: review handling of unhandled fields marked below */
+
+void free_config_fields(struct Configurable *config)
+{
+ struct getout *urlnode;
+
+ if(config->easy) {
+ curl_easy_cleanup(config->easy);
+ config->easy = NULL;
+ }
+
+ Curl_safefree(config->random_file);
+ Curl_safefree(config->egd_file);
+ Curl_safefree(config->useragent);
+ Curl_safefree(config->cookie);
+ Curl_safefree(config->cookiejar);
+ Curl_safefree(config->cookiefile);
+
+ Curl_safefree(config->postfields);
+ Curl_safefree(config->referer);
+
+ Curl_safefree(config->headerfile);
+ Curl_safefree(config->ftpport);
+ Curl_safefree(config->iface);
+
+ Curl_safefree(config->range);
+
+ Curl_safefree(config->userpwd);
+ Curl_safefree(config->tls_username);
+ Curl_safefree(config->tls_password);
+ Curl_safefree(config->tls_authtype);
+ Curl_safefree(config->proxyuserpwd);
+ Curl_safefree(config->proxy);
+
+ Curl_safefree(config->noproxy);
+ Curl_safefree(config->mail_from);
+ curl_slist_free_all(config->mail_rcpt);
+
+ Curl_safefree(config->netrc_file);
+
+ urlnode = config->url_list;
+ while(urlnode) {
+ struct getout *next = urlnode->next;
+ Curl_safefree(urlnode->url);
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ Curl_safefree(urlnode);
+ urlnode = next;
+ }
+ config->url_list = NULL;
+ config->url_last = NULL;
+ config->url_get = NULL;
+ config->url_out = NULL;
+
+ Curl_safefree(config->cipher_list);
+ Curl_safefree(config->cert);
+ Curl_safefree(config->cert_type);
+ Curl_safefree(config->cacert);
+ Curl_safefree(config->capath);
+ Curl_safefree(config->crlfile);
+ Curl_safefree(config->key);
+ Curl_safefree(config->key_type);
+ Curl_safefree(config->key_passwd);
+ Curl_safefree(config->pubkey);
+ Curl_safefree(config->hostpubmd5);
+ Curl_safefree(config->engine);
+
+ Curl_safefree(config->customrequest);
+ Curl_safefree(config->krblevel);
+ Curl_safefree(config->trace_dump);
+
+ config->trace_stream = NULL; /* closed elsewhere when appropriate */
+
+ Curl_safefree(config->writeout);
+
+ config->errors = NULL; /* closed elsewhere when appropriate */
+
+ curl_slist_free_all(config->quote);
+ curl_slist_free_all(config->postquote);
+ curl_slist_free_all(config->prequote);
+
+ curl_slist_free_all(config->headers);
+
+ if(config->httppost) {
+ curl_formfree(config->httppost);
+ config->httppost = NULL;
+ }
+
+ /* config->last_post not handled */
+
+ curl_slist_free_all(config->telnet_options);
+ curl_slist_free_all(config->resolve);
+
+ Curl_safefree(config->socksproxy);
+ Curl_safefree(config->socks5_gssapi_service);
+
+ Curl_safefree(config->ftp_account);
+ Curl_safefree(config->ftp_alternative_to_user);
+
+ Curl_safefree(config->libcurl);
+}
+
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
new file mode 100644
index 000000000..adbb44627
--- /dev/null
+++ b/src/tool_cfgable.h
@@ -0,0 +1,204 @@
+#ifndef HEADER_CURL_TOOL_CFGABLE_H
+#define HEADER_CURL_TOOL_CFGABLE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include "tool_sdecls.h"
+
+struct Configurable {
+ CURL *easy; /* once we have one, we keep it here */
+ bool remote_time;
+ char *random_file;
+ char *egd_file;
+ char *useragent;
+ char *cookie; /* single line with specified cookies */
+ char *cookiejar; /* write to this file */
+ char *cookiefile; /* read from this file */
+ bool cookiesession; /* new session? */
+ bool encoding; /* Accept-Encoding please */
+ bool tr_encoding; /* Transfer-Encoding please */
+ long authtype; /* auth bitmask */
+ bool use_resume;
+ bool resume_from_current;
+ bool disable_epsv;
+ bool disable_eprt;
+ bool ftp_pret;
+ long proto;
+ bool proto_present;
+ long proto_redir;
+ bool proto_redir_present;
+ curl_off_t resume_from;
+ char *postfields;
+ curl_off_t postfieldsize;
+ char *referer;
+ long timeout;
+ long connecttimeout;
+ long maxredirs;
+ curl_off_t max_filesize;
+ char *headerfile;
+ char *ftpport;
+ char *iface;
+ int localport;
+ int localportrange;
+ unsigned short porttouse;
+ char *range;
+ long low_speed_limit;
+ long low_speed_time;
+ int showerror; /* -1 == unset, default => show errors
+ 0 => -s is used to NOT show errors
+ 1 => -S has been used to show errors */
+ char *userpwd;
+ char *tls_username;
+ char *tls_password;
+ char *tls_authtype;
+ char *proxyuserpwd;
+ char *proxy;
+ int proxyver; /* set to CURLPROXY_HTTP* define */
+ char *noproxy;
+ char *mail_from;
+ struct curl_slist *mail_rcpt;
+ bool proxytunnel;
+ bool ftp_append; /* APPE on ftp */
+ bool mute; /* don't show messages, --silent given */
+ bool use_ascii; /* select ascii or text transfer */
+ bool autoreferer; /* automatically set referer */
+ bool failonerror; /* fail on (HTTP) errors */
+ bool include_headers; /* send headers to data output */
+ bool no_body; /* don't get the body */
+ bool dirlistonly; /* only get the FTP dir list */
+ bool followlocation; /* follow http redirects */
+ bool unrestricted_auth; /* Continue to send authentication (user+password)
+ when following ocations, even when hostname
+ changed */
+ bool netrc_opt;
+ bool netrc;
+ char *netrc_file;
+ bool noprogress; /* don't show progress meter, --silent given */
+ bool isatty; /* updated internally only if output is a tty */
+ struct getout *url_list; /* point to the first node */
+ struct getout *url_last; /* point to the last/current node */
+ struct getout *url_get; /* point to the node to fill in URL */
+ struct getout *url_out; /* point to the node to fill in outfile */
+ char *cipher_list;
+ char *cert;
+ char *cert_type;
+ char *cacert;
+ char *capath;
+ char *crlfile;
+ char *key;
+ char *key_type;
+ char *key_passwd;
+ char *pubkey;
+ char *hostpubmd5;
+ char *engine;
+ bool list_engines;
+ bool crlf;
+ char *customrequest;
+ char *krblevel;
+ char *trace_dump; /* file to dump the network trace to, or NULL */
+ FILE *trace_stream;
+ bool trace_fopened;
+ trace tracetype;
+ bool tracetime; /* include timestamp? */
+ long httpversion;
+ int progressmode; /* CURL_PROGRESS_BAR or CURL_PROGRESS_STATS */
+ bool nobuffer;
+ bool readbusy; /* set when reading input returns EAGAIN */
+ bool globoff;
+ bool use_httpget;
+ bool insecure_ok; /* set TRUE to allow insecure SSL connects */
+ bool create_dirs;
+ bool ftp_create_dirs;
+ bool ftp_skip_ip;
+ bool proxynegotiate;
+ bool proxyntlm;
+ bool proxydigest;
+ bool proxybasic;
+ bool proxyanyauth;
+ char *writeout; /* %-styled format string to output */
+ bool writeenv; /* write results to environment, if available */
+ FILE *errors; /* errors stream, defaults to stderr */
+ bool errors_fopened; /* whether errors stream isn't stderr */
+ struct curl_slist *quote;
+ struct curl_slist *postquote;
+ struct curl_slist *prequote;
+ long ssl_version;
+ long ip_version;
+ curl_TimeCond timecond;
+ time_t condtime;
+ struct curl_slist *headers;
+ struct curl_httppost *httppost;
+ struct curl_httppost *last_post;
+ struct curl_slist *telnet_options;
+ struct curl_slist *resolve;
+ HttpReq httpreq;
+
+ /* for bandwidth limiting features: */
+ curl_off_t sendpersecond; /* send to peer */
+ curl_off_t recvpersecond; /* receive from peer */
+
+ bool ftp_ssl;
+ bool ftp_ssl_reqd;
+ bool ftp_ssl_control;
+ bool ftp_ssl_ccc;
+ int ftp_ssl_ccc_mode;
+
+ char *socksproxy; /* set to server string */
+ int socksver; /* set to CURLPROXY_SOCKS* define */
+ char *socks5_gssapi_service; /* set service name for gssapi principal
+ * default rcmd */
+ int socks5_gssapi_nec ; /* The NEC reference server does not protect
+ * the encryption type exchange */
+
+ bool tcp_nodelay;
+ long req_retry; /* number of retries */
+ long retry_delay; /* delay between retries (in seconds) */
+ long retry_maxtime; /* maximum time to keep retrying */
+
+ char *ftp_account; /* for ACCT */
+ char *ftp_alternative_to_user; /* send command if USER/PASS fails */
+ int ftp_filemethod;
+ long tftp_blksize; /* TFTP BLKSIZE option */
+ bool ignorecl; /* --ignore-content-length */
+ bool disable_sessionid;
+
+ char *libcurl; /* output libcurl code to this file name */
+ bool raw;
+ bool post301;
+ bool post302;
+ bool nokeepalive; /* for keepalive needs */
+ long alivetime;
+ bool content_disposition; /* use Content-disposition filename */
+
+ int default_node_flags; /* default flags to search for each 'node', which
+ is basically each given URL to transfer */
+
+ bool xattr; /* store metadata in extended attributes */
+ long gssapi_delegation;
+
+}; /* struct Configurable */
+
+void free_config_fields(struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_CFGABLE_H */
+
diff --git a/src/tool_convert.c b/src/tool_convert.c
new file mode 100644
index 000000000..e72a091b6
--- /dev/null
+++ b/src/tool_convert.c
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "tool_convert.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef HAVE_ICONV
+
+/* curl tool iconv conversion descriptors */
+static iconv_t inbound_cd = (iconv_t)-1;
+static iconv_t outbound_cd = (iconv_t)-1;
+
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+
+/*
+ * convert_to_network() is a curl tool function to convert
+ * from the host encoding to ASCII on non-ASCII platforms.
+ */
+CURLcode convert_to_network(char *buffer, size_t length)
+{
+ /* translate from the host encoding to the network encoding */
+ char *input_ptr, *output_ptr;
+ size_t res, in_bytes, out_bytes;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(outbound_cd == (iconv_t)-1) {
+ outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(outbound_cd == (iconv_t)-1) {
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ res = iconv(outbound_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((res == (size_t)-1) || (in_bytes != 0)) {
+ return CURLE_CONV_FAILED;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * convert_from_network() is a curl tool function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode convert_from_network(char *buffer, size_t length)
+{
+ /* translate from the network encoding to the host encoding */
+ char *input_ptr, *output_ptr;
+ size_t res, in_bytes, out_bytes;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(inbound_cd == (iconv_t)-1) {
+ inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(inbound_cd == (iconv_t)-1) {
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ res = iconv(inbound_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((res == (size_t)-1) || (in_bytes != 0)) {
+ return CURLE_CONV_FAILED;
+ }
+
+ return CURLE_OK;
+}
+
+void convert_cleanup(void)
+{
+ /* close iconv conversion descriptors */
+ if(inbound_cd != (iconv_t)-1)
+ (void)iconv_close(inbound_cd);
+ if(outbound_cd != (iconv_t)-1)
+ (void)iconv_close(outbound_cd);
+}
+
+#endif /* HAVE_ICONV */
+
+char convert_char(curl_infotype infotype, char this_char)
+{
+/* determine how this specific character should be displayed */
+ switch(infotype) {
+ case CURLINFO_DATA_IN:
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT:
+ /* data, treat as ASCII */
+ if((this_char >= 0x20) && (this_char < 0x7f)) {
+ /* printable ASCII hex value: convert to host encoding */
+ (void)convert_from_network(&this_char, 1);
+ }
+ else {
+ /* non-printable ASCII, use a replacement character */
+ return UNPRINTABLE_CHAR;
+ }
+ /* fall through to default */
+ default:
+ /* treat as host encoding */
+ if(ISPRINT(this_char)
+ && (this_char != '\t')
+ && (this_char != '\r')
+ && (this_char != '\n')) {
+ /* printable characters excluding tabs and line end characters */
+ return this_char;
+ }
+ break;
+ }
+ /* non-printable, use a replacement character */
+ return UNPRINTABLE_CHAR;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */
+
diff --git a/src/tool_convert.h b/src/tool_convert.h
new file mode 100644
index 000000000..d3ef676b2
--- /dev/null
+++ b/src/tool_convert.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_TOOL_CONVERT_H
+#define HEADER_CURL_TOOL_CONVERT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#ifdef HAVE_ICONV
+
+CURLcode convert_to_network(char *buffer, size_t length);
+CURLcode convert_from_network(char *buffer, size_t length);
+void convert_cleanup(void);
+
+#endif /* HAVE_ICONV */
+
+char convert_char(curl_infotype infotype, char this_char);
+
+#endif /* CURL_DOES_CONVERSIONS */
+
+#if !defined(CURL_DOES_CONVERSIONS) || !defined(HAVE_ICONV)
+#define convert_cleanup() Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_CONVERT_H */
+
diff --git a/src/tool_dirhie.c b/src/tool_dirhie.c
new file mode 100644
index 000000000..f538d8b2f
--- /dev/null
+++ b/src/tool_dirhie.c
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef WIN32
+# include <direct.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_dirhie.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef NETWARE
+# ifndef __NOVELL_LIBC__
+# define mkdir mkdir_510
+# endif
+#endif
+
+#ifdef WIN32
+# define mkdir(x,y) (mkdir)((x))
+# ifndef __POCC__
+# define F_OK 0
+# endif
+#endif
+
+static void show_dir_errno(FILE *errors, const char *name)
+{
+ switch(ERRNO) {
+#ifdef EACCES
+ case EACCES:
+ fprintf(errors, "You don't have permission to create %s.\n", name);
+ break;
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG:
+ fprintf(errors, "The directory name %s is too long.\n", name);
+ break;
+#endif
+#ifdef EROFS
+ case EROFS:
+ fprintf(errors, "%s resides on a read-only file system.\n", name);
+ break;
+#endif
+#ifdef ENOSPC
+ case ENOSPC:
+ fprintf(errors, "No space left on the file system that will "
+ "contain the directory %s.\n", name);
+ break;
+#endif
+#ifdef EDQUOT
+ case EDQUOT:
+ fprintf(errors, "Cannot create directory %s because you "
+ "exceeded your quota.\n", name);
+ break;
+#endif
+ default :
+ fprintf(errors, "Error creating directory %s.\n", name);
+ break;
+ }
+}
+
+/*
+ * Create the needed directory hierarchy recursively in order to save
+ * multi-GETs in file output, ie:
+ * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
+ * should create all the dir* automagically
+ */
+
+CURLcode create_dir_hierarchy(const char *outfile, FILE *errors)
+{
+ char *tempdir;
+ char *tempdir2;
+ char *outdup;
+ char *dirbuildup;
+ CURLcode result = CURLE_OK;
+
+ outdup = strdup(outfile);
+ if(!outdup)
+ return CURLE_OUT_OF_MEMORY;
+
+ dirbuildup = malloc(strlen(outfile) + 1);
+ if(!dirbuildup) {
+ Curl_safefree(outdup);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ dirbuildup[0] = '\0';
+
+ tempdir = strtok(outdup, DIR_CHAR);
+
+ while(tempdir != NULL) {
+ tempdir2 = strtok(NULL, DIR_CHAR);
+ /* since strtok returns a token for the last word even
+ if not ending with DIR_CHAR, we need to prune it */
+ if(tempdir2 != NULL) {
+ size_t dlen = strlen(dirbuildup);
+ if(dlen)
+ sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
+ else {
+ if(0 != strncmp(outdup, DIR_CHAR, 1))
+ strcpy(dirbuildup, tempdir);
+ else
+ sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
+ }
+ if(access(dirbuildup, F_OK) == -1) {
+ if(-1 == mkdir(dirbuildup,(mode_t)0000750)) {
+ show_dir_errno(errors, dirbuildup);
+ result = CURLE_WRITE_ERROR;
+ break; /* get out of loop */
+ }
+ }
+ }
+ tempdir = tempdir2;
+ }
+
+ Curl_safefree(dirbuildup);
+ Curl_safefree(outdup);
+
+ return result;
+}
+
diff --git a/src/tool_dirhie.h b/src/tool_dirhie.h
new file mode 100644
index 000000000..eee30c47f
--- /dev/null
+++ b/src/tool_dirhie.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_DIRHIE_H
+#define HEADER_CURL_TOOL_DIRHIE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+CURLcode create_dir_hierarchy(const char *outfile, FILE *errors);
+
+#endif /* HEADER_CURL_TOOL_DIRHIE_H */
+
diff --git a/src/tool_doswin.c b/src/tool_doswin.c
new file mode 100644
index 000000000..b23b50af1
--- /dev/null
+++ b/src/tool_doswin.c
@@ -0,0 +1,300 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#if defined(MSDOS) || defined(WIN32)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+# include <libgen.h>
+#endif
+
+#ifdef WIN32
+# include <curl/curl.h>
+# include "tool_cfgable.h"
+# include "tool_libinfo.h"
+#endif
+
+#include "tool_bname.h"
+#include "tool_doswin.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+ * Macros ALWAYS_TRUE and ALWAYS_FALSE are used to avoid compiler warnings.
+ */
+
+#define ALWAYS_TRUE (1)
+#define ALWAYS_FALSE (0)
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# undef ALWAYS_TRUE
+# undef ALWAYS_FALSE
+# if (_MSC_VER < 1500)
+# define ALWAYS_TRUE (0, 1)
+# define ALWAYS_FALSE (1, 0)
+# else
+# define ALWAYS_TRUE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+(1) \
+__pragma(warning(pop))
+# define ALWAYS_FALSE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+(0) \
+__pragma(warning(pop))
+# endif
+#endif
+
+#ifdef WIN32
+# undef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) (0) /* cannot tell if file is a device */
+# endif
+#endif
+
+#ifdef WIN32
+# define _use_lfn(f) ALWAYS_TRUE /* long file names always available */
+#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
+# define _use_lfn(f) ALWAYS_FALSE /* long file names never available */
+#endif
+
+static const char *msdosify (const char *file_name);
+static char *rename_if_dos_device_name (char *file_name);
+
+/*
+ * sanitize_dos_name: returns a newly allocated string holding a
+ * valid file name which will be a transformation of given argument
+ * in case this wasn't already a valid file name.
+ *
+ * This function takes ownership of given argument, free'ing it before
+ * returning. Caller is responsible of free'ing returned string. Upon
+ * out of memory condition function returns NULL.
+ */
+
+char *sanitize_dos_name(char *file_name)
+{
+ char new_name[PATH_MAX];
+
+ if(!file_name)
+ return NULL;
+
+ if(strlen(file_name) >= PATH_MAX)
+ file_name[PATH_MAX-1] = '\0'; /* truncate it */
+
+ strcpy(new_name, msdosify(file_name));
+
+ Curl_safefree(file_name);
+
+ return strdup(rename_if_dos_device_name(new_name));
+}
+
+/* The following functions are taken with modification from the DJGPP
+ * port of tar 1.12. They use algorithms originally from DJTAR. */
+
+static const char *msdosify (const char *file_name)
+{
+ static char dos_name[PATH_MAX];
+ static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
+ "|<>\\\":?*"; /* illegal in DOS & W95 */
+ static const char *illegal_chars_w95 = &illegal_chars_dos[8];
+ int idx, dot_idx;
+ const char *s = file_name;
+ char *d = dos_name;
+ const char *const dlimit = dos_name + sizeof(dos_name) - 1;
+ const char *illegal_aliens = illegal_chars_dos;
+ size_t len = sizeof(illegal_chars_dos) - 1;
+
+ /* Support for Windows 9X VFAT systems, when available. */
+ if(_use_lfn(file_name)) {
+ illegal_aliens = illegal_chars_w95;
+ len -= (illegal_chars_w95 - illegal_chars_dos);
+ }
+
+ /* Get past the drive letter, if any. */
+ if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
+ if(memchr(illegal_aliens, *s, len)) {
+ /* Dots are special: DOS doesn't allow them as the leading character,
+ and a file name cannot have more than a single dot. We leave the
+ first non-leading dot alone, unless it comes too close to the
+ beginning of the name: we want sh.lex.c to become sh_lex.c, not
+ sh.lex-c. */
+ if(*s == '.') {
+ if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
+ /* Copy "./" and "../" verbatim. */
+ *d++ = *s++;
+ if(*s == '.')
+ *d++ = *s++;
+ *d = *s;
+ }
+ else if(idx == 0)
+ *d = '_';
+ else if(dot_idx >= 0) {
+ if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
+ d[dot_idx - idx] = '_'; /* replace previous dot */
+ *d = '.';
+ }
+ else
+ *d = '-';
+ }
+ else
+ *d = '.';
+
+ if(*s == '.')
+ dot_idx = idx;
+ }
+ else if(*s == '+' && s[1] == '+') {
+ if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
+ *d++ = 'x';
+ *d = 'x';
+ }
+ else {
+ /* libg++ etc. */
+ memcpy (d, "plus", 4);
+ d += 3;
+ }
+ s++;
+ idx++;
+ }
+ else
+ *d = '_';
+ }
+ else
+ *d = *s;
+ if(*s == '/') {
+ idx = 0;
+ dot_idx = -1;
+ }
+ else
+ idx++;
+ }
+
+ *d = '\0';
+ return dos_name;
+}
+
+static char *rename_if_dos_device_name (char *file_name)
+{
+ /* We could have a file whose name is a device on MS-DOS. Trying to
+ * retrieve such a file would fail at best and wedge us at worst. We need
+ * to rename such files. */
+ char *base;
+ struct_stat st_buf;
+ char fname[PATH_MAX];
+
+ strncpy(fname, file_name, PATH_MAX-1);
+ fname[PATH_MAX-1] = '\0';
+ base = basename(fname);
+ if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
+ size_t blen = strlen(base);
+
+ if(strlen(fname) >= PATH_MAX-1) {
+ /* Make room for the '_' */
+ blen--;
+ base[blen] = '\0';
+ }
+ /* Prepend a '_'. */
+ memmove(base + 1, base, blen + 1);
+ base[0] = '_';
+ strcpy(file_name, fname);
+ }
+ return file_name;
+}
+
+#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
+
+/*
+ * Disable program default argument globbing. We do it on our own.
+ */
+char **__crt0_glob_function(char *arg)
+{
+ (void)arg;
+ return (char**)0;
+}
+
+#endif /* MSDOS && (__DJGPP__ || __GO32__) */
+
+#ifdef WIN32
+
+/*
+ * Function to find CACert bundle on a Win32 platform using SearchPath.
+ * (SearchPath is already declared via inclusions done in setup header file)
+ * (Use the ASCII version instead of the unicode one!)
+ * The order of the directories it searches is:
+ * 1. application's directory
+ * 2. current working directory
+ * 3. Windows System directory (e.g. C:\windows\system32)
+ * 4. Windows Directory (e.g. C:\windows)
+ * 5. all directories along %PATH%
+ *
+ * For WinXP and later search order actually depends on registry value:
+ * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
+ */
+
+CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file)
+{
+ CURLcode result = CURLE_OK;
+
+ /* search and set cert file only if libcurl supports SSL */
+ if(curlinfo->features & CURL_VERSION_SSL) {
+
+ DWORD res_len;
+ DWORD buf_tchar_size = PATH_MAX + 1;
+ DWORD buf_bytes_size = sizeof(TCHAR) * buf_tchar_size;
+ char *ptr = NULL;
+
+ char *buf = malloc(buf_bytes_size);
+ if(!buf)
+ return CURLE_OUT_OF_MEMORY;
+ buf[0] = '\0';
+
+ res_len = SearchPathA(NULL, bundle_file, NULL, buf_tchar_size, buf, &ptr);
+ if(res_len > 0) {
+ Curl_safefree(config->cacert);
+ config->cacert = strdup(buf);
+ if(!config->cacert)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else
+ result = CURLE_SSL_CACERT;
+
+ Curl_safefree(buf);
+ }
+
+ return result;
+}
+
+#endif /* WIN32 */
+
+#endif /* MSDOS || WIN32 */
+
diff --git a/src/tool_doswin.h b/src/tool_doswin.h
new file mode 100644
index 000000000..ce475acf9
--- /dev/null
+++ b/src/tool_doswin.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_TOOL_DOSWIN_H
+#define HEADER_CURL_TOOL_DOSWIN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#if defined(MSDOS) || defined(WIN32)
+
+char *sanitize_dos_name(char *file_name);
+
+#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
+
+char **__crt0_glob_function(char *arg);
+
+#endif /* MSDOS && (__DJGPP__ || __GO32__) */
+
+#ifdef WIN32
+
+CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file);
+
+#endif /* WIN32 */
+
+#endif /* MSDOS || WIN32 */
+
+#endif /* HEADER_CURL_TOOL_DOSWIN_H */
+
diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c
new file mode 100644
index 000000000..5c42e808e
--- /dev/null
+++ b/src/tool_easysrc.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_easysrc.h"
+#include "tool_msgs.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* global variable definitions, for easy-interface source code generation */
+
+struct curl_slist *easysrc = NULL;
+struct curl_slist *easysrc_remarks = NULL;
+
+static const char *const srchead[]={
+ "/********* Sample code generated by the curl command line tool **********",
+ " * All curl_easy_setopt() options are documented at:",
+ " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html",
+ " ************************************************************************/",
+ "#include <curl/curl.h>",
+ "",
+ "int main(int argc, char *argv[])",
+ "{",
+ " CURLcode ret;",
+ NULL
+};
+
+void dumpeasysrc(struct Configurable *config)
+{
+ struct curl_slist *ptr;
+ char *o = config->libcurl;
+
+ if(o) {
+ FILE *out;
+ bool fopened = FALSE;
+ if(strcmp(o, "-")) {
+ out = fopen(o, "wt");
+ fopened = TRUE;
+ }
+ else
+ out = stdout;
+ if(!out)
+ warnf(config, "Failed to open %s to write libcurl code!\n", o);
+ else {
+ int i;
+ const char *c;
+
+ for(i=0; ((c = srchead[i]) != '\0'); i++)
+ fprintf(out, "%s\n", c);
+
+ ptr = easysrc;
+ while(ptr) {
+ fprintf(out, " %s\n", ptr->data);
+ ptr = ptr->next;
+ }
+
+ ptr = easysrc_remarks;
+ if(ptr) {
+ fprintf(out,
+ "\n /* Here is a list of options the curl code"
+ " used that cannot get generated\n"
+ " as source easily. You may select to either"
+ " not use them or implement\n them yourself.\n"
+ "\n");
+ while(ptr) {
+ fprintf(out, " %s\n", ptr->data);
+ ptr = ptr->next;
+ }
+ fprintf(out, "\n */\n");
+ }
+
+ fprintf(out,
+ " return (int)ret;\n"
+ "}\n"
+ "/**** End of sample code ****/\n");
+ if(fopened)
+ fclose(out);
+ }
+ }
+
+ curl_slist_free_all(easysrc_remarks);
+ curl_slist_free_all(easysrc);
+ easysrc_remarks = NULL;
+ easysrc = NULL;
+}
+
diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h
new file mode 100644
index 000000000..21b567458
--- /dev/null
+++ b/src/tool_easysrc.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_TOOL_EASYSRC_H
+#define HEADER_CURL_TOOL_EASYSRC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/* global variable declarations, for easy-interface source code generation */
+
+extern struct curl_slist *easysrc;
+extern struct curl_slist *easysrc_remarks;
+
+void dumpeasysrc(struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_EASYSRC_H */
+
diff --git a/src/tool_formparse.c b/src/tool_formparse.c
new file mode 100644
index 000000000..5d6263e5c
--- /dev/null
+++ b/src/tool_formparse.c
@@ -0,0 +1,321 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_mfiles.h"
+#include "tool_msgs.h"
+#include "tool_formparse.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/***************************************************************************
+ *
+ * formparse()
+ *
+ * Reads a 'name=value' parameter and builds the appropriate linked list.
+ *
+ * Specify files to upload with 'name=@filename'. Supports specified
+ * given Content-Type of the files. Such as ';type=<content-type>'.
+ *
+ * If literal_value is set, any initial '@' or '<' in the value string
+ * loses its special meaning, as does any embedded ';type='.
+ *
+ * You may specify more than one file for a single name (field). Specify
+ * multiple files by writing it like:
+ *
+ * 'name=@filename,filename2,filename3'
+ *
+ * If you want content-types specified for each too, write them like:
+ *
+ * 'name=@filename;type=image/gif,filename2,filename3'
+ *
+ * If you want custom headers added for a single part, write them in a separate
+ * file and do like this:
+ *
+ * 'name=foo;headers=@headerfile' or why not
+ * 'name=@filemame;headers=@headerfile'
+ *
+ * To upload a file, but to fake the file name that will be included in the
+ * formpost, do like this:
+ *
+ * 'name=@filename;filename=/dev/null'
+ *
+ * This function uses curl_formadd to fulfill it's job. Is heavily based on
+ * the old curl_formparse code.
+ *
+ ***************************************************************************/
+
+#define FORM_FILE_SEPARATOR ','
+#define FORM_TYPE_SEPARATOR ';'
+
+int formparse(struct Configurable *config,
+ const char *input,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ bool literal_value)
+{
+ /* nextarg MUST be a string in the format 'name=contents' and we'll
+ build a linked list with the info */
+ char name[256];
+ char *contents = NULL;
+ char major[128];
+ char minor[128];
+ char *contp;
+ const char *type = NULL;
+ char *sep;
+ char *sep2;
+
+ if((1 == sscanf(input, "%255[^=]=", name)) &&
+ ((contp = strchr(input, '=')) != NULL)) {
+ /* the input was using the correct format */
+
+ /* Allocate the contents */
+ contents = strdup(contp+1);
+ if(!contents) {
+ fprintf(config->errors, "out of memory\n");
+ return 1;
+ }
+ contp = contents;
+
+ if('@' == contp[0] && !literal_value) {
+
+ /* we use the @-letter to indicate file name(s) */
+
+ struct multi_files *multi_start = NULL;
+ struct multi_files *multi_current = NULL;
+
+ contp++;
+
+ do {
+ /* since this was a file, it may have a content-type specifier
+ at the end too, or a filename. Or both. */
+ char *ptr;
+ char *filename = NULL;
+
+ sep = strchr(contp, FORM_TYPE_SEPARATOR);
+ sep2 = strchr(contp, FORM_FILE_SEPARATOR);
+
+ /* pick the closest */
+ if(sep2 && (sep2 < sep)) {
+ sep = sep2;
+
+ /* no type was specified! */
+ }
+
+ type = NULL;
+
+ if(sep) {
+
+ /* if we got here on a comma, don't do much */
+ if(FORM_FILE_SEPARATOR == *sep)
+ ptr = NULL;
+ else
+ ptr = sep+1;
+
+ *sep = '\0'; /* terminate file name at separator */
+
+ while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
+
+ /* pass all white spaces */
+ while(ISSPACE(*ptr))
+ ptr++;
+
+ if(checkprefix("type=", ptr)) {
+ /* set type pointer */
+ type = &ptr[5];
+
+ /* verify that this is a fine type specifier */
+ if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
+ major, minor)) {
+ warnf(config, "Illegally formatted content-type field!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 2; /* illegal content-type syntax! */
+ }
+
+ /* now point beyond the content-type specifier */
+ sep = (char *)type + strlen(major)+strlen(minor)+1;
+
+ /* there's a semicolon following - we check if it is a filename
+ specified and if not we simply assume that it is text that
+ the user wants included in the type and include that too up
+ to the next zero or semicolon. */
+ if((*sep==';') && !checkprefix(";filename=", sep)) {
+ sep2 = strchr(sep+1, ';');
+ if(sep2)
+ sep = sep2;
+ else
+ sep = sep + strlen(sep); /* point to end of string */
+ }
+
+ if(*sep) {
+ *sep = '\0'; /* zero terminate type string */
+
+ ptr = sep+1;
+ }
+ else
+ ptr = NULL; /* end */
+ }
+ else if(checkprefix("filename=", ptr)) {
+ filename = &ptr[9];
+ ptr = strchr(filename, FORM_TYPE_SEPARATOR);
+ if(!ptr) {
+ ptr = strchr(filename, FORM_FILE_SEPARATOR);
+ }
+ if(ptr) {
+ *ptr = '\0'; /* zero terminate */
+ ptr++;
+ }
+ }
+ else
+ /* confusion, bail out of loop */
+ break;
+ }
+ /* find the following comma */
+ if(ptr)
+ sep = strchr(ptr, FORM_FILE_SEPARATOR);
+ else
+ sep = NULL;
+ }
+ else {
+ sep = strchr(contp, FORM_FILE_SEPARATOR);
+ }
+ if(sep) {
+ /* the next file name starts here */
+ *sep = '\0';
+ sep++;
+ }
+ /* if type == NULL curl_formadd takes care of the problem */
+
+ if(!AddMultiFiles(contp, type, filename, &multi_start,
+ &multi_current)) {
+ warnf(config, "Error building form post!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 3;
+ }
+ contp = sep; /* move the contents pointer to after the separator */
+
+ } while(sep && *sep); /* loop if there's another file name */
+
+ /* now we add the multiple files section */
+ if(multi_start) {
+ struct curl_forms *forms = NULL;
+ struct multi_files *ptr = multi_start;
+ unsigned int i, count = 0;
+ while(ptr) {
+ ptr = ptr->next;
+ ++count;
+ }
+ forms = malloc((count+1)*sizeof(struct curl_forms));
+ if(!forms) {
+ fprintf(config->errors, "Error building form post!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 4;
+ }
+ for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) {
+ forms[i].option = ptr->form.option;
+ forms[i].value = ptr->form.value;
+ }
+ forms[count].option = CURLFORM_END;
+ FreeMultiInfo(&multi_start, &multi_current);
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_COPYNAME, name,
+ CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(forms);
+ Curl_safefree(contents);
+ return 5;
+ }
+ Curl_safefree(forms);
+ }
+ }
+ else {
+ struct curl_forms info[4];
+ int i = 0;
+ char *ct = literal_value ? NULL : strstr(contp, ";type=");
+
+ info[i].option = CURLFORM_COPYNAME;
+ info[i].value = name;
+ i++;
+
+ if(ct) {
+ info[i].option = CURLFORM_CONTENTTYPE;
+ info[i].value = &ct[6];
+ i++;
+ ct[0] = '\0'; /* zero terminate here */
+ }
+
+ if(contp[0]=='<' && !literal_value) {
+ info[i].option = CURLFORM_FILECONTENT;
+ info[i].value = contp+1;
+ i++;
+ info[i].option = CURLFORM_END;
+
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
+ warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
+ contp+1);
+ Curl_safefree(contents);
+ return 6;
+ }
+ }
+ else {
+#ifdef CURL_DOES_CONVERSIONS
+ if(convert_to_network(contp, strlen(contp))) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(contents);
+ return 7;
+ }
+#endif
+ info[i].option = CURLFORM_COPYCONTENTS;
+ info[i].value = contp;
+ i++;
+ info[i].option = CURLFORM_END;
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(contents);
+ return 8;
+ }
+ }
+ }
+
+ }
+ else {
+ warnf(config, "Illegally formatted input field!\n");
+ return 1;
+ }
+ Curl_safefree(contents);
+ return 0;
+}
+
diff --git a/src/tool_formparse.h b/src/tool_formparse.h
new file mode 100644
index 000000000..eebf507f4
--- /dev/null
+++ b/src/tool_formparse.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_FORMPARSE_H
+#define HEADER_CURL_TOOL_FORMPARSE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+int formparse(struct Configurable *config,
+ const char *input,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ bool literal_value);
+
+#endif /* HEADER_CURL_TOOL_FORMPARSE_H */
+
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
new file mode 100644
index 000000000..bd7375fd9
--- /dev/null
+++ b/src/tool_getparam.c
@@ -0,0 +1,1634 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#ifdef USE_MANUAL
+# include "hugehelp.h"
+#endif
+
+#include "tool_binmode.h"
+#include "tool_cfgable.h"
+#include "tool_cb_prg.h"
+#include "tool_formparse.h"
+#include "tool_getparam.h"
+#include "tool_help.h"
+#include "tool_helpers.h"
+#include "tool_libinfo.h"
+#include "tool_msgs.h"
+#include "tool_paramhlp.h"
+#include "tool_parsecfg.h"
+#include "tool_version.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef MSDOS
+# define USE_WATT32
+#endif
+
+#define GetStr(str,val) do { \
+ if(*(str)) { \
+ free(*(str)); \
+ *(str) = NULL; \
+ } \
+ if((val)) \
+ *(str) = strdup((val)); \
+ if(!(val)) \
+ return PARAM_NO_MEM; \
+} WHILE_FALSE
+
+struct LongShort {
+ const char *letter; /* short name option */
+ const char *lname; /* long name option */
+ bool extraparam; /* whether it takes an additional argument */
+};
+
+static const struct LongShort aliases[]= {
+ /* all these ones, starting with "*" or "$" as a short-option have *no*
+ short option to mention. */
+ {"*", "url", TRUE},
+ {"*a", "random-file", TRUE},
+ {"*b", "egd-file", TRUE},
+ {"*c", "connect-timeout", TRUE},
+ {"*d", "ciphers", TRUE},
+ {"*e", "disable-epsv", FALSE},
+ {"*E", "epsv", FALSE},
+ /* 'epsv' made like this to make --no-epsv and --epsv to work
+ although --disable-epsv is the documented option */
+#ifdef USE_ENVIRONMENT
+ {"*f", "environment", FALSE},
+#endif
+ {"*g", "trace", TRUE},
+ {"*h", "trace-ascii", TRUE},
+ {"*i", "limit-rate", TRUE},
+ {"*j", "compressed", FALSE},
+ {"*J", "tr-encoding", FALSE},
+ {"*k", "digest", FALSE},
+ {"*l", "negotiate", FALSE},
+ {"*m", "ntlm", FALSE},
+ {"*M", "ntlm-wb", FALSE},
+ {"*n", "basic", FALSE},
+ {"*o", "anyauth", FALSE},
+#ifdef USE_WATT32
+ {"*p", "wdebug", FALSE},
+#endif
+ {"*q", "ftp-create-dirs", FALSE},
+ {"*r", "create-dirs", FALSE},
+ {"*s", "max-redirs", TRUE},
+ {"*t", "proxy-ntlm", FALSE},
+ {"*u", "crlf", FALSE},
+ {"*v", "stderr", TRUE},
+ {"*w", "interface", TRUE},
+ {"*x", "krb" , TRUE},
+ {"*x", "krb4" , TRUE},
+ /* 'krb4' is the previous name */
+ {"*y", "max-filesize", TRUE},
+ {"*z", "disable-eprt", FALSE},
+ {"*Z", "eprt", FALSE},
+ /* 'eprt' made like this to make --no-eprt and --eprt to work
+ although --disable-eprt is the documented option */
+ {"$a", "ftp-ssl", FALSE},
+ /* 'ftp-ssl' deprecated name since 7.20.0 */
+ {"$a", "ssl", FALSE},
+ /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */
+ {"$b", "ftp-pasv", FALSE},
+ {"$c", "socks5", TRUE},
+ {"$c", "socks", TRUE},
+ /* 'socks' is how the option once was documented but we prefer
+ the --socks5 version for explicit version */
+ {"$d", "tcp-nodelay", FALSE},
+ {"$e", "proxy-digest", FALSE},
+ {"$f", "proxy-basic", FALSE},
+ {"$g", "retry", TRUE},
+ {"$h", "retry-delay", TRUE},
+ {"$i", "retry-max-time", TRUE},
+ {"$k", "proxy-negotiate", FALSE},
+ {"$m", "ftp-account", TRUE},
+ {"$n", "proxy-anyauth", FALSE},
+ {"$o", "trace-time", FALSE},
+ {"$p", "ignore-content-length", FALSE},
+ {"$q", "ftp-skip-pasv-ip", FALSE},
+ {"$r", "ftp-method", TRUE},
+ {"$s", "local-port", TRUE},
+ {"$t", "socks4", TRUE},
+ {"$T", "socks4a", TRUE},
+ {"$u", "ftp-alternative-to-user", TRUE},
+ {"$v", "ftp-ssl-reqd", FALSE},
+ /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */
+ {"$v", "ssl-reqd", FALSE},
+ /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */
+ {"$w", "sessionid", FALSE},
+ /* ¡sessionid' listed as --no-sessionid in the help */
+ {"$x", "ftp-ssl-control", FALSE},
+ {"$y", "ftp-ssl-ccc", FALSE},
+ {"$j", "ftp-ssl-ccc-mode", TRUE},
+ {"$z", "libcurl", TRUE},
+ {"$#", "raw", FALSE},
+ {"$0", "post301", FALSE},
+ {"$1", "keepalive", FALSE},
+ /* 'keepalive' listed as --no-keepalive in the help */
+ {"$2", "socks5-hostname", TRUE},
+ {"$3", "keepalive-time", TRUE},
+ {"$4", "post302", FALSE},
+ {"$5", "noproxy", TRUE},
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ {"$6", "socks5-gssapi-service", TRUE},
+ {"$7", "socks5-gssapi-nec", FALSE},
+#endif
+ {"$8", "proxy1.0", TRUE},
+ {"$9", "tftp-blksize", TRUE},
+ {"$A", "mail-from", TRUE},
+ {"$B", "mail-rcpt", TRUE},
+ {"$C", "ftp-pret", FALSE},
+ {"$D", "proto", TRUE},
+ {"$E", "proto-redir", TRUE},
+ {"$F", "resolve", TRUE},
+ {"$G", "delegation", TRUE},
+ {"0", "http1.0", FALSE},
+ {"1", "tlsv1", FALSE},
+ {"2", "sslv2", FALSE},
+ {"3", "sslv3", FALSE},
+ {"4", "ipv4", FALSE},
+ {"6", "ipv6", FALSE},
+ {"a", "append", FALSE},
+ {"A", "user-agent", TRUE},
+ {"b", "cookie", TRUE},
+ {"B", "use-ascii", FALSE},
+ {"c", "cookie-jar", TRUE},
+ {"C", "continue-at", TRUE},
+ {"d", "data", TRUE},
+ {"da", "data-ascii", TRUE},
+ {"db", "data-binary", TRUE},
+ {"de", "data-urlencode", TRUE},
+ {"D", "dump-header", TRUE},
+ {"e", "referer", TRUE},
+ {"E", "cert", TRUE},
+ {"Ea", "cacert", TRUE},
+ {"Eb", "cert-type", TRUE},
+ {"Ec", "key", TRUE},
+ {"Ed", "key-type", TRUE},
+ {"Ee", "pass", TRUE},
+ {"Ef", "engine", TRUE},
+ {"Eg", "capath ", TRUE},
+ {"Eh", "pubkey", TRUE},
+ {"Ei", "hostpubmd5", TRUE},
+ {"Ej", "crlfile", TRUE},
+ {"Ek", "tlsuser", TRUE},
+ {"El", "tlspassword", TRUE},
+ {"Em", "tlsauthtype", TRUE},
+ {"f", "fail", FALSE},
+ {"F", "form", TRUE},
+ {"Fs", "form-string", TRUE},
+ {"g", "globoff", FALSE},
+ {"G", "get", FALSE},
+ {"h", "help", FALSE},
+ {"H", "header", TRUE},
+ {"i", "include", FALSE},
+ {"I", "head", FALSE},
+ {"j", "junk-session-cookies", FALSE},
+ {"J", "remote-header-name", FALSE},
+ {"k", "insecure", FALSE},
+ {"K", "config", TRUE},
+ {"l", "list-only", FALSE},
+ {"L", "location", FALSE},
+ {"Lt", "location-trusted", FALSE},
+ {"m", "max-time", TRUE},
+ {"M", "manual", FALSE},
+ {"n", "netrc", FALSE},
+ {"no", "netrc-optional", FALSE},
+ {"ne", "netrc-file", TRUE},
+ {"N", "buffer", FALSE},
+ /* 'buffer' listed as --no-buffer in the help */
+ {"o", "output", TRUE},
+ {"O", "remote-name", FALSE},
+ {"Oa", "remote-name-all", FALSE},
+ {"p", "proxytunnel", FALSE},
+ {"P", "ftpport", TRUE},
+ /* 'ftpport' old version */
+ {"P", "ftp-port", TRUE},
+ {"q", "disable", FALSE},
+ {"Q", "quote", TRUE},
+ {"r", "range", TRUE},
+ {"R", "remote-time", FALSE},
+ {"s", "silent", FALSE},
+ {"S", "show-error", FALSE},
+ {"t", "telnet-options", TRUE},
+ /* 'telnet-options' documented as telnet-option */
+ {"T", "upload-file", TRUE},
+ {"u", "user", TRUE},
+ {"U", "proxy-user", TRUE},
+ {"v", "verbose", FALSE},
+ {"V", "version", FALSE},
+ {"w", "write-out", TRUE},
+ {"x", "proxy", TRUE},
+ {"X", "request", TRUE},
+ {"X", "http-request", TRUE},
+ /* 'http-request' OBSOLETE VERSION */
+ {"Y", "speed-limit", TRUE},
+ {"y", "speed-time", TRUE},
+ {"z", "time-cond", TRUE},
+ {"#", "progress-bar", FALSE},
+ {"~", "xattr", FALSE},
+};
+
+struct feat {
+ const char *name;
+ int bitmask;
+};
+
+static const struct feat feats[] = {
+ {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
+ {"Debug", CURL_VERSION_DEBUG},
+ {"TrackMemory", CURL_VERSION_CURLDEBUG},
+ {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
+ {"IDN", CURL_VERSION_IDN},
+ {"IPv6", CURL_VERSION_IPV6},
+ {"Largefile", CURL_VERSION_LARGEFILE},
+ {"NTLM", CURL_VERSION_NTLM},
+ {"NTLM_WB", CURL_VERSION_NTLM_WB},
+ {"SPNEGO", CURL_VERSION_SPNEGO},
+ {"SSL", CURL_VERSION_SSL},
+ {"SSPI", CURL_VERSION_SSPI},
+ {"krb4", CURL_VERSION_KERBEROS4},
+ {"libz", CURL_VERSION_LIBZ},
+ {"CharConv", CURL_VERSION_CONV},
+ {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}
+};
+
+ParameterError getparameter(char *flag, /* f or -long-flag */
+ char *nextarg, /* NULL if unset */
+ bool *usedarg, /* set to TRUE if the arg
+ has been used */
+ struct Configurable *config)
+{
+ char letter;
+ char subletter = '\0'; /* subletters can only occur on long options */
+ int rc;
+ const char *parse = NULL;
+ unsigned int j;
+ time_t now;
+ int hit = -1;
+ bool longopt = FALSE;
+ bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
+ ParameterError err;
+ bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
+ by using --OPTION or --no-OPTION */
+
+
+ if(('-' != flag[0]) ||
+ (('-' == flag[0]) && ('-' == flag[1]))) {
+ /* this should be a long name */
+ char *word = ('-' == flag[0]) ? flag+2 : flag;
+ size_t fnam = strlen(word);
+ int numhits = 0;
+
+ if(!strncmp(word, "no-", 3)) {
+ /* disable this option but ignore the "no-" part when looking for it */
+ word += 3;
+ toggle = FALSE;
+ }
+
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(curlx_strnequal(aliases[j].lname, word, fnam)) {
+ longopt = TRUE;
+ numhits++;
+ if(curlx_raw_equal(aliases[j].lname, word)) {
+ parse = aliases[j].letter;
+ hit = j;
+ numhits = 1; /* a single unique hit */
+ break;
+ }
+ parse = aliases[j].letter;
+ hit = j;
+ }
+ }
+ if(numhits > 1) {
+ /* this is at least the second match! */
+ return PARAM_OPTION_AMBIGUOUS;
+ }
+ if(hit < 0) {
+ return PARAM_OPTION_UNKNOWN;
+ }
+ }
+ else {
+ flag++; /* prefixed with one dash, pass it */
+ hit = -1;
+ parse = flag;
+ }
+
+ do {
+ /* we can loop here if we have multiple single-letters */
+
+ if(!longopt) {
+ if(NULL != parse) {
+ letter = (char)*parse;
+ }
+ else {
+ letter = '\0';
+ }
+ subletter='\0';
+ }
+ else {
+ letter = parse[0];
+ subletter = parse[1];
+ }
+ *usedarg = FALSE; /* default is that we don't use the arg */
+
+ if(hit < 0) {
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(letter == aliases[j].letter[0]) {
+ hit = j;
+ break;
+ }
+ }
+ if(hit < 0) {
+ return PARAM_OPTION_UNKNOWN;
+ }
+ }
+
+ if(aliases[hit].extraparam) {
+ /* this option requires an extra parameter */
+ if(!longopt && parse[1]) {
+ nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
+ singleopt = TRUE; /* don't loop anymore after this */
+ }
+ else if(!nextarg)
+ return PARAM_REQUIRES_PARAMETER;
+ else
+ *usedarg = TRUE; /* mark it as used */
+ }
+
+ switch(letter) {
+ case '*': /* options without a short option */
+ switch(subletter) {
+ case 'a': /* random-file */
+ GetStr(&config->random_file, nextarg);
+ break;
+ case 'b': /* egd-file */
+ GetStr(&config->egd_file, nextarg);
+ break;
+ case 'c': /* connect-timeout */
+ if(str2num(&config->connecttimeout, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case 'd': /* ciphers */
+ GetStr(&config->cipher_list, nextarg);
+ break;
+ case 'e': /* --disable-epsv */
+ config->disable_epsv = toggle;
+ break;
+ case 'E': /* --epsv */
+ config->disable_epsv = (!toggle)?TRUE:FALSE;
+ break;
+#ifdef USE_ENVIRONMENT
+ case 'f':
+ config->writeenv = toggle;
+ break;
+#endif
+ case 'g': /* --trace */
+ GetStr(&config->trace_dump, nextarg);
+ if(config->tracetype && (config->tracetype != TRACE_BIN))
+ warnf(config, "--trace overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_BIN;
+ break;
+ case 'h': /* --trace-ascii */
+ GetStr(&config->trace_dump, nextarg);
+ if(config->tracetype && (config->tracetype != TRACE_ASCII))
+ warnf(config,
+ "--trace-ascii overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_ASCII;
+ break;
+ case 'i': /* --limit-rate */
+ {
+ /* We support G, M, K too */
+ char *unit;
+ curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
+
+ if(!*unit)
+ unit = (char *)"b";
+ else if(strlen(unit) > 1)
+ unit = (char *)"w"; /* unsupported */
+
+ switch(*unit) {
+ case 'G':
+ case 'g':
+ value *= 1024*1024*1024;
+ break;
+ case 'M':
+ case 'm':
+ value *= 1024*1024;
+ break;
+ case 'K':
+ case 'k':
+ value *= 1024;
+ break;
+ case 'b':
+ case 'B':
+ /* for plain bytes, leave as-is */
+ break;
+ default:
+ warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
+ return PARAM_BAD_USE;
+ }
+ config->recvpersecond = value;
+ config->sendpersecond = value;
+ }
+ break;
+
+ case 'j': /* --compressed */
+ if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->encoding = toggle;
+ break;
+
+ case 'J': /* --tr-encoding */
+ config->tr_encoding = toggle;
+ break;
+
+ case 'k': /* --digest */
+ if(toggle)
+ config->authtype |= CURLAUTH_DIGEST;
+ else
+ config->authtype &= ~CURLAUTH_DIGEST;
+ break;
+
+ case 'l': /* --negotiate */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+ config->authtype |= CURLAUTH_GSSNEGOTIATE;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
+ break;
+
+ case 'm': /* --ntlm */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_NTLM)
+ config->authtype |= CURLAUTH_NTLM;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_NTLM;
+ break;
+
+ case 'M': /* --ntlm-wb */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_NTLM_WB)
+ config->authtype |= CURLAUTH_NTLM_WB;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_NTLM_WB;
+ break;
+
+ case 'n': /* --basic for completeness */
+ if(toggle)
+ config->authtype |= CURLAUTH_BASIC;
+ else
+ config->authtype &= ~CURLAUTH_BASIC;
+ break;
+
+ case 'o': /* --anyauth, let libcurl pick it */
+ if(toggle)
+ config->authtype = CURLAUTH_ANY;
+ /* --no-anyauth simply doesn't touch it */
+ break;
+
+#ifdef USE_WATT32
+ case 'p': /* --wdebug */
+ dbug_init();
+ break;
+#endif
+ case 'q': /* --ftp-create-dirs */
+ config->ftp_create_dirs = toggle;
+ break;
+
+ case 'r': /* --create-dirs */
+ config->create_dirs = TRUE;
+ break;
+
+ case 's': /* --max-redirs */
+ /* specified max no of redirects (http(s)) */
+ if(str2num(&config->maxredirs, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+
+ case 't': /* --proxy-ntlm */
+ if(curlinfo->features & CURL_VERSION_NTLM)
+ config->proxyntlm = toggle;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+
+ case 'u': /* --crlf */
+ /* LF -> CRLF conversion? */
+ config->crlf = TRUE;
+ break;
+
+ case 'v': /* --stderr */
+ if(strcmp(nextarg, "-")) {
+ FILE *newfile = fopen(nextarg, "wt");
+ if(!newfile)
+ warnf(config, "Failed to open %s!\n", nextarg);
+ else {
+ if(config->errors_fopened)
+ fclose(config->errors);
+ config->errors = newfile;
+ config->errors_fopened = TRUE;
+ }
+ }
+ else
+ config->errors = stdout;
+ break;
+ case 'w': /* --interface */
+ /* interface */
+ GetStr(&config->iface, nextarg);
+ break;
+ case 'x': /* --krb */
+ /* kerberos level string */
+ if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
+ CURL_VERSION_GSSNEGOTIATE))
+ GetStr(&config->krblevel, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'y': /* --max-filesize */
+ if(str2offset(&config->max_filesize, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case 'z': /* --disable-eprt */
+ config->disable_eprt = toggle;
+ break;
+ case 'Z': /* --eprt */
+ config->disable_eprt = (!toggle)?TRUE:FALSE;
+ break;
+
+ default: /* the URL! */
+ {
+ struct getout *url;
+ if(config->url_get || ((config->url_get = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_get && (config->url_get->flags & GETOUT_URL))
+ config->url_get = config->url_get->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_get)
+ /* existing node */
+ url = config->url_get;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ /* fill in the URL */
+ GetStr(&url->url, nextarg);
+ url->flags |= GETOUT_URL;
+ }
+ }
+ }
+ break;
+ case '$': /* more options without a short option */
+ switch(subletter) {
+ case 'a': /* --ftp-ssl */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl = toggle;
+ break;
+ case 'b': /* --ftp-pasv */
+ Curl_safefree(config->ftpport);
+ break;
+ case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
+ the name locally and passes on the resolved address */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS5;
+ break;
+ case 't': /* --socks4 specifies a socks4 proxy to use */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS4;
+ break;
+ case 'T': /* --socks4a specifies a socks4a proxy to use */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS4A;
+ break;
+ case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
+ resolving with the proxy */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
+ break;
+ case 'd': /* --tcp-nodelay option */
+ config->tcp_nodelay = toggle;
+ break;
+ case 'e': /* --proxy-digest */
+ config->proxydigest = toggle;
+ break;
+ case 'f': /* --proxy-basic */
+ config->proxybasic = toggle;
+ break;
+ case 'g': /* --retry */
+ if(str2num(&config->req_retry, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case 'h': /* --retry-delay */
+ if(str2num(&config->retry_delay, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case 'i': /* --retry-max-time */
+ if(str2num(&config->retry_maxtime, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+
+ case 'k': /* --proxy-negotiate */
+ if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+ config->proxynegotiate = toggle;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'm': /* --ftp-account */
+ GetStr(&config->ftp_account, nextarg);
+ break;
+ case 'n': /* --proxy-anyauth */
+ config->proxyanyauth = toggle;
+ break;
+ case 'o': /* --trace-time */
+ config->tracetime = toggle;
+ break;
+ case 'p': /* --ignore-content-length */
+ config->ignorecl = toggle;
+ break;
+ case 'q': /* --ftp-skip-pasv-ip */
+ config->ftp_skip_ip = toggle;
+ break;
+ case 'r': /* --ftp-method (undocumented at this point) */
+ config->ftp_filemethod = ftpfilemethod(config, nextarg);
+ break;
+ case 's': /* --local-port */
+ rc = sscanf(nextarg, "%d - %d",
+ &config->localport,
+ &config->localportrange);
+ if(!rc)
+ return PARAM_BAD_USE;
+ else if(rc == 1)
+ config->localportrange = 1; /* default number of ports to try */
+ else {
+ config->localportrange -= config->localport;
+ if(config->localportrange < 1) {
+ warnf(config, "bad range input\n");
+ return PARAM_BAD_USE;
+ }
+ }
+ break;
+ case 'u': /* --ftp-alternative-to-user */
+ GetStr(&config->ftp_alternative_to_user, nextarg);
+ break;
+ case 'v': /* --ftp-ssl-reqd */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl_reqd = toggle;
+ break;
+ case 'w': /* --no-sessionid */
+ config->disable_sessionid = (!toggle)?TRUE:FALSE;
+ break;
+ case 'x': /* --ftp-ssl-control */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl_control = toggle;
+ break;
+ case 'y': /* --ftp-ssl-ccc */
+ config->ftp_ssl_ccc = toggle;
+ if(!config->ftp_ssl_ccc_mode)
+ config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
+ break;
+ case 'j': /* --ftp-ssl-ccc-mode */
+ config->ftp_ssl_ccc = TRUE;
+ config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
+ break;
+ case 'z': /* --libcurl */
+ GetStr(&config->libcurl, nextarg);
+ break;
+ case '#': /* --raw */
+ config->raw = toggle;
+ break;
+ case '0': /* --post301 */
+ config->post301 = toggle;
+ break;
+ case '1': /* --no-keepalive */
+ config->nokeepalive = (!toggle)?TRUE:FALSE;
+ break;
+ case '3': /* --keepalive-time */
+ if(str2num(&config->alivetime, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case '4': /* --post302 */
+ config->post302 = toggle;
+ break;
+ case '5': /* --noproxy */
+ /* This specifies the noproxy list */
+ GetStr(&config->noproxy, nextarg);
+ break;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ case '6': /* --socks5-gssapi-service */
+ GetStr(&config->socks5_gssapi_service, nextarg);
+ break;
+ case '7': /* --socks5-gssapi-nec*/
+ config->socks5_gssapi_nec = TRUE;
+ break;
+#endif
+ case '8': /* --proxy1.0 */
+ /* http 1.0 proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_HTTP_1_0;
+ break;
+ case '9': /* --tftp-blksize */
+ str2num(&config->tftp_blksize, nextarg);
+ break;
+ case 'A': /* --mail-from */
+ GetStr(&config->mail_from, nextarg);
+ break;
+ case 'B': /* --mail-rcpt */
+ /* append receiver to a list */
+ err = add2list(&config->mail_rcpt, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'C': /* --ftp-pret */
+ config->ftp_pret = toggle;
+ break;
+ case 'D': /* --proto */
+ config->proto_present = TRUE;
+ if(proto2num(config, &config->proto, nextarg))
+ return PARAM_BAD_USE;
+ break;
+ case 'E': /* --proto-redir */
+ config->proto_redir_present = TRUE;
+ if(proto2num(config, &config->proto_redir, nextarg))
+ return PARAM_BAD_USE;
+ break;
+ case 'F': /* --resolve */
+ err = add2list(&config->resolve, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'G': /* --delegation LEVEL */
+ config->gssapi_delegation = delegation(config, nextarg);
+ break;
+ }
+ break;
+ case '#': /* --progress-bar */
+ if(toggle)
+ config->progressmode = CURL_PROGRESS_BAR;
+ else
+ config->progressmode = CURL_PROGRESS_STATS;
+ break;
+ case '~': /* --xattr */
+ config->xattr = toggle;
+ break;
+ case '0':
+ /* HTTP version 1.0 */
+ config->httpversion = CURL_HTTP_VERSION_1_0;
+ break;
+ case '1':
+ /* TLS version 1 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1;
+ break;
+ case '2':
+ /* SSL version 2 */
+ config->ssl_version = CURL_SSLVERSION_SSLv2;
+ break;
+ case '3':
+ /* SSL version 3 */
+ config->ssl_version = CURL_SSLVERSION_SSLv3;
+ break;
+ case '4':
+ /* IPv4 */
+ config->ip_version = 4;
+ break;
+ case '6':
+ /* IPv6 */
+ config->ip_version = 6;
+ break;
+ case 'a':
+ /* This makes the FTP sessions use APPE instead of STOR */
+ config->ftp_append = toggle;
+ break;
+ case 'A':
+ /* This specifies the User-Agent name */
+ GetStr(&config->useragent, nextarg);
+ break;
+ case 'b': /* cookie string coming up: */
+ if(nextarg[0] == '@') {
+ nextarg++;
+ }
+ else if(strchr(nextarg, '=')) {
+ /* A cookie string must have a =-letter */
+ GetStr(&config->cookie, nextarg);
+ break;
+ }
+ /* We have a cookie file to read from! */
+ GetStr(&config->cookiefile, nextarg);
+ break;
+ case 'B':
+ /* use ASCII/text when transferring */
+ config->use_ascii = toggle;
+ break;
+ case 'c':
+ /* get the file name to dump all cookies in */
+ GetStr(&config->cookiejar, nextarg);
+ break;
+ case 'C':
+ /* This makes us continue an ftp transfer at given position */
+ if(!curlx_strequal(nextarg, "-")) {
+ if(str2offset(&config->resume_from, nextarg))
+ return PARAM_BAD_NUMERIC;
+ config->resume_from_current = FALSE;
+ }
+ else {
+ config->resume_from_current = TRUE;
+ config->resume_from = 0;
+ }
+ config->use_resume=TRUE;
+ break;
+ case 'd':
+ /* postfield data */
+ {
+ char *postdata = NULL;
+ FILE *file;
+ size_t size = 0;
+
+ if(subletter == 'e') { /* --data-urlencode*/
+ /* [name]=[content], we encode the content part only
+ * [name]@[file name]
+ *
+ * Case 2: we first load the file using that name and then encode
+ * the content.
+ */
+ const char *p = strchr(nextarg, '=');
+ size_t nlen;
+ char is_file;
+ if(!p)
+ /* there was no '=' letter, check for a '@' instead */
+ p = strchr(nextarg, '@');
+ if(p) {
+ nlen = p - nextarg; /* length of the name part */
+ is_file = *p++; /* pass the separator */
+ }
+ else {
+ /* neither @ nor =, so no name and it isn't a file */
+ nlen = is_file = 0;
+ p = nextarg;
+ }
+ if('@' == is_file) {
+ /* a '@' letter, it means that a file name or - (stdin) follows */
+
+ if(curlx_strequal("-", p)) {
+ file = stdin;
+ set_binmode(stdin);
+ }
+ else {
+ file = fopen(p, "rb");
+ if(!file)
+ warnf(config,
+ "Couldn't read data from file \"%s\", this makes "
+ "an empty POST.\n", nextarg);
+ }
+
+ err = file2memory(&postdata, &size, file);
+
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+ }
+ else {
+ GetStr(&postdata, p);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+ if(!postdata) {
+ /* no data from the file, point to a zero byte string to make this
+ get sent as a POST anyway */
+ postdata = strdup("");
+ if(!postdata)
+ return PARAM_NO_MEM;
+ size = 0;
+ }
+ else {
+ char *enc = curl_easy_escape(config->easy, postdata, (int)size);
+ Curl_safefree(postdata); /* no matter if it worked or not */
+ if(enc) {
+ /* now make a string with the name from above and append the
+ encoded string */
+ size_t outlen = nlen + strlen(enc) + 2;
+ char *n = malloc(outlen);
+ if(!n) {
+ curl_free(enc);
+ return PARAM_NO_MEM;
+ }
+ if(nlen > 0) { /* only append '=' if we have a name */
+ snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
+ size = outlen-1;
+ }
+ else {
+ strcpy(n, enc);
+ size = outlen-2; /* since no '=' was inserted */
+ }
+ curl_free(enc);
+ postdata = n;
+ }
+ else
+ return PARAM_NO_MEM;
+ }
+ }
+ else if('@' == *nextarg) {
+ /* the data begins with a '@' letter, it means that a file name
+ or - (stdin) follows */
+ nextarg++; /* pass the @ */
+
+ if(curlx_strequal("-", nextarg)) {
+ file = stdin;
+ if(subletter == 'b') /* forced data-binary */
+ set_binmode(stdin);
+ }
+ else {
+ file = fopen(nextarg, "rb");
+ if(!file)
+ warnf(config, "Couldn't read data from file \"%s\", this makes "
+ "an empty POST.\n", nextarg);
+ }
+
+ if(subletter == 'b')
+ /* forced binary */
+ err = file2memory(&postdata, &size, file);
+ else {
+ err = file2string(&postdata, file);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+
+ if(!postdata) {
+ /* no data from the file, point to a zero byte string to make this
+ get sent as a POST anyway */
+ postdata = strdup("");
+ if(!postdata)
+ return PARAM_NO_MEM;
+ }
+ }
+ else {
+ GetStr(&postdata, nextarg);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(subletter != 'b') {
+ /* NOT forced binary, convert to ASCII */
+ if(convert_to_network(postdata, strlen(postdata))) {
+ Curl_safefree(postdata);
+ return PARAM_NO_MEM;
+ }
+ }
+#endif
+
+ if(config->postfields) {
+ /* we already have a string, we append this one with a separating
+ &-letter */
+ char *oldpost = config->postfields;
+ curl_off_t oldlen = config->postfieldsize;
+ curl_off_t newlen = oldlen + size + 2;
+ config->postfields = malloc((size_t)newlen);
+ if(!config->postfields) {
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ return PARAM_NO_MEM;
+ }
+ memcpy(config->postfields, oldpost, (size_t)oldlen);
+ /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */
+ config->postfields[oldlen] = '\x26';
+ memcpy(&config->postfields[oldlen+1], postdata, size);
+ config->postfields[oldlen+1+size] = '\0';
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ config->postfieldsize += size+1;
+ }
+ else {
+ config->postfields = postdata;
+ config->postfieldsize = size;
+ }
+ }
+ /*
+ We can't set the request type here, as this data might be used in
+ a simple GET if -G is used. Already or soon.
+
+ if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) {
+ Curl_safefree(postdata);
+ return PARAM_BAD_USE;
+ }
+ */
+ break;
+ case 'D':
+ /* dump-header to given file name */
+ GetStr(&config->headerfile, nextarg);
+ break;
+ case 'e':
+ {
+ char *ptr = strstr(nextarg, ";auto");
+ if(ptr) {
+ /* Automatic referer requested, this may be combined with a
+ set initial one */
+ config->autoreferer = TRUE;
+ *ptr = 0; /* zero terminate here */
+ }
+ else
+ config->autoreferer = FALSE;
+ GetStr(&config->referer, nextarg);
+ }
+ break;
+ case 'E':
+ switch(subletter) {
+ case 'a': /* CA info PEM file */
+ /* CA info PEM file */
+ GetStr(&config->cacert, nextarg);
+ break;
+ case 'b': /* cert file type */
+ GetStr(&config->cert_type, nextarg);
+ break;
+ case 'c': /* private key file */
+ GetStr(&config->key, nextarg);
+ break;
+ case 'd': /* private key file type */
+ GetStr(&config->key_type, nextarg);
+ break;
+ case 'e': /* private key passphrase */
+ GetStr(&config->key_passwd, nextarg);
+ cleanarg(nextarg);
+ break;
+ case 'f': /* crypto engine */
+ GetStr(&config->engine, nextarg);
+ if(config->engine && curlx_raw_equal(config->engine,"list"))
+ config->list_engines = TRUE;
+ break;
+ case 'g': /* CA info PEM file */
+ /* CA cert directory */
+ GetStr(&config->capath, nextarg);
+ break;
+ case 'h': /* --pubkey public key file */
+ GetStr(&config->pubkey, nextarg);
+ break;
+ case 'i': /* --hostpubmd5 md5 of the host public key */
+ GetStr(&config->hostpubmd5, nextarg);
+ if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
+ return PARAM_BAD_USE;
+ break;
+ case 'j': /* CRL info PEM file */
+ /* CRL file */
+ GetStr(&config->crlfile, nextarg);
+ break;
+ case 'k': /* TLS username */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
+ GetStr(&config->tls_username, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'l': /* TLS password */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
+ GetStr(&config->tls_password, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'm': /* TLS authentication type */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
+ GetStr(&config->tls_authtype, nextarg);
+ if(!strequal(config->tls_authtype, "SRP"))
+ return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
+ }
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ default: /* certificate file */
+ {
+ char *ptr = strchr(nextarg, ':');
+ /* Since we live in a world of weirdness and confusion, the win32
+ dudes can use : when using drive letters and thus
+ c:\file:password needs to work. In order not to break
+ compatibility, we still use : as separator, but we try to detect
+ when it is used for a file name! On windows. */
+#ifdef WIN32
+ if(ptr &&
+ (ptr == &nextarg[1]) &&
+ (nextarg[2] == '\\' || nextarg[2] == '/') &&
+ (ISALPHA(nextarg[0])) )
+ /* colon in the second column, followed by a backslash, and the
+ first character is an alphabetic letter:
+
+ this is a drive letter colon */
+ ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
+#endif
+ if(ptr) {
+ /* we have a password too */
+ *ptr = '\0';
+ ptr++;
+ GetStr(&config->key_passwd, ptr);
+ }
+ GetStr(&config->cert, nextarg);
+ cleanarg(nextarg);
+ }
+ }
+ break;
+ case 'f':
+ /* fail hard on errors */
+ config->failonerror = toggle;
+ break;
+ case 'F':
+ /* "form data" simulation, this is a little advanced so lets do our best
+ to sort this out slowly and carefully */
+ if(formparse(config,
+ nextarg,
+ &config->httppost,
+ &config->last_post,
+ (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */
+ return PARAM_BAD_USE;
+ if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
+ return PARAM_BAD_USE;
+ break;
+
+ case 'g': /* g disables URLglobbing */
+ config->globoff = toggle;
+ break;
+
+ case 'G': /* HTTP GET */
+ config->use_httpget = TRUE;
+ break;
+
+ case 'h': /* h for help */
+ if(toggle) {
+ tool_help();
+ return PARAM_HELP_REQUESTED;
+ }
+ /* we now actually support --no-help too! */
+ break;
+ case 'H':
+ /* A custom header to append to a list */
+ err = add2list(&config->headers, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'i':
+ config->include_headers = toggle; /* include the headers as well in the
+ general output stream */
+ break;
+ case 'j':
+ config->cookiesession = toggle;
+ break;
+ case 'I':
+ /*
+ * no_body will imply include_headers later on
+ */
+ config->no_body = toggle;
+ if(SetHTTPrequest(config,
+ (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
+ &config->httpreq))
+ return PARAM_BAD_USE;
+ break;
+ case 'J': /* --remote-header-name */
+ if(config->include_headers) {
+ warnf(config,
+ "--include and --remote-header-name cannot be combined.\n");
+ return PARAM_BAD_USE;
+ }
+ config->content_disposition = toggle;
+ break;
+ case 'k': /* allow insecure SSL connects */
+ config->insecure_ok = toggle;
+ break;
+ case 'K': /* parse config file */
+ if(parseconfig(nextarg, config))
+ warnf(config, "error trying read config from the '%s' file\n",
+ nextarg);
+ break;
+ case 'l':
+ config->dirlistonly = toggle; /* only list the names of the FTP dir */
+ break;
+ case 'L':
+ config->followlocation = toggle; /* Follow Location: HTTP headers */
+ switch (subletter) {
+ case 't':
+ /* Continue to send authentication (user+password) when following
+ * locations, even when hostname changed */
+ config->unrestricted_auth = toggle;
+ break;
+ }
+ break;
+ case 'm':
+ /* specified max time */
+ if(str2num(&config->timeout, nextarg))
+ return PARAM_BAD_NUMERIC;
+ break;
+ case 'M': /* M for manual, huge help */
+ if(toggle) { /* --no-manual shows no manual... */
+#ifdef USE_MANUAL
+ hugehelp();
+ return PARAM_HELP_REQUESTED;
+#else
+ warnf(config,
+ "built-in manual was disabled at build-time!\n");
+ return PARAM_OPTION_UNKNOWN;
+#endif
+ }
+ break;
+ case 'n':
+ switch(subletter) {
+ case 'o': /* CA info PEM file */
+ /* use .netrc or URL */
+ config->netrc_opt = toggle;
+ break;
+ case 'e': /* netrc-file */
+ GetStr(&config->netrc_file, nextarg);
+ break;
+ default:
+ /* pick info from .netrc, if this is used for http, curl will
+ automatically enfore user+password with the request */
+ config->netrc = toggle;
+ break;
+ }
+ break;
+ case 'N':
+ /* disable the output I/O buffering. note that the option is called
+ --buffer but is mostly used in the negative form: --no-buffer */
+ if(longopt)
+ config->nobuffer = (!toggle)?TRUE:FALSE;
+ else
+ config->nobuffer = toggle;
+ break;
+ case 'O': /* --remote-name */
+ if(subletter == 'a') { /* --remote-name-all */
+ config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
+ break;
+ }
+ /* fall-through! */
+ case 'o': /* --output */
+ /* output file */
+ {
+ struct getout *url;
+ if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
+ config->url_out = config->url_out->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_out)
+ /* existing node */
+ url = config->url_out;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ /* fill in the outfile */
+ if('o' == letter) {
+ GetStr(&url->outfile, nextarg);
+ url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+ }
+ else {
+ url->outfile = NULL; /* leave it */
+ if(toggle)
+ url->flags |= GETOUT_USEREMOTE; /* switch on */
+ else
+ url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+ }
+ url->flags |= GETOUT_OUTFILE;
+ }
+ }
+ break;
+ case 'P':
+ /* This makes the FTP sessions use PORT instead of PASV */
+ /* use <eth0> or <192.168.10.10> style addresses. Anything except
+ this will make us try to get the "default" address.
+ NOTE: this is a changed behaviour since the released 4.1!
+ */
+ GetStr(&config->ftpport, nextarg);
+ break;
+ case 'p':
+ /* proxy tunnel for non-http protocols */
+ config->proxytunnel = toggle;
+ break;
+
+ case 'q': /* if used first, already taken care of, we do it like
+ this so we don't cause an error! */
+ break;
+ case 'Q':
+ /* QUOTE command to send to FTP server */
+ switch(nextarg[0]) {
+ case '-':
+ /* prefixed with a dash makes it a POST TRANSFER one */
+ nextarg++;
+ err = add2list(&config->postquote, nextarg);
+ break;
+ case '+':
+ /* prefixed with a plus makes it a just-before-transfer one */
+ nextarg++;
+ err = add2list(&config->prequote, nextarg);
+ break;
+ default:
+ err = add2list(&config->quote, nextarg);
+ break;
+ }
+ if(err)
+ return err;
+ break;
+ case 'r':
+ /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
+ (and won't actually be range by definition). The man page previously
+ claimed that to be a good way, why this code is added to work-around
+ it. */
+ if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
+ char buffer[32];
+ curl_off_t off;
+ warnf(config,
+ "A specified range MUST include at least one dash (-). "
+ "Appending one for you!\n");
+ off = curlx_strtoofft(nextarg, NULL, 10);
+ snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
+ Curl_safefree(config->range);
+ config->range = strdup(buffer);
+ if(!config->range)
+ return PARAM_NO_MEM;
+ }
+ {
+ /* byte range requested */
+ char *tmp_range;
+ tmp_range = nextarg;
+ while(*tmp_range != '\0') {
+ if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
+ warnf(config,"Invalid character is found in given range. "
+ "A specified range MUST have only digits in "
+ "\'start\'-\'stop\'. The server's response to this "
+ "request is uncertain.\n");
+ break;
+ }
+ tmp_range++;
+ }
+ /* byte range requested */
+ GetStr(&config->range, nextarg);
+ }
+ break;
+ case 'R':
+ /* use remote file's time */
+ config->remote_time = toggle;
+ break;
+ case 's':
+ /* don't show progress meter, don't show errors : */
+ if(toggle)
+ config->mute = config->noprogress = TRUE;
+ else
+ config->mute = config->noprogress = FALSE;
+ if(config->showerror < 0)
+ /* if still on the default value, set showerror to the reverse of
+ toggle. This is to allow -S and -s to be used in an independent
+ order but still have the same effect. */
+ config->showerror = (!toggle)?TRUE:FALSE; /* toggle off */
+ break;
+ case 'S':
+ /* show errors */
+ config->showerror = toggle?1:0; /* toggle on if used with -s */
+ break;
+ case 't':
+ /* Telnet options */
+ err = add2list(&config->telnet_options, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'T':
+ /* we are uploading */
+ {
+ struct getout *url;
+ if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD))
+ config->url_out = config->url_out->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_out)
+ /* existing node */
+ url = config->url_out;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ url->flags |= GETOUT_UPLOAD; /* mark -T used */
+ if(!*nextarg)
+ url->flags |= GETOUT_NOUPLOAD;
+ else {
+ /* "-" equals stdin, but keep the string around for now */
+ GetStr(&url->infile, nextarg);
+ }
+ }
+ }
+ break;
+ case 'u':
+ /* user:password */
+ GetStr(&config->userpwd, nextarg);
+ cleanarg(nextarg);
+ err = checkpasswd("host", &config->userpwd);
+ if(err)
+ return err;
+ break;
+ case 'U':
+ /* Proxy user:password */
+ GetStr(&config->proxyuserpwd, nextarg);
+ cleanarg(nextarg);
+ err = checkpasswd("proxy", &config->proxyuserpwd);
+ if(err)
+ return err;
+ break;
+ case 'v':
+ if(toggle) {
+ /* the '%' thing here will cause the trace get sent to stderr */
+ Curl_safefree(config->trace_dump);
+ config->trace_dump = strdup("%");
+ if(!config->trace_dump)
+ return PARAM_NO_MEM;
+ if(config->tracetype && (config->tracetype != TRACE_PLAIN))
+ warnf(config,
+ "-v, --verbose overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_PLAIN;
+ }
+ else
+ /* verbose is disabled here */
+ config->tracetype = TRACE_NONE;
+ break;
+ case 'V':
+ {
+ const char *const *proto;
+
+ if(!toggle)
+ /* --no-version yields no output! */
+ break;
+
+ printf(CURL_ID "%s\n", curl_version());
+ if(curlinfo->protocols) {
+ printf("Protocols: ");
+ for(proto = curlinfo->protocols; *proto; ++proto) {
+ printf("%s ", *proto);
+ }
+ puts(""); /* newline */
+ }
+ if(curlinfo->features) {
+ unsigned int i;
+ printf("Features: ");
+ for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) {
+ if(curlinfo->features & feats[i].bitmask)
+ printf("%s ", feats[i].name);
+ }
+ puts(""); /* newline */
+ }
+ }
+ return PARAM_HELP_REQUESTED;
+ case 'w':
+ /* get the output string */
+ if('@' == *nextarg) {
+ /* the data begins with a '@' letter, it means that a file name
+ or - (stdin) follows */
+ FILE *file;
+ const char *fname;
+ nextarg++; /* pass the @ */
+ if(curlx_strequal("-", nextarg)) {
+ fname = "<stdin>";
+ file = stdin;
+ }
+ else {
+ fname = nextarg;
+ file = fopen(nextarg, "r");
+ }
+ err = file2string(&config->writeout, file);
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+ if(!config->writeout)
+ warnf(config, "Failed to read %s", fname);
+ }
+ else
+ GetStr(&config->writeout, nextarg);
+ break;
+ case 'x':
+ /* proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_HTTP;
+ break;
+ case 'X':
+ /* set custom request */
+ GetStr(&config->customrequest, nextarg);
+ break;
+ case 'y':
+ /* low speed time */
+ if(str2num(&config->low_speed_time, nextarg))
+ return PARAM_BAD_NUMERIC;
+ if(!config->low_speed_limit)
+ config->low_speed_limit = 1;
+ break;
+ case 'Y':
+ /* low speed limit */
+ if(str2num(&config->low_speed_limit, nextarg))
+ return PARAM_BAD_NUMERIC;
+ if(!config->low_speed_time)
+ config->low_speed_time = 30;
+ break;
+ case 'z': /* time condition coming up */
+ switch(*nextarg) {
+ case '+':
+ nextarg++;
+ default:
+ /* If-Modified-Since: (section 14.28 in RFC2068) */
+ config->timecond = CURL_TIMECOND_IFMODSINCE;
+ break;
+ case '-':
+ /* If-Unmodified-Since: (section 14.24 in RFC2068) */
+ config->timecond = CURL_TIMECOND_IFUNMODSINCE;
+ nextarg++;
+ break;
+ case '=':
+ /* Last-Modified: (section 14.29 in RFC2068) */
+ config->timecond = CURL_TIMECOND_LASTMOD;
+ nextarg++;
+ break;
+ }
+ now = time(NULL);
+ config->condtime=curl_getdate(nextarg, &now);
+ if(-1 == (int)config->condtime) {
+ /* now let's see if it is a file name to get the time from instead! */
+ struct_stat statbuf;
+ if(-1 == stat(nextarg, &statbuf)) {
+ /* failed, remove time condition */
+ config->timecond = CURL_TIMECOND_NONE;
+ warnf(config,
+ "Illegal date format for -z, --timecond (and not "
+ "a file name). Disabling time condition. "
+ "See curl_getdate(3) for valid date syntax.\n");
+ }
+ else {
+ /* pull the time out from the file */
+ config->condtime = statbuf.st_mtime;
+ }
+ }
+ break;
+ default: /* unknown flag */
+ return PARAM_OPTION_UNKNOWN;
+ }
+ hit = -1;
+
+ } while(!longopt && !singleopt && *++parse && !*usedarg);
+
+ return PARAM_OK;
+}
+
diff --git a/src/tool_getparam.h b/src/tool_getparam.h
new file mode 100644
index 000000000..c402fd77b
--- /dev/null
+++ b/src/tool_getparam.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_TOOL_GETPARAM_H
+#define HEADER_CURL_TOOL_GETPARAM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+typedef enum {
+ PARAM_OK,
+ PARAM_OPTION_AMBIGUOUS,
+ PARAM_OPTION_UNKNOWN,
+ PARAM_REQUIRES_PARAMETER,
+ PARAM_BAD_USE,
+ PARAM_HELP_REQUESTED,
+ PARAM_GOT_EXTRA_PARAMETER,
+ PARAM_BAD_NUMERIC,
+ PARAM_LIBCURL_DOESNT_SUPPORT,
+ PARAM_NO_MEM,
+ PARAM_LAST
+} ParameterError;
+
+ParameterError getparameter(char *flag,
+ char *nextarg,
+ bool *usedarg,
+ struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_GETPARAM_H */
+
diff --git a/src/getpass.c b/src/tool_getpass.c
index 95d257b2f..b6aa5dd5e 100644
--- a/src/getpass.c
+++ b/src/tool_getpass.c
@@ -19,46 +19,52 @@
* KIND, either express or implied.
*
***************************************************************************/
-
-/* This file is a reimplementation of the previous one, due to license
- problems. */
-
#include "setup.h"
#ifndef HAVE_GETPASS_R
/* this file is only for systems without getpass_r() */
-#include <stdio.h>
-#include <string.h>
-
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
-#include "getpass.h"
-
#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
+# include <fcntl.h>
#endif
+
#ifdef HAVE_TERMIOS_H
-#include <termios.h>
-#else
-#ifdef HAVE_TERMIO_H
-#include <termio.h>
+# include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+# include <termio.h>
#endif
+
+#ifdef __VMS
+# include descrip
+# include starlet
+# include iodef
+#endif
+
+#ifdef WIN32
+# include <conio.h>
#endif
-/* The last #include file should be: */
-#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
-#include "memdebug.h"
+#ifdef NETWARE
+# ifdef __NOVELL_LIBC__
+# include <screen.h>
+# else
+# include <nwconio.h>
+# endif
#endif
+#define _MPRINTF_REPLACE
+#include <curl/mprintf.h>
+
+#include "tool_getpass.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
#ifdef __VMS
/* VMS implementation */
-#include descrip
-#include starlet
-#include iodef
-/* #include iosbdef */
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
{
long sts;
@@ -76,15 +82,15 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
$DESCRIPTOR(ttdesc, "TT");
- buffer[0]='\0';
- sts = sys$assign(&ttdesc, &chan,0,0);
+ buffer[0] = '\0';
+ sts = sys$assign(&ttdesc, &chan, 0, 0);
if(sts & 1) {
sts = sys$qiow(0, chan,
IO$_READPROMPT | IO$M_NOECHO,
&iosb, 0, 0, buffer, buflen, 0, 0,
prompt, strlen(prompt));
- if((sts & 1) && (iosb.iosb$w_status&1))
+ if((sts & 1) && (iosb.iosb$w_status & 1))
buffer[iosb.iosb$w_bcnt] = '\0';
sts = sys$dassgn(chan);
@@ -94,14 +100,8 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
#define DONE
#endif /* __VMS */
-
-#ifdef WIN32
-/* Windows implementation */
-#include <conio.h>
-#endif
-
#ifdef __SYMBIAN32__
-#define getch() getchar()
+# define getch() getchar()
#endif
#if defined(WIN32) || defined(__SYMBIAN32__)
@@ -111,25 +111,25 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
size_t i;
fputs(prompt, stderr);
- for(i=0; i<buflen; i++) {
+ for(i = 0; i < buflen; i++) {
buffer[i] = (char)getch();
if(buffer[i] == '\r' || buffer[i] == '\n') {
- buffer[i] = 0;
+ buffer[i] = '\0';
break;
}
else
if(buffer[i] == '\b')
/* remove this letter and if this is not the first key, remove the
previous one as well */
- i = i - (i>=1?2:1);
+ i = i - (i >= 1) ? 2 : 1;
}
#ifndef __SYMBIAN32__
/* since echo is disabled, print a newline */
fputs("\n", stderr);
#endif
/* if user didn't hit ENTER, terminate buffer */
- if(i==buflen)
- buffer[buflen-1]=0;
+ if(i == buflen)
+ buffer[buflen-1] = '\0';
return buffer; /* we always return success */
}
@@ -139,13 +139,11 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
#ifdef NETWARE
/* NetWare implementation */
#ifdef __NOVELL_LIBC__
-#include <screen.h>
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
{
return getpassword(prompt, buffer, buflen);
}
#else
-#include <nwconio.h>
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
{
size_t i = 0;
@@ -169,7 +167,7 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
putchar('*');
} while((buffer[i-1] != 13) && (i < buflen));
- buffer[i-1] = 0;
+ buffer[i-1] = '\0';
printf("\r\n");
return buffer;
}
@@ -180,13 +178,11 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
#ifndef DONE /* not previously provided */
#ifdef HAVE_TERMIOS_H
-#define struct_term struct termios
-#else
-#ifdef HAVE_TERMIO_H
-#define struct_term struct termio
+# define struct_term struct termios
+#elif defined(HAVE_TERMIO_H)
+# define struct_term struct termio
#else
-#undef struct_term
-#endif
+# undef struct_term
#endif
static bool ttyecho(bool enable, int fd)
@@ -203,18 +199,16 @@ static bool ttyecho(bool enable, int fd)
noecho = withecho;
noecho.c_lflag &= ~ECHO;
tcsetattr(fd, TCSANOW, &noecho);
-#else /* HAVE_TERMIOS_H */
-#ifdef HAVE_TERMIO_H
+#elif defined(HAVE_TERMIO_H)
ioctl(fd, TCGETA, &withecho);
noecho = withecho;
noecho.c_lflag &= ~ECHO;
ioctl(fd, TCSETA, &noecho);
-#else /* HAVE_TERMIO_H */
-/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
- (void)fd; /* prevent compiler warning on unused variable */
+#else
+ /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
+ (void)fd;
return FALSE; /* not disabled */
#endif
-#endif
return TRUE; /* disabled */
}
else {
@@ -222,14 +216,11 @@ static bool ttyecho(bool enable, int fd)
now use to reset the terminal status) */
#ifdef HAVE_TERMIOS_H
tcsetattr(fd, TCSAFLUSH, &withecho);
-#else /* HAVE_TERMIOS_H */
-#ifdef HAVE_TERMIO_H
+#elif defined(HAVE_TERMIO_H)
ioctl(fd, TCSETA, &withecho);
#else
-/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H */
return FALSE; /* not enabled */
#endif
-#endif
return TRUE; /* enabled */
}
}
@@ -240,18 +231,18 @@ char *getpass_r(const char *prompt, /* prompt to display */
{
ssize_t nread;
bool disabled;
- int fd=open("/dev/tty", O_RDONLY);
+ int fd = open("/dev/tty", O_RDONLY);
if(-1 == fd)
fd = 1; /* use stdin if the tty couldn't be used */
disabled = ttyecho(FALSE, fd); /* disable terminal echo */
fputs(prompt, stderr);
- nread=read(fd, password, buflen);
+ nread = read(fd, password, buflen);
if(nread > 0)
- password[--nread]=0; /* zero terminate where enter is stored */
+ password[--nread] = '\0'; /* zero terminate where enter is stored */
else
- password[0]=0; /* got nothing */
+ password[0] = '\0'; /* got nothing */
if(disabled) {
/* if echo actually was disabled, add a newline */
diff --git a/src/getpass.h b/src/tool_getpass.h
index 3b29d47a1..506d0feef 100644
--- a/src/getpass.h
+++ b/src/tool_getpass.h
@@ -1,5 +1,5 @@
-#ifndef __GETPASS_H
-#define __GETPASS_H
+#ifndef HEADER_CURL_TOOL_GETPASS_H
+#define HEADER_CURL_TOOL_GETPASS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,6 +21,8 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
+
#ifndef HAVE_GETPASS_R
/* If there's a system-provided function named like this, we trust it is
also found in one of the standard headers. */
@@ -28,7 +30,7 @@
/*
* Returning NULL will abort the continued operation!
*/
-char* getpass_r(const char *prompt, char* buffer, size_t buflen );
+char* getpass_r(const char *prompt, char* buffer, size_t buflen);
#endif
-#endif
+#endif /* HEADER_CURL_TOOL_GETPASS_H */
diff --git a/src/tool_help.c b/src/tool_help.c
new file mode 100644
index 000000000..7c7d8d315
--- /dev/null
+++ b/src/tool_help.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include "tool_panykey.h"
+#include "tool_help.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef MSDOS
+# define USE_WATT32
+#endif
+
+/*
+ * A few of these source lines are >80 columns wide, but that's only because
+ * breaking the strings narrower makes this chunk look even worse!
+ *
+ * Starting with 7.18.0, this list of command line options is sorted based
+ * on the long option name. It is not done automatically, although a command
+ * line like the following can help out:
+ *
+ * curl --help | cut -c5- | grep "^-" | sort
+ */
+
+static const char *const helptext[] = {
+ "Usage: curl [options...] <url>",
+ "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
+ " --anyauth Pick \"any\" authentication method (H)",
+ " -a, --append Append to target file when uploading (F/SFTP)",
+ " --basic Use HTTP Basic Authentication (H)",
+ " --cacert FILE CA certificate to verify peer against (SSL)",
+ " --capath DIR CA directory to verify peer against (SSL)",
+ " -E, --cert CERT[:PASSWD] Client certificate file and password (SSL)",
+ " --cert-type TYPE Certificate file type (DER/PEM/ENG) (SSL)",
+ " --ciphers LIST SSL ciphers to use (SSL)",
+ " --compressed Request compressed response (using deflate or gzip)",
+ " -K, --config FILE Specify which config file to read",
+ " --connect-timeout SECONDS Maximum time allowed for connection",
+ " -C, --continue-at OFFSET Resumed transfer offset",
+ " -b, --cookie STRING/FILE String or file to read cookies from (H)",
+ " -c, --cookie-jar FILE Write cookies to this file after operation (H)",
+ " --create-dirs Create necessary local directory hierarchy",
+ " --crlf Convert LF to CRLF in upload",
+ " --crlfile FILE Get a CRL list in PEM format from the given file",
+ " -d, --data DATA HTTP POST data (H)",
+ " --data-ascii DATA HTTP POST ASCII data (H)",
+ " --data-binary DATA HTTP POST binary data (H)",
+ " --data-urlencode DATA HTTP POST data url encoded (H)",
+ " --delegation STRING GSS-API delegation permission",
+ " --digest Use HTTP Digest Authentication (H)",
+ " --disable-eprt Inhibit using EPRT or LPRT (F)",
+ " --disable-epsv Inhibit using EPSV (F)",
+ " -D, --dump-header FILE Write the headers to this file",
+ " --egd-file FILE EGD socket path for random data (SSL)",
+ " --engine ENGINGE Crypto engine (SSL). \"--engine list\" for list",
+#ifdef USE_ENVIRONMENT
+ " --environment Write results to environment variables (RISC OS)",
+#endif
+ " -f, --fail Fail silently (no output at all) on HTTP errors (H)",
+ " -F, --form CONTENT Specify HTTP multipart POST data (H)",
+ " --form-string STRING Specify HTTP multipart POST data (H)",
+ " --ftp-account DATA Account data string (F)",
+ " --ftp-alternative-to-user COMMAND "
+ "String to replace \"USER [name]\" (F)",
+ " --ftp-create-dirs Create the remote dirs if not present (F)",
+ " --ftp-method [MULTICWD/NOCWD/SINGLECWD] Control CWD usage (F)",
+ " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
+ " -P, --ftp-port ADR Use PORT with given address instead of PASV (F)",
+ " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
+ " --ftp-pret Send PRET before PASV (for drftpd) (F)",
+ " --ftp-ssl-ccc Send CCC after authenticating (F)",
+ " --ftp-ssl-ccc-mode ACTIVE/PASSIVE Set CCC mode (F)",
+ " --ftp-ssl-control Require SSL/TLS for ftp login, "
+ "clear for transfer (F)",
+ " -G, --get Send the -d data with a HTTP GET (H)",
+ " -g, --globoff Disable URL sequences and ranges using {} and []",
+ " -H, --header LINE Custom header to pass to server (H)",
+ " -I, --head Show document info only",
+ " -h, --help This help text",
+ " --hostpubmd5 MD5 "
+ "Hex encoded MD5 string of the host public key. (SSH)",
+ " -0, --http1.0 Use HTTP 1.0 (H)",
+ " --ignore-content-length Ignore the HTTP Content-Length header",
+ " -i, --include Include protocol headers in the output (H/F)",
+ " -k, --insecure Allow connections to SSL sites without certs (H)",
+ " --interface INTERFACE Specify network interface/address to use",
+ " -4, --ipv4 Resolve name to IPv4 address",
+ " -6, --ipv6 Resolve name to IPv6 address",
+ " -j, --junk-session-cookies Ignore session cookies read from file (H)",
+ " --keepalive-time SECONDS Interval between keepalive probes",
+ " --key KEY Private key file name (SSL/SSH)",
+ " --key-type TYPE Private key file type (DER/PEM/ENG) (SSL)",
+ " --krb LEVEL Enable Kerberos with specified security level (F)",
+ " --libcurl FILE Dump libcurl equivalent code of this command line",
+ " --limit-rate RATE Limit transfer speed to this rate",
+ " -l, --list-only List only names of an FTP directory (F)",
+ " --local-port RANGE Force use of these local port numbers",
+ " -L, --location Follow redirects (H)",
+ " --location-trusted like --location and send auth to other hosts (H)",
+ " -M, --manual Display the full manual",
+ " --mail-from FROM Mail from this address",
+ " --mail-rcpt TO Mail to this receiver(s)",
+ " --max-filesize BYTES Maximum file size to download (H/F)",
+ " --max-redirs NUM Maximum number of redirects allowed (H)",
+ " -m, --max-time SECONDS Maximum time allowed for the transfer",
+ " --negotiate Use HTTP Negotiate Authentication (H)",
+ " -n, --netrc Must read .netrc for user name and password",
+ " --netrc-optional Use either .netrc or URL; overrides -n",
+ " --netrc-file FILE Set up the netrc filename to use",
+ " -N, --no-buffer Disable buffering of the output stream",
+ " --no-keepalive Disable keepalive use on the connection",
+ " --no-sessionid Disable SSL session-ID reusing (SSL)",
+ " --noproxy List of hosts which do not use proxy",
+ " --ntlm Use HTTP NTLM authentication (H)",
+ " -o, --output FILE Write output to <file> instead of stdout",
+ " --pass PASS Pass phrase for the private key (SSL/SSH)",
+ " --post301 "
+ "Do not switch to GET after following a 301 redirect (H)",
+ " --post302 "
+ "Do not switch to GET after following a 302 redirect (H)",
+ " -#, --progress-bar Display transfer progress as a progress bar",
+ " --proto PROTOCOLS Enable/disable specified protocols",
+ " --proto-redir PROTOCOLS "
+ "Enable/disable specified protocols on redirect",
+ " -x, --proxy [PROTOCOL://]HOST[:PORT] Use proxy on given port",
+ " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
+ " --proxy-basic Use Basic authentication on the proxy (H)",
+ " --proxy-digest Use Digest authentication on the proxy (H)",
+ " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
+ " --proxy-ntlm Use NTLM authentication on the proxy (H)",
+ " -U, --proxy-user USER[:PASSWORD] Proxy user and password",
+ " --proxy1.0 HOST[:PORT] Use HTTP/1.0 proxy on given port",
+ " -p, --proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
+ " --pubkey KEY Public key file name (SSH)",
+ " -Q, --quote CMD Send command(s) to server before transfer (F/SFTP)",
+ " --random-file FILE File for reading random data from (SSL)",
+ " -r, --range RANGE Retrieve only the bytes within a range",
+ " --raw Do HTTP \"raw\", without any transfer decoding (H)",
+ " -e, --referer Referer URL (H)",
+ " -J, --remote-header-name Use the header-provided filename (H)",
+ " -O, --remote-name Write output to a file named as the remote file",
+ " --remote-name-all Use the remote file name for all URLs",
+ " -R, --remote-time Set the remote file's time on the local output",
+ " -X, --request COMMAND Specify request command to use",
+ " --resolve HOST:PORT:ADDRESS Force resolve of HOST:PORT to ADDRESS",
+ " --retry NUM "
+ "Retry request NUM times if transient problems occur",
+ " --retry-delay SECONDS "
+ "When retrying, wait this many seconds between each",
+ " --retry-max-time SECONDS Retry only within this period",
+ " -S, --show-error "
+ "Show error. With -s, make curl show errors when they occur",
+ " -s, --silent Silent mode. Don't output anything",
+ " --socks4 HOST[:PORT] SOCKS4 proxy on given host + port",
+ " --socks4a HOST[:PORT] SOCKS4a proxy on given host + port",
+ " --socks5 HOST[:PORT] SOCKS5 proxy on given host + port",
+ " --socks5-hostname HOST[:PORT] "
+ "SOCKS5 proxy, pass host name to proxy",
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ " --socks5-gssapi-service NAME SOCKS5 proxy service name for gssapi",
+ " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
+#endif
+ " -Y, --speed-limit RATE "
+ "Stop transfers below speed-limit for 'speed-time' secs",
+ " -y, --speed-time SECONDS "
+ "Time for trig speed-limit abort. Defaults to 30",
+ " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
+ " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
+ " -2, --sslv2 Use SSLv2 (SSL)",
+ " -3, --sslv3 Use SSLv3 (SSL)",
+ " --stderr FILE Where to redirect stderr. - means stdout",
+ " --tcp-nodelay Use the TCP_NODELAY option",
+ " -t, --telnet-option OPT=VAL Set telnet option",
+ " --tftp-blksize VALUE Set TFTP BLKSIZE option (must be >512)",
+ " -z, --time-cond TIME Transfer based on a time condition",
+ " -1, --tlsv1 Use TLSv1 (SSL)",
+ " --trace FILE Write a debug trace to the given file",
+ " --trace-ascii FILE Like --trace but without the hex output",
+ " --trace-time Add time stamps to trace/verbose output",
+ " --tr-encoding Request compressed transfer encoding (H)",
+ " -T, --upload-file FILE Transfer FILE to destination",
+ " --url URL URL to work with",
+ " -B, --use-ascii Use ASCII/text transfer",
+ " -u, --user USER[:PASSWORD] Server user and password",
+ " --tlsuser USER TLS username",
+ " --tlspassword STRING TLS password",
+ " --tlsauthtype STRING TLS authentication type (default SRP)",
+ " -A, --user-agent STRING User-Agent to send to server (H)",
+ " -v, --verbose Make the operation more talkative",
+ " -V, --version Show version number and quit",
+#ifdef USE_WATT32
+ " --wdebug Turn on Watt-32 debugging",
+#endif
+ " -w, --write-out FORMAT What to output after completion",
+ " --xattr Store metadata in extended file attributes",
+ " -q If used as the first parameter disables .curlrc",
+ NULL
+};
+
+#ifdef NETWARE
+# define PRINT_LINES_PAUSE 23
+#endif
+
+#ifdef __SYMBIAN32__
+# define PRINT_LINES_PAUSE 16
+#endif
+
+void tool_help(void)
+{
+ int i;
+ for(i = 0; helptext[i]; i++) {
+ puts(helptext[i]);
+#ifdef PRINT_LINES_PAUSE
+ if(i && ((i % PRINT_LINES_PAUSE) == 0))
+ tool_pressanykey();
+#endif
+ }
+}
+
diff --git a/src/writeenv.h b/src/tool_help.h
index 8d92f6c89..f9664113a 100644
--- a/src/writeenv.h
+++ b/src/tool_help.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_WRITEENV_H
-#define HEADER_CURL_WRITEENV_H
+#ifndef HEADER_CURL_TOOL_HELP_H
+#define HEADER_CURL_TOOL_HELP_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,7 +21,9 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
-void ourWriteEnv(CURL *curl);
+void tool_help(void);
+
+#endif /* HEADER_CURL_TOOL_HELP_H */
-#endif /* HEADER_CURL_WRITEENV_H */
diff --git a/src/tool_helpers.c b/src/tool_helpers.c
new file mode 100644
index 000000000..b6371785d
--- /dev/null
+++ b/src/tool_helpers.c
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** Helper functions that are used from more tha one source file.
+*/
+
+const char *param2text(int res)
+{
+ ParameterError error = (ParameterError)res;
+ switch(error) {
+ case PARAM_GOT_EXTRA_PARAMETER:
+ return "had unsupported trailing garbage";
+ case PARAM_OPTION_UNKNOWN:
+ return "is unknown";
+ case PARAM_OPTION_AMBIGUOUS:
+ return "is ambiguous";
+ case PARAM_REQUIRES_PARAMETER:
+ return "requires parameter";
+ case PARAM_BAD_USE:
+ return "is badly used here";
+ case PARAM_BAD_NUMERIC:
+ return "expected a proper numerical parameter";
+ case PARAM_LIBCURL_DOESNT_SUPPORT:
+ return "the installed libcurl version doesn't support this";
+ case PARAM_NO_MEM:
+ return "out of memory";
+ default:
+ return "unknown error";
+ }
+}
+
+int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store)
+{
+ if((*store == HTTPREQ_UNSPEC) ||
+ (*store == req)) {
+ *store = req;
+ return 0;
+ }
+ warnf(config, "You can only select one HTTP request!\n");
+ return 1;
+}
+
diff --git a/src/tool_helpers.h b/src/tool_helpers.h
new file mode 100644
index 000000000..4385bfce4
--- /dev/null
+++ b/src/tool_helpers.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_TOOL_HELPERS_H
+#define HEADER_CURL_TOOL_HELPERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+const char *param2text(int res);
+
+int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store);
+
+#endif /* HEADER_CURL_TOOL_HELPERS_H */
+
diff --git a/src/homedir.c b/src/tool_homedir.c
index 52f69c7ee..95d25c74f 100644
--- a/src/homedir.c
+++ b/src/tool_homedir.c
@@ -19,31 +19,23 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include "setup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#ifdef HAVE_PWD_H
-#include <pwd.h>
+# include <pwd.h>
#endif
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
#ifdef __VMS
-#include <unixlib.h>
+# include <unixlib.h>
#endif
-#include "homedir.h"
+#include "tool_homedir.h"
-#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
-#include "memdebug.h"
-#endif
+#include "memdebug.h" /* keep this as LAST include */
-static
-char *GetEnv(const char *variable, char do_expand)
+static char *GetEnv(const char *variable, char do_expand)
{
char *env = NULL;
#ifdef WIN32
@@ -77,7 +69,7 @@ char *GetEnv(const char *variable, char do_expand)
env = getenv(variable);
#endif
#endif
- return (env && env[0])?strdup(env):NULL;
+ return (env && env[0]) ? strdup(env) : NULL;
}
/* return the home directory of the current user as an allocated string */
diff --git a/src/homedir.h b/src/tool_homedir.h
index c88d51723..109c1f282 100644
--- a/src/homedir.h
+++ b/src/tool_homedir.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_HOMEDIR_H
-#define HEADER_CURL_HOMEDIR_H
+#ifndef HEADER_CURL_TOOL_HOMEDIR_H
+#define HEADER_CURL_TOOL_HOMEDIR_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,7 +21,8 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
char *homedir(void);
-#endif /* HEADER_CURL_HOMEDIR_H */
+#endif /* HEADER_CURL_TOOL_HOMEDIR_H */
diff --git a/src/tool_libinfo.c b/src/tool_libinfo.c
new file mode 100644
index 000000000..1469c8807
--- /dev/null
+++ b/src/tool_libinfo.c
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_libinfo.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* global variable definitions, for libcurl run-time info */
+
+curl_version_info_data *curlinfo = NULL;
+long built_in_protos = 0;
+
+/*
+ * libcurl_info_init: retrieves run-time information about libcurl,
+ * setting a global pointer 'curlinfo' to libcurl's run-time info
+ * struct, and a global bit pattern 'built_in_protos' composed of
+ * CURLPROTO_* bits indicating which protocols are actually built
+ * into library being used.
+ */
+
+CURLcode get_libcurl_info(void)
+{
+ static struct proto_name_pattern {
+ const char *proto_name;
+ long proto_pattern;
+ } const possibly_built_in[] = {
+ { "dict", CURLPROTO_DICT },
+ { "file", CURLPROTO_FILE },
+ { "ftp", CURLPROTO_FTP },
+ { "ftps", CURLPROTO_FTPS },
+ { "gopher", CURLPROTO_GOPHER },
+ { "http", CURLPROTO_HTTP },
+ { "https", CURLPROTO_HTTPS },
+ { "imap", CURLPROTO_IMAP },
+ { "imaps", CURLPROTO_IMAPS },
+ { "ldap", CURLPROTO_LDAP },
+ { "ldaps", CURLPROTO_LDAPS },
+ { "pop3", CURLPROTO_POP3 },
+ { "pop3s", CURLPROTO_POP3S },
+ { "rtmp", CURLPROTO_RTMP },
+ { "rtsp", CURLPROTO_RTSP },
+ { "scp", CURLPROTO_SCP },
+ { "sftp", CURLPROTO_SFTP },
+ { "smtp", CURLPROTO_SMTP },
+ { "smtps", CURLPROTO_SMTPS },
+ { "telnet", CURLPROTO_TELNET },
+ { "tftp", CURLPROTO_TFTP },
+ { NULL, 0 }
+ };
+
+ struct proto_name_pattern const *p;
+ const char *const *proto;
+
+ /* Pointer to libcurl's run-time version information */
+ curlinfo = curl_version_info(CURLVERSION_NOW);
+ if(!curlinfo)
+ return CURLE_FAILED_INIT;
+
+ /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */
+ built_in_protos = 0;
+ if(curlinfo->protocols) {
+ for(proto = curlinfo->protocols; *proto; proto++) {
+ for(p = possibly_built_in; p->proto_name; p++) {
+ if(curlx_raw_equal(*proto, p->proto_name)) {
+ built_in_protos |= p->proto_pattern;
+ break;
+ }
+ }
+ }
+ }
+
+ return CURLE_OK;
+}
+
diff --git a/src/tool_libinfo.h b/src/tool_libinfo.h
new file mode 100644
index 000000000..dfdf78a61
--- /dev/null
+++ b/src/tool_libinfo.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_TOOL_LIBINFO_H
+#define HEADER_CURL_TOOL_LIBINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/* global variable declarations, for libcurl run-time info */
+
+extern curl_version_info_data *curlinfo;
+extern long built_in_protos;
+
+CURLcode get_libcurl_info(void);
+
+#endif /* HEADER_CURL_TOOL_LIBINFO_H */
+
diff --git a/src/tool_main.c b/src/tool_main.c
new file mode 100644
index 000000000..86780c7f1
--- /dev/null
+++ b/src/tool_main.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_convert.h"
+#include "tool_operate.h"
+#include "tool_panykey.h"
+#include "tool_vms.h"
+#include "tool_main.h"
+
+/*
+ * This is low-level hard-hacking memory leak tracking and similar. Using
+ * the library level code from this client-side is ugly, but we do this
+ * anyway for convenience.
+ */
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef __VMS
+static int vms_show = 0;
+#endif
+
+/*
+ * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
+ * open before starting to run. Otherwise, the first three network
+ * sockets opened by curl could be used for input sources, downloaded data
+ * or error logs as they will effectively be stdin, stdout and/or stderr.
+ */
+static void main_checkfds(void)
+{
+#ifdef HAVE_PIPE
+ int fd[2] = { STDIN_FILENO, STDIN_FILENO };
+ while(fd[0] == STDIN_FILENO ||
+ fd[0] == STDOUT_FILENO ||
+ fd[0] == STDERR_FILENO ||
+ fd[1] == STDIN_FILENO ||
+ fd[1] == STDOUT_FILENO ||
+ fd[1] == STDERR_FILENO)
+ if(pipe(fd) < 0)
+ return; /* Out of handles. This isn't really a big problem now, but
+ will be when we try to create a socket later. */
+ close(fd[0]);
+ close(fd[1]);
+#endif
+}
+
+/*
+** curl tool main function.
+*/
+int main(int argc, char *argv[])
+{
+ int res;
+ struct Configurable config;
+
+ memset(&config, 0, sizeof(struct Configurable));
+
+ config.errors = stderr; /* default errors to stderr */
+
+ main_checkfds();
+
+ res = operate(&config, argc, argv);
+
+#ifdef __SYMBIAN32__
+ if(config.showerror)
+ tool_pressanykey();
+#endif
+
+ free_config_fields(&config);
+
+#ifdef __NOVELL_LIBC__
+ if(getenv("_IN_NETWARE_BASH_") == NULL)
+ tool_pressanykey();
+#endif
+
+#ifdef __VMS
+ vms_special_exit(res, vms_show);
+#else
+ return res;
+#endif
+}
+
diff --git a/src/tool_main.h b/src/tool_main.h
new file mode 100644
index 000000000..2193cb96e
--- /dev/null
+++ b/src/tool_main.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_TOOL_MAIN_H
+#define HEADER_CURL_TOOL_MAIN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#define DEFAULT_MAXREDIRS 50L
+
+#define RETRY_SLEEP_DEFAULT 1000L /* ms */
+#define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO fileno(stdin)
+#endif
+
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO fileno(stdout)
+#endif
+
+#ifndef STDERR_FILENO
+# define STDERR_FILENO fileno(stderr)
+#endif
+
+#endif /* HEADER_CURL_TOOL_MAIN_H */
+
diff --git a/src/tool_mfiles.c b/src/tool_mfiles.c
new file mode 100644
index 000000000..17edbfaab
--- /dev/null
+++ b/src/tool_mfiles.c
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "tool_mfiles.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static void AppendNode(struct multi_files **first,
+ struct multi_files **last,
+ struct multi_files *new)
+{
+ DEBUGASSERT(((*first) && (*last)) || ((!*first) && (!*last)));
+
+ if(*last)
+ (*last)->next = new;
+ else
+ *first = new;
+ *last = new;
+}
+
+/*
+ * AddMultiFiles: Add a new list node possibly followed with a type_name.
+ *
+ * multi_first argument is the address of a pointer to the first element
+ * of the multi_files linked list. A NULL pointer indicates empty list.
+ *
+ * multi_last argument is the address of a pointer to the last element
+ * of the multi_files linked list. A NULL pointer indicates empty list.
+ *
+ * Pointers stored in multi_first and multi_last are modified while
+ * function is executed. An out of memory condition free's the whole
+ * list and returns with pointers stored in multi_first and multi_last
+ * set to NULL and a NULL function result.
+ *
+ * Function returns same pointer as stored at multi_last.
+ */
+
+struct multi_files *AddMultiFiles(const char *file_name,
+ const char *type_name,
+ const char *show_filename,
+ struct multi_files **multi_first,
+ struct multi_files **multi_last)
+{
+ struct multi_files *multi;
+ struct multi_files *multi_type;
+ struct multi_files *multi_name;
+
+ multi = calloc(1, sizeof(struct multi_files));
+ if(multi) {
+ multi->form.option = CURLFORM_FILE;
+ multi->form.value = file_name;
+ AppendNode(multi_first, multi_last, multi);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+
+ if(type_name) {
+ multi_type = calloc(1, sizeof(struct multi_files));
+ if(multi_type) {
+ multi_type->form.option = CURLFORM_CONTENTTYPE;
+ multi_type->form.value = type_name;
+ AppendNode(multi_first, multi_last, multi_type);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+ }
+
+ if(show_filename) {
+ multi_name = calloc(1, sizeof(struct multi_files));
+ if(multi_name) {
+ multi_name->form.option = CURLFORM_FILENAME;
+ multi_name->form.value = show_filename;
+ AppendNode(multi_first, multi_last, multi_name);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+ }
+
+ return *multi_last;
+}
+
+/*
+ * FreeMultiInfo: Free the items of the list.
+ */
+
+void FreeMultiInfo(struct multi_files **multi_first,
+ struct multi_files **multi_last)
+{
+ struct multi_files *next;
+ struct multi_files *item = *multi_first;
+
+ while(item) {
+ next = item->next;
+ Curl_safefree(item);
+ item = next;
+ }
+ *multi_first = NULL;
+ if(multi_last)
+ *multi_last = NULL;
+}
+
diff --git a/src/tool_mfiles.h b/src/tool_mfiles.h
new file mode 100644
index 000000000..8a3b53935
--- /dev/null
+++ b/src/tool_mfiles.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_TOOL_MFILES_H
+#define HEADER_CURL_TOOL_MFILES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+ * Structure for storing the information needed to build
+ * a multiple files section.
+ */
+
+struct multi_files {
+ struct curl_forms form;
+ struct multi_files *next;
+};
+
+struct multi_files *AddMultiFiles(const char *file_name,
+ const char *type_name,
+ const char *show_filename,
+ struct multi_files **multi_first,
+ struct multi_files **multi_last);
+
+void FreeMultiInfo(struct multi_files **multi_first,
+ struct multi_files **multi_last);
+
+#endif /* HEADER_CURL_TOOL_MFILES_H */
+
diff --git a/src/tool_msgs.c b/src/tool_msgs.c
new file mode 100644
index 000000000..b6a80a2dd
--- /dev/null
+++ b/src/tool_msgs.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define WARN_PREFIX "Warning: "
+#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
+
+/*
+ * Emit warning formatted message on configured 'errors' stream unless
+ * mute (--silent) was selected.
+ */
+
+void warnf(struct Configurable *config, const char *fmt, ...)
+{
+ if(!config->mute) {
+ va_list ap;
+ int len;
+ char *ptr;
+ char print_buffer[256];
+
+ va_start(ap, fmt);
+ len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ va_end(ap);
+
+ ptr = print_buffer;
+ while(len > 0) {
+ fputs(WARN_PREFIX, config->errors);
+
+ if(len > (int)WARN_TEXTWIDTH) {
+ int cut = WARN_TEXTWIDTH-1;
+
+ while(!ISSPACE(ptr[cut]) && cut) {
+ cut--;
+ }
+ if(0 == cut)
+ /* not a single cutting position was found, just cut it at the
+ max text width then! */
+ cut = WARN_TEXTWIDTH-1;
+
+ (void)fwrite(ptr, cut + 1, 1, config->errors);
+ fputs("\n", config->errors);
+ ptr += cut+1; /* skip the space too */
+ len -= cut;
+ }
+ else {
+ fputs(ptr, config->errors);
+ len = 0;
+ }
+ }
+ }
+}
+
+/*
+ * Emit help formatted message on given stream.
+ */
+
+void helpf(FILE *errors, const char *fmt, ...)
+{
+ va_list ap;
+ if(fmt) {
+ va_start(ap, fmt);
+ fputs("curl: ", errors); /* prefix it */
+ vfprintf(errors, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(errors, "curl: try 'curl --help' "
+#ifdef USE_MANUAL
+ "or 'curl --manual' "
+#endif
+ "for more information\n");
+}
+
diff --git a/src/tool_msgs.h b/src/tool_msgs.h
new file mode 100644
index 000000000..9102139bd
--- /dev/null
+++ b/src/tool_msgs.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_TOOL_MSGS_H
+#define HEADER_CURL_TOOL_MSGS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+void warnf(struct Configurable *config, const char *fmt, ...);
+
+void helpf(FILE *errors, const char *fmt, ...);
+
+#endif /* HEADER_CURL_TOOL_MSGS_H */
+
diff --git a/src/tool_operate.c b/src/tool_operate.c
new file mode 100644
index 000000000..7ab815f83
--- /dev/null
+++ b/src/tool_operate.c
@@ -0,0 +1,1559 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#elif defined(HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_binmode.h"
+#include "tool_cfgable.h"
+#include "tool_cb_dbg.h"
+#include "tool_cb_hdr.h"
+#include "tool_cb_prg.h"
+#include "tool_cb_rea.h"
+#include "tool_cb_see.h"
+#include "tool_cb_skt.h"
+#include "tool_cb_wrt.h"
+#include "tool_dirhie.h"
+#include "tool_doswin.h"
+#include "tool_easysrc.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+#include "tool_homedir.h"
+#include "tool_libinfo.h"
+#include "tool_main.h"
+#include "tool_msgs.h"
+#include "tool_operate.h"
+#include "tool_operhlp.h"
+#include "tool_parsecfg.h"
+#include "tool_setopt.h"
+#include "tool_sleep.h"
+#include "tool_urlglob.h"
+#include "tool_util.h"
+#include "tool_writeenv.h"
+#include "tool_writeout.h"
+#include "tool_xattr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define CURLseparator "--_curl_--"
+
+#ifndef O_BINARY
+/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
+ source code but yet it doesn't ruin anything */
+# define O_BINARY 0
+#endif
+
+#define CURL_CA_CERT_ERRORMSG1 \
+ "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
+ "curl performs SSL certificate verification by default, " \
+ "using a \"bundle\"\n" \
+ " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
+ " bundle file isn't adequate, you can specify an alternate file\n" \
+ " using the --cacert option.\n"
+
+#define CURL_CA_CERT_ERRORMSG2 \
+ "If this HTTPS server uses a certificate signed by a CA represented in\n" \
+ " the bundle, the certificate verification probably failed due to a\n" \
+ " problem with the certificate (it might be expired, or the name might\n" \
+ " not match the domain name in the URL).\n" \
+ "If you'd like to turn off curl's verification of the certificate, use\n" \
+ " the -k (or --insecure) option.\n"
+
+int operate(struct Configurable *config, int argc, argv_item_t argv[])
+{
+ char errorbuffer[CURL_ERROR_SIZE];
+ struct ProgressData progressbar;
+ struct getout *urlnode;
+
+ struct OutStruct heads;
+
+ CURL *curl = NULL;
+ char *httpgetfields = NULL;
+
+ bool stillflags;
+ int res = 0;
+ int i;
+
+ errorbuffer[0] = '\0';
+ /* default headers output stream is stdout */
+ memset(&heads, 0, sizeof(struct OutStruct));
+ heads.stream = stdout;
+ heads.config = config;
+
+ memory_tracking_init();
+
+ /*
+ ** Initialize curl library - do not call any libcurl functions before
+ ** this point. Note that the memory_tracking_init() magic above is an
+ ** exception, but then that's not part of the official public API.
+ */
+ if(main_init() != CURLE_OK) {
+ helpf(config->errors, "error initializing curl library\n");
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Get libcurl info right away */
+ if(get_libcurl_info() != CURLE_OK) {
+ helpf(config->errors, "error retrieving curl library information\n");
+ main_free();
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Get a curl handle to use for all forthcoming curl transfers */
+ curl = curl_easy_init();
+ if(!curl) {
+ helpf(config->errors, "error initializing curl easy handle\n");
+ main_free();
+ return CURLE_FAILED_INIT;
+ }
+ config->easy = curl;
+
+ /*
+ ** Beyond this point no return'ing from this function allowed.
+ ** Jump to label 'quit_curl' in order to abandon this function
+ ** from outside of nested loops further down below.
+ */
+
+ /* setup proper locale from environment */
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+
+ /* inits */
+ config->postfieldsize = -1;
+ config->showerror = -1; /* will show errors */
+ config->use_httpget = FALSE;
+ config->create_dirs = FALSE;
+ config->maxredirs = DEFAULT_MAXREDIRS;
+ config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
+ config->proto_present = FALSE;
+ config->proto_redir =
+ CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
+ config->proto_redir_present = FALSE;
+
+ if((argc > 1) &&
+ (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
+ strchr(argv[1], 'q')) {
+ /*
+ * The first flag, that is not a verbose name, but a shortname
+ * and it includes the 'q' flag!
+ */
+ ;
+ }
+ else {
+ parseconfig(NULL, config); /* ignore possible failure */
+ }
+
+ if((argc < 2) && !config->url_list) {
+ helpf(config->errors, NULL);
+ res = CURLE_FAILED_INIT;
+ goto quit_curl;
+ }
+
+ /* Parse options */
+ for(i = 1, stillflags = TRUE; i < argc; i++) {
+ if(stillflags &&
+ ('-' == argv[i][0])) {
+ char *nextarg;
+ bool passarg;
+ char *origopt = argv[i];
+
+ char *flag = argv[i];
+
+ if(curlx_strequal("--", argv[i]))
+ /* this indicates the end of the flags and thus enables the
+ following (URL) argument to start with -. */
+ stillflags = FALSE;
+ else {
+ nextarg = (i < (argc-1)) ? argv[i+1] : NULL;
+
+ res = getparameter(flag, nextarg, &passarg, config);
+ if(res) {
+ int retval = CURLE_OK;
+ if(res != PARAM_HELP_REQUESTED) {
+ const char *reason = param2text(res);
+ helpf(config->errors, "option %s: %s\n", origopt, reason);
+ retval = CURLE_FAILED_INIT;
+ }
+ res = retval;
+ goto quit_curl;
+ }
+
+ if(passarg) /* we're supposed to skip this */
+ i++;
+ }
+ }
+ else {
+ bool used;
+ /* just add the URL please */
+ res = getparameter((char *)"--url", argv[i], &used, config);
+ if(res)
+ goto quit_curl;
+ }
+ }
+
+ if((!config->url_list || !config->url_list->url) && !config->list_engines) {
+ helpf(config->errors, "no URL specified!\n");
+ res = CURLE_FAILED_INIT;
+ goto quit_curl;
+ }
+
+ if(!config->useragent)
+ config->useragent = my_useragent();
+ if(!config->useragent) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+
+ /* On WIN32 we can't set the path to curl-ca-bundle.crt
+ * at compile time. So we look here for the file in two ways:
+ * 1: look at the environment variable CURL_CA_BUNDLE for a path
+ * 2: if #1 isn't found, use the windows API function SearchPath()
+ * to find it along the app's path (includes app's dir and CWD)
+ *
+ * We support the environment variable thing for non-Windows platforms
+ * too. Just for the sake of it.
+ */
+ if(!config->cacert &&
+ !config->capath &&
+ !config->insecure_ok) {
+ char *env;
+ env = curlx_getenv("CURL_CA_BUNDLE");
+ if(env) {
+ config->cacert = strdup(env);
+ if(!config->cacert) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ else {
+ env = curlx_getenv("SSL_CERT_DIR");
+ if(env) {
+ config->capath = strdup(env);
+ if(!config->capath) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ else {
+ env = curlx_getenv("SSL_CERT_FILE");
+ if(env) {
+ config->cacert = strdup(env);
+ if(!config->cacert) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ }
+ }
+
+ if(env)
+ curl_free(env);
+#ifdef WIN32
+ else {
+ res = FindWin32CACert(config, "curl-ca-bundle.crt");
+ if(res)
+ goto quit_curl;
+ }
+#endif
+ }
+
+ if(config->postfields) {
+ if(config->use_httpget) {
+ /* Use the postfields data for a http get */
+ httpgetfields = strdup(config->postfields);
+ Curl_safefree(config->postfields);
+ if(!httpgetfields) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ if(SetHTTPrequest(config,
+ (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
+ &config->httpreq)) {
+ res = PARAM_BAD_USE;
+ goto quit_curl;
+ }
+ }
+ else {
+ if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
+ res = PARAM_BAD_USE;
+ goto quit_curl;
+ }
+ }
+ }
+
+ /* This is the first entry added to easysrc and it initializes the slist */
+ easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();");
+ if(!easysrc) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+
+ if(config->list_engines) {
+ struct curl_slist *engines = NULL;
+ curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
+ list_engines(engines);
+ curl_slist_free_all(engines);
+ res = CURLE_OK;
+ goto quit_curl;
+ }
+
+ /* Single header file for all URLs */
+ if(config->headerfile) {
+ /* open file for output: */
+ if(!curlx_strequal(config->headerfile, "-")) {
+ FILE *newfile = fopen(config->headerfile, "wb");
+ if(!newfile) {
+ warnf(config, "Failed to open %s\n", config->headerfile);
+ res = CURLE_WRITE_ERROR;
+ goto quit_curl;
+ }
+ else {
+ heads.filename = config->headerfile;
+ heads.s_isreg = TRUE;
+ heads.fopened = TRUE;
+ heads.stream = newfile;
+ }
+ }
+ }
+
+ /*
+ ** Nested loops start here.
+ */
+
+ /* loop through the list of given URLs */
+
+ for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
+
+ int up; /* upload file counter within a single upload glob */
+ char *infiles; /* might be a glob pattern */
+ char *outfiles;
+ int infilenum;
+ URLGlob *inglob;
+
+ outfiles = NULL;
+ infilenum = 0;
+ inglob = NULL;
+
+ /* urlnode->url is the full URL (it might be NULL) */
+
+ if(!urlnode->url) {
+ /* This node has no URL. Free node data without destroying the
+ node itself nor modifying next pointer and continue to next */
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ urlnode->flags = 0;
+ continue; /* next URL please */
+ }
+
+ /* save outfile pattern before expansion */
+ if(urlnode->outfile) {
+ outfiles = strdup(urlnode->outfile);
+ if(!outfiles) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ }
+
+ infiles = urlnode->infile;
+
+ if(!config->globoff && infiles) {
+ /* Unless explicitly shut off */
+ res = glob_url(&inglob, infiles, &infilenum,
+ config->showerror?config->errors:NULL);
+ if(res) {
+ Curl_safefree(outfiles);
+ break;
+ }
+ }
+
+ /* Here's the loop for uploading multiple files within the same
+ single globbed string. If no upload, we enter the loop once anyway. */
+ for(up = 0 ;; up++) {
+
+ char *uploadfile; /* a single file, never a glob */
+ int separator;
+ URLGlob *urls;
+ int urlnum;
+
+ uploadfile = NULL;
+ separator = 0;
+ urls = NULL;
+ urlnum = 0;
+
+ if(!up && !infiles)
+ Curl_nop_stmt;
+ else {
+ if(inglob) {
+ res = glob_next_url(&uploadfile, inglob);
+ if(res == CURLE_OUT_OF_MEMORY)
+ helpf(config->errors, "out of memory\n");
+ }
+ else if(!up) {
+ uploadfile = strdup(infiles);
+ if(!uploadfile) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ uploadfile = NULL;
+ if(!uploadfile)
+ break;
+ }
+
+ if(!config->globoff) {
+ /* Unless explicitly shut off, we expand '{...}' and '[...]'
+ expressions and return total number of URLs in pattern set */
+ res = glob_url(&urls, urlnode->url, &urlnum,
+ config->showerror?config->errors:NULL);
+ if(res) {
+ Curl_safefree(uploadfile);
+ break;
+ }
+ }
+ else
+ urlnum = 1; /* without globbing, this is a single URL */
+
+ /* if multiple files extracted to stdout, insert separators! */
+ separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
+
+ /* Here's looping around each globbed URL */
+ for(i = 0 ;; i++) {
+
+ int infd;
+ bool infdopen;
+ char *outfile;
+ struct OutStruct outs;
+ struct InStruct input;
+ struct timeval retrystart;
+ curl_off_t uploadfilesize;
+ long retry_numretries;
+ long retry_sleep_default;
+ long retry_sleep;
+ char *this_url;
+
+ outfile = NULL;
+ infdopen = FALSE;
+ infd = STDIN_FILENO;
+ uploadfilesize = -1; /* -1 means unknown */
+
+ /* default output stream is stdout */
+ memset(&outs, 0, sizeof(struct OutStruct));
+ outs.stream = stdout;
+ outs.config = config;
+
+ if(urls) {
+ res = glob_next_url(&this_url, urls);
+ if(res)
+ goto show_error;
+ }
+ else if(!i) {
+ this_url = strdup(urlnode->url);
+ if(!this_url) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+ else
+ this_url = NULL;
+ if(!this_url)
+ break;
+
+ if(outfiles) {
+ outfile = strdup(outfiles);
+ if(!outfile) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+
+ if((urlnode->flags&GETOUT_USEREMOTE) ||
+ (outfile && !curlx_strequal("-", outfile)) ) {
+
+ /*
+ * We have specified a file name to store the result in, or we have
+ * decided we want to use the remote file name.
+ */
+
+ if(!outfile) {
+ /* extract the file name from the URL */
+ res = get_url_file_name(&outfile, this_url);
+ if(res)
+ goto show_error;
+ if((!outfile || !*outfile) && !config->content_disposition) {
+ helpf(config->errors, "Remote file name has no length!\n");
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+#if defined(MSDOS) || defined(WIN32)
+ /* For DOS and WIN32, we do some major replacing of
+ bad characters in the file name before using it */
+ outfile = sanitize_dos_name(outfile);
+ if(!outfile) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+#endif /* MSDOS || WIN32 */
+ }
+ else if(urls) {
+ /* fill '#1' ... '#9' terms from URL pattern */
+ char *storefile = outfile;
+ res = glob_match_url(&outfile, storefile, urls);
+ Curl_safefree(storefile);
+ if(res) {
+ /* bad globbing */
+ warnf(config, "bad output glob!\n");
+ goto quit_urls;
+ }
+ }
+
+ /* Create the directory hierarchy, if not pre-existent to a multiple
+ file output call */
+
+ if(config->create_dirs) {
+ res = create_dir_hierarchy(outfile, config->errors);
+ /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
+ if(res == CURLE_WRITE_ERROR)
+ goto quit_urls;
+ if(res) {
+ goto show_error;
+ }
+ }
+
+ if((urlnode->flags & GETOUT_USEREMOTE)
+ && config->content_disposition) {
+ /* Our header callback sets the filename */
+ DEBUGASSERT(!outs.filename);
+ }
+ else {
+ if(config->resume_from_current) {
+ /* We're told to continue from where we are now. Get the size
+ of the file as it is now and open it for append instead */
+ struct_stat fileinfo;
+ /* VMS -- Danger, the filesize is only valid for stream files */
+ if(0 == stat(outfile, &fileinfo))
+ /* set offset to current file size: */
+ config->resume_from = fileinfo.st_size;
+ else
+ /* let offset be 0 */
+ config->resume_from = 0;
+ }
+
+ if(config->resume_from) {
+ /* open file for output: */
+ FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
+ if(!file) {
+ helpf(config->errors, "Can't open '%s'!\n", outfile);
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+ outs.fopened = TRUE;
+ outs.stream = file;
+ outs.init = config->resume_from;
+ }
+ else {
+ outs.stream = NULL; /* open when needed */
+ }
+ outs.filename = outfile;
+ outs.s_isreg = TRUE;
+ }
+ }
+
+ if(uploadfile && !stdin_upload(uploadfile)) {
+ /*
+ * We have specified a file to upload and it isn't "-".
+ */
+ struct_stat fileinfo;
+
+ this_url = add_file_name_to_url(curl, this_url, uploadfile);
+ if(!this_url) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ /* VMS Note:
+ *
+ * Reading binary from files can be a problem... Only FIXED, VAR
+ * etc WITHOUT implied CC will work Others need a \n appended to a
+ * line
+ *
+ * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
+ * fixed file with implied CC needs to have a byte added for every
+ * record processed, this can by derived from Filesize & recordsize
+ * for VARiable record files the records need to be counted! for
+ * every record add 1 for linefeed and subtract 2 for the record
+ * header for VARIABLE header files only the bare record data needs
+ * to be considered with one appended if implied CC
+ */
+
+ infd = open(uploadfile, O_RDONLY | O_BINARY);
+ if((infd == -1) || fstat(infd, &fileinfo)) {
+ helpf(config->errors, "Can't open '%s'!\n", uploadfile);
+ if(infd != -1) {
+ close(infd);
+ infd = STDIN_FILENO;
+ }
+ res = CURLE_READ_ERROR;
+ goto quit_urls;
+ }
+ infdopen = TRUE;
+
+ /* we ignore file size for char/block devices, sockets, etc. */
+ if(S_ISREG(fileinfo.st_mode))
+ uploadfilesize = fileinfo.st_size;
+
+ }
+ else if(uploadfile && stdin_upload(uploadfile)) {
+ /* count to see if there are more than one auth bit set
+ in the authtype field */
+ int authbits = 0;
+ int bitcheck = 0;
+ while(bitcheck < 32) {
+ if(config->authtype & (1 << bitcheck++)) {
+ authbits++;
+ if(authbits > 1) {
+ /* more than one, we're done! */
+ break;
+ }
+ }
+ }
+
+ /*
+ * If the user has also selected --anyauth or --proxy-anyauth
+ * we should warn him/her.
+ */
+ if(config->proxyanyauth || (authbits>1)) {
+ warnf(config,
+ "Using --anyauth or --proxy-anyauth with upload from stdin"
+ " involves a big risk of it not working. Use a temporary"
+ " file or a fixed auth type instead!\n");
+ }
+
+ DEBUGASSERT(infdopen == FALSE);
+ DEBUGASSERT(infd == STDIN_FILENO);
+
+ set_binmode(stdin);
+ if(curlx_strequal(uploadfile, ".")) {
+ if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
+ warnf(config,
+ "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
+ }
+ }
+
+ if(uploadfile && config->resume_from_current)
+ config->resume_from = -1; /* -1 will then force get-it-yourself */
+
+ if(output_expected(this_url, uploadfile)
+ && outs.stream && isatty(fileno(outs.stream)))
+ /* we send the output to a tty, therefore we switch off the progress
+ meter */
+ config->noprogress = config->isatty = TRUE;
+
+ if(urlnum > 1 && !(config->mute)) {
+ fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
+ i+1, urlnum, this_url, outfile ? outfile : "<stdout>");
+ if(separator)
+ printf("%s%s\n", CURLseparator, this_url);
+ }
+ if(httpgetfields) {
+ char *urlbuffer;
+ /* Find out whether the url contains a file name */
+ const char *pc = strstr(this_url, "://");
+ char sep = '?';
+ if(pc)
+ pc += 3;
+ else
+ pc = this_url;
+
+ pc = strrchr(pc, '/'); /* check for a slash */
+
+ if(pc) {
+ /* there is a slash present in the URL */
+
+ if(strchr(pc, '?'))
+ /* Ouch, there's already a question mark in the URL string, we
+ then append the data with an ampersand separator instead! */
+ sep='&';
+ }
+ /*
+ * Then append ? followed by the get fields to the url.
+ */
+ urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3);
+ if(!urlbuffer) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ if(pc)
+ sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields);
+ else
+ /* Append / before the ? to create a well-formed url
+ if the url contains a hostname only
+ */
+ sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields);
+
+ Curl_safefree(this_url); /* free previous URL */
+ this_url = urlbuffer; /* use our new URL instead! */
+ }
+
+ if(!config->errors)
+ config->errors = stderr;
+
+ if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
+ /* We get the output to stdout and we have not got the ASCII/text
+ flag, then set stdout to be binary */
+ set_binmode(stdout);
+ }
+
+ if(config->tcp_nodelay)
+ my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+
+ /* where to store */
+ my_setopt(curl, CURLOPT_WRITEDATA, &outs);
+ /* what call to write */
+ my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
+
+ /* for uploads */
+ input.fd = infd;
+ input.config = config;
+ my_setopt(curl, CURLOPT_READDATA, &input);
+ /* what call to read */
+ if((outfile && !curlx_strequal("-", outfile)) ||
+ !checkprefix("telnet:", this_url))
+ my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
+
+ /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
+ CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
+ my_setopt(curl, CURLOPT_SEEKDATA, &input);
+ my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
+
+ if(config->recvpersecond)
+ /* tell libcurl to use a smaller sized buffer as it allows us to
+ make better sleeps! 7.9.9 stuff! */
+ my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
+
+ /* size of uploaded file: */
+ if(uploadfilesize != -1)
+ my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
+ my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */
+ my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
+ if(config->no_body) {
+ my_setopt(curl, CURLOPT_NOBODY, 1);
+ my_setopt(curl, CURLOPT_HEADER, 1);
+ }
+ else
+ my_setopt(curl, CURLOPT_HEADER, config->include_headers);
+
+#if !defined(CURL_DISABLE_PROXY)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
+ my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
+
+ /* new in libcurl 7.3 */
+ my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
+
+ /* new in libcurl 7.5 */
+ if(config->proxy)
+ my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
+
+ /* new in libcurl 7.10 */
+ if(config->socksproxy) {
+ my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
+ my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
+ }
+
+ /* new in libcurl 7.10.6 */
+ if(config->proxyanyauth)
+ my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+ else if(config->proxynegotiate)
+ my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
+ else if(config->proxyntlm)
+ my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
+ else if(config->proxydigest)
+ my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
+ else if(config->proxybasic)
+ my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
+
+ /* new in libcurl 7.19.4 */
+ my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
+ }
+#endif
+
+ my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
+ my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
+ my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
+ my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
+
+ if(config->netrc_opt)
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+ else if(config->netrc || config->netrc_file)
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
+ else
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
+
+ if(config->netrc_file)
+ my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file);
+
+ my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
+ my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
+ my_setopt_str(curl, CURLOPT_RANGE, config->range);
+ my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+ my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
+
+ if(built_in_protos & CURLPROTO_HTTP) {
+
+ my_setopt(curl, CURLOPT_FOLLOWLOCATION,
+ config->followlocation);
+ my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
+ config->unrestricted_auth);
+
+ switch(config->httpreq) {
+ case HTTPREQ_SIMPLEPOST:
+ my_setopt_str(curl, CURLOPT_POSTFIELDS,
+ config->postfields);
+ my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
+ config->postfieldsize);
+ break;
+ case HTTPREQ_POST:
+ my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
+ break;
+ default:
+ break;
+ }
+
+ my_setopt_str(curl, CURLOPT_REFERER, config->referer);
+ my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
+ my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
+ my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
+
+ /* new in libcurl 7.5 */
+ my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
+
+ /* new in libcurl 7.9.1 */
+ if(config->httpversion)
+ my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
+
+ /* new in libcurl 7.10.6 (default is Basic) */
+ if(config->authtype)
+ my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
+
+ /* curl 7.19.1 (the 301 version existed in 7.18.2) */
+ my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
+ (config->post302 ? CURL_REDIR_POST_302 : FALSE));
+
+ /* new in libcurl 7.21.6 */
+ if(config->encoding)
+ my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
+
+ /* new in libcurl 7.21.6 */
+ if(config->tr_encoding)
+ my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1);
+
+ } /* (built_in_protos & CURLPROTO_HTTP) */
+
+ my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
+ my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
+ config->low_speed_limit);
+ my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
+ my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
+ config->sendpersecond);
+ my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
+ config->recvpersecond);
+ my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
+ config->use_resume?config->resume_from:0);
+
+ my_setopt(curl, CURLOPT_SSLCERT, config->cert);
+ my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
+ my_setopt(curl, CURLOPT_SSLKEY, config->key);
+ my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
+ my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
+
+ if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
+
+ /* SSH and SSL private key uses same command-line option */
+ /* new in libcurl 7.16.1 */
+ my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
+ /* new in libcurl 7.16.1 */
+ my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
+
+ /* new in libcurl 7.17.1: SSH host key md5 checking allows us
+ to fail if we are not talking to who we think we should */
+ my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
+ config->hostpubmd5);
+ }
+
+ if(config->cacert)
+ my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
+ if(config->capath)
+ my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
+ if(config->crlfile)
+ my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
+
+ if(curlinfo->features & CURL_VERSION_SSL) {
+ if(config->insecure_ok) {
+ my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
+ }
+ else {
+ my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+ /* libcurl default is strict verifyhost -> 2L */
+ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
+ }
+ }
+
+ if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
+ if(!config->insecure_ok) {
+ char *home;
+ char *file;
+ res = CURLE_OUT_OF_MEMORY;
+ home = homedir();
+ if(home) {
+ file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
+ if(file) {
+ /* new in curl 7.19.6 */
+ res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
+ curl_free(file);
+ if(res == CURLE_UNKNOWN_OPTION)
+ /* libssh2 version older than 1.1.1 */
+ res = CURLE_OK;
+ }
+ Curl_safefree(home);
+ }
+ if(res)
+ goto show_error;
+ }
+ }
+
+ if(config->no_body || config->remote_time) {
+ /* no body or use remote time */
+ my_setopt(curl, CURLOPT_FILETIME, TRUE);
+ }
+
+ my_setopt(curl, CURLOPT_CRLF, config->crlf);
+ my_setopt(curl, CURLOPT_QUOTE, config->quote);
+ my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
+ my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ if(config->cookie)
+ my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
+
+ if(config->cookiefile)
+ my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
+
+ /* new in libcurl 7.9 */
+ if(config->cookiejar)
+ my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
+
+ /* new in libcurl 7.9.7 */
+ my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
+ }
+#endif
+
+ my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
+ my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
+ my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
+ my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
+ my_setopt(curl, CURLOPT_STDERR, config->errors);
+
+ /* three new ones in libcurl 7.3: */
+ my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
+ my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
+
+ progressbarinit(&progressbar, config);
+ if((config->progressmode == CURL_PROGRESS_BAR) &&
+ !config->noprogress && !config->mute) {
+ /* we want the alternative style, then we have to implement it
+ ourselves! */
+ my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb);
+ my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
+ }
+
+ /* new in libcurl 7.6.2: */
+ my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
+
+ /* new in libcurl 7.7: */
+ my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
+ my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
+ my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
+
+ if(config->cipher_list)
+ my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
+
+ /* new in libcurl 7.9.2: */
+ if(config->disable_epsv)
+ /* disable it */
+ my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
+
+ /* new in libcurl 7.10.5 */
+ if(config->disable_eprt)
+ /* disable it */
+ my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
+
+ if(config->tracetype != TRACE_NONE) {
+ my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
+ my_setopt(curl, CURLOPT_DEBUGDATA, config);
+ my_setopt(curl, CURLOPT_VERBOSE, TRUE);
+ }
+
+ /* new in curl 7.9.3 */
+ if(config->engine) {
+ res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
+ if(res)
+ goto show_error;
+ my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
+ }
+
+ /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
+ my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
+ config->ftp_create_dirs);
+
+ /* new in curl 7.10.8 */
+ if(config->max_filesize)
+ my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
+ config->max_filesize);
+
+ if(4 == config->ip_version)
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ else if(6 == config->ip_version)
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
+ else
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
+
+ /* new in curl 7.15.5 */
+ if(config->ftp_ssl_reqd)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
+
+ /* new in curl 7.11.0 */
+ else if(config->ftp_ssl)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+
+ /* new in curl 7.16.0 */
+ else if(config->ftp_ssl_control)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
+
+ /* new in curl 7.16.1 */
+ if(config->ftp_ssl_ccc)
+ my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ /* new in curl 7.19.4 */
+ if(config->socks5_gssapi_service)
+ my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
+ config->socks5_gssapi_service);
+
+ /* new in curl 7.19.4 */
+ if(config->socks5_gssapi_nec)
+ my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
+ config->socks5_gssapi_nec);
+ }
+#endif
+ /* curl 7.13.0 */
+ my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
+
+ my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
+
+ /* curl 7.14.2 */
+ my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
+
+ /* curl 7.15.1 */
+ my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
+
+ /* curl 7.15.2 */
+ if(config->localport) {
+ my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
+ my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
+ config->localportrange);
+ }
+
+ /* curl 7.15.5 */
+ my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
+ config->ftp_alternative_to_user);
+
+ /* curl 7.16.0 */
+ if(config->disable_sessionid)
+ my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
+ !config->disable_sessionid);
+
+ /* curl 7.16.2 */
+ if(config->raw) {
+ my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
+ my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
+ }
+
+ /* curl 7.17.1 */
+ if(!config->nokeepalive) {
+ my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, tool_sockopt_cb);
+ my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
+ }
+
+ /* curl 7.20.0 */
+ if(config->tftp_blksize)
+ my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
+
+ if(config->mail_from)
+ my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
+
+ if(config->mail_rcpt)
+ my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
+
+ /* curl 7.20.x */
+ if(config->ftp_pret)
+ my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
+
+ if(config->proto_present)
+ my_setopt(curl, CURLOPT_PROTOCOLS, config->proto);
+ if(config->proto_redir_present)
+ my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
+
+ if((urlnode->flags & GETOUT_USEREMOTE)
+ && config->content_disposition) {
+ my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
+ my_setopt(curl, CURLOPT_HEADERDATA, &outs);
+ }
+ else {
+ /* if HEADERFUNCTION was set to something in the previous loop, it
+ is important that we set it (back) to NULL now */
+ my_setopt(curl, CURLOPT_HEADERFUNCTION, NULL);
+ my_setopt(curl, CURLOPT_HEADERDATA, config->headerfile?&heads:NULL);
+ }
+
+ if(config->resolve)
+ /* new in 7.21.3 */
+ my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
+
+ /* new in 7.21.4 */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
+ if(config->tls_username)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
+ config->tls_username);
+ if(config->tls_password)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
+ config->tls_password);
+ if(config->tls_authtype)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
+ config->tls_authtype);
+ }
+
+ /* new in 7.22.0 */
+ if(config->gssapi_delegation)
+ my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
+ config->gssapi_delegation);
+
+ /* initialize retry vars for loop below */
+ retry_sleep_default = (config->retry_delay) ?
+ config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
+
+ retry_numretries = config->req_retry;
+ retry_sleep = retry_sleep_default; /* ms */
+ retrystart = tvnow();
+
+ if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+
+ for(;;) {
+ res = curl_easy_perform(curl);
+
+ if(config->content_disposition && outs.stream && !config->mute &&
+ outs.filename)
+ printf("curl: Saved to filename '%s'\n", outs.filename);
+
+ /* if retry-max-time is non-zero, make sure we haven't exceeded the
+ time */
+ if(retry_numretries &&
+ (!config->retry_maxtime ||
+ (tvdiff(tvnow(), retrystart) <
+ config->retry_maxtime*1000L)) ) {
+ enum {
+ RETRY_NO,
+ RETRY_TIMEOUT,
+ RETRY_HTTP,
+ RETRY_FTP,
+ RETRY_LAST /* not used */
+ } retry = RETRY_NO;
+ long response;
+ if(CURLE_OPERATION_TIMEDOUT == res)
+ /* retry timeout always */
+ retry = RETRY_TIMEOUT;
+ else if((CURLE_OK == res) ||
+ (config->failonerror &&
+ (CURLE_HTTP_RETURNED_ERROR == res))) {
+ /* If it returned OK. _or_ failonerror was enabled and it
+ returned due to such an error, check for HTTP transient
+ errors to retry on. */
+ char *effective_url = NULL;
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
+ if(effective_url &&
+ checkprefix("http", effective_url)) {
+ /* This was HTTP(S) */
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+ switch(response) {
+ case 500: /* Internal Server Error */
+ case 502: /* Bad Gateway */
+ case 503: /* Service Unavailable */
+ case 504: /* Gateway Timeout */
+ retry = RETRY_HTTP;
+ /*
+ * At this point, we have already written data to the output
+ * file (or terminal). If we write to a file, we must rewind
+ * or close/re-open the file so that the next attempt starts
+ * over from the beginning.
+ *
+ * TODO: similar action for the upload case. We might need
+ * to start over reading from a previous point if we have
+ * uploaded something when this was returned.
+ */
+ break;
+ }
+ }
+ } /* if CURLE_OK */
+ else if(res) {
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+ if(response/100 == 4)
+ /*
+ * This is typically when the FTP server only allows a certain
+ * amount of users and we are not one of them. All 4xx codes
+ * are transient.
+ */
+ retry = RETRY_FTP;
+ }
+
+ if(retry) {
+ static const char * const m[]={
+ NULL, "timeout", "HTTP error", "FTP error"
+ };
+ warnf(config, "Transient problem: %s "
+ "Will retry in %ld seconds. "
+ "%ld retries left.\n",
+ m[retry], retry_sleep/1000L, retry_numretries);
+
+ tool_go_sleep(retry_sleep);
+ retry_numretries--;
+ if(!config->retry_delay) {
+ retry_sleep *= 2;
+ if(retry_sleep > RETRY_SLEEP_MAX)
+ retry_sleep = RETRY_SLEEP_MAX;
+ }
+ if(outs.bytes && outs.filename) {
+ /* We have written data to a output file, we truncate file
+ */
+ if(!config->mute)
+ fprintf(config->errors, "Throwing away %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ outs.bytes);
+ fflush(outs.stream);
+ /* truncate file at the position where we started appending */
+#ifdef HAVE_FTRUNCATE
+ if(ftruncate( fileno(outs.stream), outs.init)) {
+ /* when truncate fails, we can't just append as then we'll
+ create something strange, bail out */
+ if(!config->mute)
+ fprintf(config->errors,
+ "failed to truncate, exiting\n");
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+ /* now seek to the end of the file, the position where we
+ just truncated the file in a large file-safe way */
+ fseek(outs.stream, 0, SEEK_END);
+#else
+ /* ftruncate is not available, so just reposition the file
+ to the location we would have truncated it. This won't
+ work properly with large files on 32-bit systems, but
+ most of those will have ftruncate. */
+ fseek(outs.stream, (long)outs.init, SEEK_SET);
+#endif
+ outs.bytes = 0; /* clear for next round */
+ }
+ continue; /* curl_easy_perform loop */
+ }
+ } /* if retry_numretries */
+
+ /* In all ordinary cases, just break out of loop here */
+ break; /* curl_easy_perform loop */
+
+ }
+
+ if((config->progressmode == CURL_PROGRESS_BAR) &&
+ progressbar.calls)
+ /* if the custom progress bar has been displayed, we output a
+ newline here */
+ fputs("\n", progressbar.out);
+
+ if(config->writeout)
+ ourWriteOut(curl, config->writeout);
+
+ if(config->writeenv)
+ ourWriteEnv(curl);
+
+ /*
+ ** Code within this loop may jump directly here to label 'show_error'
+ ** in order to display an error message for CURLcode stored in 'res'
+ ** variable and exit loop once that necessary writing and cleanup
+ ** in label 'quit_urls' has been done.
+ */
+
+ show_error:
+
+#ifdef __VMS
+ if(is_vms_shell()) {
+ /* VMS DCL shell behavior */
+ if(!config->showerror)
+ vms_show = VMSSTS_HIDE;
+ }
+ else
+#endif
+ if(res && config->showerror) {
+ fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ?
+ errorbuffer : curl_easy_strerror((CURLcode)res));
+ if(res == CURLE_SSL_CACERT)
+ fprintf(config->errors, "%s%s",
+ CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
+ }
+
+ /* Fall through comment to 'quit_urls' label */
+
+ /*
+ ** Upon error condition and always that a message has already been
+ ** displayed, code within this loop may jump directly here to label
+ ** 'quit_urls' otherwise it should jump to 'show_error' label above.
+ **
+ ** When 'res' variable is _not_ CURLE_OK loop will exit once that
+ ** all code following 'quit_urls' has been executed. Otherwise it
+ ** will loop to the beginning from where it may exit if there are
+ ** no more urls left.
+ */
+
+ quit_urls:
+
+ /* Set file extended attributes */
+ if(!res && config->xattr && outs.fopened && outs.stream) {
+ int rc = fwrite_xattr(curl, fileno(outs.stream));
+ if(rc)
+ warnf(config, "Error setting extended attributes: %s\n",
+ strerror(errno));
+ }
+
+ /* Close the file */
+ if(outs.fopened && outs.stream) {
+ int rc = fclose(outs.stream);
+ if(!res && rc) {
+ /* something went wrong in the writing process */
+ res = CURLE_WRITE_ERROR;
+ fprintf(config->errors, "(%d) Failed writing body\n", res);
+ }
+ }
+ else if(!outs.s_isreg && outs.stream) {
+ /* Dump standard stream buffered data */
+ int rc = fflush(outs.stream);
+ if(!res && rc) {
+ /* something went wrong in the writing process */
+ res = CURLE_WRITE_ERROR;
+ fprintf(config->errors, "(%d) Failed writing body\n", res);
+ }
+ }
+
+#ifdef __AMIGA__
+ if(!res && outs.s_isreg && outs.filename) {
+ /* Set the url (up to 80 chars) as comment for the file */
+ if(strlen(url) > 78)
+ url[79] = '\0';
+ SetComment(outs.filename, url);
+ }
+#endif
+
+#ifdef HAVE_UTIME
+ /* File time can only be set _after_ the file has been closed */
+ if(!res && config->remote_time && outs.s_isreg && outs.filename) {
+ /* Ask libcurl if we got a remote file time */
+ long filetime = -1;
+ curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
+ if(filetime >= 0) {
+ struct utimbuf times;
+ times.actime = (time_t)filetime;
+ times.modtime = (time_t)filetime;
+ utime(outs.filename, &times); /* set the time we got */
+ }
+ }
+#endif
+ /* No more business with this output struct */
+ if(outs.alloc_filename)
+ Curl_safefree(outs.filename);
+ memset(&outs, 0, sizeof(struct OutStruct));
+
+ /* Free loop-local allocated memory and close loop-local opened fd */
+
+ Curl_safefree(outfile);
+ Curl_safefree(this_url);
+
+ if(infdopen) {
+ close(infd);
+ infdopen = FALSE;
+ infd = STDIN_FILENO;
+ }
+
+ /* upon error exit loop */
+ if(res)
+ break;
+
+ } /* loop to the next URL */
+
+ /* Free loop-local allocated memory */
+
+ Curl_safefree(uploadfile);
+
+ if(urls) {
+ /* Free list of remaining URLs */
+ glob_cleanup(urls);
+ urls = NULL;
+ }
+
+ /* upon error exit loop */
+ if(res)
+ break;
+
+ } /* loop to the next globbed upload file */
+
+ /* Free loop-local allocated memory */
+
+ Curl_safefree(outfiles);
+
+ if(inglob) {
+ /* Free list of globbed upload files */
+ glob_cleanup(inglob);
+ inglob = NULL;
+ }
+
+ /* Free this URL node data without destroying the
+ the node itself nor modifying next pointer. */
+ Curl_safefree(urlnode->url);
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ urlnode->flags = 0;
+
+ /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
+
+ /*
+ ** Bail out upon critical errors
+ */
+ switch(res) {
+ case CURLE_FAILED_INIT:
+ case CURLE_OUT_OF_MEMORY:
+ case CURLE_FUNCTION_NOT_FOUND:
+ case CURLE_BAD_FUNCTION_ARGUMENT:
+ goto quit_curl;
+ default:
+ /* Merrily loop to next URL */
+ break;
+ }
+
+ } /* for-loop through all URLs */
+
+ /*
+ ** Nested loops end here.
+ */
+
+ quit_curl:
+
+ /* Free function-local referenced allocated memory */
+ Curl_safefree(httpgetfields);
+
+ /* Free list of given URLs */
+ clean_getout(config);
+
+ /* Cleanup the curl handle now that our
+ progressbar struct is still in scope */
+ if(curl) {
+ curl_easy_cleanup(curl);
+ config->easy = curl = NULL;
+ }
+ if(easysrc)
+ curl_slist_append(easysrc, "curl_easy_cleanup(hnd);");
+
+ /* Close function-local opened file descriptors */
+
+ if(heads.fopened && heads.stream)
+ fclose(heads.stream);
+ if(heads.alloc_filename)
+ Curl_safefree(heads.filename);
+
+ if(config->trace_fopened && config->trace_stream)
+ fclose(config->trace_stream);
+
+ /* Dump the libcurl code if previously enabled.
+ NOTE: that this function relies on config->errors amongst other things
+ so not everything can be closed and cleaned before this is called */
+ dumpeasysrc(config);
+
+ if(config->errors_fopened && config->errors)
+ fclose(config->errors);
+
+ main_free(); /* cleanup */
+
+ return res;
+}
+
diff --git a/src/tool_operate.h b/src/tool_operate.h
new file mode 100644
index 000000000..4986cc4e3
--- /dev/null
+++ b/src/tool_operate.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_OPERATE_H
+#define HEADER_CURL_TOOL_OPERATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+int operate(struct Configurable *config, int argc, argv_item_t argv[]);
+
+#endif /* HEADER_CURL_TOOL_OPERATE_H */
+
diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c
new file mode 100644
index 000000000..808d2d564
--- /dev/null
+++ b/src/tool_operhlp.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_convert.h"
+#include "tool_operhlp.h"
+#include "tool_version.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+ * my_useragent: returns allocated string with default user agent
+ */
+char *my_useragent(void)
+{
+ char useragent[256]; /* we don't want a larger default user agent */
+
+ snprintf(useragent, sizeof(useragent),
+ CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
+
+ return strdup(useragent);
+}
+
+/*
+ * Print list of OpenSSL supported engines
+ */
+void list_engines(const struct curl_slist *engines)
+{
+ puts("Build-time engines:");
+ if(!engines) {
+ puts(" <none>");
+ return;
+ }
+ for(; engines; engines = engines->next)
+ printf(" %s\n", engines->data);
+}
+
+void clean_getout(struct Configurable *config)
+{
+ struct getout *next;
+ struct getout *node = config->url_list;
+
+ while(node) {
+ next = node->next;
+ Curl_safefree(node->url);
+ Curl_safefree(node->outfile);
+ Curl_safefree(node->infile);
+ Curl_safefree(node);
+ node = next;
+ }
+ config->url_list = NULL;
+}
+
+bool output_expected(const char *url, const char *uploadfile)
+{
+ if(!uploadfile)
+ return TRUE; /* download */
+ if(checkprefix("http://", url) || checkprefix("https://", url))
+ return TRUE; /* HTTP(S) upload */
+
+ return FALSE; /* non-HTTP upload, probably no output should be expected */
+}
+
+bool stdin_upload(const char *uploadfile)
+{
+ return (curlx_strequal(uploadfile, "-") ||
+ curlx_strequal(uploadfile, ".")) ? TRUE : FALSE;
+}
+
+/*
+ * Adds the file name to the URL if it doesn't already have one.
+ * url will be freed before return if the returned pointer is different
+ */
+char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
+{
+ /* If no file name part is given in the URL, we add this file name */
+ char *ptr = strstr(url, "://");
+ if(ptr)
+ ptr += 3;
+ else
+ ptr = url;
+ ptr = strrchr(ptr, '/');
+ if(!ptr || !strlen(++ptr)) {
+ /* The URL has no file name part, add the local file name. In order
+ to be able to do so, we have to create a new URL in another
+ buffer.*/
+
+ /* We only want the part of the local path that is on the right
+ side of the rightmost slash and backslash. */
+ const char *filep = strrchr(filename, '/');
+ char *file2 = strrchr(filep?filep:filename, '\\');
+ char *encfile;
+
+ if(file2)
+ filep = file2 + 1;
+ else if(filep)
+ filep++;
+ else
+ filep = filename;
+
+ /* URL encode the file name */
+ encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
+ if(encfile) {
+ char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
+ if(!urlbuffer) {
+ curl_free(encfile);
+ Curl_safefree(url);
+ return NULL;
+ }
+ if(ptr)
+ /* there is a trailing slash on the URL */
+ sprintf(urlbuffer, "%s%s", url, encfile);
+ else
+ /* there is no trailing slash on the URL */
+ sprintf(urlbuffer, "%s/%s", url, encfile);
+
+ curl_free(encfile);
+ Curl_safefree(url);
+
+ url = urlbuffer; /* use our new URL instead! */
+ }
+ }
+ return url;
+}
+
+/* Extracts the name portion of the URL.
+ * Returns a pointer to a heap-allocated string or NULL if
+ * no name part, at location indicated by first argument.
+ */
+CURLcode get_url_file_name(char **filename, const char *url)
+{
+ const char *pc;
+
+ *filename = NULL;
+
+ /* Find and get the remote file name */
+ pc = strstr(url, "://");
+ if(pc)
+ pc += 3;
+ else
+ pc = url;
+ pc = strrchr(pc, '/');
+
+ if(pc) {
+ /* duplicate the string beyond the slash */
+ pc++;
+ if(*pc) {
+ *filename = strdup(pc);
+ if(!*filename)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
+ * This is the main global constructor for the app. Call this before
+ * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
+ * used, or havoc may be the result.
+ */
+CURLcode main_init(void)
+{
+#if defined(__DJGPP__) || defined(__GO32__)
+ /* stop stat() wasting time */
+ _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
+#endif
+
+ return curl_global_init(CURL_GLOBAL_DEFAULT);
+}
+
+/*
+ * This is the main global destructor for the app. Call this after
+ * _all_ libcurl usage is done.
+ */
+void main_free(void)
+{
+ curl_global_cleanup();
+ convert_cleanup();
+}
+
+#ifdef CURLDEBUG
+void memory_tracking_init(void)
+{
+ char *env;
+ /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
+ env = curlx_getenv("CURL_MEMDEBUG");
+ if(env) {
+ /* use the value as file name */
+ char fname[CURL_MT_LOGFNAME_BUFSIZE];
+ if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
+ env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
+ strcpy(fname, env);
+ curl_free(env);
+ curl_memdebug(fname);
+ /* this weird stuff here is to make curl_free() get called
+ before curl_memdebug() as otherwise memory tracking will
+ log a free() without an alloc! */
+ }
+ /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
+ env = curlx_getenv("CURL_MEMLIMIT");
+ if(env) {
+ char *endptr;
+ long num = strtol(env, &endptr, 10);
+ if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
+ curl_memlimit(num);
+ curl_free(env);
+ }
+}
+#endif
+
diff --git a/src/tool_operhlp.h b/src/tool_operhlp.h
new file mode 100644
index 000000000..3629bf13a
--- /dev/null
+++ b/src/tool_operhlp.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_TOOL_OPERHLP_H
+#define HEADER_CURL_TOOL_OPERHLP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+char *my_useragent(void);
+
+void list_engines(const struct curl_slist *engines);
+
+void clean_getout(struct Configurable *config);
+
+bool output_expected(const char *url, const char *uploadfile);
+
+bool stdin_upload(const char *uploadfile);
+
+char *add_file_name_to_url(CURL *curl, char *url, const char *filename);
+
+CURLcode get_url_file_name(char **filename, const char *url);
+
+CURLcode main_init(void);
+
+void main_free(void);
+
+#ifdef CURLDEBUG
+void memory_tracking_init(void);
+#else
+# define memory_tracking_init() Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_OPERHLP_H */
+
diff --git a/src/tool_panykey.c b/src/tool_panykey.c
new file mode 100644
index 000000000..95fa6a763
--- /dev/null
+++ b/src/tool_panykey.c
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#if defined(__SYMBIAN32__) || defined(NETWARE)
+
+#ifdef NETWARE
+# ifdef __NOVELL_LIBC__
+# include <screen.h>
+# else
+# include <nwconio.h>
+# endif
+#endif
+
+#include "tool_panykey.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void tool_pressanykey(void)
+{
+#if defined(__SYMBIAN32__)
+ getchar();
+#elif defined(NETWARE)
+ pressanykey();
+#endif
+}
+
+#endif /* __SYMBIAN32__ || NETWARE */
+
diff --git a/src/tool_panykey.h b/src/tool_panykey.h
new file mode 100644
index 000000000..30fd658d3
--- /dev/null
+++ b/src/tool_panykey.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_TOOL_PANYKEY_H
+#define HEADER_CURL_TOOL_PANYKEY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#if defined(__SYMBIAN32__) || defined(NETWARE)
+
+void tool_pressanykey(void);
+
+#else
+
+#define tool_pressanykey() Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_TOOL_PANYKEY_H */
+
diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c
new file mode 100644
index 000000000..adb12ce70
--- /dev/null
+++ b/src/tool_paramhlp.c
@@ -0,0 +1,387 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_getparam.h"
+#include "tool_getpass.h"
+#include "tool_homedir.h"
+#include "tool_msgs.h"
+#include "tool_paramhlp.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+struct getout *new_getout(struct Configurable *config)
+{
+ struct getout *node = calloc(1, sizeof(struct getout));
+ struct getout *last = config->url_last;
+ if(node) {
+ /* append this new node last in the list */
+ if(last)
+ last->next = node;
+ else
+ config->url_list = node; /* first node */
+
+ /* move the last pointer */
+ config->url_last = node;
+
+ node->flags = config->default_node_flags;
+ }
+ return node;
+}
+
+ParameterError file2string(char **bufp, FILE *file)
+{
+ char buffer[256];
+ char *ptr;
+ char *string = NULL;
+ size_t stringlen = 0;
+ size_t buflen;
+
+ if(file) {
+ while(fgets(buffer, sizeof(buffer), file)) {
+ if((ptr = strchr(buffer, '\r')) != NULL)
+ *ptr = '\0';
+ if((ptr = strchr(buffer, '\n')) != NULL)
+ *ptr = '\0';
+ buflen = strlen(buffer);
+ if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
+ Curl_safefree(string);
+ return PARAM_NO_MEM;
+ }
+ string = ptr;
+ strcpy(string+stringlen, buffer);
+ stringlen += buflen;
+ }
+ }
+ *bufp = string;
+ return PARAM_OK;
+}
+
+ParameterError file2memory(char **bufp, size_t *size, FILE *file)
+{
+ char *newbuf;
+ char *buffer = NULL;
+ size_t alloc = 512;
+ size_t nused = 0;
+ size_t nread;
+
+ if(file) {
+ do {
+ if(!buffer || (alloc == nused)) {
+ /* size_t overflow detection for huge files */
+ if(alloc+1 > ((size_t)-1)/2) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ alloc *= 2;
+ /* allocate an extra char, reserved space, for null termination */
+ if((newbuf = realloc(buffer, alloc+1)) == NULL) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ buffer = newbuf;
+ }
+ nread = fread(buffer+nused, 1, alloc-nused, file);
+ nused += nread;
+ } while(nread);
+ /* null terminate the buffer in case it's used as a string later */
+ buffer[nused] = '\0';
+ /* free trailing slack space, if possible */
+ if(alloc != nused) {
+ if((newbuf = realloc(buffer, nused+1)) == NULL) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ buffer = newbuf;
+ }
+ /* discard buffer if nothing was read */
+ if(!nused) {
+ Curl_safefree(buffer); /* no string */
+ }
+ }
+ *size = nused;
+ *bufp = buffer;
+ return PARAM_OK;
+}
+
+void cleanarg(char *str)
+{
+#ifdef HAVE_WRITABLE_ARGV
+ /* now that GetStr has copied the contents of nextarg, wipe the next
+ * argument out so that the username:password isn't displayed in the
+ * system process list */
+ if(str) {
+ size_t len = strlen(str);
+ memset(str, ' ', len);
+ }
+#else
+ (void)str;
+#endif
+}
+
+/*
+ * Parse the string and write the integer in the given address. Return
+ * non-zero on failure, zero on success.
+ *
+ * The string must start with a digit to be valid.
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+int str2num(long *val, const char *str)
+{
+ if(str && ISDIGIT(*str)) {
+ char *endptr;
+ long num = strtol(str, &endptr, 10);
+ if((endptr != str) && (endptr == str + strlen(str))) {
+ *val = num;
+ return 0; /* Ok */
+ }
+ }
+ return 1; /* badness */
+}
+
+/*
+ * Parse the string and modify the long in the given address. Return
+ * non-zero on failure, zero on success.
+ *
+ * The string is a list of protocols
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+long proto2num(struct Configurable *config, long *val, const char *str)
+{
+ char *buffer;
+ const char *sep = ",";
+ char *token;
+
+ static struct sprotos {
+ const char *name;
+ long bit;
+ } const protos[] = {
+ { "all", CURLPROTO_ALL },
+ { "http", CURLPROTO_HTTP },
+ { "https", CURLPROTO_HTTPS },
+ { "ftp", CURLPROTO_FTP },
+ { "ftps", CURLPROTO_FTPS },
+ { "scp", CURLPROTO_SCP },
+ { "sftp", CURLPROTO_SFTP },
+ { "telnet", CURLPROTO_TELNET },
+ { "ldap", CURLPROTO_LDAP },
+ { "ldaps", CURLPROTO_LDAPS },
+ { "dict", CURLPROTO_DICT },
+ { "file", CURLPROTO_FILE },
+ { "tftp", CURLPROTO_TFTP },
+ { "imap", CURLPROTO_IMAP },
+ { "imaps", CURLPROTO_IMAPS },
+ { "pop3", CURLPROTO_POP3 },
+ { "pop3s", CURLPROTO_POP3S },
+ { "smtp", CURLPROTO_SMTP },
+ { "smtps", CURLPROTO_SMTPS },
+ { "rtsp", CURLPROTO_RTSP },
+ { "gopher", CURLPROTO_GOPHER },
+ { NULL, 0 }
+ };
+
+ if(!str)
+ return 1;
+
+ buffer = strdup(str); /* because strtok corrupts it */
+ if(!buffer)
+ return 1;
+
+ for(token = strtok(buffer, sep);
+ token;
+ token = strtok(NULL, sep)) {
+ enum e_action { allow, deny, set } action = allow;
+
+ struct sprotos const *pp;
+
+ /* Process token modifiers */
+ while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
+ switch (*token++) {
+ case '=':
+ action = set;
+ break;
+ case '-':
+ action = deny;
+ break;
+ case '+':
+ action = allow;
+ break;
+ default: /* Includes case of terminating NULL */
+ Curl_safefree(buffer);
+ return 1;
+ }
+ }
+
+ for(pp=protos; pp->name; pp++) {
+ if(curlx_raw_equal(token, pp->name)) {
+ switch (action) {
+ case deny:
+ *val &= ~(pp->bit);
+ break;
+ case allow:
+ *val |= pp->bit;
+ break;
+ case set:
+ *val = pp->bit;
+ break;
+ }
+ break;
+ }
+ }
+
+ if(!(pp->name)) { /* unknown protocol */
+ /* If they have specified only this protocol, we say treat it as
+ if no protocols are allowed */
+ if(action == set)
+ *val = 0;
+ warnf(config, "unrecognized protocol '%s'\n", token);
+ }
+ }
+ Curl_safefree(buffer);
+ return 0;
+}
+
+/**
+ * Parses the given string looking for an offset (which may be
+ * a larger-than-integer value).
+ *
+ * @param val the offset to populate
+ * @param str the buffer containing the offset
+ * @return zero if successful, non-zero if failure.
+ */
+int str2offset(curl_off_t *val, const char *str)
+{
+#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+ *val = curlx_strtoofft(str, NULL, 0);
+ if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
+ return 1;
+#else
+ *val = strtol(str, NULL, 0);
+ if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
+ return 1;
+#endif
+ return 0;
+}
+
+ParameterError checkpasswd(const char *kind, /* for what purpose */
+ char **userpwd) /* pointer to allocated string */
+{
+ char *ptr;
+
+ if(!*userpwd)
+ return PARAM_OK;
+
+ ptr = strchr(*userpwd, ':');
+ if(!ptr) {
+ /* no password present, prompt for one */
+ char passwd[256] = "";
+ char prompt[256];
+ size_t passwdlen;
+ size_t userlen = strlen(*userpwd);
+ char *passptr;
+
+ /* build a nice-looking prompt */
+ curlx_msnprintf(prompt, sizeof(prompt),
+ "Enter %s password for user '%s':",
+ kind, *userpwd);
+
+ /* get password */
+ getpass_r(prompt, passwd, sizeof(passwd));
+ passwdlen = strlen(passwd);
+
+ /* extend the allocated memory area to fit the password too */
+ passptr = realloc(*userpwd,
+ passwdlen + 1 + /* an extra for the colon */
+ userlen + 1); /* an extra for the zero */
+ if(!passptr)
+ return PARAM_NO_MEM;
+
+ /* append the password separated with a colon */
+ passptr[userlen] = ':';
+ memcpy(&passptr[userlen+1], passwd, passwdlen+1);
+ *userpwd = passptr;
+ }
+ return PARAM_OK;
+}
+
+ParameterError add2list(struct curl_slist **list, const char *ptr)
+{
+ struct curl_slist *newlist = curl_slist_append(*list, ptr);
+ if(newlist)
+ *list = newlist;
+ else
+ return PARAM_NO_MEM;
+
+ return PARAM_OK;
+}
+
+int ftpfilemethod(struct Configurable *config, const char *str)
+{
+ if(curlx_raw_equal("singlecwd", str))
+ return CURLFTPMETHOD_SINGLECWD;
+ if(curlx_raw_equal("nocwd", str))
+ return CURLFTPMETHOD_NOCWD;
+ if(curlx_raw_equal("multicwd", str))
+ return CURLFTPMETHOD_MULTICWD;
+ warnf(config, "unrecognized ftp file method '%s', using default\n", str);
+ return CURLFTPMETHOD_MULTICWD;
+}
+
+int ftpcccmethod(struct Configurable *config, const char *str)
+{
+ if(curlx_raw_equal("passive", str))
+ return CURLFTPSSL_CCC_PASSIVE;
+ if(curlx_raw_equal("active", str))
+ return CURLFTPSSL_CCC_ACTIVE;
+ warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
+ return CURLFTPSSL_CCC_PASSIVE;
+}
+
+long delegation(struct Configurable *config, char *str)
+{
+ if(curlx_raw_equal("none", str))
+ return CURLGSSAPI_DELEGATION_NONE;
+ if(curlx_raw_equal("policy", str))
+ return CURLGSSAPI_DELEGATION_POLICY_FLAG;
+ if(curlx_raw_equal("always", str))
+ return CURLGSSAPI_DELEGATION_FLAG;
+ warnf(config, "unrecognized delegation method '%s', using none\n", str);
+ return CURLGSSAPI_DELEGATION_NONE;
+}
+
diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h
new file mode 100644
index 000000000..f17999198
--- /dev/null
+++ b/src/tool_paramhlp.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_TOOL_PARAMHLP_H
+#define HEADER_CURL_TOOL_PARAMHLP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+struct getout *new_getout(struct Configurable *config);
+
+ParameterError file2string(char **bufp, FILE *file);
+
+ParameterError file2memory(char **bufp, size_t *size, FILE *file);
+
+void cleanarg(char *str);
+
+int str2num(long *val, const char *str);
+
+long proto2num(struct Configurable *config, long *val, const char *str);
+
+int str2offset(curl_off_t *val, const char *str);
+
+ParameterError checkpasswd(const char *kind, char **userpwd);
+
+ParameterError add2list(struct curl_slist **list, const char *ptr);
+
+int ftpfilemethod(struct Configurable *config, const char *str);
+
+int ftpcccmethod(struct Configurable *config, const char *str);
+
+long delegation(struct Configurable *config, char *str);
+
+#endif /* HEADER_CURL_TOOL_PARAMHLP_H */
+
diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c
new file mode 100644
index 000000000..b60d31830
--- /dev/null
+++ b/src/tool_parsecfg.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+#include "tool_homedir.h"
+#include "tool_msgs.h"
+#include "tool_parsecfg.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define CURLRC DOT_CHAR "curlrc"
+#define ISSEP(x) (((x) == '=') || ((x) == ':'))
+
+static const char *unslashquote(const char *line, char *param);
+static char *my_get_line(FILE *fp);
+
+/* return 0 on everything-is-fine, and non-zero otherwise */
+int parseconfig(const char *filename,
+ struct Configurable *config)
+{
+ int res;
+ FILE *file;
+ char filebuffer[512];
+ bool usedarg;
+ char *home;
+ int rc = 0;
+
+ if(!filename || !*filename) {
+ /* NULL or no file name attempts to load .curlrc from the homedir! */
+
+#ifndef __AMIGA__
+ filename = CURLRC; /* sensible default */
+ home = homedir(); /* portable homedir finder */
+ if(home) {
+ if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) {
+ snprintf(filebuffer, sizeof(filebuffer),
+ "%s%s%s", home, DIR_CHAR, CURLRC);
+
+#ifdef WIN32
+ /* Check if the file exists - if not, try CURLRC in the same
+ * directory as our executable
+ */
+ file = fopen(filebuffer, "r");
+ if(file != NULL) {
+ fclose(file);
+ filename = filebuffer;
+ }
+ else {
+ /* Get the filename of our executable. GetModuleFileName is
+ * already declared via inclusions done in setup header file.
+ * We assume that we are using the ASCII version here.
+ */
+ int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
+ if(n > 0 && n < (int)sizeof(filebuffer)) {
+ /* We got a valid filename - get the directory part */
+ char *lastdirchar = strrchr(filebuffer, '\\');
+ if(lastdirchar) {
+ size_t remaining;
+ *lastdirchar = 0;
+ /* If we have enough space, build the RC filename */
+ remaining = sizeof(filebuffer) - strlen(filebuffer);
+ if(strlen(CURLRC) < remaining - 1) {
+ snprintf(lastdirchar, remaining,
+ "%s%s", DIR_CHAR, CURLRC);
+ /* Don't bother checking if it exists - we do
+ * that later
+ */
+ filename = filebuffer;
+ }
+ }
+ }
+ }
+#else /* WIN32 */
+ filename = filebuffer;
+#endif /* WIN32 */
+ }
+ Curl_safefree(home); /* we've used it, now free it */
+ }
+
+# else /* __AMIGA__ */
+ /* On AmigaOS all the config files are into env:
+ */
+ filename = "ENV:" CURLRC;
+
+#endif
+ }
+
+ if(strcmp(filename,"-"))
+ file = fopen(filename, "r");
+ else
+ file = stdin;
+
+ if(file) {
+ char *line;
+ char *aline;
+ char *option;
+ char *param;
+ int lineno = 0;
+ bool alloced_param;
+
+ while(NULL != (aline = my_get_line(file))) {
+ lineno++;
+ line = aline;
+ alloced_param=FALSE;
+
+ /* line with # in the first non-blank column is a comment! */
+ while(*line && ISSPACE(*line))
+ line++;
+
+ switch(*line) {
+ case '#':
+ case '/':
+ case '\r':
+ case '\n':
+ case '*':
+ case '\0':
+ Curl_safefree(aline);
+ continue;
+ }
+
+ /* the option keywords starts here */
+ option = line;
+ while(*line && !ISSPACE(*line) && !ISSEP(*line))
+ line++;
+ /* ... and has ended here */
+
+ if(*line)
+ *line++ = '\0'; /* zero terminate, we have a local copy of the data */
+
+#ifdef DEBUG_CONFIG
+ fprintf(stderr, "GOT: %s\n", option);
+#endif
+
+ /* pass spaces and separator(s) */
+ while(*line && (ISSPACE(*line) || ISSEP(*line)))
+ line++;
+
+ /* the parameter starts here (unless quoted) */
+ if(*line == '\"') {
+ /* quoted parameter, do the quote dance */
+ line++;
+ param = malloc(strlen(line) + 1); /* parameter */
+ if(!param) {
+ /* out of memory */
+ Curl_safefree(aline);
+ rc = 1;
+ break;
+ }
+ alloced_param = TRUE;
+ (void)unslashquote(line, param);
+ }
+ else {
+ param = line; /* parameter starts here */
+ while(*line && !ISSPACE(*line))
+ line++;
+ *line = '\0'; /* zero terminate */
+ }
+
+ if(param && !*param) {
+ /* do this so getparameter can check for required parameters.
+ Otherwise it always thinks there's a parameter. */
+ if(alloced_param)
+ Curl_safefree(param);
+ param = NULL;
+ }
+
+#ifdef DEBUG_CONFIG
+ fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
+#endif
+ res = getparameter(option, param, &usedarg, config);
+
+ if(param && *param && !usedarg)
+ /* we passed in a parameter that wasn't used! */
+ res = PARAM_GOT_EXTRA_PARAMETER;
+
+ if(res != PARAM_OK) {
+ /* the help request isn't really an error */
+ if(!strcmp(filename, "-")) {
+ filename = (char *)"<stdin>";
+ }
+ if(PARAM_HELP_REQUESTED != res) {
+ const char *reason = param2text(res);
+ warnf(config, "%s:%d: warning: '%s' %s\n",
+ filename, lineno, option, reason);
+ }
+ }
+
+ if(alloced_param)
+ Curl_safefree(param);
+
+ Curl_safefree(aline);
+ }
+ if(file != stdin)
+ fclose(file);
+ }
+ else
+ rc = 1; /* couldn't open the file */
+
+ return rc;
+}
+
+/*
+ * Copies the string from line to the buffer at param, unquoting
+ * backslash-quoted characters and NUL-terminating the output string.
+ * Stops at the first non-backslash-quoted double quote character or the
+ * end of the input string. param must be at least as long as the input
+ * string. Returns the pointer after the last handled input character.
+ */
+static const char *unslashquote(const char *line, char *param)
+{
+ while(*line && (*line != '\"')) {
+ if(*line == '\\') {
+ char out;
+ line++;
+
+ /* default is to output the letter after the backslash */
+ switch(out = *line) {
+ case '\0':
+ continue; /* this'll break out of the loop */
+ case 't':
+ out = '\t';
+ break;
+ case 'n':
+ out = '\n';
+ break;
+ case 'r':
+ out = '\r';
+ break;
+ case 'v':
+ out = '\v';
+ break;
+ }
+ *param++ = out;
+ line++;
+ }
+ else
+ *param++ = *line++;
+ }
+ *param = '\0'; /* always zero terminate */
+ return line;
+}
+
+/*
+ * Reads a line from the given file, ensuring is NUL terminated.
+ * The pointer must be freed by the caller.
+ * NULL is returned on an out of memory condition.
+ */
+static char *my_get_line(FILE *fp)
+{
+ char buf[4096];
+ char *nl = NULL;
+ char *retval = NULL;
+
+ do {
+ if(NULL == fgets(buf, sizeof(buf), fp))
+ break;
+ if(!retval) {
+ retval = strdup(buf);
+ if(!retval)
+ return NULL;
+ }
+ else {
+ char *ptr;
+ ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
+ if(!ptr) {
+ Curl_safefree(retval);
+ return NULL;
+ }
+ retval = ptr;
+ strcat(retval, buf);
+ }
+ nl = strchr(retval, '\n');
+ } while(!nl);
+
+ if(nl)
+ *nl = '\0';
+
+ return retval;
+}
+
diff --git a/src/tool_parsecfg.h b/src/tool_parsecfg.h
new file mode 100644
index 000000000..faa1f1924
--- /dev/null
+++ b/src/tool_parsecfg.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_TOOL_PARSECFG_H
+#define HEADER_CURL_TOOL_PARSECFG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+int parseconfig(const char *filename,
+ struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_PARSECFG_H */
+
diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h
new file mode 100644
index 000000000..50365273b
--- /dev/null
+++ b/src/tool_sdecls.h
@@ -0,0 +1,141 @@
+#ifndef HEADER_CURL_TOOL_SDECLS_H
+#define HEADER_CURL_TOOL_SDECLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+
+/*
+ * OutStruct variables keep track of information relative to curl's
+ * output writing, which may take place to a standard stream or a file.
+ *
+ * 'filename' member is either a pointer to a file name string or NULL
+ * when dealing with a standard stream.
+ *
+ * 'alloc_filename' member is TRUE when string pointed by 'filename' has been
+ * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE.
+ *
+ * 's_isreg' member is TRUE when output goes to a regular file, this also
+ * implies that output is 'seekable' and 'appendable' and also that member
+ * 'filename' points to file name's string. For any standard stream member
+ * 's_isreg' will be FALSE.
+ *
+ * 'fopened' member is TRUE when output goes to a regular file and it
+ * has been fopen'ed, requiring it to be closed later on. In any other
+ * case this is FALSE.
+ *
+ * 'stream' member is a pointer to a stream controlling object as returned
+ * from a 'fopen' call or a standard stream.
+ *
+ * 'config' member is a pointer to associated 'Configurable' struct.
+ *
+ * 'bytes' member represents amount written so far.
+ *
+ * 'init' member holds original file size or offset at which truncation is
+ * taking place. Always zero unless appending to a non-empty regular file.
+ */
+
+struct OutStruct {
+ char *filename;
+ bool alloc_filename;
+ bool s_isreg;
+ bool fopened;
+ FILE *stream;
+ struct Configurable *config;
+ curl_off_t bytes;
+ curl_off_t init;
+};
+
+
+/*
+ * InStruct variables keep track of information relative to curl's
+ * input reading, which may take place from stdin or from some file.
+ *
+ * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO
+ * or a file descriptor as returned from an 'open' call for some file.
+ *
+ * 'config' member is a pointer to associated 'Configurable' struct.
+ */
+
+struct InStruct {
+ int fd;
+ struct Configurable *config;
+};
+
+
+/*
+ * A linked list of these 'getout' nodes contain URL's to fetch,
+ * as well as information relative to where URL contents should
+ * be stored or which file should be uploaded.
+ */
+
+struct getout {
+ struct getout *next; /* next one */
+ char *url; /* the URL we deal with */
+ char *outfile; /* where to store the output */
+ char *infile; /* file to upload, if GETOUT_UPLOAD is set */
+ int flags; /* options - composed of GETOUT_* bits */
+};
+
+#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
+#define GETOUT_URL (1<<1) /* set when URL is deemed done */
+#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
+#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
+#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
+
+
+/*
+ * 'trace' enumeration represents curl's output look'n feel possibilities.
+ */
+
+typedef enum {
+ TRACE_NONE, /* no trace/verbose output at all */
+ TRACE_BIN, /* tcpdump inspired look */
+ TRACE_ASCII, /* like *BIN but without the hex output */
+ TRACE_PLAIN /* -v/--verbose type */
+} trace;
+
+
+/*
+ * 'HttpReq' enumeration represents HTTP request types.
+ */
+
+typedef enum {
+ HTTPREQ_UNSPEC, /* first in list */
+ HTTPREQ_GET,
+ HTTPREQ_HEAD,
+ HTTPREQ_POST,
+ HTTPREQ_SIMPLEPOST,
+ HTTPREQ_CUSTOM,
+ HTTPREQ_LAST /* last in list */
+} HttpReq;
+
+
+/*
+ * Complete struct declarations which have Configurable struct members,
+ * just in case this header is directly included in some source file.
+ */
+
+#include "tool_cfgable.h"
+
+#endif /* HEADER_CURL_TOOL_SDECLS_H */
+
diff --git a/src/tool_setopt.c b/src/tool_setopt.c
new file mode 100644
index 000000000..b636aab38
--- /dev/null
+++ b/src/tool_setopt.c
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_easysrc.h"
+#include "tool_setopt.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
+ const char *name, CURLoption tag, ...)
+{
+ va_list arg;
+ char *bufp;
+ char value[256];
+ bool remark = FALSE;
+ bool skip = FALSE;
+ CURLcode ret = CURLE_OK;
+
+ va_start(arg, tag);
+
+ if(tag < CURLOPTTYPE_OBJECTPOINT) {
+ long lval = va_arg(arg, long);
+ snprintf(value, sizeof(value), "%ldL", lval);
+ ret = curl_easy_setopt(curl, tag, lval);
+ if(!lval)
+ skip = TRUE;
+ }
+ else if(tag < CURLOPTTYPE_OFF_T) {
+ void *pval = va_arg(arg, void *);
+ unsigned char *ptr = (unsigned char *)pval;
+
+ /* function pointers are never printable */
+ if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
+ if(pval) {
+ strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */
+ remark = TRUE;
+ }
+ else
+ skip = TRUE;
+ }
+
+ else if(pval && str)
+ snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
+ else if(pval) {
+ strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */
+ remark = TRUE;
+ }
+ else
+ skip = TRUE;
+
+ ret = curl_easy_setopt(curl, tag, pval);
+
+ }
+ else {
+ curl_off_t oval = va_arg(arg, curl_off_t);
+ snprintf(value, sizeof(value),
+ "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
+ ret = curl_easy_setopt(curl, tag, oval);
+
+ if(!oval)
+ skip = TRUE;
+ }
+
+ va_end(arg);
+
+ if(config->libcurl && !skip && !ret) {
+ /* we only use this for real if --libcurl was used */
+
+ if(remark)
+ bufp = curlx_maprintf("%s set to a %s", name, value);
+ else
+ bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value);
+
+ if(!bufp)
+ ret = CURLE_OUT_OF_MEMORY;
+ else {
+ struct curl_slist *list =
+ curl_slist_append(remark?easysrc_remarks:easysrc, bufp);
+
+ curl_free(bufp);
+
+ if(!list) {
+ curl_slist_free_all(easysrc_remarks);
+ curl_slist_free_all(easysrc);
+ easysrc_remarks = NULL;
+ easysrc = NULL;
+ ret = CURLE_OUT_OF_MEMORY;
+ }
+ else if(remark)
+ easysrc_remarks = list;
+ else
+ easysrc = list;
+ }
+ }
+
+ return ret;
+}
+
diff --git a/src/tool_setopt.h b/src/tool_setopt.h
new file mode 100644
index 000000000..d01c9eb24
--- /dev/null
+++ b/src/tool_setopt.h
@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_TOOL_SETOPT_H
+#define HEADER_CURL_TOOL_SETOPT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
+ const char *name, CURLoption tag, ...);
+
+/*
+ * Macros used in operate()
+ */
+
+#define my_setopt(x,y,z) do { \
+ res = tool_setopt(x, FALSE, config, #y, y, z); \
+ if(res) \
+ goto show_error; \
+} WHILE_FALSE
+
+#define my_setopt_str(x,y,z) do { \
+ res = tool_setopt(x, TRUE, config, #y, y, z); \
+ if(res) \
+ goto show_error; \
+} WHILE_FALSE
+
+#define res_setopt(x,y,z) tool_setopt(x, FALSE, config, #y, y, z)
+
+#define res_setopt_str(x,y,z) tool_setopt(x, TRUE, config, #y, y, z)
+
+#endif /* HEADER_CURL_TOOL_SETOPT_H */
+
diff --git a/src/tool_sleep.c b/src/tool_sleep.c
new file mode 100644
index 000000000..08db8861b
--- /dev/null
+++ b/src/tool_sleep.c
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#elif defined(HAVE_POLL_H)
+# include <poll.h>
+#endif
+
+#ifdef MSDOS
+# include <dos.h>
+#endif
+
+#include "tool_sleep.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void tool_go_sleep(long ms)
+{
+#if defined(MSDOS)
+ delay(ms);
+#elif defined(WIN32)
+ Sleep(ms);
+#elif defined(HAVE_POLL_FINE)
+ poll((void *)0, 0, (int)ms);
+#else
+ struct timeval timeout;
+ timeout.tv_sec = ms / 1000L;
+ ms = ms % 1000L;
+ timeout.tv_usec = ms * 1000L;
+ select(0, NULL, NULL, NULL, &timeout);
+#endif
+}
+
diff --git a/src/tool_sleep.h b/src/tool_sleep.h
new file mode 100644
index 000000000..29655cedd
--- /dev/null
+++ b/src/tool_sleep.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_SLEEP_H
+#define HEADER_CURL_TOOL_SLEEP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+void tool_go_sleep(long ms);
+
+#endif /* HEADER_CURL_TOOL_SLEEP_H */
+
diff --git a/src/urlglob.c b/src/tool_urlglob.c
index 8dd77e136..f5c09a1e8 100644
--- a/src/urlglob.c
+++ b/src/tool_urlglob.c
@@ -19,28 +19,21 @@
* KIND, either express or implied.
*
***************************************************************************/
-
-/* client-local setup.h */
#include "setup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
#include <curl/curl.h>
#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
#include <curl/mprintf.h>
-#include "urlglob.h"
-#include "os-specific.h"
+#include "tool_urlglob.h"
+#include "tool_vms.h"
-#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
-#include "memdebug.h"
-#endif
+#include "memdebug.h" /* keep this as LAST include */
typedef enum {
GLOB_OK,
+ GLOB_NO_MEM,
GLOB_ERROR
} GlobCode;
@@ -61,11 +54,12 @@ static GlobCode glob_set(URLGlob *glob, char *pattern,
/* processes a set expression with the point behind the opening '{'
','-separated elements are collected until the next closing '}'
*/
+ URLPattern *pat;
+ GlobCode res;
bool done = FALSE;
char* buf = glob->glob_buffer;
- URLPattern *pat;
- pat = (URLPattern*)&glob->pattern[glob->size / 2];
+ pat = &glob->pattern[glob->size / 2];
/* patterns 0,1,2,... correspond to size=1,3,5,... */
pat->type = UPTSet;
pat->content.Set.size = 0;
@@ -90,22 +84,36 @@ static GlobCode glob_set(URLGlob *glob, char *pattern,
case ',':
case '}': /* set element completed */
*buf = '\0';
- if(pat->content.Set.elements)
- pat->content.Set.elements =
- realloc(pat->content.Set.elements,
- (pat->content.Set.size + 1) * sizeof(char*));
+ if(pat->content.Set.elements) {
+ char **new_arr = realloc(pat->content.Set.elements,
+ (pat->content.Set.size + 1) * sizeof(char*));
+ if(!new_arr) {
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ }
+ pat->content.Set.elements = new_arr;
+ }
else
- pat->content.Set.elements =
- malloc((pat->content.Set.size + 1) * sizeof(char*));
+ pat->content.Set.elements = malloc(sizeof(char*));
if(!pat->content.Set.elements) {
- snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory");
- return GLOB_ERROR;
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
}
pat->content.Set.elements[pat->content.Set.size] =
strdup(glob->glob_buffer);
if(!pat->content.Set.elements[pat->content.Set.size]) {
- snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory");
- return GLOB_ERROR;
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
}
++pat->content.Set.size;
@@ -114,8 +122,17 @@ static GlobCode glob_set(URLGlob *glob, char *pattern,
int wordamount;
/* always check for a literal (may be "") between patterns */
- if(GLOB_ERROR == glob_word(glob, ++pattern, ++pos, &wordamount))
- return GLOB_ERROR;
+ res = glob_word(glob, ++pattern, ++pos, &wordamount);
+ if(res) {
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ return res;
+ }
+
*amount = pat->content.Set.size * wordamount;
done = TRUE;
@@ -157,22 +174,26 @@ static GlobCode glob_range(URLGlob *glob, char *pattern,
*/
URLPattern *pat;
char *c;
- int wordamount=1;
char sep;
char sep2;
int step;
int rc;
+ GlobCode res;
+ int wordamount = 1;
- pat = (URLPattern*)&glob->pattern[glob->size / 2];
+ pat = &glob->pattern[glob->size / 2];
/* patterns 0,1,2,... correspond to size=1,3,5,... */
++glob->size;
- if(ISALPHA(*pattern)) { /* character range detected */
+ if(ISALPHA(*pattern)) {
+ /* character range detected */
char min_c;
char max_c;
pat->type = UPTCharRange;
+
rc = sscanf(pattern, "%c-%c%c%d%c", &min_c, &max_c, &sep, &step, &sep2);
+
if((rc < 3) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a'))) {
/* the pattern is not well-formed */
snprintf(glob->errormsg, sizeof(glob->errormsg),
@@ -190,12 +211,13 @@ static GlobCode glob_range(URLGlob *glob, char *pattern,
/* if there was a ":[num]" thing, use that as step or else use 1 */
pat->content.CharRange.step =
- ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1;
+ ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
pat->content.CharRange.max_c = max_c;
}
- else if(ISDIGIT(*pattern)) { /* numeric range detected */
+ else if(ISDIGIT(*pattern)) {
+ /* numeric range detected */
int min_n;
int max_n;
@@ -210,14 +232,15 @@ static GlobCode glob_range(URLGlob *glob, char *pattern,
"error: bad range specification after pos %zu\n", pos);
return GLOB_ERROR;
}
- pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
+ pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
pat->content.NumRange.max_n = max_n;
/* if there was a ":[num]" thing, use that as step or else use 1 */
pat->content.NumRange.step =
- ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1;
+ ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
- if(*pattern == '0') { /* leading zero specified */
+ if(*pattern == '0') {
+ /* leading zero specified */
c = pattern;
while(ISDIGIT(*c)) {
c++;
@@ -225,7 +248,6 @@ static GlobCode glob_range(URLGlob *glob, char *pattern,
instances of this pattern */
}
}
-
}
else {
snprintf(glob->errormsg, sizeof(glob->errormsg),
@@ -243,18 +265,22 @@ static GlobCode glob_range(URLGlob *glob, char *pattern,
/* always check for a literal (may be "") between patterns */
- if(GLOB_ERROR == glob_word(glob, c, pos + (c - pattern), &wordamount))
+ res = glob_word(glob, c, pos + (c - pattern), &wordamount);
+ if(res == GLOB_ERROR) {
wordamount = 1;
+ res = GLOB_OK;
+ }
- if(pat->type == UPTCharRange)
- *amount = (pat->content.CharRange.max_c -
- pat->content.CharRange.min_c + 1) *
- wordamount;
- else
- *amount = (pat->content.NumRange.max_n -
- pat->content.NumRange.min_n + 1) * wordamount;
+ if(!res) {
+ if(pat->type == UPTCharRange)
+ *amount = wordamount * (pat->content.CharRange.max_c -
+ pat->content.CharRange.min_c + 1);
+ else
+ *amount = wordamount * (pat->content.NumRange.max_n -
+ pat->content.NumRange.min_n + 1);
+ }
- return GLOB_OK;
+ return res; /* GLOB_OK or GLOB_NO_MEM */
}
static GlobCode glob_word(URLGlob *glob, char *pattern,
@@ -285,20 +311,23 @@ static GlobCode glob_word(URLGlob *glob, char *pattern,
++pattern;
++pos;
}
- *buf++ = *pattern++; /* copy character to literal */
+ *buf++ = *pattern++; /* copy character to literal */
++pos;
}
*buf = '\0';
litindex = glob->size / 2;
/* literals 0,1,2,... correspond to size=0,2,4,... */
glob->literal[litindex] = strdup(glob->glob_buffer);
- if(!glob->literal[litindex])
- return GLOB_ERROR;
+ if(!glob->literal[litindex]) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
+ }
++glob->size;
switch (*pattern) {
case '\0':
- break; /* singular URL processed */
+ /* singular URL processed */
+ break;
case '{':
/* process set pattern */
@@ -307,15 +336,14 @@ static GlobCode glob_word(URLGlob *glob, char *pattern,
case '[':
/* process range pattern */
- res= glob_range(glob, ++pattern, ++pos, amount);
+ res = glob_range(glob, ++pattern, ++pos, amount);
break;
}
- if(GLOB_OK != res)
- /* free that strdup'ed string again */
- free(glob->literal[litindex]);
+ if(res)
+ Curl_safefree(glob->literal[litindex]);
- return res; /* something got wrong */
+ return res;
}
int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
@@ -326,35 +354,40 @@ int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
*/
URLGlob *glob_expand;
int amount;
- char *glob_buffer = malloc(strlen(url)+1);
+ char *glob_buffer;
+ GlobCode res;
*glob = NULL;
- if(NULL == glob_buffer)
+
+ glob_buffer = malloc(strlen(url) + 1);
+ if(!glob_buffer)
return CURLE_OUT_OF_MEMORY;
glob_expand = calloc(1, sizeof(URLGlob));
- if(NULL == glob_expand) {
- free(glob_buffer);
+ if(!glob_expand) {
+ Curl_safefree(glob_buffer);
return CURLE_OUT_OF_MEMORY;
}
glob_expand->size = 0;
glob_expand->urllen = strlen(url);
glob_expand->glob_buffer = glob_buffer;
- glob_expand->beenhere=0;
- if(GLOB_OK == glob_word(glob_expand, url, 1, &amount))
+ glob_expand->beenhere = 0;
+
+ res = glob_word(glob_expand, url, 1, &amount);
+ if(!res)
*urlnum = amount;
else {
if(error && glob_expand->errormsg[0]) {
/* send error description to the error-stream */
fprintf(error, "curl: (%d) [globbing] %s",
- CURLE_URL_MALFORMAT, glob_expand->errormsg);
+ (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT,
+ glob_expand->errormsg);
}
/* it failed, we cleanup */
- free(glob_buffer);
- free(glob_expand);
- glob_expand = NULL;
+ Curl_safefree(glob_buffer);
+ Curl_safefree(glob_expand);
*urlnum = 1;
- return CURLE_URL_MALFORMAT;
+ return (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
}
*glob = glob_expand;
@@ -368,7 +401,7 @@ void glob_cleanup(URLGlob* glob)
for(i = glob->size - 1; i < glob->size; --i) {
if(!(i & 1)) { /* even indexes contain literals */
- free(glob->literal[i/2]);
+ Curl_safefree(glob->literal[i/2]);
}
else { /* odd indexes contain sets or ranges */
if((glob->pattern[i/2].type == UPTSet) &&
@@ -376,26 +409,27 @@ void glob_cleanup(URLGlob* glob)
for(elem = glob->pattern[i/2].content.Set.size - 1;
elem >= 0;
--elem) {
- if(glob->pattern[i/2].content.Set.elements[elem])
- free(glob->pattern[i/2].content.Set.elements[elem]);
+ Curl_safefree(glob->pattern[i/2].content.Set.elements[elem]);
}
- free(glob->pattern[i/2].content.Set.elements);
+ Curl_safefree(glob->pattern[i/2].content.Set.elements);
}
}
}
- free(glob->glob_buffer);
- free(glob);
+ Curl_safefree(glob->glob_buffer);
+ Curl_safefree(glob);
}
-char *glob_next_url(URLGlob *glob)
+int glob_next_url(char **globbed, URLGlob *glob)
{
- char *buf = glob->glob_buffer;
URLPattern *pat;
char *lit;
size_t i;
size_t j;
- size_t buflen = glob->urllen+1;
size_t len;
+ size_t buflen = glob->urllen + 1;
+ char *buf = glob->glob_buffer;
+
+ *globbed = NULL;
if(!glob->beenhere)
glob->beenhere = 1;
@@ -404,12 +438,13 @@ char *glob_next_url(URLGlob *glob)
/* implement a counter over the index ranges of all patterns,
starting with the rightmost pattern */
- for(i = glob->size / 2 - 1; carry && i < glob->size; --i) {
+ for(i = glob->size / 2 - 1; carry && (i < glob->size); --i) {
carry = FALSE;
pat = &glob->pattern[i];
switch (pat->type) {
case UPTSet:
- if(++pat->content.Set.ptr_s == pat->content.Set.size) {
+ if((pat->content.Set.elements) &&
+ (++pat->content.Set.ptr_s == pat->content.Set.size)) {
pat->content.Set.ptr_s = 0;
carry = TRUE;
}
@@ -431,11 +466,13 @@ char *glob_next_url(URLGlob *glob)
break;
default:
printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
- exit (CURLE_FAILED_INIT);
+ return CURLE_FAILED_INIT;
}
}
- if(carry) /* first pattern ptr has run into overflow, done! */
- return NULL;
+ if(carry) { /* first pattern ptr has run into overflow, done! */
+ /* TODO: verify if this should actally return CURLE_OK. */
+ return CURLE_OK; /* CURLE_OK to match previous behavior */
+ }
}
for(j = 0; j < glob->size; ++j) {
@@ -449,11 +486,13 @@ char *glob_next_url(URLGlob *glob)
pat = &glob->pattern[j/2];
switch(pat->type) {
case UPTSet:
- len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
- snprintf(buf, buflen, "%s",
- pat->content.Set.elements[pat->content.Set.ptr_s]);
- buf += len;
- buflen -= len;
+ if(pat->content.Set.elements) {
+ len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
+ snprintf(buf, buflen, "%s",
+ pat->content.Set.elements[pat->content.Set.ptr_s]);
+ buf += len;
+ buflen -= len;
+ }
break;
case UPTCharRange:
*buf++ = pat->content.CharRange.ptr_c;
@@ -467,52 +506,62 @@ char *glob_next_url(URLGlob *glob)
break;
default:
printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
- exit (CURLE_FAILED_INIT);
+ return CURLE_FAILED_INIT;
}
}
}
*buf = '\0';
- return strdup(glob->glob_buffer);
+
+ *globbed = strdup(glob->glob_buffer);
+ if(!*globbed)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
}
-char *glob_match_url(char *filename, URLGlob *glob)
+int glob_match_url(char **result, char *filename, URLGlob *glob)
{
char *target;
size_t allocsize;
- size_t stringlen=0;
char numbuf[18];
char *appendthis = NULL;
size_t appendlen = 0;
+ size_t stringlen = 0;
+
+ *result = NULL;
/* We cannot use the glob_buffer for storage here since the filename may
* be longer than the URL we use. We allocate a good start size, then
* we need to realloc in case of need.
*/
- allocsize=strlen(filename)+1; /* make it at least one byte to store the
- trailing zero */
+ allocsize = strlen(filename) + 1; /* make it at least one byte to store the
+ trailing zero */
target = malloc(allocsize);
- if(NULL == target)
- return NULL; /* major failure */
+ if(!target)
+ return CURLE_OUT_OF_MEMORY;
while(*filename) {
if(*filename == '#' && ISDIGIT(filename[1])) {
unsigned long i;
char *ptr = filename;
unsigned long num = strtoul(&filename[1], &filename, 10);
- i = num-1;
+ i = num - 1UL;
if(num && (i <= glob->size / 2)) {
URLPattern pat = glob->pattern[i];
switch (pat.type) {
case UPTSet:
- appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
- appendlen = strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
+ if(pat.content.Set.elements) {
+ appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
+ appendlen =
+ strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
+ }
break;
case UPTCharRange:
- numbuf[0]=pat.content.CharRange.ptr_c;
- numbuf[1]=0;
- appendthis=numbuf;
- appendlen=1;
+ numbuf[0] = pat.content.CharRange.ptr_c;
+ numbuf[1] = 0;
+ appendthis = numbuf;
+ appendlen = 1;
break;
case UPTNumRange:
snprintf(numbuf, sizeof(numbuf), "%0*d",
@@ -524,36 +573,38 @@ char *glob_match_url(char *filename, URLGlob *glob)
default:
printf("internal error: invalid pattern type (%d)\n",
(int)pat.type);
- free(target);
- return NULL;
+ Curl_safefree(target);
+ return CURLE_FAILED_INIT;
}
}
else {
/* #[num] out of range, use the #[num] in the output */
filename = ptr;
- appendthis=filename++;
- appendlen=1;
+ appendthis = filename++;
+ appendlen = 1;
}
}
else {
- appendthis=filename++;
- appendlen=1;
+ appendthis = filename++;
+ appendlen = 1;
}
if(appendlen + stringlen >= allocsize) {
char *newstr;
/* we append a single byte to allow for the trailing byte to be appended
at the end of this function outside the while() loop */
- allocsize = (appendlen + stringlen)*2;
- newstr=realloc(target, allocsize + 1);
- if(NULL ==newstr) {
- free(target);
- return NULL;
+ allocsize = (appendlen + stringlen) * 2;
+ newstr = realloc(target, allocsize + 1);
+ if(!newstr) {
+ Curl_safefree(target);
+ return CURLE_OUT_OF_MEMORY;
}
- target=newstr;
+ target = newstr;
}
memcpy(&target[stringlen], appendthis, appendlen);
stringlen += appendlen;
}
target[stringlen]= '\0';
- return target;
+ *result = target;
+ return CURLE_OK;
}
+
diff --git a/src/urlglob.h b/src/tool_urlglob.h
index a5b789e6b..18281bf61 100644
--- a/src/urlglob.h
+++ b/src/tool_urlglob.h
@@ -1,5 +1,5 @@
-#ifndef __URLGLOB_H
-#define __URLGLOB_H
+#ifndef HEADER_CURL_TOOL_URLGLOB_H
+#define HEADER_CURL_TOOL_URLGLOB_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,8 +21,10 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
+
typedef enum {
- UPTSet=1,
+ UPTSet = 1,
UPTCharRange,
UPTNumRange
} URLPatternType;
@@ -36,12 +38,14 @@ typedef struct {
short ptr_s;
} Set;
struct {
- char min_c, max_c;
+ char min_c;
+ char max_c;
char ptr_c;
int step;
} CharRange;
struct {
- int min_n, max_n;
+ int min_n;
+ int max_n;
short padlength;
int ptr_n;
int step;
@@ -50,7 +54,7 @@ typedef struct {
} URLPattern;
typedef struct {
- char* literal[10];
+ char *literal[10];
URLPattern pattern[9];
size_t size;
size_t urllen;
@@ -60,8 +64,9 @@ typedef struct {
} URLGlob;
int glob_url(URLGlob**, char*, int *, FILE *);
-char* glob_next_url(URLGlob*);
-char* glob_match_url(char*, URLGlob *);
+int glob_next_url(char **, URLGlob *);
+int glob_match_url(char **, char*, URLGlob *);
void glob_cleanup(URLGlob* glob);
-#endif
+#endif /* HEADER_CURL_TOOL_URLGLOB_H */
+
diff --git a/src/curlutil.c b/src/tool_util.c
index bca2db7aa..79c998295 100644
--- a/src/curlutil.c
+++ b/src/tool_util.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -19,14 +19,15 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include "setup.h"
-#include "curlutil.h"
+#include "tool_util.h"
+
+#include "memdebug.h" /* keep this as LAST include */
#if defined(WIN32) && !defined(MSDOS)
-struct timeval cutil_tvnow(void)
+struct timeval tool_tvnow(void)
{
/*
** GetTickCount() is available on _all_ Windows versions from W95 up
@@ -42,7 +43,7 @@ struct timeval cutil_tvnow(void)
#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
-struct timeval cutil_tvnow(void)
+struct timeval tool_tvnow(void)
{
/*
** clock_gettime() is granted to be increased monotonically when the
@@ -76,7 +77,7 @@ struct timeval cutil_tvnow(void)
#elif defined(HAVE_GETTIMEOFDAY)
-struct timeval cutil_tvnow(void)
+struct timeval tool_tvnow(void)
{
/*
** gettimeofday() is not granted to be increased monotonically, due to
@@ -90,7 +91,7 @@ struct timeval cutil_tvnow(void)
#else
-struct timeval cutil_tvnow(void)
+struct timeval tool_tvnow(void)
{
/*
** time() returns the value of time in seconds since the Epoch.
@@ -109,25 +110,25 @@ struct timeval cutil_tvnow(void)
*
* Returns: the time difference in number of milliseconds.
*/
-long cutil_tvdiff(struct timeval newer, struct timeval older)
+long tool_tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*1000+
(newer.tv_usec-older.tv_usec)/1000;
}
/*
- * Same as cutil_tvdiff but with full usec resolution.
+ * Same as tool_tvdiff but with full usec resolution.
*
* Returns: the time difference in seconds with subsecond resolution.
*/
-double cutil_tvdiff_secs(struct timeval newer, struct timeval older)
+double tool_tvdiff_secs(struct timeval newer, struct timeval older)
{
return (double)(newer.tv_sec-older.tv_sec)+
(double)(newer.tv_usec-older.tv_usec)/1000000.0;
}
/* return the number of seconds in the given input timeval struct */
-long cutil_tvlong(struct timeval t1)
+long tool_tvlong(struct timeval t1)
{
return t1.tv_sec;
}
diff --git a/src/curlutil.h b/src/tool_util.h
index a993a775e..7c2a2978a 100644
--- a/src/curlutil.h
+++ b/src/tool_util.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_SRC_UTIL_H
-#define __CURL_SRC_UTIL_H
+#ifndef HEADER_CURL_TOOL_UTIL_H
+#define HEADER_CURL_TOOL_UTIL_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,11 +21,9 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include "setup.h"
-
-struct timeval cutil_tvnow(void);
+struct timeval tool_tvnow(void);
/*
* Make sure that the first argument (t1) is the more recent time and t2 is
@@ -33,17 +31,26 @@ struct timeval cutil_tvnow(void);
*
* Returns: the time difference in number of milliseconds.
*/
-long cutil_tvdiff(struct timeval t1, struct timeval t2);
+long tool_tvdiff(struct timeval t1, struct timeval t2);
/*
- * Same as cutil_tvdiff but with full usec resolution.
+ * Same as tool_tvdiff but with full usec resolution.
*
* Returns: the time difference in seconds with subsecond resolution.
*/
-double cutil_tvdiff_secs(struct timeval t1, struct timeval t2);
+double tool_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+long tool_tvlong(struct timeval t1);
-long cutil_tvlong(struct timeval t1);
+#undef tvnow
+#undef tvdiff
+#undef tvdiff_secs
+#undef tvlong
+#define tvnow() tool_tvnow()
+#define tvdiff(a,b) tool_tvdiff((a), (b))
+#define tvdiff_secs(a,b) tool_tvdiff_secs((a), (b))
+#define tvlong(a) tool_tvlong((a))
-#endif /* __CURL_SRC_UTIL_H */
+#endif /* HEADER_CURL_TOOL_UTIL_H */
diff --git a/src/version.h b/src/tool_version.h
index ce83b8579..569526bfe 100644
--- a/src/version.h
+++ b/src/tool_version.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_VERSION_H
-#define HEADER_CURL_VERSION_H
+#ifndef HEADER_CURL_TOOL_VERSION_H
+#define HEADER_CURL_TOOL_VERSION_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,7 +21,6 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include <curl/curlver.h>
#define CURL_NAME "curl"
@@ -32,4 +31,4 @@
#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "
-#endif /* HEADER_CURL_VERSION_H */
+#endif /* HEADER_CURL_TOOL_VERSION_H */
diff --git a/src/os-specific.c b/src/tool_vms.c
index ac07c4cec..b1ecfe551 100644
--- a/src/os-specific.c
+++ b/src/tool_vms.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,20 +21,22 @@
***************************************************************************/
#include "setup.h"
+#ifdef __VMS
+
+#if defined(__DECC) && !defined(__VAX) && \
+ defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
+#include <unixlib.h>
+#endif
+
#include <curl/curl.h>
#define ENABLE_CURLX_PRINTF
#include "curlx.h"
-#include "os-specific.h"
-
-#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
-# include "memdebug.h"
-#endif
-
-#ifdef __VMS
-
#include "curlmsg_vms.h"
+#include "tool_vms.h"
+
+#include "memdebug.h" /* keep this as LAST include */
void decc$__posix_exit(int __status);
void decc$exit(int __status);
@@ -121,8 +123,6 @@ void vms_special_exit(int code, int vms_show)
* requiring the user to define the corresponding logical names.
*/
-#include <unixlib.h>
-
/* Structure to hold a DECC$* feature name and its desired value. */
typedef struct {
char *name;
diff --git a/src/os-specific.h b/src/tool_vms.h
index 93cac743c..56db34ba1 100644
--- a/src/os-specific.h
+++ b/src/tool_vms.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_OS_SPECIFIC_H
-#define HEADER_CURL_OS_SPECIFIC_H
+#ifndef HEADER_CURL_TOOL_VMS_H
+#define HEADER_CURL_TOOL_VMS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,6 +21,7 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
#ifdef __VMS
@@ -35,4 +36,5 @@ void vms_special_exit(int code, int vms_show);
#endif /* __VMS */
-#endif /* HEADER_CURL_OS_SPECIFIC_H */
+#endif /* HEADER_CURL_TOOL_VMS_H */
+
diff --git a/src/writeenv.c b/src/tool_writeenv.c
index e3edbec75..232ab697c 100644
--- a/src/writeenv.c
+++ b/src/tool_writeenv.c
@@ -19,24 +19,22 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include "setup.h"
#ifdef USE_ENVIRONMENT
-#include <curl/curl.h>
-#include "writeenv.h"
-
#ifdef __riscos__
-#include <kernel.h>
+# include <kernel.h>
#endif
+#include <curl/curl.h>
+
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
-#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
-#include "memdebug.h"
-#endif
+#include "tool_writeenv.h"
+
+#include "memdebug.h" /* keep this as LAST include */
static const struct
{
diff --git a/src/tool_writeenv.h b/src/tool_writeenv.h
new file mode 100644
index 000000000..74fdc97d9
--- /dev/null
+++ b/src/tool_writeenv.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_WRITEENV_H
+#define HEADER_CURL_TOOL_WRITEENV_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef USE_ENVIRONMENT
+
+void ourWriteEnv(CURL *curl);
+
+#else
+# define ourWriteEnv(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_WRITEENV_H */
+
diff --git a/src/writeout.c b/src/tool_writeout.c
index e044a9d8e..1ea1c9881 100644
--- a/src/writeout.c
+++ b/src/tool_writeout.c
@@ -19,25 +19,16 @@
* KIND, either express or implied.
*
***************************************************************************/
-
#include "setup.h"
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
#include <curl/curl.h>
#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
#include <curl/mprintf.h>
-#include "writeout.h"
+#include "tool_writeout.h"
+
+#include "memdebug.h" /* keep this as LAST include */
typedef enum {
VAR_NONE, /* must be the first */
@@ -102,7 +93,7 @@ static const struct variable replacements[]={
void ourWriteOut(CURL *curl, const char *writeinfo)
{
FILE *stream = stdout;
- const char *ptr=writeinfo;
+ const char *ptr = writeinfo;
char *stringp;
long longinfo;
double doubleinfo;
@@ -112,7 +103,7 @@ void ourWriteOut(CURL *curl, const char *writeinfo)
if('%' == ptr[1]) {
/* an escaped %-letter */
fputc('%', stream);
- ptr+=2;
+ ptr += 2;
}
else {
/* this is meant as a variable to output */
@@ -121,10 +112,10 @@ void ourWriteOut(CURL *curl, const char *writeinfo)
int i;
if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) {
bool match = FALSE;
- ptr+=2; /* pass the % and the { */
- keepit=*end;
- *end=0; /* zero terminate */
- for(i=0; replacements[i].name; i++) {
+ ptr += 2; /* pass the % and the { */
+ keepit = *end;
+ *end = 0; /* zero terminate */
+ for(i = 0; replacements[i].name; i++) {
if(curl_strequal(ptr, replacements[i].name)) {
match = TRUE;
switch(replacements[i].id) {
@@ -257,17 +248,17 @@ void ourWriteOut(CURL *curl, const char *writeinfo)
break;
}
}
- if(FALSE == match) {
+ if(!match) {
fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr);
}
- ptr=end+1; /* pass the end */
+ ptr = end + 1; /* pass the end */
*end = keepit;
}
else {
/* illegal syntax, then just output the characters that are used */
fputc('%', stream);
fputc(ptr[1], stream);
- ptr+=2;
+ ptr += 2;
}
}
}
@@ -288,7 +279,7 @@ void ourWriteOut(CURL *curl, const char *writeinfo)
fputc(ptr[1], stream);
break;
}
- ptr+=2;
+ ptr += 2;
}
else {
fputc(*ptr, stream);
diff --git a/src/writeout.h b/src/tool_writeout.h
index 1b221026e..815cfcfff 100644
--- a/src/writeout.h
+++ b/src/tool_writeout.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_WRITEOUT_H
-#define HEADER_CURL_WRITEOUT_H
+#ifndef HEADER_CURL_TOOL_WRITEOUT_H
+#define HEADER_CURL_TOOL_WRITEOUT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,7 +21,8 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
void ourWriteOut(CURL *curl, const char *out);
-#endif /* HEADER_CURL_WRITEOUT_H */
+#endif /* HEADER_CURL_TOOL_WRITEOUT_H */
diff --git a/src/xattr.c b/src/tool_xattr.c
index 61d6697bb..1f3883fa6 100644
--- a/src/xattr.c
+++ b/src/tool_xattr.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010, 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -19,16 +19,19 @@
* KIND, either express or implied.
*
***************************************************************************/
-
-/* client-local setup.h */
#include "setup.h"
+
+#ifdef HAVE_FSETXATTR
+# include <sys/xattr.h> /* header from libc, not from libattr */
+#endif
+
#include <curl/curl.h>
-#include "xattr.h"
+
+#include "tool_xattr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
#ifdef HAVE_FSETXATTR
-#include <sys/types.h>
-#include <string.h>
-#include <sys/xattr.h> /* include header from libc, not from libattr */
/* mapping table of curl metadata to extended attribute names */
static const struct xattr_mapping {
@@ -39,8 +42,8 @@ static const struct xattr_mapping {
* http://freedesktop.org/wiki/CommonExtendedAttributes
*/
{ "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL },
- { "user.mime_type", CURLINFO_CONTENT_TYPE },
- { NULL, CURLINFO_NONE } /* last element, abort loop here */
+ { "user.mime_type", CURLINFO_CONTENT_TYPE },
+ { NULL, CURLINFO_NONE } /* last element, abort loop here */
};
/* store metadata from the curl request alongside the downloaded
@@ -56,9 +59,9 @@ int fwrite_xattr(CURL *curl, int fd)
CURLcode rc = curl_easy_getinfo(curl, mappings[i].info, &value);
if(rc == CURLE_OK && value) {
#ifdef HAVE_FSETXATTR_6
- err = fsetxattr( fd, mappings[i].attr, value, strlen(value), 0, 0 );
+ err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0);
#elif defined(HAVE_FSETXATTR_5)
- err = fsetxattr( fd, mappings[i].attr, value, strlen(value), 0 );
+ err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0);
#endif
}
i++;
diff --git a/src/xattr.h b/src/tool_xattr.h
index fea98f188..14c8c944b 100644
--- a/src/xattr.h
+++ b/src/tool_xattr.h
@@ -1,5 +1,5 @@
-#ifndef __XATTR_H
-#define __XATTR_H
+#ifndef HEADER_CURL_TOOL_XATTR_H
+#define HEADER_CURL_TOOL_XATTR_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,6 +21,8 @@
* KIND, either express or implied.
*
***************************************************************************/
+#include "setup.h"
+
int fwrite_xattr(CURL *curl, int fd);
-#endif
+#endif /* HEADER_CURL_TOOL_XATTR_H */
diff --git a/src/vc6curlsrc.dsp b/src/vc6curlsrc.dsp
index 1fb1d7bf9..4711703bc 100644
--- a/src/vc6curlsrc.dsp
+++ b/src/vc6curlsrc.dsp
@@ -139,83 +139,179 @@ LINK32=link.exe
# PROP Default_Filter ""
# Begin Source File
-SOURCE=.\curlutil.c
+SOURCE=.\hugehelp.c
# End Source File
# Begin Source File
-SOURCE=.\getpass.c
+SOURCE=..\lib\nonblock.c
# End Source File
# Begin Source File
-SOURCE=.\homedir.c
+SOURCE=..\lib\rawstr.c
# End Source File
# Begin Source File
-SOURCE=.\hugehelp.c
+SOURCE=..\lib\strtoofft.c
# End Source File
# Begin Source File
-SOURCE=.\main.c
+SOURCE=.\tool_binmode.c
# End Source File
# Begin Source File
-SOURCE=.\os-specific.c
+SOURCE=.\tool_bname.c
# End Source File
# Begin Source File
-SOURCE=..\lib\nonblock.c
+SOURCE=.\tool_cb_dbg.c
# End Source File
# Begin Source File
-SOURCE=..\lib\rawstr.c
+SOURCE=.\tool_cb_hdr.c
# End Source File
# Begin Source File
-SOURCE=..\lib\strtoofft.c
+SOURCE=.\tool_cb_prg.c
# End Source File
# Begin Source File
-SOURCE=.\urlglob.c
+SOURCE=.\tool_cb_rea.c
# End Source File
# Begin Source File
-SOURCE=.\writeenv.c
+SOURCE=.\tool_cb_see.c
# End Source File
# Begin Source File
-SOURCE=.\writeout.c
+SOURCE=.\tool_cb_skt.c
# End Source File
# Begin Source File
-SOURCE=.\xattr.c
+SOURCE=.\tool_cb_wrt.c
# End Source File
-# End Group
-# Begin Group "Header Files"
+# Begin Source File
-# PROP Default_Filter ""
+SOURCE=.\tool_cfgable.c
+# End Source File
# Begin Source File
-SOURCE=".\config-win32.h"
+SOURCE=.\tool_convert.c
# End Source File
# Begin Source File
-SOURCE=.\curlutil.h
+SOURCE=.\tool_dirhie.c
# End Source File
# Begin Source File
-SOURCE=.\getpass.h
+SOURCE=.\tool_doswin.c
# End Source File
# Begin Source File
-SOURCE=.\homedir.h
+SOURCE=.\tool_easysrc.c
# End Source File
# Begin Source File
-SOURCE=.\hugehelp.h
+SOURCE=.\tool_formparse.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.c
# End Source File
# Begin Source File
-SOURCE=.\os-specific.h
+SOURCE=.\tool_panykey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_vms.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeenv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_xattr.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=".\config-win32.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\hugehelp.h
# End Source File
# Begin Source File
@@ -235,23 +331,159 @@ SOURCE=..\lib\strtoofft.h
# End Source File
# Begin Source File
-SOURCE=.\urlglob.h
+SOURCE=.\tool_binmode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_bname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_hdr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_prg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_rea.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_see.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_skt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_wrt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cfgable.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_convert.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_dirhie.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_doswin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_easysrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_formparse.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_panykey.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sdecls.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_version.h
# End Source File
# Begin Source File
-SOURCE=.\version.h
+SOURCE=.\tool_vms.h
# End Source File
# Begin Source File
-SOURCE=.\writeenv.h
+SOURCE=.\tool_writeenv.h
# End Source File
# Begin Source File
-SOURCE=.\writeout.h
+SOURCE=.\tool_writeout.h
# End Source File
# Begin Source File
-SOURCE=.\xattr.h
+SOURCE=.\tool_xattr.h
# End Source File
# End Group
# Begin Group "Resource Files"