diff options
author | Daniel Stenberg <daniel@haxx.se> | 1999-12-29 14:20:26 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 1999-12-29 14:20:26 +0000 |
commit | ae1912cb0d494b48d514d937826c9fe83ec96c4d (patch) | |
tree | 3b027d577182fc74bade646227f729eac461d0d2 /lib | |
download | curl-ae1912cb0d494b48d514d937826c9fe83ec96c4d.tar.gz |
Initial revision
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 282 | ||||
-rw-r--r-- | lib/Makefile.am | 31 | ||||
-rw-r--r-- | lib/Makefile.in | 282 | ||||
-rw-r--r-- | lib/Makefile.m32 | 67 | ||||
-rw-r--r-- | lib/Makefile.vc6 | 315 | ||||
-rw-r--r-- | lib/arpa_telnet.h | 319 | ||||
-rw-r--r-- | lib/base64.c | 94 | ||||
-rw-r--r-- | lib/base64.h | 44 | ||||
-rw-r--r-- | lib/cookie.c | 457 | ||||
-rw-r--r-- | lib/cookie.h | 45 | ||||
-rw-r--r-- | lib/dict.c | 245 | ||||
-rw-r--r-- | lib/dict.h | 45 | ||||
-rw-r--r-- | lib/download.c | 484 | ||||
-rw-r--r-- | lib/download.h | 50 | ||||
-rw-r--r-- | lib/escape.c | 111 | ||||
-rw-r--r-- | lib/escape.h | 49 | ||||
-rw-r--r-- | lib/file.c | 175 | ||||
-rw-r--r-- | lib/file.h | 45 | ||||
-rwxr-xr-x | lib/formdata | bin | 0 -> 23808 bytes | |||
-rw-r--r-- | lib/formdata.c | 617 | ||||
-rw-r--r-- | lib/formdata.h | 103 | ||||
-rw-r--r-- | lib/ftp.c | 1046 | ||||
-rw-r--r-- | lib/ftp.h | 52 | ||||
-rw-r--r-- | lib/getdate.c | 2101 | ||||
-rw-r--r-- | lib/getdate.h | 46 | ||||
-rw-r--r-- | lib/getdate.y | 1051 | ||||
-rw-r--r-- | lib/getenv.c | 95 | ||||
-rw-r--r-- | lib/getenv.h | 71 | ||||
-rw-r--r-- | lib/getpass.c | 185 | ||||
-rw-r--r-- | lib/getpass.h | 1 | ||||
-rw-r--r-- | lib/hostip.c | 111 | ||||
-rw-r--r-- | lib/hostip.h | 46 | ||||
-rw-r--r-- | lib/http.c | 381 | ||||
-rw-r--r-- | lib/http.h | 45 | ||||
-rw-r--r-- | lib/if2ip.c | 110 | ||||
-rw-r--r-- | lib/if2ip.h | 50 | ||||
-rw-r--r-- | lib/ldap.c | 226 | ||||
-rw-r--r-- | lib/ldap.h | 45 | ||||
-rw-r--r-- | lib/mprintf.c | 1253 | ||||
-rw-r--r-- | lib/netrc.c | 182 | ||||
-rw-r--r-- | lib/netrc.h | 70 | ||||
-rw-r--r-- | lib/progress.c | 221 | ||||
-rw-r--r-- | lib/progress.h | 54 | ||||
-rw-r--r-- | lib/sendf.c | 115 | ||||
-rw-r--r-- | lib/sendf.h | 47 | ||||
-rw-r--r-- | lib/setup.h | 169 | ||||
-rw-r--r-- | lib/speedcheck.c | 81 | ||||
-rw-r--r-- | lib/speedcheck.h | 50 | ||||
-rw-r--r-- | lib/ssluse.c | 265 | ||||
-rw-r--r-- | lib/ssluse.h | 46 | ||||
-rw-r--r-- | lib/sta01005 | bin | 0 -> 1024 bytes | |||
-rw-r--r-- | lib/sta18057 | bin | 0 -> 461824 bytes | |||
-rw-r--r-- | lib/telnet.c | 937 | ||||
-rw-r--r-- | lib/telnet.h | 45 | ||||
-rw-r--r-- | lib/timeval.c | 93 | ||||
-rw-r--r-- | lib/timeval.h | 64 | ||||
-rw-r--r-- | lib/upload.c | 178 | ||||
-rw-r--r-- | lib/upload.h | 46 | ||||
-rw-r--r-- | lib/url.c | 1181 | ||||
-rw-r--r-- | lib/url.h | 0 | ||||
-rw-r--r-- | lib/urldata.h | 212 | ||||
-rw-r--r-- | lib/version.c | 86 |
62 files changed, 14917 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 000000000..303df5359 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,282 @@ +# Generated automatically from Makefile.in by configure. +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# +# $Id$ +# + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. +prefix = /usr/local +exec_prefix = ${prefix} + +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +libexecdir = ${exec_prefix}/libexec +datadir = ${prefix}/share +sysconfdir = ${prefix}/etc +sharedstatedir = ${prefix}/com +localstatedir = ${prefix}/var +libdir = ${exec_prefix}/lib +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/curl +pkglibdir = $(libdir)/curl +pkgincludedir = $(includedir)/curl + +top_builddir = .. + +ACLOCAL = aclocal +AUTOCONF = autoconf +AUTOMAKE = automake +AUTOHEADER = autoheader + +INSTALL = .././install-sh -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL_PROGRAM} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = sparc-sun-solaris2.6 +host_triplet = sparc-sun-solaris2.6 +CC = gcc +MAKEINFO = makeinfo +NROFF = /bin/nroff +PACKAGE = curl +PERL = /usr/local/bin/perl +RANLIB = ranlib +VERSION = 6.3.1 +YACC = bison -y + +AUTOMAKE_OPTIONS = foreign no-dependencies + +noinst_LIBRARIES = libcurl.a + +# Some flags needed when trying to cause warnings ;-) +# CFLAGS = -Wall -pedantic + +INCLUDES = -I$(top_srcdir)/include + +libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c hostip.h progress.h upload.c cookie.c formdata.h http.c sendf.c upload.h cookie.h ftp.c http.h sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h getdate.c if2ip.h speedcheck.h urldata.h download.c getdate.h ldap.c ssluse.c version.c download.h getenv.c ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c telnet.h + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h ../src/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = -DHAVE_CONFIG_H -I. -I$(srcdir) -I.. -I../src +CPPFLAGS = -I/home/dast/include/openssl -I/home/dast/include +LDFLAGS = +LIBS = -lssl -lcrypto -ldl -lsocket -lnsl -L/home/dast/lib +libcurl_a_LIBADD = +libcurl_a_OBJECTS = file.o timeval.o base64.o hostip.o progress.o \ +formdata.o upload.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \ +speedcheck.o getdate.o download.o ldap.o ssluse.o version.o getenv.o \ +escape.o mprintf.o telnet.o getpass.o netrc.o +AR = ar +CFLAGS = -g -O2 +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(libcurl_a_SOURCES) +OBJECTS = $(libcurl_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libcurl.a: $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) + -rm -f libcurl.a + $(AR) cru libcurl.a $(libcurl_a_OBJECTS) $(libcurl_a_LIBADD) + $(RANLIB) libcurl.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule. +$(srcdir)/getdate.c: getdate.y + cd $(srcdir) && \ + $(YACC) $(YFLAGS) getdate.y; \ + mv -f y.tab.c getdate.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 000000000..ca83f8627 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,31 @@ +# +# $Id$ +# + +AUTOMAKE_OPTIONS = foreign no-dependencies + +noinst_LIBRARIES = libcurl.a + +# Some flags needed when trying to cause warnings ;-) +# CFLAGS = -Wall -pedantic + +INCLUDES = -I$(top_srcdir)/include + +libcurl_a_SOURCES = \ +arpa_telnet.h file.c getpass.h netrc.h timeval.c \ +base64.c file.h hostip.c progress.c timeval.h \ +base64.h formdata.c hostip.h progress.h upload.c \ +cookie.c formdata.h http.c sendf.c upload.h \ +cookie.h ftp.c http.h sendf.h url.c \ +dict.c ftp.h if2ip.c speedcheck.c url.h \ +dict.h getdate.c if2ip.h speedcheck.h urldata.h \ +download.c getdate.h ldap.c ssluse.c version.c \ +download.h getenv.c ldap.h ssluse.h \ +escape.c getenv.h mprintf.c telnet.c \ +escape.h getpass.c netrc.c telnet.h + +# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule. +$(srcdir)/getdate.c: getdate.y + cd $(srcdir) && \ + $(YACC) $(YFLAGS) getdate.y; \ + mv -f y.tab.c getdate.c diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 000000000..eb39e2a2b --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,282 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# +# $Id$ +# + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NROFF = @NROFF@ +PACKAGE = @PACKAGE@ +PERL = @PERL@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +AUTOMAKE_OPTIONS = foreign no-dependencies + +noinst_LIBRARIES = libcurl.a + +# Some flags needed when trying to cause warnings ;-) +# CFLAGS = -Wall -pedantic + +INCLUDES = -I$(top_srcdir)/include + +libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c hostip.h progress.h upload.c cookie.c formdata.h http.c sendf.c upload.h cookie.h ftp.c http.h sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h getdate.c if2ip.h speedcheck.h urldata.h download.c getdate.h ldap.c ssluse.c version.c download.h getenv.c ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c telnet.h + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h ../src/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. -I../src +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libcurl_a_LIBADD = +libcurl_a_OBJECTS = file.o timeval.o base64.o hostip.o progress.o \ +formdata.o upload.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \ +speedcheck.o getdate.o download.o ldap.o ssluse.o version.o getenv.o \ +escape.o mprintf.o telnet.o getpass.o netrc.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(libcurl_a_SOURCES) +OBJECTS = $(libcurl_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libcurl.a: $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) + -rm -f libcurl.a + $(AR) cru libcurl.a $(libcurl_a_OBJECTS) $(libcurl_a_LIBADD) + $(RANLIB) libcurl.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule. +$(srcdir)/getdate.c: getdate.y + cd $(srcdir) && \ + $(YACC) $(YFLAGS) getdate.y; \ + mv -f y.tab.c getdate.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 new file mode 100644 index 000000000..00aa77650 --- /dev/null +++ b/lib/Makefile.m32 @@ -0,0 +1,67 @@ +############################################################# +## Makefile for building libcurl.a with MingW32 (GCC-2.95) and +## optionally OpenSSL (0.9.4) +## Use: make -f Makefile.m32 +## +## Comments to: Troy Engel <tengel@sonic.net> or +## Joern Hartroth <hartroth@acm.org> + +CC = gcc +AR = ar +RANLIB = ranlib +OPENSSL_PATH = ../../openssl-0.9.4 + +######################################################## +## Nothing more to do below this line! + +INCLUDES = -I. -I.. -I../include +CFLAGS = -g -O2 +ifdef SSL + INCLUDES += -I"$(OPENSSL_PATH)/outinc" -I"$(OPENSSL_PATH)/outinc/openssl" + CFLAGS += -DUSE_SSLEAY +endif +COMPILE = $(CC) $(INCLUDES) $(CFLAGS) + +libcurl_a_LIBRARIES = libcurl.a + +libcurl_a_SOURCES = base64.c getenv.c if2ip.h progress.h upload.h \ +base64.h getenv.h mprintf.c setup.h url.c download.c getpass.c \ +mprintf.h ssluse.c url.h download.h hostip.c netrc.c ssluse.h \ +urldata.h formdata.c hostip.h netrc.h stdcheaders.h formdata.h \ +if2ip.c progress.c upload.c sendf.c sendf.h speedcheck.c speedcheck.h \ +ftp.c ftp.h getpass.c getpass.h version.c timeval.c timeval.h cookie.c \ +cookie.h escape.c escape.h getdate.c getdate.h dict.h dict.c http.c \ +http.h telnet.c telnet.h file.c file.h ldap.c ldap.h + +libcurl_a_OBJECTS = base64.o getenv.o mprintf.o url.o download.o \ +getpass.o ssluse.o hostip.o netrc.o formdata.o if2ip.o progress.o \ +upload.o sendf.o speedcheck.o ftp.o getpass.o version.o timeval.o \ +cookie.o escape.o getdate.o dict.o http.o telnet.o file.o ldap.o + +LIBRARIES = $(libcurl_a_LIBRARIES) +SOURCES = $(libcurl_a_SOURCES) +OBJECTS = $(libcurl_a_OBJECTS) + + +all: libcurl.a + +libcurl.a: $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) + -@erase libcurl.a + $(AR) cru libcurl.a $(libcurl_a_OBJECTS) + $(RANLIB) libcurl.a + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +clean: + -@erase $(libcurl_a_OBJECTS) + +distrib: clean + -@erase $(libcurl_a_LIBRARIES) + diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 new file mode 100644 index 000000000..e7db08e56 --- /dev/null +++ b/lib/Makefile.vc6 @@ -0,0 +1,315 @@ +#############################################################
+## Makefile for building libcurl.lib with MSVC6
+## Use: nmake -f makefile.vc6 [release | release-ssl | debug]
+## (default is release)
+##
+## Comments to: Troy Engel <tengel@sonic.net>
+
+PROGRAM_NAME = libcurl.lib
+OPENSSL_PATH = ../../openssl-0.9.3a
+
+########################################################
+## Nothing more to do below this line!
+
+## Release
+CCR = cl.exe /ML /O2 /D "NDEBUG"
+LINKR = link.exe -lib
+
+## Debug
+CCD = cl.exe /MLd /Gm /ZI /Od /D "_DEBUG" /GZ
+LINKD = link.exe -lib
+
+## SSL Release
+CCRS = cl.exe /ML /O2 /D "NDEBUG" /D "USE_SSLEAY" /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl"
+LINKRS = link.exe -lib /LIBPATH:$(OPENSSL_PATH)/out32dll
+
+CFLAGS = /nologo /W3 /GX /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
+LFLAGS = /nologo /out:$(PROGRAM_NAME)
+LINKLIBS = kernel32.lib wsock32.lib
+LINKSLIBS = libeay32.lib ssleay32.lib RSAglue.lib
+
+RELEASE_OBJS= \
+ base64r.obj \
+ cookier.obj \
+ downloadr.obj \
+ escaper.obj \
+ formdatar.obj \
+ ftpr.obj \
+ httpr.obj \
+ dictr.obj \
+ telnetr.obj \
+ getdater.obj \
+ getenvr.obj \
+ getpassr.obj \
+ hostipr.obj \
+ if2ipr.obj \
+ mprintfr.obj \
+ netrcr.obj \
+ progressr.obj \
+ sendfr.obj \
+ speedcheckr.obj \
+ ssluser.obj \
+ timevalr.obj \
+ uploadr.obj \
+ urlr.obj \
+ filer.obj \
+ versionr.obj
+
+DEBUG_OBJS= \
+ base64d.obj \
+ cookied.obj \
+ downloadd.obj \
+ escaped.obj \
+ formdatad.obj \
+ ftpd.obj \
+ httpd.obj \
+ dictd.obj \
+ telnetd.obj \
+ getdated.obj \
+ getenvd.obj \
+ getpassd.obj \
+ hostipd.obj \
+ if2ipd.obj \
+ mprintfd.obj \
+ netrcd.obj \
+ progressd.obj \
+ sendfd.obj \
+ speedcheckd.obj \
+ sslused.obj \
+ timevald.obj \
+ uploadd.obj \
+ urld.obj \
+ filed.obj \
+ versiond.obj
+
+RELEASE_SSL_OBJS= \
+ base64rs.obj \
+ cookiers.obj \
+ downloadrs.obj \
+ escapers.obj \
+ formdatars.obj \
+ ftprs.obj \
+ httprs.obj \
+ dictrs.obj \
+ telnetrs.obj \
+ getdaters.obj \
+ getenvrs.obj \
+ getpassrs.obj \
+ hostiprs.obj \
+ if2iprs.obj \
+ mprintfrs.obj \
+ netrcrs.obj \
+ progressrs.obj \
+ sendfrs.obj \
+ speedcheckrs.obj \
+ sslusers.obj \
+ timevalrs.obj \
+ uploadrs.obj \
+ urlrs.obj \
+ filers.obj \
+ versionrs.obj
+
+LINK_OBJS= \
+ base64.obj \
+ cookie.obj \
+ download.obj \
+ escape.obj \
+ formdata.obj \
+ ftp.obj \
+ http.obj \
+ dict.obj \
+ telnet.obj \
+ getdate.obj \
+ getenv.obj \
+ getpass.obj \
+ hostip.obj \
+ if2ip.obj \
+ mprintf.obj \
+ netrc.obj \
+ progress.obj \
+ sendf.obj \
+ speedcheck.obj \
+ ssluse.obj \
+ timeval.obj \
+ upload.obj \
+ url.obj \
+ file.obj \
+ version.obj
+
+all : release
+
+release: $(RELEASE_OBJS)
+ $(LINKR) $(LFLAGS) $(LINKLIBS) $(LINK_OBJS)
+
+debug: $(DEBUG_OBJS)
+ $(LINKD) $(LFLAGS) $(LINKLIBS) $(LINK_OBJS)
+
+release-ssl: $(RELEASE_SSL_OBJS)
+ $(LINKRS) $(LFLAGS) $(LINKLIBS) $(LINKSLIBS) $(LINK_OBJS)
+
+
+## Release
+base64r.obj: base64.c
+ $(CCR) $(CFLAGS) base64.c
+cookier.obj: cookie.c
+ $(CCR) $(CFLAGS) cookie.c
+downloadr.obj: download.c
+ $(CCR) $(CFLAGS) download.c
+escaper.obj: escape.c
+ $(CCR) $(CFLAGS) escape.c
+formdatar.obj: formdata.c
+ $(CCR) $(CFLAGS) formdata.c
+ftpr.obj: ftp.c
+ $(CCR) $(CFLAGS) ftp.c
+httpr.obj: http.c
+ $(CCR) $(CFLAGS) http.c
+dictr.obj: dict.c
+ $(CCR) $(CFLAGS) dict.c
+telnetr.obj: telnet.c
+ $(CCR) $(CFLAGS) telnet.c
+getdater.obj: getdate.c
+ $(CCR) $(CFLAGS) getdate.c
+getenvr.obj: getenv.c
+ $(CCR) $(CFLAGS) getenv.c
+getpassr.obj: getpass.c
+ $(CCR) $(CFLAGS) getpass.c
+hostipr.obj: hostip.c
+ $(CCR) $(CFLAGS) hostip.c
+if2ipr.obj: if2ip.c
+ $(CCR) $(CFLAGS) if2ip.c
+mprintfr.obj: mprintf.c
+ $(CCR) $(CFLAGS) mprintf.c
+netrcr.obj: netrc.c
+ $(CCR) $(CFLAGS) netrc.c
+progressr.obj: progress.c
+ $(CCR) $(CFLAGS) progress.c
+sendfr.obj: sendf.c
+ $(CCR) $(CFLAGS) sendf.c
+speedcheckr.obj: speedcheck.c
+ $(CCR) $(CFLAGS) speedcheck.c
+ssluser.obj: ssluse.c
+ $(CCR) $(CFLAGS) ssluse.c
+timevalr.obj: timeval.c
+ $(CCR) $(CFLAGS) timeval.c
+uploadr.obj: upload.c
+ $(CCR) $(CFLAGS) upload.c
+urlr.obj: url.c
+ $(CCR) $(CFLAGS) url.c
+filer.obj: file.c
+ $(CCR) $(CFLAGS) file.c
+versionr.obj: version.c
+ $(CCR) $(CFLAGS) version.c
+
+## Debug
+base64d.obj: base64.c
+ $(CCD) $(CFLAGS) base64.c
+cookied.obj: cookie.c
+ $(CCD) $(CFLAGS) cookie.c
+downloadd.obj: download.c
+ $(CCD) $(CFLAGS) download.c
+escaped.obj: escape.c
+ $(CCD) $(CFLAGS) escape.c
+formdatad.obj: formdata.c
+ $(CCD) $(CFLAGS) formdata.c
+ftpd.obj: ftp.c
+ $(CCD) $(CFLAGS) ftp.c
+httpd.obj: http.c
+ $(CCD) $(CFLAGS) http.c
+dictd.obj: dict.c
+ $(CCD) $(CFLAGS) dict.c
+telnetd.obj: telnet.c
+ $(CCD) $(CFLAGS) telnet.c
+getdated.obj: getdate.c
+ $(CCD) $(CFLAGS) getdate.c
+getenvd.obj: getenv.c
+ $(CCD) $(CFLAGS) getenv.c
+getpassd.obj: getpass.c
+ $(CCD) $(CFLAGS) getpass.c
+hostipd.obj: hostip.c
+ $(CCD) $(CFLAGS) hostip.c
+if2ipd.obj: if2ip.c
+ $(CCD) $(CFLAGS) if2ip.c
+mprintfd.obj: mprintf.c
+ $(CCD) $(CFLAGS) mprintf.c
+netrcd.obj: netrc.c
+ $(CCD) $(CFLAGS) netrc.c
+progressd.obj: progress.c
+ $(CCD) $(CFLAGS) progress.c
+sendfd.obj: sendf.c
+ $(CCD) $(CFLAGS) sendf.c
+speedcheckd.obj: speedcheck.c
+ $(CCD) $(CFLAGS) speedcheck.c
+sslused.obj: ssluse.c
+ $(CCD) $(CFLAGS) ssluse.c
+timevald.obj: timeval.c
+ $(CCD) $(CFLAGS) timeval.c
+uploadd.obj: upload.c
+ $(CCD) $(CFLAGS) upload.c
+urld.obj: url.c
+ $(CCD) $(CFLAGS) url.c
+filed.obj: file.c
+ $(CCD) $(CFLAGS) file.c
+versiond.obj: version.c
+ $(CCD) $(CFLAGS) version.c
+
+
+## Release SSL
+base64rs.obj: base64.c
+ $(CCRS) $(CFLAGS) base64.c
+cookiers.obj: cookie.c
+ $(CCRS) $(CFLAGS) cookie.c
+downloadrs.obj: download.c
+ $(CCRS) $(CFLAGS) download.c
+escapers.obj: escape.c
+ $(CCRS) $(CFLAGS) escape.c
+formdatars.obj: formdata.c
+ $(CCRS) $(CFLAGS) formdata.c
+ftprs.obj: ftp.c
+ $(CCRS) $(CFLAGS) ftp.c
+httprs.obj: http.c
+ $(CCRS) $(CFLAGS) http.c
+dictrs.obj: dict.c
+ $(CCRS) $(CFLAGS) dict.c
+telnetrs.obj: telnet.c
+ $(CCRS) $(CFLAGS) telnet.c
+getdaters.obj: getdate.c
+ $(CCRS) $(CFLAGS) getdate.c
+getenvrs.obj: getenv.c
+ $(CCRS) $(CFLAGS) getenv.c
+getpassrs.obj: getpass.c
+ $(CCRS) $(CFLAGS) getpass.c
+hostiprs.obj: hostip.c
+ $(CCRS) $(CFLAGS) hostip.c
+if2iprs.obj: if2ip.c
+ $(CCRS) $(CFLAGS) if2ip.c
+mprintfrs.obj: mprintf.c
+ $(CCRS) $(CFLAGS) mprintf.c
+netrcrs.obj: netrc.c
+ $(CCRS) $(CFLAGS) netrc.c
+progressrs.obj: progress.c
+ $(CCRS) $(CFLAGS) progress.c
+sendfrs.obj: sendf.c
+ $(CCRS) $(CFLAGS) sendf.c
+speedcheckrs.obj: speedcheck.c
+ $(CCRS) $(CFLAGS) speedcheck.c
+sslusers.obj: ssluse.c
+ $(CCRS) $(CFLAGS) ssluse.c
+timevalrs.obj: timeval.c
+ $(CCRS) $(CFLAGS) timeval.c
+uploadrs.obj: upload.c
+ $(CCRS) $(CFLAGS) upload.c
+urlrs.obj: url.c
+ $(CCRS) $(CFLAGS) url.c
+filers.obj: file.c
+ $(CCRS) $(CFLAGS) file.c
+versionrs.obj: version.c
+ $(CCRS) $(CFLAGS) version.c
+
+clean:
+ -@erase *.obj
+ -@erase vc60.idb
+ -@erase vc60.pch
+
+distrib: clean
+ -@erase $(PROGRAM_NAME)
+
diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h new file mode 100644 index 000000000..25085b89a --- /dev/null +++ b/lib/arpa_telnet.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)telnet.h 8.2 (Berkeley) 12/15/93 + */ + +#ifndef _ARPA_TELNET_H +#define _ARPA_TELNET_H + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, +}; +#else +extern char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ + (unsigned int)(x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#define NTELOPTS (1+TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", + 0, +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_NEW_ENVIRON +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ +#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ +#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ +#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ + +#define LFLOW_OFF 0 /* Disable remote flow control */ +#define LFLOW_ON 1 /* Enable remote flow control */ +#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ +#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +/* + * For backwards compatability, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +/* + * AUTHENTICATION suboptions + */ + +/* + * Who is authenticating who ... + */ +#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ +#define AUTH_WHO_SERVER 1 /* Server authenticating client */ +#define AUTH_WHO_MASK 1 + +/* + * amount of authentication done + */ +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char *authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +/* + * ENCRYPTion suboptions + */ +#define ENCRYPT_IS 0 /* I pick encryption type ... */ +#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ +#define ENCRYPT_REPLY 2 /* Initial setup response */ +#define ENCRYPT_START 3 /* Am starting to send encrypted */ +#define ENCRYPT_END 4 /* Am ending encrypted */ +#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ +#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char *encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0, +}; +char *enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", 0, +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] +#endif /* _ARPA_TELNET_H */ diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 000000000..8758af1ef --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> + +/* ---- Base64 Encoding --- */ +static char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void base64Encode(char *intext, char *output) +{ + unsigned char ibuf[3]; + unsigned char obuf[4]; + int i; + int inputparts; + + while(*intext) { + for (i = inputparts = 0; i < 3; i++) { + if(*intext) { + inputparts++; + ibuf[i] = *intext; + intext++; + } + else + ibuf[i] = 0; + } + + obuf [0] = (ibuf [0] & 0xFC) >> 2; + obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4); + obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6); + obuf [3] = ibuf [2] & 0x3F; + + switch(inputparts) { + case 1: /* only one byte read */ + sprintf(output, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); + break; + case 2: /* two bytes read */ + sprintf(output, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); + break; + default: + sprintf(output, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]] ); + break; + } + output += 4; + } + *output=0; +} +/* ---- End of Base64 Encoding ---- */ diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 000000000..460974331 --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,44 @@ +#ifndef __BASE64_H +#define __BASE64_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +void base64Encode(char *intext, char *output); +#endif diff --git a/lib/cookie.c b/lib/cookie.c new file mode 100644 index 000000000..dde335042 --- /dev/null +++ b/lib/cookie.c @@ -0,0 +1,457 @@ + +/*** + + +RECEIVING COOKIE INFORMATION +============================ + +struct CookieInfo *cookie_init(char *file); + + Inits a cookie struct to store data in a local file. This is always + called before any cookies are set. + +int cookies_set(struct CookieInfo *cookie, char *cookie_line); + + The 'cookie_line' parameter is a full "Set-cookie:" line as + received from a server. + + The function need to replace previously stored lines that this new + line superceeds. + + It may remove lines that are expired. + + It should return an indication of success/error. + + +SENDING COOKIE INFORMATION +========================== + +struct Cookies *cookie_getlist(struct CookieInfo *cookie, + char *host, char *path, bool secure); + + For a given host and path, return a linked list of cookies that + the client should send to the server if used now. The secure + boolean informs the cookie if a secure connection is achieved or + not. + + It shall only return cookies that haven't expired. + + +Example set of cookies: + + Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure + Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/ftgw; secure + Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; + domain=.fidelity.com; path=/; secure + Set-cookie: + Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, + 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure +****/ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "cookie.h" +#include "setup.h" +#include "getdate.h" + +/**************************************************************************** + * + * cookie_add() + * + * Add a single cookie line to the cookie keeping object. + * + ***************************************************************************/ + +struct Cookie *cookie_add(struct CookieInfo *c, + bool httpheader, /* TRUE if HTTP header-style line */ + char *lineptr) /* first non-space of the line */ +{ + struct Cookie *clist; + char what[MAX_COOKIE_LINE]; + char name[MAX_NAME]; + char *ptr; + char *semiptr; + struct Cookie *co; + time_t now = time(NULL); + bool replace_old = FALSE; + + /* First, alloc and init a new struct for it */ + co = (struct Cookie *)malloc(sizeof(struct Cookie)); + if(!co) + return NULL; /* bail out if we're this low on memory */ + + /* clear the whole struct first */ + memset(co, 0, sizeof(struct Cookie)); + + if(httpheader) { + /* This line was read off a HTTP-header */ + + semiptr=strchr(lineptr, ';'); /* first, find a semicolon */ + ptr = lineptr; + while(semiptr) { + *semiptr='\0'; /* zero terminate for a while */ + /* we have a <what>=<this> pair or a 'secure' word here */ + if(strchr(ptr, '=')) { + if(2 == sscanf(ptr, "%" MAX_NAME_TXT "[^=]=%" + MAX_COOKIE_LINE_TXT "[^\r\n]", + name, what)) { + /* this is a legal <what>=<this> pair */ + if(strequal("path", name)) { + co->path=strdup(what); + } + else if(strequal("domain", name)) { + co->domain=strdup(what); + } + else if(strequal("expires", name)) { + co->expirestr=strdup(what); + co->expires = get_date(what, &now); + } + else if(!co->name) { + co->name = strdup(name); + co->value = strdup(what); + } + else + ;/* this is the second (or more) name we don't know + about! */ + } + else { + /* this is an "illegal" <what>=<this> pair */ + } + } + else { + if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^\r\n]", + what)) { + if(strequal("secure", what)) + co->secure = TRUE; + else + ; /* unsupported keyword without assign! */ + } + } + *semiptr=';'; /* put the semicolon back */ + ptr=semiptr+1; + while(ptr && *ptr && isspace((int)*ptr)) + ptr++; + semiptr=strchr(ptr, ';'); /* now, find the next semicolon */ + } + } + else { + /* This line is NOT a HTTP header style line, we do offer support for + reading the odd netscape cookies-file format here */ + char *firstptr; + int fields; + + if(lineptr[0]=='#') { + /* don't even try the comments */ + free(co); + return NULL; + } + /* strip off the possible end-of-line characters */ + if(ptr=strchr(lineptr, '\r')) + *ptr=0; /* clear it */ + if(ptr=strchr(lineptr, '\n')) + *ptr=0; /* clear it */ + + firstptr=strtok(lineptr, "\t"); /* first tokenize it on the TAB */ + + /* Here's a quick check to eliminate normal HTTP-headers from this */ + if(!firstptr || strchr(firstptr, ':')) { + free(co); + return NULL; + } + + /* Now loop through the fields and init the struct we already have + allocated */ + for(ptr=firstptr, fields=0; ptr; ptr=strtok(NULL, "\t"), fields++) { + switch(fields) { + case 0: + co->domain = strdup(ptr); + break; + case 1: + /* what _is_ this field for? */ + break; + case 2: + co->path = strdup(ptr); + break; + case 3: + co->secure = strequal(ptr, "TRUE"); + break; + case 4: + co->expires = atoi(ptr); + break; + case 5: + co->name = strdup(ptr); + break; + case 6: + co->value = strdup(ptr); + break; + } + } + + if(7 != fields) { + /* we did not find the sufficient number of fields to recognize this + as a valid line, abort and go home */ + + if(co->domain) + free(co->domain); + if(co->path) + free(co->path); + if(co->name) + free(co->name); + if(co->value) + free(co->value); + + free(co); + return NULL; + } + + } + + /* now, we have parsed the incoming line, we must now check if this + superceeds an already existing cookie, which it may if the previous have + the same domain and path as this */ + + clist = c->cookies; + replace_old = FALSE; + while(clist) { + if(strequal(clist->name, co->name)) { + /* the names are identical */ + + if(clist->domain && co->domain) { + if(strequal(clist->domain, co->domain)) + replace_old=TRUE; + } + else if(!clist->domain && !co->domain) + replace_old = TRUE; + + if(replace_old) { + /* the domains were identical */ + + if(clist->path && co->path) { + if(strequal(clist->path, co->path)) { + replace_old = TRUE; + } + else + replace_old = FALSE; + } + else if(!clist->path && !co->path) + replace_old = TRUE; + else + replace_old = FALSE; + + } + + if(replace_old) { + co->next = clist->next; /* get the next-pointer first */ + + /* then free all the old pointers */ + if(clist->name) + free(clist->name); + if(clist->value) + free(clist->value); + if(clist->domain) + free(clist->domain); + if(clist->path) + free(clist->path); + if(clist->expirestr) + free(clist->expirestr); + + *clist = *co; /* then store all the new data */ + } + + } + clist = clist->next; + } + + if(!replace_old) { + + /* first, point to our "next" */ + co->next = c->cookies; + /* then make ourselves first in the list */ + c->cookies = co; + } + return co; +} + +/***************************************************************************** + * + * cookie_init() + * + * Inits a cookie struct to read data from a local file. This is always + * called before any cookies are set. File may be NULL. + * + ****************************************************************************/ +struct CookieInfo *cookie_init(char *file) +{ + char line[MAX_COOKIE_LINE]; + struct CookieInfo *c; + FILE *fp; + + c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo)); + if(!c) + return NULL; /* failed to get memory */ + memset(c, 0, sizeof(struct CookieInfo)); + c->filename = strdup(file?file:"none"); /* copy the name just in case */ + + fp = file?fopen(file, "r"):NULL; + if(fp) { + while(fgets(line, MAX_COOKIE_LINE, fp)) { + if(strnequal("Set-Cookie:", line, 11)) { + /* This is a cookie line, get it! */ + char *lineptr=&line[11]; + while(*lineptr && isspace((int)*lineptr)) + lineptr++; + + cookie_add(c, TRUE, lineptr); + } + else { + /* This might be a netscape cookie-file line, get it! */ + char *lineptr=line; + while(*lineptr && isspace((int)*lineptr)) + lineptr++; + + cookie_add(c, FALSE, lineptr); + } + } + fclose(fp); + } + + return c; +} + +/***************************************************************************** + * + * cookie_getlist() + * + * For a given host and path, return a linked list of cookies that the + * client should send to the server if used now. The secure boolean informs + * the cookie if a secure connection is achieved or not. + * + * It shall only return cookies that haven't expired. + * + ****************************************************************************/ + +struct Cookie *cookie_getlist(struct CookieInfo *c, + char *host, char *path, bool secure) +{ + struct Cookie *newco; + struct Cookie *co; + time_t now = time(NULL); + int hostlen=strlen(host); + int domlen; + + struct Cookie *mainco=NULL; + + if(!c || !c->cookies) + return NULL; /* no cookie struct or no cookies in the struct */ + + co = c->cookies; + + while(co) { + /* only process this cookie if it is not expired or had no expire + date AND that if the cookie requires we're secure we must only + continue if we are! */ + if( (co->expires<=0 || (co->expires> now)) && + (co->secure?secure:TRUE) ) { + + /* now check if the domain is correct */ + domlen=co->domain?strlen(co->domain):0; + if(!co->domain || + ((domlen<hostlen) && + strequal(host+(hostlen-domlen), co->domain)) ) { + /* the right part of the host matches the domain stuff in the + cookie data */ + + /* now check the left part of the path with the cookies path + requirement */ + if(!co->path || + strnequal(path, co->path, strlen(co->path))) { + + /* and now, we know this is a match and we should create an + entry for the return-linked-list */ + + newco = (struct Cookie *)malloc(sizeof(struct Cookie)); + if(newco) { + /* first, copy the whole source cookie: */ + memcpy(newco, co, sizeof(struct Cookie)); + + /* then modify our next */ + newco->next = mainco; + + /* point the main to us */ + mainco = newco; + } + } + } + } + co = co->next; + } + + return mainco; /* return the new list */ +} + + +/***************************************************************************** + * + * cookie_freelist() + * + * Free a list previously returned by cookie_getlist(); + * + ****************************************************************************/ + +void cookie_freelist(struct Cookie *co) +{ + struct Cookie *next; + if(co) { + while(co) { + next = co->next; + free(co); /* we only free the struct since the "members" are all + just copied! */ + co = next; + } + } +} + +/***************************************************************************** + * + * cookie_cleanup() + * + * Free a "cookie object" previous created with cookie_init(). + * + ****************************************************************************/ +void cookie_cleanup(struct CookieInfo *c) +{ + struct Cookie *co; + struct Cookie *next; + if(c) { + if(c->filename) + free(c->filename); + co = c->cookies; + + while(co) { + if(co->name) + free(co->name); + if(co->value) + free(co->value); + if(co->domain) + free(co->domain); + if(co->path) + free(co->path); + if(co->expirestr) + free(co->expirestr); + + next = co->next; + free(co); + co = next; + } + } +} + diff --git a/lib/cookie.h b/lib/cookie.h new file mode 100644 index 000000000..466844a5d --- /dev/null +++ b/lib/cookie.h @@ -0,0 +1,45 @@ +#ifndef __COOKIE_H +#define __COOKIE_H + +#include <stdio.h> +#ifdef WIN32 +#include <time.h> +#else +#include <sys/time.h> +#endif + +#include <curl/curl.h> + +struct Cookie { + struct Cookie *next; /* next in the chain */ + char *name; /* <this> = value */ + char *value; /* name = <this> */ + char *path; /* path = <this> */ + char *domain; /* domain = <this> */ + time_t expires; /* expires = <this> */ + char *expirestr; /* the plain text version */ + bool secure; /* whether the 'secure' keyword was used */ +}; + +struct CookieInfo { + /* linked list of cookies we know of */ + struct Cookie *cookies; + + char *filename; /* file we read from/write to */ +}; + +/* This is the maximum line length we accept for a cookie line */ +#define MAX_COOKIE_LINE 2048 +#define MAX_COOKIE_LINE_TXT "2047" + +/* This is the maximum length of a cookie name we deal with: */ +#define MAX_NAME 256 +#define MAX_NAME_TXT "255" + +struct Cookie *cookie_add(struct CookieInfo *, bool, char *); +struct CookieInfo *cookie_init(char *); +struct Cookie *cookie_getlist(struct CookieInfo *, char *, char *, bool); +void cookie_freelist(struct Cookie *); +void cookie_cleanup(struct CookieInfo *); + +#endif diff --git a/lib/dict.c b/lib/dict.c new file mode 100644 index 000000000..e26437022 --- /dev/null +++ b/lib/dict.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#include <time.h> +#include <io.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <sys/time.h> +#include <sys/resource.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> +#include <signal.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "download.h" +#include "sendf.h" + +#include "progress.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + + +UrgError dict(struct UrlData *data, char *path, long *bytecount) +{ + int nth; + char *word; + char *ppath; + char *database = NULL; + char *strategy = NULL; + char *nthdef = NULL; /* This is not part of the protocol, but required + by RFC 2229 */ + UrgError result=URG_OK; + + if(data->conf & CONF_USERPWD) { + /* AUTH is missing */ + } + + if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + + word = strchr(path, ':'); + if (word) { + word++; + database = strchr(word, ':'); + if (database) { + *database++ = (char)0; + strategy = strchr(database, ':'); + if (strategy) { + *strategy++ = (char)0; + nthdef = strchr(strategy, ':'); + if (nthdef) { + *nthdef++ = (char)0; + } + } + } + } + + if ((word == NULL) || (*word == (char)0)) { + failf(data, "lookup word is missing\n"); + } + if ((database == NULL) || (*database == (char)0)) { + database = "!"; + } + if ((strategy == NULL) || (*strategy == (char)0)) { + strategy = "."; + } + if ((nthdef == NULL) || (*nthdef == (char)0)) { + nth = 0; + } + else { + nth = atoi(nthdef); + } + + sendf(data->firstsocket, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" + "MATCH " + "%s " /* database */ + "%s " /* strategy */ + "%s\n" /* word */ + "QUIT\n", + + database, + strategy, + word + ); + + result = Download(data, data->firstsocket, -1, FALSE, bytecount); + + if(result) + return result; + + } + else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + + word = strchr(path, ':'); + if (word) { + word++; + database = strchr(word, ':'); + if (database) { + *database++ = (char)0; + nthdef = strchr(database, ':'); + if (nthdef) { + *nthdef++ = (char)0; + } + } + } + + if ((word == NULL) || (*word == (char)0)) { + failf(data, "lookup word is missing\n"); + } + if ((database == NULL) || (*database == (char)0)) { + database = "!"; + } + if ((nthdef == NULL) || (*nthdef == (char)0)) { + nth = 0; + } + else { + nth = atoi(nthdef); + } + + sendf(data->firstsocket, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" + "DEFINE " + "%s " /* database */ + "%s\n" /* word */ + "QUIT\n", + + database, + word + ); + + result = Download(data, data->firstsocket, -1, FALSE, bytecount); + + if(result) + return result; + + } + else { + + ppath = strchr(path, '/'); + if (ppath) { + int i; + + ppath++; + for (i = 0; (i < URL_MAX_LENGTH) && (ppath[i]); i++) { + if (ppath[i] == ':') + ppath[i] = ' '; + } + sendf(data->firstsocket, data, + "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" + "%s\n" + "QUIT\n", + ppath); + + result = Download(data, data->firstsocket, -1, FALSE, bytecount); + + if(result) + return result; + + } + } + + ProgressEnd(data); + return URG_OK; +} diff --git a/lib/dict.h b/lib/dict.h new file mode 100644 index 000000000..edff0c434 --- /dev/null +++ b/lib/dict.h @@ -0,0 +1,45 @@ +#ifndef __DICT_H +#define __DICT_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError dict(struct UrlData *data, char *path, long *bytecountp); + +#endif diff --git a/lib/download.c b/lib/download.c new file mode 100644 index 000000000..fb0cb60ea --- /dev/null +++ b/lib/download.c @@ -0,0 +1,484 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#include "urldata.h" +#include <curl/curl.h> + +#ifdef __BEOS__ +#include <net/socket.h> +#endif + +#ifdef WIN32 +#if !defined( __GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#endif +#include <time.h> /* for the time_t typedef! */ + +#if defined(__GNUC__) && defined(TIME_WITH_SYS_TIME) +#include <sys/time.h> +#endif + +#endif + +#include "progress.h" +#include "speedcheck.h" +#include "sendf.h" + +#ifdef USE_ZLIB +#include <zlib.h> +#endif + +#define MAX(x,y) ((x)>(y)?(x):(y)) + +/* --- download a stream from a socket --- */ + +/* This newly edited version of Download() was brought to us by the friendly + Mark Butler <butlerm@xmission.com>. Re-indented with the indent command. */ + +UrgError +Download (struct UrlData *data, + int sockfd, /* socket to read from */ + int size, /* -1 if unknown at this point */ + bool getheader, /* TRUE if header parsing is wanted */ + long *bytecountp /* return number of bytes read */ +) +{ + char *buf = data->buffer; + size_t nread; + int bytecount = 0; + long contentlength=0; + struct timeval start = tvnow(); + struct timeval now = start; + bool header = TRUE; + int headerline = 0; /* counts header lines to better track the first one */ + + char *hbufp; /* points at *end* of header line */ + int hbuflen = 0; + char *str; /* within buf */ + char *str_start; /* within buf */ + char *end_ptr; /* within buf */ + char *p; /* within headerbuff */ + bool content_range = FALSE; /* set TRUE if Content-Range: was found */ + int offset = 0; /* possible resume offset read from the + Content-Range: header */ + int code = 0; /* error code from the 'HTTP/1.? XXX' line */ +#ifdef USE_ZLIB + gzFile gzfile=NULL; +#endif + + /* for the low speed checks: */ + UrgError urg; + time_t timeofdoc=0; + long bodywrites=0; + + char newurl[URL_MAX_LENGTH]; /* buffer for Location: URL */ + + hbufp = data->headerbuff; + + myalarm (0); /* switch off the alarm-style timeout */ + + now = tvnow(); + start = now; + + if (!getheader) { + header = FALSE; + ProgressInit (data, size); + } + { + fd_set readfd; + fd_set keepfd; + struct timeval interval; + bool keepon = TRUE; + + /* timeout every X second + - makes a better progressmeter (i.e even when no data is read, the + meter can be updated and reflect reality) + - allows removal of the alarm() crap + - variable timeout is easier + */ + + FD_ZERO (&readfd); /* clear it */ + FD_SET (sockfd, &readfd); + + keepfd = readfd; +#ifdef USE_ZLIB + gzfile = gzdopen(sockfd, "rb"); +#endif + while (keepon) { + readfd = keepfd; /* set this every lap in the loop */ + interval.tv_sec = 2; + interval.tv_usec = 0; + + switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) { + case -1: /* error, stop reading */ + keepon = FALSE; + continue; + case 0: /* timeout */ + break; + default: /* read! */ +#ifdef USE_SSLEAY + if (data->use_ssl) { + nread = SSL_read (data->ssl, buf, BUFSIZE - 1); + } + else { +#endif +#ifdef USE_ZLIB + nread = gzread(gzfile, buf, BUFSIZE -1 ); +#else + nread = sread (sockfd, buf, BUFSIZE - 1); +#endif +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + + /* NULL terminate, allowing string ops to be used */ + if (0 < (signed int) nread) + buf[nread] = 0; + + /* if we receive 0 or less here, the server closed the connection and + we bail out from this! */ + else if (0 >= (signed int) nread) { + keepon = FALSE; + break; + } + + str = buf; /* Default buffer to use when we write the + buffer, it may be changed in the flow below + before the actual storing is done. */ + + /* Since this is a two-state thing, we check if we are parsing + headers at the moment or not. */ + + if (header) { + /* we are in parse-the-header-mode */ + + /* header line within buffer loop */ + do { + int hbufp_index; + + str_start = str; /* str_start is start of line within buf */ + + end_ptr = strchr (str_start, '\n'); + + if (!end_ptr) { + /* no more complete header lines within buffer */ + /* copy what is remaining into headerbuff */ + int str_length = (int)strlen(str); + + if (hbuflen + (int)str_length >= data->headersize) { + char *newbuff; + long newsize=MAX((hbuflen+str_length)*3/2, + data->headersize*2); + hbufp_index = hbufp - data->headerbuff; + newbuff = (char *)realloc(data->headerbuff, newsize); + if(!newbuff) { + failf (data, "Failed to alloc memory for big header!"); + return URG_READ_ERROR; + } + data->headersize=newsize; + data->headerbuff = newbuff; + hbufp = data->headerbuff + hbufp_index; + } + strcpy (hbufp, str); + hbufp += strlen (str); + hbuflen += strlen (str); + break; /* read more and try again */ + } + + str = end_ptr + 1; /* move just past new line */ + + if (hbuflen + (str - str_start) >= data->headersize) { + char *newbuff; + long newsize=MAX((hbuflen+(str-str_start))*3/2, + data->headersize*2); + hbufp_index = hbufp - data->headerbuff; + newbuff = (char *)realloc(data->headerbuff, newsize); + if(!newbuff) { + failf (data, "Failed to alloc memory for big header!"); + return URG_READ_ERROR; + } + data->headersize= newsize; + data->headerbuff = newbuff; + hbufp = data->headerbuff + hbufp_index; + } + + /* copy to end of line */ + strncpy (hbufp, str_start, str - str_start); + hbufp += str - str_start; + hbuflen += str - str_start; + *hbufp = 0; + + p = data->headerbuff; + + /* we now have a full line that p points to */ + if (('\n' == *p) || ('\r' == *p)) { + /* Zero-length line means end of header! */ + if (-1 != size) /* if known */ + size += bytecount; /* we append the already read size */ + + + if ('\r' == *p) + p++; /* pass the \r byte */ + if ('\n' == *p) + p++; /* pass the \n byte */ + + ProgressInit (data, size); /* init progress meter */ + header = FALSE; /* no more header to parse! */ + + /* now, only output this if the header AND body are requested: */ + if ((data->conf & (CONF_HEADER | CONF_NOBODY)) == CONF_HEADER) { + if((p - data->headerbuff) != + data->fwrite (data->headerbuff, 1, + p - data->headerbuff, data->out)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + } + if(data->writeheader) { + /* obviously, the header is requested to be written to + this file: */ + if((p - data->headerbuff) != + fwrite (data->headerbuff, 1, p - data->headerbuff, + data->writeheader)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + } + break; /* exit header line loop */ + } + + if (!headerline++) { + /* This is the first header, it MUST be the error code line + or else we consiser this to be the body right away! */ + if (sscanf (p, " HTTP/1.%*c %3d", &code)) { + /* 404 -> URL not found! */ + if ( + ( ((data->conf & CONF_FOLLOWLOCATION) && (code >= 400)) || + !(data->conf & CONF_FOLLOWLOCATION) && (code >= 300)) + && (data->conf & CONF_FAILONERROR)) { + /* If we have been told to fail hard on HTTP-errors, + here is the check for that: */ + /* serious error, go home! */ + failf (data, "The requested file was not found"); + return URG_HTTP_NOT_FOUND; + } + } + else { + header = FALSE; /* this is not a header line */ + break; + } + } + /* check for Content-Length: header lines to get size */ + if (strnequal("Content-Length", p, 14) && + sscanf (p+14, ": %ld", &contentlength)) + size = contentlength; + else if (strnequal("Content-Range", p, 13) && + sscanf (p+13, ": bytes %d-", &offset)) { + if (data->resume_from == offset) { + /* we asked for a resume and we got it */ + content_range = TRUE; + } + } + else if(data->cookies && + strnequal("Set-Cookie: ", p, 11)) { + cookie_add(data->cookies, TRUE, &p[12]); + } + else if(strnequal("Last-Modified:", p, strlen("Last-Modified:")) && + data->timecondition) { + time_t secs=time(NULL); + timeofdoc = get_date(p+strlen("Last-Modified:"), &secs); + } + else if ((code >= 300 && code < 400) && + (data->conf & CONF_FOLLOWLOCATION) && + strnequal("Location", p, 8) && + sscanf (p+8, ": %" URL_MAX_LENGTH_TXT "s", newurl)) { + /* this is the URL that the server advices us to get + instead */ + data->newurl = strdup (newurl); + } + + if (data->conf & CONF_HEADER) { + if(hbuflen != data->fwrite (p, 1, hbuflen, data->out)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + } + if(data->writeheader) { + /* the header is requested to be written to this file */ + if(hbuflen != fwrite (p, 1, hbuflen, data->writeheader)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + } + + /* reset hbufp pointer && hbuflen */ + hbufp = data->headerbuff; + hbuflen = 0; + } + while (*str); /* header line within buffer */ + + /* We might have reached the end of the header part here, but + there might be a non-header part left in the end of the read + buffer. */ + + if (!header) { + /* the next token and forward is not part of + the header! */ + + /* we subtract the remaining header size from the buffer */ + nread -= (str - buf); + } + + } /* end if header mode */ + + /* This is not an 'else if' since it may be a rest from the header + parsing, where the beginning of the buffer is headers and the end + is non-headers. */ + if (str && !header && (nread > 0)) { + + if(0 == bodywrites) { + /* These checks are only made the first time we are about to + write a chunk of the body */ + if(data->conf&CONF_HTTP) { + /* HTTP-only checks */ + if (data->resume_from && !content_range ) { + /* we wanted to resume a download, although the server doesn't + seem to support this */ + failf (data, "HTTP server doesn't seem to support byte ranges. Cannot resume."); + return URG_HTTP_RANGE_ERROR; + } + else if (data->newurl) { + /* abort after the headers if "follow Location" is set */ + infof (data, "Follow to new URL: %s\n", data->newurl); + return URG_OK; + } + else if(data->timecondition && !data->range) { + /* A time condition has been set AND no ranges have been + requested. This seems to be what chapter 13.3.4 of RFC 2616 + defines to be the correct action for a HTTP/1.1 client */ + if((timeofdoc > 0) && (data->timevalue > 0)) { + switch(data->timecondition) { + case TIMECOND_IFMODSINCE: + default: + if(timeofdoc < data->timevalue) { + infof(data, "The requested document is not new enough"); + return URG_OK; + } + break; + case TIMECOND_IFUNMODSINCE: + if(timeofdoc > data->timevalue) { + infof(data, "The requested document is not old enough"); + return URG_OK; + } + break; + } /* switch */ + } /* two valid time strings */ + } /* we have a time condition */ + } /* this is HTTP */ + } /* this is the first time we write a body part */ + bodywrites++; + + if(data->maxdownload && + (bytecount + nread > data->maxdownload)) { + nread = data->maxdownload - bytecount; + if(nread < 0 ) /* this should be unusual */ + nread = 0; + keepon = FALSE; /* we're done now! */ + } + + bytecount += nread; + + if (nread != data->fwrite (str, 1, nread, data->out)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + + } + break; + } + now = tvnow(); + if (!header) { + ProgressShow (data, bytecount, start, now, FALSE); + } + urg = speedcheck (data, now); + if (urg) + return urg; + + if (data->timeout && (tvdiff (now, start) > data->timeout)) { + failf (data, "Operation timed out with %d out of %d bytes received", + bytecount, size); + return URG_OPERATION_TIMEOUTED; + } +#ifdef MULTIDOC + if(contentlength && bytecount >= contentlength) { + /* we're done with this download, now stop it */ + break; + } +#endif + } + } + if(contentlength && (bytecount != contentlength)) { + failf(data, "transfer closed with %d bytes remaining", contentlength-bytecount); + return URG_PARTIAL_FILE; + } + ProgressShow (data, bytecount, start, now, TRUE); + + *bytecountp = bytecount; + +#ifdef USE_ZLIB + gzclose(gzfile); +#endif + return URG_OK; +} + + diff --git a/lib/download.h b/lib/download.h new file mode 100644 index 000000000..e8ca82add --- /dev/null +++ b/lib/download.h @@ -0,0 +1,50 @@ +#ifndef __DOWNLOAD_H +#define __DOWNLOAD_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError +Download (struct UrlData *data, + int sockfd, /* socket to read from */ + int size, /* -1 if unknown at this point */ + bool getheader, /* TRUE if header parsing is wanted */ + long *bytecountp /* return number of bytes read */ +); + +#endif diff --git a/lib/escape.c b/lib/escape.c new file mode 100644 index 000000000..68000cd71 --- /dev/null +++ b/lib/escape.c @@ -0,0 +1,111 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +char *curl_escape(char *string) +{ + int alloc=strlen(string); + char *ns = malloc(alloc); + unsigned char in; + int newlen = alloc; + int index=0; + + while(*string) { + in = *string; + if(' ' == in) + ns[index++] = '+'; + else if(!(in >= 'a' && in <= 'z') && + !(in >= 'A' && in <= 'Z') && + !(in >= '0' && in <= '9')) { + /* encode it */ + newlen += 2; /* the size grows with two, since this'll become a %XX */ + if(newlen > alloc) { + alloc *= 2; + ns = realloc(ns, alloc); + if(!ns) + return NULL; + } + sprintf(&ns[index], "%%%02X", in); + index+=3; + } + else { + /* just copy this */ + ns[index++]=in; + } + string++; + } + ns[index]=0; /* terminate it */ + return ns; +} + +char *curl_unescape(char *string) +{ + int alloc = strlen(string); + char *ns = malloc(alloc); + unsigned char in; + int index=0; + int hex; + + + while(*string) { + in = *string; + if('+' == in) + in = ' '; + else if('%' == in) { + /* encoded part */ + if(sscanf(string+1, "%02X", &hex)) { + in = hex; + string+=2; + } + } + + ns[index++] = in; + string++; + } + ns[index]=0; /* terminate it */ + return ns; + +} diff --git a/lib/escape.h b/lib/escape.h new file mode 100644 index 000000000..bca4d8bd9 --- /dev/null +++ b/lib/escape.h @@ -0,0 +1,49 @@ +#ifndef __ESCAPE_H +#define __ESCAPE_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +/* Escape and unescape URL encoding in strings. The functions return a new + * allocated string or NULL if an error occurred. */ + +char *curl_escape(char *string); +char *curl_unescape(char *string); + +#endif diff --git a/lib/file.c b/lib/file.c new file mode 100644 index 000000000..b5d198e57 --- /dev/null +++ b/lib/file.c @@ -0,0 +1,175 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1999. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#include <time.h> +#include <io.h> +#include <fcntl.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <sys/time.h> +#include <sys/resource.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> +#include <signal.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "progress.h" +#include "sendf.h" +#include "escape.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + + +UrgError file(struct UrlData *data, char *path, long *bytecountp) +{ + /* This implementation ignores the host name in conformance with + RFC 1738. Only local files (reachable via the standard file system) + are supported. This means that files on remotely mounted directories + (via NFS, Samba, NT sharing) can be accessed through a file:// URL + */ + + struct stat statbuf; + size_t expected_size=-1; + size_t nread; + char *buf = data->buffer; + int bytecount = 0; + struct timeval start = tvnow(); + struct timeval now = start; + int fd; + char *actual_path = curl_unescape(path); + +#ifdef WIN32 + int i; + + /* change path separators from '/' to '\\' for Windows */ + for (i=0; actual_path[i] != '\0'; ++i) + if (actual_path[i] == '/') + actual_path[i] = '\\'; + + fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */ +#else + fd = open(actual_path, O_RDONLY); +#endif + free(actual_path); + + if(fd == -1) { + failf(data, "Couldn't open file %s", path); + return URG_FILE_COULDNT_READ_FILE; + } + if( -1 != fstat(fd, &statbuf)) { + /* we could stat it, then read out the size */ + expected_size = statbuf.st_size; + } + + /* The following is a shortcut implementation of file reading + this is both more efficient than the former call to download() and + it avoids problems with select() and recv() on file descriptors + in Winsock */ + ProgressInit (data, expected_size); + while (1) { + nread = read(fd, buf, BUFSIZE-1); + + if (0 <= nread) + buf[nread] = 0; + + if (nread <= 0) + break; + bytecount += nread; + /* NOTE: The following call to fwrite does CR/LF translation on + Windows systems if the target is stdout. Use -O or -o parameters + to prevent CR/LF translation (this then goes to a binary mode + file descriptor). */ + if(nread != data->fwrite (buf, 1, nread, data->out)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + now = tvnow(); + ProgressShow (data, bytecount, start, now, FALSE); + } + now = tvnow(); + ProgressShow (data, bytecount, start, now, TRUE); + + close(fd); + + return URG_OK; +} diff --git a/lib/file.h b/lib/file.h new file mode 100644 index 000000000..eeaeef4f4 --- /dev/null +++ b/lib/file.h @@ -0,0 +1,45 @@ +#ifndef __FILE_H +#define __FILE_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError file(struct UrlData *data, char *path, long *bytecountp); + +#endif diff --git a/lib/formdata b/lib/formdata Binary files differnew file mode 100755 index 000000000..dc8e9e803 --- /dev/null +++ b/lib/formdata diff --git a/lib/formdata.c b/lib/formdata.c new file mode 100644 index 000000000..eff0212e4 --- /dev/null +++ b/lib/formdata.c @@ -0,0 +1,617 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* + Debug the form generator stand-alone by compiling this source file with: + + gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c + + run the 'formdata' executable and make sure the output is ok! + + try './formdata "name=Daniel" "poo=noo" "foo=bar"' and similarly + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <time.h> + +#include "setup.h" +#include <curl/curl.h> +#include "formdata.h" + +/* Length of the random boundary string. The risk of this being used + in binary data is very close to zero, 64^32 makes + 6277101735386680763835789423207666416102355444464034512896 + combinations... */ +#define BOUNDARY_LENGTH 32 + +/* What kind of Content-Type to use on un-specified files with unrecognized + extensions. */ +#define HTTPPOST_CONTENTTYPE_DEFAULT "text/plain" + +/* This is a silly duplicate of the function in main.c to enable this source + to compile stand-alone for better debugging */ +static void GetStr(char **string, + char *value) +{ + if(*string) + free(*string); + *string = strdup(value); +} + +/*************************************************************************** + * + * FormParse() + * + * Reads a 'name=value' paramter 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>'. + * + * 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' + * + ***************************************************************************/ + +int curl_FormParse(char *input, + struct HttpPost **httppost, + struct HttpPost **last_post) +{ + return FormParse(input, httppost, last_post); +} + +#define FORM_FILE_SEPARATOR ',' +#define FORM_TYPE_SEPARATOR ';' + +int FormParse(char *input, + struct HttpPost **httppost, + struct HttpPost **last_post) +{ + /* 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[1024]=""; + char major[128]; + char minor[128]; + long flags = 0; + char *contp; + char *type = NULL; + char *prevtype = NULL; + char *sep; + char *sep2; + struct HttpPost *post; + struct HttpPost *subpost; /* a sub-node */ + unsigned int i; + + if(1 <= sscanf(input, "%255[^ =] = %1023[^\n]", name, contents)) { + /* the input was using the correct format */ + contp = contents; + + if('@' == contp[0]) { + /* we use the @-letter to indicate file name(s) */ + + flags = HTTPPOST_FILENAME; + contp++; + + post=NULL; + + do { + /* since this was a file, it may have a content-type specifier + at the end too */ + + 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! */ + } + if(sep) { + + /* if we got here on a comma, don't do much */ + if(FORM_FILE_SEPARATOR != *sep) + type = strstr(sep+1, "type="); + else + type=NULL; + + *sep=0; /* terminate file name at separator */ + + if(type) { + type += strlen("type="); + + if(2 != sscanf(type, "%127[^/]/%127[^,\n]", + major, minor)) { + fprintf(stderr, "Illegally formatted content-type field!\n"); + return 2; /* illegal content-type syntax! */ + } + /* now point beyond the content-type specifier */ + sep = type + strlen(major)+strlen(minor)+1; + + /* find the following comma */ + sep=strchr(sep, FORM_FILE_SEPARATOR); + } + } + else { + type=NULL; + sep=strchr(contp, FORM_FILE_SEPARATOR); + } + if(sep) { + /* the next file name starts here */ + *sep =0; + sep++; + } + if(!type) { + /* + * No type was specified, we scan through a few well-known + * extensions and pick the first we match! + */ + struct ContentType { + char *extension; + char *type; + }; + static struct ContentType ctts[]={ + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".txt", "text/plain"}, + {".html", "text/plain"} + }; + + if(prevtype) + /* default to the previously set/used! */ + type = prevtype; + else + /* It seems RFC1867 defines no Content-Type to default to + text/plain so we don't actually need to set this: */ + type = HTTPPOST_CONTENTTYPE_DEFAULT; + + for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) { + if(strlen(contp) >= strlen(ctts[i].extension)) { + if(strequal(contp + + strlen(contp) - strlen(ctts[i].extension), + ctts[i].extension)) { + type = ctts[i].type; + break; + } + } + } + /* we have a type by now */ + } + + if(NULL == post) { + /* For the first file name, we allocate and initiate the main list + node */ + + post = (struct HttpPost *)malloc(sizeof(struct HttpPost)); + if(post) { + memset(post, 0, sizeof(struct HttpPost)); + GetStr(&post->name, name); /* get the name */ + GetStr(&post->contents, contp); /* get the contents */ + post->flags = flags; + if(type) { + GetStr(&post->contenttype, type); /* get type */ + prevtype=post->contenttype; /* point to the allocated string! */ + } + /* make the previous point to this */ + if(*last_post) + (*last_post)->next = post; + else + (*httppost) = post; + + (*last_post) = post; + } + + } + else { + /* we add a file name to the previously allocated node, known as + 'post' now */ + subpost =(struct HttpPost *)malloc(sizeof(struct HttpPost)); + if(subpost) { + memset(subpost, 0, sizeof(struct HttpPost)); + GetStr(&subpost->name, name); /* get the name */ + GetStr(&subpost->contents, contp); /* get the contents */ + subpost->flags = flags; + if(type) { + GetStr(&subpost->contenttype, type); /* get type */ + prevtype=subpost->contenttype; /* point to the allocated string! */ + } + /* now, point our 'more' to the original 'more' */ + subpost->more = post->more; + + /* then move the original 'more' to point to ourselves */ + post->more = subpost; + } + } + contp = sep; /* move the contents pointer to after the separator */ + } while(sep && *sep); /* loop if there's another file name */ + } + else { + post = (struct HttpPost *)malloc(sizeof(struct HttpPost)); + if(post) { + memset(post, 0, sizeof(struct HttpPost)); + GetStr(&post->name, name); /* get the name */ + GetStr(&post->contents, contp); /* get the contents */ + post->flags = 0; + + /* make the previous point to this */ + if(*last_post) + (*last_post)->next = post; + else + (*httppost) = post; + + (*last_post) = post; + } + + } + + } + else { + fprintf(stderr, "Illegally formatted input field!\n"); + return 1; + } + return 0; +} + +static int AddFormData(struct FormData **formp, + void *line, + long length) +{ + struct FormData *newform = (struct FormData *) + malloc(sizeof(struct FormData)); + newform->next = NULL; + + /* we make it easier for plain strings: */ + if(!length) + length = strlen((char *)line); + + newform->line = (char *)malloc(length+1); + memcpy(newform->line, line, length+1); + newform->length = length; + + if(*formp) { + (*formp)->next = newform; + *formp = newform; + } + else + *formp = newform; + + return length; +} + + +static int AddFormDataf(struct FormData **formp, + char *fmt, ...) +{ + char s[1024]; + va_list ap; + va_start(ap, fmt); + vsprintf(s, fmt, ap); + va_end(ap); + + return AddFormData(formp, s, 0); +} + + +char *MakeFormBoundary(void) +{ + char *retstring; + static int randomizer=0; /* this is just so that two boundaries within + the same form won't be identical */ + int i; + + static char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + retstring = (char *)malloc(BOUNDARY_LENGTH); + + if(!retstring) + return NULL; /* failed */ + + srand(time(NULL)+randomizer++); /* seed */ + + strcpy(retstring, "curl"); /* bonus commercials 8*) */ + + for(i=4; i<(BOUNDARY_LENGTH-1); i++) { + retstring[i] = table64[rand()%64]; + } + retstring[BOUNDARY_LENGTH-1]=0; /* zero terminate */ + + return retstring; +} + + +void FormFree(struct FormData *form) +{ + struct FormData *next; + do { + next=form->next; /* the following form line */ + free(form->line); /* free the line */ + free(form); /* free the struct */ + + } while(form=next); /* continue */ +} + +struct FormData *getFormData(struct HttpPost *post, + int *sizep) +{ + struct FormData *form = NULL; + struct FormData *firstform; + + struct HttpPost *file; + + int size =0; + char *boundary; + char *fileboundary=NULL; + + if(!post) + return NULL; /* no input => no output! */ + + boundary = MakeFormBoundary(); + + /* Make the first line of the output */ + AddFormDataf(&form, + "Content-Type: multipart/form-data;" + " boundary=%s\r\n", + boundary); + /* we DO NOT count that line since that'll be part of the header! */ + + firstform = form; + + do { + + /* boundary */ + size += AddFormDataf(&form, "\r\n--%s\r\n", boundary); + + size += AddFormDataf(&form, + "Content-Disposition: form-data; name=\"%s\"", + post->name); + + if(post->more) { + /* If used, this is a link to more file names, we must then do + the magic to include several files with the same field name */ + + fileboundary = MakeFormBoundary(); + + size += AddFormDataf(&form, + "\r\nContent-Type: multipart/mixed," + " boundary=%s\r\n", + fileboundary); + } + + file = post; + + do { + if(post->more) { + /* if multiple-file */ + size += AddFormDataf(&form, + "\r\n--%s\r\nContent-Disposition: attachment; filename=\"%s\"", + fileboundary, file->contents); + } + else if(post->flags & HTTPPOST_FILENAME) { + size += AddFormDataf(&form, + "; filename=\"%s\"", + post->contents); + } + + if(file->contenttype) { + /* we have a specified type */ + size += AddFormDataf(&form, + "\r\nContent-Type: %s", + file->contenttype); + } + if(file->contenttype && + !strnequal("text/", file->contenttype, 5)) { + /* this is not a text content, mention our binary encoding */ + size += AddFormDataf(&form, + "\r\nContent-Transfer-Encoding: binary"); + } + + + size += AddFormDataf(&form, + "\r\n\r\n"); + + if(post->flags & HTTPPOST_FILENAME) { + /* we should include the contents from the specified file */ + FILE *fileread; + char buffer[1024]; + int nread; + + fileread = strequal("-", file->contents)?stdin: + /* binary read for win32 crap */ + fopen(file->contents, "rb"); + if(fileread) { + while((nread = fread(buffer, 1, 1024, fileread))) { + size += AddFormData(&form, + buffer, + nread); + } + if(fileread != stdin) + fclose(fileread); + } + else { + size += AddFormDataf(&form, "[File wasn't found by client]"); + } + } + else { + /* include the contents we got */ + size += AddFormDataf(&form, + post->contents); + } + } while((file = file->more)); /* for each specified file for this field */ + + if(post->more) { + /* this was a multiple-file inclusion, make a termination file + boundary: */ + size += AddFormDataf(&form, + "\r\n--%s--", + fileboundary); + free(fileboundary); + } + + } while((post=post->next)); /* for each field */ + + /* end-boundary for everything */ + size += AddFormDataf(&form, + "\r\n--%s--\r\n", + boundary); + + *sizep = size; + + free(boundary); + + return firstform; +} + +int FormInit(struct Form *form, struct FormData *formdata ) +{ + form->data = formdata; + form->sent = 0; + + if(!formdata) + return 1; /* error */ + + return 0; +} + +/* fread() emulation */ +int FormReader(char *buffer, + size_t size, + size_t nitems, + FILE *mydata) +{ + struct Form *form; + int wantedsize; + int gotsize; + + form=(struct Form *)mydata; + + wantedsize = size * nitems; + + if(!form->data) + return 0; /* nothing, error, empty */ + + do { + + if( (form->data->length - form->sent ) > wantedsize ) { + + memcpy(buffer, form->data->line + form->sent, wantedsize); + + form->sent += wantedsize; + + return wantedsize; + } + + memcpy(buffer, + form->data->line + form->sent, + gotsize = (form->data->length - form->sent) ); + + form->sent = 0; + + form->data = form->data->next; /* advance */ + + } while(!gotsize && form->data); + /* If we got an empty line and we have more data, we proceed to the next + line immediately to avoid returning zero before we've reached the end. + This is the bug reported November 22 1999 on curl 6.3. (Daniel) */ + + return gotsize; +} + + +#ifdef _FORM_DEBUG + +int main(int argc, char **argv) +{ +#if 0 + char *testargs[]={ + "name1 = data in number one", + "name2 = number two data", + "test = @upload" + }; +#endif + int i; + char *nextarg; + struct HttpPost *httppost=NULL; + struct HttpPost *last_post=NULL; + struct HttpPost *post; + int size; + int nread; + char buffer[4096]; + + struct FormData *form; + struct Form formread; + + for(i=1; i<argc; i++) { + + if( FormParse( argv[i], + &httppost, + &last_post)) { + fprintf(stderr, "Illegally formatted input field: '%s'!\n", + argv[i]); + return 1; + } + } + + form=getFormData(httppost, &size); + + FormInit(&formread, form); + + while(nread = FormReader(buffer, 1, sizeof(buffer), (FILE *)&formread)) { + fwrite(buffer, nread, 1, stderr); + } + + fprintf(stderr, "size: %d\n", size); + + return 0; +} + +#endif diff --git a/lib/formdata.h b/lib/formdata.h new file mode 100644 index 000000000..6b08a05b4 --- /dev/null +++ b/lib/formdata.h @@ -0,0 +1,103 @@ +#ifndef __FORMDATA_H +#define __FORMDATA_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * Contributor(s): + * Rafael Sagula <sagula@inf.ufrgs.br> + * Sampo Kellomaki <sampo@iki.fi> + * Linas Vepstas <linas@linas.org> + * Bjorn Reese <breese@imada.ou.dk> + * Johan Anderson <johan@homemail.com> + * Kjell Ericson <Kjell.Ericson@haxx.nu> + * Troy Engel <tengel@palladium.net> + * Ryan Nelson <ryan@inch.com> + * Bjorn Stenberg <Bjorn.Stenberg@haxx.nu> + * Angus Mackay <amackay@gus.ml.org> + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + * $Log$ + * Revision 1.1 1999-12-29 14:21:22 bagder + * Initial revision + * + * Revision 1.4 1999/09/06 06:59:40 dast + * Changed email info + * + * Revision 1.3 1999/08/13 07:34:47 dast + * Changed the URL in the header + * + * Revision 1.2 1999/07/30 12:59:47 dast + * FormFree() was added to properly cleanup after a form was posted. + * + * Revision 1.1.1.1 1999/03/11 22:23:34 dast + * Imported sources + * + ****************************************************************************/ +/* plain and simple linked list with lines to send */ +struct FormData { + struct FormData *next; + char *line; + long length; +}; + +struct Form { + struct FormData *data; /* current form line to send */ + int sent; /* number of bytes of the current line that has already + been sent in a previous invoke */ +}; + +int FormParse(char *string, + struct HttpPost **httppost, + struct HttpPost **last_post); + +int FormInit(struct Form *form, struct FormData *formdata ); + +struct FormData *getFormData(struct HttpPost *post, + int *size); + +/* fread() emulation */ +int FormReader(char *buffer, + size_t size, + size_t nitems, + FILE *mydata); + +char *MakeFormBoundary(void); + +void FormFree(struct FormData *); + +#endif diff --git a/lib/ftp.c b/lib/ftp.c new file mode 100644 index 000000000..d62891298 --- /dev/null +++ b/lib/ftp.c @@ -0,0 +1,1046 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#else /* some kind of unix */ +#include <sys/socket.h> +#include <netinet/in.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <sys/utsname.h> +#include <netdb.h> +#endif + +#if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__) +#include <errno.h> +#endif + + +#include <curl/curl.h> +#include "urldata.h" +#include "sendf.h" + +#include "if2ip.h" +#include "hostip.h" +#include "progress.h" +#include "upload.h" +#include "download.h" + + +/* returns last node in linked list */ +static struct curl_slist *slist_get_last(struct curl_slist *list) +{ + struct curl_slist *item; + + /* if caller passed us a NULL, return now */ + if (!list) + return NULL; + + /* loop through to find the last item */ + item = list; + while (item->next) { + item = item->next; + } + return item; +} + +/* append a struct to the linked list. It always retunrs the address of the + * first record, so that you can sure this function as an initialization + * function as well as an append function. If you find this bothersome, + * then simply create a separate _init function and call it appropriately from + * within the proram. */ +struct curl_slist *curl_slist_append(struct curl_slist *list, char *data) +{ + struct curl_slist *last; + struct curl_slist *new_item; + + new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist)); + if (new_item) { + new_item->next = NULL; + new_item->data = strdup(data); + } + else { + fprintf(stderr, "Cannot allocate memory for QUOTE list.\n"); + exit(-1); + } + + if (list) { + last = slist_get_last(list); + last->next = new_item; + return list; + } + + /* if this is the first item, then new_item *is* the list */ + return new_item; +} + +/* be nice and clean up resources */ +void curl_slist_free_all(struct curl_slist *list) +{ + struct curl_slist *next; + struct curl_slist *item; + + if (!list) + return; + + item = list; + do { + next = item->next; + + if (item->data) { + free(item->data); + } + free(item); + item = next; + } while (next); +} + + +static UrgError AllowServerConnect(struct UrlData *data, + int sock) +{ + fd_set rdset; + struct timeval dt; + + FD_ZERO(&rdset); + + FD_SET(sock, &rdset); + + /* we give the server 10 seconds to connect to us */ + dt.tv_sec = 10; + dt.tv_usec = 0; + + switch ( select(sock+1, &rdset, NULL, NULL, &dt)) { + case -1: /* error */ + /* let's die here */ + failf(data, "Error while waiting for server connect"); + return URG_FTP_PORT_FAILED; + case 0: /* timeout */ + /* let's die here */ + failf(data, "Timeout while waiting for server connect"); + return URG_FTP_PORT_FAILED; + default: + /* we have received data here */ + { + int s; + size_t size = sizeof(struct sockaddr_in); + struct sockaddr_in add; + + getsockname(sock, (struct sockaddr *) &add, (int *)&size); + s=accept(sock, (struct sockaddr *) &add, (int *)&size); + + if( -1 == s) { + /* DIE! */ + failf(data, "Error accept()ing server connect"); + return URG_FTP_PORT_FAILED; + } + infof(data, "Connection accepted from server\n"); + + data->secondarysocket = s; + } + break; + } + return URG_OK; +} + + +/* --- parse FTP server responses --- */ + +#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \ + isdigit((int)line[2]) && (' ' == line[3])) + +static int GetLastResponse(int sockfd, char *buf, + struct UrlData *data) +{ + int nread; + int read_rc=1; + char *ptr; + do { + ptr=buf; + + /* get us a full line, terminated with a newline */ + for(nread=0; + (nread<BUFSIZE) && read_rc; + nread++, ptr++) { +#ifdef USE_SSLEAY + if (data->use_ssl) { + read_rc = SSL_read(data->ssl, ptr, 1); + } + else { +#endif + read_rc = sread(sockfd, ptr, 1); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + if (*ptr == '\n') + break; + } + *ptr=0; /* zero terminate */ + + if(data->conf & CONF_VERBOSE) { + fputs("< ", data->err); + fwrite(buf, 1, nread, data->err); + fputs("\n", data->err); + } + } while(read_rc && + (nread<4 || !lastline(buf)) ); + return nread; +} + +/* -- who are we? -- */ +char *getmyhost(void) +{ + static char myhost[256]; +#if !defined(WIN32) && !defined(HAVE_UNAME) && !defined(HAVE_GETHOSTNAME) + /* We have no means of finding the local host name! */ + strcpy(myhost, "localhost"); +#endif +#if defined(WIN32) || !defined(HAVE_UNAME) + gethostname(myhost, 256); +#else + struct utsname ugnm; + + if (uname(&ugnm) < 0) + return "localhost"; + + (void) strncpy(myhost, ugnm.nodename, 255); + myhost[255] = '\0'; +#endif + return myhost; +} + +#if 0 +/* + * URLfix() + * + * This function returns a string converted FROM the input URL format to a + * format that is more likely usable for the remote server. That is, all + * special characters (found as %XX-codes) will be eascaped with \<letter>. + */ + +static char *URLfix(char *string) +{ + /* The length of the new string can't be longer than twice the original + string, if all letters are '+'... */ + int alloc = strlen(string)*2; + char *ns = malloc(alloc); + unsigned char in; + int index=0; + int hex; + + while(*string) { + in = *string; + switch(in) { + case '+': + ns[index++] = '\\'; + ns[index++] = ' '; + string++; + continue; + + case '%': + /* encoded part */ + if(sscanf(string+1, "%02X", &hex)) { + ns[index++] = '\\'; + ns[index++] = hex; + string+=3; + continue; + } + /* FALLTHROUGH */ + default: + ns[index++] = in; + string++; + } + } + ns[index]=0; /* terminate it */ + return ns; +} +#endif + +static +UrgError _ftp(struct UrlData *data, + long *bytecountp, + char *ftpuser, + char *ftppasswd, + char *ppath) +{ + /* this is FTP and no proxy */ + size_t nread; + UrgError result; + char *buf = data->buffer; /* this is our buffer */ + /* for the ftp PORT mode */ + int portsock=-1; + struct sockaddr_in serv_addr; + + struct curl_slist *qitem; /* QUOTE item */ + + /* The first thing we do is wait for the "220*" line: */ + nread = GetLastResponse(data->firstsocket, buf, data); + if(strncmp(buf, "220", 3)) { + failf(data, "This doesn't seem like a nice ftp-server response"); + return URG_FTP_WEIRD_SERVER_REPLY; + } + + /* send USER */ + sendf(data->firstsocket, data, "USER %s\r\n", ftpuser); + + /* wait for feedback */ + nread = GetLastResponse(data->firstsocket, buf, data); + + if(!strncmp(buf, "530", 3)) { + /* 530 User ... access denied + (the server denies to log the specified user) */ + failf(data, "Access denied: %s", &buf[4]); + return URG_FTP_ACCESS_DENIED; + } + else if(!strncmp(buf, "331", 3)) { + /* 331 Password required for ... + (the server requires to send the user's password too) */ + sendf(data->firstsocket, data, "PASS %s\r\n", ftppasswd); + nread = GetLastResponse(data->firstsocket, buf, data); + + if(!strncmp(buf, "530", 3)) { + /* 530 Login incorrect. + (the username and/or the password are incorrect) */ + failf(data, "the username and/or the password are incorrect"); + return URG_FTP_USER_PASSWORD_INCORRECT; + } + else if(!strncmp(buf, "230", 3)) { + /* 230 User ... logged in. + (user successfully logged in) */ + + infof(data, "We have successfully logged in\n"); + } + else { + failf(data, "Odd return code after PASS"); + return URG_FTP_WEIRD_PASS_REPLY; + } + } + else if(! strncmp(buf, "230", 3)) { + /* 230 User ... logged in. + (the user logged in without password) */ + infof(data, "We have successfully logged in\n"); + } + else { + failf(data, "Odd return code after USER"); + return URG_FTP_WEIRD_USER_REPLY; + } + + /* Send any QUOTE strings? */ + if(data->quote) { + qitem = data->quote; + /* Send all QUOTE strings in same order as on command-line */ + while (qitem) { + /* Send string */ + if (qitem->data) { + sendf(data->firstsocket, data, "%s\r\n", qitem->data); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if (buf[0] != '2') { + failf(data, "QUOT string not accepted: %s", + qitem->data); + return URG_FTP_QUOTE_ERROR; + } + } + qitem = qitem->next; + } + } + + /* If we have selected NOBODY, it means that we only want file information. + Which in FTP can't be much more than the file size! */ + if(data->conf & CONF_NOBODY) { + /* The SIZE command is _not_ RFC 959 specified, and therefor many servers + may not support it! It is however the only way we have to get a file's + size! */ + int filesize; + sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "213", 3)) { + failf(data, "Couldn't get file size: %s", buf+4); + return URG_FTP_COULDNT_GET_SIZE; + } + /* get the size from the ascii string: */ + filesize = atoi(buf+4); + + sprintf(buf, "Content-Length: %d\n", filesize); + + if(strlen(buf) != data->fwrite(buf, 1, strlen(buf), data->out)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + if(data->writeheader) { + /* the header is requested to be written to this file */ + if(strlen(buf) != fwrite (buf, 1, strlen(buf), data->writeheader)) { + failf (data, "Failed writing output"); + return URG_WRITE_ERROR; + } + } + return URG_OK; + } + + /* We have chosen to use the PORT command */ + if(data->conf & CONF_FTPPORT) { + struct sockaddr_in sa; + struct hostent *h=NULL; + size_t size; + unsigned short porttouse; + + char *myhost=NULL; + + if(data->ftpport) { + myhost = if2ip(data->ftpport); + if(myhost) { + h = GetHost(data, myhost); + } + else { + if(strlen(data->ftpport)>1) + h = GetHost(data, data->ftpport); + if(h) + myhost=data->ftpport; + } + } + if(!myhost) { + myhost = getmyhost(); + h=GetHost(data, myhost); + } + infof(data, "We connect from %s\n", myhost); + + if ( h ) { + if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) { + memset((char *)&sa, 0, sizeof(sa)); + memcpy((char *)&sa.sin_addr, + h->h_addr, + h->h_length); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = INADDR_ANY; + sa.sin_port = 0; + size = sizeof(sa); + + if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) { + /* we succeeded to bind */ + struct sockaddr_in add; + size = sizeof(add); + + if(getsockname(portsock, (struct sockaddr *) &add, + (int *)&size)<0) { + failf(data, "getsockname() failed"); + return URG_FTP_PORT_FAILED; + } + porttouse = ntohs(add.sin_port); + + if ( listen(portsock, 1) < 0 ) { + failf(data, "listen(2) failed on socket"); + return URG_FTP_PORT_FAILED; + } + } + else { + failf(data, "bind(2) failed on socket"); + return URG_FTP_PORT_FAILED; + } + } + else { + failf(data, "socket(2) failed (%s)"); + return URG_FTP_PORT_FAILED; + } + } + else { + failf(data, "could't find my own IP address (%s)", myhost); + return URG_FTP_PORT_FAILED; + } + { + struct in_addr in; + unsigned short ip[5]; + (void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr)); + sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3]); + sendf(data->firstsocket, data, "PORT %d,%d,%d,%d,%d,%d\n", + ip[0], ip[1], ip[2], ip[3], + porttouse >> 8, + porttouse & 255); + } + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "200", 3)) { + failf(data, "Server does not grok PORT, try without it!"); + return URG_FTP_PORT_FAILED; + } + } + else { /* we use the PASV command */ + + sendf(data->firstsocket, data, "PASV\r\n"); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "227", 3)) { + failf(data, "Odd return code after PASV"); + return URG_FTP_WEIRD_PASV_REPLY; + } + else { + int ip[4]; + int port[2]; + unsigned short newport; + char newhost[32]; + struct hostent *he; + char *str=buf; + + /* + * New 227-parser June 3rd 1999. + * It now scans for a sequence of six comma-separated numbers and + * will take them as IP+port indicators. + * + * Found reply-strings include: + * "227 Entering Passive Mode (127,0,0,1,4,51)" + * "227 Data transfer will passively listen to 127,0,0,1,4,51" + * "227 Entering passive mode. 127,0,0,1,4,51" + */ + + while(*str) { + if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d", + &ip[0], &ip[1], &ip[2], &ip[3], + &port[0], &port[1])) + break; + str++; + } + if(!*str) { + failf(data, "Couldn't interpret this 227-reply: %s", buf); + return URG_FTP_WEIRD_227_FORMAT; + } + sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + he = GetHost(data, newhost); + if(!he) { + failf(data, "Can't resolve new host %s", newhost); + return URG_FTP_CANT_GET_HOST; + } + + + newport = (port[0]<<8) + port[1]; + data->secondarysocket = socket(AF_INET, SOCK_STREAM, 0); + + memset((char *) &serv_addr, '\0', sizeof(serv_addr)); + memcpy((char *)&(serv_addr.sin_addr), he->h_addr, he->h_length); + serv_addr.sin_family = he->h_addrtype; + serv_addr.sin_port = htons(newport); + + if(data->conf & CONF_VERBOSE) { + struct in_addr in; +#if 1 + struct hostent * answer; + + unsigned long address; +#if defined(HAVE_INET_ADDR) || defined(WIN32) + address = inet_addr(newhost); + answer = gethostbyaddr((char *) &address, sizeof(address), + AF_INET); +#else + answer = NULL; +#endif + (void) memcpy(&in.s_addr, *he->h_addr_list, sizeof (in.s_addr)); + infof(data, "Connecting to %s (%s) port %u\n", + answer?answer->h_name:newhost, inet_ntoa(in), newport); +#else + (void) memcpy(&in.s_addr, *he->h_addr_list, sizeof (in.s_addr)); + infof(data, "Connecting to %s (%s) port %u\n", + he->h_name, inet_ntoa(in), newport); +#endif + } + + if (connect(data->secondarysocket, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) { + switch(errno) { +#ifdef ECONNREFUSED + /* this should be made nicer */ + case ECONNREFUSED: + failf(data, "Connection refused by ftp server"); + break; +#endif +#ifdef EINTR + case EINTR: + failf(data, "Connection timeouted to ftp server"); + break; +#endif + default: + failf(data, "Can't connect to ftp server"); + break; + } + return URG_FTP_CANT_RECONNECT; + } + } + + } + /* we have the (new) data connection ready */ + + if(data->conf & CONF_UPLOAD) { + + /* Set type to binary (unless specified ASCII) */ + sendf(data->firstsocket, data, "TYPE %s\r\n", + (data->conf&CONF_FTPASCII)?"A":"I"); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "200", 3)) { + failf(data, "Couldn't set %s mode", + (data->conf&CONF_FTPASCII)?"ASCII":"binary"); + return (data->conf&CONF_FTPASCII)? URG_FTP_COULDNT_SET_ASCII: + URG_FTP_COULDNT_SET_BINARY; + } + + if(data->resume_from) { + /* we're about to continue the uploading of a file */ + /* 1. get already existing file's size. We use the SIZE + command for this which may not exist in the server! + The SIZE command is not in RFC959. */ + + /* 2. This used to set REST. But since we can do append, we + don't another ftp command. We just skip the source file + offset and then we APPEND the rest on the file instead */ + + /* 3. pass file-size number of bytes in the source file */ + /* 4. lower the infilesize counter */ + /* => transfer as usual */ + + if(data->resume_from < 0 ) { + /* we could've got a specified offset from the command line, + but now we know we didn't */ + + sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "213", 3)) { + failf(data, "Couldn't get file size: %s", buf+4); + return URG_FTP_COULDNT_GET_SIZE; + } + + /* get the size from the ascii string: */ + data->resume_from = atoi(buf+4); + } + + if(data->resume_from) { + /* do we still game? */ + int passed=0; +#if 0 + /* Set resume file transfer offset */ + infof(data, "Instructs server to resume from offset %d\n", + data->resume_from); + + sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "350", 3)) { + failf(data, "Couldn't use REST: %s", buf+4); + return URG_FTP_COULDNT_USE_REST; + } +#else + /* enable append instead */ + data->conf |= CONF_FTPAPPEND; +#endif + /* Now, let's read off the proper amount of bytes from the + input. If we knew it was a proper file we could've just + fseek()ed but we only have a stream here */ + do { + int readthisamountnow = (data->resume_from - passed); + int actuallyread; + + if(readthisamountnow > BUFSIZE) + readthisamountnow = BUFSIZE; + + actuallyread = + data->fread(data->buffer, 1, readthisamountnow, data->in); + + passed += actuallyread; + if(actuallyread != readthisamountnow) { + failf(data, "Could only read %d bytes from the input\n", + passed); + return URG_FTP_COULDNT_USE_REST; + } + } + while(passed != data->resume_from); + + /* now, decrease the size of the read */ + if(data->infilesize>0) { + data->infilesize -= data->resume_from; + + if(data->infilesize <= 0) { + infof(data, "File already completely uploaded\n"); + return URG_OK; + } + } + /* we've passed, proceed as normal */ + } + } + + /* Send everything on data->in to the socket */ + if(data->conf & CONF_FTPAPPEND) + /* we append onto the file instead of rewriting it */ + sendf(data->firstsocket, data, "APPE %s\r\n", ppath); + else + sendf(data->firstsocket, data, "STOR %s\r\n", ppath); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(atoi(buf)>=400) { + failf(data, "Failed FTP upload:%s", buf+3); + /* oops, we never close the sockets! */ + return URG_FTP_COULDNT_STOR_FILE; + } + + if(data->conf & CONF_FTPPORT) { + result = AllowServerConnect(data, portsock); + if( result ) + return result; + } + + *bytecountp=0; + + /* When we know we're uploading a specified file, we can get the file + size prior to the actual upload. */ + + ProgressInit(data, data->infilesize); + result = Upload(data, data->secondarysocket, bytecountp); + if(result) + return result; + + if((-1 != data->infilesize) && (data->infilesize != *bytecountp)) { + failf(data, "Wrote only partial file (%d out of %d bytes)", + *bytecountp, data->infilesize); + return URG_PARTIAL_FILE; + } + } + else { + /* Retrieve file or directory */ + bool dirlist=FALSE; + long downloadsize=-1; + + if(data->conf&CONF_RANGE && data->range) { + int from, to; + int totalsize=-1; + char *ptr; + char *ptr2; + + from=strtol(data->range, &ptr, 0); + while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-'))) + ptr++; + to=strtol(ptr, &ptr2, 0); + if(ptr == ptr2) { + /* we didn't get any digit */ + to=-1; + } + if(-1 == to) { + /* X - */ + data->resume_from = from; + } + else if(from < 0) { + /* -Y */ + from = 0; + to = -from; + totalsize = to-from; + data->maxdownload = totalsize; + } + else { + /* X- */ + totalsize = to-from; + data->maxdownload = totalsize; + } + infof(data, "range-download from %d to %d, totally %d bytes\n", + from, to, totalsize); + } + + if(!ppath[0]) + /* make sure this becomes a valid name */ + ppath="./"; + + if((data->conf & CONF_FTPLISTONLY) || + ('/' == ppath[strlen(ppath)-1] )) { + /* The specified path ends with a slash, and therefore we think this + is a directory that is requested, use LIST. But before that we + need to set ASCII transfer mode. */ + dirlist = TRUE; + + /* Set type to ASCII */ + sendf(data->firstsocket, data, "TYPE A\r\n"); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "200", 3)) { + failf(data, "Couldn't set ascii mode"); + return URG_FTP_COULDNT_SET_ASCII; + } + + /* if this output is to be machine-parsed, the NLST command will be + better used since the LIST command output is not specified or + standard in any way */ + + sendf(data->firstsocket, data, "%s %s\r\n", + data->customrequest?data->customrequest: + (data->conf&CONF_FTPLISTONLY?"NLST":"LIST"), + ppath); + } + else { + /* Set type to binary (unless specified ASCII) */ + sendf(data->firstsocket, data, "TYPE %s\r\n", + (data->conf&CONF_FTPASCII)?"A":"I"); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "200", 3)) { + failf(data, "Couldn't set %s mode", + (data->conf&CONF_FTPASCII)?"ASCII":"binary"); + return (data->conf&CONF_FTPASCII)? URG_FTP_COULDNT_SET_ASCII: + URG_FTP_COULDNT_SET_BINARY; + } + + if(data->resume_from) { + + /* Daniel: (August 4, 1999) + * + * We start with trying to use the SIZE command to figure out the size + * of the file we're gonna get. If we can get the size, this is by far + * the best way to know if we're trying to resume beyond the EOF. */ + + sendf(data->firstsocket, data, "SIZE %s\r\n", ppath); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "213", 3)) { + infof(data, "server doesn't support SIZE: %s", buf+4); + /* We couldn't get the size and therefore we can't know if there + really is a part of the file left to get, although the server + will just close the connection when we start the connection so it + won't cause us any harm, just not make us exit as nicely. */ + } + else { + int foundsize=atoi(buf+4); + /* We got a file size report, so we check that there actually is a + part of the file left to get, or else we go home. */ + if(foundsize <= data->resume_from) { + failf(data, "Offset (%d) was beyond file size (%d)", + data->resume_from, foundsize); + return URG_FTP_BAD_DOWNLOAD_RESUME; + } + /* Now store the number of bytes we are expected to download */ + downloadsize = foundsize-data->resume_from; + } + + /* Set resume file transfer offset */ + infof(data, "Instructs server to resume from offset %d\n", + data->resume_from); + + sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from); + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(strncmp(buf, "350", 3)) { + failf(data, "Couldn't use REST: %s", buf+4); + return URG_FTP_COULDNT_USE_REST; + } + } + + sendf(data->firstsocket, data, "RETR %s\r\n", ppath); + } + + nread = GetLastResponse(data->firstsocket, buf, data); + + if(!strncmp(buf, "150", 3) || !strncmp(buf, "125", 3)) { + + /* + A; + 150 Opening BINARY mode data connection for /etc/passwd (2241 + bytes). (ok, the file is being transfered) + + B: + 150 Opening ASCII mode data connection for /bin/ls + + C: + 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). + + D: + 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes). + + E: + 125 Data connection already open; Transfer starting. */ + + int size=-1; /* default unknown size */ + + if(!dirlist && (-1 == downloadsize)) { + /* + * It seems directory listings either don't show the size or very + * often uses size 0 anyway. + * Example D above makes this parsing a little tricky + */ + char *bytes; + bytes=strstr(buf, " bytes"); + if(bytes--) { + int index=bytes-buf; + /* this is a hint there is size information in there! ;-) */ + while(--index) { + /* scan for the parenthesis and break there */ + if('(' == *bytes) + break; + /* if only skip digits, or else we're in deep trouble */ + if(!isdigit((int)*bytes)) { + bytes=NULL; + break; + } + /* one more estep backwards */ + bytes--; + } + /* only if we have nothing but digits: */ + if(bytes++) { + /* get the number! */ + size = atoi(bytes); + } + + } +#if 0 + if(2 != sscanf(buf, "%*[^(](%d bytes%c", &size, &paren)) + size=-1; +#endif + } + else if(downloadsize > -1) + size = downloadsize; + +#if 0 + if((size > -1) && (data->resume_from>0)) { + size -= data->resume_from; + if(size <= 0) { + failf(data, "Offset (%d) was beyond file size (%d)", + data->resume_from, data->resume_from+size); + return URG_PARTIAL_FILE; + } + } +#endif + + if(data->conf & CONF_FTPPORT) { + result = AllowServerConnect(data, portsock); + if( result ) + return result; + } + + infof(data, "Getting file with size: %d\n", size); + + /* FTP download: */ + result=Download(data, data->secondarysocket, size, FALSE, + bytecountp); + if(result) + return result; + + if((-1 != size) && (size != *bytecountp)) { + failf(data, "Received only partial file"); + return URG_PARTIAL_FILE; + } + else if(0 == *bytecountp) { + failf(data, "No data was received!"); + return URG_FTP_COULDNT_RETR_FILE; + } + } + else { + failf(data, "%s", buf+4); + return URG_FTP_COULDNT_RETR_FILE; + } + + } + /* end of transfer */ + ProgressEnd(data); + + /* shut down the socket to inform the server we're done */ + sclose(data->secondarysocket); + data->secondarysocket = -1; + + /* now let's see what the server says about the transfer we + just performed: */ + nread = GetLastResponse(data->firstsocket, buf, data); + + /* 226 Transfer complete */ + if(strncmp(buf, "226", 3)) { + failf(data, "%s", buf+4); + return URG_FTP_WRITE_ERROR; + } + + return URG_OK; +} + +/* -- deal with the ftp server! -- */ + +UrgError ftp(struct UrlData *data, + long *bytecountp, + char *ftpuser, + char *ftppasswd, + char *urlpath) +{ + char *realpath; + UrgError retcode; + +#if 0 + realpath = URLfix(urlpath); +#else + realpath = curl_unescape(urlpath); +#endif + if(realpath) { + retcode = _ftp(data, bytecountp, ftpuser, ftppasswd, realpath); + free(realpath); + } + else + /* then we try the original path */ + retcode = _ftp(data, bytecountp, ftpuser, ftppasswd, urlpath); + + return retcode; +} + diff --git a/lib/ftp.h b/lib/ftp.h new file mode 100644 index 000000000..b7d265927 --- /dev/null +++ b/lib/ftp.h @@ -0,0 +1,52 @@ +#ifndef __FTP_H +#define __FTP_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError ftp(struct UrlData *data, + long *bytecountp, + char *ftpuser, + char *ftppasswd, + char *ppath); + +struct curl_slist *curl_slist_append(struct curl_slist *list, char *data); +void curl_slist_free_all(struct curl_slist *list); + +#endif diff --git a/lib/getdate.c b/lib/getdate.c new file mode 100644 index 000000000..e3342ff3a --- /dev/null +++ b/lib/getdate.c @@ -0,0 +1,2101 @@ + +/* A Bison parser, made from getdate.y + by GNU Bison version 1.27 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define tAGO 257 +#define tDAY 258 +#define tDAY_UNIT 259 +#define tDAYZONE 260 +#define tDST 261 +#define tHOUR_UNIT 262 +#define tID 263 +#define tMERIDIAN 264 +#define tMINUTE_UNIT 265 +#define tMONTH 266 +#define tMONTH_UNIT 267 +#define tSEC_UNIT 268 +#define tSNUMBER 269 +#define tUNUMBER 270 +#define tYEAR_UNIT 271 +#define tZONE 272 + +#line 1 "getdate.y" + +/* +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990. +** +** This code is in the public domain and has no copyright. +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# endif +#endif + +/* Since the code of getdate.y is not included in the Emacs executable + itself, there is no need to #define static in this file. Even if + the code were included in the Emacs executable, it probably + wouldn't do any harm to #undef it here; this will only cause + problems if we try to write to a static variable, which I don't + think this code needs to do. */ +#ifdef emacs +# undef static +#endif + +#include <malloc.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#if HAVE_STDLIB_H +# include <stdlib.h> /* for `free'; used by Bison 1.27 */ +#endif + +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that + only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless + it's important to use the locale's definition of `digit' even when the + host does not conform to Posix. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#if defined (STDC_HEADERS) || defined (USG) +# include <string.h> +#endif + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +/* Some old versions of bison generate parsers that use bcopy. + That loses on systems that don't provide the function, so we have + to redefine it here. */ +#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) +# define bcopy(from, to, len) memcpy ((to), (from), (len)) +#endif + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in the same program. Note that these are only + the variables produced by yacc. If other parser generators (bison, + byacc, etc) produce additional global names that conflict at link time, + then those parser generators need to be fixed instead of adding those + names to this list. */ + +#define yymaxdepth gd_maxdepth +#define yyparse gd_parse +#define yylex gd_lex +#define yyerror gd_error +#define yylval gd_lval +#define yychar gd_char +#define yydebug gd_debug +#define yypact gd_pact +#define yyr1 gd_r1 +#define yyr2 gd_r2 +#define yydef gd_def +#define yychk gd_chk +#define yypgo gd_pgo +#define yyact gd_act +#define yyexca gd_exca +#define yyerrflag gd_errflag +#define yynerrs gd_nerrs +#define yyps gd_ps +#define yypv gd_pv +#define yys gd_s +#define yy_yys gd_yys +#define yystate gd_state +#define yytmp gd_tmp +#define yyv gd_v +#define yy_yyv gd_yyv +#define yyval gd_val +#define yylloc gd_lloc +#define yyreds gd_reds /* With YYDEBUG defined */ +#define yytoks gd_toks /* With YYDEBUG defined */ +#define yylhs gd_yylhs +#define yylen gd_yylen +#define yydefred gd_yydefred +#define yydgoto gd_yydgoto +#define yysindex gd_yysindex +#define yyrindex gd_yyrindex +#define yygindex gd_yygindex +#define yytable gd_yytable +#define yycheck gd_yycheck + +static int yylex (); +static int yyerror (); + +#define EPOCH 1970 +#define HOUR(x) ((x) * 60) + +#define MAX_BUFF_LEN 128 /* size of buffer to read the date into */ + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + const char *name; + int type; + int value; +} TABLE; + + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static const char *yyInput; +static int yyDayOrdinal; +static int yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static int yyTimezone; +static int yyDay; +static int yyHour; +static int yyMinutes; +static int yyMonth; +static int yySeconds; +static int yyYear; +static MERIDIAN yyMeridian; +static int yyRelDay; +static int yyRelHour; +static int yyRelMinutes; +static int yyRelMonth; +static int yyRelSeconds; +static int yyRelYear; + + +#line 184 "getdate.y" +typedef union { + int Number; + enum _MERIDIAN Meridian; +} YYSTYPE; +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#ifndef const +#define const +#endif +#endif +#endif + + + +#define YYFINAL 61 +#define YYFLAG -32768 +#define YYNTBASE 22 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 272 ? yytranslate[x] : 32) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 20, 2, 2, 21, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 19, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 6, 8, 10, 12, 14, 16, 19, + 24, 29, 36, 43, 45, 47, 50, 52, 55, 58, + 62, 68, 72, 76, 79, 84, 87, 91, 94, 96, + 99, 102, 104, 107, 110, 112, 115, 118, 120, 123, + 126, 128, 131, 134, 136, 139, 142, 144, 146, 147 +}; + +static const short yyrhs[] = { -1, + 22, 23, 0, 24, 0, 25, 0, 27, 0, 26, + 0, 28, 0, 30, 0, 16, 10, 0, 16, 19, + 16, 31, 0, 16, 19, 16, 15, 0, 16, 19, + 16, 19, 16, 31, 0, 16, 19, 16, 19, 16, + 15, 0, 18, 0, 6, 0, 18, 7, 0, 4, + 0, 4, 20, 0, 16, 4, 0, 16, 21, 16, + 0, 16, 21, 16, 21, 16, 0, 16, 15, 15, + 0, 16, 12, 15, 0, 12, 16, 0, 12, 16, + 20, 16, 0, 16, 12, 0, 16, 12, 16, 0, + 29, 3, 0, 29, 0, 16, 17, 0, 15, 17, + 0, 17, 0, 16, 13, 0, 15, 13, 0, 13, + 0, 16, 5, 0, 15, 5, 0, 5, 0, 16, + 8, 0, 15, 8, 0, 8, 0, 16, 11, 0, + 15, 11, 0, 11, 0, 16, 14, 0, 15, 14, + 0, 14, 0, 16, 0, 0, 10, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 200, 201, 204, 207, 210, 213, 216, 219, 222, 228, + 234, 243, 249, 261, 264, 267, 273, 277, 281, 287, + 291, 309, 315, 321, 325, 330, 334, 341, 349, 352, + 355, 358, 361, 364, 367, 370, 373, 376, 379, 382, + 385, 388, 391, 394, 397, 400, 403, 408, 441, 445 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","tAGO","tDAY", +"tDAY_UNIT","tDAYZONE","tDST","tHOUR_UNIT","tID","tMERIDIAN","tMINUTE_UNIT", +"tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tYEAR_UNIT","tZONE", +"':'","','","'/'","spec","item","time","zone","day","date","rel","relunit","number", +"o_merid", NULL +}; +#endif + +static const short yyr1[] = { 0, + 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, + 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, + 27, 27, 27, 27, 27, 27, 27, 28, 28, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 30, 31, 31 +}; + +static const short yyr2[] = { 0, + 0, 2, 1, 1, 1, 1, 1, 1, 2, 4, + 4, 6, 6, 1, 1, 2, 1, 2, 2, 3, + 5, 3, 3, 2, 4, 2, 3, 2, 1, 2, + 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, + 1, 2, 2, 1, 2, 2, 1, 1, 0, 1 +}; + +static const short yydefact[] = { 1, + 0, 17, 38, 15, 41, 44, 0, 35, 47, 0, + 48, 32, 14, 2, 3, 4, 6, 5, 7, 29, + 8, 18, 24, 37, 40, 43, 34, 46, 31, 19, + 36, 39, 9, 42, 26, 33, 45, 0, 30, 0, + 0, 16, 28, 0, 23, 27, 22, 49, 20, 25, + 50, 11, 0, 10, 0, 49, 21, 13, 12, 0, + 0 +}; + +static const short yydefgoto[] = { 1, + 14, 15, 16, 17, 18, 19, 20, 21, 54 +}; + +static const short yypact[] = {-32768, + 0, -19,-32768,-32768,-32768,-32768, -13,-32768,-32768, 30, + 15,-32768, 14,-32768,-32768,-32768,-32768,-32768,-32768, 19, +-32768,-32768, 4,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768, -6,-32768,-32768, 16,-32768, 17, + 23,-32768,-32768, 24,-32768,-32768,-32768, 27, 28,-32768, +-32768,-32768, 29,-32768, 32, -8,-32768,-32768,-32768, 50, +-32768 +}; + +static const short yypgoto[] = {-32768, +-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -5 +}; + + +#define YYLAST 51 + + +static const short yytable[] = { 60, + 22, 51, 23, 2, 3, 4, 58, 5, 45, 46, + 6, 7, 8, 9, 10, 11, 12, 13, 30, 31, + 42, 43, 32, 44, 33, 34, 35, 36, 37, 38, + 47, 39, 48, 40, 24, 41, 51, 25, 49, 50, + 26, 52, 27, 28, 56, 53, 29, 57, 55, 61, + 59 +}; + +static const short yycheck[] = { 0, + 20, 10, 16, 4, 5, 6, 15, 8, 15, 16, + 11, 12, 13, 14, 15, 16, 17, 18, 4, 5, + 7, 3, 8, 20, 10, 11, 12, 13, 14, 15, + 15, 17, 16, 19, 5, 21, 10, 8, 16, 16, + 11, 15, 13, 14, 16, 19, 17, 16, 21, 0, + 56 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/boot/apps/GeekGadgets/share/bison.simple" +/* This file comes from bison-1.27. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include <alloca.h> +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include <malloc.h> +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include <malloc.h> */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 216 "/boot/apps/GeekGadgets/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +#line 204 "getdate.y" +{ + yyHaveTime++; + ; + break;} +case 4: +#line 207 "getdate.y" +{ + yyHaveZone++; + ; + break;} +case 5: +#line 210 "getdate.y" +{ + yyHaveDate++; + ; + break;} +case 6: +#line 213 "getdate.y" +{ + yyHaveDay++; + ; + break;} +case 7: +#line 216 "getdate.y" +{ + yyHaveRel++; + ; + break;} +case 9: +#line 222 "getdate.y" +{ + yyHour = yyvsp[-1].Number; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 10: +#line 228 "getdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 11: +#line 234 "getdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yyMeridian = MER24; + yyHaveZone++; + yyTimezone = (yyvsp[0].Number < 0 + ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 + : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); + ; + break;} +case 12: +#line 243 "getdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 13: +#line 249 "getdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = MER24; + yyHaveZone++; + yyTimezone = (yyvsp[0].Number < 0 + ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 + : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); + ; + break;} +case 14: +#line 261 "getdate.y" +{ + yyTimezone = yyvsp[0].Number; + ; + break;} +case 15: +#line 264 "getdate.y" +{ + yyTimezone = yyvsp[0].Number - 60; + ; + break;} +case 16: +#line 268 "getdate.y" +{ + yyTimezone = yyvsp[-1].Number - 60; + ; + break;} +case 17: +#line 273 "getdate.y" +{ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[0].Number; + ; + break;} +case 18: +#line 277 "getdate.y" +{ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[-1].Number; + ; + break;} +case 19: +#line 281 "getdate.y" +{ + yyDayOrdinal = yyvsp[-1].Number; + yyDayNumber = yyvsp[0].Number; + ; + break;} +case 20: +#line 287 "getdate.y" +{ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 21: +#line 291 "getdate.y" +{ + /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. + The goal in recognizing YYYY/MM/DD is solely to support legacy + machine-generated dates like those in an RCS log listing. If + you want portability, use the ISO 8601 format. */ + if (yyvsp[-4].Number >= 1000) + { + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } + else + { + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } + ; + break;} +case 22: +#line 309 "getdate.y" +{ + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = yyvsp[-2].Number; + yyMonth = -yyvsp[-1].Number; + yyDay = -yyvsp[0].Number; + ; + break;} +case 23: +#line 315 "getdate.y" +{ + /* e.g. 17-JUN-1992. */ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + yyYear = -yyvsp[0].Number; + ; + break;} +case 24: +#line 321 "getdate.y" +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 25: +#line 325 "getdate.y" +{ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + ; + break;} +case 26: +#line 330 "getdate.y" +{ + yyMonth = yyvsp[0].Number; + yyDay = yyvsp[-1].Number; + ; + break;} +case 27: +#line 334 "getdate.y" +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + ; + break;} +case 28: +#line 341 "getdate.y" +{ + yyRelSeconds = -yyRelSeconds; + yyRelMinutes = -yyRelMinutes; + yyRelHour = -yyRelHour; + yyRelDay = -yyRelDay; + yyRelMonth = -yyRelMonth; + yyRelYear = -yyRelYear; + ; + break;} +case 30: +#line 352 "getdate.y" +{ + yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 31: +#line 355 "getdate.y" +{ + yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 32: +#line 358 "getdate.y" +{ + yyRelYear += yyvsp[0].Number; + ; + break;} +case 33: +#line 361 "getdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 34: +#line 364 "getdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 35: +#line 367 "getdate.y" +{ + yyRelMonth += yyvsp[0].Number; + ; + break;} +case 36: +#line 370 "getdate.y" +{ + yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 37: +#line 373 "getdate.y" +{ + yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 38: +#line 376 "getdate.y" +{ + yyRelDay += yyvsp[0].Number; + ; + break;} +case 39: +#line 379 "getdate.y" +{ + yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 40: +#line 382 "getdate.y" +{ + yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 41: +#line 385 "getdate.y" +{ + yyRelHour += yyvsp[0].Number; + ; + break;} +case 42: +#line 388 "getdate.y" +{ + yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 43: +#line 391 "getdate.y" +{ + yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 44: +#line 394 "getdate.y" +{ + yyRelMinutes += yyvsp[0].Number; + ; + break;} +case 45: +#line 397 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 46: +#line 400 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 47: +#line 403 "getdate.y" +{ + yyRelSeconds += yyvsp[0].Number; + ; + break;} +case 48: +#line 409 "getdate.y" +{ + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = yyvsp[0].Number; + else + { + if (yyvsp[0].Number>10000) + { + yyHaveDate++; + yyDay= (yyvsp[0].Number)%100; + yyMonth= (yyvsp[0].Number/100)%100; + yyYear = yyvsp[0].Number/10000; + } + else + { + yyHaveTime++; + if (yyvsp[0].Number < 100) + { + yyHour = yyvsp[0].Number; + yyMinutes = 0; + } + else + { + yyHour = yyvsp[0].Number / 100; + yyMinutes = yyvsp[0].Number % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + ; + break;} +case 49: +#line 442 "getdate.y" +{ + yyval.Meridian = MER24; + ; + break;} +case 50: +#line 446 "getdate.y" +{ + yyval.Meridian = yyvsp[0].Meridian; + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 542 "/boot/apps/GeekGadgets/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} +#line 451 "getdate.y" + + +/* Include this file down here because bison inserts code above which + may define-away `const'. We want the prototype for get_date to have + the same signature as the function definition does. */ +#include "getdate.h" + +extern struct tm *gmtime (); +extern struct tm *localtime (); +extern time_t mktime (); + +/* Month and day table. */ +static TABLE const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL, 0, 0 } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tYEAR_UNIT, 1 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tDAY_UNIT, 14 }, + { "week", tDAY_UNIT, 7 }, + { "day", tDAY_UNIT, 1 }, + { "hour", tHOUR_UNIT, 1 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL, 0, 0 } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 1 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL, 0, 0 } +}; + +/* The timezone table. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR ( 0) }, + { "wet", tZONE, HOUR ( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */ + { "wat", tZONE, HOUR ( 1) }, /* West Africa */ + { "at", tZONE, HOUR ( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR ( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR (10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR (11) }, /* Nome */ + { "idlw", tZONE, HOUR (12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR (1) }, /* Central European */ + { "met", tZONE, -HOUR (1) }, /* Middle European */ + { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ + { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR (1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */ + { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR (3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Standard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR (12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR (12) }, /* International Date Line East */ + { NULL, 0, 0 } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR ( 1) }, + { "b", tZONE, HOUR ( 2) }, + { "c", tZONE, HOUR ( 3) }, + { "d", tZONE, HOUR ( 4) }, + { "e", tZONE, HOUR ( 5) }, + { "f", tZONE, HOUR ( 6) }, + { "g", tZONE, HOUR ( 7) }, + { "h", tZONE, HOUR ( 8) }, + { "i", tZONE, HOUR ( 9) }, + { "k", tZONE, HOUR ( 10) }, + { "l", tZONE, HOUR ( 11) }, + { "m", tZONE, HOUR ( 12) }, + { "n", tZONE, HOUR (- 1) }, + { "o", tZONE, HOUR (- 2) }, + { "p", tZONE, HOUR (- 3) }, + { "q", tZONE, HOUR (- 4) }, + { "r", tZONE, HOUR (- 5) }, + { "s", tZONE, HOUR (- 6) }, + { "t", tZONE, HOUR (- 7) }, + { "u", tZONE, HOUR (- 8) }, + { "v", tZONE, HOUR (- 9) }, + { "w", tZONE, HOUR (-10) }, + { "x", tZONE, HOUR (-11) }, + { "y", tZONE, HOUR (-12) }, + { "z", tZONE, HOUR ( 0) }, + { NULL, 0, 0 } +}; + + + + +/* ARGSUSED */ +static int +yyerror (s) + char *s ATTRIBUTE_UNUSED; +{ + return 0; +} + +static int +ToHour (Hours, Meridian) + int Hours; + MERIDIAN Meridian; +{ + switch (Meridian) + { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return Hours; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours + 12; + default: + abort (); + } + /* NOTREACHED */ +} + +static int +ToYear (Year) + int Year; +{ + if (Year < 0) + Year = -Year; + + /* XPG4 suggests that years 00-68 map to 2000-2068, and + years 69-99 map to 1969-1999. */ + if (Year < 69) + Year += 2000; + else if (Year < 100) + Year += 1900; + + return Year; +} + +static int +LookupWord (buff) + char *buff; +{ + register char *p; + register char *q; + register const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (ISUPPER ((unsigned char) *p)) + *p = tolower (*p); + + if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) + { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) + { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen (buff) == 3) + abbrev = 1; + else if (strlen (buff) == 4 && buff[3] == '.') + { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) + { + if (abbrev) + { + if (strncmp (buff, tp->name, 3) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp (buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen (buff) - 1; + if (buff[i] == 's') + { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff)) + { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + +static int +yylex () +{ + register unsigned char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for (;;) + { + while (ISSPACE ((unsigned char) *yyInput)) + yyInput++; + + if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') + { + if (c == '-' || c == '+') + { + sign = c == '-' ? -1 : 1; + if (!ISDIGIT (*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; ISDIGIT (c = *yyInput++);) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (ISALPHA (c)) + { + for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord (buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do + { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } + while (Count > 0); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + long days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay / 100 - by / 100) + + ((ay / 100 >> 2) - (by / 100 >> 2)) + /* + difference in years * 365 */ + + (long) (ay - by) * 365 + ); + return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date (const char *p, const time_t *now) +{ + struct tm tm, tm0, *tmp; + time_t Start; + + yyInput = p; + Start = now ? *now : time ((time_t *) NULL); + tmp = localtime (&Start); + if (!tmp) + return -1; + yyYear = tmp->tm_year + TM_YEAR_ORIGIN; + yyMonth = tmp->tm_mon + 1; + yyDay = tmp->tm_mday; + yyHour = tmp->tm_hour; + yyMinutes = tmp->tm_min; + yySeconds = tmp->tm_sec; + tm.tm_isdst = tmp->tm_isdst; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMinutes = 0; + yyRelHour = 0; + yyRelDay = 0; + yyRelMonth = 0; + yyRelYear = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse () + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear; + tm.tm_mon = yyMonth - 1 + yyRelMonth; + tm.tm_mday = yyDay + yyRelDay; + if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay)) + { + tm.tm_hour = ToHour (yyHour, yyMeridian); + if (tm.tm_hour < 0) + return -1; + tm.tm_min = yyMinutes; + tm.tm_sec = yySeconds; + } + else + { + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + } + tm.tm_hour += yyRelHour; + tm.tm_min += yyRelMinutes; + tm.tm_sec += yyRelSeconds; + + /* Let mktime deduce tm_isdst if we have an absolute timestamp, + or if the relative timestamp mentions days, months, or years. */ + if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear) + tm.tm_isdst = -1; + + tm0 = tm; + + Start = mktime (&tm); + + if (Start == (time_t) -1) + { + + /* Guard against falsely reporting errors near the time_t boundaries + when parsing times in other time zones. For example, if the min + time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead + of UTC, then the min localtime value is 1970-01-01 08:00:00; if + we apply mktime to 1970-01-01 00:00:00 we will get an error, so + we apply mktime to 1970-01-02 08:00:00 instead and adjust the time + zone by 24 hours to compensate. This algorithm assumes that + there is no DST transition within a day of the time_t boundaries. */ + if (yyHaveZone) + { + tm = tm0; + if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) + { + tm.tm_mday++; + yyTimezone -= 24 * 60; + } + else + { + tm.tm_mday--; + yyTimezone += 24 * 60; + } + Start = mktime (&tm); + } + + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveDay && !yyHaveDate) + { + tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7 + + 7 * (yyDayOrdinal - (0 < yyDayOrdinal))); + Start = mktime (&tm); + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveZone) + { + long delta; + struct tm *gmt = gmtime (&Start); + if (!gmt) + return -1; + delta = yyTimezone * 60L + difftm (&tm, gmt); + if ((Start + delta < Start) != (delta < 0)) + return -1; /* time_t overflow */ + Start += delta; + } + + return Start; +} + +#if defined (TEST) + +/* ARGSUSED */ +int +main (ac, av) + int ac; + char *av[]; +{ + char buff[MAX_BUFF_LEN + 1]; + time_t d; + + (void) printf ("Enter date, or blank line to exit.\n\t> "); + (void) fflush (stdout); + + buff[MAX_BUFF_LEN] = 0; + while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) + { + d = get_date (buff, (time_t *) NULL); + if (d == -1) + (void) printf ("Bad format - couldn't convert.\n"); + else + (void) printf ("%s", ctime (&d)); + (void) printf ("\t> "); + (void) fflush (stdout); + } + exit (0); + /* NOTREACHED */ +} +#endif /* defined (TEST) */ diff --git a/lib/getdate.h b/lib/getdate.h new file mode 100644 index 000000000..674c474f1 --- /dev/null +++ b/lib/getdate.h @@ -0,0 +1,46 @@ +/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef PARAMS +# if defined PROTOTYPES || (defined __STDC__ && __STDC__) +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +#endif + +#ifdef vms +# include <types.h> +# include <time.h> +#else +# include <sys/types.h> +# if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +# else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +# endif +#endif /* defined (vms) */ + +time_t get_date PARAMS ((const char *p, const time_t *now)); diff --git a/lib/getdate.y b/lib/getdate.y new file mode 100644 index 000000000..d60be3cf0 --- /dev/null +++ b/lib/getdate.y @@ -0,0 +1,1051 @@ +%{ +/* +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990. +** +** This code is in the public domain and has no copyright. +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# endif +#endif + +/* Since the code of getdate.y is not included in the Emacs executable + itself, there is no need to #define static in this file. Even if + the code were included in the Emacs executable, it probably + wouldn't do any harm to #undef it here; this will only cause + problems if we try to write to a static variable, which I don't + think this code needs to do. */ +#ifdef emacs +# undef static +#endif + +#include <malloc.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#if HAVE_STDLIB_H +# include <stdlib.h> /* for `free'; used by Bison 1.27 */ +#endif + +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that + only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless + it's important to use the locale's definition of `digit' even when the + host does not conform to Posix. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#if defined (STDC_HEADERS) || defined (USG) +# include <string.h> +#endif + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +/* Some old versions of bison generate parsers that use bcopy. + That loses on systems that don't provide the function, so we have + to redefine it here. */ +#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) +# define bcopy(from, to, len) memcpy ((to), (from), (len)) +#endif + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in the same program. Note that these are only + the variables produced by yacc. If other parser generators (bison, + byacc, etc) produce additional global names that conflict at link time, + then those parser generators need to be fixed instead of adding those + names to this list. */ + +#define yymaxdepth gd_maxdepth +#define yyparse gd_parse +#define yylex gd_lex +#define yyerror gd_error +#define yylval gd_lval +#define yychar gd_char +#define yydebug gd_debug +#define yypact gd_pact +#define yyr1 gd_r1 +#define yyr2 gd_r2 +#define yydef gd_def +#define yychk gd_chk +#define yypgo gd_pgo +#define yyact gd_act +#define yyexca gd_exca +#define yyerrflag gd_errflag +#define yynerrs gd_nerrs +#define yyps gd_ps +#define yypv gd_pv +#define yys gd_s +#define yy_yys gd_yys +#define yystate gd_state +#define yytmp gd_tmp +#define yyv gd_v +#define yy_yyv gd_yyv +#define yyval gd_val +#define yylloc gd_lloc +#define yyreds gd_reds /* With YYDEBUG defined */ +#define yytoks gd_toks /* With YYDEBUG defined */ +#define yylhs gd_yylhs +#define yylen gd_yylen +#define yydefred gd_yydefred +#define yydgoto gd_yydgoto +#define yysindex gd_yysindex +#define yyrindex gd_yyrindex +#define yygindex gd_yygindex +#define yytable gd_yytable +#define yycheck gd_yycheck + +static int yylex (); +static int yyerror (); + +#define EPOCH 1970 +#define HOUR(x) ((x) * 60) + +#define MAX_BUFF_LEN 128 /* size of buffer to read the date into */ + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + const char *name; + int type; + int value; +} TABLE; + + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static const char *yyInput; +static int yyDayOrdinal; +static int yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static int yyTimezone; +static int yyDay; +static int yyHour; +static int yyMinutes; +static int yyMonth; +static int yySeconds; +static int yyYear; +static MERIDIAN yyMeridian; +static int yyRelDay; +static int yyRelHour; +static int yyRelMinutes; +static int yyRelMonth; +static int yyRelSeconds; +static int yyRelYear; + +%} + +/* This grammar has 13 shift/reduce conflicts. */ +%expect 13 + +%union { + int Number; + enum _MERIDIAN Meridian; +} + +%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID +%token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT +%token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE + +%type <Number> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT +%type <Number> tMONTH tMONTH_UNIT +%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE +%type <Meridian> tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; + } + | zone { + yyHaveZone++; + } + | date { + yyHaveDate++; + } + | day { + yyHaveDay++; + } + | rel { + yyHaveRel++; + } + | number + ; + +time : tUNUMBER tMERIDIAN { + yyHour = $1; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yyMeridian = MER24; + yyHaveZone++; + yyTimezone = ($4 < 0 + ? -$4 % 100 + (-$4 / 100) * 60 + : - ($4 % 100 + ($4 / 100) * 60)); + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = MER24; + yyHaveZone++; + yyTimezone = ($6 < 0 + ? -$6 % 100 + (-$6 / 100) * 60 + : - ($6 % 100 + ($6 / 100) * 60)); + } + ; + +zone : tZONE { + yyTimezone = $1; + } + | tDAYZONE { + yyTimezone = $1 - 60; + } + | + tZONE tDST { + yyTimezone = $1 - 60; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. + The goal in recognizing YYYY/MM/DD is solely to support legacy + machine-generated dates like those in an RCS log listing. If + you want portability, use the ISO 8601 format. */ + if ($1 >= 1000) + { + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } + else + { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + } + | tUNUMBER tSNUMBER tSNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = -$2; + yyDay = -$3; + } + | tUNUMBER tMONTH tSNUMBER { + /* e.g. 17-JUN-1992. */ + yyDay = $1; + yyMonth = $2; + yyYear = -$3; + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + yyMonth = $2; + yyDay = $1; + } + | tUNUMBER tMONTH tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; + } + ; + +rel : relunit tAGO { + yyRelSeconds = -yyRelSeconds; + yyRelMinutes = -yyRelMinutes; + yyRelHour = -yyRelHour; + yyRelDay = -yyRelDay; + yyRelMonth = -yyRelMonth; + yyRelYear = -yyRelYear; + } + | relunit + ; + +relunit : tUNUMBER tYEAR_UNIT { + yyRelYear += $1 * $2; + } + | tSNUMBER tYEAR_UNIT { + yyRelYear += $1 * $2; + } + | tYEAR_UNIT { + yyRelYear += $1; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tMONTH_UNIT { + yyRelMonth += $1; + } + | tUNUMBER tDAY_UNIT { + yyRelDay += $1 * $2; + } + | tSNUMBER tDAY_UNIT { + yyRelDay += $1 * $2; + } + | tDAY_UNIT { + yyRelDay += $1; + } + | tUNUMBER tHOUR_UNIT { + yyRelHour += $1 * $2; + } + | tSNUMBER tHOUR_UNIT { + yyRelHour += $1 * $2; + } + | tHOUR_UNIT { + yyRelHour += $1; + } + | tUNUMBER tMINUTE_UNIT { + yyRelMinutes += $1 * $2; + } + | tSNUMBER tMINUTE_UNIT { + yyRelMinutes += $1 * $2; + } + | tMINUTE_UNIT { + yyRelMinutes += $1; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSEC_UNIT { + yyRelSeconds += $1; + } + ; + +number : tUNUMBER + { + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = $1; + else + { + if ($1>10000) + { + yyHaveDate++; + yyDay= ($1)%100; + yyMonth= ($1/100)%100; + yyYear = $1/10000; + } + else + { + yyHaveTime++; + if ($1 < 100) + { + yyHour = $1; + yyMinutes = 0; + } + else + { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + } + ; + +o_merid : /* NULL */ + { + $$ = MER24; + } + | tMERIDIAN + { + $$ = $1; + } + ; + +%% + +/* Include this file down here because bison inserts code above which + may define-away `const'. We want the prototype for get_date to have + the same signature as the function definition does. */ +#include "getdate.h" + +extern struct tm *gmtime (); +extern struct tm *localtime (); +extern time_t mktime (); + +/* Month and day table. */ +static TABLE const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL, 0, 0 } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tYEAR_UNIT, 1 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tDAY_UNIT, 14 }, + { "week", tDAY_UNIT, 7 }, + { "day", tDAY_UNIT, 1 }, + { "hour", tHOUR_UNIT, 1 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL, 0, 0 } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 1 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL, 0, 0 } +}; + +/* The timezone table. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR ( 0) }, + { "wet", tZONE, HOUR ( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */ + { "wat", tZONE, HOUR ( 1) }, /* West Africa */ + { "at", tZONE, HOUR ( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR ( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR (10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR (11) }, /* Nome */ + { "idlw", tZONE, HOUR (12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR (1) }, /* Central European */ + { "met", tZONE, -HOUR (1) }, /* Middle European */ + { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ + { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR (1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */ + { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR (3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Standard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR (12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR (12) }, /* International Date Line East */ + { NULL, 0, 0 } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR ( 1) }, + { "b", tZONE, HOUR ( 2) }, + { "c", tZONE, HOUR ( 3) }, + { "d", tZONE, HOUR ( 4) }, + { "e", tZONE, HOUR ( 5) }, + { "f", tZONE, HOUR ( 6) }, + { "g", tZONE, HOUR ( 7) }, + { "h", tZONE, HOUR ( 8) }, + { "i", tZONE, HOUR ( 9) }, + { "k", tZONE, HOUR ( 10) }, + { "l", tZONE, HOUR ( 11) }, + { "m", tZONE, HOUR ( 12) }, + { "n", tZONE, HOUR (- 1) }, + { "o", tZONE, HOUR (- 2) }, + { "p", tZONE, HOUR (- 3) }, + { "q", tZONE, HOUR (- 4) }, + { "r", tZONE, HOUR (- 5) }, + { "s", tZONE, HOUR (- 6) }, + { "t", tZONE, HOUR (- 7) }, + { "u", tZONE, HOUR (- 8) }, + { "v", tZONE, HOUR (- 9) }, + { "w", tZONE, HOUR (-10) }, + { "x", tZONE, HOUR (-11) }, + { "y", tZONE, HOUR (-12) }, + { "z", tZONE, HOUR ( 0) }, + { NULL, 0, 0 } +}; + + + + +/* ARGSUSED */ +static int +yyerror (s) + char *s ATTRIBUTE_UNUSED; +{ + return 0; +} + +static int +ToHour (Hours, Meridian) + int Hours; + MERIDIAN Meridian; +{ + switch (Meridian) + { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return Hours; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours + 12; + default: + abort (); + } + /* NOTREACHED */ +} + +static int +ToYear (Year) + int Year; +{ + if (Year < 0) + Year = -Year; + + /* XPG4 suggests that years 00-68 map to 2000-2068, and + years 69-99 map to 1969-1999. */ + if (Year < 69) + Year += 2000; + else if (Year < 100) + Year += 1900; + + return Year; +} + +static int +LookupWord (buff) + char *buff; +{ + register char *p; + register char *q; + register const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (ISUPPER ((unsigned char) *p)) + *p = tolower (*p); + + if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) + { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) + { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen (buff) == 3) + abbrev = 1; + else if (strlen (buff) == 4 && buff[3] == '.') + { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) + { + if (abbrev) + { + if (strncmp (buff, tp->name, 3) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp (buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen (buff) - 1; + if (buff[i] == 's') + { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff)) + { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + +static int +yylex () +{ + register unsigned char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for (;;) + { + while (ISSPACE ((unsigned char) *yyInput)) + yyInput++; + + if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') + { + if (c == '-' || c == '+') + { + sign = c == '-' ? -1 : 1; + if (!ISDIGIT (*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; ISDIGIT (c = *yyInput++);) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (ISALPHA (c)) + { + for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord (buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do + { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } + while (Count > 0); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + long days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay / 100 - by / 100) + + ((ay / 100 >> 2) - (by / 100 >> 2)) + /* + difference in years * 365 */ + + (long) (ay - by) * 365 + ); + return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date (const char *p, const time_t *now) +{ + struct tm tm, tm0, *tmp; + time_t Start; + + yyInput = p; + Start = now ? *now : time ((time_t *) NULL); + tmp = localtime (&Start); + if (!tmp) + return -1; + yyYear = tmp->tm_year + TM_YEAR_ORIGIN; + yyMonth = tmp->tm_mon + 1; + yyDay = tmp->tm_mday; + yyHour = tmp->tm_hour; + yyMinutes = tmp->tm_min; + yySeconds = tmp->tm_sec; + tm.tm_isdst = tmp->tm_isdst; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMinutes = 0; + yyRelHour = 0; + yyRelDay = 0; + yyRelMonth = 0; + yyRelYear = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse () + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear; + tm.tm_mon = yyMonth - 1 + yyRelMonth; + tm.tm_mday = yyDay + yyRelDay; + if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay)) + { + tm.tm_hour = ToHour (yyHour, yyMeridian); + if (tm.tm_hour < 0) + return -1; + tm.tm_min = yyMinutes; + tm.tm_sec = yySeconds; + } + else + { + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + } + tm.tm_hour += yyRelHour; + tm.tm_min += yyRelMinutes; + tm.tm_sec += yyRelSeconds; + + /* Let mktime deduce tm_isdst if we have an absolute timestamp, + or if the relative timestamp mentions days, months, or years. */ + if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear) + tm.tm_isdst = -1; + + tm0 = tm; + + Start = mktime (&tm); + + if (Start == (time_t) -1) + { + + /* Guard against falsely reporting errors near the time_t boundaries + when parsing times in other time zones. For example, if the min + time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead + of UTC, then the min localtime value is 1970-01-01 08:00:00; if + we apply mktime to 1970-01-01 00:00:00 we will get an error, so + we apply mktime to 1970-01-02 08:00:00 instead and adjust the time + zone by 24 hours to compensate. This algorithm assumes that + there is no DST transition within a day of the time_t boundaries. */ + if (yyHaveZone) + { + tm = tm0; + if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) + { + tm.tm_mday++; + yyTimezone -= 24 * 60; + } + else + { + tm.tm_mday--; + yyTimezone += 24 * 60; + } + Start = mktime (&tm); + } + + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveDay && !yyHaveDate) + { + tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7 + + 7 * (yyDayOrdinal - (0 < yyDayOrdinal))); + Start = mktime (&tm); + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveZone) + { + long delta; + struct tm *gmt = gmtime (&Start); + if (!gmt) + return -1; + delta = yyTimezone * 60L + difftm (&tm, gmt); + if ((Start + delta < Start) != (delta < 0)) + return -1; /* time_t overflow */ + Start += delta; + } + + return Start; +} + +#if defined (TEST) + +/* ARGSUSED */ +int +main (ac, av) + int ac; + char *av[]; +{ + char buff[MAX_BUFF_LEN + 1]; + time_t d; + + (void) printf ("Enter date, or blank line to exit.\n\t> "); + (void) fflush (stdout); + + buff[MAX_BUFF_LEN] = 0; + while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) + { + d = get_date (buff, (time_t *) NULL); + if (d == -1) + (void) printf ("Bad format - couldn't convert.\n"); + else + (void) printf ("%s", ctime (&d)); + (void) printf ("\t> "); + (void) fflush (stdout); + } + exit (0); + /* NOTREACHED */ +} +#endif /* defined (TEST) */ diff --git a/lib/getenv.c b/lib/getenv.c new file mode 100644 index 000000000..404f1c970 --- /dev/null +++ b/lib/getenv.c @@ -0,0 +1,95 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * Contributor(s): + * Rafael Sagula <sagula@inf.ufrgs.br> + * Sampo Kellomaki <sampo@iki.fi> + * Linas Vepstas <linas@linas.org> + * Bjorn Reese <breese@imada.ou.dk> + * Johan Anderson <johan@homemail.com> + * Kjell Ericson <Kjell.Ericson@haxx.nu> + * Troy Engel <tengel@palladium.net> + * Ryan Nelson <ryan@inch.com> + * Bjorn Stenberg <Bjorn.Stenberg@haxx.nu> + * Angus Mackay <amackay@gus.ml.org> + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + * $Log$ + * Revision 1.1 1999-12-29 14:21:29 bagder + * Initial revision + * + * Revision 1.4 1999/09/06 06:59:40 dast + * Changed email info + * + * Revision 1.3 1999/08/13 07:34:48 dast + * Changed the URL in the header + * + * Revision 1.2 1999/03/13 00:56:09 dast + * Big changes done due to url.c being split up in X smaller files and that + * the lib is now more stand-alone. + * + * Revision 1.1.1.1 1999/03/11 22:23:34 dast + * Imported sources + * + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#ifdef WIN32 +#include <windows.h> +#endif + +char *GetEnv(char *variable) +{ +#ifdef WIN32 + /* This shit requires windows.h (HUGE) to be included */ + static char env[MAX_PATH]; /* MAX_PATH is from windef.h */ + char *temp = getenv(variable); + env[0] = '\0'; + ExpandEnvironmentStrings(temp, env, sizeof(env)); +#else + /* no length control */ + char *env = getenv(variable); +#endif + return env; +} + +char *curl_GetEnv(char *v) +{ + return GetEnv(v); +} diff --git a/lib/getenv.h b/lib/getenv.h new file mode 100644 index 000000000..83b9495e1 --- /dev/null +++ b/lib/getenv.h @@ -0,0 +1,71 @@ +#ifndef __GETENV_H +#define __GETENV_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * Contributor(s): + * Rafael Sagula <sagula@inf.ufrgs.br> + * Sampo Kellomaki <sampo@iki.fi> + * Linas Vepstas <linas@linas.org> + * Bjorn Reese <breese@imada.ou.dk> + * Johan Anderson <johan@homemail.com> + * Kjell Ericson <Kjell.Ericson@haxx.nu> + * Troy Engel <tengel@palladium.net> + * Ryan Nelson <ryan@inch.com> + * Bjorn Stenberg <Bjorn.Stenberg@haxx.nu> + * Angus Mackay <amackay@gus.ml.org> + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + * $Log$ + * Revision 1.1 1999-12-29 14:21:30 bagder + * Initial revision + * + * Revision 1.3 1999/09/06 06:59:40 dast + * Changed email info + * + * Revision 1.2 1999/08/13 07:34:48 dast + * Changed the URL in the header + * + * Revision 1.1.1.1 1999/03/11 22:23:34 dast + * Imported sources + * + ****************************************************************************/ + +/* Unix and Win32 getenv function call */ +char *GetEnv(char *variable); + +#endif diff --git a/lib/getpass.c b/lib/getpass.c new file mode 100644 index 000000000..c0c7bf97b --- /dev/null +++ b/lib/getpass.c @@ -0,0 +1,185 @@ +/* ============================================================================ + * Copyright (C) 1998 Angus Mackay. All rights reserved; + * + * Redistribution and use are freely permitted provided that: + * + * 1) This header remain in tact. + * 2) The prototype for getpass is not changed from: + * char *getpass(const char *prompt) + * 3) This source code is not used outside of this(getpass.c) file. + * 3) Any changes to this(getpass.c) source code are made publicly available. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * $Id$ + * + * The spirit of this license is to allow use of this source code in any + * project be it open or closed but still encourage the use of the open, + * library based equivilents. + * + * Author(s): + * Angus Mackay <amackay@gus.ml.org> + * + * Contributor(s): + * Daniel Stenberg <Daniel.Stenberg@haxx.nu> + */ + +#ifndef WIN32 +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_TERMIOS_H +# if !defined(HAVE_TCGETATTR) && !defined(HAVE_TCSETATTR) +# undef HAVE_TERMIOS_H +# endif +#endif + +#define INPUT_BUFFER 128 + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> +#include <signal.h> +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#else +# ifdef HAVE_TERMIO_H +# include <termio.h> +# else +# endif +#endif + +/* no perror? make an fprintf! */ +#ifndef HAVE_PERROR +# define perror(x) fprintf(stderr, "Error in: %s\n", x) +#endif + +char *getpass(const char *prompt) +{ + FILE *infp; + FILE *outfp; + static char buf[INPUT_BUFFER]; + RETSIGTYPE (*sigint)(); + RETSIGTYPE (*sigtstp)(); + size_t bytes_read; + int infd; + int outfd; +#ifdef HAVE_TERMIOS_H + struct termios orig; + struct termios noecho; +#else +# ifdef HAVE_TERMIO_H + struct termio orig; + struct termio noecho; +# else +# endif +#endif + + sigint = signal(SIGINT, SIG_IGN); + sigtstp = signal(SIGTSTP, SIG_IGN); + + if( (infp=fopen("/dev/tty", "r")) == NULL ) + { + infp = stdin; + } + if( (outfp=fopen("/dev/tty", "w")) == NULL ) + { + outfp = stderr; + } + infd = fileno(infp); + outfd = fileno(outfp); + + /* dissable echo */ +#ifdef HAVE_TERMIOS_H + if(tcgetattr(outfd, &orig) != 0) + { + perror("tcgetattr"); + } + noecho = orig; + noecho.c_lflag &= ~ECHO; + if(tcsetattr(outfd, TCSANOW, &noecho) != 0) + { + perror("tcgetattr"); + } +#else +# ifdef HAVE_TERMIO_H + if(ioctl(outfd, TCGETA, &orig) != 0) + { + perror("ioctl"); + } + noecho = orig; + noecho.c_lflag &= ~ECHO; + if(ioctl(outfd, TCSETA, &noecho) != 0) + { + perror("ioctl"); + } +# else +# endif +#endif + + fputs(prompt, outfp); + fflush(outfp); + + bytes_read=read(infd, buf, INPUT_BUFFER); + buf[bytes_read > 0 ? (bytes_read -1) : 0] = '\0'; + + /* print a new line if needed */ +#ifdef HAVE_TERMIOS_H + fputs("\n", outfp); +#else +# ifdef HAVE_TERMIO_H + fputs("\n", outfp); +# else +# endif +#endif + + /* + * reset term charectaristics, use TCSAFLUSH incase the + * user types more than INPUT_BUFFER + */ +#ifdef HAVE_TERMIOS_H + if(tcsetattr(outfd, TCSAFLUSH, &orig) != 0) + { + perror("tcgetattr"); + } +#else +# ifdef HAVE_TERMIO_H + if(ioctl(outfd, TCSETA, &orig) != 0) + { + perror("ioctl"); + } +# else +# endif +#endif + + signal(SIGINT, sigint); + signal(SIGTSTP, sigtstp); + + return(buf); +} +#else +#include <stdio.h> +char *getpass(const char *prompt) +{ + static char password[80]; + printf(prompt); + gets(password); + return password; +} +#endif /* don't do anything if WIN32 */ diff --git a/lib/getpass.h b/lib/getpass.h new file mode 100644 index 000000000..33dfed668 --- /dev/null +++ b/lib/getpass.h @@ -0,0 +1 @@ +char *getpass(const char *prompt); diff --git a/lib/hostip.c b/lib/hostip.c new file mode 100644 index 000000000..453d8a387 --- /dev/null +++ b/lib/hostip.c @@ -0,0 +1,111 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <string.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#else +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#endif + +#include "urldata.h" +#include "sendf.h" + +/* --- resolve name or IP-number --- */ + +char *MakeIP(unsigned long num) +{ +#ifdef HAVE_INET_NTOA + struct in_addr in; + + in.s_addr = htonl(num); + return (inet_ntoa(in)); +#else + static char addr[128]; + unsigned char *paddr; + + num = htonl(num); /* htonl() added to avoid endian probs */ + paddr = (unsigned char *)# + sprintf(addr, "%u.%u.%u.%u", paddr[0], paddr[1], paddr[2], paddr[3]); + return (addr); +#endif +} + +/* Stolen from Dancer source code, written by + Bjorn Reese <breese@imada.ou.dk> */ +#ifndef INADDR_NONE +#define INADDR_NONE (unsigned long) ~0 +#endif +struct hostent *GetHost(struct UrlData *data, char *hostname) +{ + struct hostent *h = NULL; + unsigned long in; + static struct hostent he; + static char name[MAXHOSTNAMELEN]; + static char *addrlist[2]; + static struct in_addr addrentry; + + if ( (in=inet_addr(hostname)) != INADDR_NONE ) { + addrentry.s_addr = in; + addrlist[0] = (char *)&addrentry; + addrlist[1] = NULL; + he.h_name = strncpy(name, MakeIP(ntohl(in)), MAXHOSTNAMELEN); + he.h_addrtype = AF_INET; + he.h_length = sizeof(struct in_addr); + he.h_addr_list = addrlist; + h = &he; + } else if ( (h=gethostbyname(hostname)) == NULL ) { + infof(data, "gethostbyname(2) failed for %s\n", hostname); + } + return (h); +} diff --git a/lib/hostip.h b/lib/hostip.h new file mode 100644 index 000000000..8753e3975 --- /dev/null +++ b/lib/hostip.h @@ -0,0 +1,46 @@ +#ifndef __HOSTIP_H +#define __HOSTIP_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +struct hostent *GetHost(struct UrlData *data, char *hostname); +char *MakeIP(unsigned long num); + +#endif diff --git a/lib/http.c b/lib/http.c new file mode 100644 index 000000000..2dd380214 --- /dev/null +++ b/lib/http.c @@ -0,0 +1,381 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#include <time.h> +#include <io.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <sys/time.h> +#include <sys/resource.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> +#include <signal.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "download.h" +#include "sendf.h" +#include "formdata.h" +#include "progress.h" +#include "base64.h" +#include "upload.h" +#include "cookie.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* + * This function checks the linked list of custom HTTP headers for a particular + * header (prefix). + */ +bool static checkheaders(struct UrlData *data, char *thisheader) +{ + struct HttpHeader *head; + size_t thislen = strlen(thisheader); + + for(head = data->headers; head; head=head->next) { + if(strnequal(head->header, thisheader, thislen)) { + return TRUE; + } + } + return FALSE; +} + +UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount) +{ + /* Send the GET line to the HTTP server */ + + struct FormData *sendit=NULL; + int postsize=0; + UrgError result; + char *buf; + struct Cookie *co = NULL; + char *p_pragma = NULL; + char *p_accept = NULL; + + buf = data->buffer; /* this is our buffer */ + + if ( (data->conf&(CONF_HTTP|CONF_FTP)) && + (data->conf&CONF_UPLOAD)) { + data->conf |= CONF_PUT; + } +#if 0 /* old version */ + if((data->conf&(CONF_HTTP|CONF_UPLOAD)) == + (CONF_HTTP|CONF_UPLOAD)) { + /* enable PUT! */ + data->conf |= CONF_PUT; + } +#endif + + /* The User-Agent string has been built in url.c already, because it might + have been used in the proxy connect, but if we have got a header with + the user-agent string specified, we erase the previosly made string + here. */ + if(checkheaders(data, "User-Agent:") && data->ptr_uagent) { + free(data->ptr_uagent); + data->ptr_uagent=NULL; + } + + if((data->conf & CONF_USERPWD) && !checkheaders(data, "Authorization:")) { + char authorization[512]; + sprintf(data->buffer, "%s:%s", data->user, data->passwd); + base64Encode(data->buffer, authorization); + data->ptr_userpwd = maprintf( "Authorization: Basic %s\015\012", + authorization); + } + if((data->conf & CONF_RANGE) && !checkheaders(data, "Range:")) { + data->ptr_rangeline = maprintf("Range: bytes=%s\015\012", data->range); + } + if((data->conf & CONF_REFERER) && !checkheaders(data, "Referer:")) { + data->ptr_ref = maprintf("Referer: %s\015\012", data->referer); + } + if(data->cookie && !checkheaders(data, "Cookie:")) { + data->ptr_cookie = maprintf("Cookie: %s\015\012", data->cookie); + } + + if(data->cookies) { + co = cookie_getlist(data->cookies, + host, + ppath, + data->conf&CONF_HTTPS?TRUE:FALSE); + } + if ((data->conf & CONF_PROXY) && (!(data->conf & CONF_HTTPS))) { + /* The path sent to the proxy is in fact the entire URL */ + strncpy(ppath, data->url, URL_MAX_LENGTH-1); + } + if(data->conf & CONF_HTTPPOST) { + /* we must build the whole darned post sequence first, so that we have + a size of the whole shebang before we start to send it */ + sendit = getFormData(data->httppost, &postsize); + } + + if(!checkheaders(data, "Host:")) + data->ptr_host = maprintf("Host: %s\r\n", host); + + + if(!checkheaders(data, "Pragma:")) + p_pragma = "Pragma: no-cache\r\n"; + + if(!checkheaders(data, "Accept:")) + p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"; + + do { + sendf(data->firstsocket, data, + "%s " /* GET/HEAD/POST/PUT */ + "%s HTTP/1.0\r\n" /* path */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* cookie */ + "%s" /* host */ + "%s" /* pragma */ + "%s" /* accept */ + "%s", /* referer */ + + data->customrequest?data->customrequest: + (data->conf&CONF_NOBODY?"HEAD": + (data->conf&(CONF_POST|CONF_HTTPPOST))?"POST": + (data->conf&CONF_PUT)?"PUT":"GET"), + ppath, + (data->conf&CONF_PROXYUSERPWD && data->ptr_proxyuserpwd)?data->ptr_proxyuserpwd:"", + (data->conf&CONF_USERPWD && data->ptr_userpwd)?data->ptr_userpwd:"", + (data->conf&CONF_RANGE && data->ptr_rangeline)?data->ptr_rangeline:"", + (data->useragent && *data->useragent && data->ptr_uagent)?data->ptr_uagent:"", + (data->ptr_cookie?data->ptr_cookie:""), /* Cookie: <data> */ + (data->ptr_host?data->ptr_host:""), /* Host: host */ + p_pragma?p_pragma:"", + p_accept?p_accept:"", + (data->conf&CONF_REFERER && data->ptr_ref)?data->ptr_ref:"" /* Referer: <data> <CRLF> */ + ); + + if(co) { + int count=0; + /* now loop through all cookies that matched */ + while(co) { + if(0 == count) { + sendf(data->firstsocket, data, + "Cookie: "); + } + count++; + sendf(data->firstsocket, data, + "%s=%s;", co->name, co->value); + co = co->next; /* next cookie please */ + } + if(count) { + sendf(data->firstsocket, data, + "\r\n"); + } + cookie_freelist(co); /* free the cookie list */ + co=NULL; + } + + if(data->timecondition) { + struct tm *thistime; + + thistime = localtime(&data->timevalue); + +#if defined(HAVE_STRFTIME) || defined(WIN32) + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S %Z", thistime); +#else + /* Right, we *could* write a replacement here */ + strcpy(buf, "no strftime() support"); +#endif + switch(data->timecondition) { + case TIMECOND_IFMODSINCE: + default: + sendf(data->firstsocket, data, + "If-Modified-Since: %s\r\n", buf); + break; + case TIMECOND_IFUNMODSINCE: + sendf(data->firstsocket, data, + "If-Unmodified-Since: %s\r\n", buf); + break; + case TIMECOND_LASTMOD: + sendf(data->firstsocket, data, + "Last-Modified: %s\r\n", buf); + break; + } + } + + while(data->headers) { + sendf(data->firstsocket, data, + "%s\015\012", + data->headers->header); + data->headers = data->headers->next; + } + + if(data->conf&(CONF_POST|CONF_HTTPPOST)) { + if(data->conf & CONF_POST) { + /* this is the simple x-www-form-urlencoded style */ + sendf(data->firstsocket, data, + "Content-Length: %d\015\012" + "Content-Type: application/x-www-form-urlencoded\r\n\r\n" + "%s\015\012", + strlen(data->postfields), + data->postfields ); + } + else { + struct Form form; + size_t (*storefread)(char *, size_t , size_t , FILE *); + FILE *in; + long conf; + + if(FormInit(&form, sendit)) { + failf(data, "Internal HTTP POST error!\n"); + return URG_HTTP_POST_ERROR; + } + + storefread = data->fread; /* backup */ + in = data->in; /* backup */ + + data->fread = + (size_t (*)(char *, size_t, size_t, FILE *)) + FormReader; /* set the read function to read from the + generated form data */ + data->in = (FILE *)&form; + + sendf(data->firstsocket, data, + "Content-Length: %d\r\n", + postsize-2); + + conf = data->conf; + data->conf &= ~CONF_NOPROGRESS; /* enable progress meter */ + ProgressInit(data, postsize); + + result = Upload(data, data->firstsocket, bytecount); + + FormFree(sendit); /* Now free that whole lot */ + + data->conf = conf; /* restore conf values for the download */ + + if(result) + return result; + + data->fread = storefread; /* restore */ + data->in = in; /* restore */ + + sendf(data->firstsocket, data, + "\r\n\r\n"); + } + } + else if(data->conf&CONF_PUT) { + /* Let's PUT the data to the server! */ + long conf; + + if(data->infilesize>0) { + sendf(data->firstsocket, data, + "Content-Length: %d\r\n\r\n", /* file size */ + data->infilesize ); + } + else + sendf(data->firstsocket, data, + "\015\012"); + + conf = data->conf; + data->conf &= ~CONF_NOPROGRESS; /* enable progress meter */ + + ProgressInit(data, data->infilesize); + + result = Upload(data, data->firstsocket, bytecount); + + data->conf = conf; + + if(result) + return result; + + /* reset the byte counter */ + *bytecount=0; + } + else { + sendf(data->firstsocket, data, "\r\n"); + } + /* HTTP GET/HEAD download: */ + result = Download(data, data->firstsocket, -1, TRUE, bytecount); + + if(result) + return result; + + ProgressEnd(data); + } while (0); /* this is just a left-over from the multiple document download + attempts */ + + return URG_OK; +} + diff --git a/lib/http.h b/lib/http.h new file mode 100644 index 000000000..be35842cf --- /dev/null +++ b/lib/http.h @@ -0,0 +1,45 @@ +#ifndef __HTTP_H +#define __HTTP_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError http(struct UrlData *data, char *path, char *host, long *bytecountp); + +#endif diff --git a/lib/if2ip.c b/lib/if2ip.c new file mode 100644 index 000000000..f8a37bb12 --- /dev/null +++ b/lib/if2ip.c @@ -0,0 +1,110 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if ! defined(WIN32) && ! defined(__BEOS__) + +#include <sys/socket.h> +#include <netinet/in.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <netinet/in.h> +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> + +/* -- if2ip() -- */ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif + +#define SYS_ERROR -1 + +char *if2ip(char *interface) +{ + int dummy; + char *ip=NULL; + + if(!interface) + return NULL; + + dummy = socket(AF_INET, SOCK_STREAM, 0); + if (SYS_ERROR == dummy) { + return NULL; + } + else { + struct ifreq req; + memset(&req, 0, sizeof(req)); + strcpy(req.ifr_name, interface); + req.ifr_addr.sa_family = AF_INET; + if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) { + return NULL; + } + else { + struct in_addr in; + + struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr; + memcpy(&in, &(s->sin_addr.s_addr), sizeof(in)); + ip = (char *)strdup(inet_ntoa(in)); + } + close(dummy); + } + return ip; +} + +/* -- end of if2ip() -- */ +#else +#define if2ip(x) NULL +#endif diff --git a/lib/if2ip.h b/lib/if2ip.h new file mode 100644 index 000000000..0b658f9d2 --- /dev/null +++ b/lib/if2ip.h @@ -0,0 +1,50 @@ +#ifndef __IF2IP_H +#define __IF2IP_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +#include "setup.h" + +#if ! defined(WIN32) && ! defined(__BEOS__) +char *if2ip(char *interface); +#else +#define if2ip(x) NULL +#endif + +#endif diff --git a/lib/ldap.c b/lib/ldap.c new file mode 100644 index 000000000..7f0e0251f --- /dev/null +++ b/lib/ldap.c @@ -0,0 +1,226 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Contributor(s): + * Bjørn Reese <breese@mail1.stofanet.dk> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) +#else +# ifdef HAVE_UNISTD_H +# include <unistd.h> +# endif +# ifdef HAVE_DLFCN_H +# include <dlfcn.h> +# endif +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "sendf.h" +#include "escape.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + + +#define DYNA_GET_FUNCTION(type, fnc) \ + (fnc) = (type)DynaGetFunction(#fnc); \ + if ((fnc) == NULL) { \ + return URG_FUNCTION_NOT_FOUND; \ + } \ + +/*********************************************************************** + */ +static void *libldap = NULL; +static void *liblber = NULL; + +static void DynaOpen(void) +{ +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap == NULL) { + /* + * libldap.so should be able to resolve its dependency on + * liblber.so automatically, but since it does not we will + * handle it here by opening liblber.so as global. + */ + dlopen("liblber.so", RTLD_LAZY | RTLD_GLOBAL); + libldap = dlopen("libldap.so", RTLD_LAZY); + } +#endif +} + +static void DynaClose(void) +{ +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap) { + dlclose(libldap); + } + if (liblber) { + dlclose(liblber); + } +#endif +} + +static void * DynaGetFunction(char *name) +{ + void *func = NULL; + +#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) + if (libldap) { + func = dlsym(libldap, name); + } +#endif + + return func; +} + +static int WriteProc(void *param, char *text, int len) +{ + struct UrlData *data = (struct UrlData *)param; + + printf("%s\n", text); + return 0; +} + +/*********************************************************************** + */ +UrgError ldap(struct UrlData *data, char *path, long *bytecount) +{ + UrgError status = URG_OK; + int rc; + void *(*ldap_open)(char *, int); + int (*ldap_simple_bind_s)(void *, char *, char *); + int (*ldap_unbind_s)(void *); + int (*ldap_url_search_s)(void *, char *, int, void **); + void *(*ldap_first_entry)(void *, void *); + void *(*ldap_next_entry)(void *, void *); + char *(*ldap_err2string)(int); + int (*ldap_entry2text)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long); + int (*ldap_entry2html)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *); + void *server; + void *result; + void *entryIterator; +#if 0 + char *dn; + char **attrArray; + char *attrIterator; + char *attrString; + void *dummy; +#endif + int ldaptext; + + infof(data, "LDAP: %s %s\n", data->url); + + DynaOpen(); + if (libldap == NULL) { + failf(data, "The needed LDAP library/libraries couldn't be opened"); + return URG_LIBRARY_NOT_FOUND; + } + + ldaptext = data->conf & CONF_FTPASCII; /* This is a dirty hack */ + + /* The types are needed because ANSI C distinguishes between + * pointer-to-object (data) and pointer-to-function. + */ + DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_open); + DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s); + DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s); + DYNA_GET_FUNCTION(int (*)(void *, char *, int, void **), ldap_url_search_s); + DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry); + DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry); + DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string); + DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long), ldap_entry2text); + DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *), ldap_entry2html); + + server = ldap_open(data->hostname, data->port); + if (server == NULL) { + failf(data, "LDAP: Cannot connect to %s:%d", + data->hostname, data->port); + status = URG_COULDNT_CONNECT; + } else { + rc = ldap_simple_bind_s(server, data->user, data->passwd); + if (rc != 0) { + failf(data, "LDAP: %s", ldap_err2string(rc)); + status = URG_LDAP_CANNOT_BIND; + } else { + rc = ldap_url_search_s(server, data->url, 0, &result); + if (rc != 0) { + failf(data, "LDAP: %s", ldap_err2string(rc)); + status = URG_LDAP_SEARCH_FAILED; + } else { + for (entryIterator = ldap_first_entry(server, result); + entryIterator; + entryIterator = ldap_next_entry(server, entryIterator)) + { + if (ldaptext) { + rc = ldap_entry2text(server, NULL, entryIterator, NULL, + NULL, NULL, WriteProc, data, + "", 0, 0); + if (rc != 0) { + failf(data, "LDAP: %s", ldap_err2string(rc)); + status = URG_LDAP_SEARCH_FAILED; + } + } else { + rc = ldap_entry2html(server, NULL, entryIterator, NULL, + NULL, NULL, WriteProc, data, + "", 0, 0, NULL, NULL); + if (rc != 0) { + failf(data, "LDAP: %s", ldap_err2string(rc)); + status = URG_LDAP_SEARCH_FAILED; + } + } + } + } + ldap_unbind_s(server); + } + } + DynaClose(); + + return status; +} diff --git a/lib/ldap.h b/lib/ldap.h new file mode 100644 index 000000000..d88880ede --- /dev/null +++ b/lib/ldap.h @@ -0,0 +1,45 @@ +#ifndef __LDAP_H +#define __LDAP_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://www.fts.frontec.se/~dast/curl/ + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError ldap(struct UrlData *data, char *path, long *bytecount); + +#endif /* __LDAP_H */ diff --git a/lib/mprintf.c b/lib/mprintf.c new file mode 100644 index 000000000..237a21a9d --- /dev/null +++ b/lib/mprintf.c @@ -0,0 +1,1253 @@ +/**************************************************************************** + * + * $Id$ + * + ************************************************************************* + * + * Purpose: + * A merge of Bjorn Reese's format() function and Daniel's dsprintf() + * 1.0. A full blooded printf() clone with full support for <num>$ + * everywhere (parameters, widths and precisions) including variabled + * sized parameters (like doubles, long longs, long doubles and even + * void * in 64-bit architectures). + * + * Current restrictions: + * - Max 128 parameters + * - No 'long double' support. + * + ************************************************************************* + * + * + * 1998/01/10 (v2.8) + * Daniel + * - Updated version number. + * - Corrected a static non-zero prefixed width problem. + * + * 1998/11/17 - Daniel + * Added daprintf() and dvaprintf() for allocated printf() and vprintf(). + * They return an allocated buffer with the result inside. The result must + * be free()ed! + * + * 1998/08/23 - breese + * + * Converted all non-printable (and non-whitespace) characters into + * their decimal ASCII value preceeded by a '\' character + * (this only applies to snprintf family so far) + * + * Added %S (which is the same as %#s) + * + * 1998/05/05 (v2.7) + * + * Fixed precision and width qualifiers (%.*s) + * + * Added support for snprintf() + * + * Quoting (%#s) is disabled for the (nil) pointer + * + * 1997/06/09 (v2.6) + * + * %#s means that the string will be quoted with " + * (I was getting tired of writing \"%s\" all the time) + * + * [ERR] for strings changed to (nil) + * + * v2.5 + * - Added C++ support + * - Prepended all internal functions with dprintf_ + * - Defined the booleans + * + * v2.4 + * - Added dvsprintf(), dvfprintf() and dvprintf(). + * - Made the formatting function available with the name _formatf() to enable + * other *printf()-inspired functions. (I considered adding a dmsprintf() + * that works like sprintf() but allocates the destination string and + * possibly enlarges it itself, but things like that should be done with the + * new _formatf() instead.) + * + * v2.3 + * - Small modifications to make it compile nicely at both Daniel's and + * Bjorn's place. + * + * v2.2 + * - Made it work with text to the right of the last %! + * - Introduced dprintf(), dsprintf() and dfprintf(). + * - Float/double support enabled. This system is currently using the ordinary + * sprintf() function. NOTE that positional parameters, widths and precisions + * will still work like it should since the d-system takes care of that and + * passes that information re-formatted to the old sprintf(). + * + * v2.1 + * - Fixed space padding (i.e %d was extra padded previously) + * - long long output is supported + * - alternate output is done correct like in %#08x + * + ****************************************************************************/ + +static const char rcsid[] = "@(#)$Id$"; + +/* + * To test: + * + * Use WIDTH, PRECISION and NUMBERED ARGUMENT combined. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> + + +#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ +#define MAX_PARAMETERS 128 /* lame static limit */ + +#undef TRUE +#undef FALSE +#undef BOOL +#ifdef __cplusplus +# define TRUE true +# define FALSE false +# define BOOL bool +#else +# define TRUE ((char)(1 == 1)) +# define FALSE ((char)(0 == 1)) +# define BOOL char +#endif + + +/* Lower-case digits. */ +static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/* Upper-case digits. */ +static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#define OUTCHAR(x) done+=(stream(x, (FILE *)data)==-1?0:1) + +/* Data type to read from the arglist */ +typedef enum { + FORMAT_UNKNOWN = 0, + FORMAT_STRING, + FORMAT_PTR, + FORMAT_INT, + FORMAT_INTPTR, + FORMAT_LONG, + FORMAT_LONGLONG, + FORMAT_DOUBLE, + FORMAT_LONGDOUBLE, + FORMAT_WIDTH /* For internal use */ +} FormatType; + +/* convertion and display flags */ +enum { + FLAGS_NEW = 0, + FLAGS_SPACE = 1<<0, + FLAGS_SHOWSIGN = 1<<1, + FLAGS_LEFT = 1<<2, + FLAGS_ALT = 1<<3, + FLAGS_SHORT = 1<<4, + FLAGS_LONG = 1<<5, + FLAGS_LONGLONG = 1<<6, + FLAGS_LONGDOUBLE = 1<<7, + FLAGS_PAD_NIL = 1<<8, + FLAGS_UNSIGNED = 1<<9, + FLAGS_OCTAL = 1<<10, + FLAGS_HEX = 1<<11, + FLAGS_UPPER = 1<<12, + FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */ + FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ + FLAGS_PREC = 1<<15, /* precision was specified */ + FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ + FLAGS_CHAR = 1<<17, /* %c story */ + FLAGS_FLOATE = 1<<18, /* %e or %E */ + FLAGS_FLOATG = 1<<19 /* %g or %G */ +}; + +typedef struct { + FormatType type; + int flags; + int width; /* width OR width parameter number */ + int precision; /* precision OR precision parameter number */ + union { + char *str; + void *ptr; + long num; +#if SIZEOF_LONG_LONG /* if this is non-zero */ + long long lnum; +#endif + double dnum; +#if SIZEOF_LONG_DOUBLE + long double ldnum; +#endif + } data; +} va_stack_t; + +struct nsprintf { + char *buffer; + size_t length; + size_t max; +}; + +struct asprintf { + char *buffer; /* allocated buffer */ + size_t len; /* length of string */ + size_t alloc; /* length of alloc */ +}; + +int msprintf(char *buffer, const char *format, ...); + +static int dprintf_DollarString(char *input, char **end) +{ + int number=0; + while(isdigit((int)*input)) { + number *= 10; + number += *input-'0'; + input++; + } + if(number && ('$'==*input++)) { + *end = input; + return number; + } + return 0; +} + +static BOOL dprintf_IsQualifierNoDollar(char c) +{ + switch (c) { + case '-': case '+': case ' ': case '#': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'h': case 'l': case 'L': case 'Z': case 'q': + return TRUE; + default: + return FALSE; + } +} + +#ifdef DPRINTF_DEBUG2 +int dprintf_Pass1Report(va_stack_t *vto, int max) +{ + int i; + char buffer[128]; + int bit; + int flags; + + for(i=0; i<max; i++) { + char *type; + switch(vto[i].type) { + case FORMAT_UNKNOWN: + type = "unknown"; + break; + case FORMAT_STRING: + type ="string"; + break; + case FORMAT_PTR: + type ="pointer"; + break; + case FORMAT_INT: + type = "int"; + break; + case FORMAT_LONG: + type = "long"; + break; + case FORMAT_LONGLONG: + type = "long long"; + break; + case FORMAT_DOUBLE: + type = "double"; + break; + case FORMAT_LONGDOUBLE: + type = "long double"; + break; + } + + + buffer[0]=0; + + for(bit=0; bit<31; bit++) { + flags = vto[i].flags & (1<<bit); + + if(flags & FLAGS_SPACE) + strcat(buffer, "space "); + else if(flags & FLAGS_SHOWSIGN) + strcat(buffer, "plus "); + else if(flags & FLAGS_LEFT) + strcat(buffer, "left "); + else if(flags & FLAGS_ALT) + strcat(buffer, "alt "); + else if(flags & FLAGS_SHORT) + strcat(buffer, "short "); + else if(flags & FLAGS_LONG) + strcat(buffer, "long "); + else if(flags & FLAGS_LONGLONG) + strcat(buffer, "longlong "); + else if(flags & FLAGS_LONGDOUBLE) + strcat(buffer, "longdouble "); + else if(flags & FLAGS_PAD_NIL) + strcat(buffer, "padnil "); + else if(flags & FLAGS_UNSIGNED) + strcat(buffer, "unsigned "); + else if(flags & FLAGS_OCTAL) + strcat(buffer, "octal "); + else if(flags & FLAGS_HEX) + strcat(buffer, "hex "); + else if(flags & FLAGS_UPPER) + strcat(buffer, "upper "); + else if(flags & FLAGS_WIDTH) + strcat(buffer, "width "); + else if(flags & FLAGS_WIDTHPARAM) + strcat(buffer, "widthparam "); + else if(flags & FLAGS_PREC) + strcat(buffer, "precision "); + else if(flags & FLAGS_PRECPARAM) + strcat(buffer, "precparam "); + else if(flags & FLAGS_CHAR) + strcat(buffer, "char "); + else if(flags & FLAGS_FLOATE) + strcat(buffer, "floate "); + else if(flags & FLAGS_FLOATG) + strcat(buffer, "floatg "); + } + printf("REPORT: %d. %s [%s]\n", i, type, buffer); + + } + + +} +#endif + +/****************************************************************** + * + * Pass 1: + * Create an index with the type of each parameter entry and its + * value (may vary in size) + * + ******************************************************************/ + +static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list arglist) +{ + char *fmt = format; + int param_num = 0; + int this_param; + int width; + int precision; + int flags; + int max_param=0; + int i; + + while (*fmt) { + if (*fmt++ == '%') { + if (*fmt == '%') { + fmt++; + continue; /* while */ + } + + flags = FLAGS_NEW; + + /* Handle the positional case (N$) */ + + param_num++; + + this_param = dprintf_DollarString(fmt, &fmt); + if (0 == this_param) + /* we got no positional, get the next counter */ + this_param = param_num; + + if (this_param > max_param) + max_param = this_param; + + /* + * The parameter with number 'i' should be used. Next, we need + * to get SIZE and TYPE of the parameter. Add the information + * to our array. + */ + + width = 0; + precision = 0; + + /* Handle the flags */ + + while (dprintf_IsQualifierNoDollar(*fmt)) { + switch (*fmt++) { + case ' ': + flags |= FLAGS_SPACE; + break; + case '+': + flags |= FLAGS_SHOWSIGN; + break; + case '-': + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; + break; + case '#': + flags |= FLAGS_ALT; + break; + case '.': + flags |= FLAGS_PREC; + if ('*' == *fmt) { + /* The precision is picked from a specified parameter */ + + flags |= FLAGS_PRECPARAM; + fmt++; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if (i) + precision = i; + else + precision = param_num; + + if (precision > max_param) + max_param = precision; + } + else { + flags |= FLAGS_PREC; + precision = strtol(fmt, &fmt, 10); + } + break; + case 'h': + flags |= FLAGS_SHORT; + break; + case 'l': + if (flags & FLAGS_LONG) + flags |= FLAGS_LONGLONG; + else + flags |= FLAGS_LONG; + break; + case 'L': + flags |= FLAGS_LONGDOUBLE; + break; + case 'q': + flags |= FLAGS_LONGLONG; + break; + case 'Z': + if (sizeof(size_t) > sizeof(unsigned long int)) + flags |= FLAGS_LONGLONG; + if (sizeof(size_t) > sizeof(unsigned int)) + flags |= FLAGS_LONG; + break; + case '0': + if (!(flags & FLAGS_LEFT)) + flags |= FLAGS_PAD_NIL; + /* FALLTHROUGH */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FLAGS_WIDTH; + width = strtol(--fmt, &fmt, 10); + break; + case '*': /* Special case */ + flags |= FLAGS_WIDTHPARAM; + param_num++; + + i = dprintf_DollarString(fmt, &fmt); + if(i) + width = i; + else + width = param_num; + if(width > max_param) + max_param=width; + break; + default: + break; + } + } /* switch */ + + /* Handle the specifier */ + + i = this_param - 1; + + switch (*fmt) { + case 'S': + flags |= FLAGS_ALT; + /* FALLTHROUGH */ + case 's': + vto[i].type = FORMAT_STRING; + break; + case 'n': + vto[i].type = FORMAT_INTPTR; + break; + case 'p': + vto[i].type = FORMAT_PTR; + break; + case 'd': case 'i': + vto[i].type = FORMAT_INT; + break; + case 'u': + vto[i].type = FORMAT_INT; + flags |= FLAGS_UNSIGNED; + break; + case 'o': + vto[i].type = FORMAT_INT; + flags |= FLAGS_OCTAL; + break; + case 'x': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX; + break; + case 'X': + vto[i].type = FORMAT_INT; + flags |= FLAGS_HEX|FLAGS_UPPER; + break; + case 'c': + vto[i].type = FORMAT_INT; + flags |= FLAGS_CHAR; + break; + case 'f': + vto[i].type = FORMAT_DOUBLE; + break; + case 'e': case 'E': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATE| (('E' == *fmt)?FLAGS_UPPER:0); + break; + case 'g': case 'G': + vto[i].type = FORMAT_DOUBLE; + flags |= FLAGS_FLOATG| (('G' == *fmt)?FLAGS_UPPER:0); + break; + default: + vto[i].type = FORMAT_UNKNOWN; + break; + } /* switch */ + + vto[i].flags = flags; + vto[i].width = width; + vto[i].precision = precision; + + if (flags & FLAGS_WIDTHPARAM) { + /* we have the width specified from a parameter, so we make that + parameter's info setup properly */ + vto[i].width = width - 1; + i = width - 1; + vto[i].type = FORMAT_WIDTH; + vto[i].flags = FLAGS_NEW; + vto[i].precision = vto[i].width = 0; /* can't use width or precision + of width! */ + } + if (flags & FLAGS_PRECPARAM) { + /* we have the precision specified from a parameter, so we make that + parameter's info setup properly */ + vto[i].precision = precision - 1; + i = precision - 1; + vto[i].type = FORMAT_WIDTH; + vto[i].flags = FLAGS_NEW; + vto[i].precision = vto[i].width = 0; /* can't use width or precision + of width! */ + } + *endpos++ = fmt + 1; /* end of this sequence */ + } + } + +#ifdef DPRINTF_DEBUG2 + dprintf_Pass1Report(vto, max_param); +#endif + + /* Read the arg list parameters into our data list */ + for (i=0; i<max_param; i++) { + if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) + { + /* Width/precision arguments must be read before the main argument + * they are attached to + */ + vto[i + 1].data.num = va_arg(arglist, int); + } + + switch (vto[i].type) + { + case FORMAT_STRING: + vto[i].data.str = va_arg(arglist, char *); + break; + + case FORMAT_INTPTR: + case FORMAT_UNKNOWN: + case FORMAT_PTR: + vto[i].data.ptr = va_arg(arglist, void *); + break; + + case FORMAT_INT: +#if SIZEOF_LONG_LONG + if(vto[i].flags & FLAGS_LONGLONG) + vto[i].data.lnum = va_arg(arglist, long long); + else +#endif + if(vto[i].flags & FLAGS_LONG) + vto[i].data.num = va_arg(arglist, long); + else + vto[i].data.num = va_arg(arglist, int); + break; + + case FORMAT_DOUBLE: +#if SIZEOF_LONG_DOUBLE + if(vto[i].flags & FLAGS_LONG) + vto[i].data.ldnum = va_arg(arglist, long double); + else +#endif + vto[i].data.dnum = va_arg(arglist, double); + break; + + case FORMAT_WIDTH: + /* Argument has been read. Silently convert it into an integer + * for later use + */ + vto[i].type = FORMAT_INT; + break; + + default: + break; + } + } + + return max_param; + +} + +static int dprintf_formatf( + void *data, /* untouched by format(), just sent to the + stream() function in the first argument */ + int (*stream)(int, FILE *), /* function pointer called for each + output character */ + const char *format, /* %-formatted string */ + va_list ap_save) /* list of parameters */ +{ + /* Base-36 digits for numbers. */ + const char *digits = lower_digits; + + /* Pointer into the format string. */ + char *f; + + /* Number of characters written. */ + register size_t done = 0; + + long param; /* current parameter to read */ + long param_num=0; /* parameter counter */ + + va_stack_t vto[MAX_PARAMETERS]; + char *endpos[MAX_PARAMETERS]; + char **end; + + char work[BUFFSIZE]; + + va_stack_t *p; + + /* Do the actual %-code parsing */ + dprintf_Pass1((char *)format, vto, endpos, ap_save); + + end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() + created for us */ + + f = (char *)format; + while (*f != '\0') { + /* Format spec modifiers. */ + char alt; + + /* Width of a field. */ + register long width; + /* Precision of a field. */ + long prec; + + /* Decimal integer is negative. */ + char is_neg; + + /* Base of a number to be written. */ + long base; + + /* Integral values to be written. */ +#if SIZEOF_LONG_LONG + unsigned long long num; +#else + unsigned long num; +#endif + long signed_num; + + if (*f != '%') { + /* This isn't a format spec, so write everything out until the next one + OR end of string is reached. */ + do { + OUTCHAR(*f); + } while(*++f && ('%' != *f)); + continue; + } + + ++f; + + /* Check for "%%". Note that although the ANSI standard lists + '%' as a conversion specifier, it says "The complete format + specification shall be `%%'," so we can avoid all the width + and precision processing. */ + if (*f == '%') { + ++f; + OUTCHAR('%'); + continue; + } + + /* If this is a positional parameter, the position must follow imediately + after the %, thus create a %<num>$ sequence */ + param=dprintf_DollarString(f, &f); + + if(!param) + param = param_num; + else + --param; + + param_num++; /* increase this always to allow "%2$s %1$s %s" and then the + third %s will pick the 3rd argument */ + + p = &vto[param]; + + /* pick up the specified width */ + if(p->flags & FLAGS_WIDTHPARAM) + width = vto[p->width].data.num; + else + width = p->width; + + /* pick up the specified precision */ + if(p->flags & FLAGS_PRECPARAM) + prec = vto[p->precision].data.num; + else if(p->flags & FLAGS_PREC) + prec = p->precision; + else + prec = -1; + + alt = p->flags & FLAGS_ALT; + + switch (p->type) { + case FORMAT_INT: + num = p->data.num; + if(p->flags & FLAGS_CHAR) { + /* Character. */ + if (!(p->flags & FLAGS_LEFT)) + while (--width > 0) + OUTCHAR(' '); + OUTCHAR((char) num); + if (p->flags & FLAGS_LEFT) + while (--width > 0) + OUTCHAR(' '); + break; + } + if(p->flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer. */ + base = 10; + goto unsigned_number; + } + if(p->flags & FLAGS_OCTAL) { + /* Octal unsigned integer. */ + base = 8; + goto unsigned_number; + } + if(p->flags & FLAGS_HEX) { + /* Hexadecimal unsigned integer. */ + + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + base = 16; + goto unsigned_number; + } + + /* Decimal integer. */ + base = 10; + +#if SIZEOF_LONG_LONG + if(p->flags & FLAGS_LONGLONG) { + /* long long */ + num = p->data.lnum; + is_neg = num < 0; + num = is_neg ? (- num) : num; + } + else +#endif + { + signed_num = (long) num; + + is_neg = signed_num < 0; + num = is_neg ? (- signed_num) : signed_num; + } + goto number; + + unsigned_number:; + /* Unsigned number of base BASE. */ + is_neg = 0; + + number:; + /* Number of base BASE. */ + { + char *workend = &work[sizeof(work) - 1]; + register char *w; + + /* Supply a default precision if none was given. */ + if (prec == -1) + prec = 1; + + /* Put the number in WORK. */ + w = workend; + while (num > 0) { + *w-- = digits[num % base]; + num /= base; + } + width -= workend - w; + prec -= workend - w; + + if (alt && base == 8 && prec <= 0) { + *w-- = '0'; + --width; + } + + if (prec > 0) { + width -= prec; + while (prec-- > 0) + *w-- = '0'; + } + + if (alt && base == 16) + width -= 2; + + if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) + --width; + + if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) + while (width-- > 0) + OUTCHAR(' '); + + if (is_neg) + OUTCHAR('-'); + else if (p->flags & FLAGS_SHOWSIGN) + OUTCHAR('+'); + else if (p->flags & FLAGS_SPACE) + OUTCHAR(' '); + + if (alt && base == 16) { + OUTCHAR('0'); + if(p->flags & FLAGS_UPPER) + OUTCHAR('X'); + else + OUTCHAR('x'); + } + + if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) + while (width-- > 0) + OUTCHAR('0'); + + /* Write the number. */ + while (++w <= workend) { + OUTCHAR(*w); + } + + if (p->flags & FLAGS_LEFT) + while (width-- > 0) + OUTCHAR(' '); + } + break; + + case FORMAT_STRING: + /* String. */ + { + static char null[] = "(nil)"; + char *str; + size_t len; + + str = (char *) p->data.str; + if ( str == NULL) { + /* Write null[] if there's space. */ + if (prec == -1 || prec >= (long) sizeof(null) - 1) { + str = null; + len = sizeof(null) - 1; + /* Disable quotes around (nil) */ + p->flags &= (~FLAGS_ALT); + } + else { + str = ""; + len = 0; + } + } + else + len = strlen(str); + + if (prec != -1 && (size_t) prec < len) + len = prec; + width -= len; + + if (p->flags & FLAGS_ALT) + OUTCHAR('"'); + + if (!(p->flags&FLAGS_LEFT)) + while (width-- > 0) + OUTCHAR(' '); + + while (len-- > 0) + OUTCHAR(*str++); + if (p->flags&FLAGS_LEFT) + while (width-- > 0) + OUTCHAR(' '); + + if (p->flags & FLAGS_ALT) + OUTCHAR('"'); + } + break; + + case FORMAT_PTR: + /* Generic pointer. */ + { + void *ptr; + ptr = (void *) p->data.ptr; + if (ptr != NULL) { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + alt = 1; + num = (unsigned long) ptr; + is_neg = 0; + goto number; + } + else { + /* Write "(nil)" for a nil pointer. */ + static char nil[] = "(nil)"; + register char *point; + + width -= sizeof(nil) - 1; + if (p->flags & FLAGS_LEFT) + while (width-- > 0) + OUTCHAR(' '); + for (point = nil; *point != '\0'; ++point) + OUTCHAR(*point); + if (! (p->flags & FLAGS_LEFT)) + while (width-- > 0) + OUTCHAR(' '); + } + } + break; + + case FORMAT_DOUBLE: + { + char formatbuf[32]="%"; + char *fptr; + + width = -1; + if (p->flags & FLAGS_WIDTH) + width = p->width; + else if (p->flags & FLAGS_WIDTHPARAM) + width = vto[p->width].data.num; + + prec = -1; + if (p->flags & FLAGS_PREC) + prec = p->precision; + else if (p->flags & FLAGS_PRECPARAM) + prec = vto[p->precision].data.num; + + if (p->flags & FLAGS_LEFT) + strcat(formatbuf, "-"); + if (p->flags & FLAGS_SHOWSIGN) + strcat(formatbuf, "+"); + if (p->flags & FLAGS_SPACE) + strcat(formatbuf, " "); + if (p->flags & FLAGS_ALT) + strcat(formatbuf, "#"); + + fptr=&formatbuf[strlen(formatbuf)]; + + if(width >= 0) { + /* RECURSIVE USAGE */ + fptr += msprintf(fptr, "%d", width); + } + if(prec >= 0) { + /* RECURSIVE USAGE */ + fptr += msprintf(fptr, ".%d", prec); + } + if (p->flags & FLAGS_LONG) + strcat(fptr, "l"); + + if (p->flags & FLAGS_FLOATE) + strcat(fptr, p->flags&FLAGS_UPPER?"E":"e"); + else if (p->flags & FLAGS_FLOATG) + strcat(fptr, (p->flags & FLAGS_UPPER) ? "G" : "g"); + else + strcat(fptr, "f"); + + /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number + of output characters */ +#if SIZEOF_LONG_DOUBLE + if (p->flags & FLAGS_LONG) + /* This is for support of the 'long double' type */ + (sprintf)(work, formatbuf, p->data.ldnum); + else +#endif + (sprintf)(work, formatbuf, p->data.dnum); + + for(fptr=work; *fptr; fptr++) + OUTCHAR(*fptr); + } + break; + + case FORMAT_INTPTR: + /* Answer the count of characters written. */ +#if SIZEOF_LONG_LONG + if (p->flags & FLAGS_LONGLONG) + *(long long int *) p->data.ptr = done; + else +#endif + if (p->flags & FLAGS_LONG) + *(long int *) p->data.ptr = done; + else if (!(p->flags & FLAGS_SHORT)) + *(int *) p->data.ptr = done; + else + *(short int *) p->data.ptr = done; + break; + + default: + break; + } + f = *end++; /* goto end of %-code */ + + } + return done; +} + +static int StoreNonPrintable(int output, struct nsprintf *infop) +{ + /* If the character isn't printable then we convert it */ + char work[64], *w; + int num = output; + + w = &work[sizeof(work)]; + *(--w) = (char)0; + for(; num > 0; num /= 10) { + *(--w) = lower_digits[num % 10]; + } + if (infop->length + strlen(w) + 1 < infop->max) + { + infop->buffer[0] = '\\'; + infop->buffer++; + infop->length++; + for (; *w; w++) + { + infop->buffer[0] = *w; + infop->buffer++; + infop->length++; + } + return output; + } + return -1; +} + +/* fputc() look-alike */ +static int addbyter(int output, FILE *data) +{ + struct nsprintf *infop=(struct nsprintf *)data; + + if(infop->length < infop->max) { + /* only do this if we haven't reached max length yet */ + if (isprint(output) || isspace(output)) + { + infop->buffer[0] = (char)output; /* store */ + infop->buffer++; /* increase pointer */ + infop->length++; /* we are now one byte larger */ + } + else + { + return StoreNonPrintable(output, infop); + } + return output; /* fputc() returns like this on success */ + } + return -1; +} + +int msnprintf(char *buffer, size_t maxlength, const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + struct nsprintf info; + + info.buffer = buffer; + info.length = 0; + info.max = maxlength; + + va_start(ap_save, format); + retcode = dprintf_formatf(&info, addbyter, format, ap_save); + va_end(ap_save); + info.buffer[0] = 0; /* we terminate this with a zero byte */ + + /* we could even return things like */ + + return retcode; +} + +int mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list ap_save) +{ + int retcode; + struct nsprintf info; + + info.buffer = buffer; + info.length = 0; + info.max = maxlength; + + retcode = dprintf_formatf(&info, addbyter, format, ap_save); + info.buffer[0] = 0; /* we terminate this with a zero byte */ + return retcode; +} + + +/* fputc() look-alike */ +static int alloc_addbyter(int output, FILE *data) +{ + struct asprintf *infop=(struct asprintf *)data; + + if(!infop->buffer) { + infop->buffer=(char *)malloc(32); + if(!infop->buffer) + return -1; /* fail */ + infop->alloc = 32; + infop->len =0; + } + else if(infop->len+1 >= infop->alloc) { + char *newptr; + + newptr = (char *)realloc(infop->buffer, infop->alloc*2); + + if(!newptr) { + return -1; + } + infop->buffer = newptr; + infop->alloc *= 2; + } + + infop->buffer[ infop->len ] = output; + + infop->len++; + + return output; /* fputc() returns like this on success */ + +} + +char *maprintf(const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + + va_start(ap_save, format); + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + va_end(ap_save); + if(info.len) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return NULL; +} + +char *mvaprintf(const char *format, va_list ap_save) +{ + int retcode; + struct asprintf info; + + info.buffer = NULL; + info.len = 0; + info.alloc = 0; + + retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + if(info.len) { + info.buffer[info.len] = 0; /* we terminate this with a zero byte */ + return info.buffer; + } + else + return NULL; +} + +static int storebuffer(int output, FILE *data) +{ + char **buffer = (char **)data; + **buffer = (char)output; + (*buffer)++; + return output; /* act like fputc() ! */ +} + +int msprintf(char *buffer, const char *format, ...) +{ + va_list ap_save; /* argument pointer */ + int retcode; + va_start(ap_save, format); + retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + va_end(ap_save); + *buffer=0; /* we terminate this with a zero byte */ + return retcode; +} + +extern int fputc(int, FILE *); + +int mprintf(const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = dprintf_formatf(stdout, fputc, format, ap_save); + va_end(ap_save); + return retcode; +} + +int mfprintf(FILE *whereto, const char *format, ...) +{ + int retcode; + va_list ap_save; /* argument pointer */ + va_start(ap_save, format); + retcode = dprintf_formatf(whereto, fputc, format, ap_save); + va_end(ap_save); + return retcode; +} + +int mvsprintf(char *buffer, const char *format, va_list ap_save) +{ + int retcode; + retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + *buffer=0; /* we terminate this with a zero byte */ + return retcode; +} + +int mvprintf(const char *format, va_list ap_save) +{ + return dprintf_formatf(stdout, fputc, format, ap_save); +} + +int mvfprintf(FILE *whereto, const char *format, va_list ap_save) +{ + return dprintf_formatf(whereto, fputc, format, ap_save); +} + +#ifdef DPRINTF_DEBUG +int main() +{ + char buffer[129]; + char *ptr; +#ifdef SIZEOF_LONG_LONG + long long hullo; + dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65); +#endif + + mprintf("%3d %5d\n", 10, 1998); + + ptr=maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001); + + puts(ptr); + + memset(ptr, 55, strlen(ptr)+1); + + free(ptr); + +#if 1 + mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988); + puts(buffer); + + mfprintf(stderr, "%s %#08x\n", "dummy", 65); + + printf("%s %#08x\n", "dummy", 65); + { + double tryout = 3.14156592; + mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout); + puts(buffer); + printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout); + } +#endif + + return 0; +} + +#endif diff --git a/lib/netrc.c b/lib/netrc.c new file mode 100644 index 000000000..f0e1382fe --- /dev/null +++ b/lib/netrc.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * Contributor(s): + * Rafael Sagula <sagula@inf.ufrgs.br> + * Sampo Kellomaki <sampo@iki.fi> + * Linas Vepstas <linas@linas.org> + * Bjorn Reese <breese@imada.ou.dk> + * Johan Anderson <johan@homemail.com> + * Kjell Ericson <Kjell.Ericson@haxx.nu> + * Troy Engel <tengel@palladium.net> + * Ryan Nelson <ryan@inch.com> + * Bjorn Stenberg <Bjorn.Stenberg@haxx.nu> + * Angus Mackay <amackay@gus.ml.org> + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "setup.h" +#include "getenv.h" + +/* Debug this single source file with: + 'make netrc' then run './netrc'! + + Oh, make sure you have a .netrc file too ;-) + */ + +/* Get user and password from .netrc when given a machine name */ + +enum { + NOTHING, + HOSTFOUND, /* the 'machine' keyword was found */ + HOSTCOMPLETE, /* the machine name following the keyword was found too */ + HOSTVALID, /* this is "our" machine! */ + + HOSTEND /* LAST enum */ +}; + +/* make sure we have room for at least this size: */ +#define LOGINSIZE 64 +#define PASSWORDSIZE 64 + +int ParseNetrc(char *host, + char *login, + char *password) +{ + FILE *file; + char netrcbuffer[256]; + int retcode=1; + + char *home = GetEnv("HOME"); /* portable environment reader */ + int state=NOTHING; + + char state_login=0; + char state_password=0; + +#define NETRC DOT_CHAR "netrc" + + if(!home || (strlen(home)>(sizeof(netrcbuffer)-strlen(NETRC)))) + return -1; + + sprintf(netrcbuffer, "%s%s%s", home, DIR_CHAR, NETRC); + + file = fopen(netrcbuffer, "r"); + if(file) { + char *tok; + while(fgets(netrcbuffer, sizeof(netrcbuffer), file)) { + tok=strtok(netrcbuffer, " \t\n"); + while(tok) { + switch(state) { + case NOTHING: + if(strequal("machine", tok)) { + /* the next tok is the machine name, this is in itself the + delimiter that starts the stuff entered for this machine, + after this we need to search for 'login' and + 'password'. */ + state=HOSTFOUND; + } + break; + case HOSTFOUND: + if(strequal(host, tok)) { + /* and yes, this is our host! */ + state=HOSTVALID; +#ifdef _NETRC_DEBUG + printf("HOST: %s\n", tok); +#endif + retcode=0; /* we did find our host */ + } + else + /* not our host */ + state=NOTHING; + break; + case HOSTVALID: + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + strncpy(login, tok, LOGINSIZE-1); +#ifdef _NETRC_DEBUG + printf("LOGIN: %s\n", login); +#endif + state_login=0; + } + else if(state_password) { + strncpy(password, tok, PASSWORDSIZE-1); +#if _NETRC_DEBUG + printf("PASSWORD: %s\n", password); +#endif + state_password=0; + } + else if(strequal("login", tok)) + state_login=1; + else if(strequal("password", tok)) + state_password=1; + else if(strequal("machine", tok)) { + /* ok, there's machine here go => */ + state = HOSTFOUND; + } + break; + } /* switch (state) */ + tok = strtok(NULL, " \t\n"); + } /* while (tok) */ + } /* while fgets() */ + + fclose(file); + } + + return retcode; +} + +#ifdef _NETRC_DEBUG +int main(int argc, char **argv) +{ + char login[64]=""; + char password[64]=""; + + if(argc<2) + return -1; + + if(0 == ParseNetrc(argv[1], login, password)) { + printf("HOST: %s LOGIN: %s PASSWORD: %s\n", + argv[1], login, password); + } +} + +#endif diff --git a/lib/netrc.h b/lib/netrc.h new file mode 100644 index 000000000..2875cbc53 --- /dev/null +++ b/lib/netrc.h @@ -0,0 +1,70 @@ +#ifndef __NETRC_H +#define __NETRC_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * Contributor(s): + * Rafael Sagula <sagula@inf.ufrgs.br> + * Sampo Kellomaki <sampo@iki.fi> + * Linas Vepstas <linas@linas.org> + * Bjorn Reese <breese@imada.ou.dk> + * Johan Anderson <johan@homemail.com> + * Kjell Ericson <Kjell.Ericson@haxx.nu> + * Troy Engel <tengel@palladium.net> + * Ryan Nelson <ryan@inch.com> + * Bjorn Stenberg <Bjorn.Stenberg@haxx.nu> + * Angus Mackay <amackay@gus.ml.org> + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + * $Log$ + * Revision 1.1 1999-12-29 14:21:35 bagder + * Initial revision + * + * Revision 1.3 1999/09/06 06:59:41 dast + * Changed email info + * + * Revision 1.2 1999/08/13 07:34:48 dast + * Changed the URL in the header + * + * Revision 1.1.1.1 1999/03/11 22:23:34 dast + * Imported sources + * + ****************************************************************************/ +int ParseNetrc(char *host, + char *login, + char *password); +#endif diff --git a/lib/progress.c b/lib/progress.c new file mode 100644 index 000000000..6a083370b --- /dev/null +++ b/lib/progress.c @@ -0,0 +1,221 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <string.h> +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#if defined(__MINGW32__) +#include <winsock.h> +#endif +#include <time.h> +#endif + +#include <curl/curl.h> +#include "urldata.h" + +#include "progress.h" + +/* --- start of progress routines --- */ +int progressmax=-1; + +static int prev = 0; +static int width = 0; + +void ProgressInit(struct UrlData *data, int max) +{ + if(data->conf&(CONF_NOPROGRESS|CONF_MUTE)) + return; + + prev = 0; + +/* TODO: get terminal width through ansi escapes or something similar. + try to update width when xterm is resized... - 19990617 larsa */ + if (curl_GetEnv("COLUMNS") != NULL) + width = atoi(curl_GetEnv("COLUMNS")); + else + width = 80; + + progressmax = max; + if(-1 == max) + return; + if(progressmax <= LEAST_SIZE_PROGRESS) { + progressmax = -1; /* disable */ + return; + } + + if ( data->progressmode == CURL_PROGRESS_STATS ) + fprintf(data->err, + " %% Received Total Speed Time left Total Curr.Speed\n"); +} + +void time2str(char *r, int t) +{ + int h = (t/3600); + int m = (t-(h*3600))/60; + int s = (t-(h*3600)-(m*60)); + sprintf(r,"%3d:%02d:%02d",h,m,s); +} + +void ProgressShow(struct UrlData *data, + int point, struct timeval start, struct timeval now, bool force) +{ + switch ( data->progressmode ) { + case CURL_PROGRESS_STATS: + { + static long lastshow; + double percen; + + double spent; + double speed; + +#define CURR_TIME 5 + + static int speeder[ CURR_TIME ]; + static int speeder_c=0; + + int nowindex = speeder_c% CURR_TIME; + int checkindex; + int count; + + if(!force && (point != progressmax) && (lastshow == tvlong(now))) + return; /* never update this more than once a second if the end isn't + reached */ + + spent = tvdiff (now, start); + speed = point/(spent!=0.0?spent:1.0); + if(!speed) + speed=1; + + /* point is where we are right now */ + speeder[ nowindex ] = point; + speeder_c++; /* increase */ + count = ((speeder_c>=CURR_TIME)?CURR_TIME:speeder_c) - 1; + checkindex = (speeder_c>=CURR_TIME)?speeder_c%CURR_TIME:0; + + /* find out the average speed the last CURR_TIME seconds */ + data->current_speed = (speeder[nowindex]-speeder[checkindex])/(count?count:1); + +#if 0 + printf("NOW %d(%d) THEN %d(%d) DIFF %lf COUNT %d\n", + speeder[nowindex], nowindex, + speeder[checkindex], checkindex, + data->current_speed, count); +#endif + + if(data->conf&(CONF_NOPROGRESS|CONF_MUTE)) + return; + + if(-1 != progressmax) { + char left[20],estim[20]; + int estimate = progressmax/(int) speed; + + time2str(left,estimate-(int) spent); + time2str(estim,estimate); + + percen=(double)point/progressmax; + percen=percen*100; + + fprintf(data->err, "\r%3d %8d %8d %6.0lf %s %s %6.0lf ", + (int)percen, point, progressmax, + speed, left, estim, data->current_speed); + } + else + fprintf(data->err, + "\r%d bytes received in %.3lf seconds (%.0lf bytes/sec)", + point, spent, speed); + + lastshow = now.tv_sec; + break; + } + case CURL_PROGRESS_BAR: /* 19990617 larsa */ + { + if (point == prev) break; + if (progressmax == -1) { + int prevblock = prev / 1024; + int thisblock = point / 1024; + while ( thisblock > prevblock ) { + fprintf( data->err, "#" ); + prevblock++; + } + prev = point; + } else { + char line[256]; + char outline[256]; + char format[40]; + float frac = (float) point / (float) progressmax; + float percent = frac * 100.0f; + int barwidth = width - 7; + int num = (int) (((float)barwidth) * frac); + int i = 0; + for ( i = 0; i < num; i++ ) { + line[i] = '#'; + } + line[i] = '\0'; + sprintf( format, "%%-%ds %%5.1f%%%%", barwidth ); + sprintf( outline, format, line, percent ); + fprintf( data->err, "\r%s", outline ); + } + prev = point; + break; + } + default: /* 19990617 larsa */ + { + int prevblock = prev / 1024; + int thisblock = point / 1024; + if (prev == point) break; + while ( thisblock > prevblock ) { + fprintf( data->err, "#" ); + prevblock++; + } + prev = point; + break; + } + } +} + +void ProgressEnd(struct UrlData *data) +{ + if(data->conf&(CONF_NOPROGRESS|CONF_MUTE)) + return; + fputs("\n", data->err); +} + +/* --- end of progress routines --- */ diff --git a/lib/progress.h b/lib/progress.h new file mode 100644 index 000000000..6babd89ca --- /dev/null +++ b/lib/progress.h @@ -0,0 +1,54 @@ +#ifndef __PROGRESS_H +#define __PROGRESS_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include "timeval.h" + +void ProgressInit(struct UrlData *data, int max); +void ProgressShow(struct UrlData *data, + int point, struct timeval start, struct timeval now, bool force); +void ProgressEnd(struct UrlData *data); +void ProgressMode(int mode); + +/* Don't show progress for sizes smaller than: */ +#define LEAST_SIZE_PROGRESS BUFSIZE + +#endif /* __PROGRESS_H */ diff --git a/lib/sendf.c b/lib/sendf.c new file mode 100644 index 000000000..387984d9d --- /dev/null +++ b/lib/sendf.c @@ -0,0 +1,115 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#endif + +#include <curl/curl.h> +#include "urldata.h" + +#include <curl/mprintf.h> + +/* infof() is for info message along the way */ + +void infof(struct UrlData *data, char *fmt, ...) +{ + va_list ap; + if(data->conf & CONF_VERBOSE) { + va_start(ap, fmt); + fputs("* ", data->err); + vfprintf(data->err, fmt, ap); + va_end(ap); + } +} + +/* failf() is for messages stating why we failed, the LAST one will be + returned for the user (if requested) */ + +void failf(struct UrlData *data, char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if(data->errorbuffer) + vsprintf(data->errorbuffer, fmt, ap); + else /* no errorbuffer receives this, write to data->err instead */ + vfprintf(data->err, fmt, ap); + va_end(ap); +} + +/* sendf() sends the formated data to the server */ + +int sendf(int fd, struct UrlData *data, char *fmt, ...) +{ + size_t bytes_written; + char *s; + va_list ap; + va_start(ap, fmt); + s = mvaprintf(fmt, ap); + va_end(ap); + if(!s) + return 0; /* failure */ + if(data->conf & CONF_VERBOSE) + fprintf(data->err, "> %s", s); +#ifndef USE_SSLEAY + bytes_written = swrite(fd, s, strlen(s)); +#else + if (data->use_ssl) { + bytes_written = SSL_write(data->ssl, s, strlen(s)); + } else { + bytes_written = swrite(fd, s, strlen(s)); + } +#endif /* USE_SSLEAY */ + free(s); /* free the output string */ + return(bytes_written); +} + + + + diff --git a/lib/sendf.h b/lib/sendf.h new file mode 100644 index 000000000..de6571930 --- /dev/null +++ b/lib/sendf.h @@ -0,0 +1,47 @@ +#ifndef __SENDF_H +#define __SENDF_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +int sendf(int fd, struct UrlData *, char *fmt, ...); +void infof(struct UrlData *, char *fmt, ...); +void failf(struct UrlData *, char *fmt, ...); + +#endif diff --git a/lib/setup.h b/lib/setup.h new file mode 100644 index 000000000..6770ec6c4 --- /dev/null +++ b/lib/setup.h @@ -0,0 +1,169 @@ +#ifndef __SETUP_H +#define __SETUP_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> + +#if !defined(WIN32) && defined(_WIN32) +/* This _might_ be a good Borland fix. Please report whether this works or + not! */ +#define WIN32 +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" /* the configure script results */ +#else +#ifdef WIN32 +/* include the hand-modified win32 adjusted config.h! */ +#include "../config-win32.h" +#endif +#endif + + + +#ifndef OS +#ifdef WIN32 +#define OS "win32" +#else +#define OS "unknown" +#endif +#endif + +#if defined(HAVE_X509_H) && defined(HAVE_SSL_H) && defined(HAVE_RSA_H) && \ +defined(HAVE_PEM_H) && defined(HAVE_ERR_H) && defined(HAVE_CRYPTO_H) && \ +defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO) + /* the six important includes files all exist and so do both libs, + defined SSLeay usage */ +#define USE_SSLEAY 1 +#endif +#if defined(HAVE_OPENSSL_X509_H) && defined(HAVE_OPENSSL_SSL_H) && \ +defined(HAVE_OPENSSL_RSA_H) && defined(HAVE_OPENSSL_PEM_H) && \ +defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_CRYPTO_H) && \ +defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO) + /* the six important includes files all exist and so do both libs, + defined SSLeay usage */ +#define USE_SSLEAY 1 +#define USE_OPENSSL 1 +#endif + +#ifndef STDC_HEADERS /* no standard C headers! */ +#include "stdcheaders.h" +#else +#ifdef _AIX +#include "stdcheaders.h" +#endif +#endif + +#if 0 /* zlib experiments are halted 17th october, 1999 (Daniel) */ +#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) + /* Both lib and header file exist, we have libz! */ +#define USE_ZLIB +#endif +#endif + +#ifdef HAVE_STRCASECMP +#define strnequal(x,y,z) !(strncasecmp)(x,y,z) +#define strequal(x,y) !(strcasecmp)(x,y) + +#else +#define strnequal(x,y,z) !strnicmp(x,y,z) +#define strequal(x,y) !stricmp(x,y) +#endif + +/* Below we define four functions. They should + 1. close a socket + 2. read from a socket + 3. write to a socket + (Hopefully, only win32-crap do this weird name changing) + + 4. set the SIGALRM signal timeout + 5. set dir/file naming defines + */ + +#ifdef WIN32 +#if !defined(__GNUC__) || defined(__MINGW32__) +#define sclose(x) closesocket(x) +#define sread(x,y,z) recv(x,y,z,0) +#define swrite(x,y,z) (size_t)send(x,y,z,0) +#define myalarm(x) /* win32 is a silly system */ +#else + /* gcc-for-win is still good :) */ +#define sclose(x) close(x) +#define sread(x,y,z) read(x,y,z) +#define swrite(x,y,z) write(x,y,z) +#define myalarm(x) alarm(x) +#endif + +#define PATH_CHAR ";" +#define DIR_CHAR "\\" +#define DOT_CHAR "_" + +#else +#define sclose(x) close(x) +#define sread(x,y,z) read(x,y,z) +#define swrite(x,y,z) write(x,y,z) +#define myalarm(x) alarm(x) + +#define PATH_CHAR ":" +#define DIR_CHAR "/" +#define DOT_CHAR "." + +#ifdef HAVE_STRCASECMP +/* this is for "-ansi -Wall -pedantic" to stop complaining! */ +extern int (strcasecmp)(const char *s1, const char *s2); +extern int (strncasecmp)(const char *s1, const char *s2, size_t n); +#ifndef fileno /* sunos 4 have this as a macro! */ +int fileno( FILE *stream); +#endif +#endif + +#endif + +/* + * FIXME: code for getting a passwd in windows/non termcap/signal systems? + */ +#ifndef WIN32 +#define get_password(x) getpass(x) +#else +#define get_password(x) +#endif + +#endif /* __CONFIG_H */ diff --git a/lib/speedcheck.c b/lib/speedcheck.c new file mode 100644 index 000000000..5647b50e2 --- /dev/null +++ b/lib/speedcheck.c @@ -0,0 +1,81 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <stdio.h> +#if defined(__MINGW32__) +#include <winsock.h> +#endif + +#include <curl/curl.h> +#include "urldata.h" +#include "sendf.h" +#include "speedcheck.h" + +UrgError speedcheck(struct UrlData *data, + struct timeval now) +{ + static struct timeval keeps_speed; + + if((data->current_speed >= 0) && + data->low_speed_time && + (tvlong(keeps_speed) != 0) && + (data->current_speed < data->low_speed_limit)) { + + /* We are now below the "low speed limit". If we are below it + for "low speed time" seconds we consider that enough reason + to abort the download. */ + + if( tvdiff(now, keeps_speed) > data->low_speed_time) { + /* we have been this slow for long enough, now die */ + failf(data, + "Operation too slow. " + "Less than %d bytes/sec transfered the last %d seconds", + data->low_speed_limit, + data->low_speed_time); + return URG_OPERATION_TIMEOUTED; + } + } + else { + /* we keep up the required speed all right */ + keeps_speed = now; + } + return URG_OK; +} + diff --git a/lib/speedcheck.h b/lib/speedcheck.h new file mode 100644 index 000000000..27e7ba2f6 --- /dev/null +++ b/lib/speedcheck.h @@ -0,0 +1,50 @@ +#ifndef __SPEEDCHECK_H +#define __SPEEDCHECK_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include "setup.h" + +#include "timeval.h" + +UrgError speedcheck(struct UrlData *data, + struct timeval now); + +#endif diff --git a/lib/ssluse.c b/lib/ssluse.c new file mode 100644 index 000000000..bb78df009 --- /dev/null +++ b/lib/ssluse.c @@ -0,0 +1,265 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <string.h> +#include <stdlib.h> + +#include "urldata.h" +#include "sendf.h" + +#ifdef USE_SSLEAY + +static char global_passwd[64]; + +static int passwd_callback(char *buf, int num, int verify +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + /* This was introduced in 0.9.4, we can set this + using SSL_CTX_set_default_passwd_cb_userdata() + */ + , void *userdata +#endif + ) +{ + if(verify) + fprintf(stderr, "%s\n", buf); + else { + if(num > strlen(global_passwd)) { + strcpy(buf, global_passwd); + return strlen(buf); + } + } + return 0; +} + +/* This function is *highly* inspired by (and parts are directly stolen + * from) source from the SSLeay package written by Eric Young + * (eay@cryptsoft.com). */ + +int SSL_cert_stuff(struct UrlData *data, + char *cert_file, + char *key_file) +{ + if (cert_file != NULL) { + SSL *ssl; + X509 *x509; + + if(data->cert_passwd) { + /* + * If password has been given, we store that in the global + * area (*shudder*) for a while: + */ + strcpy(global_passwd, data->cert_passwd); + /* Set passwd callback: */ + SSL_CTX_set_default_passwd_cb(data->ctx, passwd_callback); + } + + if (SSL_CTX_use_certificate_file(data->ctx, + cert_file, + SSL_FILETYPE_PEM) <= 0) { + failf(data, "unable to set certificate file (wrong password?)\n"); + return(0); + } + if (key_file == NULL) + key_file=cert_file; + + if (SSL_CTX_use_PrivateKey_file(data->ctx, + key_file, + SSL_FILETYPE_PEM) <= 0) { + failf(data, "unable to set public key file\n"); + return(0); + } + + ssl=SSL_new(data->ctx); + x509=SSL_get_certificate(ssl); + + if (x509 != NULL) + EVP_PKEY_copy_parameters(X509_get_pubkey(x509), + SSL_get_privatekey(ssl)); + SSL_free(ssl); + + /* If we are using DSA, we can copy the parameters from + * the private key */ + + + /* Now we know that a key and cert have been set against + * the SSL context */ + if (!SSL_CTX_check_private_key(data->ctx)) { + failf(data, "Private key does not match the certificate public key\n"); + return(0); + } + + /* erase it now */ + memset(global_passwd, 0, sizeof(global_passwd)); + } + return(1); +} + +#endif + +#if SSL_VERIFY_CERT +int cert_verify_callback(int ok, X509_STORE_CTX *ctx) +{ + X509 *err_cert; + char buf[256]; + + err_cert=X509_STORE_CTX_get_current_cert(ctx); + X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256); + + return 1; +} + +#endif + +/* ====================================================== */ +int +UrgSSLConnect (struct UrlData *data) +{ +#ifdef USE_SSLEAY + int err; + char * str; + SSL_METHOD *req_method; + + /* mark this is being ssl enabled from here on out. */ + data->use_ssl = 1; + + /* Lets get nice error messages */ + SSL_load_error_strings(); + + /* Setup all the global SSL stuff */ + SSLeay_add_ssl_algorithms(); + + switch(data->ssl_version) { + default: + req_method = SSLv23_client_method(); + break; + case 2: + req_method = SSLv2_client_method(); + break; + case 3: + req_method = SSLv3_client_method(); + break; + } + + data->ctx = SSL_CTX_new(req_method); + + if(!data->ctx) { + failf(data, "SSL: couldn't create a context!"); + return 1; + } + + if(data->cert) { + if (!SSL_cert_stuff(data, data->cert, data->cert)) { + failf(data, "couldn't use certificate!\n"); + return 2; + } + } + +#if SSL_VERIFY_CERT + SSL_CTX_set_verify(data->ctx, + SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT| + SSL_VERIFY_CLIENT_ONCE, + cert_verify_callback); +#endif + + /* Lets make an SSL structure */ + data->ssl = SSL_new (data->ctx); + SSL_set_connect_state (data->ssl); + + data->server_cert = 0x0; + + /* pass the raw socket into the SSL layers */ + SSL_set_fd (data->ssl, data->firstsocket); + err = SSL_connect (data->ssl); + + if (-1 == err) { + err = ERR_get_error(); + failf(data, "SSL: %s", ERR_error_string(err, NULL)); + return 10; + } + + + infof (data, "SSL connection using %s\n", SSL_get_cipher (data->ssl)); + + /* Get server's certificate (note: beware of dynamic allocation) - opt */ + /* major serious hack alert -- we should check certificates + * to authenticate the server; otherwise we risk man-in-the-middle + * attack + */ + + data->server_cert = SSL_get_peer_certificate (data->ssl); + if(!data->server_cert) { + failf(data, "SSL: couldn't get peer certificate!"); + return 3; + } + infof (data, "Server certificate:\n"); + + str = X509_NAME_oneline (X509_get_subject_name (data->server_cert), NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-subject!"); + return 4; + } + infof (data, "\t subject: %s\n", str); + Free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (data->server_cert), NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-issuer name!"); + return 5; + } + infof (data, "\t issuer: %s\n", str); + Free (str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + +#if SSL_VERIFY_CERT + infof(data, "Verify result: %d\n", SSL_get_verify_result(data->ssl)); +#endif + + + + X509_free (data->server_cert); +#else /* USE_SSLEAY */ + /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ + (void) data; +#endif + return 0; +} diff --git a/lib/ssluse.h b/lib/ssluse.h new file mode 100644 index 000000000..c1996b28e --- /dev/null +++ b/lib/ssluse.h @@ -0,0 +1,46 @@ +#ifndef __SSLUSE_H +#define __SSLUSE_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +int SSL_cert_stuff(struct UrlData *data, + char *cert_file, + char *key_file); +int UrgSSLConnect (struct UrlData *data); +#endif diff --git a/lib/sta01005 b/lib/sta01005 Binary files differnew file mode 100644 index 000000000..31cd282d1 --- /dev/null +++ b/lib/sta01005 diff --git a/lib/sta18057 b/lib/sta18057 Binary files differnew file mode 100644 index 000000000..36d824b46 --- /dev/null +++ b/lib/sta18057 diff --git a/lib/telnet.c b/lib/telnet.c new file mode 100644 index 000000000..8ca12450d --- /dev/null +++ b/lib/telnet.c @@ -0,0 +1,937 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + * + * This implementation of the TELNET protocol is written by + * Linus Nielsen <Linus.Nielsen@haxx.nu>, + * with some code snippets stolen from the BSD Telnet client. + * + * The negotiation is performed according to RFC 1143 (D. Bernstein, + * "The Q Method of Implementing TELNET Option Negotiation") + * + ****************************************************************************/ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#include <time.h> +#include <io.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <sys/time.h> +#include <sys/resource.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> +#include <signal.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "download.h" +#include "sendf.h" +#include "formdata.h" +#include "progress.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#define TELOPTS +#define TELCMDS +#define SLC_NAMES + +#include "arpa_telnet.h" + +#define SUBBUFSIZE 512 + +#define SB_CLEAR() subpointer = subbuffer; +#define SB_TERM() { subend = subpointer; SB_CLEAR(); } +#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ + *subpointer++ = (c); \ + } + +#define SB_GET() ((*subpointer++)&0xff) +#define SB_PEEK() ((*subpointer)&0xff) +#define SB_EOF() (subpointer >= subend) +#define SB_LEN() (subend - subpointer) + +void telwrite(struct UrlData *data, + unsigned char *buffer, /* Data to write */ + int count); /* Number of bytes to write */ + +void telrcv(struct UrlData *data, + unsigned char *inbuf, /* Data received from socket */ + int count); /* Number of bytes received */ + +static void printoption(struct UrlData *data, + const char *direction, + int cmd, int option); + +static void negotiate(struct UrlData *data); +static void send_negotiation(struct UrlData *data, int cmd, int option); +static void set_local_option(struct UrlData *data, int cmd, int option); +static void set_remote_option(struct UrlData *data, int cmd, int option); + +static void printsub(struct UrlData *data, + int direction, unsigned char *pointer, int length); +static void suboption(struct UrlData *data); + +/* suboptions */ +static char subbuffer[SUBBUFSIZE]; +static char *subpointer, *subend; /* buffer for sub-options */ + +/* + * Telnet receiver states for fsm + */ +static enum +{ + TS_DATA = 0, + TS_IAC, + TS_WILL, + TS_WONT, + TS_DO, + TS_DONT, + TS_CR, + TS_SB, /* sub-option collection */ + TS_SE /* looking for sub-option end */ +} telrcv_state; + +/* For negotiation compliant to RFC 1143 */ +#define NO 0 +#define YES 1 +#define WANTYES 2 +#define WANTNO 3 + +#define EMPTY 0 +#define OPPOSITE 1 + +static int us[256]; +static int usq[256]; +static int us_preferred[256]; +static int him[256]; +static int himq[256]; +static int him_preferred[256]; + +void init_telnet(struct UrlData *data) +{ + telrcv_state = TS_DATA; + + /* Init suboptions */ + SB_CLEAR(); + + /* Set all options to NO */ + memset(us, NO, 256); + memset(usq, NO, 256); + memset(us_preferred, NO, 256); + memset(him, NO, 256); + memset(himq, NO, 256); + memset(him_preferred, NO, 256); + + /* Set the options we want */ + us_preferred[TELOPT_BINARY] = YES; + us_preferred[TELOPT_SGA] = YES; + him_preferred[TELOPT_BINARY] = YES; + him_preferred[TELOPT_SGA] = YES; + + /* Start negotiating */ + negotiate(data); +} + +static void negotiate(struct UrlData *data) +{ + int i; + + for(i = 0;i < NTELOPTS;i++) + { + if(us_preferred[i] == YES) + set_local_option(data, i, YES); + + if(him_preferred[i] == YES) + set_remote_option(data, i, YES); + } +} + +static void printoption(struct UrlData *data, + const char *direction, int cmd, int option) +{ + char *fmt; + char *opt; + + if (data->conf & CONF_VERBOSE) + { + if (cmd == IAC) + { + if (TELCMD_OK(option)) + printf("%s IAC %s\n", direction, TELCMD(option)); + else + printf("%s IAC %d\n", direction, option); + } + else + { + fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : + (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; + if (fmt) + { + if (TELOPT_OK(option)) + opt = TELOPT(option); + else if (option == TELOPT_EXOPL) + opt = "EXOPL"; + else + opt = NULL; + + if(opt) + printf("%s %s %s\n", direction, fmt, opt); + else + printf("%s %s %d\n", direction, fmt, option); + } + else + printf("%s %d %d\n", direction, cmd, option); + } + } +} + +static void send_negotiation(struct UrlData *data, int cmd, int option) +{ + unsigned char buf[3]; + + buf[0] = IAC; + buf[1] = cmd; + buf[2] = option; + + swrite(data->firstsocket, buf, 3); + + printoption(data, "SENT", cmd, option); +} + +void set_remote_option(struct UrlData *data, int option, int newstate) +{ + if(newstate == YES) + { + switch(him[option]) + { + case NO: + him[option] = WANTYES; + send_negotiation(data, DO, option); + break; + + case YES: + /* Already enabled */ + break; + + case WANTNO: + switch(himq[option]) + { + case EMPTY: + /* Already negotiating for YES, queue the request */ + himq[option] = OPPOSITE; + break; + case OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case WANTYES: + switch(himq[option]) + { + case EMPTY: + /* Error: already negotiating for enable */ + break; + case OPPOSITE: + himq[option] = EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(him[option]) + { + case NO: + /* Already disabled */ + break; + + case YES: + him[option] = WANTNO; + send_negotiation(data, DONT, option); + break; + + case WANTNO: + switch(himq[option]) + { + case EMPTY: + /* Already negotiating for NO */ + break; + case OPPOSITE: + himq[option] = EMPTY; + break; + } + break; + + case WANTYES: + switch(himq[option]) + { + case EMPTY: + himq[option] = OPPOSITE; + break; + case OPPOSITE: + break; + } + break; + } + } +} + +void rec_will(struct UrlData *data, int option) +{ + switch(him[option]) + { + case NO: + if(him_preferred[option] == YES) + { + him[option] = YES; + send_negotiation(data, DO, option); + } + else + { + send_negotiation(data, DONT, option); + } + break; + + case YES: + /* Already enabled */ + break; + + case WANTNO: + switch(himq[option]) + { + case EMPTY: + /* Error: DONT answered by WILL */ + him[option] = NO; + break; + case OPPOSITE: + /* Error: DONT answered by WILL */ + him[option] = YES; + himq[option] = EMPTY; + break; + } + break; + + case WANTYES: + switch(himq[option]) + { + case EMPTY: + him[option] = YES; + break; + case OPPOSITE: + him[option] = WANTNO; + himq[option] = EMPTY; + send_negotiation(data, DONT, option); + break; + } + break; + } +} + +void rec_wont(struct UrlData *data, int option) +{ + switch(him[option]) + { + case NO: + /* Already disabled */ + break; + + case YES: + him[option] = NO; + send_negotiation(data, DONT, option); + break; + + case WANTNO: + switch(himq[option]) + { + case EMPTY: + him[option] = NO; + break; + + case OPPOSITE: + him[option] = WANTYES; + himq[option] = EMPTY; + send_negotiation(data, DO, option); + break; + } + break; + + case WANTYES: + switch(himq[option]) + { + case EMPTY: + him[option] = NO; + break; + case OPPOSITE: + him[option] = NO; + himq[option] = EMPTY; + break; + } + break; + } +} + +void set_local_option(struct UrlData *data, int option, int newstate) +{ + if(newstate == YES) + { + switch(us[option]) + { + case NO: + us[option] = WANTYES; + send_negotiation(data, WILL, option); + break; + + case YES: + /* Already enabled */ + break; + + case WANTNO: + switch(usq[option]) + { + case EMPTY: + /* Already negotiating for YES, queue the request */ + usq[option] = OPPOSITE; + break; + case OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; + + case WANTYES: + switch(usq[option]) + { + case EMPTY: + /* Error: already negotiating for enable */ + break; + case OPPOSITE: + usq[option] = EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(us[option]) + { + case NO: + /* Already disabled */ + break; + + case YES: + us[option] = WANTNO; + send_negotiation(data, WONT, option); + break; + + case WANTNO: + switch(usq[option]) + { + case EMPTY: + /* Already negotiating for NO */ + break; + case OPPOSITE: + usq[option] = EMPTY; + break; + } + break; + + case WANTYES: + switch(usq[option]) + { + case EMPTY: + usq[option] = OPPOSITE; + break; + case OPPOSITE: + break; + } + break; + } + } +} + +void rec_do(struct UrlData *data, int option) +{ + switch(us[option]) + { + case NO: + if(us_preferred[option] == YES) + { + us[option] = YES; + send_negotiation(data, WILL, option); + } + else + { + send_negotiation(data, WONT, option); + } + break; + + case YES: + /* Already enabled */ + break; + + case WANTNO: + switch(usq[option]) + { + case EMPTY: + /* Error: DONT answered by WILL */ + us[option] = NO; + break; + case OPPOSITE: + /* Error: DONT answered by WILL */ + us[option] = YES; + usq[option] = EMPTY; + break; + } + break; + + case WANTYES: + switch(usq[option]) + { + case EMPTY: + us[option] = YES; + break; + case OPPOSITE: + us[option] = WANTNO; + himq[option] = EMPTY; + send_negotiation(data, WONT, option); + break; + } + break; + } +} + +void rec_dont(struct UrlData *data, int option) +{ + switch(us[option]) + { + case NO: + /* Already disabled */ + break; + + case YES: + us[option] = NO; + send_negotiation(data, WONT, option); + break; + + case WANTNO: + switch(usq[option]) + { + case EMPTY: + us[option] = NO; + break; + + case OPPOSITE: + us[option] = WANTYES; + usq[option] = EMPTY; + send_negotiation(data, WILL, option); + break; + } + break; + + case WANTYES: + switch(usq[option]) + { + case EMPTY: + us[option] = NO; + break; + case OPPOSITE: + us[option] = NO; + usq[option] = EMPTY; + break; + } + break; + } +} + + +static void printsub(struct UrlData *data, + int direction, /* '<' or '>' */ + unsigned char *pointer, /* where suboption data is */ + int length) /* length of suboption data */ + +{ + int i = 0; + + if (data->conf & CONF_VERBOSE) + { + if (direction) + { + printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT"); + if (length >= 3) + { + int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if (i != IAC || j != SE) + { + printf("(terminated by "); + if (TELOPT_OK(i)) + printf("%s ", TELOPT(i)); + else if (TELCMD_OK(i)) + printf("%s ", TELCMD(i)); + else + printf("%d ", i); + if (TELOPT_OK(j)) + printf("%s", TELOPT(j)); + else if (TELCMD_OK(j)) + printf("%s", TELCMD(j)); + else + printf("%d", j); + printf(", not IAC SE!) "); + } + } + length -= 2; + } + if (length < 1) + { + printf("(Empty suboption?)"); + return; + } + + if (TELOPT_OK(pointer[0])) + printf("%s (unknown)", TELOPT(pointer[0])); + else + printf("%d (unknown)", pointer[i]); + for (i = 1; i < length; i++) + printf(" %d", pointer[i]); + + if (direction) + { + printf("\n"); + } + } +} + +/* + * suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + * No suboptions are supported yet. + */ + +static void suboption(struct UrlData *data) +{ + printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2); + return; +} + +void telrcv(struct UrlData *data, + unsigned char *inbuf, /* Data received from socket */ + int count) /* Number of bytes received */ +{ + unsigned char c; + int index = 0; + + while(count--) + { + c = inbuf[index++]; + + switch (telrcv_state) + { + case TS_CR: + telrcv_state = TS_DATA; + if (c == '\0') + { + break; /* Ignore \0 after CR */ + } + + data->fwrite((char *)&c, 1, 1, data->out); + continue; + + case TS_DATA: + if (c == IAC) + { + telrcv_state = TS_IAC; + break; + } + else if(c == '\r') + { + telrcv_state = TS_CR; + } + + data->fwrite((char *)&c, 1, 1, data->out); + continue; + + case TS_IAC: + process_iac: + switch (c) + { + case WILL: + telrcv_state = TS_WILL; + continue; + case WONT: + telrcv_state = TS_WONT; + continue; + case DO: + telrcv_state = TS_DO; + continue; + case DONT: + telrcv_state = TS_DONT; + continue; + case SB: + SB_CLEAR(); + telrcv_state = TS_SB; + continue; + case IAC: + data->fwrite((char *)&c, 1, 1, data->out); + break; + case DM: + case NOP: + case GA: + default: + printoption(data, "RCVD", IAC, c); + break; + } + telrcv_state = TS_DATA; + continue; + + case TS_WILL: + printoption(data, "RCVD", WILL, c); + rec_will(data, c); + telrcv_state = TS_DATA; + continue; + + case TS_WONT: + printoption(data, "RCVD", WONT, c); + rec_wont(data, c); + telrcv_state = TS_DATA; + continue; + + case TS_DO: + printoption(data, "RCVD", DO, c); + rec_do(data, c); + telrcv_state = TS_DATA; + continue; + + case TS_DONT: + printoption(data, "RCVD", DONT, c); + rec_dont(data, c); + telrcv_state = TS_DATA; + continue; + + case TS_SB: + if (c == IAC) + { + telrcv_state = TS_SE; + } + else + { + SB_ACCUM(c); + } + continue; + + case TS_SE: + if (c != SE) + { + if (c != IAC) + { + /* + * This is an error. We only expect to get + * "IAC IAC" or "IAC SE". Several things may + * have happend. An IAC was not doubled, the + * IAC SE was left off, or another option got + * inserted into the suboption are all possibilities. + * If we assume that the IAC was not doubled, + * and really the IAC SE was left off, we could + * get into an infinate loop here. So, instead, + * we terminate the suboption, and process the + * partial suboption if we can. + */ + SB_ACCUM((unsigned char)IAC); + SB_ACCUM(c); + subpointer -= 2; + SB_TERM(); + + printoption(data, "In SUBOPTION processing, RCVD", IAC, c); + suboption(data); /* handle sub-option */ + telrcv_state = TS_IAC; + goto process_iac; + } + SB_ACCUM(c); + telrcv_state = TS_SB; + } + else + { + SB_ACCUM((unsigned char)IAC); + SB_ACCUM((unsigned char)SE); + subpointer -= 2; + SB_TERM(); + suboption(data); /* handle sub-option */ + telrcv_state = TS_DATA; + } + break; + } + } +} + +void telwrite(struct UrlData *data, + unsigned char *buffer, /* Data to write */ + int count) /* Number of bytes to write */ +{ + unsigned char outbuf[2]; + int out_count = 0; + int bytes_written; + + while(count--) + { + outbuf[0] = *buffer++; + out_count = 1; + if(outbuf[0] == IAC) + outbuf[out_count++] = IAC; + +#ifndef USE_SSLEAY + bytes_written = swrite(data->firstsocket, outbuf, out_count); +#else + if (data->use_ssl) { + bytes_written = SSL_write(data->ssl, (char *)outbuf, out_count); + } + else { + bytes_written = swrite(data->firstsocket, outbuf, out_count); + } +#endif /* USE_SSLEAY */ + } +} + +UrgError telnet(struct UrlData *data) +{ + int sockfd = data->firstsocket; + fd_set readfd; + fd_set keepfd; + + bool keepon = TRUE; + char *buf = data->buffer; + int nread; + + init_telnet(data); + + FD_ZERO (&readfd); /* clear it */ + FD_SET (sockfd, &readfd); + FD_SET (1, &readfd); + + keepfd = readfd; + + while (keepon) + { + readfd = keepfd; /* set this every lap in the loop */ + + switch (select (sockfd + 1, &readfd, NULL, NULL, NULL)) + { + case -1: /* error, stop reading */ + keepon = FALSE; + continue; + case 0: /* timeout */ + break; + default: /* read! */ + if(FD_ISSET(1, &readfd)) + { + nread = read(1, buf, 255); + telwrite(data, (unsigned char *)buf, nread); + } + + if(FD_ISSET(sockfd, &readfd)) + { +#ifndef USE_SSLEAY + nread = sread (sockfd, buf, BUFSIZE - 1); +#else + if (data->use_ssl) { + nread = SSL_read (data->ssl, buf, BUFSIZE - 1); + } + else { + nread = sread (sockfd, buf, BUFSIZE - 1); + } +#endif /* USE_SSLEAY */ + } + + /* if we receive 0 or less here, the server closed the connection and + we bail out from this! */ + if (nread <= 0) { + keepon = FALSE; + break; + } + + telrcv(data, (unsigned char *)buf, nread); + } + } + return URG_OK; +} + + diff --git a/lib/telnet.h b/lib/telnet.h new file mode 100644 index 000000000..25b7f2d29 --- /dev/null +++ b/lib/telnet.h @@ -0,0 +1,45 @@ +#ifndef __TELNET_H +#define __TELNET_H + +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError telnet(struct UrlData *data); + +#endif diff --git a/lib/timeval.c b/lib/timeval.c new file mode 100644 index 000000000..8ad25325f --- /dev/null +++ b/lib/timeval.c @@ -0,0 +1,93 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#ifdef WIN32 +#include <windows.h> +#endif +#include "timeval.h" + +#ifndef HAVE_GETTIMEOFDAY + +#ifdef WIN32 +int +gettimeofday (struct timeval *tp, void *nothing) +{ + SYSTEMTIME st; + time_t tt; + struct tm tmtm; + /* mktime converts local to UTC */ + GetLocalTime (&st); + tmtm.tm_sec = st.wSecond; + tmtm.tm_min = st.wMinute; + tmtm.tm_hour = st.wHour; + tmtm.tm_mday = st.wDay; + tmtm.tm_mon = st.wMonth - 1; + tmtm.tm_year = st.wYear - 1900; + tmtm.tm_isdst = -1; + tt = mktime (&tmtm); + tp->tv_sec = tt; + tp->tv_usec = st.wMilliseconds * 1000; + return 1; +} +#define HAVE_GETTIMEOFDAY +#endif +#endif + +struct timeval tvnow () +{ + struct timeval now; +#ifdef HAVE_GETTIMEOFDAY + gettimeofday (&now, NULL); +#else + now.tv_sec = (long) time(NULL); + now.tv_usec = 0; +#endif + return now; +} + +double tvdiff (struct timeval t1, struct timeval t2) +{ + return (double)(t1.tv_sec - t2.tv_sec) + ((t1.tv_usec-t2.tv_usec)/1000000.0); +} + +long tvlong (struct timeval t1) +{ + return t1.tv_sec; +} diff --git a/lib/timeval.h b/lib/timeval.h new file mode 100644 index 000000000..fe99e2896 --- /dev/null +++ b/lib/timeval.h @@ -0,0 +1,64 @@ +#ifndef __TIMEVAL_H +#define __TIMEVAL_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <time.h> +#else +#include <sys/time.h> +#endif + +#include "setup.h" + +#ifndef HAVE_GETTIMEOFDAY +#if !defined(_WINSOCKAPI_) && !defined(__MINGW32__) +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif +#endif + +struct timeval tvnow (); +double tvdiff (struct timeval t1, struct timeval t2); +long tvlong (struct timeval t1); + +#endif diff --git a/lib/upload.c b/lib/upload.c new file mode 100644 index 000000000..0673382e9 --- /dev/null +++ b/lib/upload.c @@ -0,0 +1,178 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include "setup.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef WIN32 +#if !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#endif +#include <time.h> /* for the time_t typedef! */ + +#if defined(__GNUC__) && defined(TIME_WITH_SYS_TIME) +#include <sys/time.h> +#endif + +#endif + +#include <curl/curl.h> + +#ifdef __BEOS__ +#include <net/socket.h> +#endif + +#include "urldata.h" +#include "speedcheck.h" +#include "sendf.h" +#include "progress.h" + +/* --- upload a stream to a socket --- */ + +UrgError Upload(struct UrlData *data, + int sockfd, + long *bytecountp) +{ + fd_set writefd; + fd_set keepfd; + struct timeval interval; + bool keepon=TRUE; + char *buf = data->buffer; + size_t nread; + long bytecount=0; + struct timeval start; + struct timeval now; + UrgError urg; + char scratch[BUFSIZE * 2]; + int i, si; + + /* timeout every X second + - makes a better progressmeter (i.e even when no data is sent, the + meter can be updated and reflect reality) + - allows removal of the alarm() crap + - variable timeout is easier + */ + + myalarm(0); /* switch off the alarm-style timeout */ + + start = tvnow(); + now = start; + + FD_ZERO(&writefd); /* clear it */ + FD_SET(sockfd, &writefd); + + keepfd = writefd; + + while(keepon) { + size_t bytes_written = 0; + + writefd = keepfd; /* set this every lap in the loop */ + interval.tv_sec = 2; + interval.tv_usec = 0; + + switch(select(sockfd+1, NULL, &writefd, NULL, &interval)) { + case -1: /* error, stop writing */ + keepon=FALSE; + continue; + case 0: /* timeout */ + break; + default: /* write! */ + if(data->crlf) + buf = data->buffer; /* put it back on the buffer */ + + nread = data->fread(buf, 1, BUFSIZE, data->in); + bytecount += nread; + + if (nread==0) { + /* done */ + keepon = FALSE; + break; + } + + /* convert LF to CRLF if so asked */ + if (data->crlf) { + for(i = 0, si = 0; i < (int)nread; i++, si++) { + if (buf[i] == 0x0a) { + scratch[si++] = 0x0d; + scratch[si] = 0x0a; + } + else { + scratch[si] = buf[i]; + } + } + nread = si; + buf = scratch; /* point to the new buffer */ + } + + /* write to socket */ +#ifndef USE_SSLEAY + bytes_written = swrite(sockfd, buf, nread); +#else + if (data->use_ssl) { + bytes_written = SSL_write(data->ssl, buf, nread); + } else { + bytes_written = swrite(sockfd, buf, nread); + } +#endif /* USE_SSLEAY */ + if(nread != bytes_written) { + failf(data, "Failed uploading file"); + return URG_FTP_WRITE_ERROR; + } + } + now = tvnow(); + ProgressShow(data, bytecount, start, now, FALSE); + urg=speedcheck(data, now); + if(urg) + return urg; + if(data->timeout && (tvdiff(now,start)>data->timeout)) { + failf(data, "Upload timed out with %d bytes sent", bytecount); + return URG_OPERATION_TIMEOUTED; + } + + } + ProgressShow(data, bytecount, start, now, TRUE); + *bytecountp = bytecount; + + return URG_OK; +} diff --git a/lib/upload.h b/lib/upload.h new file mode 100644 index 000000000..dbb6600c8 --- /dev/null +++ b/lib/upload.h @@ -0,0 +1,46 @@ +#ifndef __UPLOAD_H +#define __UPLOAD_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ +UrgError Upload(struct UrlData *data, + int sockfd, + long *bytecountp); + +#endif diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 000000000..b520898dc --- /dev/null +++ b/lib/url.c @@ -0,0 +1,1181 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* + * SSL code intially written by + * Linas Vepstas <linas@linas.org> and Sampo Kellomaki <sampo@iki.fi> + */ + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "setup.h" + +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +#include <winsock.h> +#include <time.h> +#include <io.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#include <sys/time.h> +#include <sys/resource.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#include <sys/ioctl.h> +#include <signal.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef HAVE_VPRINTF +#error "We can't compile without vprintf() support!" +#endif +#ifndef HAVE_SELECT +#error "We can't compile without select() support!" +#endif +#ifndef HAVE_SOCKET +#error "We can't compile without socket() support!" +#endif + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "netrc.h" + +#include "formdata.h" +#include "getenv.h" +#include "base64.h" +#include "ssluse.h" +#include "hostip.h" +#include "if2ip.h" +#include "upload.h" +#include "download.h" +#include "sendf.h" +#include "speedcheck.h" +#include "getpass.h" +#include "progress.h" +#include "cookie.h" + +/* And now for the protocols */ +#include "ftp.h" +#include "dict.h" +#include "telnet.h" +#include "http.h" +#include "file.h" +#include "ldap.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* -- -- */ + +/*********************************************************************** + * Start with some silly functions to make win32-systems survive + ***********************************************************************/ +#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) +static void cleanup(void) +{ + WSACleanup(); +} + +static int init(void) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + wVersionRequested = MAKEWORD(1, 1); + + err = WSAStartup(wVersionRequested, &wsaData); + + if (err != 0) + /* Tell the user that we couldn't find a useable */ + /* winsock.dll. */ + return 1; + + /* Confirm that the Windows Sockets DLL supports 1.1.*/ + /* Note that if the DLL supports versions greater */ + /* than 1.1 in addition to 1.1, it will still return */ + /* 1.1 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 1 || + HIBYTE( wsaData.wVersion ) != 1 ) { + /* Tell the user that we couldn't find a useable */ + + /* winsock.dll. */ + WSACleanup(); + return 1; + } + return 0; +} +/* The Windows Sockets DLL is acceptable. Proceed. */ +#else +static int init(void) { return 0; } +static void cleanup(void) {} +#endif + +static UrgError _urlget(struct UrlData *data); + + +void urlfree(struct UrlData *data, bool totally) +{ +#ifdef USE_SSLEAY + if (data->use_ssl) { + if(data->ssl) { + SSL_shutdown(data->ssl); + SSL_set_connect_state(data->ssl); + + SSL_free (data->ssl); + data->ssl = NULL; + } + if(data->ctx) { + SSL_CTX_free (data->ctx); + data->ctx = NULL; + } + data->use_ssl = FALSE; /* get back to ordinary socket usage */ + } +#endif /* USE_SSLEAY */ + + /* close possibly still open sockets */ + if(-1 != data->secondarysocket) { + sclose(data->secondarysocket); + data->secondarysocket = -1; + } + if(-1 != data->firstsocket) { + sclose(data->firstsocket); + data->firstsocket=-1; + } + + + if(data->ptr_proxyuserpwd) { + free(data->ptr_proxyuserpwd); + data->ptr_proxyuserpwd=NULL; + } + if(data->ptr_uagent) { + free(data->ptr_uagent); + data->ptr_uagent=NULL; + } + if(data->ptr_userpwd) { + free(data->ptr_userpwd); + data->ptr_userpwd=NULL; + } + if(data->ptr_rangeline) { + free(data->ptr_rangeline); + data->ptr_rangeline=NULL; + } + if(data->ptr_ref) { + free(data->ptr_ref); + data->ptr_ref=NULL; + } + if(data->ptr_cookie) { + free(data->ptr_cookie); + data->ptr_cookie=NULL; + } + if(data->ptr_host) { + free(data->ptr_host); + data->ptr_host=NULL; + } + + if(totally) { + /* we let the switch decide whether we're doing a part or total + cleanup */ + + /* check for allocated [URL] memory to free: */ + if(data->freethis) + free(data->freethis); + + if(data->headerbuff) + free(data->headerbuff); + + cookie_cleanup(data->cookies); + + free(data); + + /* winsock crap cleanup */ + cleanup(); + } +} + +typedef int (*func_T)(void); + +UrgError curl_urlget(UrgTag tag, ...) +{ + va_list arg; + func_T param_func = (func_T)0; + long param_long = 0; + void *param_obj = NULL; + UrgError res; + char *cookiefile; + + struct UrlData *data; + + /* this is for the lame win32 socket crap */ + if(init()) + return URG_FAILED_INIT; + + data = (struct UrlData *)malloc(sizeof(struct UrlData)); + if(data) { + + memset(data, 0, sizeof(struct UrlData)); + + /* Let's set some default values: */ + data->out = stdout; /* default output to stdout */ + data->in = stdin; /* default input from stdin */ + data->err = stderr; /* default stderr to stderr */ + data->firstsocket = -1; /* no file descriptor */ + data->secondarysocket = -1; /* no file descriptor */ + + /* use fwrite as default function to store output */ + data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite; + + /* use fread as default function to read input */ + data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread; + + data->infilesize = -1; /* we don't know any size */ + + data->current_speed = -1; /* init to negative == impossible */ + + va_start(arg, tag); + + while(tag != URGTAG_DONE) { + /* PORTING NOTE: + Ojbect pointers can't necessarily be casted to function pointers and + therefore we need to know what type it is and read the correct type + at once. This should also correct problems with different sizes of + the types. + */ + + if(tag < URGTYPE_OBJECTPOINT) { + /* This is a LONG type */ + param_long = va_arg(arg, long); + } + else if(tag < URGTYPE_FUNCTIONPOINT) { + /* This is a object pointer type */ + param_obj = va_arg(arg, void *); + } + else + param_func = va_arg(arg, func_T ); + + /* printf("tag: %d\n", tag); */ + + + switch(tag) { +#ifdef MULTIDOC + case URGTAG_MOREDOCS: + data->moredoc = (struct MoreDoc *)param_obj; + break; +#endif + case URGTAG_TIMECONDITION: + data->timecondition = (long)param_long; + break; + + case URGTAG_TIMEVALUE: + data->timevalue = (long)param_long; + break; + + case URGTAG_SSLVERSION: + data->ssl_version = (int)param_long; + break; + + case URGTAG_COOKIEFILE: + cookiefile = (char *)param_obj; + if(cookiefile) { + data->cookies = cookie_init(cookiefile); + } + break; + case URGTAG_WRITEHEADER: + data->writeheader = (FILE *)param_obj; + break; + case URGTAG_COOKIE: + data->cookie = (char *)param_obj; + break; + case URGTAG_ERRORBUFFER: + data->errorbuffer = (char *)param_obj; + break; + case URGTAG_FILE: + data->out = (FILE *)param_obj; + break; + case URGTAG_FTPPORT: + data->ftpport = (char *)param_obj; + break; + case URGTAG_HTTPHEADER: + data->headers = (struct HttpHeader *)param_obj; + break; + case URGTAG_CUSTOMREQUEST: + data->customrequest = (char *)param_obj; + break; + case URGTAG_HTTPPOST: + data->httppost = (struct HttpPost *)param_obj; + break; + case URGTAG_INFILE: + data->in = (FILE *)param_obj; + break; + case URGTAG_INFILESIZE: + data->infilesize = (long)param_long; + break; + case URGTAG_LOW_SPEED_LIMIT: + data->low_speed_limit=(long)param_long; + break; + case URGTAG_LOW_SPEED_TIME: + data->low_speed_time=(long)param_long; + break; + case URGTAG_URL: + data->url = (char *)param_obj; + break; + case URGTAG_PORT: + /* this typecast is used to fool the compiler to NOT warn for a + "cast from pointer to integer of different size" */ + data->port = (unsigned short)((long)param_long); + break; + case URGTAG_POSTFIELDS: + data->postfields = (char *)param_obj; + break; + case URGTAG_PROGRESSMODE: + data->progressmode = (long)param_long; + break; + case URGTAG_REFERER: + data->referer = (char *)param_obj; + break; + case URGTAG_PROXY: + data->proxy = (char *)param_obj; + break; + case URGTAG_FLAGS: + data->conf = (long)param_long; + break; + case URGTAG_TIMEOUT: + data->timeout = (long)param_long; + break; + case URGTAG_USERAGENT: + data->useragent = (char *)param_obj; + break; + case URGTAG_USERPWD: + data->userpwd = (char *)param_obj; + break; + case URGTAG_PROXYUSERPWD: + data->proxyuserpwd = (char *)param_obj; + break; + case URGTAG_RANGE: + data->range = (char *)param_obj; + break; + case URGTAG_RESUME_FROM: + data->resume_from = (long)param_long; + break; + case URGTAG_STDERR: + data->err = (FILE *)param_obj; + break; + case URGTAG_WRITEFUNCTION: + data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))param_func; + break; + case URGTAG_READFUNCTION: + data->fread = (size_t (*)(char *, size_t, size_t, FILE *))param_func; + break; + case URGTAG_SSLCERT: + data->cert = (char *)param_obj; + break; + case URGTAG_SSLCERTPASSWD: + data->cert_passwd = (char *)param_obj; + break; + case URGTAG_CRLF: + data->crlf = (long)param_long; + break; + case URGTAG_QUOTE: + data->quote = (struct curl_slist *)param_obj; + break; + case URGTAG_DONE: /* done with the parsing, fall through */ + continue; + default: + /* unknown tag and its companion, just ignore: */ + break; + } + tag = va_arg(arg, UrgTag); + } + + va_end(arg); + + data-> headerbuff=(char*)malloc(HEADERSIZE); + if(!data->headerbuff) + return URG_FAILED_INIT; + + data-> headersize=HEADERSIZE; + + res = _urlget(data); /* fetch the URL please */ + + while((res == URG_OK) && data->newurl) { + /* Location: redirect */ + char prot[16]; + char path[URL_MAX_LENGTH]; + + if(2 != sscanf(data->newurl, "%15[^:]://%" URL_MAX_LENGTH_TXT + "s", prot, path)) { + /*** + *DANG* this is an RFC 2068 violation. The URL is supposed + to be absolute and this doesn't seem to be that! + At least the Zeus HTTP server seem to do this. + *** + Instead, we have to TRY to append this new path to the old URL + to the right of the host part. Oh crap, this is doomed to cause + problems in the future... + */ + char *protsep; + char *pathsep; + char *newest; + + /* protsep points to the start of the host name */ + protsep=strstr(data->url, "//"); + if(!protsep) + protsep=data->url; + else { + data->port=0; /* we got a full URL and then we should reset the + port number here to re-initiate it later */ + protsep+=2; /* pass the // */ + } + + if('/' != data->newurl[0]) { + /* First we need to find out if there's a ?-letter in the URL, and + cut it and the right-side of that off */ + pathsep = strrchr(protsep, '?'); + if(pathsep) + *pathsep=0; + + /* we have a relative path to append to the last slash if + there's one available */ + pathsep = strrchr(protsep, '/'); + if(pathsep) + *pathsep=0; + } + else { + /* We got a new absolute path for this server, cut off from the + first slash */ + pathsep = strchr(protsep, '/'); + if(pathsep) + *pathsep=0; + } + + newest=(char *)malloc( strlen(data->url) + + 1 + /* possible slash */ + strlen(data->newurl) + 1/* zero byte */); + + if(!newest) + return URG_OUT_OF_MEMORY; + sprintf(newest, "%s%s%s", data->url, ('/' == data->newurl[0])?"":"/", + data->newurl); + free(data->newurl); + data->newurl = newest; + } + + data->url = data->newurl; + data->newurl = NULL; /* don't show! */ + + infof(data, "Follows Location: to new URL: '%s'\n", data->url); + + /* clean up the sockets and SSL stuff from the previous "round" */ + urlfree(data, FALSE); + + res = _urlget(data); + } + if(data->newurl) + free(data->newurl); + + } + else + res = URG_FAILED_INIT; /* failed */ + + /* total cleanup */ + urlfree(data, TRUE); + + return res; +} + + +/* + * Read everything until a newline. + */ + +static int GetLine(int sockfd, char *buf, + struct UrlData *data) +{ + int nread; + int read_rc=1; + char *ptr; + ptr=buf; + + /* get us a full line, terminated with a newline */ + for(nread=0; + (nread<BUFSIZE) && read_rc; + nread++, ptr++) { +#ifdef USE_SSLEAY + if (data->use_ssl) { + read_rc = SSL_read(data->ssl, ptr, 1); + } + else { +#endif + read_rc = sread(sockfd, ptr, 1); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + if (*ptr == '\n') + break; + } + *ptr=0; /* zero terminate */ + + if(data->conf & CONF_VERBOSE) { + fputs("< ", data->err); + fwrite(buf, 1, nread, data->err); + fputs("\n", data->err); + } + return nread; +} + + + +#ifndef WIN32 +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif +RETSIGTYPE alarmfunc(int signal) +{ + /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ + (void)signal; + return; +} +#endif + +/* ====================================================== */ +/* + * urlget <url> + * (result put on stdout) + * + * <url> ::= <proto> "://" <host> [ ":" <port> ] "/" <path> + * + * <proto> = "HTTP" | "HTTPS" | "GOPHER" | "FTP" + * + * When FTP: + * + * <host> ::= [ <user> ":" <password> "@" ] <host> + */ + +static UrgError _urlget(struct UrlData *data) +{ + struct hostent *hp=NULL; + struct sockaddr_in serv_addr; + char *buf; + char proto[64]; + char gname[256]="default.com"; + char *name; + char path[URL_MAX_LENGTH]="/"; + char *ppath, *tmp; + long bytecount; + struct timeval now; + + UrgError result; + char resumerange[12]=""; + + buf = data->buffer; /* this is our buffer */ + +#if 0 + signal(SIGALRM, alarmfunc); +#endif + + /* Parse <url> */ + /* We need to parse the url, even when using the proxy, because + * we will need the hostname and port in case we are trying + * to SSL connect through the proxy -- and we don't know if we + * will need to use SSL until we parse the url ... + */ + if((1 == sscanf(data->url, "file://%" URL_MAX_LENGTH_TXT "[^\n]", + path))) { + /* we deal with file://<host>/<path> differently since it + supports no hostname other than "localhost" and "127.0.0.1", + which ist unique among the protocols specified in RFC 1738 */ + if (strstr(path, "localhost/") || strstr(path, "127.0.0.1/")) + strcpy(path, &path[10]); /* ... since coincidentally + both host strings are of + equal length */ + /* otherwise, <host>/ is quietly ommitted */ + + + /* that's it, no more fiddling with proxies, redirections, + or SSL for files, go directly to the file reading function */ + result = file(data, path, &bytecount); + if(result) + return result; + + return URG_OK; + } + else if (2 > sscanf(data->url, "%64[^\n:]://%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", + proto, gname, path)) { + + + /* badly formatted, let's try the browser-style _without_ 'http://' */ + if((1 > sscanf(data->url, "%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", gname, + path)) ) { + failf(data, "<url> malformed"); + return URG_URL_MALFORMAT; + } + if(strnequal(gname, "FTP", 3)) { + strcpy(proto, "ftp"); + } + else if(strnequal(gname, "GOPHER", 6)) + strcpy(proto, "gopher"); +#ifdef USE_SSLEAY + else if(strnequal(gname, "HTTPS", 5)) + strcpy(proto, "https"); +#endif /* USE_SSLEAY */ + else if(strnequal(gname, "TELNET", 6)) + strcpy(proto, "telnet"); + else if (strnequal(gname, "DICT", sizeof("DICT")-1)) + strcpy(proto, "DICT"); + else if (strnequal(gname, "LDAP", sizeof("LDAP")-1)) + strcpy(proto, "LDAP"); + else + strcpy(proto, "http"); + + data->conf |= CONF_NOPROT; + } + + + if((data->conf & CONF_USERPWD) && ! (data->conf & CONF_NETRC)) { + if(':' != *data->userpwd) { + if((1 <= sscanf(data->userpwd, "%127[^:]:%127s", + data->user, data->passwd))) { + /* check for password, if no ask for one */ + if( !data->passwd[0] ) + { + strncpy(data->passwd, getpass("password: "), sizeof(data->passwd)); + } + } + } + if(!data->user[0]) { + failf(data, "USER malformat: user name can't be zero length"); + return URG_MALFORMAT_USER; + } + } + + if(data->conf & CONF_PROXYUSERPWD) { + if(':' != *data->proxyuserpwd) { + if((1 <= sscanf(data->proxyuserpwd, "%127[^:]:%127s", + data->proxyuser, data->proxypasswd))) { + /* check for password, if no ask for one */ + if( !data->proxypasswd[0] ) + { + strncpy(data->proxypasswd, getpass("proxy password: "), sizeof(data->proxypasswd)); + } + } + } + if(!data->proxyuser[0]) { + failf(data, " Proxy USER malformat: user name can't be zero length"); + return URG_MALFORMAT_USER; + } + } + + name = gname; + ppath = path; + data->hostname = name; + + + if(!(data->conf & CONF_PROXY)) { + /* If proxy was not specified, we check for default proxy environment + variables, to enable i.e Lynx compliance: + + HTTP_PROXY http://some.server.dom:port/ + HTTPS_PROXY http://some.server.dom:port/ + FTP_PROXY http://some.server.dom:port/ + GOPHER_PROXY http://some.server.dom:port/ + NO_PROXY host.domain.dom (a comma-separated list of hosts which should + not be proxied, or an asterisk to override all proxy variables) + ALL_PROXY seems to exist for the CERN www lib. Probably the first to + check for. + + */ + char *no_proxy=GetEnv("NO_PROXY"); + char *proxy=NULL; + char proxy_env[128]; + + if(!no_proxy || !strequal("*", no_proxy)) { + /* NO_PROXY wasn't specified or it wasn't just an asterisk */ + char *nope; + + nope=no_proxy?strtok(no_proxy, ", "):NULL; + while(nope) { + if(strlen(nope) <= strlen(name)) { + char *checkn= + name + strlen(name) - strlen(nope); + if(strnequal(nope, checkn, strlen(nope))) { + /* no proxy for this host! */ + break; + } + } + nope=strtok(NULL, ", "); + } + if(!nope) { + /* It was not listed as without proxy */ + char *protop = proto; + char *envp = proxy_env; + char *prox; + + /* Now, build <PROTOCOL>_PROXY and check for such a one to use */ + while(*protop) { + *envp++ = toupper(*protop++); + } + /* append _PROXY */ + strcpy(envp, "_PROXY"); +#if 0 + infof(data, "DEBUG: checks the environment variable %s\n", proxy_env); +#endif + /* read the protocol proxy: */ + prox=GetEnv(proxy_env); + + if(prox && *prox) { /* don't count "" strings */ + proxy = prox; /* use this */ + } + else + proxy = GetEnv("ALL_PROXY"); /* default proxy to use */ + + if(proxy && *proxy) { + /* we have a proxy here to set */ + data->proxy = proxy; + data->conf |= CONF_PROXY; + } + } /* if (!nope) - it wasn't specfied non-proxy */ + } /* NO_PROXY wasn't specified or '*' */ + } /* if not using proxy */ + + if((data->conf & (CONF_PROXY|CONF_NOPROT)) == (CONF_PROXY|CONF_NOPROT) ) { + /* We're guessing prefixes here and since we're told to use a proxy, we + need to add the protocol prefix to the URL string before we continue! + */ + char *reurl; + + reurl = maprintf("%s://%s", proto, data->url); + + if(!reurl) + return URG_OUT_OF_MEMORY; + + data->url = reurl; + if(data->freethis) + free(data->freethis); + data->freethis = reurl; + + data->conf &= ~CONF_NOPROT; /* switch that one off again */ + } + + /* RESUME on a HTTP page is a tricky business. First, let's just check that + 'range' isn't used, then set the range parameter and leave the resume as + it is to inform about this situation for later use. We will then + "attempt" to resume, and if we're talking to a HTTP/1.1 (or later) + server, we will get the document resumed. If we talk to a HTTP/1.0 + server, we just fail since we can't rewind the file writing from within + this function. */ + if(data->resume_from) { + if(!(data->conf & CONF_RANGE)) { + /* if it already was in use, we just skip this */ + sprintf(resumerange, "%d-", data->resume_from); + data->range=resumerange; /* tell ourselves to fetch this range */ + data->conf |= CONF_RANGE; /* switch on range usage */ + } + } + + + if(data->timeout) { + /* We set the timeout on the connection/resolving phase first, separately + from the download/upload part to allow a maximum time on everything */ + myalarm(data->timeout); /* this sends a signal when the timeout fires + off, and that will abort system calls */ + } + + /* + * Hmm, if we are using a proxy, then we can skip the GOPHER and the + * FTP steps, although we cannot skip the HTTPS step (since the proxy + * works differently, depending on whether its SSL or not). + */ + + if (strequal(proto, "HTTP")) { + if(!data->port) + data->port = PORT_HTTP; + data->remote_port = PORT_HTTP; + data->conf |= CONF_HTTP; + } + else if (strequal(proto, "HTTPS")) { +#ifdef USE_SSLEAY + if(!data->port) + data->port = PORT_HTTPS; + data->remote_port = PORT_HTTPS; + data->conf |= CONF_HTTP; + data->conf |= CONF_HTTPS; +#else /* USE_SSLEAY */ + failf(data, "SSL is disabled, https: not supported!"); + return URG_UNSUPPORTED_PROTOCOL; +#endif /* !USE_SSLEAY */ + } + else if (strequal(proto, "GOPHER")) { + if(!data->port) + data->port = PORT_GOPHER; + data->remote_port = PORT_GOPHER; + /* Skip /<item-type>/ in path if present */ + if (isdigit((int)path[1])) { + ppath = strchr(&path[1], '/'); + if (ppath == NULL) + ppath = path; + } + data->conf |= CONF_GOPHER; + } + else if(strequal(proto, "FTP")) { + char *type; + if(!data->port) + data->port = PORT_FTP; + data->remote_port = PORT_FTP; + data->conf |= CONF_FTP; + + ppath++; /* don't include the initial slash */ + + /* FTP URLs support an extension like ";type=<typecode>" that + we'll try to get now! */ + type=strstr(ppath, ";type="); + if(!type) { + type=strstr(gname, ";type="); + } + if(type) { + char command; + *type=0; + command = toupper(type[6]); + switch(command) { + case 'A': /* ASCII mode */ + data->conf |= CONF_FTPASCII; + break; + case 'D': /* directory mode */ + data->conf |= CONF_FTPLISTONLY; + break; + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->conf &= ~CONF_FTPASCII; + break; + } + } + } + else if(strequal(proto, "TELNET")) { + /* telnet testing factory */ + data->conf |= CONF_TELNET; + if(!data->port) + data->port = PORT_TELNET; + data->remote_port = PORT_TELNET; + } + else if (strequal(proto, "DICT")) { + data->conf |= CONF_DICT; + if(!data->port) + data->port = PORT_DICT; + data->remote_port = PORT_DICT; + } + else if (strequal(proto, "LDAP")) { + data->conf |= CONF_LDAP; + if(!data->port) + data->port = PORT_LDAP; + data->remote_port = PORT_LDAP; + } + /* file:// is handled above */ + /* else if (strequal(proto, "FILE")) { + data->conf |= CONF_FILE; + + result = file(data, path, &bytecount); + if(result) + return result; + + return URG_OK; + }*/ + else { + failf(data, "Unsupported protocol: %s", proto); + return URG_UNSUPPORTED_PROTOCOL; + } + + if(data->conf & CONF_NETRC) { + if(ParseNetrc(data->hostname, data->user, data->passwd)) { + infof(data, "Couldn't find host %s in the .netrc file, using defaults", + data->hostname); + } + /* weather we failed or not, we don't know which fields that were filled + in anyway */ + if(!data->user[0]) + strcpy(data->user, CURL_DEFAULT_USER); + if(!data->passwd[0]) + strcpy(data->passwd, CURL_DEFAULT_PASSWORD); + if(data->conf & CONF_HTTP) { + data->conf |= CONF_USERPWD; + } + } + else if(!(data->conf & CONF_USERPWD) && + (data->conf & (CONF_FTP|CONF_HTTP)) ) { + /* This is a FTP or HTTP URL, and we haven't got the user+password in + the extra parameter, we will now try to extract the possible + user+password pair in a string like: + ftp://user:password@ftp.my.site:8021/README */ + char *ptr=NULL; /* assign to remove possible warnings */ + if(':' == *name) { + failf(data, "URL malformat: user can't be zero length"); + return URG_URL_MALFORMAT_USER; + } + if((1 <= sscanf(name, "%127[^:]:%127[^@]", + data->user, data->passwd)) && (ptr=strchr(name, '@'))) { + name = ++ptr; + data->conf |= CONF_USERPWD; + } + else { + strcpy(data->user, CURL_DEFAULT_USER); + strcpy(data->passwd, CURL_DEFAULT_PASSWORD); + } + } + + if(!(data->conf & CONF_PROXY)) { + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + tmp = strchr(name, ':'); + if (tmp) { + *tmp++ = '\0'; + data->port = atoi(tmp); + } + + /* Connect to target host right on */ + if(!(hp = GetHost(data, name))) { + failf(data, "Couldn't resolv host '%s'", name); + return URG_COULDNT_RESOLVE_HOST; + } + } + else { + char *prox_portno; + char *endofprot; + + /* we use proxy all right, but we wanna know the remote port for SSL + reasons */ + tmp = strchr(name, ':'); + if (tmp) { + *tmp++ = '\0'; /* cut off the name there */ + data->remote_port = atoi(tmp); + } + + /* Daniel Dec 10, 1998: + We do the proxy host string parsing here. We want the host name and the + port name. Accept a protocol:// prefix, even though it should just be + ignored. */ + + /* 1. skip the protocol part if present */ + endofprot=strstr(data->proxy, "://"); + if(endofprot) { + data->proxy = endofprot+3; + } + + /* allow user to specify proxy.server.com:1080 if desired */ + prox_portno = strchr (data->proxy, ':'); + if (prox_portno) { + *prox_portno = 0x0; /* cut off number from host name */ + prox_portno ++; + /* now set the local port number */ + data->port = atoi(prox_portno); + } + + /* connect to proxy */ + if(!(hp = GetHost(data, data->proxy))) { + failf(data, "Couldn't resolv proxy '%s'", data->proxy); + return URG_COULDNT_RESOLVE_PROXY; + } + } + + data->firstsocket = socket(AF_INET, SOCK_STREAM, 0); + + memset((char *) &serv_addr, '\0', sizeof(serv_addr)); + memcpy((char *)&(serv_addr.sin_addr), hp->h_addr, hp->h_length); + serv_addr.sin_family = hp->h_addrtype; + + serv_addr.sin_port = htons(data->port); + + if (connect(data->firstsocket, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) { + switch(errno) { +#ifdef ECONNREFUSED + /* this should be made nicer */ + case ECONNREFUSED: + failf(data, "Connection refused"); + break; +#endif +#ifdef EINTR + case EINTR: + failf(data, "Connection timeouted"); + break; +#endif + default: + failf(data, "Can't connect to server: %d", errno); + break; + } + return URG_COULDNT_CONNECT; + } + + if(data->conf & CONF_PROXYUSERPWD) { + char authorization[512]; + sprintf(data->buffer, "%s:%s", data->proxyuser, data->proxypasswd); + base64Encode(data->buffer, authorization); + + data->ptr_proxyuserpwd = maprintf("Proxy-authorization: Basic %s\015\012", + authorization); + } + if(data->conf & (CONF_HTTPS|CONF_HTTP)) { + if(data->useragent) { + data->ptr_uagent = maprintf("User-Agent: %s\015\012", data->useragent); + } + } + + + /* If we are not using a proxy and we want a secure connection, + * perform SSL initialization & connection now. + * If using a proxy with https, then we must tell the proxy to CONNECT + * us to the host we want to talk to. Only after the connect + * has occured, can we start talking SSL + */ + if (data->conf & CONF_HTTPS) { + if (data->conf & CONF_PROXY) { + + /* OK, now send the connect statment */ + sendf(data->firstsocket, data, + "CONNECT %s:%d HTTP/1.0\015\012" + "%s" + "%s" + "\r\n", + data->hostname, data->remote_port, + (data->conf&CONF_PROXYUSERPWD)?data->ptr_proxyuserpwd:"", + (data->useragent?data->ptr_uagent:"") + ); + + /* wait for the proxy to send us a HTTP/1.0 200 OK header */ + /* Daniel rewrote this part Nov 5 1998 to make it more obvious */ + { + int httperror=0; + int subversion=0; + while(GetLine(data->firstsocket, data->buffer, data)) { + if('\r' == data->buffer[0]) + break; /* end of headers */ + if(2 == sscanf(data->buffer, "HTTP/1.%d %d", + &subversion, + &httperror)) { + ; + } + } + if(200 != httperror) { + if(407 == httperror) + /* Added Nov 6 1998 */ + failf(data, "Proxy requires authorization!"); + else + failf(data, "Received error code %d from proxy", httperror); + return URG_READ_ERROR; + } + } + infof (data, "Proxy has replied to CONNECT request\n"); + } + + /* now, perform the SSL initialization for this socket */ + if(UrgSSLConnect (data)) { + return URG_SSL_CONNECT_ERROR; + } + } + + now = tvnow(); /* time this *after* the connect is done */ + bytecount = 0; + + /* Figure out the ip-number and the first host name it shows: */ + { + struct in_addr in; + (void) memcpy(&in.s_addr, *hp->h_addr_list, sizeof (in.s_addr)); + infof(data, "Connected to %s (%s)\n", hp->h_name, inet_ntoa(in)); + } + + if((data->conf&(CONF_FTP|CONF_PROXY)) == CONF_FTP) { + result = ftp(data, &bytecount, data->user, data->passwd, ppath); + if(result) + return result; + } + else if(data->conf & CONF_TELNET) { + result=telnet(data); + if(result) + return result; + } + else if (data->conf & CONF_LDAP) { + result = ldap(data, path, &bytecount); + if (result) + return result; + } + else if (data->conf & CONF_DICT) { + result = dict(data, path, &bytecount); + if(result) + return result; + } + else { + result = http(data, ppath, name, &bytecount); + if(result) + return result; + } + if(bytecount) { + double ittook = tvdiff (tvnow(), now); + infof(data, "%i bytes transfered in %.3lf seconds (%.0lf bytes/sec).\n", + bytecount, ittook, (double)bytecount/(ittook!=0.0?ittook:1)); + } + return URG_OK; +} + diff --git a/lib/url.h b/lib/url.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/lib/url.h diff --git a/lib/urldata.h b/lib/urldata.h new file mode 100644 index 000000000..f171cd096 --- /dev/null +++ b/lib/urldata.h @@ -0,0 +1,212 @@ +#ifndef __URLDATA_H +#define __URLDATA_H +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +/* This file is for lib internal stuff */ + +#include "setup.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#define PORT_FTP 21 +#define PORT_TELNET 23 +#define PORT_GOPHER 70 +#define PORT_HTTP 80 +#define PORT_HTTPS 443 +#define PORT_DICT 2628 +#define PORT_LDAP 389 + +#define DICT_MATCH "/MATCH:" +#define DICT_MATCH2 "/M:" +#define DICT_MATCH3 "/FIND:" +#define DICT_DEFINE "/DEFINE:" +#define DICT_DEFINE2 "/D:" +#define DICT_DEFINE3 "/LOOKUP:" + +#define CURL_DEFAULT_USER "anonymous" +#define CURL_DEFAULT_PASSWORD "curl_by_Daniel.Stenberg@haxx.nu" + +#include "cookie.h" + +#ifdef USE_SSLEAY +/* SSLeay stuff usually in /usr/local/ssl/include */ +#ifdef USE_OPENSSL +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#else +#include "rsa.h" +#include "crypto.h" +#include "x509.h" +#include "pem.h" +#include "ssl.h" +#include "err.h" +#endif +#endif + + +/* Download buffer size, keep it fairly big for speed reasons */ +#define BUFSIZE (1024*50) + +/* Initial size of the buffer to store headers in, it'll be enlarged in case + of need. */ +#define HEADERSIZE 256 + +struct UrlData { + FILE *out; /* the fetched file goes here */ + FILE *in; /* the uploaded file is read from here */ + FILE *err; /* the stderr writes goes here */ + FILE *writeheader; /* write the header to this is non-NULL */ + char *url; /* what to get */ + char *freethis; /* if non-NULL, an allocated string for the URL */ + char *hostname; /* hostname to contect, as parsed from url */ + unsigned short port; /* which port to use (if non-protocol bind) set + CONF_PORT to use this */ + unsigned short remote_port; /* what remote port to connect to, not the proxy + port! */ + char *proxy; /* if proxy, set it here, set CONF_PROXY to use this */ + long conf; /* configure flags */ + char *userpwd; /* <user:password>, if used */ + char *proxyuserpwd; /* Proxy <user:password>, if used */ + char *range; /* range, if used. See README for detailed specification on + this syntax. */ + char *postfields; /* if POST, set the fields' values here */ + char *referer; + char *errorbuffer; /* store failure messages in here */ + char *useragent; /* User-Agent string */ + + char *ftpport; /* port to send with the PORT command */ + + /* function that stores the output:*/ + size_t (*fwrite)(char *buffer, + size_t size, + size_t nitems, + FILE *outstream); + + /* function that reads the input:*/ + size_t (*fread)(char *buffer, + size_t size, + size_t nitems, + FILE *outstream); + + long timeout; /* in seconds, 0 means no timeout */ + long infilesize; /* size of file to upload, -1 means unknown */ + + long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 + means unlimited */ + + /* fields only set and used within _urlget() */ + int firstsocket; /* the main socket to use */ + int secondarysocket; /* for i.e ftp transfers */ + + char buffer[BUFSIZE+1]; /* buffer with size BUFSIZE */ + + double current_speed; /* the ProgressShow() funcion sets this */ + + long low_speed_limit; /* bytes/second */ + long low_speed_time; /* number of seconds */ + + int resume_from; /* continue [ftp] transfer from here */ + + char *cookie; /* HTTP cookie string to send */ + + short use_ssl; /* use ssl encrypted communications */ + + char *newurl; /* This can only be set if a Location: was in the + document headers */ + +#ifdef MULTIDOC + struct MoreDoc *moredoc; /* linked list of more docs to get */ +#endif + struct HttpHeader *headers; /* linked list of extra headers */ + struct HttpPost *httppost; /* linked list of POST data */ + + char *cert; /* PEM-formatted certificate */ + char *cert_passwd; /* plain text certificate password */ + + struct CookieInfo *cookies; + + long ssl_version; /* what version the client wants to use */ +#ifdef USE_SSLEAY + SSL_CTX* ctx; + SSL* ssl; + X509* server_cert; +#endif /* USE_SSLEAY */ + long crlf; + struct curl_slist *quote; + + TimeCond timecondition; + time_t timevalue; + + char *customrequest; /* http/ftp request to use */ + + char *headerbuff; /* allocated buffer to store headers in */ + int headersize; /* size of the allocation */ + int progressmode; /* what kind of progress meter to display */ + +#define MAX_CURL_USER_LENGTH 128 +#define MAX_CURL_PASSWORD_LENGTH 128 + + char user[MAX_CURL_USER_LENGTH]; + char passwd[MAX_CURL_PASSWORD_LENGTH]; + char proxyuser[MAX_CURL_USER_LENGTH]; + char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; + + /**** Dynamicly allocated strings, may need to be freed on return ****/ + char *ptr_proxyuserpwd; /* free later if not NULL! */ + char *ptr_uagent; /* free later if not NULL! */ + char *ptr_userpwd; /* free later if not NULL! */ + char *ptr_rangeline; /* free later if not NULL! */ + char *ptr_ref; /* free later if not NULL! */ + char *ptr_cookie; /* free later if not NULL! */ + char *ptr_host; /* free later if not NULL */ +}; + +#define LIBCURL_NAME "libcurl" +#define LIBCURL_ID LIBCURL_NAME " " LIBCURL_VERSION " " SSL_ID + + +#endif diff --git a/lib/version.c b/lib/version.c new file mode 100644 index 000000000..73be0d7f9 --- /dev/null +++ b/lib/version.c @@ -0,0 +1,86 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Curl. + * + * The Initial Developer of the Original Code is Daniel Stenberg. + * + * Portions created by the Initial Developer are Copyright (C) 1998. + * All Rights Reserved. + * + * ------------------------------------------------------------ + * Main author: + * - Daniel Stenberg <Daniel.Stenberg@haxx.nu> + * + * http://curl.haxx.nu + * + * $Source$ + * $Revision$ + * $Date$ + * $Author$ + * $State$ + * $Locker$ + * + * ------------------------------------------------------------ + ****************************************************************************/ + +#include <string.h> +#include <stdio.h> + +#include "setup.h" +#include <curl/curl.h> +#include "urldata.h" + +char *curl_version(void) +{ + static char version[200]; + char *ptr; +#if defined(USE_SSLEAY) + static char sub[2]; +#endif + strcpy(version, LIBCURL_NAME " " LIBCURL_VERSION ); + ptr=strchr(version, '\0'); + +#ifdef USE_SSLEAY + +#if (SSLEAY_VERSION_NUMBER >= 0x900000) + sprintf(ptr, " (SSL %x.%x.%x)", + (SSLEAY_VERSION_NUMBER>>28)&0xff, + (SSLEAY_VERSION_NUMBER>>20)&0xff, + (SSLEAY_VERSION_NUMBER>>12)&0xf); +#else + if(SSLEAY_VERSION_NUMBER&0x0f) { + sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1; + } + else + sub[0]=0; + + sprintf(ptr, " (SSL %x.%x.%x%s)", + (SSLEAY_VERSION_NUMBER>>12)&0xff, + (SSLEAY_VERSION_NUMBER>>8)&0xf, + (SSLEAY_VERSION_NUMBER>>4)&0xf, sub); + +#endif + ptr=strchr(ptr, '\0'); +#endif + +#ifdef USE_ZLIB + sprintf(ptr, " (zlib %s)", zlibVersion()); +#endif + + return version; +} |