summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>1999-12-29 14:20:26 +0000
committerDaniel Stenberg <daniel@haxx.se>1999-12-29 14:20:26 +0000
commitae1912cb0d494b48d514d937826c9fe83ec96c4d (patch)
tree3b027d577182fc74bade646227f729eac461d0d2 /lib
downloadcurl-ae1912cb0d494b48d514d937826c9fe83ec96c4d.tar.gz
Initial revision
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile282
-rw-r--r--lib/Makefile.am31
-rw-r--r--lib/Makefile.in282
-rw-r--r--lib/Makefile.m3267
-rw-r--r--lib/Makefile.vc6315
-rw-r--r--lib/arpa_telnet.h319
-rw-r--r--lib/base64.c94
-rw-r--r--lib/base64.h44
-rw-r--r--lib/cookie.c457
-rw-r--r--lib/cookie.h45
-rw-r--r--lib/dict.c245
-rw-r--r--lib/dict.h45
-rw-r--r--lib/download.c484
-rw-r--r--lib/download.h50
-rw-r--r--lib/escape.c111
-rw-r--r--lib/escape.h49
-rw-r--r--lib/file.c175
-rw-r--r--lib/file.h45
-rwxr-xr-xlib/formdatabin0 -> 23808 bytes
-rw-r--r--lib/formdata.c617
-rw-r--r--lib/formdata.h103
-rw-r--r--lib/ftp.c1046
-rw-r--r--lib/ftp.h52
-rw-r--r--lib/getdate.c2101
-rw-r--r--lib/getdate.h46
-rw-r--r--lib/getdate.y1051
-rw-r--r--lib/getenv.c95
-rw-r--r--lib/getenv.h71
-rw-r--r--lib/getpass.c185
-rw-r--r--lib/getpass.h1
-rw-r--r--lib/hostip.c111
-rw-r--r--lib/hostip.h46
-rw-r--r--lib/http.c381
-rw-r--r--lib/http.h45
-rw-r--r--lib/if2ip.c110
-rw-r--r--lib/if2ip.h50
-rw-r--r--lib/ldap.c226
-rw-r--r--lib/ldap.h45
-rw-r--r--lib/mprintf.c1253
-rw-r--r--lib/netrc.c182
-rw-r--r--lib/netrc.h70
-rw-r--r--lib/progress.c221
-rw-r--r--lib/progress.h54
-rw-r--r--lib/sendf.c115
-rw-r--r--lib/sendf.h47
-rw-r--r--lib/setup.h169
-rw-r--r--lib/speedcheck.c81
-rw-r--r--lib/speedcheck.h50
-rw-r--r--lib/ssluse.c265
-rw-r--r--lib/ssluse.h46
-rw-r--r--lib/sta01005bin0 -> 1024 bytes
-rw-r--r--lib/sta18057bin0 -> 461824 bytes
-rw-r--r--lib/telnet.c937
-rw-r--r--lib/telnet.h45
-rw-r--r--lib/timeval.c93
-rw-r--r--lib/timeval.h64
-rw-r--r--lib/upload.c178
-rw-r--r--lib/upload.h46
-rw-r--r--lib/url.c1181
-rw-r--r--lib/url.h0
-rw-r--r--lib/urldata.h212
-rw-r--r--lib/version.c86
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
new file mode 100755
index 000000000..dc8e9e803
--- /dev/null
+++ b/lib/formdata
Binary files differ
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 *)&num;
+ 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
new file mode 100644
index 000000000..31cd282d1
--- /dev/null
+++ b/lib/sta01005
Binary files differ
diff --git a/lib/sta18057 b/lib/sta18057
new file mode 100644
index 000000000..36d824b46
--- /dev/null
+++ b/lib/sta18057
Binary files differ
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;
+}