diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 2 | ||||
-rw-r--r-- | src/Makefile.Watcom | 2 | ||||
-rw-r--r-- | src/Makefile.am | 13 | ||||
-rw-r--r-- | src/Makefile.inc | 83 | ||||
-rw-r--r-- | src/Makefile.m32 | 90 | ||||
-rw-r--r-- | src/Makefile.netware | 60 | ||||
-rw-r--r-- | src/Makefile.vc6 | 277 | ||||
-rw-r--r-- | src/config-amigaos.h | 3 | ||||
-rw-r--r-- | src/config-mac.h | 1 | ||||
-rw-r--r-- | src/config-riscos.h | 3 | ||||
-rw-r--r-- | src/config-win32.h | 439 | ||||
-rw-r--r-- | src/curl.rc | 2 | ||||
-rw-r--r-- | src/hugehelp.c.cvs | 3 | ||||
-rw-r--r-- | src/hugehelp.h | 4 | ||||
-rw-r--r-- | src/main.c | 6207 | ||||
-rw-r--r-- | src/mkhelp.pl | 21 | ||||
-rw-r--r-- | src/setup.h | 70 | ||||
-rw-r--r-- | src/tool_binmode.c | 52 | ||||
-rw-r--r-- | src/tool_binmode.h | 37 | ||||
-rw-r--r-- | src/tool_bname.c | 50 | ||||
-rw-r--r-- | src/tool_bname.h | 35 | ||||
-rw-r--r-- | src/tool_cb_dbg.c | 275 | ||||
-rw-r--r-- | src/tool_cb_dbg.h | 35 | ||||
-rw-r--r-- | src/tool_cb_hdr.c | 207 | ||||
-rw-r--r-- | src/tool_cb_hdr.h | 33 | ||||
-rw-r--r-- | src/tool_cb_prg.c | 146 | ||||
-rw-r--r-- | src/tool_cb_prg.h | 49 | ||||
-rw-r--r-- | src/tool_cb_rea.c | 61 | ||||
-rw-r--r-- | src/tool_cb_rea.h | 33 | ||||
-rw-r--r-- | src/tool_cb_see.c | 129 | ||||
-rw-r--r-- | src/tool_cb_see.h | 45 | ||||
-rw-r--r-- | src/tool_cb_skt.c | 97 | ||||
-rw-r--r-- | src/tool_cb_skt.h | 35 | ||||
-rw-r--r-- | src/tool_cb_wrt.c | 146 | ||||
-rw-r--r-- | src/tool_cb_wrt.h | 33 | ||||
-rw-r--r-- | src/tool_cfgable.c | 131 | ||||
-rw-r--r-- | src/tool_cfgable.h | 204 | ||||
-rw-r--r-- | src/tool_convert.c | 152 | ||||
-rw-r--r-- | src/tool_convert.h | 45 | ||||
-rw-r--r-- | src/tool_dirhie.c | 151 | ||||
-rw-r--r-- | src/tool_dirhie.h | 29 | ||||
-rw-r--r-- | src/tool_doswin.c | 300 | ||||
-rw-r--r-- | src/tool_doswin.h | 45 | ||||
-rw-r--r-- | src/tool_easysrc.c | 112 | ||||
-rw-r--r-- | src/tool_easysrc.h | 34 | ||||
-rw-r--r-- | src/tool_formparse.c | 321 | ||||
-rw-r--r-- | src/tool_formparse.h | 33 | ||||
-rw-r--r-- | src/tool_getparam.c | 1634 | ||||
-rw-r--r-- | src/tool_getparam.h | 46 | ||||
-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.c | 238 | ||||
-rw-r--r-- | src/tool_help.h (renamed from src/writeenv.h) | 12 | ||||
-rw-r--r-- | src/tool_helpers.c | 78 | ||||
-rw-r--r-- | src/tool_helpers.h | 31 | ||||
-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.c | 102 | ||||
-rw-r--r-- | src/tool_libinfo.h | 34 | ||||
-rw-r--r-- | src/tool_main.c | 112 | ||||
-rw-r--r-- | src/tool_main.h | 44 | ||||
-rw-r--r-- | src/tool_mfiles.c | 129 | ||||
-rw-r--r-- | src/tool_mfiles.h | 46 | ||||
-rw-r--r-- | src/tool_msgs.c | 100 | ||||
-rw-r--r-- | src/tool_msgs.h | 31 | ||||
-rw-r--r-- | src/tool_operate.c | 1559 | ||||
-rw-r--r-- | src/tool_operate.h | 29 | ||||
-rw-r--r-- | src/tool_operhlp.c | 238 | ||||
-rw-r--r-- | src/tool_operhlp.h | 51 | ||||
-rw-r--r-- | src/tool_panykey.c | 48 | ||||
-rw-r--r-- | src/tool_panykey.h | 37 | ||||
-rw-r--r-- | src/tool_paramhlp.c | 387 | ||||
-rw-r--r-- | src/tool_paramhlp.h | 51 | ||||
-rw-r--r-- | src/tool_parsecfg.c | 308 | ||||
-rw-r--r-- | src/tool_parsecfg.h | 30 | ||||
-rw-r--r-- | src/tool_sdecls.h | 141 | ||||
-rw-r--r-- | src/tool_setopt.c | 125 | ||||
-rw-r--r-- | src/tool_setopt.h | 50 | ||||
-rw-r--r-- | src/tool_sleep.c | 62 | ||||
-rw-r--r-- | src/tool_sleep.h | 29 | ||||
-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.h | 35 | ||||
-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.dsp | 286 |
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, ×); /* 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, ×); /* 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"
|