diff options
author | Mats O Jansson <maja@cvs.openbsd.org> | 1998-03-11 17:48:09 +0000 |
---|---|---|
committer | Mats O Jansson <maja@cvs.openbsd.org> | 1998-03-11 17:48:09 +0000 |
commit | 69de3a9e357327c17caa3b7bb058035e263573bc (patch) | |
tree | f6260f228c4d949b174128d017a7e323c7122f32 /gnu/usr.bin/lynx/WWW | |
parent | b81973f175db7d3f4c763069b191dd57f4bd83d3 (diff) |
Lynx 2.8
Diffstat (limited to 'gnu/usr.bin/lynx/WWW')
147 files changed, 61252 insertions, 0 deletions
diff --git a/gnu/usr.bin/lynx/WWW/BUILD b/gnu/usr.bin/lynx/WWW/BUILD new file mode 100644 index 00000000000..5fda9e0e7c0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/BUILD @@ -0,0 +1,42 @@ +#! /bin/csh +# Build all WWW Code for this platform +# +# Figure out what sort of unix this is +# (NeXT machines don't have uname!) + +set UNAME=NeXT +if (-e /usr/bin/uname) set UNAME=`/usr/bin/uname` +if (-e /bin/uname) set UNAME=`/bin/uname` +if (-e /usr/apollo/bin) set UNAME=`ver sys5.3 /bin/uname` +if ( $UNAME == "" ) then + if (-r /NextApps ) set UNAME=next +endif +# +setenv UNAME $UNAME +# For apollo, must use bsd mode. Also, WWW_MACH not inherited through make! +if ($UNAME == "DomainOS") setenv WWW_MACH apollo_m68k +if ($UNAME == next) setenv WWW_MACH next +if ($UNAME == "HP-UX") setenv WWW_MACH snake +if ($UNAME == "IRIX") setenv WWW_MACH sgi +if ($UNAME == "SunOS") setenv WWW_MACH sun4 +if ($UNAME == "ULTRIX") setenv WWW_MACH decstation +if ($UNAME == "AIX") setenv WWW_MACH rs6000 +if ($UNAME == "OSF1") setenv WWW_MACH osf1 + +if ($WWW_MACH == "") then + echo "Please edit BUILD file to include your machine OS" + echo "and mail differences back to www-bug@info.cern.ch + exit -99 +endif +echo "________________________________________________________________" +echo "WWW build for machine type: " $WWW_MACH + +# Now go do build + +# We don't want SHELL set to something funny to screw up make + +(cd All/Implementation; unsetenv SHELL; make) +set stat = $status +echo +echo "WWW build for " $WWW_MACH " done. status = " $stat +exit $stat diff --git a/gnu/usr.bin/lynx/WWW/Copyright.txt b/gnu/usr.bin/lynx/WWW/Copyright.txt new file mode 100644 index 00000000000..3d7397bba61 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Copyright.txt @@ -0,0 +1,22 @@ + Copyright -- /hypertext + COPYRIGHT CERN 1990-1993 + + Except where specifically placed in the public domain, the information (of + all forms) in these directories is the intellectual property of the European + Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is + provided by CERN. No liability whatsoever is accepted for any loss or damage + of any kind resulting from any defect or inaccuracy in this information or + code. + + The conditions for public domain and other access to the code are defined in + distribution conditions of WWW code[1] + + Tim Berners-Lee[2] + + CERN + + 1211 Geneva 23, Switzerland + + Tel +41(22)767 3755, Fax +41(22)767 7155, Email: tbl@cernvax.cern.ch + + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/BSDI_Makefile b/gnu/usr.bin/lynx/WWW/Library/Implementation/BSDI_Makefile new file mode 100644 index 00000000000..21ff1c02d8e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/BSDI_Makefile @@ -0,0 +1,405 @@ +# Make WWW under unix +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = unix + +# The ASIS repository's name for the machine we are on +ASIS_MACH = generic/unix + + +CFLAGS = -O -DDEBUG -DUSE_DIRENT -DSVR4 -DNO_FILIO_H +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +# Common Makefile for W3 Library Code +# ----------------------------------- +# +# (c) CERN 1990, 1991 -- see Copyright.html for conditions +# +# This file should be invariant between systems. +# DEPENDENCIES NOT COMPLETE @@ +# +# make Compile and link the software (private version) +# make install Copy it into the system (implies make) +# make update Copy installed version into installed version +# make uninstall Unlink installed version from the system +# make clean Remove intermediate files +# make cleanall Remove intremediate files and products +# +# Macros required to be defined already for make: +# +# CC The C compiler +# CFLAGS Flags for $(CC) -- except the -I which are below +# LFLAGS Flags for ld +# LYFLAGS Flags for Lynx +# +# WWW The WWW source tree directory +# +# Macros needed for make install: +# +# LIBDIR Directory for installed library +#______________________________________________________________________ + +# If this env var is set to something else Some makes will use that instead +SHELL = /bin/sh + +# .h files are distributed but originally are made from the +# self-documenting hypertext files. + +.SUFFIXES: .h .html +.html.h: +# - chmod +w $*.h + www -w90 -na -to text/x-c $*.html > $*.h +# chmod -w $*.h + +# If this is actually run in a subdirectory, +# +# WWW = ../../.. +# WWW = ../.. For [cernlib] build in this directory + +WC = $(WWW)/Library +CMN = $(WWW)/Library/Implementation/ +VMS = $(CMN)vms +# Where shall we put the objects and built library? + +LOB = $(WTMP)/Library/$(WWW_MACH) + +# Only needed if HTWAIS.c is to be compiled. Put into your Makefile.include +# uncomment these and fill in WAISINC for adding direct wais access +# to Lynx. +#HTWAIS = $(LOB)/HTWAIS.o +#WAIS = YES +#WAISINC = -I../../../../freeWAIS-0.202/ir +#WAISCFLAGS = -DDIRECT_WAIS +# + +# This path, if relative, is taken relative to the directory +# in which this makefile is, not the pwd. This screws up the +# recursive invocation +# include $(CMN)Version.make +VC = 2.14 + +# XMOsAIC hack is only for server to cope with xmosaic kludge for mmedia +# +# add -DNEW_GATEWAY here for the new gateway config stuff +CFLAGS2 = $(CFLAGS) $(LYFLAGS) $(WAISCFLAGS) -I$(CMN) -DXMOSAIC_HACK -DACCESS_AUTH + +CERNLIBBIN = $(WWW)/bin + +COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ + $(LOB)/HTFile.o $(LOB)/HTBTree.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ + $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ + $(LOB)/HTPlain.o $(LOB)/HTWriter.o \ + $(LOB)/HTMLGen.o \ + $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ + $(LOB)/HTList.o $(LOB)/HTString.o \ + $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTMIME.o \ + $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ + $(LOB)/HTTelnet.o $(LOB)/HTFinger.o $(LOB)/HTWSRC.o $(HTWAIS) \ + $(LOB)/HTAAUtil.o $(LOB)/HTAAServ.o $(LOB)/HTAABrow.o \ + $(LOB)/HTAAFile.o $(LOB)/HTPasswd.o $(LOB)/HTGroup.o \ + $(LOB)/HTACL.o $(LOB)/HTAuth.o $(LOB)/HTAAProt.o \ + $(LOB)/HTAssoc.o $(LOB)/HTLex.o $(LOB)/HTUU.o + +CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ + $(CMN)HTBTree.c \ + $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ + $(CMN)HTMLDTD.c \ + $(CMN)HTPlain.c $(CMN)HTWriter.c \ + $(CMN)HTMLGen.c \ + $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ + $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTRules.c \ + $(CMN)HTFormat.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ + $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ + $(CMN)HTFinger.c $(CMN)HTWAIS.c $(CMN)HTWSRC.c \ + $(CMN)HTAAUtil.c $(CMN)HTAAServ.c $(CMN)HTAABrow.c \ + $(CMN)HTAAFile.c $(CMN)HTPasswd.c $(CMN)HTGroup.c \ + $(CMN)HTACL.c $(CMN)HTAuth.c $(CMN)HTAAProt.c \ + $(CMN)HTAssoc.c $(CMN)HTLex.c $(CMN)HTUU.c + +HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ + $(CMN)HTBTree.h $(CMN)HTFTP.h $(CMN)HTTCP.h \ + $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ + $(CMN)HTPlain.h $(CMN)HTWriter.h \ + $(CMN)HTFWriter.h $(CMN)HTMLGen.h \ + $(CMN)HTStream.h \ + $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ + $(CMN)HTList.h \ + $(CMN)HTString.h $(CMN)HTAlert.h $(CMN)HTRules.h \ + $(CMN)HTFormat.h $(CMN)HTInit.h \ + $(CMN)HTMIME.h $(CMN)HTHistory.h $(CMN)HTNews.h \ + $(CMN)HTGopher.h \ + $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)HText.h \ + $(CMN)HTTelnet.h $(CMN)HTFinger.h \ + $(CMN)HTWAIS.h $(CMN)HTWSRC.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAServ.h $(CMN)HTAABrow.h \ + $(CMN)HTAAFile.h $(CMN)HTPasswd.h $(CMN)HTGroup.h \ + $(CMN)HTACL.h $(CMN)HTAuth.h $(CMN)HTAAProt.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h $(CMN)HTUU.h + +SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make \ + $(CMN)CommonMakefile $(CMN)Makefile \ + $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD $(WWW)/Makefile +SPECIFIC = $(WWW)/All/*/Makefile.include $(WWW)/All/Implementation/Makefile* \ + $(VMS)/descrip.mms $(VMS)/build_multinet.com \ + $(VMS)/COPYING.LIB $(VMS)/setup.com $(VMS)/multinet.opt \ + $(VMS)/patchlevel.h $(VMS)/ufc-crypt.h \ + $(VMS)/crypt.c $(VMS)/crypt_util.c \ + $(VMS)/getline.c $(VMS)/getpass.c \ + $(VMS)/HTVMSUtils.h $(VMS)/HTVMSUtils.c + + +# Library +# +# On SGI, ranlib is unnecessary and does not exist so we ignore errors +# for that step +$(LOB)/libwww.a : $(COMMON) + ar r $(LOB)/libwww.a $(COMMON) + -ranlib $(LOB)/libwww.a + +# Clean up everything generatable except final products +clean : + rm $(LOB)/*.o $(LOB)/.created + -rmdir $(LOB) + +# Clean up everything generatable including final products + +cleanall : clean + rm $(LOB)/libwww.a + +# Install W3 library into system space (not normally necessary) + +install : libwww.a + if [ ! -r $(LIBDIR) ] mkdir $(LIBDIR) + cp libwww.a $(LIBDIR)/libwww.a + +uninstall : + rm $(LIBDIR)/libwww.a + +# Distribution use only: +# ---------------------- + +# Needs www version 2.4 or later to do this +inc : $(HFILES) + echo Include files generated from hypertext. + +binary : /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + echo FTP archive binary Libray $(VC) for $(WWW_MACH) up to date. + + +/pub/www/bin/$(WWW_MACH)/libwww_$(VC).a : libwww.a + -mkdir /pub/www/bin/$(WWW_MACH) + cp libwww.a /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + +# Source Distribution: + +distribute : /pub/www/README.txt /pub/www/Copyright.txt + (cd $(WWW)/..; WWW=WWW ABS=`pwd`/ make $(MFLAGS) \ + -f WWW/Library/Implementation/CommonMakefile \ + /pub/www/src/WWWLibrary_$(VC).tar.Z) + (cd ../Implementation; cvs tag \ + `sed -e 's/VC = /v/' Version.make | sed -e 's?\.?/?'` ) + echo Distribution of Library version $(VC) up to date. + +/pub/www/src/WWWLibrary_$(VC).tar.Z : $(SOURCES) + tar cf /pub/www/src/WWWLibrary_$(VC).tar \ + $(SOURCES) $(SPECIFIC) $(WC)/*/Makefile + compress /pub/www/src/WWWLibrary_$(VC).tar + + +# Hypertext supplied in text format +# --------------------------------- + +$(WWW)/README.txt : $(WWW)/../README.html + www -n -p66 http://www.w3.org/hypertext/README.html \ + > $(WWW)/README.txt +/pub/www/README.txt : $(WWW)/README.txt + cp $(WWW)/README.txt /pub/www/README.txt + +$(WWW)/Copyright.txt : $(WWW)/../Copyright.html + www -n -p66 http://www.w3.org/hypertext/Copyright.html \ + > $(WWW)/Copyright.txt +/pub/www/Copyright.txt : $(WWW)/Copyright.txt + cp $(WWW)/Copyright.txt /pub/www/Copyright.txt + +# Common code +# ----------- + +# Directory for object files - .created checks it exists + +OE = $(LOB)/.created +$(OE) : + if [ ! -r $(WTMP) ] ; then mkdir $(WTMP); else echo OK ; fi + if [ ! -r $(WTMP)/Library ] ; then mkdir $(WTMP)/Library; else echo OK ; fi + if [ ! -r $(WTMP)/Library/$(WWW_MACH) ] ; \ + then mkdir $(WTMP)/Library/$(WWW_MACH); else echo OK ; fi + touch $@ + +$(LOB)/HTList.o : $(OE) $(CMN)HTList.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTList.c + +$(LOB)/HTAnchor.o : $(OE) $(CMN)HTAnchor.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAnchor.c + +$(LOB)/HTFormat.o : $(OE) $(CMN)HTFormat.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFormat.c + +$(LOB)/HTMIME.o : $(OE) $(CMN)HTMIME.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMIME.c + +$(LOB)/HTHistory.o : $(OE) $(CMN)HTHistory.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTHistory.c + +$(LOB)/HTNews.o : $(OE) $(CMN)HTNews.c $(CMN)HTUtils.h $(CMN)HTList.h\ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTNews.c + +$(LOB)/HTGopher.o : $(OE) $(CMN)HTGopher.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGopher.c + +$(LOB)/HTTelnet.o : $(OE) $(CMN)HTTelnet.c $(CMN)HTUtils.h $(CMN)HTTelnet.h $(CMN)../../../userdefs.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTelnet.c + +$(LOB)/HTFinger.o : $(OE) $(CMN)HTFinger.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFinger.c + +$(LOB)/HTStyle.o : $(OE) $(CMN)HTStyle.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTStyle.c + +$(LOB)/HTAtom.o : $(OE) $(CMN)HTAtom.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAtom.c + +$(LOB)/HTChunk.o : $(OE) $(CMN)HTChunk.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTChunk.c + +$(LOB)/HTString.o : $(OE) $(CMN)HTString.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTString.c + +$(LOB)/HTRules.o : $(OE) $(CMN)HTRules.c $(CMN)HTUtils.h $(CMN)Version.make \ + $(CMN)HTAAServ.h $(CMN)HTAAProt.h + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTRules.c + +$(LOB)/SGML.o : $(OE) $(CMN)SGML.c $(CMN)HTUtils.h $(CMN)UCAux.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)SGML.c + +$(LOB)/HTMLGen.o : $(OE) $(CMN)HTMLGen.c $(CMN)HTUtils.h $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLGen.c + +$(LOB)/HTMLDTD.o : $(OE) $(CMN)HTMLDTD.c $(CMN)SGML.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLDTD.c + +$(LOB)/HTPlain.o : $(OE) $(CMN)HTPlain.c $(CMN)HTPlain.h $(CMN)HTStream.h \ + $(CMN)UCAux.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPlain.c + +$(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + +$(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c + +$(LOB)/HTWriter.o : $(OE) $(CMN)HTWriter.c $(CMN)HTWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWriter.c + + +# Access Authorization + +$(LOB)/HTAAUtil.o : $(OE) $(CMN)HTAAUtil.c $(CMN)HTAAUtil.h \ + $(CMN)HTUtils.h $(CMN)HTString.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAUtil.c + +$(LOB)/HTAAFile.o : $(OE) $(CMN)HTAAFile.c $(CMN)HTAAFile.h \ + $(CMN)HTAAUtil.h $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAFile.c + +$(LOB)/HTPasswd.o : $(OE) $(CMN)HTPasswd.c $(CMN)HTPasswd.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPasswd.c + +$(LOB)/HTGroup.o : $(OE) $(CMN)HTGroup.c $(CMN)HTGroup.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGroup.c + +$(LOB)/HTACL.o : $(OE) $(CMN)HTACL.c $(CMN)HTACL.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTGroup.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTACL.c + +$(LOB)/HTAuth.o : $(OE) $(CMN)HTAuth.c $(CMN)HTAuth.h \ + $(CMN)HTAAUtil.h $(CMN)HTPasswd.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAuth.c + +$(LOB)/HTAAServ.o : $(OE) $(CMN)HTAAServ.c $(CMN)HTAAServ.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTPasswd.h \ + $(CMN)HTGroup.h $(CMN)HTACL.h $(CMN)HTAuth.h \ + $(CMN)HTUU.h $(CMN)HTParse.h $(CMN)HTList.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTRules.h \ + $(CMN)HTAAProt.h $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAServ.c + +$(LOB)/HTAABrow.o : $(OE) $(CMN)HTAABrow.c $(CMN)HTAABrow.h \ + $(CMN)HTAAUtil.h $(CMN)HTUU.h \ + $(CMN)HTUtils.h $(CMN)HTString.h \ + $(CMN)HTParse.h $(CMN)HTList.h $(CMN)HTAlert.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAABrow.c + +$(LOB)/HTAAProt.o : $(OE) $(CMN)HTAAProt.c $(CMN)HTAAProt.h \ + $(CMN)HTUtils.h $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAProt.c + +$(LOB)/HTAssoc.o : $(OE) $(CMN)HTAssoc.c $(CMN)HTAssoc.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAssoc.c + +$(LOB)/HTLex.o : $(OE) $(CMN)HTLex.c $(CMN)HTLex.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTLex.c + +$(LOB)/HTUU.o : $(OE) $(CMN)HTUU.c $(CMN)HTUU.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTUU.c + + +# Communications & Files + +$(LOB)/HTTP.o : $(OE) $(CMN)HTTP.c $(CMN)HTUtils.h $(CMN)HTAABrow.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTP.c + +$(LOB)/HTTCP.o : $(OE) $(CMN)HTTCP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTCP.c + +$(LOB)/HTFile.o : $(OE) $(CMN)HTFile.c $(CMN)HTUtils.h \ + $(CMN)HTMLDTD.h $(CMN)HTAAServ.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFile.c + +$(LOB)/HTBTree.o : $(OE) $(CMN)HTBTree.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTBTree.c + +$(LOB)/HTFTP.o : $(OE) $(CMN)HTFTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFTP.c + +$(LOB)/HTAccess.o : $(OE) $(CMN)HTAccess.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAccess.c + +$(LOB)/HTParse.o : $(OE) $(CMN)HTParse.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTParse.c + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/CommonMakefile b/gnu/usr.bin/lynx/WWW/Library/Implementation/CommonMakefile new file mode 100644 index 00000000000..b7d32576ec9 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/CommonMakefile @@ -0,0 +1,373 @@ +# Common Makefile for W3 Library Code +# ----------------------------------- +# +# (c) CERN 1990, 1991 -- see Copyright.html for conditions +# +# This file should be invariant between systems. +# DEPENDENCIES NOT COMPLETE @@ +# +# make Compile and link the software (private version) +# make install Copy it into the system (implies make) +# make update Copy installed version into installed version +# make uninstall Unlink installed version from the system +# make clean Remove intermediate files +# make cleanall Remove intremediate files and products +# +# Macros required to be defined already for make: +# +# CC The C compiler +# CFLAGS Flags for $(CC) -- except the -I which are below +# LFLAGS Flags for ld +# LYFLAGS Flags for Lynx +# +# WWW The WWW source tree directory +# +# Macros needed for make install: +# +# LIBDIR Directory for installed library +#______________________________________________________________________ + +# If this env var is set to something else Some makes will use that instead +SHELL = /bin/sh + +RANLIB = ranlib + +# .h files are distributed but originally are made from the +# self-documenting hypertext files. + +.SUFFIXES: .h .html +.html.h: +# - chmod +w $*.h + www -w90 -na -to text/x-c $*.html > $*.h +# chmod -w $*.h + +# If this is actually run in a subdirectory, +# +# WWW = ../../.. +# WWW = ../.. For [cernlib] build in this directory + +WC = $(WWW)/Library +CMN = $(WWW)/Library/Implementation/ +VMS = $(CMN)vms +# Where shall we put the objects and built library? + +LOB = $(WTMP)/Library/$(WWW_MACH) + +# Only needed if HTWAIS.c is to be compiled. Put into your Makefile.include +# uncomment these and fill in WAISINC for adding direct wais access +# to Lynx. +#HTWAIS = $(LOB)/HTWAIS.o +#WAIS = YES +#WAISINC = -I../../../../freeWAIS-0.202/ir +#WAISCFLAGS = -DDIRECT_WAIS +# + +# XMOsAIC hack is only for server to cope with xmosaic kludge for mmedia +# +# add -DNEW_GATEWAY here for the new gateway config stuff +CFLAGS2 = $(CFLAGS) $(LYFLAGS) $(WAISCFLAGS) -I$(CMN) -DXMOSAIC_HACK -DACCESS_AUTH + +CERNLIBBIN = $(WWW)/bin + +COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ + $(LOB)/HTFile.o $(LOB)/HTBTree.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ + $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ + $(LOB)/HTPlain.o $(LOB)/HTWriter.o \ + $(LOB)/HTMLGen.o \ + $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ + $(LOB)/HTList.o $(LOB)/HTString.o \ + $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTMIME.o \ + $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ + $(LOB)/HTTelnet.o $(LOB)/HTFinger.o $(LOB)/HTWSRC.o $(HTWAIS) \ + $(LOB)/HTAAUtil.o $(LOB)/HTAAServ.o $(LOB)/HTAABrow.o \ + $(LOB)/HTAAFile.o $(LOB)/HTPasswd.o $(LOB)/HTGroup.o \ + $(LOB)/HTACL.o $(LOB)/HTAuth.o $(LOB)/HTAAProt.o \ + $(LOB)/HTAssoc.o $(LOB)/HTLex.o $(LOB)/HTUU.o + +CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ + $(CMN)HTBTree.c \ + $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ + $(CMN)HTMLDTD.c \ + $(CMN)HTPlain.c $(CMN)HTWriter.c \ + $(CMN)HTMLGen.c \ + $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ + $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTRules.c \ + $(CMN)HTFormat.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ + $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ + $(CMN)HTFinger.c $(CMN)HTWAIS.c $(CMN)HTWSRC.c \ + $(CMN)HTAAUtil.c $(CMN)HTAAServ.c $(CMN)HTAABrow.c \ + $(CMN)HTAAFile.c $(CMN)HTPasswd.c $(CMN)HTGroup.c \ + $(CMN)HTACL.c $(CMN)HTAuth.c $(CMN)HTAAProt.c \ + $(CMN)HTAssoc.c $(CMN)HTLex.c $(CMN)HTUU.c + +HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ + $(CMN)HTBTree.h $(CMN)HTFTP.h $(CMN)HTTCP.h \ + $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ + $(CMN)HTPlain.h $(CMN)HTWriter.h \ + $(CMN)HTFWriter.h $(CMN)HTMLGen.h \ + $(CMN)HTStream.h \ + $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ + $(CMN)HTList.h \ + $(CMN)HTString.h $(CMN)HTAlert.h $(CMN)HTRules.h \ + $(CMN)HTFormat.h $(CMN)HTInit.h \ + $(CMN)HTMIME.h $(CMN)HTHistory.h $(CMN)HTNews.h \ + $(CMN)HTGopher.h \ + $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)HText.h \ + $(CMN)HTTelnet.h $(CMN)HTFinger.h \ + $(CMN)HTWAIS.h $(CMN)HTWSRC.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAServ.h $(CMN)HTAABrow.h \ + $(CMN)HTAAFile.h $(CMN)HTPasswd.h $(CMN)HTGroup.h \ + $(CMN)HTACL.h $(CMN)HTAuth.h $(CMN)HTAAProt.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h $(CMN)HTUU.h + +SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make \ + $(CMN)CommonMakefile $(CMN)Makefile \ + $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD $(WWW)/Makefile +SPECIFIC = $(WWW)/All/*/Makefile.include $(WWW)/All/Implementation/Makefile* \ + $(VMS)/descrip.mms $(VMS)/build_multinet.com \ + $(VMS)/COPYING.LIB $(VMS)/setup.com $(VMS)/multinet.opt \ + $(VMS)/patchlevel.h $(VMS)/ufc-crypt.h \ + $(VMS)/crypt.c $(VMS)/crypt_util.c \ + $(VMS)/getline.c $(VMS)/getpass.c \ + $(VMS)/HTVMSUtils.h $(VMS)/HTVMSUtils.c + + +# Library +# +# On SGI, ranlib is unnecessary and does not exist so we ignore errors +# for that step +$(LOB)/libwww.a : $(COMMON) + ar r $(LOB)/libwww.a $(COMMON) + -$(RANLIB) $(LOB)/libwww.a + +# Clean up everything generatable except final products +clean : + rm $(LOB)/*.o $(LOB)/.created + -rmdir $(LOB) + +# Clean up everything generatable including final products + +cleanall : clean + rm $(LOB)/libwww.a + +# Install W3 library into system space (not normally necessary) + +install : libwww.a + if [ ! -r $(LIBDIR) ] mkdir $(LIBDIR) + cp libwww.a $(LIBDIR)/libwww.a + +uninstall : + rm $(LIBDIR)/libwww.a + +# Distribution use only: +# ---------------------- + +# Needs www version 2.4 or later to do this +inc : $(HFILES) + echo Include files generated from hypertext. + +binary : /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + echo FTP archive binary Libray $(VC) for $(WWW_MACH) up to date. + + +/pub/www/bin/$(WWW_MACH)/libwww_$(VC).a : libwww.a + -mkdir /pub/www/bin/$(WWW_MACH) + cp libwww.a /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + +# Source Distribution: + +distribute : /pub/www/README.txt /pub/www/Copyright.txt + (cd $(WWW)/..; WWW=WWW ABS=`pwd`/ make $(MFLAGS) \ + -f WWW/Library/Implementation/CommonMakefile \ + /pub/www/src/WWWLibrary_$(VC).tar.Z) + (cd ../Implementation; cvs tag \ + `sed -e 's/VC = /v/' Version.make | sed -e 's?\.?/?'` ) + echo Distribution of Library version $(VC) up to date. + +/pub/www/src/WWWLibrary_$(VC).tar.Z : $(SOURCES) + tar cf /pub/www/src/WWWLibrary_$(VC).tar \ + $(SOURCES) $(SPECIFIC) $(WC)/*/Makefile + compress /pub/www/src/WWWLibrary_$(VC).tar + + +# Hypertext supplied in text format +# --------------------------------- + +$(WWW)/README.txt : $(WWW)/../README.html + www -n -p66 http://www.w3.org/hypertext/README.html \ + > $(WWW)/README.txt +/pub/www/README.txt : $(WWW)/README.txt + cp $(WWW)/README.txt /pub/www/README.txt + +$(WWW)/Copyright.txt : $(WWW)/../Copyright.html + www -n -p66 http://www.w3.org/hypertext/Copyright.html \ + > $(WWW)/Copyright.txt +/pub/www/Copyright.txt : $(WWW)/Copyright.txt + cp $(WWW)/Copyright.txt /pub/www/Copyright.txt + +# Common code +# ----------- + +# Directory for object files - .created checks it exists + +OE = $(LOB)/.created +$(OE) : + if [ ! -r $(WTMP) ] ; then mkdir $(WTMP); else echo OK ; fi + if [ ! -r $(WTMP)/Library ] ; then mkdir $(WTMP)/Library; else echo OK ; fi + if [ ! -r $(WTMP)/Library/$(WWW_MACH) ] ; \ + then mkdir $(WTMP)/Library/$(WWW_MACH); else echo OK ; fi + touch $@ + +$(LOB)/HTList.o : $(OE) $(CMN)HTList.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTList.c + +$(LOB)/HTAnchor.o : $(OE) $(CMN)HTAnchor.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAnchor.c + +$(LOB)/HTFormat.o : $(OE) $(CMN)HTFormat.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFormat.c + +$(LOB)/HTMIME.o : $(OE) $(CMN)HTMIME.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMIME.c + +$(LOB)/HTHistory.o : $(OE) $(CMN)HTHistory.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTHistory.c + +$(LOB)/HTNews.o : $(OE) $(CMN)HTNews.c $(CMN)HTUtils.h $(CMN)HTList.h\ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTNews.c + +$(LOB)/HTGopher.o : $(OE) $(CMN)HTGopher.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGopher.c + +$(LOB)/HTTelnet.o : $(OE) $(CMN)HTTelnet.c $(CMN)HTUtils.h $(CMN)HTTelnet.h $(CMN)../../../userdefs.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTelnet.c + +$(LOB)/HTFinger.o : $(OE) $(CMN)HTFinger.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFinger.c + +$(LOB)/HTStyle.o : $(OE) $(CMN)HTStyle.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTStyle.c + +$(LOB)/HTAtom.o : $(OE) $(CMN)HTAtom.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAtom.c + +$(LOB)/HTChunk.o : $(OE) $(CMN)HTChunk.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTChunk.c + +$(LOB)/HTString.o : $(OE) $(CMN)HTString.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTString.c + +$(LOB)/HTRules.o : $(OE) $(CMN)HTRules.c $(CMN)HTUtils.h $(CMN)Version.make \ + $(CMN)HTAAServ.h $(CMN)HTAAProt.h + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTRules.c + +$(LOB)/SGML.o : $(OE) $(CMN)SGML.c $(CMN)HTUtils.h $(CMN)UCAux.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)SGML.c + +$(LOB)/HTMLGen.o : $(OE) $(CMN)HTMLGen.c $(CMN)HTUtils.h $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLGen.c + +$(LOB)/HTMLDTD.o : $(OE) $(CMN)HTMLDTD.c $(CMN)SGML.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLDTD.c + +$(LOB)/HTPlain.o : $(OE) $(CMN)HTPlain.c $(CMN)HTPlain.h $(CMN)HTStream.h \ + $(CMN)UCAux.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPlain.c + +$(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + +$(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c + +$(LOB)/HTWriter.o : $(OE) $(CMN)HTWriter.c $(CMN)HTWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWriter.c + + +# Access Authorization + +$(LOB)/HTAAUtil.o : $(OE) $(CMN)HTAAUtil.c $(CMN)HTAAUtil.h \ + $(CMN)HTUtils.h $(CMN)HTString.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAUtil.c + +$(LOB)/HTAAFile.o : $(OE) $(CMN)HTAAFile.c $(CMN)HTAAFile.h \ + $(CMN)HTAAUtil.h $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAFile.c + +$(LOB)/HTPasswd.o : $(OE) $(CMN)HTPasswd.c $(CMN)HTPasswd.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPasswd.c + +$(LOB)/HTGroup.o : $(OE) $(CMN)HTGroup.c $(CMN)HTGroup.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGroup.c + +$(LOB)/HTACL.o : $(OE) $(CMN)HTACL.c $(CMN)HTACL.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTGroup.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTACL.c + +$(LOB)/HTAuth.o : $(OE) $(CMN)HTAuth.c $(CMN)HTAuth.h \ + $(CMN)HTAAUtil.h $(CMN)HTPasswd.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAuth.c + +$(LOB)/HTAAServ.o : $(OE) $(CMN)HTAAServ.c $(CMN)HTAAServ.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTPasswd.h \ + $(CMN)HTGroup.h $(CMN)HTACL.h $(CMN)HTAuth.h \ + $(CMN)HTUU.h $(CMN)HTParse.h $(CMN)HTList.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTRules.h \ + $(CMN)HTAAProt.h $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAServ.c + +$(LOB)/HTAABrow.o : $(OE) $(CMN)HTAABrow.c $(CMN)HTAABrow.h \ + $(CMN)HTAAUtil.h $(CMN)HTUU.h \ + $(CMN)HTUtils.h $(CMN)HTString.h \ + $(CMN)HTParse.h $(CMN)HTList.h $(CMN)HTAlert.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAABrow.c + +$(LOB)/HTAAProt.o : $(OE) $(CMN)HTAAProt.c $(CMN)HTAAProt.h \ + $(CMN)HTUtils.h $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAProt.c + +$(LOB)/HTAssoc.o : $(OE) $(CMN)HTAssoc.c $(CMN)HTAssoc.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAssoc.c + +$(LOB)/HTLex.o : $(OE) $(CMN)HTLex.c $(CMN)HTLex.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTLex.c + +$(LOB)/HTUU.o : $(OE) $(CMN)HTUU.c $(CMN)HTUU.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTUU.c + + +# Communications & Files + +$(LOB)/HTTP.o : $(OE) $(CMN)HTTP.c $(CMN)HTUtils.h $(CMN)HTAABrow.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTP.c + +$(LOB)/HTTCP.o : $(OE) $(CMN)HTTCP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTCP.c + +$(LOB)/HTFile.o : $(OE) $(CMN)HTFile.c $(CMN)HTUtils.h \ + $(CMN)HTMLDTD.h $(CMN)HTAAServ.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFile.c + +$(LOB)/HTBTree.o : $(OE) $(CMN)HTBTree.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTBTree.c + +$(LOB)/HTFTP.o : $(OE) $(CMN)HTFTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFTP.c + +$(LOB)/HTAccess.o : $(OE) $(CMN)HTAccess.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAccess.c + +$(LOB)/HTParse.o : $(OE) $(CMN)HTParse.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTParse.c + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c new file mode 100644 index 00000000000..0ebe5309e7d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c @@ -0,0 +1,1309 @@ + +/* MODULE HTAABrow.c +** BROWSER SIDE ACCESS AUTHORIZATION MODULE +** +** Containts the code for keeping track on server hostnames, +** port numbers, scheme names, usernames, passwords +** (and servers' public keys). +** +** IMPORTANT: +** Routines in this module use dynamic allocation, but free +** automatically all the memory reserved by them. +** +** Therefore the caller never has to (and never should) +** free() any object returned by these functions. +** +** Therefore also all the strings returned by this package +** are only valid until the next call to the same function +** is made. This approach is selected, because of the nature +** of access authorization: no string returned by the package +** needs to be valid longer than until the next call. +** +** This also makes it easy to plug the AA package in: +** you don't have to ponder whether to free() something +** here or is it done somewhere else (because it is always +** done somewhere else). +** +** The strings that the package needs to store are copied +** so the original strings given as parameters to AA +** functions may be freed or modified with no side effects. +** +** The AA package does not free() anything else than what +** it has itself allocated. +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** Oct 17 AL Made corrections suggested by marca: +** Added if (!realm->username) return NULL; +** Changed some ""s to NULLs. +** Now doing calloc() to init uuencode source; +** otherwise HTUU_encode() reads uninitialized memory +** every now and then (not a real bug but not pretty). +** Corrected the formula for uuencode destination size. +** +** 28 Apr 1997 AJL Do Proxy Authorisation. +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include <string.h> /* strchr() */ +#include "HTString.h" +#include "HTParse.h" /* URL parsing function */ +#include "HTList.h" /* HTList object */ +#include "HTAlert.h" /* HTConfirm(), HTPrompt() */ +#include "HTAAUtil.h" /* AA common to both sides */ +#include "HTAssoc.h" /* Assoc list */ +#include "HTAABrow.h" /* Implemented here */ +#include "HTUU.h" /* Uuencoding and uudecoding */ + +#include "LYLeaks.h" + +extern BOOL using_proxy; /* Are we using an HTTP gateway? */ + +/* +** Local datatype definitions +** +** HTAAServer contains all the information about one server. +*/ +typedef struct { + + char * hostname; /* Host's name */ + int portnumber; /* Port number */ + BOOL IsProxy; /* Is it a proxy? */ + HTList * setups; /* List of protection setups */ + /* on this server; i.e. valid */ + /* authentication schemes and */ + /* templates when to use them. */ + /* This is actually a list of */ + /* HTAASetup objects. */ + HTList * realms; /* Information about passwords */ +} HTAAServer; + +/* +** HTAASetup contains information about one server's one +** protected tree of documents. +*/ +typedef struct { + HTAAServer *server; /* Which server serves this tree */ + char * template; /* Template for this tree */ + HTList * valid_schemes; /* Valid authentic.schemes */ + HTAssocList**scheme_specifics;/* Scheme specific params */ + BOOL retry; /* Failed last time -- reprompt (or whatever)*/ +} HTAASetup; + +/* +** Information about usernames and passwords in +** Basic and Pubkey authentication schemes; +*/ +typedef struct { + char * realmname; /* Password domain name */ + char * username; /* Username in that domain */ + char * password; /* Corresponding password */ +} HTAARealm; + +/* +** To free off all globals. - FM +*/ +PRIVATE void free_HTAAGlobals NOPARAMS; +PRIVATE BOOL free_HTAAGlobalsSet = FALSE; +PRIVATE char *HTAA_composeAuthResult = NULL; +PRIVATE char *compose_auth_stringResult = NULL; /* Uuencoded presentation */ + +/* +** Module-wide global variables +*/ +PRIVATE HTList *server_table = NULL; /* Browser's info about servers */ +PRIVATE char *secret_key = NULL; /* Browser's latest secret key */ +PRIVATE HTAASetup *current_setup= NULL; /* The server setup we are currently */ + /* talking to */ +PRIVATE char *current_hostname = NULL; /* The server's name and portnumber */ +PRIVATE int current_portnumber = 80; /* where we are currently trying to */ + /* connect. */ +PRIVATE char *current_docname = NULL; /* The document's name we are */ + /* trying to access. */ +PRIVATE char *HTAAForwardAuth = NULL; /* Authorization: line to forward */ + /* (used by gateway httpds) */ +PRIVATE HTAASetup *proxy_setup = NULL; /* Same as above, but for Proxy -AJL */ +PRIVATE char *proxy_hostname = NULL; +PRIVATE char *proxy_docname = NULL; +PRIVATE int proxy_portnumber = 80; + + +/*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/ + +PUBLIC void HTAAForwardAuth_set ARGS2( + CONST char *, scheme_name, + CONST char *, scheme_specifics) +{ + int len = 20 + (scheme_name ? strlen(scheme_name) : 0) + + (scheme_specifics ? strlen(scheme_specifics) : 0); + + FREE(HTAAForwardAuth); + if (!(HTAAForwardAuth = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAAForwardAuth_set"); + + strcpy(HTAAForwardAuth, "Authorization: "); + if (scheme_name) { + strcat(HTAAForwardAuth, scheme_name); + strcat(HTAAForwardAuth, " "); + if (scheme_specifics) { + strcat(HTAAForwardAuth, scheme_specifics); + } + } +} + +PUBLIC void HTAAForwardAuth_reset NOARGS +{ + FREE(HTAAForwardAuth); +} + + +/**************************** HTAAServer ***********************************/ + +PRIVATE void HTAASetup_delete PARAMS((HTAASetup * killme)); /* Forward */ + +/* PRIVATE HTAAServer_new() +** ALLOCATE A NEW NODE TO HOLD SERVER INFO +** AND ADD IT TO THE LIST OF SERVERS +** ON ENTRY: +** hostname is the name of the host that the server +** is running in. +** portnumber is the portnumber which the server listens. +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns the newly-allocated node with all the strings +** duplicated. +** Strings will be automatically freed by +** the function HTAAServer_delete(), which also +** frees the node itself. +*/ +PRIVATE HTAAServer *HTAAServer_new ARGS3( + CONST char*, hostname, + int, portnumber, + BOOL, IsProxy) +{ + HTAAServer *server; + + if (!(server = (HTAAServer *)calloc(1, sizeof(HTAAServer)))) + outofmem(__FILE__, "HTAAServer_new"); + + server->hostname = NULL; + server->portnumber = (portnumber > 0 ? portnumber : 80); + server->IsProxy = IsProxy; + server->setups = HTList_new(); + server->realms = HTList_new(); + + if (hostname) + StrAllocCopy(server->hostname, hostname); + + if (!server_table) + server_table = HTList_new(); + + HTList_addObject(server_table, (void*)server); + + return server; +} + + +/* PRIVATE HTAAServer_delete() +** +** DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE, +** AND FREE THE MEMORY USED BY IT. +** +** ON ENTRY: +** killme points to the HTAAServer to be freed. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAAServer_delete ARGS1( + HTAAServer *, killme) +{ + int n, i; + HTAASetup *setup; + HTAARealm *realm; + HTList *cur; + + if (killme) { + if (killme->setups != NULL) { + n = HTList_count(killme->setups); + for (i = (n - 1); i >= 0; i--) { + if ((setup = (HTAASetup*)HTList_objectAt(killme->setups, + i)) != NULL) { + HTAASetup_delete(setup); + setup = NULL; + } + } + HTList_delete(killme->setups); + killme->setups = NULL; + } + + cur = killme->realms; + while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) { + FREE(realm->realmname); + FREE(realm->username); + FREE(realm->password); + FREE(realm); + } + HTList_delete(killme->realms); + killme->realms = NULL; + + FREE(killme->hostname); + + HTList_removeObject(server_table, (void*)killme); + FREE(killme); + } +} + +/* PRIVATE HTAAServer_lookup() +** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER +** ON ENTRY: +** hostname obvious. +** portnumber if non-positive defaults to 80. +** IsProxy should be TRUE if this is a proxy. +** +** Looks up the server in the module-global server_table. +** +** ON EXIT: +** returns pointer to a HTAAServer structure +** representing the looked-up server. +** NULL, if not found. +*/ +PRIVATE HTAAServer *HTAAServer_lookup ARGS3( + CONST char *, hostname, + int, portnumber, + BOOL, IsProxy) +{ + if (hostname) { + HTList *cur = server_table; + HTAAServer *server; + + if (portnumber <= 0) + portnumber = 80; + + while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) { + if (server->portnumber == portnumber && + 0==strcmp(server->hostname, hostname) && + server->IsProxy == IsProxy) + return server; + } + } + return NULL; /* NULL parameter, or not found */ +} + + +/*************************** HTAASetup *******************************/ + +/* PRIVATE HTAASetup_lookup() +** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER +** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT +** +** ON ENTRY: +** hostname is the name of the server host machine. +** portnumber is the port that the server is running in. +** docname is the (URL-)pathname of the document we +** are trying to access. +** IsProxy should be TRUE if this is a proxy. +** +** This function goes through the information known about +** all the setups of the server, and finds out if the given +** filename resides in one of the protected directories. +** +** ON EXIT: +** returns NULL if no match. +** Otherwise, a HTAASetup structure representing +** the protected server setup on the corresponding +** document tree. +** +*/ +PRIVATE HTAASetup *HTAASetup_lookup ARGS4( + CONST char *, hostname, + int, portnumber, + CONST char *, docname, + BOOL, IsProxy) +{ + HTAAServer *server; + HTAASetup *setup; + + if (portnumber <= 0) + portnumber = 80; + + if (hostname && docname && *hostname && *docname && + NULL != (server = HTAAServer_lookup(hostname, + portnumber, + IsProxy))) { + + HTList *cur = server->setups; + + if (TRACE) + fprintf(stderr, "%s %s (%s:%d:%s)\n", + "HTAASetup_lookup: resolving setup for", + (IsProxy ? "proxy" : "server"), + hostname, portnumber, docname); + + while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) { + if (HTAA_templateMatch(setup->template, docname)) { + if (TRACE) + fprintf(stderr, "%s `%s' %s `%s'\n", + "HTAASetup_lookup:", docname, + "matched template", setup->template); + return setup; + } + else if (TRACE) + fprintf(stderr, "%s `%s' %s `%s'\n", + "HTAASetup_lookup:", docname, + "did NOT match template", setup->template); + } /* while setups remain */ + } /* if valid parameters and server found */ + + if (TRACE) + fprintf(stderr, "%s `%s' %s\n", + "HTAASetup_lookup: No template matched", + (docname ? docname : "(null)"), + "(so probably not protected)"); + + return NULL; /* NULL in parameters, or not found */ +} + +/* PRIVATE HTAASetup_new() +** CREATE A NEW SETUP NODE +** ON ENTRY: +** server is a pointer to a HTAAServer structure +** to which this setup belongs. +** template documents matching this template +** are protected according to this setup. +** valid_schemes a list containing all valid authentication +** schemes for this setup. +** If NULL, all schemes are disallowed. +** scheme_specifics is an array of assoc lists, which +** contain scheme specific parameters given +** by server in Authenticate: fields. +** If NULL, all scheme specifics are +** set to NULL. +** ON EXIT: +** returns a new HTAASetup node, and also adds it as +** part of the HTAAServer given as parameter. +*/ +PRIVATE HTAASetup *HTAASetup_new ARGS4( + HTAAServer *, server, + char *, template, + HTList *, valid_schemes, + HTAssocList **, scheme_specifics) +{ + HTAASetup *setup; + + if (!server || !template || !*template) + return NULL; + + if (!(setup = (HTAASetup*)calloc(1, sizeof(HTAASetup)))) + outofmem(__FILE__, "HTAASetup_new"); + + setup->retry = NO; + setup->server = server; + setup->template = NULL; + if (template) + StrAllocCopy(setup->template, template); + setup->valid_schemes = valid_schemes; + setup->scheme_specifics = scheme_specifics; + + HTList_addObject(server->setups, (void*)setup); + + return setup; +} + +/* PRIVATE HTAASetup_delete() +** FREE A HTAASetup STRUCTURE +** ON ENTRY: +** killme is a pointer to the structure to free(). +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAASetup_delete ARGS1( + HTAASetup *, killme) +{ + int scheme; + + if (killme) { + FREE(killme->template); + if (killme->valid_schemes) + HTList_delete(killme->valid_schemes); + killme->valid_schemes = NULL; + for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++) + if (killme->scheme_specifics[scheme]) + HTAssocList_delete(killme->scheme_specifics[scheme]); + FREE(killme->scheme_specifics); + FREE(killme); + } +} + +/* PRIVATE HTAASetup_updateSpecifics() +* COPY SCHEME SPECIFIC PARAMETERS +** TO HTAASetup STRUCTURE +** ON ENTRY: +** setup destination setup structure. +** specifics string array containing scheme +** specific parameters for each scheme. +** If NULL, all the scheme specific +** parameters are set to NULL. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAASetup_updateSpecifics ARGS2( + HTAASetup *, setup, + HTAssocList **, specifics) +{ + int scheme; + + if (setup) { + if (setup->scheme_specifics) { + for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++) { + if (setup->scheme_specifics[scheme]) + HTAssocList_delete(setup->scheme_specifics[scheme]); + } + FREE(setup->scheme_specifics); + } + setup->scheme_specifics = specifics; + } +} + + +/*************************** HTAARealm **********************************/ + +/* PRIVATE HTAARealm_lookup() +** LOOKUP HTAARealm STRUCTURE BY REALM NAME +** ON ENTRY: +** realm_table a list of realm objects. +** realmname is the name of realm to look for. +** +** ON EXIT: +** returns the realm. NULL, if not found. +*/ +PRIVATE HTAARealm *HTAARealm_lookup ARGS2( + HTList *, realm_table, + CONST char *, realmname) +{ + if (realm_table && realmname) { + HTList *cur = realm_table; + HTAARealm *realm; + + while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) { + if (0==strcmp(realm->realmname, realmname)) + return realm; + } + } + return NULL; /* No table, NULL param, or not found */ +} + +/* PRIVATE HTAARealm_new() +** CREATE A NODE CONTAINING USERNAME AND +** PASSWORD USED FOR THE GIVEN REALM. +** IF REALM ALREADY EXISTS, CHANGE +** USERNAME/PASSWORD. +** ON ENTRY: +** realm_table a list of realms to where to add +** the new one, too. +** realmname is the name of the password domain. +** username and +** password are what you can expect them to be. +** +** ON EXIT: +** returns the created realm. +*/ +PRIVATE HTAARealm *HTAARealm_new ARGS4( + HTList *, realm_table, + CONST char *, realmname, + CONST char *, username, + CONST char *, password) +{ + HTAARealm *realm; + + realm = HTAARealm_lookup(realm_table, realmname); + + if (!realm) { + if (!(realm = (HTAARealm*)calloc(1, sizeof(HTAARealm)))) + outofmem(__FILE__, "HTAARealm_new"); + realm->realmname = NULL; + realm->username = NULL; + realm->password = NULL; + StrAllocCopy(realm->realmname, realmname); + if (realm_table) + HTList_addObject(realm_table, (void*)realm); + } + if (username) + StrAllocCopy(realm->username, username); + if (password) + StrAllocCopy(realm->password, password); + + return realm; +} + + +/***************** Basic and Pubkey Authentication ************************/ + +/* PRIVATE compose_auth_string() +** +** COMPOSE Basic OR Pubkey AUTHENTICATION STRING; +** PROMPTS FOR USERNAME AND PASSWORD IF NEEDED +** +** ON ENTRY: +** scheme is either HTAA_BASIC or HTAA_PUBKEY. +** setup is the current server setup. +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns a newly composed authorization string, +** (with, of course, a newly generated secret +** key and fresh timestamp, if Pubkey-scheme +** is being used). +** NULL, if something fails. +** NOTE: +** Like throughout the entire AA package, no string or structure +** returned by AA package needs to (or should) be freed. +** +*/ +PRIVATE char *compose_auth_string ARGS3( + HTAAScheme, scheme, + HTAASetup *, setup, + BOOL, IsProxy) +{ + char *cleartext = NULL; /* Cleartext presentation */ + char *ciphertext = NULL; /* Encrypted presentation */ + int len; + char *msg = NULL; + char *username = NULL; + char *password = NULL; + char *realmname = NULL; + char *theHost = NULL; + char *proxiedHost = NULL; + char *thePort = NULL; + HTAARealm *realm; + char *i_net_addr = "0.0.0.0"; /* Change... @@@@ */ + char *timestamp = "42"; /* ... these @@@@ */ + + + FREE(compose_auth_stringResult); /* From previous call */ + + if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup || + !setup->scheme_specifics || !setup->scheme_specifics[scheme] || + !setup->server || !setup->server->realms) + return NULL; + + realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm"); + if (!realmname) + return NULL; + + realm = HTAARealm_lookup(setup->server->realms, realmname); + if (!(realm && + realm->username && *realm->username && + realm->password && *realm->password) || setup->retry) { + if (!realm) { + if (TRACE) + fprintf(stderr, "%s `%s' %s\n", + "compose_auth_string: realm:", realmname, + "not found -- creating"); + realm = HTAARealm_new(setup->server->realms, + realmname, NULL, NULL); + } + /* + * The template should be either the '*' global + * for everthing on the server (always true for + * proxy authorization setups), or a path for + * the start of a protected limb, with no host + * field, but we'll check for a host anyway in + * case a WWW-Protection-Template header set an + * absolute URL instead of a path. If we do get + * a host from this, it will include the port. - FM + */ + if ((!IsProxy) && using_proxy && setup->template) { + proxiedHost = HTParse(setup->template, "", PARSE_HOST); + if (proxiedHost && *proxiedHost != '\0') { + theHost = proxiedHost; + } + } + /* + * If we didn't get a host field from the + * template, set up the host name and port + * from the setup->server elements. - FM + */ + if (!theHost) + theHost = setup->server->hostname; + if (setup->server->portnumber > 0 && + setup->server->portnumber != 80) { + if (!(thePort = (char *)calloc(1, sizeof(char) * 40))) + outofmem(__FILE__, "compose_auth_string"); + sprintf(thePort, ":%d", setup->server->portnumber); + } + /* + * Set up the message for the username prompt, + * and then issue the prompt. The default + * username is included in the call to the + * prompting function, but the password is + * NULL-ed and always replaced. - FM + */ + len = strlen(realm->realmname) + + strlen(theHost ? + theHost : "??") + 50; + if (!(msg = (char *)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "compose_auth_string"); + sprintf(msg, "Username for '%s' at %s '%s%s':", + realm->realmname, + (IsProxy ? "proxy" : "server"), + (theHost ? theHost : "??"), + (thePort ? thePort : "")); + FREE(proxiedHost); + FREE(thePort); + username = realm->username; + password = NULL; + HTPromptUsernameAndPassword(msg, &username, &password, IsProxy); + + FREE(msg); + FREE(realm->username); + FREE(realm->password); + realm->username = username; + realm->password = password; + + if (!realm->username || !realm->password) { + /* + * Signals to retry. - FM + */ + return NULL; + } else if (*realm->username == '\0' || *realm->password == '\0') { + /* + * Signals to abort. - FM + */ + StrAllocCopy(compose_auth_stringResult, ""); + return compose_auth_stringResult; + } + } + + len = strlen(realm->username ? realm->username : "") + + strlen(realm->password ? realm->password : "") + 3; + + if (scheme == HTAA_PUBKEY) { +#ifdef PUBKEY + /* Generate new secret key */ + StrAllocCopy(secret_key, HTAA_generateRandomKey()); +#endif /* PUBKEY */ + /* Room for secret key, timestamp and inet address */ + len += strlen(secret_key ? secret_key : "") + 30; + } else { + FREE(secret_key); + } + + if (!(cleartext = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "compose_auth_string"); + + if (realm->username) + strcpy(cleartext, realm->username); + else + *cleartext = '\0'; + + strcat(cleartext, ":"); + + if (realm->password) + strcat(cleartext, realm->password); + + if (scheme == HTAA_PUBKEY) { + strcat(cleartext, ":"); + strcat(cleartext, i_net_addr); + strcat(cleartext, ":"); + strcat(cleartext, timestamp); + strcat(cleartext, ":"); + if (secret_key) + strcat(cleartext, secret_key); + + if (!((ciphertext = (char *)calloc(1, (sizeof(char) * 2) * len)) && + (compose_auth_stringResult = + (char *)calloc(1, (sizeof(char) * 3) * len)))) + outofmem(__FILE__, "compose_auth_string"); +#ifdef PUBKEY + HTPK_encrypt(cleartext, ciphertext, server->public_key); + HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), + compose_auth_stringResult); +#endif /* PUBKEY */ + FREE(cleartext); + FREE(ciphertext); + } + else { /* scheme == HTAA_BASIC */ + if (!(compose_auth_stringResult = + (char*)calloc(1, (4 * ((len+2)/3)) + 1))) + outofmem(__FILE__, "compose_auth_string"); + HTUU_encode((unsigned char *)cleartext, strlen(cleartext), + compose_auth_stringResult); + FREE(cleartext); + } + return compose_auth_stringResult; +} + +/* BROWSER PRIVATE HTAA_selectScheme() +** SELECT THE AUTHENTICATION SCHEME TO USE +** ON ENTRY: +** setup is the server setup structure which can +** be used to make the decision about the +** used scheme. +** +** When new authentication methods are added to library +** this function makes the decision about which one to +** use at a given time. This can be done by inspecting +** environment variables etc. +** +** Currently only searches for the first valid scheme, +** and if nothing found suggests Basic scheme; +** +** ON EXIT: +** returns the authentication scheme to use. +*/ +PRIVATE HTAAScheme HTAA_selectScheme ARGS1( + HTAASetup *, setup) +{ + HTAAScheme scheme; + + if (setup && setup->valid_schemes) { + for (scheme = HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++) + if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme)) + return scheme; + } + return HTAA_BASIC; +} + +/* +** Purpose: Free off all module globals. +** Arguments: void +** Return Value: void +** Remarks/Portability/Dependencies/Restrictions: +** To be used at program exit. +** Revision History: +** 06-19-96 created - FM +*/ +PRIVATE void free_HTAAGlobals NOARGS +{ + HTAAServer * server; + int n, i; + + if (server_table != NULL) { + n = HTList_count(server_table); + for (i = (n - 1); i >= 0; i--) { + if ((server = (HTAAServer*)HTList_objectAt(server_table, + i)) != NULL) { + HTAAServer_delete(server); + server = NULL; + } + } + HTList_delete(server_table); + server_table = NULL; + } + + HTAAForwardAuth_reset(); + FREE(HTAA_composeAuthResult); + FREE(current_hostname); + FREE(current_docname); + FREE(proxy_hostname); + FREE(proxy_docname); + FREE(compose_auth_stringResult); + FREE(secret_key); +} + +/* BROWSER PUBLIC HTAA_composeAuth() +** +** SELECT THE AUTHENTICATION SCHEME AND +** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE +** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION +** +** ON ENTRY: +** hostname is the hostname of the server. +** portnumber is the portnumber in which the server runs. +** docname is the pathname of the document (as in URL) +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns NULL, if no authorization seems to be needed, or +** if it is the entire Authorization: line, e.g. +** +** "Authorization: Basic username:password" +** +** As usual, this string is automatically freed. +*/ +PUBLIC char *HTAA_composeAuth ARGS4( + CONST char *, hostname, + CONST int, portnumber, + CONST char *, docname, + BOOL, IsProxy) +{ + char *auth_string; + BOOL retry; + HTAAScheme scheme; + int len; + + /* + ** Setup atexit() freeing if not done already. - FM + */ + if (!free_HTAAGlobalsSet) { + atexit(free_HTAAGlobals); + free_HTAAGlobalsSet = TRUE; + } + + /* + ** Make gateway httpds pass authorization field as it was received. + ** (This still doesn't really work because Authenticate: headers + ** from remote server are not forwarded to client yet so it cannot + ** really know that it should send authorization; I will not + ** implement it yet because I feel we will soon change radically + ** the way requests are represented to allow multithreading + ** on server-side. Life is hard.) + */ + if (HTAAForwardAuth) { + if (TRACE) + fprintf(stderr, "HTAA_composeAuth: %s\n", + "Forwarding received authorization"); + StrAllocCopy(HTAA_composeAuthResult, HTAAForwardAuth); + HTAAForwardAuth_reset(); /* Just a precaution */ + return HTAA_composeAuthResult; + } + + FREE(HTAA_composeAuthResult); /* From previous call */ + + if (IsProxy) { + /* + ** Proxy Authorization required. - AJL + */ + + if (TRACE) + fprintf(stderr, + "Composing Proxy Authorization for %s:%d/%s\n", + hostname, portnumber, docname); + + if (proxy_portnumber != portnumber || + !proxy_hostname || !proxy_docname || + !hostname || !docname || + 0 != strcmp(proxy_hostname, hostname) || + 0 != strcmp(proxy_docname, docname)) { + + retry = NO; + + proxy_portnumber = portnumber; + + if (hostname) + StrAllocCopy(proxy_hostname, hostname); + else + FREE(proxy_hostname); + + if (docname) + StrAllocCopy(proxy_docname, docname); + else + FREE(proxy_docname); + } else { + retry = YES; + } + + if (!proxy_setup || !retry) + proxy_setup = HTAASetup_lookup(hostname, portnumber, + docname, IsProxy); + + if (!proxy_setup) + return NULL; + + switch (scheme = HTAA_selectScheme(proxy_setup)) { + case HTAA_BASIC: + case HTAA_PUBKEY: + auth_string = compose_auth_string(scheme, proxy_setup, IsProxy); + break; + case HTAA_KERBEROS_V4: + /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */ + default: + { + char msg[100]; + sprintf(msg, "%s %s `%s'", + "This client doesn't know how to compose proxy", + "authorization information for scheme", + HTAAScheme_name(scheme)); + HTAlert(msg); + auth_string = NULL; + } + } /* switch scheme */ + + proxy_setup->retry = NO; + + if (!auth_string) + /* + ** Signal a failure. - FM + */ + return NULL; /* Added by marca. */ + if (*auth_string == '\0') { + /* + ** Signal an abort. - FM + */ + StrAllocCopy(HTAA_composeAuthResult, ""); + return(HTAA_composeAuthResult); + } + len = strlen(auth_string) + strlen((char *)HTAAScheme_name(scheme)) + 26; + if (!(HTAA_composeAuthResult = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAA_composeAuth"); + strcpy(HTAA_composeAuthResult, "Proxy-Authorization: "); + + } else { + /* + ** Normal WWW authorization. + */ + if (TRACE) + fprintf(stderr, + "Composing Authorization for %s:%d/%s\n", + hostname, portnumber, docname); + + if (current_portnumber != portnumber || + !current_hostname || !current_docname || + !hostname || !docname || + 0 != strcmp(current_hostname, hostname) || + 0 != strcmp(current_docname, docname)) { + + retry = NO; + + current_portnumber = portnumber; + + if (hostname) + StrAllocCopy(current_hostname, hostname); + else + FREE(current_hostname); + + if (docname) + StrAllocCopy(current_docname, docname); + else + FREE(current_docname); + } else { + retry = YES; + } + + if (!current_setup || !retry) + current_setup = HTAASetup_lookup(hostname, portnumber, + docname, IsProxy); + + if (!current_setup) + return NULL; + + switch (scheme = HTAA_selectScheme(current_setup)) { + case HTAA_BASIC: + case HTAA_PUBKEY: + auth_string = compose_auth_string(scheme, current_setup, IsProxy); + break; + case HTAA_KERBEROS_V4: + /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */ + default: + { + char msg[100]; + sprintf(msg, "%s %s `%s'", + "This client doesn't know how to compose", + "authoritzation information for scheme", + HTAAScheme_name(scheme)); + HTAlert(msg); + auth_string = NULL; + } + } /* switch scheme */ + + current_setup->retry = NO; + + if (!auth_string) + /* + ** Signal a failure. - FM + */ + return NULL; /* Added by marca. */ + if (*auth_string == '\0') { + /* + ** Signal an abort. - FM + */ + StrAllocCopy(HTAA_composeAuthResult, ""); + return(HTAA_composeAuthResult); + } + + len = strlen(auth_string) + strlen((char *)HTAAScheme_name(scheme)) + 20; + if (!(HTAA_composeAuthResult = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAA_composeAuth"); + strcpy(HTAA_composeAuthResult, "Authorization: "); + } + + strcat(HTAA_composeAuthResult, HTAAScheme_name(scheme)); + strcat(HTAA_composeAuthResult, " "); + strcat(HTAA_composeAuthResult, auth_string); + return HTAA_composeAuthResult; +} + +/* BROWSER PUBLIC HTAA_shouldRetryWithAuth() +** +** DETERMINES IF WE SHOULD RETRY THE SERVER +** WITH AUTHORIZATION +** (OR IF ALREADY RETRIED, WITH A DIFFERENT +** USERNAME AND/OR PASSWORD (IF MISSPELLED)) +** ON ENTRY: +** start_of_headers is the first block already read from socket, +** but status line skipped; i.e. points to the +** start of the header section. +** length is the remaining length of the first block. +** soc is the socket to read the rest of server reply. +** IsProxy should be TRUE if this is a proxy. +** +** This function should only be called when +** server has replied with a 401 (Unauthorized) +** status code. +** ON EXIT: +** returns YES, if connection should be retried. +** The node containing all the necessary +** information is +** * either constructed if it does not exist +** * or password is reset to NULL to indicate +** that username and password should be +** reprompted when composing Authorization: +** field (in function HTAA_composeAuth()). +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS5( + char *, start_of_headers, + int, length, + void *, handle, + int, soc, + BOOL, IsProxy) +{ + HTAAScheme scheme; + char *line = NULL; + int num_schemes = 0; + HTList *valid_schemes = HTList_new(); + HTAssocList **scheme_specifics = NULL; + char *template = NULL; + char *temp = NULL; + + /* + ** Setup atexit() freeing if not done already. - FM + */ + if (!free_HTAAGlobalsSet) { + atexit(free_HTAAGlobals); + free_HTAAGlobalsSet = TRUE; + } + + /* + ** Read server reply header lines + */ + if (TRACE) + fprintf(stderr, "Server reply header lines:\n"); + + HTAA_setupReader(start_of_headers, length, handle, soc); + while (NULL != (line = HTAA_getUnfoldedLine()) && *line != '\0') { + if (TRACE) + fprintf(stderr, "%s\n", line); + + if (strchr(line, ':')) { /* Valid header line */ + + char *p = line; + char *fieldname = HTNextField(&p); + char *arg1 = HTNextField(&p); + char *args = p; + + if ((IsProxy && + 0==strcasecomp(fieldname, "Proxy-Authenticate:")) || + (!IsProxy && + 0==strcasecomp(fieldname, "WWW-Authenticate:"))) { + if (!(arg1 && *arg1 && args && *args)) { + temp = (char *)calloc(1, strlen(line) + + (arg1 ? strlen(arg1) : 0) + + (args ? strlen(args) : 0) + 24); + if (!temp) + outofmem(__FILE__, "HTAA_shouldRetryWithAuth"); + sprintf(temp, "Invalid header '%s%s%s%s%s'", line, + ((arg1 && *arg1) ? " " : ""), + ((arg1 && *arg1) ? arg1 : ""), + ((args && *args) ? " " : ""), + ((args && *args) ? args : "")); + HTAlert(temp); + FREE(temp); + } + else if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) { + HTList_addObject(valid_schemes, (void*)scheme); + if (!scheme_specifics) { + int i; + scheme_specifics = (HTAssocList**) + calloc(1, HTAA_MAX_SCHEMES * sizeof(HTAssocList*)); + if (!scheme_specifics) + outofmem(__FILE__, "HTAA_shouldRetryWithAuth"); + for (i=0; i < HTAA_MAX_SCHEMES; i++) + scheme_specifics[i] = NULL; + } + scheme_specifics[scheme] = HTAA_parseArgList(args); + num_schemes++; + } + else if (TRACE) { + fprintf(stderr, "Unknown scheme `%s' %s\n", + (arg1 ? arg1 : "(null)"), + (IsProxy ? + "in Proxy-Authenticate: field" : + "in WWW-Authenticate: field")); + } + } + + else if (!IsProxy && + 0==strcasecomp(fieldname, "WWW-Protection-Template:")) { + if (TRACE) + fprintf(stderr, "Protection template set to `%s'\n", arg1); + StrAllocCopy(template, arg1); + } + + } /* if a valid header line */ + else if (TRACE) { + fprintf(stderr, "Invalid header line `%s' ignored\n", line); + } /* else invalid header line */ + + FREE(line); + } /* while header lines remain */ + FREE(line); + + + /* + ** So should we retry with authorization? + */ + if (IsProxy) { + if (num_schemes == 0) { + /* + ** No proxy authorization valid + */ + proxy_setup = NULL; + return NO; + } + /* + ** Doing it for proxy. -AJL + */ + if (proxy_setup && proxy_setup->server) { + /* + ** We have already tried with proxy authorization. + ** Either we don't have access or username or + ** password was misspelled. + ** + ** Update scheme-specific parameters + ** (in case they have expired by chance). + */ + HTAASetup_updateSpecifics(proxy_setup, scheme_specifics); + + if (NO == HTConfirm("Authorization failed. Retry?")) { + proxy_setup = NULL; + return NO; + } else { + /* + ** Re-ask username+password (if misspelled). + */ + proxy_setup->retry = YES; + return YES; + } + } else { + /* + ** proxy_setup == NULL, i.e. we have a + ** first connection to a protected server or + ** the server serves a wider set of documents + ** than we expected so far. + */ + HTAAServer *server = HTAAServer_lookup(proxy_hostname, + proxy_portnumber, + IsProxy); + if (!server) { + server = HTAAServer_new(proxy_hostname, + proxy_portnumber, + IsProxy); + } + if (!template) /* Proxy matches everything -AJL */ + StrAllocCopy(template, "*"); + proxy_setup = HTAASetup_new(server, + template, + valid_schemes, + scheme_specifics); + FREE(template); + + HTAlert("Proxy authorization required -- retrying"); + return YES; + } + /* Never reached */ + } + /* + ** Normal WWW authorization. + */ + if (num_schemes == 0) { + /* + ** No authorization valid. + */ + current_setup = NULL; + return NO; + } + if (current_setup && current_setup->server) { + /* + ** So we have already tried with WWW authorization. + ** Either we don't have access or username or + ** password was misspelled. + ** + ** Update scheme-specific parameters + ** (in case they have expired by chance). + */ + HTAASetup_updateSpecifics(current_setup, scheme_specifics); + + if (NO == HTConfirm("Authorization failed. Retry?")) { + current_setup = NULL; + return NO; + } else { + /* + ** Re-ask username+password (if misspelled). + */ + current_setup->retry = YES; + return YES; + } + } else { + /* + ** current_setup == NULL, i.e. we have a + ** first connection to a protected server or + ** the server serves a wider set of documents + ** than we expected so far. + */ + HTAAServer *server = HTAAServer_lookup(current_hostname, + current_portnumber, + IsProxy); + if (!server) { + server = HTAAServer_new(current_hostname, + current_portnumber, + IsProxy); + } + if (!template) + template = HTAA_makeProtectionTemplate(current_docname); + current_setup = HTAASetup_new(server, + template, + valid_schemes, + scheme_specifics); + FREE(template); + + HTAlert("Access without authorization denied -- retrying"); + return YES; + } + /* Never reached */ +} + +/* +** This function clears all authorization information by +** invoking the free_HTAAGlobals() function, which normally +** is invoked at exit. It allows a browser command to do +** this at any time, for example, if the user is leaving +** the terminal for a period of time, but does not want +** to end the current session. - FM +*/ +PUBLIC void HTClearHTTPAuthInfo NOARGS +{ + /* + ** Need code to check cached documents against the + ** protention templates, and do something to ensure + ** that any protected documents no longer can be + ** accessed without a new retrieval. - FM + */ + + /* + ** Now free all of the authorization info, and + ** reset the free_HTAAGlobalsSet flag. - FM + */ + free_HTAAGlobals(); + free_HTAAGlobalsSet = FALSE; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.h new file mode 100644 index 00000000000..80da3e6e330 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.h @@ -0,0 +1,150 @@ +/* BROWSER SIDE ACCESS AUTHORIZATION MODULE + + This module is the browser side interface to Access Authorization (AA) package. It + contains code only for browser. + + Important to know about memory allocation: + + Routines in this module use dynamic allocation, but free automatically all the memory + reserved by them. + + Therefore the caller never has to (and never should) free() any object returned by + these functions. + + Therefore also all the strings returned by this package are only valid until the next + call to the same function is made. This approach is selected, because of the nature of + access authorization: no string returned by the package needs to be valid longer than + until the next call. + + This also makes it easy to plug the AA package in: you don't have to ponder whether to + free()something here or is it done somewhere else (because it is always done somewhere + else). + + The strings that the package needs to store are copied so the original strings given as + parameters to AA functions may be freed or modified with no side effects. + + Also note:The AA package does not free() anything else than what it has itself + allocated. + + */ + +#ifndef HTAABROW_H +#define HTAABROW_H + +#ifndef HTUTILS_H +#include "HTUtils.h" /* BOOL, PARAMS, ARGS */ +#endif /* HTUTILS_H */ +#include "HTAAUtil.h" /* Common parts of AA */ + + +#ifdef SHORT_NAMES +#define HTAAcoAu HTAA_composeAuth +#define HTAAsRWA HTAA_shouldRetryWithAuth +#endif /*SHORT_NAMES*/ + +/* + +Routines for Browser Side Recording of AA Info + + Most of the browser-side AA is done by the following two functions (which are called + from file HTTP.c so the browsers using libwww only need to be linked with the new + library and not be changed at all): + + HTAA_composeAuth() composes the Authorization: line contents, if the AA package + thinks that the given document is protected. Otherwise this function returns NULL. + This function also calls the functions HTPrompt(),HTPromptPassword() and HTConfirm() + to get the username, password and some confirmation from the user. + + HTAA_shouldRetryWithAuth() determines whether to retry the request with AA or with a + new AA (in case username or password was misspelled). + + */ + +/* PUBLIC HTAA_composeAuth() +** +** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE IF WE +** ALREADY KNOW, THAT THE HOST MIGHT REQUIRE AUTHORIZATION +** +** ON ENTRY: +** hostname is the hostname of the server. +** portnumber is the portnumber in which the server runs. +** docname is the pathname of the document (as in URL) +** +** ON EXIT: +** returns NULL, if no authorization seems to be needed, or +** if it is the entire Authorization: line, e.g. +** +** "Authorization: basic username:password" +** +** As usual, this string is automatically freed. +*/ +extern char *HTAA_composeAuth PARAMS(( + CONST char * hostname, + CONST int portnumber, + CONST char * docname, + BOOL IsProxy)); + + +/* BROWSER PUBLIC HTAA_shouldRetryWithAuth() +** +** DETERMINES IF WE SHOULD RETRY THE SERVER +** WITH AUTHORIZATION +** (OR IF ALREADY RETRIED, WITH A DIFFERENT +** USERNAME AND/OR PASSWORD (IF MISSPELLED)) +** ON ENTRY: +** start_of_headers is the first block already read from socket, +** but status line skipped; i.e. points to the +** start of the header section. +** length is the remaining length of the first block. +** soc is the socket to read the rest of server reply. +** +** This function should only be called when +** server has replied with a 401 (Unauthorized) +** status code. +** ON EXIT: +** returns YES, if connection should be retried. +** The node containing all the necessary +** information is +** * either constructed if it does not exist +** * or password is reset to NULL to indicate +** that username and password should be +** reprompted when composing Authorization: +** field (in function HTAA_composeAuth()). +** NO, otherwise. +*/ +extern BOOL HTAA_shouldRetryWithAuth PARAMS(( + char * start_of_headers, + int length, + void * handle, + int soc, + BOOL IsProxy)); + +/* +** Function to allow clearing of all Authorization info +** via a browser command. - FM +*/ +extern void HTClearHTTPAuthInfo NOPARAMS; + +/* + +Enabling Gateway httpds to Forward Authorization + + These functions should only be called from daemon code, and HTAAForwardAuth_reset() + must be called before the next request is handled to make sure that authorization + string isn't cached in daemon so that other people can access private files using + somebody elses previous authorization information. + + */ + +extern void HTAAForwardAuth_set PARAMS(( + CONST char * scheme_name, + CONST char * scheme_specifics)); +extern void HTAAForwardAuth_reset NOPARAMS; +/* + + */ + +#endif /* NOT HTAABROW_H */ +/* + + End of file HTAABrow.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.c new file mode 100644 index 00000000000..a55b2f899c4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.c @@ -0,0 +1,210 @@ + +/* MODULE HTAAFile.c +** FILE ROUTINES FOR AUTHENTICATION +** (PASSWD AND GROUP FILES) AND +** ACCESS CONTROL LIST (.www_acl) +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** +** +** BUGS: +** +** +*/ + + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +#include "tcp.h" /* Macro FROMASCII() */ +/*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */ +#include <string.h> +#include "HTAAUtil.h" /* Common utilities used in AA */ +#include "HTAAFile.h" /* Implemented here */ + +#include "LYLeaks.h" + +#define SPACE ' ' +#define TAB '\t' + + + +/* PUBLIC HTAAFile_nextRec() +** GO TO THE BEGINNING OF THE NEXT RECORD +** ON ENTRY: +** fp is the file from which records are read from. +** +** ON EXIT: +** returns nothing. File read pointer is located at the beginning +** of the next record. Handles continuation lines +** (lines ending in comma indicate a following +** continuation line). +** +*/ +PUBLIC void HTAAFile_nextRec ARGS1(FILE *, fp) +{ + int ch = getc(fp); + int last = (char)0; + + do { + while (ch != EOF && ch != CR && ch != LF) { + if (ch != ' ' && ch != '\t') + last = ch; /* Last non-whitespace */ + ch = getc(fp); /* Skip until end-of-line */ + } + while (ch != EOF && + (ch == CR || ch == LF))/*Skip carriage returns and linefeeds*/ + ch = getc(fp); + if (ch != EOF) + ungetc(ch, fp); + } while (last == ',' && ch != EOF); /* Skip also continuation lines */ +} + + +/* PRIVATE read_item() +** READ AN ITEM FROM A PASSWORD, GROUP +** OR ACCESS CONTROL LIST FILE +** i.e. either a field, or a list item. +** ON ENTRY: +** fp is the file to read the characters from +** contents is the character array to put the characters +** reading_list if TRUE, read a list item (ends either in +** acomma or acolon), +** if FALSE, read a field (ends in acolon). +** max_len is the maximum number of characters that may +** be read (i.e. the size of dest minus one for +** terminating null). +** ON EXIT: +** returns the terminating character +** (i.e. either separator or CR or LF or EOF). +** contents contains a null-terminated string representing +** the read field. +** NOTE 1: +** Ignores leading and trailing blanks and tabs. +** NOTE 2: +** If the item is more than max_len characters +** long, the rest of the characters in that item +** are ignored. However, contents is always +** null-terminated! +*/ +PRIVATE int read_item ARGS4(FILE *, fp, + char *, contents, + BOOL, reading_list, + int, max_len) +{ + char * dest = contents; + char * end = contents; + int cnt = 0; + int ch = getc(fp); + + while (SPACE == ch || TAB == ch) /* Skip spaces and tabs */ + ch = getc(fp); + + while (ch != FIELD_SEPARATOR && + (!reading_list || ch != LIST_SEPARATOR) && + ch != CR && ch != LF && ch != EOF && cnt < max_len) { + *(dest++) = ch; + cnt++; + if (ch != SPACE && ch != TAB) + end = dest; + ch = getc(fp); + } /* while not eol or eof or too many read */ + + if (cnt == max_len) { + /* If the field was too long (or exactly maximum) ignore the rest */ + while (ch != FIELD_SEPARATOR && + (!reading_list || ch != LIST_SEPARATOR) && + ch != CR && ch != LF && ch != EOF) + ch = getc(fp); + } + + if (ch == CR || ch == LF) + ungetc(ch, fp); /* Push back the record separator (NL or LF) */ + + /* Terminate the string, truncating trailing whitespace off. + ** Otherwise (if whitespace would be included), here would + ** be *dest='\0'; and cnt -= ... would be left out. + */ + *end = '\0'; + cnt -= dest-end; + + return ch; /* Return the terminating character */ +} + + + +/* PUBLIC HTAAFile_readField() +** READ A FIELD FROM A PASSWORD, GROUP +** OR ACCESS CONTROL LIST FILE +** i.e. an item terminated by colon, +** end-of-line, or end-of-file. +** ON ENTRY: +** fp is the file to read the characters from +** contents is the character array to put the characters +** max_len is the maximum number of characters that may +** be read (i.e. the size of dest minus one for +** terminating null). +** ON EXIT: +** returns the terminating character +** (i.e. either separator or CR or LF or EOF). +** contents contains a null-terminated string representing +** the read field. +** NOTE 1: +** Ignores leading and trailing blanks and tabs. +** NOTE 2: +** If the field is more than max_len characters +** long, the rest of the characters in that item +** are ignored. However, contents is always +** null-terminated! +*/ +PUBLIC int HTAAFile_readField ARGS3(FILE *, fp, + char *, contents, + int, max_len) +{ + return read_item(fp, contents, NO, max_len); +} + + + + +/* PUBLIC HTAAFile_readList() +** +** READ A LIST OF STRINGS SEPARATED BY COMMAS +** (FROM A GROUP OR ACCESS CONTROL LIST FILE) +** ON ENTRY: +** fp is a pointer to the input file. +** result is the list to which append the read items. +** max_len is the maximum number of characters in each +** list entry (extra characters are ignored). +** ON EXIT: +** returns the number of items read. +** +*/ +PUBLIC int HTAAFile_readList ARGS3(FILE *, fp, + HTList *, result, + int, max_len) +{ + char *item = NULL; + int terminator; + int cnt = 0; + + do { + if (!item && !(item = (char*)malloc(max_len+1))) + outofmem(__FILE__, "HTAAFile_readList"); + terminator = read_item(fp, item, YES, max_len); + if (strlen(item) > 0) { + cnt++; + HTList_addObject(result, (void*)item); + item = NULL; + } + } while (terminator != FIELD_SEPARATOR && + terminator != CR && terminator != LF && + terminator != EOF); + + FREE(item); /* This was not needed */ + return cnt; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.h new file mode 100644 index 00000000000..f6f8ac5053e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.h @@ -0,0 +1,126 @@ +/* FILE ROUTINES FOR ACCESS AUTHORIZATION PACKAGE + + This module implements the routines used for accessing (and parsing) the files used in + the access authorization: + + password file + + group file + + access control list (ACL) file + + */ + + +#ifndef HTAAFILE_H +#define HTAAFILE_H + +#ifndef HTUTILS_H +#include "HTUtils.h" /* BOOL, PARAMS, ARGS */ +#endif /* HTUTILS_H */ +/*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */ +#include "HTList.h" /* HTList */ + +#ifdef SHORT_NAMES +#define HTAAFnRe HTAAFile_nextRec +#define HTAAFrFi HTAAFile_readField +#define HTAAFrLi HTAAFile_readList +#endif /*SHORT_NAMES*/ + + +/* Used field separators */ + +#define FIELD_SEPARATOR ':' /* Used to separate fields */ +#define LIST_SEPARATOR ',' /* Used to separate items in a list */ + /* in group and ALC files. */ + +/* + +Naming conventions + + Record is an entire line in file. + + Field is an entity separated by colons and/or by end-of-line. + + List is a field in which there are items separated by commas. + +Record-oriented Read Routines + + Password, group and ACL are internally read in by the following functions: + + HTAAFile_nextRec() skips to the beginning of the next record (must be called even + after the last field of a record is read to proceed to the next + record). + + HTAAFile_readField() reads a field (separated by colons). + + HTAAFile_readList() reads a field containing a comma-separated list of items. + + */ + +/* PUBLIC HTAAFile_nextRec() +** GO TO THE BEGINNING OF THE NEXT RECORD +** ON ENTRY: +** fp is the file from which records are read from. +** +** ON EXIT: +** returns nothing. File read pointer is located at the beginning +** of the next record. +** +*/ +PUBLIC void HTAAFile_nextRec PARAMS((FILE * fp)); + + +/* PUBLIC HTAAFile_readField() +** READ A FIELD FROM A PASSWORD, GROUP +** OR ACCESS CONTROL LIST FILE +** i.e. an item terminated by colon, +** end-of-line, or end-of-file. +** ON ENTRY: +** fp is the file to read the characters from +** contents is the character array to put the characters +** max_len is the maximum number of characters that may +** be read (i.e. the size of dest minus one for +** terminating null). +** ON EXIT: +** returns the terminating character +** (i.e. either separator or CR or LF or EOF). +** contents contains a null-terminated string representing +** the read field. +** NOTE 1: +** Ignores leading and trailing blanks and tabs. +** NOTE 2: +** If the field is more than max_len characters +** long, the rest of the characters in that item +** are ignored. However, contents is always +** null-terminated! +*/ +PUBLIC int HTAAFile_readField PARAMS((FILE * fp, + char * contents, + int max_len)); + + +/* PUBLIC HTAAFile_readList() +** +** READ A LIST OF STRINGS SEPARATED BY COMMAS +** (FROM A GROUP OR ACCESS CONTROL LIST FILE) +** ON ENTRY: +** fp is a pointer to the input file. +** result is the list to which append the read items. +** max_len is the maximum number of characters in each +** list entry (extra characters are ignored). +** ON EXIT: +** returns the number of items read. +** +*/ +PUBLIC int HTAAFile_readList PARAMS((FILE * fp, + HTList * result, + int max_len)); +/* + + */ + +#endif /* not HTAAFILE_H */ +/* + + End of file HTAAFile.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.c new file mode 100644 index 00000000000..9b40c3beee3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.c @@ -0,0 +1,598 @@ + +/* MODULE HTAAProt.c +** PROTECTION FILE PARSING MODULE +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 20 Oct 93 AL Now finds uid/gid for nobody/nogroup by name +** (doesn't use default 65534 right away). +** Also understands negative uids/gids. +** 14 Nov 93 MD Added VMS compatibility +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" + +#include <string.h> +#ifndef VMS +#ifndef NOUSERS +#include <pwd.h> /* Unix password file routine: getpwnam() */ +#include <grp.h> /* Unix group file routine: getgrnam() */ +#endif /* NOUSERS */ +#endif /* not VMS */ + +#include "HTAAUtil.h" +#include "HTAAFile.h" +#include "HTLex.h" /* Lexical analysor */ +#include "HTAssoc.h" /* Association list */ +#include "HTAAProt.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* +** Protection setup caching +*/ +typedef struct { + char * prot_filename; + HTAAProt * prot; +} HTAAProtCache; + +PRIVATE HTList * prot_cache = NULL; /* Protection setup cache. */ +PRIVATE HTAAProt *default_prot = NULL; /* Default protection. */ +PRIVATE HTAAProt *current_prot = NULL; /* Current protection mode */ + /* which is set up by callbacks */ + /* from the rule system when */ + /* a "protect" rule is matched. */ + + +/* PRIVATE isNumber() +** DOES A CHARACTER STRING REPRESENT A NUMBER +*/ +PRIVATE BOOL isNumber ARGS1(CONST char *, s) +{ + CONST char *cur = s; + + if (!s || !*s) return NO; + + if (*cur == '-') + cur++; /* Allow initial minus sign in a number */ + + while (*cur) { + if (*cur < '0' || *cur > '9') + return NO; + cur++; + } + return YES; +} + + +#if defined (VMS) || defined (NOUSERS) +/* PUBLIC HTAA_getUidName() +** GET THE USER ID NAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the user name +** Default is "" (nobody). +*/ +PUBLIC char * HTAA_getUidName NOARGS +{ + if (current_prot && current_prot->uid_name + && (0 != strcmp(current_prot->uid_name,"nobody")) ) + return(current_prot->uid_name); + else + return(""); +} + +/* PUBLIC HTAA_getFileName +** GET THE FILENAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the filename +*/ +PUBLIC char * HTAA_getFileName NOARGS +{ + if (current_prot && current_prot->filename) + return(current_prot->filename); + else + return(""); +} + +#else /* not VMS */ + +/* PUBLIC HTAA_getUid() +** GET THE USER ID TO CHANGE THE PROCESS UID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setuid() system call. +** Default is 65534 (nobody). +*/ +PUBLIC int HTAA_getUid NOARGS +{ + struct passwd *pw = NULL; + + if (current_prot && current_prot->uid_name) { + if (isNumber(current_prot->uid_name)) { + if (NULL != (pw = getpwuid(atoi(current_prot->uid_name)))) { + if (TRACE) fprintf(stderr, + "%s(%s) returned (%s:%s:%d:%d:...)\n", + "HTAA_getUid: getpwuid", + current_prot->uid_name, + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid); + return pw->pw_uid; + } + } + else { /* User name (not a number) */ + if (NULL != (pw = getpwnam(current_prot->uid_name))) { + if (TRACE) fprintf(stderr, "%s(\"%s\") %s (%s:%s:%d:%d:...)\n", + "HTAA_getUid: getpwnam", + current_prot->uid_name, "returned", + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid); + return pw->pw_uid; + } + } + } + /* + ** Ok, then let's get uid for nobody. + */ + if (NULL != (pw = getpwnam("nobody"))) { + if (TRACE) fprintf(stderr, "HTAA_getUid: Uid for `nobody' is %d\n", + pw->pw_uid); + return pw->pw_uid; + } + /* + ** Ok, then use default. + */ + return 65534; /* nobody */ +} + + +/* PUBLIC HTAA_getGid() +** GET THE GROUP ID TO CHANGE THE PROCESS GID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setgid() system call. +** Default is 65534 (nogroup). +*/ +PUBLIC int HTAA_getGid NOARGS +{ + struct group *gr = NULL; + + if (current_prot && current_prot->gid_name) { + if (isNumber(current_prot->gid_name)) { + if (NULL != (gr = getgrgid(atoi(current_prot->gid_name)))) { +#ifndef __EMX__ /* no gr_passwd */ + if (TRACE) fprintf(stderr, + "%s(%s) returned (%s:%s:%d:...)\n", + "HTAA_getGid: getgrgid", + current_prot->gid_name, + gr->gr_name, gr->gr_passwd, gr->gr_gid); +#endif + return gr->gr_gid; + } + } + else { /* Group name (not number) */ + if (NULL != (gr = getgrnam(current_prot->gid_name))) { +#ifndef __EMX__ /* no gr_passwd */ + if (TRACE) fprintf(stderr, + "%s(\"%s\") returned (%s:%s:%d:...)\n", + "HTAA_getGid: getgrnam", + current_prot->gid_name, + gr->gr_name, gr->gr_passwd, gr->gr_gid); +#endif + return gr->gr_gid; + } + } + } + /* + ** Ok, then let's get gid for nogroup. + */ + if (NULL != (gr = getgrnam("nogroup"))) { + if (TRACE) fprintf(stderr, "HTAA_getGid: Gid for `nogroup' is %d\n", + gr->gr_gid); + return gr->gr_gid; + } + /* + ** Ok, then use default. + */ + return 65534; /* nogroup */ +} +#endif /* not VMS */ + + +/* PRIVATE HTAA_setIds() +** SET UID AND GID (AS NAMES OR NUMBERS) +** TO HTAAProt STRUCTURE +** ON ENTRY: +** prot destination. +** ids is a string like "james.www" or "1422.69" etc. +** giving uid and gid. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAA_setIds ARGS2(HTAAProt *, prot, + CONST char *, ids) +{ + if (ids) { + char *local_copy = NULL; + char *point; + + StrAllocCopy(local_copy, ids); + point = strchr(local_copy, '.'); + if (point) { + *(point++) = (char)0; + StrAllocCopy(prot->gid_name, point); + } + else { + StrAllocCopy(prot->gid_name, "nogroup"); + } + StrAllocCopy(prot->uid_name, local_copy); + FREE(local_copy); + } + else { + StrAllocCopy(prot->uid_name, "nobody"); + StrAllocCopy(prot->gid_name, "nogroup"); + } +} + + +/* PRIVATE HTAA_parseProtFile() +** PARSE A PROTECTION SETUP FILE AND +** PUT THE RESULT IN A HTAAProt STRUCTURE +** ON ENTRY: +** prot destination structure. +** fp open protection file. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAA_parseProtFile ARGS2(HTAAProt *, prot, + FILE *, fp) +{ + if (prot && fp) { + LexItem lex_item; + char *fieldname = NULL; + + while (LEX_EOF != (lex_item = lex(fp))) { + + while (lex_item == LEX_REC_SEP) /* Ignore empty lines */ + lex_item = lex(fp); + + if (lex_item == LEX_EOF) /* End of file */ + break; + + if (lex_item == LEX_ALPH_STR) { /* Valid setup record */ + + StrAllocCopy(fieldname, HTlex_buffer); + + if (LEX_FIELD_SEP != (lex_item = lex(fp))) + unlex(lex_item); /* If someone wants to use colon */ + /* after field name it's ok, but */ + /* not required. Here we read it.*/ + + if (0==strncasecomp(fieldname, "Auth", 4)) { + lex_item = lex(fp); + while (lex_item == LEX_ALPH_STR) { + HTAAScheme scheme = HTAAScheme_enum(HTlex_buffer); + if (scheme != HTAA_UNKNOWN) { + if (!prot->valid_schemes) + prot->valid_schemes = HTList_new(); + HTList_addObject(prot->valid_schemes,(void*)scheme); + if (TRACE) fprintf(stderr, "%s %s `%s'\n", + "HTAA_parseProtFile: valid", + "authentication scheme:", + HTAAScheme_name(scheme)); + } + else if (TRACE) fprintf(stderr, "%s %s `%s'\n", + "HTAA_parseProtFile: unknown", + "authentication scheme:", + HTlex_buffer); + + if (LEX_ITEM_SEP != (lex_item = lex(fp))) + break; + /* + ** Here lex_item == LEX_ITEM_SEP; after item separator + ** it is ok to have one or more newlines (LEX_REC_SEP) + ** and they are ignored (continuation line). + */ + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); + } /* while items in list */ + } /* if "Authenticate" */ + + else if (0==strncasecomp(fieldname, "mask", 4)) { + prot->mask_group = HTAA_parseGroupDef(fp); + lex_item=LEX_REC_SEP; /*groupdef parser read this already*/ + if (TRACE) { + if (prot->mask_group) { + fprintf(stderr, + "HTAA_parseProtFile: Mask group:\n"); + HTAA_printGroupDef(prot->mask_group); + } else fprintf(stderr, "HTAA_parseProtFile: %s\n", + "Mask group syntax error"); + } + } /* if "Mask" */ + + else { /* Just a name-value pair, put it to assoclist */ + + if (LEX_ALPH_STR == (lex_item = lex(fp))) { + if (!prot->values) + prot->values = HTAssocList_new(); + HTAssocList_add(prot->values, fieldname, HTlex_buffer); + lex_item = lex(fp); /* Read record separator */ + if (TRACE) fprintf(stderr, + "%s `%s' bound to value `%s'\n", + "HTAA_parseProtFile: Name", + fieldname, HTlex_buffer); + } + } /* else name-value pair */ + + } /* if valid field */ + + if (lex_item != LEX_EOF && lex_item != LEX_REC_SEP) { + if (TRACE) fprintf(stderr, "%s %s %d (that line ignored)\n", + "HTAA_parseProtFile: Syntax error", + "in protection setup file at line", + HTlex_line); + do { + lex_item = lex(fp); + } while (lex_item != LEX_EOF && lex_item != LEX_REC_SEP); + } /* if syntax error */ + } /* while not end-of-file */ + FREE(fieldname); + } /* if valid parameters */ +} + + +/* PRIVATE HTAAProt_new() +** ALLOCATE A NEW HTAAProt STRUCTURE AND +** INITIALIZE IT FROM PROTECTION SETUP FILE +** ON ENTRY: +** cur_docname current filename after rule translations. +** prot_filename protection setup file name. +** If NULL, not an error. +** ids Uid and gid names or numbers, +** examples: +** james ( <=> james.nogroup) +** .www ( <=> nobody.www) +** james.www +** james.69 +** 1422.69 +** 1422.www +** +** May be NULL, defaults to nobody.nogroup. +** Should be NULL, if prot_file is NULL. +** +** ON EXIT: +** returns returns a new and initialized protection +** setup structure. +** If setup file is already read in (found +** in cache), only sets uid_name and gid +** fields, and returns that. +*/ +PRIVATE HTAAProt *HTAAProt_new ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + HTList *cur = prot_cache; + HTAAProtCache *cache_item = NULL; + HTAAProt *prot; + FILE *fp; + + if (!prot_cache) + prot_cache = HTList_new(); + + while (NULL != (cache_item = (HTAAProtCache*)HTList_nextObject(cur))) { + if (!strcmp(cache_item->prot_filename, prot_filename)) + break; + } + if (cache_item) { + prot = cache_item->prot; + if (TRACE) fprintf(stderr, "%s `%s' already in cache\n", + "HTAAProt_new: Protection file", prot_filename); + } else { + if (TRACE) fprintf(stderr, + "HTAAProt_new: Loading protection file `%s'\n", + prot_filename); + + if (!(prot = (HTAAProt*)calloc(1, sizeof(HTAAProt)))) + outofmem(__FILE__, "HTAAProt_new"); + + prot->template = NULL; + prot->filename = NULL; + prot->uid_name = NULL; + prot->gid_name = NULL; + prot->valid_schemes = HTList_new(); + prot->mask_group= NULL; /* Masking disabled by defaults */ + prot->values = HTAssocList_new(); + + if (prot_filename && NULL != (fp = fopen(prot_filename, "r"))) { + HTAA_parseProtFile(prot, fp); + fclose(fp); + if (!(cache_item = + (HTAAProtCache*)calloc(1, sizeof(HTAAProtCache)))) + outofmem(__FILE__, "HTAAProt_new"); + cache_item->prot = prot; + cache_item->prot_filename = NULL; + StrAllocCopy(cache_item->prot_filename, prot_filename); + HTList_addObject(prot_cache, (void*)cache_item); + } + else if (TRACE) fprintf(stderr, "HTAAProt_new: %s `%s'\n", + "Unable to open protection setup file", + (prot_filename ? prot_filename : "(null)")); + } + + if (cur_docname) + StrAllocCopy(prot->filename, cur_docname); + HTAA_setIds(prot, ids); + + return prot; +} + + +/* PUBLIC HTAA_setDefaultProtection() +** SET THE DEFAULT PROTECTION MODE +** (called by rule system when a +** "defprot" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "defprot" rule, optional) +** ids contains user and group names separated by +** a dot, corresponding to the uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "defprot" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable default_prot. +*/ +PUBLIC void HTAA_setDefaultProtection ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + default_prot = NULL; /* Not free()'d because this is in cache */ + + if (prot_filename) { + default_prot = HTAAProt_new(cur_docname, prot_filename, ids); + } else { + if (TRACE) fprintf(stderr, "%s %s\n", + "HTAA_setDefaultProtection: ERROR: Protection file", + "not specified (obligatory for DefProt rule)!!\n"); + } +} + + +/* PUBLIC HTAA_setCurrentProtection() +** SET THE CURRENT PROTECTION MODE +** (called by rule system when a +** "protect" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "protect" rule, optional) +** ids contains user and group names separated by +** a dot, corresponding to the uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "protect" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable current_prot. +*/ +PUBLIC void HTAA_setCurrentProtection ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + current_prot = NULL; /* Not free()'d because this is in cache */ + + if (prot_filename) { + current_prot = HTAAProt_new(cur_docname, prot_filename, ids); + } else { + if (default_prot) { + current_prot = default_prot; + HTAA_setIds(current_prot, ids); + if (TRACE) fprintf(stderr, "%s %s %s\n", + "HTAA_setCurrentProtection: Protection file", + "not specified for Protect rule", + "-- using default protection"); + } else { + if (TRACE) fprintf(stderr, "%s %s %s\n", + "HTAA_setCurrentProtection: ERROR: Protection", + "file not specified for Protect rule, and", + "default protection is not set!!"); + } + } +} + + +/* PUBLIC HTAA_getCurrentProtection() +** GET CURRENT PROTECTION SETUP STRUCTURE +** (this is set up by callbacks made from +** the rule system when matching "protect" +** (and "defprot") rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** protection setup of the HTTranslate()'d file. +** This must not be free()'d. +*/ +PUBLIC HTAAProt *HTAA_getCurrentProtection NOARGS +{ + return current_prot; +} + + +/* PUBLIC HTAA_getDefaultProtection() +** GET DEFAULT PROTECTION SETUP STRUCTURE +** AND SET IT TO CURRENT PROTECTION +** (this is set up by callbacks made from +** the rule system when matching "defprot" +** rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** default protection setup of the HTTranslate()'d +** file (if HTAA_getCurrentProtection() returned +** NULL, i.e. if there is no "protect" rule +** but ACL exists, and we need to know default +** protection settings). +** This must not be free()'d. +** IMPORTANT: +** As a side-effect this tells the protection system that +** the file is in fact protected and sets the current +** protection mode to default. +*/ +PUBLIC HTAAProt *HTAA_getDefaultProtection NOARGS +{ + if (!current_prot) { + current_prot = default_prot; + default_prot = NULL; + } + return current_prot; +} + + +/* SERVER INTERNAL HTAA_clearProtections() +** CLEAR DOCUMENT PROTECTION MODE +** (ALSO DEFAULT PROTECTION) +** (called by the rule system) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns nothing. +** Frees the memory used by protection information. +*/ +PUBLIC void HTAA_clearProtections NOARGS +{ + current_prot = NULL; /* These are not freed because */ + default_prot = NULL; /* they are actually in cache. */ +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.h new file mode 100644 index 00000000000..73bb7c454d3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.h @@ -0,0 +1,231 @@ +/* PROTECTION SETUP FILE + + */ + +#ifndef HTAAPROT_H +#define HTAAPROT_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTGroup.h" +#include "HTAssoc.h" + +#ifdef SHORT_NAMES +#define HTAAgUid HTAA_getUid +#define HTAAgGid HTAA_getGid +#define HTAAgDPr HTAA_setDefaultProtection +#define HTAAsCPr HTAA_setCurrentProtection +#define HTAAgCPr HTAA_getCurrentProtection +#define HTAAgDPr HTAA_getDefaultProtection +#define HTAAclPr HTAA_clearProtections +#endif /*SHORT_NAMES*/ +/* + +Server's Representation of Document (Tree) Protections + + */ + +typedef struct { + char * template; /* Template for this protection */ + char * filename; /* Current document file */ + char * uid_name; /* Effective uid (name of it) */ + char * gid_name; /* Effective gid (name of it) */ + GroupDef * mask_group; /* Allowed users and IP addresses */ + HTList * valid_schemes;/* Valid authentication schemes */ + HTAssocList * values; /* Association list for scheme specific */ + /* parameters. */ +} HTAAProt; +/* + +Callbacks for rule system + + The following three functioncs are called by the rule system: + + HTAA_clearProtections() when starting to translate a filename + + HTAA_setDefaultProtection() when "defprot" rule is matched + + HTAA_setCurrentProtection() when "protect" rule is matched + + Protection setup files are cached by these functions. + + */ + +/* PUBLIC HTAA_setDefaultProtection() +** SET THE DEFAULT PROTECTION MODE +** (called by rule system when a +** "defprot" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "defprot" rule, optional) +** eff_ids contains user and group names separated by +** a dot, corresponding to the effective uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "defprot" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable default_prot. +*/ +PUBLIC void HTAA_setDefaultProtection PARAMS((CONST char * cur_docname, + CONST char * prot_filename, + CONST char * eff_ids)); + + + +/* PUBLIC HTAA_setCurrentProtection() +** SET THE CURRENT PROTECTION MODE +** (called by rule system when a +** "protect" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "protect" rule, optional) +** eff_ids contains user and group names separated by +** a dot, corresponding to the effective uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "protect" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable current_prot. +*/ +PUBLIC void HTAA_setCurrentProtection PARAMS((CONST char * cur_docname, + CONST char * prot_filename, + CONST char * eff_ids)); + + +/* SERVER INTERNAL HTAA_clearProtections() +** CLEAR DOCUMENT PROTECTION MODE +** (ALSO DEFAULT PROTECTION) +** (called by the rule system) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns nothing. +** Frees the memory used by protection information. +*/ +PUBLIC void HTAA_clearProtections NOPARAMS; +/* + +Getting Protection Settings + + HTAA_getCurrentProtection() returns the current protection mode (if there was a + "protect" rule). NULL, if no "protect" rule has been matched. + + HTAA_getDefaultProtection() sets the current protection mode to what it was set to + by "defprot" rule and also returns it (therefore after this call also + HTAA_getCurrentProtection() returns the same structure. + + */ + +/* PUBLIC HTAA_getCurrentProtection() +** GET CURRENT PROTECTION SETUP STRUCTURE +** (this is set up by callbacks made from +** the rule system when matching "protect" +** (and "defprot") rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** protection setup of the HTTranslate()'d file. +** This must not be free()'d. +*/ +PUBLIC HTAAProt *HTAA_getCurrentProtection NOPARAMS; + + + +/* PUBLIC HTAA_getDefaultProtection() +** GET DEFAULT PROTECTION SETUP STRUCTURE +** (this is set up by callbacks made from +** the rule system when matching "defprot" +** rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** default protection setup of the HTTranslate()'d +** file (if HTAA_getCurrentProtection() returned +** NULL, i.e. if there is no "protect" rule +** but ACL exists, and we need to know default +** protection settings). +** This must not be free()'d. +*/ +PUBLIC HTAAProt *HTAA_getDefaultProtection NOPARAMS; +/* + +Get User and Group IDs to Which Set to + + */ + +#ifndef VMS +/* PUBLIC HTAA_getUid() +** GET THE USER ID TO CHANGE THE PROCESS UID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setuid() system call. +** Default is 65534 (nobody). +*/ +PUBLIC int HTAA_getUid NOPARAMS; + + +/* PUBLIC HTAA_getGid() +** GET THE GROUP ID TO CHANGE THE PROCESS GID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setgid() system call. +** Default is 65534 (nogroup). +*/ +PUBLIC int HTAA_getGid NOPARAMS; +#endif /* not VMS */ +/* + + For VMS: + + */ + +#ifdef VMS +/* PUBLIC HTAA_getUidName() +** GET THE USER ID NAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the user name +** Default is "" (nobody). +*/ +PUBLIC char * HTAA_getUidName NOPARAMS; + +/* PUBLIC HTAA_getFileName +** GET THE FILENAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the filename +*/ +PUBLIC char * HTAA_getFileName NOPARAMS; +#endif /* VMS */ +/* + + */ + +#endif /* not HTAAPROT_H */ +/* + + End of file HTAAProt.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.c new file mode 100644 index 00000000000..cb8623d7fd7 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.c @@ -0,0 +1,686 @@ + +/* MODULE HTAAServ.c +** SERVER SIDE ACCESS AUTHORIZATION MODULE +** +** Contains the means for checking the user access +** authorization for a file. +** +** IMPORTANT: +** Routines in this module use dynamic allocation, but free +** automatically all the memory reserved by them. +** +** Therefore the caller never has to (and never should) +** free() any object returned by these functions. +** +** Therefore also all the strings returned by this package +** are only valid until the next call to the same function +** is made. This approach is selected, because of the nature +** of access authorization: no string returned by the package +** needs to be valid longer than until the next call. +** +** This also makes it easy to plug the AA package in: +** you don't have to ponder whether to free() something +** here or is it done somewhere else (because it is always +** done somewhere else). +** +** The strings that the package needs to store are copied +** so the original strings given as parameters to AA +** functions may be freed or modified with no side effects. +** +** The AA package does not free() anything else than what +** it has itself allocated. +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" + +/*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */ +#include <string.h> /* strchr() */ + +#include "HTString.h" +#include "HTAccess.h" /* HTSecure */ +#include "HTFile.h" /* HTLocalName */ +#include "HTRules.h" /* */ +#include "HTParse.h" /* URL parsing function */ +#include "HTList.h" /* HTList object */ + +#include "HTAAUtil.h" /* AA common parts */ +#include "HTAuth.h" /* Authentication */ +#include "HTACL.h" /* Access Control List */ +#include "HTGroup.h" /* Group handling */ +#include "HTAAProt.h" /* Protection file parsing */ +#include "HTAAServ.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* +** Global variables +*/ +PUBLIC time_t theTime; + + +/* +** Module-wide global variables +*/ +PRIVATE FILE * htaa_logfile = NULL; /* Log file */ +PRIVATE HTAAUser *htaa_user = NULL; /* Authenticated user */ +PRIVATE HTAAFailReasonType HTAAFailReason = HTAA_OK; /* AA fail reason */ + + +/* SERVER PUBLIC HTAA_statusMessage() +** RETURN A STRING EXPLAINING ACCESS +** AUTHORIZATION FAILURE +** (Can be used in server reply status line +** with 401/403 replies.) +** ON EXIT: +** returns a string containing the error message +** corresponding to internal HTAAFailReason. +*/ +PUBLIC char *HTAA_statusMessage NOARGS +{ + switch (HTAAFailReason) { + + /* 401 cases */ + case HTAA_NO_AUTH: + return "Unauthorized -- authentication failed"; + break; + case HTAA_NOT_MEMBER: + return "Unauthorized to access the document"; + break; + + /* 403 cases */ + case HTAA_BY_RULE: + return "Forbidden -- by rule"; + break; + case HTAA_IP_MASK: + return "Forbidden -- server refuses to serve to your IP address"; + break; + case HTAA_NO_ACL: + case HTAA_NO_ENTRY: + return "Forbidden -- access to file is never allowed"; + break; + case HTAA_SETUP_ERROR: + return "Forbidden -- server protection setup error"; + break; + case HTAA_DOTDOT: + return "Forbidden -- URL containing /../ disallowed"; + break; + case HTAA_HTBIN: + return "Forbidden -- /htbin feature not enabled on this server"; + break; + + /* 404 cases */ + case HTAA_NOT_FOUND: + return "Not found -- file doesn't exist or is read protected"; + break; + + /* Success */ + case HTAA_OK: + return "AA: Access should be ok but something went wrong"; + break; + + case HTAA_OK_GATEWAY: + return "AA check bypassed (gatewaying) but something went wrong"; + break; + + /* Others */ + default: + return "Access denied -- unable to specify reason (bug)"; + + } /* switch */ +} + + +PRIVATE char *status_name ARGS1(HTAAFailReasonType, reason) +{ + switch (reason) { + + /* 401 cases */ + case HTAA_NO_AUTH: + return "NO-AUTHENTICATION"; + break; + case HTAA_NOT_MEMBER: + return "NOT-AUTHORIZED"; + break; + + /* 403 cases */ + case HTAA_BY_RULE: + return "FORB-RULE"; + break; + case HTAA_IP_MASK: + return "FORB-IP"; + break; + case HTAA_NO_ACL: + return "NO-ACL-FILE"; + break; + case HTAA_NO_ENTRY: + return "NO-ACL-ENTRY"; + break; + case HTAA_SETUP_ERROR: + return "SETUP-ERROR"; + break; + case HTAA_DOTDOT: + return "SLASH-DOT-DOT"; + break; + case HTAA_HTBIN: + return "HTBIN-OFF"; + break; + + /* 404 cases */ + case HTAA_NOT_FOUND: + return "NOT-FOUND"; + break; + + /* Success */ + case HTAA_OK: + return "OK"; + break; + case HTAA_OK_GATEWAY: + return "OK-GATEWAY"; + break; + + /* Others */ + default: + return "SERVER-BUG"; + } /* switch */ +} + + +/* PRIVATE check_uthorization() +** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE +** ON ENTRY: +** pathname is the physical file pathname +** to access. +** method method, e.g. METHOD_GET, METHOD_PUT, ... +** scheme authentication scheme. +** scheme_specifics authentication string (or other +** scheme specific parameters, like +** Kerberos-ticket). +** +** ON EXIT: +** returns HTAA_OK on success. +** Otherwise the reason for failing. +** NOTE: +** This function does not check whether the file +** exists or not -- so the status 404 Not found +** must be returned from somewhere else (this is +** to avoid unnecessary overhead of opening the +** file twice). +*/ +PRIVATE HTAAFailReasonType check_authorization ARGS4(CONST char *, pathname, + HTAAMethod, method, + HTAAScheme, scheme, + char *, scheme_specifics) +{ + HTAAFailReasonType reason; + GroupDef *allowed_groups; + FILE *acl_file = NULL; + HTAAProt *prot = NULL; /* Protection mode */ + + htaa_user = NULL; + + if (!pathname) { + if (TRACE) + fprintf(stderr, "HTAA_checkAuthorization: Forbidden by rule\n"); + return HTAA_BY_RULE; + } + if (TRACE) + fprintf(stderr, "%s `%s' %s %s\n", + "HTAA_checkAuthorization: translated path:", + pathname, "method:", HTAAMethod_name(method)); + + /* + ** Get protection setting (set up by callbacks from rule system) + ** NULL, if not protected by a "protect" rule. + */ + prot = HTAA_getCurrentProtection(); + + /* + ** Check ACL existence + */ + if (!(acl_file = HTAA_openAcl(pathname))) { + if (prot) { /* protect rule, but no ACL */ + if (prot->mask_group) { + /* + ** Only mask enabled, check that + */ + GroupDefList *group_def_list = + HTAA_readGroupFile(HTAssocList_lookup(prot->values, + "group")); + /* + ** Authenticate if authentication info given + */ + if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) { + htaa_user = HTAA_authenticate(scheme, + scheme_specifics, + prot); + if (TRACE) + fprintf(stderr, "Authentication returned: %s\n", + (htaa_user ? htaa_user->username + : "NOT-AUTHENTICATED")); + } + HTAA_resolveGroupReferences(prot->mask_group, group_def_list); + reason = HTAA_userAndInetInGroup(prot->mask_group, + htaa_user + ? htaa_user->username : "", + HTClientHost, + NULL); + if (TRACE) { + if (reason != HTAA_OK) + fprintf(stderr, "%s %s %s %s\n", + "HTAA_checkAuthorization: access denied", + "by mask (no ACL, only Protect rule)", + "host", HTClientHost); + else + fprintf(stderr, "%s %s %s %s\n", + "HTAA_checkAuthorization: request from", + HTClientHost, + "accepted by only mask match (no ACL, only", + "Protect rule, and only mask enabled)"); + } + return reason; + } + else { /* 403 Forbidden */ + if (TRACE) + fprintf(stderr, "%s %s\n", + "HTAA_checkAuthorization: Protected, but", + "no mask group nor ACL -- forbidden"); + return HTAA_NO_ACL; + } + } + else { /* No protect rule and no ACL => OK 200 */ + if (TRACE) + fprintf(stderr, "HTAA_checkAuthorization: %s\n", + "no protect rule nor ACL -- ok\n"); + return HTAA_OK; + } + } + + /* + ** Now we know that ACL exists + */ + if (!prot) { /* Not protected by "protect" rule */ + if (TRACE) + fprintf(stderr, "HTAA_checkAuthorization: default protection\n"); + prot = HTAA_getDefaultProtection(); /* Also sets current protection */ + + if (!prot) { /* @@ Default protection not set ?? */ + if (TRACE) + fprintf(stderr, "%s %s\n", + "HTAA_checkAuthorization: default protection", + "not set (internal server error)!!"); + return HTAA_SETUP_ERROR; + } + } + + /* + ** Now we know that document is protected and ACL exists. + ** Check against ACL entry. + */ + { + GroupDefList *group_def_list = + HTAA_readGroupFile(HTAssocList_lookup(prot->values, "group")); + + /* + ** Authenticate now that we know protection mode + */ + if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) { + htaa_user = HTAA_authenticate(scheme, + scheme_specifics, + prot); + if (TRACE) + fprintf(stderr, "Authentication returned: %s\n", + (htaa_user + ? htaa_user->username : "NOT-AUTHENTICATED")); + } + /* + ** Check mask group + */ + if (prot->mask_group) { + HTAA_resolveGroupReferences(prot->mask_group, group_def_list); + reason=HTAA_userAndInetInGroup(prot->mask_group, + htaa_user ? htaa_user->username : "", + HTClientHost, + NULL); + if (reason != HTAA_OK) { + if (TRACE) + fprintf(stderr, "%s %s %s\n", + "HTAA_checkAuthorization: access denied", + "by mask, host:", HTClientHost); + return reason; + } + else { + if (TRACE) + fprintf(stderr, "%s %s %s %s %s\n", + "HTAA_checkAuthorization: request from", + HTClientHost, + "accepted by just mask group match", + "(no ACL, only Protect rule, and only", + "mask enabled)"); + /* And continue authorization checking */ + } + } + /* + ** Get ACL entries; get first one first, the loop others + ** Remember, allowed_groups is automatically freed by + ** HTAA_getAclEntry(). + */ + allowed_groups = HTAA_getAclEntry(acl_file, pathname, method); + if (!allowed_groups) { + if (TRACE) + fprintf(stderr, "%s `%s' %s\n", + "No entry for file", pathname, "in ACL"); + HTAA_closeAcl(acl_file); + return HTAA_NO_ENTRY; /* Forbidden -- no entry in the ACL */ + } + else { + do { + HTAA_resolveGroupReferences(allowed_groups, group_def_list); + reason = HTAA_userAndInetInGroup(allowed_groups, + htaa_user + ? htaa_user->username : "", + HTClientHost, + NULL); + if (reason == HTAA_OK) { + HTAA_closeAcl(acl_file); + return HTAA_OK; /* OK */ + } + allowed_groups = HTAA_getAclEntry(acl_file, pathname, method); + } while (allowed_groups); + HTAA_closeAcl(acl_file); + return HTAA_NOT_MEMBER; /* Unauthorized */ + } + } +} + + +/* PUBLIC HTAA_checkAuthorization() +** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE +** ON ENTRY: +** url is the document to be accessed. +** method_name name of the method, e.g. "GET" +** scheme_name authentication scheme name. +** scheme_specifics authentication string (or other +** scheme specific parameters, like +** Kerberos-ticket). +** +** ON EXIT: +** returns status codes uniform with those of HTTP: +** 200 OK if file access is ok. +** 401 Unauthorized if user is not authorized to +** access the file. +** 403 Forbidden if there is no entry for the +** requested file in the ACL. +** +** NOTE: +** This function does not check whether the file +** exists or not -- so the status 404 Not found +** must be returned from somewhere else (this is +** to avoid unnecessary overhead of opening the +** file twice). +** +*/ +PUBLIC int HTAA_checkAuthorization ARGS4(CONST char *, url, + CONST char *, method_name, + CONST char *, scheme_name, + char *, scheme_specifics) +{ + static char *pathname = NULL; + char *local_copy = NULL; + HTAAMethod method = HTAAMethod_enum(method_name); + HTAAScheme scheme = HTAAScheme_enum(scheme_name); + + HTAAFailReason = HTAA_OK; + + /* + ** Translate into absolute pathname, and + ** check for "protect" and "defprot" rules. + */ + FREE(pathname); /* From previous call */ + StrAllocCopy(local_copy, url); + { + char *keywords = strchr(local_copy, '?'); + if (keywords) + *keywords = '\0'; /* Chop off keywords */ + } + HTSimplify(local_copy); /* Remove ".." etc. */ + + /* HTSimplify will leave in a "/../" at the top, which can + ** be a security hole. + */ + if (strstr(local_copy, "/../")) { + if (TRACE) + fprintf(stderr, "HTAA_checkAuthorization: %s (`%s')\n", + "Illegal attempt to use /../", url); + HTAAFailReason = HTAA_DOTDOT; + } + else { + pathname = HTTranslate(local_copy); /* Translate rules even if */ + /* a /htbin call to set up */ + /* protections. */ + if (0 == strncmp(local_copy, "/htbin/", 7)) { + if (!HTBinDir) + HTAAFailReason = HTAA_HTBIN; + else { + char *end = strchr(local_copy+7, '/'); + if (end) + *end = '\0'; + FREE(pathname); + pathname=(char*)malloc(strlen(HTBinDir)+strlen(local_copy)+1); + strcpy(pathname, HTBinDir); + strcat(pathname, local_copy+6); + } + } + + if (!pathname) { /* Forbidden by rule */ + if (TRACE) + fprintf(stderr, "HTAA_checkAuthorization: Forbidden by rule\n"); + HTAAFailReason = HTAA_BY_RULE; + } + else if (HTAAFailReason != HTAA_HTBIN) { + /* pathname != NULL */ + char *acc_method = HTParse(pathname, "", PARSE_ACCESS); + if (!*acc_method || 0 == strcmp(acc_method,"file")) { /*Local file, do AA*/ + if (!HTSecure && 0 != strncmp(local_copy, "/htbin/", 7)) { + char *localname = HTLocalName(pathname); + FREE(pathname); + pathname = localname; + } + HTAAFailReason = check_authorization(pathname, method, + scheme, scheme_specifics); + } + else { /* Not local access */ + HTAAFailReason = HTAA_OK_GATEWAY; + if (TRACE) + fprintf(stderr, + "HTAA_checkAuthorization: %s (%s access)\n", + "Gatewaying -- skipping authorization check", + acc_method); + } + } /* pathname */ + } + FREE(local_copy); + + if (htaa_logfile) { + time(&theTime); + fprintf(htaa_logfile, "%24.24s %s %s %s %s %s\n", + ctime(&theTime), + HTClientHost ? HTClientHost : "local", + method_name, + url, + status_name(HTAAFailReason), + htaa_user && htaa_user->username + ? htaa_user->username : ""); + fflush(htaa_logfile); /* Actually update it on disk */ + if (TRACE) + fprintf(stderr, "Log: %24.24s %s %s %s %s %s\n", + ctime(&theTime), + HTClientHost ? HTClientHost : "local", + method_name, + url, + status_name(HTAAFailReason), + htaa_user && htaa_user->username + ? htaa_user->username : ""); + } + + switch (HTAAFailReason) { + + case HTAA_NO_AUTH: + case HTAA_NOT_MEMBER: + return 401; + break; + + case HTAA_BY_RULE: + case HTAA_IP_MASK: + case HTAA_NO_ACL: + case HTAA_NO_ENTRY: + case HTAA_SETUP_ERROR: + case HTAA_DOTDOT: + case HTAA_HTBIN: + return 403; + break; + + case HTAA_NOT_FOUND: + return 404; + break; + + case HTAA_OK: + case HTAA_OK_GATEWAY: + return 200; + break; + + default: + return 500; + } /* switch */ +} + + +/* PRIVATE compose_scheme_specifics() +** COMPOSE SCHEME-SPECIFIC PARAMETERS +** TO BE SENT ALONG WITH SERVER REPLY +** IN THE WWW-Authenticate: FIELD. +** ON ENTRY: +** scheme is the authentication scheme for which +** parameters are asked for. +** prot protection setup structure. +** +** ON EXIT: +** returns scheme specific parameters in an +** auto-freed string. +*/ +PRIVATE char *compose_scheme_specifics ARGS2(HTAAScheme, scheme, + HTAAProt *, prot) +{ + static char *result = NULL; + + FREE(result); /* From previous call */ + + switch (scheme) { + case HTAA_BASIC: + { + char *realm = HTAssocList_lookup(prot->values, "server"); + result = (char*)malloc(60); + sprintf(result, "realm=\"%s\"", + (realm ? realm : "UNKNOWN")); + return result; + } + break; + + case HTAA_PUBKEY: + { + char *realm = HTAssocList_lookup(prot->values, "server"); + result = (char*)malloc(200); + sprintf(result, "realm=\"%s\", key=\"%s\"", + (realm ? realm : "UNKNOWN"), + "PUBKEY-NOT-IMPLEMENTED"); + return result; + } + break; + default: + return NULL; + } +} + + +/* SERVER PUBLIC HTAA_composeAuthHeaders() +** COMPOSE WWW-Authenticate: HEADER LINES +** INDICATING VALID AUTHENTICATION SCHEMES +** FOR THE REQUESTED DOCUMENT +** ON ENTRY: +** No parameters, but HTAA_checkAuthorization() must +** just before have failed because a wrong (or none) +** authentication scheme was used. +** +** ON EXIT: +** returns a buffer containing all the WWW-Authenticate: +** fields including CRLFs (this buffer is auto-freed). +** NULL, if authentication won't help in accessing +** the requested document. +** +*/ +PUBLIC char *HTAA_composeAuthHeaders NOARGS +{ + static char *result = NULL; + HTAAScheme scheme; + char *scheme_name; + char *scheme_params; + HTAAProt *prot = HTAA_getCurrentProtection(); + + if (!prot) { + if (TRACE) + fprintf(stderr, "%s %s\n", + "HTAA_composeAuthHeaders: Document not protected", + "-- why was this function called??"); + return NULL; + } + else if (TRACE) + fprintf(stderr, "HTAA_composeAuthHeaders: for file `%s'\n", + prot->filename); + + FREE(result); /* From previous call */ + if (!(result = (char*)malloc(4096))) /* @@ */ + outofmem(__FILE__, "HTAA_composeAuthHeaders"); + *result = '\0'; + + for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) { + if (-1 < HTList_indexOf(prot->valid_schemes, (void*)scheme)) { + if ((scheme_name = HTAAScheme_name(scheme))) { + scheme_params = compose_scheme_specifics(scheme,prot); + strcat(result, "WWW-Authenticate: "); + strcat(result, scheme_name); + if (scheme_params) { + strcat(result, " "); + strcat(result, scheme_params); + } + strcat(result, "\r\n"); + } /* scheme name found */ + else if (TRACE) + fprintf(stderr, "HTAA_composeAuthHeaders: %s %d\n", + "No name found for scheme number", scheme); + } /* scheme valid for requested document */ + } /* for every scheme */ + + return result; +} + + +/* PUBLIC HTAA_startLogging() +** START UP ACCESS AUTHORIZATION LOGGING +** ON ENTRY: +** fp is the open log file. +** +*/ +PUBLIC void HTAA_startLogging ARGS1(FILE *, fp) +{ + htaa_logfile = fp; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.h new file mode 100644 index 00000000000..dc03c7dd1ae --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.h @@ -0,0 +1,148 @@ +/* SERVER SIDE ACCESS AUTHORIZATION MODULE + + This module is the server side interface to Access Authorization (AA) package. It + contains code only for server. + + Important to know about memory allocation: + + Routines in this module use dynamic allocation, but free automatically all the memory + reserved by them. + + Therefore the caller never has to (and never should) free() any object returned by + these functions. + + Therefore also all the strings returned by this package are only valid until the next + call to the same function is made. This approach is selected, because of the nature of + access authorization: no string returned by the package needs to be valid longer than + until the next call. + + This also makes it easy to plug the AA package in: you don't have to ponder whether to + free()something here or is it done somewhere else (because it is always done somewhere + else). + + The strings that the package needs to store are copied so the original strings given as + parameters to AA functions may be freed or modified with no side effects. + + Also note:The AA package does not free() anything else than what it has itself + allocated. + + */ + +#ifndef HTAASERV_H +#define HTAASERV_H + +#ifndef HTUTILS_H +#include "HTUtils.h" /* BOOL, PARAMS, ARGS */ +#endif /* HTUTILS_H */ +/*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */ +#include "HTRules.h" /* This module interacts with rule system */ +#include "HTAAUtil.h" /* Common parts of AA */ +#include "HTAuth.h" /* Authentication */ + + +#ifdef SHORT_NAMES +#define HTAAstMs HTAA_statusMessage +#define HTAAchAu HTAA_checkAuthorization +#define HTAAcoAH HTAA_composeAuthHeaders +#define HTAAsLog HTAA_startLogging +#endif /*SHORT_NAMES*/ + +extern time_t theTime; + +/* + +Check Access Authorization + + HTAA_checkAuthorization() is the main access authorization function. + + */ + +/* PUBLIC HTAA_checkAuthorization() +** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE +** ON ENTRY: +** url is the document to be accessed. +** method_name name of the method, e.g. "GET" +** scheme_name authentication scheme name. +** scheme_specifics authentication string (or other +** scheme specific parameters, like +** Kerberos-ticket). +** +** ON EXIT: +** returns status codes uniform with those of HTTP: +** 200 OK if file access is ok. +** 401 Unauthorized if user is not authorized to +** access the file. +** 403 Forbidden if there is no entry for the +** requested file in the ACL. +** +** NOTE: +** This function does not check whether the file +** exists or not -- so the status 404 Not found +** must be returned from somewhere else (this is +** to avoid unnecessary overhead of opening the +** file twice). +** +*/ +PUBLIC int HTAA_checkAuthorization PARAMS((CONST char * url, + CONST char * method_name, + CONST char * scheme_name, + char * scheme_specifics)); +/* + +Compose Status Line Message + + */ + +/* SERVER PUBLIC HTAA_statusMessage() +** RETURN A STRING EXPLAINING ACCESS +** AUTHORIZATION FAILURE +** (Can be used in server reply status line +** with 401/403 replies.) +** ON EXIT: +** returns a string containing the error message +** corresponding to internal HTAAFailReason. +*/ +PUBLIC char *HTAA_statusMessage NOPARAMS; +/* + +Compose "Authenticate:" Header Lines for Server Reply + + */ + +/* SERVER PUBLIC HTAA_composeAuthHeaders() +** COMPOSE WWW-Authenticate: HEADER LINES +** INDICATING VALID AUTHENTICATION SCHEMES +** FOR THE REQUESTED DOCUMENT +** ON ENTRY: +** No parameters, but HTAA_checkAuthorization() must +** just before have failed because a wrong (or none) +** authentication scheme was used. +** +** ON EXIT: +** returns a buffer containing all the WWW-Authenticate: +** fields including CRLFs (this buffer is auto-freed). +** NULL, if authentication won't help in accessing +** the requested document. +*/ +PUBLIC char *HTAA_composeAuthHeaders NOPARAMS; +/* + +Start Access Authorization Logging + + */ + +/* PUBLIC HTAA_startLogging() +** START UP ACCESS AUTHORIZATION LOGGING +** ON ENTRY: +** fp is the open log file. +** +*/ +PUBLIC void HTAA_startLogging PARAMS((FILE * fp)); +/* + + */ + +#endif /* NOT HTAASERV_H */ +/* + + End of file HTAAServ.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.c new file mode 100644 index 00000000000..a7cad59b180 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.c @@ -0,0 +1,621 @@ + +/* MODULE HTAAUtil.c +** COMMON PARTS OF ACCESS AUTHORIZATION MODULE +** FOR BOTH SERVER AND BROWSER +** +** IMPORTANT: +** Routines in this module use dynamic allocation, but free +** automatically all the memory reserved by them. +** +** Therefore the caller never has to (and never should) +** free() any object returned by these functions. +** +** Therefore also all the strings returned by this package +** are only valid until the next call to the same function +** is made. This approach is selected, because of the nature +** of access authorization: no string returned by the package +** needs to be valid longer than until the next call. +** +** This also makes it easy to plug the AA package in: +** you don't have to ponder whether to free() something +** here or is it done somewhere else (because it is always +** done somewhere else). +** +** The strings that the package needs to store are copied +** so the original strings given as parameters to AA +** functions may be freed or modified with no side effects. +** +** The AA package does not free() anything else than what +** it has itself allocated. +** +** AA (Access Authorization) package means modules which +** names start with HTAA. +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 8 Nov 93 MD (VMS only) Added case insensitive comparison in HTAA_templateCaseMatch +** +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include "tcp.h" /* NETREAD() etc. */ +#include <string.h> +#include "HTAAUtil.h" /* Implemented here */ +#include "HTAssoc.h" /* Assoc list */ +#include "HTTCP.h" +#include "HTAlert.h" + +#include "LYLeaks.h" + +/* PUBLIC HTAAScheme_enum() +** TRANSLATE SCHEME NAME INTO +** A SCHEME ENUMERATION +** +** ON ENTRY: +** name is a string representing the scheme name. +** +** ON EXIT: +** returns the enumerated constant for that scheme. +*/ +PUBLIC HTAAScheme HTAAScheme_enum ARGS1(CONST char*, name) +{ + char *upcased = NULL; + char *cur; + + if (!name) + return HTAA_UNKNOWN; + + StrAllocCopy(upcased, name); + cur = upcased; + while (*cur) { + *cur = TOUPPER(*cur); + cur++; + } + + if (!strncmp(upcased, "NONE", 4)) { + FREE(upcased); + return HTAA_NONE; + } else if (!strncmp(upcased, "BASIC", 5)) { + FREE(upcased); + return HTAA_BASIC; + } else if (!strncmp(upcased, "PUBKEY", 6)) { + FREE(upcased); + return HTAA_PUBKEY; + } else if (!strncmp(upcased, "KERBEROSV4", 10)) { + FREE(upcased); + return HTAA_KERBEROS_V4; + } else if (!strncmp(upcased, "KERBEROSV5", 10)) { + FREE(upcased); + return HTAA_KERBEROS_V5; + } else { + FREE(upcased); + return HTAA_UNKNOWN; + } +} + + +/* PUBLIC HTAAScheme_name() +** GET THE NAME OF A GIVEN SCHEME +** ON ENTRY: +** scheme is one of the scheme enum values: +** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ... +** +** ON EXIT: +** returns the name of the scheme, i.e. +** "None", "Basic", "Pubkey", ... +*/ +PUBLIC char *HTAAScheme_name ARGS1(HTAAScheme, scheme) +{ + switch (scheme) { + case HTAA_NONE: + return "None"; + break; + case HTAA_BASIC: + return "Basic"; + break; + case HTAA_PUBKEY: + return "Pubkey"; + break; + case HTAA_KERBEROS_V4: + return "KerberosV4"; + break; + case HTAA_KERBEROS_V5: + return "KerberosV5"; + break; + case HTAA_UNKNOWN: + return "UNKNOWN"; + break; + default: + return "THIS-IS-A-BUG"; + } +} + + +/* PUBLIC HTAAMethod_enum() +** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE +** ON ENTRY: +** name is the method name to translate. +** +** ON EXIT: +** returns HTAAMethod enumerated value corresponding +** to the given name. +*/ +PUBLIC HTAAMethod HTAAMethod_enum ARGS1(CONST char *, name) +{ + char tmp[MAX_METHODNAME_LEN+1]; + CONST char *src = name; + char *dest = tmp; + + if (!name) + return METHOD_UNKNOWN; + + while (*src) { + *dest = TOUPPER(*src); + dest++; + src++; + } + *dest = 0; + + if (0==strcmp(tmp, "GET")) + return METHOD_GET; + else if (0==strcmp(tmp, "PUT")) + return METHOD_PUT; + else + return METHOD_UNKNOWN; +} + + +/* PUBLIC HTAAMethod_name() +** GET THE NAME OF A GIVEN METHOD +** ON ENTRY: +** method is one of the method enum values: +** METHOD_GET, METHOD_PUT, ... +** +** ON EXIT: +** returns the name of the scheme, i.e. +** "GET", "PUT", ... +*/ +PUBLIC char *HTAAMethod_name ARGS1(HTAAMethod, method) +{ + switch (method) { + case METHOD_GET: + return "GET"; + break; + case METHOD_PUT: + return "PUT"; + break; + case METHOD_UNKNOWN: + return "UNKNOWN"; + break; + default: + return "THIS-IS-A-BUG"; + } +} + + +/* PUBLIC HTAAMethod_inList() +** IS A METHOD IN A LIST OF METHOD NAMES +** ON ENTRY: +** method is the method to look for. +** list is a list of method names. +** +** ON EXIT: +** returns YES, if method was found. +** NO, if not found. +*/ +PUBLIC BOOL HTAAMethod_inList ARGS2(HTAAMethod, method, + HTList *, list) +{ + HTList *cur = list; + char *item; + + while (NULL != (item = (char*)HTList_nextObject(cur))) { + if (TRACE) + fprintf(stderr, " %s", item); + if (method == HTAAMethod_enum(item)) + return YES; + } + + return NO; /* Not found */ +} + + +/* PUBLIC HTAA_templateMatch() +** STRING COMPARISON FUNCTION FOR FILE NAMES +** WITH ONE WILDCARD * IN THE TEMPLATE +** NOTE: +** This is essentially the same code as in HTRules.c, but it +** cannot be used because it is embedded in between other code. +** (In fact, HTRules.c should use this routine, but then this +** routine would have to be more sophisticated... why is life +** sometimes so hard...) +** +** ON ENTRY: +** template is a template string to match the file name +** agaist, may contain a single wildcard +** character * which matches zero or more +** arbitrary characters. +** filename is the filename (or pathname) to be matched +** agaist the template. +** +** ON EXIT: +** returns YES, if filename matches the template. +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_templateMatch ARGS2(CONST char *, template, + CONST char *, filename) +{ + CONST char *p = template; + CONST char *q = filename; + int m; + + for (; *p && *q && *p == *q; p++, q++) /* Find first mismatch */ + ; /* do nothing else */ + + if (!*p && !*q) + return YES; /* Equally long equal strings */ + else if ('*' == *p) { /* Wildcard */ + p++; /* Skip wildcard character */ + m = strlen(q) - strlen(p); /* Amount to match to wildcard */ + if (m < 0) + return NO; /* No match, filename too short */ + else { /* Skip the matched characters and compare */ + if (strcmp(p, q+m)) + return NO; /* Tail mismatch */ + else + return YES; /* Tail match */ + } + } /* if wildcard */ + else + return NO; /* Length or character mismatch */ +} + + +/* PUBLIC HTAA_templateCaseMatch() +** STRING COMPARISON FUNCTION FOR FILE NAMES +** WITH ONE WILDCARD * IN THE TEMPLATE (Case Insensitive) +** NOTE: +** This is essentially the same code as in HTAA_templateMatch, but +** it compares case insensitive (for VMS). Reason for this routine +** is that HTAA_templateMatch gets called from several places, also +** there where a case sensitive match is needed, so one cannot just +** change the HTAA_templateMatch routine for VMS. +** +** ON ENTRY: +** template is a template string to match the file name +** agaist, may contain a single wildcard +** character * which matches zero or more +** arbitrary characters. +** filename is the filename (or pathname) to be matched +** agaist the template. +** +** ON EXIT: +** returns YES, if filename matches the template. +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_templateCaseMatch ARGS2(CONST char *, template, + CONST char *, filename) +{ + CONST char *p = template; + CONST char *q = filename; + int m; + + /* Find first mismatch */ + for (; *p && *q && TOUPPER(*p) == TOUPPER(*q); p++, q++) + ; /* do nothing else */ + + if (!*p && !*q) + return YES; /* Equally long equal strings */ + else if ('*' == *p) { /* Wildcard */ + p++; /* Skip wildcard character */ + m = strlen(q) - strlen(p); /* Amount to match to wildcard */ + if (m < 0) + return NO; /* No match, filename too short */ + else { /* Skip the matched characters and compare */ + if (strcasecomp(p, q+m)) + return NO; /* Tail mismatch */ + else + return YES; /* Tail match */ + } + } /* if wildcard */ + else + return NO; /* Length or character mismatch */ +} + + +/* PUBLIC HTAA_makeProtectionTemplate() +** CREATE A PROTECTION TEMPLATE FOR THE FILES +** IN THE SAME DIRECTORY AS THE GIVEN FILE +** (Used by server if there is no fancier way for +** it to tell the client, and by browser if server +** didn't send WWW-ProtectionTemplate: field) +** ON ENTRY: +** docname is the document pathname (from URL). +** +** ON EXIT: +** returns a template matching docname, and other files +** files in that directory. +** +** E.g. /foo/bar/x.html => /foo/bar/ * +** ^ +** Space only to prevent it from +** being a comment marker here, +** there really isn't any space. +*/ +PUBLIC char *HTAA_makeProtectionTemplate ARGS1(CONST char *, docname) +{ + char *template = NULL; + char *slash = NULL; + + if (docname) { + StrAllocCopy(template, docname); + slash = strrchr(template, '/'); + if (slash) + slash++; + else + slash = template; + *slash = '\0'; + StrAllocCat(template, "*"); + } + else + StrAllocCopy(template, "*"); + + if (TRACE) + fprintf(stderr, "make_template: made template `%s' for file `%s'\n", + template, docname); + + return template; +} + + +/* +** Skip leading whitespace from *s forward +*/ +#define SKIPWS(s) while (*s==' ' || *s=='\t') s++; + +/* +** Kill trailing whitespace starting from *(s-1) backwords +*/ +#define KILLWS(s) {char *c=s-1; while (*c==' ' || *c=='\t') *(c--)='\0';} + + +/* PUBLIC HTAA_parseArgList() +** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD +** ON ENTRY: +** str is a comma-separated list: +** +** item, item, item +** where +** item ::= value +** | name=value +** | name="value" +** +** Leading and trailing whitespace is ignored +** everywhere except inside quotes, so the following +** examples are equal: +** +** name=value,foo=bar +** name="value",foo="bar" +** name = value , foo = bar +** name = "value" , foo = "bar" +** +** ON EXIT: +** returns a list of name-value pairs (actually HTAssocList*). +** For items with no name, just value, the name is +** the number of order number of that item. E.g. +** "1" for the first, etc. +*/ +PUBLIC HTAssocList *HTAA_parseArgList ARGS1(char *, str) +{ + HTAssocList *assoc_list = HTAssocList_new(); + char *cur = NULL; + char *name = NULL; + int n = 0; + + if (!str) + return assoc_list; + + while (*str) { + SKIPWS(str); /* Skip leading whitespace */ + cur = str; + n++; + + while (*cur && *cur != '=' && *cur != ',') + cur++; /* Find end of name (or lonely value without a name) */ + KILLWS(cur); /* Kill trailing whitespace */ + + if (*cur == '=') { /* Name followed by a value */ + *(cur++) = '\0'; /* Terminate name */ + StrAllocCopy(name, str); + SKIPWS(cur); /* Skip WS leading the value */ + str = cur; + if (*str == '"') { /* Quoted value */ + str++; + cur = str; + while (*cur && *cur != '"') + cur++; + if (*cur == '"') + *(cur++) = '\0'; /* Terminate value */ + /* else it is lacking terminating quote */ + SKIPWS(cur); /* Skip WS leading comma */ + if (*cur == ',') + cur++; /* Skip separating colon */ + } + else { /* Unquoted value */ + while (*cur && *cur != ',') + cur++; + KILLWS(cur); /* Kill trailing whitespace */ + if (*cur == ',') + *(cur++) = '\0'; + /* else *cur already NULL */ + } + } + else { /* No name, just a value */ + if (*cur == ',') + *(cur++) = '\0'; /* Terminate value */ + /* else last value on line (already terminated by NULL) */ + StrAllocCopy(name, "nnn"); /* Room for item order number */ + sprintf(name, "%d", n); /* Item order number for name */ + } + HTAssocList_add(assoc_list, name, str); + str = cur; + } /* while *str */ + + FREE(name); + return assoc_list; +} + + +/************** HEADER LINE READER -- DOES UNFOLDING *************************/ + +#define BUFFER_SIZE 1024 + +PRIVATE char buffer[BUFFER_SIZE + 1]; +PRIVATE char *start_pointer = buffer; +PRIVATE char *end_pointer = buffer; +PRIVATE int in_soc = -1; + +/* PUBLIC HTAA_setupReader() +** SET UP HEADER LINE READER, i.e. give +** the already-read-but-not-yet-processed +** buffer of text to be read before more +** is read from the socket. +** ON ENTRY: +** start_of_headers is a pointer to a buffer containing +** the beginning of the header lines +** (rest will be read from a socket). +** length is the number of valid characters in +** 'start_of_headers' buffer. +** soc is the socket to use when start_of_headers +** buffer is used up. +** ON EXIT: +** returns nothing. +** Subsequent calls to HTAA_getUnfoldedLine() +** will use this buffer first and then +** proceed to read from socket. +*/ +PUBLIC void HTAA_setupReader ARGS4(char *, start_of_headers, + int, length, + void *, handle, + int, soc) +{ + start_pointer = buffer; + if (start_of_headers) { + strncpy(buffer, start_of_headers, length); + buffer[length] = '\0'; + end_pointer = buffer + length; + } + else { + *start_pointer = '\0'; + end_pointer = start_pointer; + } + in_soc = soc; +} + + +/* PUBLIC HTAA_getUnfoldedLine() +** READ AN UNFOLDED HEADER LINE FROM SOCKET +** ON ENTRY: +** HTAA_setupReader must absolutely be called before +** this function to set up internal buffer. +** +** ON EXIT: +** returns a newly-allocated character string representing +** the read line. The line is unfolded, i.e. +** lines that begin with whitespace are appended +** to current line. E.g. +** +** Field-Name: Blaa-Blaa +** This-Is-A-Continuation-Line +** Here-Is_Another +** +** is seen by the caller as: +** +** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another +** +*/ +PUBLIC char *HTAA_getUnfoldedLine NOARGS +{ + char *line = NULL; + char *cur; + int count; + BOOL peek_for_folding = NO; + + if (in_soc < 0) { + if (TRACE) + fprintf(stderr, "%s %s\n", + "HTAA_getUnfoldedLine: buffer not initialized", + "with function HTAA_setupReader()"); + return NULL; + } + + for(;;) { + + /* Reading from socket */ + + if (start_pointer >= end_pointer) {/*Read the next block and continue*/ + count = NETREAD(in_soc, buffer, BUFFER_SIZE); + if (count <= 0) { + in_soc = -1; + return line; + } + start_pointer = buffer; + end_pointer = buffer + count; + *end_pointer = '\0'; +#ifdef NOT_ASCII + cur = start_pointer; + while (cur < end_pointer) { + *cur = TOASCII(*cur); + cur++; + } +#endif /*NOT_ASCII*/ + } + cur = start_pointer; + + + /* Unfolding */ + + if (peek_for_folding) { + if (*cur != ' ' && *cur != '\t') + return line; /* Ok, no continuation line */ + else /* So this is a continuation line, continue */ + peek_for_folding = NO; + } + + + /* Finding end-of-line */ + + while (cur < end_pointer && *cur != '\n') /* Find the end-of-line */ + cur++; /* (or end-of-buffer). */ + + + /* Terminating line */ + + if (cur < end_pointer) { /* So *cur==LF, terminate line */ + *cur = '\0'; /* Overwrite LF */ + if (*(cur-1) == '\r') + *(cur-1) = '\0'; /* Overwrite CR */ + peek_for_folding = YES; /* Check for a continuation line */ + } + + + /* Copying the result */ + + if (line) + StrAllocCat(line, start_pointer); /* Append */ + else + StrAllocCopy(line, start_pointer); /* A new line */ + + start_pointer = cur+1; /* Skip the read line */ + + } /* forever */ +} + + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.h new file mode 100644 index 00000000000..226f1547035 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.h @@ -0,0 +1,361 @@ +/* Utilities for the Authorization parts of libwww + COMMON PARTS OF AUTHORIZATION MODULE TO BOTH SERVER AND BROWSER + + This module is the interface to the common parts of Access Authorization (AA) package + for both server and browser. Important to know about memory allocation: + + Routines in this module use dynamic allocation, but free automatically all the memory + reserved by them. + + Therefore the caller never has to (and never should) free() any object returned by + these functions. + + Therefore also all the strings returned by this package are only valid until the next + call to the same function is made. This approach is selected, because of the nature of + access authorization: no string returned by the package needs to be valid longer than + until the next call. + + This also makes it easy to plug the AA package in: you don't have to ponder whether to + free() something here or is it done somewhere else (because it is always done somewhere + else). + + The strings that the package needs to store are copied so the original strings given as + parameters to AA functions may be freed or modified with no side effects. + + Also note: The AA package does not free() anything else than what it has itself + allocated. + + */ + +#ifndef HTAAUTIL_H +#define HTAAUTIL_H + +#ifndef HTUTILS_H +#include "HTUtils.h" /* BOOL, PARAMS, ARGS */ +#endif /* HTUTILS_H */ +#include "tcp.h" +#include "HTList.h" + +#ifdef SHORT_NAMES +#define HTAASenu HTAAScheme_enum +#define HTAASnam HTAAScheme_name +#define HTAAMenu HTAAMethod_enum +#define HTAAMnam HTAAMethod_name +#define HTAAMinL HTAAMethod_inList +#define HTAAteMa HTAA_templateMatch +#define HTAAmaPT HTAA_makeProtectionTemplate +#define HTAApALi HTAA_parseArgList +#define HTAAsuRe HTAA_setupReader +#define HTAAgUfL HTAA_getUnfoldedLine +#endif /*SHORT_NAMES*/ + + +/* + +Default filenames + + */ +#ifndef PASSWD_FILE +#define PASSWD_FILE "/home2/luotonen/passwd" +#endif + +#ifndef GROUP_FILE +#define GROUP_FILE "/home2/luotonen/group" +#endif + +#define ACL_FILE_NAME ".www_acl" + + +/* +** Numeric constants +*/ +#define MAX_USERNAME_LEN 16 /* @@ Longest allowed username */ +#define MAX_PASSWORD_LEN 3*13 /* @@ Longest allowed password */ + /* (encrypted, so really only 3*8)*/ +#define MAX_METHODNAME_LEN 12 /* @@ Longest allowed method name */ +#define MAX_FIELDNAME_LEN 16 /* @@ Longest field name in */ + /* protection setup file */ +#define MAX_PATHNAME_LEN 80 /* @@ Longest passwd/group file */ + /* patname to allow */ + +/* +** Helpful macros +*/ +#define FREE(x) if (x) {free(x); x = NULL;} + +/* + +Datatype definitions + + HTAASCHEME + + The enumeration HTAAScheme represents the possible authentication schemes used by the + WWW Access Authorization. + + */ + +typedef enum { + HTAA_UNKNOWN, + HTAA_NONE, + HTAA_BASIC, + HTAA_PUBKEY, + HTAA_KERBEROS_V4, + HTAA_KERBEROS_V5, + HTAA_MAX_SCHEMES /* THIS MUST ALWAYS BE LAST! Number of schemes */ +} HTAAScheme; + +/* + + ENUMERATION TO REPRESENT HTTP METHODS + + */ + +typedef enum { + METHOD_UNKNOWN, + METHOD_GET, + METHOD_PUT +} HTAAMethod; + +/* + +Authentication Schemes + + */ + +/* PUBLIC HTAAScheme_enum() +** TRANSLATE SCHEME NAME TO A SCHEME ENUMERATION +** ON ENTRY: +** name is a string representing the scheme name. +** +** ON EXIT: +** returns the enumerated constant for that scheme. +*/ +PUBLIC HTAAScheme HTAAScheme_enum PARAMS((CONST char* name)); + + +/* PUBLIC HTAAScheme_name() +** GET THE NAME OF A GIVEN SCHEME +** ON ENTRY: +** scheme is one of the scheme enum values: +** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ... +** +** ON EXIT: +** returns the name of the scheme, i.e. +** "none", "basic", "pubkey", ... +*/ +PUBLIC char *HTAAScheme_name PARAMS((HTAAScheme scheme)); + +/* + +Methods + + */ + +/* PUBLIC HTAAMethod_enum() +** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE +** ON ENTRY: +** name is the method name to translate. +** +** ON EXIT: +** returns HTAAMethod enumerated value corresponding +** to the given name. +*/ +PUBLIC HTAAMethod HTAAMethod_enum PARAMS((CONST char * name)); + + +/* PUBLIC HTAAMethod_name() +** GET THE NAME OF A GIVEN METHOD +** ON ENTRY: +** method is one of the method enum values: +** METHOD_GET, METHOD_PUT, ... +** +** ON EXIT: +** returns the name of the scheme, i.e. +** "GET", "PUT", ... +*/ +PUBLIC char *HTAAMethod_name PARAMS((HTAAMethod method)); + + +/* PUBLIC HTAAMethod_inList() +** IS A METHOD IN A LIST OF METHOD NAMES +** ON ENTRY: +** method is the method to look for. +** list is a list of method names. +** +** ON EXIT: +** returns YES, if method was found. +** NO, if not found. +*/ +PUBLIC BOOL HTAAMethod_inList PARAMS((HTAAMethod method, + HTList * list)); +/* + +Match Template Against Filename + + */ + +/* PUBLIC HTAA_templateMatch() +** STRING COMPARISON FUNCTION FOR FILE NAMES +** WITH ONE WILDCARD * IN THE TEMPLATE +** NOTE: +** This is essentially the same code as in HTRules.c, but it +** cannot be used because it is embedded in between other code. +** (In fact, HTRules.c should use this routine, but then this +** routine would have to be more sophisticated... why is life +** sometimes so hard...) +** +** ON ENTRY: +** template is a template string to match the file name +** agaist, may contain a single wildcard +** character * which matches zero or more +** arbitrary characters. +** filename is the filename (or pathname) to be matched +** agaist the template. +** +** ON EXIT: +** returns YES, if filename matches the template. +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_templateMatch PARAMS((CONST char * template, + CONST char * filename)); + + +/* PUBLIC HTAA_templateCaseMatch() +** STRING COMPARISON FUNCTION FOR FILE NAMES +** WITH ONE WILDCARD * IN THE TEMPLATE (Case Insensitive) +** NOTE: +** This is essentially the same code as in HTAA_templateMatch, but +** it compares case insensitive (for VMS). Reason for this routine +** is that HTAA_templateMatch gets called from several places, also +** there where a case sensitive match is needed, so one cannot just +** change the HTAA_templateMatch routine for VMS. +** +** ON ENTRY: +** template is a template string to match the file name +** agaist, may contain a single wildcard +** character * which matches zero or more +** arbitrary characters. +** filename is the filename (or pathname) to be matched +** agaist the template. +** +** ON EXIT: +** returns YES, if filename matches the template. +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_templateCaseMatch PARAMS((CONST char * template, + CONST char * filename)); + + +/* PUBLIC HTAA_makeProtectionTemplate() +** CREATE A PROTECTION TEMPLATE FOR THE FILES +** IN THE SAME DIRECTORY AS THE GIVEN FILE +** (Used by server if there is no fancier way for +** it to tell the client, and by browser if server +** didn't send WWW-ProtectionTemplate: field) +** ON ENTRY: +** docname is the document pathname (from URL). +** +** ON EXIT: +** returns a template matching docname, and other files +** files in that directory. +** +** E.g. /foo/bar/x.html => /foo/bar/ * +** ^ +** Space only to prevent it from +** being a comment marker here, +** there really isn't any space. +*/ +PUBLIC char *HTAA_makeProtectionTemplate PARAMS((CONST char * docname)); +/* + +MIME Argument List Parser + + */ + + +/* PUBLIC HTAA_parseArgList() +** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD +** ON ENTRY: +** str is a comma-separated list: +** +** item, item, item +** where +** item ::= value +** | name=value +** | name="value" +** +** Leading and trailing whitespace is ignored +** everywhere except inside quotes, so the following +** examples are equal: +** +** name=value,foo=bar +** name="value",foo="bar" +** name = value , foo = bar +** name = "value" , foo = "bar" +** +** ON EXIT: +** returns a list of name-value pairs (actually HTAssocList*). +** For items with no name, just value, the name is +** the number of order number of that item. E.g. +** "1" for the first, etc. +*/ +PUBLIC HTList *HTAA_parseArgList PARAMS((char * str)); + +/* + +Header Line Reader + + */ + +/* PUBLIC HTAA_setupReader() +** SET UP HEADER LINE READER, i.e. give +** the already-read-but-not-yet-processed +** buffer of text to be read before more +** is read from the socket. +** ON ENTRY: +** start_of_headers is a pointer to a buffer containing +** the beginning of the header lines +** (rest will be read from a socket). +** length is the number of valid characters in +** 'start_of_headers' buffer. +** soc is the socket to use when start_of_headers +** buffer is used up. +** ON EXIT: +** returns nothing. +** Subsequent calls to HTAA_getUnfoldedLine() +** will use this buffer first and then +** proceed to read from socket. +*/ +PUBLIC void HTAA_setupReader PARAMS((char * start_of_headers, + int length, + void * handle, + int soc)); + + +/* PUBLIC HTAA_getUnfoldedLine() +** READ AN UNFOLDED HEADER LINE FROM SOCKET +** ON ENTRY: +** HTAA_setupReader must absolutely be called before +** this function to set up internal buffer. +** +** ON EXIT: +** returns a newly-allocated character string representing +** the read line. The line is unfolded, i.e. +** lines that begin with whitespace are appended +** to current line. E.g. +** +** Field-Name: Blaa-Blaa +** This-Is-A-Continuation-Line +** Here-Is_Another +** +** is seen by the caller as: +** +** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another +** +*/ +PUBLIC char *HTAA_getUnfoldedLine NOPARAMS; + +#endif /* NOT HTAAUTIL_H */ +/* + + End of file HTAAUtil.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.c new file mode 100644 index 00000000000..2147e23f93e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.c @@ -0,0 +1,221 @@ + +/* MODULE HTACL.c +** ACCESS CONTROL LIST ROUTINES +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 8 Nov 93 MD (VMS only) case insensitive compare reading acl entry, filename +** +** +** BUGS: +** +** +*/ + + +#include "HTUtils.h" + +/*#include <stdio.h> included by HTUtils.h -- FM *//* FILE */ +#include <string.h> + +#include "HTAAFile.h" /* File routines */ +#include "HTGroup.h" /* GroupDef */ +#include "HTACL.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* PRIVATE HTAA_getAclFilename() +** RESOLVE THE FULL PATHNAME OF ACL FILE FOR A GIVEN FILE +** ON ENTRY: +** path is the pathname of the file for which to +** ACL file should be found. +** +** ACL filename is computed by replacing +** the filename by .www_acl in the pathname +** (this is done to a local copy, of course). +** +** ON EXIT: +** returns the absolute pathname of ACL file +** (which is automatically freed next time +** this fuction is called). +*/ +PRIVATE char *HTAA_getAclFilename ARGS1(CONST char *, pathname) +{ + static char * local_copy = NULL; + static char * acl_path = NULL; + char * directory = NULL; + char * filename = NULL; + + StrAllocCopy(local_copy, pathname); /* Also frees local_copy */ + /* from previous call. */ + + directory = local_copy; + filename = strrchr(directory, '/'); + if (!filename) { /* No path in front of filename */ + directory = "."; /* So use current directory */ + filename = local_copy; /* and the pathname itself is the filename */ + } + else { + *filename = '\0'; /* Truncate filename off from directory path */ + filename++; /* and the filename begins from the next character */ + } + + StrAllocCopy(acl_path, directory); /* Also frees acl_path */ + /* from previous call. */ + StrAllocCat(acl_path, "/"); + StrAllocCat(acl_path, ACL_FILE_NAME); + + return acl_path; +} + + +/* PUBLIC HTAA_openAcl() +** OPEN THE ACL FILE FOR THE GIVEN DOCUMENT +** ON ENTRY: +** pathname is the absolute pathname of +** the file to be accessed. +** +** ON EXIT: +** returns the FILE* to open ACL. +** NULL, if ACL not found. +*/ +PUBLIC FILE *HTAA_openAcl ARGS1(CONST char *, pathname) +{ + return fopen(HTAA_getAclFilename(pathname), "r"); +} + + +/* PUBLIC HTAA_closeAcl() +** CLOSE ACL FILE +** ON ENTRY: +** acl_file is Access Control List file to close. +** +** ON EXIT: +** returns nothing. +*/ +PUBLIC void HTAA_closeAcl ARGS1(FILE *, acl_file) +{ + if (acl_file) fclose(acl_file); +} + + +/* PUBLIC HTAA_getAclEntry() +** CONSULT THE ACCESS CONTROL LIST AND +** GIVE A LIST OF GROUPS (AND USERS) +** AUTHORIZED TO ACCESS A GIVEN FILE +** ON ENTRY: +** acl_file is an open ACL file. +** pathname is the absolute pathname of +** the file to be accessed. +** method is the method for which access is wanted. +** +** ALC FILE FORMAT: +** +** template : method, method, ... : group@addr, user, group, ... +** +** The last item is in fact in exactly the same format as +** group definition in group file, i.e. everything that +** follows the 'groupname:' part, +** e.g. +** user, group, user@address, group@address, +** (user,group,...)@(address, address, ...) +** +** ON EXIT: +** returns NULL, if there is no entry for the file in the ACL, +** or ACL doesn't exist. +** If there is, a GroupDef object containing the +** group and user names allowed to access the file +** is returned (this is automatically freed +** next time this function is called). +** IMPORTANT: +** Returns the first entry with matching template and +** method. This function should be called multiple times +** to process all the valid entries (until it returns NULL). +** This is because there can be multiple entries like: +** +** *.html : get,put : ari,timbl,robert +** *.html : get : jim,james,jonathan,jojo +** +** NOTE: +** The returned group definition may well contain references +** to groups defined in group file. Therefore these references +** must be resolved according to that rule file by function +** HTAA_resolveGroupReferences() (group file is read in by +** HTAA_readGroupFile()) and after that access authorization +** can be checked with function HTAA_userAndInetGroup(). +*/ +PUBLIC GroupDef *HTAA_getAclEntry ARGS3(FILE *, acl_file, + CONST char *, pathname, + HTAAMethod, method) +{ + static GroupDef * group_def = NULL; + CONST char * filename; + int len; + char *buf; + + if (!acl_file) return NULL; /* ACL doesn't exist */ + + if (group_def) { + GroupDef_delete(group_def); /* From previous call */ + group_def = NULL; + } + + if (!(filename = strrchr(pathname, '/'))) + filename = pathname; + else filename++; /* Skip slash */ + + len = strlen(filename); + + if (!(buf = (char*)malloc((strlen(filename)+2)*sizeof(char)))) + outofmem(__FILE__, "HTAA_getAuthorizedGroups"); + + while (EOF != HTAAFile_readField(acl_file, buf, len+1)) { +#ifdef VMS + if (HTAA_templateCaseMatch(buf, filename)) { +#else /* not VMS */ + if (HTAA_templateMatch(buf, filename)) { +#endif /* not VMS */ + HTList *methods = HTList_new(); + HTAAFile_readList(acl_file, methods, MAX_METHODNAME_LEN); + if (TRACE) { + fprintf(stderr, + "Filename '%s' matched template '%s', allowed methods:", + filename, buf); + } + if (HTAAMethod_inList(method, methods)) { /* right method? */ + if (TRACE) + fprintf(stderr, " METHOD OK\n"); + HTList_delete(methods); + methods = NULL; + FREE(buf); + group_def = HTAA_parseGroupDef(acl_file); + /* + ** HTAA_parseGroupDef() already reads the record + ** separator so we don't call HTAAFile_nextRec(). + */ + return group_def; + } else if (TRACE) { + fprintf(stderr, " METHOD NOT FOUND\n"); + } + HTList_delete(methods); + methods = NULL; + } /* if template match */ + else { + if (TRACE) { + fprintf(stderr, + "Filename '%s' didn't match template '%s'\n", + filename, buf); + } + } + + HTAAFile_nextRec(acl_file); + } /* while not eof */ + FREE(buf); + + return NULL; /* No entry for requested file */ + /* (or an empty entry). */ +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.h new file mode 100644 index 00000000000..c0367c9d214 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.h @@ -0,0 +1,109 @@ +/* ACCESS CONTROL LIST ROUTINES + + */ + +#ifndef HTACL_H +#define HTACL_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTAAUtil.h" +#include "HTGroup.h" + +#ifdef SHORT_NAMES +#define HTAAoACL HTAA_openAcl +#define HTAAcACL HTAA_closeAcl +#define HTAAgAEn HTAA_getAclEntry +#endif /* SHORT_NAMES */ + +/* + +Opening Access Control List File + + */ + +/* PUBLIC HTAA_openAcl() +** OPEN THE ACL FILE FOR THE GIVEN DOCUMENT +** ON ENTRY: +** pathname is the absolute pathname of +** the file to be accessed. +** +** ON EXIT: +** returns the FILE* to open ACL. +** NULL, if ACL not found. +*/ +PUBLIC FILE *HTAA_openAcl PARAMS((CONST char * pathname)); + + +/* PUBLIC HTAA_closeAcl() +** CLOSE ACL FILE +** ON ENTRY: +** acl_file is Access Control List file to close. +** +** ON EXIT: +** returns nothing. +*/ +PUBLIC void HTAA_closeAcl PARAMS((FILE * acl_file)); +/* + +Getting ACL Entry + + */ + +/* PUBLIC HTAA_getAclEntry() +** CONSULT THE ACCESS CONTROL LIST AND +** GIVE A LIST OF GROUPS (AND USERS) +** AUTHORIZED TO ACCESS A GIVEN FILE +** ON ENTRY: +** acl_file is an open ACL file. +** pathname is the absolute pathname of +** the file to be accessed. +** method is the method for which access is wanted. +** +** ALC FILE FORMAT: +** +** template : method, method, ... : group@addr, user, group, ... +** +** The last item is in fact in exactly the same format as +** group definition in group file, i.e. everything that +** follows the 'groupname:' part, +** e.g. +** user, group, user@address, group@address, +** (user,group,...)@(address, address, ...) +** +** ON EXIT: +** returns NULL, if there is no entry for the file in the ACL, +** or ACL doesn't exist. +** If there is, a GroupDef object containing the +** group and user names allowed to access the file +** is returned (this is automatically freed +** next time this function is called). +** IMPORTANT: +** Returns the first entry with matching template and +** method. This function should be called multiple times +** to process all the valid entries (until it returns NULL). +** This is because there can be multiple entries like: +** +** *.html : get,put : ari,timbl,robert +** *.html : get : jim,james,jonathan,jojo +** +** NOTE: +** The returned group definition may well contain references +** to groups defined in group file. Therefore these references +** must be resolved according to that rule file by function +** HTAA_resolveGroupReferences() (group file is read in by +** HTAA_readGroupFile()) and after that access authorization +** can be checked with function HTAA_userAndInetGroup(). +*/ +PUBLIC GroupDef *HTAA_getAclEntry PARAMS((FILE * acl_file, + CONST char * pathname, + HTAAMethod method)); +/* + + */ + +#endif /* not HTACL_H */ +/* + + End of file HTACL.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.c new file mode 100644 index 00000000000..7d4def15269 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.c @@ -0,0 +1,1370 @@ +/* Access Manager HTAccess.c +** ============== +** +** Authors +** TBL Tim Berners-Lee timbl@info.cern.ch +** JFG Jean-Francois Groff jfg@dxcern.cern.ch +** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu> +** FM Foteos Macrides macrides@sci.wfeb.edu +** PDM Danny Mayer mayer@ljo.dec.com +** +** History +** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL +** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG +** 6 Oct 92 Moved HTClientHost and logfile into here. TBL +** 17 Dec 92 Tn3270 added, bug fix. DD +** 4 Feb 93 Access registration, Search escapes bad chars TBL +** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED +** 28 May 93 WAIS gateway explicit if no WAIS library linked in. +** 31 May 94 Added DIRECT_WAIS support for VMS. FM +** 27 Jan 95 Fixed proxy support to use NNTPSERVER for checking +** whether or not to use the proxy server. PDM +** 27 Jan 95 Ensured that proxy service will be overridden for files +** on the local host (because HTLoadFile() doesn't try ftp +** for those) and will substitute ftp for remote files. FM +** 28 Jan 95 Tweeked PDM's proxy override mods to handle port info +** for news and wais URL's. FM +** +** Bugs +** This module assumes that that the graphic object is hypertext, as it +** needs to select it when it has been loaded. A superclass needs to be +** defined which accepts select and select_anchor. +*/ + +#ifdef VMS +#define DIRECT_WAIS +#endif /* VMS */ + +#include "HTUtils.h" +#include "HTTP.h" +#include "HTAlert.h" +/* +** Implements: +*/ +#include "HTAccess.h" + +/* +** Uses: +*/ +#include "HTParse.h" +#include "HTML.h" /* SCW */ + +#ifndef NO_RULES +#include "HTRules.h" +#endif + +#include "HTList.h" +#include "HText.h" /* See bugs above */ +#include "HTAlert.h" +#include "HTCJK.h" +#include "UCMap.h" +#include "GridText.h" + +#include "LYexit.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern HTCJKlang HTCJK; + +/* +** These flags may be set to modify the operation of this module +*/ +PUBLIC char * HTClientHost = NULL; /* Name of remote login host if any */ +PUBLIC FILE * HTlogfile = NULL; /* File to which to output one-liners */ +PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */ + +PUBLIC BOOL using_proxy = NO; /* are we using a proxy gateway? */ + +/* +** To generate other things, play with these: +*/ +PUBLIC HTFormat HTOutputFormat = NULL; +PUBLIC HTStream* HTOutputStream = NULL; /* For non-interactive, set this */ + +PRIVATE HTList * protocols = NULL; /* List of registered protocol descriptors */ + +PUBLIC char *use_this_url_instead = NULL; + +PRIVATE int pushed_assume_LYhndl = -1; /* see LYUC* functions below - kw */ +PRIVATE char * pushed_assume_MIMEname = NULL; + +PRIVATE void free_protocols NOARGS +{ + HTList_delete(protocols); + protocols = NULL; + FREE(pushed_assume_MIMEname); /* shouldn't happen, just in case - kw */ +} + +/* Register a Protocol. HTRegisterProtocol() +** -------------------- +*/ +PUBLIC BOOL HTRegisterProtocol ARGS1( + HTProtocol *, protocol) +{ + if (!protocols) { + protocols = HTList_new(); + atexit(free_protocols); + } + HTList_addObject(protocols, protocol); + return YES; +} + + +/* Register all known protocols. HTAccessInit() +** ----------------------------- +** +** Add to or subtract from this list if you add or remove protocol +** modules. This routine is called the first time the protocol list +** is needed, unless any protocols are already registered, in which +** case it is not called. Therefore the application can override +** this list. +** +** Compiling with NO_INIT prevents all known protocols from being +** forced in at link time. +*/ +#ifndef NO_INIT +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF (HTProtocol, HTTP); +extern GLOBALREF (HTProtocol, HTTPS); +extern GLOBALREF (HTProtocol, HTFile); +extern GLOBALREF (HTProtocol, HTTelnet); +extern GLOBALREF (HTProtocol, HTTn3270); +extern GLOBALREF (HTProtocol, HTRlogin); +#ifndef DECNET +extern GLOBALREF (HTProtocol, HTFTP); +extern GLOBALREF (HTProtocol, HTNews); +extern GLOBALREF (HTProtocol, HTNNTP); +extern GLOBALREF (HTProtocol, HTNewsPost); +extern GLOBALREF (HTProtocol, HTNewsReply); +extern GLOBALREF (HTProtocol, HTSNews); +extern GLOBALREF (HTProtocol, HTSNewsPost); +extern GLOBALREF (HTProtocol, HTSNewsReply); +extern GLOBALREF (HTProtocol, HTGopher); +extern GLOBALREF (HTProtocol, HTCSO); +extern GLOBALREF (HTProtocol, HTFinger); +#ifdef DIRECT_WAIS +extern GLOBALREF (HTProtocol, HTWAIS); +#endif /* DIRECT_WAIS */ +#endif /* !DECNET */ +#else +GLOBALREF HTProtocol HTTP, HTTPS, HTFile, HTTelnet, HTTn3270, HTRlogin; +#ifndef DECNET +GLOBALREF HTProtocol HTFTP, HTNews, HTNNTP, HTNewsPost, HTNewsReply; +GLOBALREF HTProtocol HTSNews, HTSNewsPost, HTSNewsReply; +GLOBALREF HTProtocol HTGopher, HTCSO, HTFinger; +#ifdef DIRECT_WAIS +GLOBALREF HTProtocol HTWAIS; +#endif /* DIRECT_WAIS */ +#endif /* !DECNET */ +#endif /* GLOBALREF_IS_MACRO */ + +PRIVATE void HTAccessInit NOARGS /* Call me once */ +{ + HTRegisterProtocol(&HTTP); + HTRegisterProtocol(&HTTPS); + HTRegisterProtocol(&HTFile); + HTRegisterProtocol(&HTTelnet); + HTRegisterProtocol(&HTTn3270); + HTRegisterProtocol(&HTRlogin); +#ifndef DECNET + HTRegisterProtocol(&HTFTP); + HTRegisterProtocol(&HTNews); + HTRegisterProtocol(&HTNNTP); + HTRegisterProtocol(&HTNewsPost); + HTRegisterProtocol(&HTNewsReply); + HTRegisterProtocol(&HTSNews); + HTRegisterProtocol(&HTSNewsPost); + HTRegisterProtocol(&HTSNewsReply); + HTRegisterProtocol(&HTGopher); + HTRegisterProtocol(&HTCSO); + HTRegisterProtocol(&HTFinger); +#ifdef DIRECT_WAIS + HTRegisterProtocol(&HTWAIS); +#endif /* DIRECT_WAIS */ +#endif /* !DECNET */ + LYRegisterLynxProtocols(); +} +#endif /* !NO_INIT */ + +/* Check for proxy override. override_proxy() +** ------------------------- +** +** Check the no_proxy environment variable to get the list +** of hosts for which proxy server is not consulted. +** +** no_proxy is a comma- or space-separated list of machine +** or domain names, with optional :port part. If no :port +** part is present, it applies to all ports on that domain. +** +** Example: +** no_proxy="cern.ch,some.domain:8001" +** +** Use "*" to override all proxy service: +** no_proxy="*" +*/ +PUBLIC BOOL override_proxy ARGS1( + CONST char *, addr) +{ + CONST char * no_proxy = getenv("no_proxy"); + char * p = NULL; + char * at = NULL; + char * host = NULL; + char * Host = NULL; + char * acc_method = NULL; + int port = 0; + int h_len = 0; + + /* + * Check for global override. + */ + if (no_proxy) { + if (!strcmp(no_proxy, "*")) + return YES; + } + + /* + * Never proxy file:// URLs if they are on the local host. + * HTLoadFile() will not attempt ftp for those if direct + * access fails. We'll check that first, in case no_proxy + * hasn't been defined. - FM + */ + if (!addr) + return NO; + if (!(host = HTParse(addr, "", PARSE_HOST))) + return NO; + if (!*host) { + FREE(host); + return NO; + } + Host = (((at = strchr(host, '@')) != NULL) ? (at+1) : host); + + if ((acc_method = HTParse(addr, "", PARSE_ACCESS))) { + if (!strcmp("file", acc_method) && + (!strcmp(Host, "localhost") || +#ifdef VMS + !strcasecomp(Host, HTHostName()) +#else + !strcmp(Host, HTHostName()) +#endif /* VMS */ + )) { + FREE(host); + FREE(acc_method); + return YES; + } + FREE(acc_method); + } + + if (!no_proxy) { + FREE(host); + return NO; + } + + if (NULL != (p = strrchr(Host, ':'))) { /* Port specified */ + *p++ = 0; /* Chop off port */ + port = atoi(p); + } else { /* Use default port */ + acc_method = HTParse(addr, "", PARSE_ACCESS); + if (acc_method != NULL) { + if (!strcmp(acc_method, "http")) port = 80; + else if (!strcmp(acc_method, "https")) port = 443; + else if (!strcmp(acc_method, "ftp")) port = 21; + else if (!strcmp(acc_method, "gopher")) port = 70; + else if (!strcmp(acc_method, "cso")) port = 105; + else if (!strcmp(acc_method, "news")) port = 119; + else if (!strcmp(acc_method, "nntp")) port = 119; + else if (!strcmp(acc_method, "newspost")) port = 119; + else if (!strcmp(acc_method, "newsreply")) port = 119; + else if (!strcmp(acc_method, "snews")) port = 563; + else if (!strcmp(acc_method, "snewspost")) port = 563; + else if (!strcmp(acc_method, "snewsreply")) port = 563; + else if (!strcmp(acc_method, "wais")) port = 210; + else if (!strcmp(acc_method, "finger")) port = 79; + FREE(acc_method); + } + } + if (!port) + port = 80; /* Default */ + h_len = strlen(Host); + + while (*no_proxy) { + CONST char * end; + CONST char * colon = NULL; + int templ_port = 0; + int t_len; + + while (*no_proxy && (WHITE(*no_proxy) || *no_proxy == ',')) + no_proxy++; /* Skip whitespace and separators */ + + end = no_proxy; + while (*end && !WHITE(*end) && *end != ',') { /* Find separator */ + if (*end == ':') colon = end; /* Port number given */ + end++; + } + + if (colon) { + templ_port = atoi(colon+1); + t_len = colon - no_proxy; + } + else { + t_len = end - no_proxy; + } + + if ((!templ_port || templ_port == port) && + (t_len > 0 && t_len <= h_len && + !strncasecomp(Host + h_len - t_len, no_proxy, t_len))) { + FREE(host); + return YES; + } + if (*end) + no_proxy = (end + 1); + else + break; + } + + FREE(host); + return NO; +} + +/* Find physical name and access protocol get_physical() +** -------------------------------------- +** +** On entry, +** addr must point to the fully qualified hypertext reference. +** anchor a pareent anchor with whose address is addr +** +** On exit, +** returns HT_NO_ACCESS Error has occured. +** HT_OK Success +*/ +PRIVATE int get_physical ARGS2( + CONST char *, addr, + HTParentAnchor *, anchor) +{ + char * acc_method = NULL; /* Name of access method */ + char * physical = NULL; + char * Server_addr = NULL; + +#ifndef NO_RULES + physical = HTTranslate(addr); + if (!physical) { + return HT_FORBIDDEN; + } + if (anchor->isISMAPScript == TRUE) { + StrAllocCat(physical, "?0,0"); + if (TRACE) + fprintf(stderr, "HTAccess: Appending '?0,0' coordinate pair.\n"); + } + HTAnchor_setPhysical(anchor, physical); + FREE(physical); /* free our copy */ +#else + if (anchor->isISMAPScript == TRUE) { + StrAllocCopy(physical, addr); + StrAllocCat(physical, "?0,0"); + if (TRACE) + fprintf(stderr, "HTAccess: Appending '?0,0' coordinate pair.\n"); + HTAnchor_setPhysical(anchor, physical); + FREE(physical); /* free our copy */ + } else { + HTAnchor_setPhysical(anchor, addr); + } +#endif /* NO_RULES */ + + acc_method = HTParse(HTAnchor_physical(anchor), + "file:", PARSE_ACCESS); + + /* + ** Check whether gateway access has been set up for this. + ** + ** This function can be replaced by the rule system above. + */ +#define USE_GATEWAYS +#ifdef USE_GATEWAYS + /* + ** Make sure the using_proxy variable is FALSE. + */ + using_proxy = NO; + + if (!strcasecomp(acc_method, "news")) { + /* + ** News is different, so we need to check the name of the server, + ** as well as the default port for selective exclusions. + */ + char *host = NULL; + if ((host = HTParse(addr, "", PARSE_HOST))) { + if (strchr(host, ':') == NULL) { + StrAllocCopy(Server_addr, "news://"); + StrAllocCat(Server_addr, host); + StrAllocCat(Server_addr, ":119/"); + } + FREE(host); + } else if (getenv("NNTPSERVER") != NULL) { + StrAllocCopy(Server_addr, "news://"); + StrAllocCat(Server_addr, (char *)getenv("NNTPSERVER")); + StrAllocCat(Server_addr, ":119/"); + } + } else if (!strcasecomp(acc_method, "wais")) { + /* + ** Wais also needs checking of the default port + ** for selective exclusions. + */ + char *host = NULL; + if ((host = HTParse(addr, "", PARSE_HOST))) { + if (!(strchr(host, ':'))) { + StrAllocCopy(Server_addr, "wais://"); + StrAllocCat(Server_addr, host); + StrAllocCat(Server_addr, ":210/"); + } + FREE(host); + } + else + StrAllocCopy(Server_addr, addr); + } else { + StrAllocCopy(Server_addr, addr); + } + + if (!override_proxy(Server_addr)) { + char * gateway_parameter, *gateway, *proxy; + + /* + ** Search for gateways. + */ + gateway_parameter = (char *)calloc(1, (strlen(acc_method) + 20)); + if (gateway_parameter == NULL) + outofmem(__FILE__, "HTLoad"); + strcpy(gateway_parameter, "WWW_"); + strcat(gateway_parameter, acc_method); + strcat(gateway_parameter, "_GATEWAY"); + gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */ + + /* + ** Search for proxy servers. + */ + if (!strcmp(acc_method, "file")) + /* + ** If we got to here, a file URL is for ftp on a remote host. - FM + */ + strcpy(gateway_parameter, "ftp"); + else + strcpy(gateway_parameter, acc_method); + strcat(gateway_parameter, "_proxy"); + proxy = (char *)getenv(gateway_parameter); + FREE(gateway_parameter); + + if (TRACE && gateway) + fprintf(stderr, "Gateway found: %s\n", gateway); + if (TRACE && proxy) + fprintf(stderr, "proxy server found: %s\n", proxy); + + /* + ** Proxy servers have precedence over gateway servers. + */ + if (proxy) { + char * gatewayed = NULL; + StrAllocCopy(gatewayed,proxy); + /* + ** Ensure that the proxy server uses ftp for file URLs. - FM + */ + if (!strncmp(addr, "file", 4)) { + StrAllocCat(gatewayed, "ftp"); + StrAllocCat(gatewayed, (addr + 4)); + } else + StrAllocCat(gatewayed, addr); + using_proxy = YES; + if (anchor->isISMAPScript == TRUE) + StrAllocCat(gatewayed, "?0,0"); + HTAnchor_setPhysical(anchor, gatewayed); + FREE(gatewayed); + FREE(acc_method); + + acc_method = HTParse(HTAnchor_physical(anchor), + "http:", PARSE_ACCESS); + + } else if (gateway) { + char * path = HTParse(addr, "", + PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION); + /* Chop leading / off to make host into part of path */ + char * gatewayed = HTParse(path+1, gateway, PARSE_ALL); + FREE(path); + HTAnchor_setPhysical(anchor, gatewayed); + FREE(gatewayed); + FREE(acc_method); + + acc_method = HTParse(HTAnchor_physical(anchor), + "http:", PARSE_ACCESS); + } + } + FREE(Server_addr); +#endif /* use gateways */ + + /* + ** Search registered protocols to find suitable one. + */ + { + int i, n; +#ifndef NO_INIT + if (!protocols) HTAccessInit(); +#endif + n = HTList_count(protocols); + for (i = 0; i < n; i++) { + HTProtocol *p = (HTProtocol *)HTList_objectAt(protocols, i); + if (!strcmp(p->name, acc_method)) { + HTAnchor_setProtocol(anchor, p); + FREE(acc_method); + return (HT_OK); + } + } + } + + FREE(acc_method); + return HT_NO_ACCESS; +} + +/* + * Temporarily set the int UCLYhndl_for_unspec and string + * UCLYhndl_for_unspec used for charset "assuming" to the values + * implied by a HTParentAnchor's UCStages, after saving the current + * values for later restoration. - kw + * @@@ These functions may not really belong here, but where else? + * I want the "pop" to occur as soon as possible after loading + * has finished. - kw @@@ + */ + +extern char*UCAssume_MIMEcharset; + +PUBLIC void LYUCPushAssumed ARGS1( + HTParentAnchor *, anchor) +{ + int anchor_LYhndl = -1; + LYUCcharset * anchor_UCI = NULL; + if (anchor) { + anchor_LYhndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_PARSER); + if (anchor_LYhndl >= 0) + anchor_UCI = HTAnchor_getUCInfoStage(anchor, + UCT_STAGE_PARSER); + if (anchor_UCI && anchor_UCI->MIMEname) { + pushed_assume_MIMEname = UCAssume_MIMEcharset; + UCAssume_MIMEcharset = NULL; + StrAllocCopy(UCAssume_MIMEcharset, anchor_UCI->MIMEname); + pushed_assume_LYhndl = anchor_LYhndl; + UCLYhndl_for_unspec = anchor_LYhndl; + return; + } + } + pushed_assume_LYhndl = -1; + FREE(pushed_assume_MIMEname); +} +/* + * Restore the int UCLYhndl_for_unspec and string + * UCLYhndl_for_unspec used for charset "assuming" from the values + * saved by LYUCPushAssumed, if any. - kw + */ +PRIVATE int LYUCPopAssumed NOARGS +{ + if (pushed_assume_LYhndl >= 0) { + UCLYhndl_for_unspec = pushed_assume_LYhndl; + pushed_assume_LYhndl = -1; + FREE(UCAssume_MIMEcharset); + UCAssume_MIMEcharset = pushed_assume_MIMEname; + pushed_assume_MIMEname = NULL; + return UCLYhndl_for_unspec; + } + return -1; +} + +/* Load a document HTLoad() +** --------------- +** +** This is an internal routine, which has an address AND a matching +** anchor. (The public routines are called with one OR the other.) +** +** On entry, +** addr must point to the fully qualified hypertext reference. +** anchor a pareent anchor with whose address is addr +** +** On exit, +** returns <0 Error has occured. +** HT_LOADED Success +** HT_NO_DATA Success, but no document loaded. +** (telnet sesssion started etc) +*/ +PRIVATE int HTLoad ARGS4( + CONST char *, addr, + HTParentAnchor *, anchor, + HTFormat, format_out, + HTStream *, sink) +{ + HTProtocol *p; + int status = get_physical(addr, anchor); + if (status == HT_FORBIDDEN) { + return HTLoadError(sink, 500, "Access forbidden by rule"); + } + if (status < 0) + return status; /* Can't resolve or forbidden */ + + p = (HTProtocol *)HTAnchor_protocol(anchor); + anchor->underway = TRUE; /* Hack to deal with caching */ + status= (*(p->load))(HTAnchor_physical(anchor), + anchor, format_out, sink); + anchor->underway = FALSE; + LYUCPopAssumed(); + return status; +} + +/* Get a save stream for a document HTSaveStream() +** -------------------------------- +*/ +PUBLIC HTStream *HTSaveStream ARGS1( + HTParentAnchor *, anchor) +{ + HTProtocol *p = (HTProtocol *)HTAnchor_protocol(anchor); + if (!p) + return NULL; + + return (*p->saveStream)(anchor); +} + +extern char LYinternal_flag; /* from LYMainLoop.c */ + +/* Load a document - with logging etc HTLoadDocument() +** ---------------------------------- +** +** - Checks or documents already loaded +** - Logs the access +** - Allows stdin filter option +** - Trace ouput and error messages +** +** On Entry, +** anchor is the node_anchor for the document +** full_address The address of the document to be accessed. +** filter if YES, treat stdin as HTML +** +** On Exit, +** returns YES Success in opening document +** NO Failure +*/ + +extern char LYforce_no_cache; /* from GridText.c */ +extern char LYoverride_no_cache; /* from LYMainLoop.c */ +extern char * HTLoadedDocumentURL NOPARAMS; /* in GridText.c */ +extern BOOL HText_hasNoCacheSet PARAMS((HText *text)); /* in GridText.c */ +extern BOOL reloading; +extern BOOL permanent_redirection; +#ifdef DIRED_SUPPORT +extern BOOLEAN lynx_edit_mode; +#endif + +PRIVATE BOOL HTLoadDocument ARGS4( + CONST char *, full_address, + HTParentAnchor *, anchor, + HTFormat, format_out, + HTStream*, sink) +{ + int status; + HText * text; + CONST char * address_to_load = full_address; + char *cp; + BOOL ForcingNoCache = LYforce_no_cache; + static int redirection_attempts = 0; + + if (TRACE) + fprintf (stderr, "HTAccess: loading document %s\n", address_to_load); + + /* + ** Free use_this_url_instead and reset permanent_redirection + ** if not done elsewhere. - FM + */ + FREE(use_this_url_instead); + permanent_redirection = FALSE; + + /* + ** Make sure some yoyo doesn't send us 'round in circles + ** with redirecting URLs that point back to themselves. + ** We'll set the original Lynx limit of 10 redirections + ** per requested URL from a user, because the HTTP/1.1 + ** will no longer specify a restriction to 5, but will + ** leave it up to the browser's discretion, in deference + ** to Microsoft. - FM + */ + if (redirection_attempts > 10) { + redirection_attempts = 0; + HTAlert("Redirection limit of 10 URL's reached."); + return NO; + } + + /* + * If this is marked as an internal link but we don't have the + * document loaded any more, and we haven't explicitly flagged + * that we want to reload with LYforce_no_cache, then something + * has disappeared from the cache when we expected it to be still + * there. The user probably doesn't expect a new network access. + * So if we have POST data and safe is not set in the anchor, + * ask for confirmation, and fail if not granted. The exception + * are LYNXIMGMAP documents, for which we defer to LYLoadIMGmap + * for prompting if necessary. - kw + */ + if (LYinternal_flag && !LYforce_no_cache && + anchor->post_data && !anchor->safe && + (text = (HText *)HTAnchor_document(anchor)) == NULL && + strncmp(full_address, "LYNXIMGMAP:", 11) && + HTConfirm("Document with POST content not found in cache. Resubmit?") + != TRUE) { + return NO; + } + + /* + ** If we don't have POST content, check whether this is a previous + ** redirecting URL, and keep re-checking until we get to the final + ** destination or redirection limit. If we do have POST content, + ** we didn't allow permanent redirection, and an interactive user + ** will be deciding whether to keep redirecting. - FM + */ + if (!anchor->post_data) { + while ((cp = HTAnchor_physical(anchor)) != NULL && + !strncmp(cp, "Location=", 9)) { + DocAddress NewDoc; + + if (TRACE) { + fprintf (stderr, "HTAccess: '%s' is a redirection URL.\n", + anchor->address); + fprintf (stderr, "HTAccess: Redirecting to '%s'\n", cp+9); + } + + /* + ** Don't exceed the redirection_attempts limit. - FM + */ + if (++redirection_attempts > 10) { + HTAlert("Redirection limit of 10 URL's reached."); + redirection_attempts = 0; + FREE(use_this_url_instead); + return NO; + } + + /* + ** Set up the redirection. - FM + **/ + StrAllocCopy(use_this_url_instead, cp+9); + NewDoc.address = use_this_url_instead; + NewDoc.post_data = NULL; + NewDoc.post_content_type = NULL; + NewDoc.bookmark = anchor->bookmark; + NewDoc.isHEAD = anchor->isHEAD; + NewDoc.safe = anchor->safe; + anchor = (HTParentAnchor *)HTAnchor_findAddress(&NewDoc); + } + } + /* + ** If we had previous redirection, go back and check out + ** that the URL under the current restrictions. - FM + */ + if (use_this_url_instead) { + FREE(redirecting_url); + return(NO); + } + + /* + ** See if we can use an already loaded document. + */ + if (!LYforce_no_cache && (text = (HText *)HTAnchor_document(anchor))) { + /* + ** We have a cached rendition of the target document. + ** Check if it's OK to re-use it. We consider it OK if: + ** (1) the anchor does not have the no_cache element set, or + ** (2) we've overridden it, e.g., because we are acting on + ** a PREV_DOC command or a link in the History Page and + ** it's not a reply from a POST with the LYresubmit_posts + ** flag set, or + ** (3) we are repositioning within the currently loaded document + ** based on the target anchor's address (URL_Reference). + * + * If DONT_TRACK_INTERNAL_LINKS is defined, HText_AreDifferent() + * is used to determine whether (3) applies. If the target address + * differs from that of the current document only by a fragment + * and the taget address has an appended fragment, repositioning + * without reloading is always assumed. + * Note that HText_AreDifferent() currently always returns TRUE + * if the target has a LYNXIMGMAP URL, so that an internally + * generated pseudo-document will normally not be re-used unless + * condition (2) appplies. (Condition (1) cannot apply since in + * LYMap.c, no_cache is always set in the anchor object). This + * doesn't guarantee that the resource from which the MAP element + * is taken will be read again (reloaded) when the list of links + * for a client-side image map is regenerated, when in some cases + * it should (e.g. user requested RELOAD, or HTTP response with + * no-cache header and we are not overriding). + * + * If DONT_TRACK_INTERNAL_LINKS is undefined, a target address that + * points to the same URL as the current document may still result in + * reloading, depending on whether the original URL-Reference + * was given as an internal link in the context of the previously + * loaded document. HText_AreDifferent() is not used here for + * testing whether we are just repositioning. For an internal + * link, the potential callers of this function from mainloop() + * down will either avoid making the call (and do the repositioning + * differently) or set LYinternal_flag (or LYoverride_no_cache). + * Note that (a) LYNXIMGMAP pseudo-documents and (b) The "List Page" + * document are treated logically as being part of the document on + * which they are based, for the purpose of whether to treat a link + * as internal, but the logic for this (by setting LYinternal_flag + * as necessary) is implemented elsewhere. There is a specific + * test for LYNXIMGMAP here so that the generated pseudo-document + * will not be re-used unless LYoverride_no_cache is set. The same + * caveat as above applies w.r.t. reloading of the underlying + * resource. + * + ** We also should be checking other aspects of cache + ** regulation (e.g., based on an If-Modified-Since check, + ** etc.) but the code for doing those other things isn't + ** available yet. + */ +#ifdef DONT_TRACK_INTERNAL_LINKS + if (LYoverride_no_cache || !HText_hasNoCacheSet(text) || + !HText_AreDifferent(anchor, full_address)) +#else + if (LYoverride_no_cache || + ((LYinternal_flag || !HText_hasNoCacheSet(text)) && + strncmp(full_address, "LYNXIMGMAP:", 11))) +#endif /* TRACK_INTERNAL_LINKS */ + { + if (TRACE) + fprintf(stderr, "HTAccess: Document already in memory.\n"); + HText_select(text); + +#ifdef DIRED_SUPPORT + if (HTAnchor_format(anchor) == WWW_DIRED) + lynx_edit_mode = TRUE; +#endif + redirection_attempts = 0; + return YES; + } else { +#if NOT_USED_CODE + /* disabled 1997-10-28 - kw + callers already do this when requested + */ + reloading = TRUE; +#endif + ForcingNoCache = YES; + if (TRACE) { + fprintf(stderr, "HTAccess: Auto-reloading document.\n"); + } + } + } + + /* + ** Get the document from the net. If we are auto-reloading, + ** the mutable anchor elements from the previous rendition + ** should be freed in conjunction with loading of the new + ** rendition. - FM + */ + LYforce_no_cache = NO; /* reset after each time through */ + if (ForcingNoCache) { + FREE(anchor->title); + } + status = HTLoad(address_to_load, anchor, format_out, sink); + if (TRACE) { + fprintf(stderr, "HTAccess: status=%d\n", status); + } + + /* + ** Log the access if necessary. + */ + if (HTlogfile) { + time_t theTime; + time(&theTime); + fprintf(HTlogfile, "%24.24s %s %s %s\n", + ctime(&theTime), + HTClientHost ? HTClientHost : "local", + status < 0 ? "FAIL" : "GET", + full_address); + fflush(HTlogfile); /* Actually update it on disk */ + if (TRACE) + fprintf(stderr, "Log: %24.24s %s %s %s\n", + ctime(&theTime), + HTClientHost ? HTClientHost : "local", + status < 0 ? "FAIL" : "GET", + full_address); + } + + /* + ** Check out what we received from the net. + */ + if (status == HT_REDIRECTING) { + /* Exported from HTMIME.c, of all places. *//** NO!! - FM **/ + /* + ** Doing this via HTMIME.c meant that the redirection cover + ** page was already loaded before we learned that we want a + ** different URL. Also, changing anchor->address, as Lynx + ** was doing, meant we could never again access its hash + ** table entry, creating an insolvable memory leak. Instead, + ** if we had a 301 status and set permanent_redirection, + ** we'll load the new URL in anchor->physical, preceded by a + ** token, which we can check to make replacements on subsequent + ** access attempts. We'll check recursively, and retrieve the + ** final URL if we had multiple redirections to it. If we just + ** went to HTLoad now, as Lou originally had this, we couldn't do + ** Lynx's security checks and alternate handling of some URL types. + ** So, instead, we'll go all the way back to the top of getfile + ** in LYGetFile.c when the status is HT_REDIRECTING. This may + ** seem bizarre, but it works like a charm! - FM + */ + if (TRACE) { + fprintf(stderr, "HTAccess: '%s' is a redirection URL.\n", + address_to_load); + fprintf(stderr, "HTAccess: Redirecting to '%s'\n", + redirecting_url); + } + /* + ** Prevent circular references. + */ + if (strcmp(address_to_load, redirecting_url)) { /* if different */ + /* + ** Load token and redirecting url into anchor->physical + ** if we had 301 Permanent redirection. HTTP.c does not + ** allow this if we have POST content. - FM + */ + if (permanent_redirection) { + StrAllocCopy(anchor->physical, "Location="); + StrAllocCat(anchor->physical, redirecting_url); + } + + /* + ** Set up flags before return to getfile. - FM + */ + StrAllocCopy(use_this_url_instead, redirecting_url); + if (ForcingNoCache) + LYforce_no_cache = YES; + ++redirection_attempts; + FREE(redirecting_url); + permanent_redirection = FALSE; + return(NO); + } + ++redirection_attempts; + FREE(redirecting_url); + permanent_redirection = FALSE; + return(YES); + } + + /* + ** We did not receive a redirecting URL. - FM + */ + redirection_attempts = 0; + FREE(redirecting_url); + permanent_redirection = FALSE; + + if (status == HT_LOADED) { + if (TRACE) { + fprintf(stderr, "HTAccess: `%s' has been accessed.\n", + full_address); + } + return YES; + } + if (status == HT_PARTIAL_CONTENT) { + HTAlert("Loading incomplete."); + if (TRACE) { + fprintf(stderr, "HTAccess: `%s' has been accessed, partial content.\n", + full_address); + } + return YES; + } + + if (status == HT_NO_DATA) { + if (TRACE) { + fprintf(stderr, + "HTAccess: `%s' has been accessed, No data left.\n", + full_address); + } + return NO; + } + + if (status == HT_NOT_LOADED) { + if (TRACE) { + fprintf(stderr, + "HTAccess: `%s' has been accessed, No data loaded.\n", + full_address); + } + return NO; + } + + if (status == HT_INTERRUPTED) { + if (TRACE) { + fprintf(stderr, + "HTAccess: `%s' has been accessed, transfer interrupted.\n", + full_address); + } +/* _HTProgress("Data transfer interrupted."); */ + return NO; + } + + if (status <= 0) { /* Failure in accessing a document */ + char *temp = NULL; + StrAllocCopy(temp, "Can't Access `"); + StrAllocCat(temp, full_address); + StrAllocCat(temp, "'"); + _HTProgress(temp); + FREE(temp); + if (TRACE) fprintf(stderr, + "HTAccess: Can't access `%s'\n", full_address); + HTLoadError(sink, 500, "Unable to access document."); + return NO; + } + + /* + ** If you get this, then please find which routine is returning + ** a positive unrecognised error code! + */ + fprintf(stderr, + "**** HTAccess: socket or file number returned by obsolete load routine!\n"); + fprintf(stderr, + "**** HTAccess: Internal software error. Please mail lynx_dev@sig.net!\n"); + fprintf(stderr, "**** HTAccess: Status returned was: %d\n",status); + exit(-1); + +} /* HTLoadDocument */ + +/* Load a document from absolute name. HTLoadAbsolute() +** ----------------------------------- +** +** On Entry, +** addr The absolute address of the document to be accessed. +** filter if YES, treat document as HTML +** +** On Exit, +** returns YES Success in opening document +** NO Failure +*/ +PUBLIC BOOL HTLoadAbsolute ARGS1( + CONST DocAddress *, docaddr) +{ + return HTLoadDocument(docaddr->address, + HTAnchor_parent(HTAnchor_findAddress(docaddr)), + (HTOutputFormat ? HTOutputFormat : WWW_PRESENT), + HTOutputStream); +} + +#ifdef NOT_USED_CODE +/* Load a document from absolute name to stream. HTLoadToStream() +** --------------------------------------------- +** +** On Entry, +** addr The absolute address of the document to be accessed. +** sink if non-NULL, send data down this stream +** +** On Exit, +** returns YES Success in opening document +** NO Failure +*/ +PUBLIC BOOL HTLoadToStream ARGS3( + CONST char *, addr, + BOOL, filter, + HTStream *, sink) +{ + return HTLoadDocument(addr, + HTAnchor_parent(HTAnchor_findAddress(addr)), + (HTOutputFormat ? HTOutputFormat : WWW_PRESENT), + sink); +} +#endif /* NOT_USED_CODE */ + +/* Load a document from relative name. HTLoadRelative() +** ----------------------------------- +** +** On Entry, +** relative_name The relative address of the document +** to be accessed. +** +** On Exit, +** returns YES Success in opening document +** NO Failure +*/ +PUBLIC BOOL HTLoadRelative ARGS2( + CONST char *, relative_name, + HTParentAnchor *, here) +{ + DocAddress full_address; + BOOL result; + char * mycopy = NULL; + char * stripped = NULL; + char * current_address = HTAnchor_address((HTAnchor*)here); + + full_address.address = NULL; + full_address.post_data = NULL; + full_address.post_content_type = NULL; + full_address.bookmark = NULL; + full_address.isHEAD = FALSE; + full_address.safe = FALSE; + + StrAllocCopy(mycopy, relative_name); + + stripped = HTStrip(mycopy); + full_address.address = + HTParse(stripped, + current_address, + PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION); + result = HTLoadAbsolute(&full_address); + /* + ** If we got redirection, result will be NO, but use_this_url_instead + ** will be set. The calling routine should check both and do whatever + ** is appropriate. - FM + */ + FREE(full_address.address); + FREE(current_address); + FREE(mycopy); /* Memory leak fixed 10/7/92 -- JFG */ + return result; +} + +/* Load if necessary, and select an anchor. HTLoadAnchor() +** ---------------------------------------- +** +** On Entry, +** destination The child or parenet anchor to be loaded. +** +** On Exit, +** returns YES Success +** NO Failure +*/ +PUBLIC BOOL HTLoadAnchor ARGS1( + HTAnchor *, destination) +{ + HTParentAnchor * parent; + BOOL loaded = NO; + if (!destination) + return NO; /* No link */ + + parent = HTAnchor_parent(destination); + + if (HTAnchor_document(parent) == NULL) { /* If not alread loaded */ + /* TBL 921202 */ + BOOL result; + char * address = HTAnchor_address((HTAnchor*) parent); + + result = HTLoadDocument(address, + parent, + HTOutputFormat ? + HTOutputFormat : WWW_PRESENT, + HTOutputStream); + FREE(address); + if (!result) return NO; + loaded = YES; + } + + { + HText *text = (HText*)HTAnchor_document(parent); + + if (destination != (HTAnchor *)parent) { /* If child anchor */ + HText_selectAnchor(text, /* Double display? @@ */ + (HTChildAnchor*)destination); + } else { + if (!loaded) + HText_select(text); + } + } + return YES; + +} /* HTLoadAnchor */ + +/* Search. HTSearch() +** ------- +** +** Performs a keyword search on word given by the user. Adds the +** keyword to the end of the current address and attempts to open +** the new address. +** +** On Entry, +** *keywords space-separated keyword list or similar search list +** here is anchor search is to be done on. +*/ +PRIVATE char hex ARGS1( + int, i) +{ + char * hexchars = "0123456789ABCDEF"; + return hexchars[i]; +} + +PUBLIC BOOL HTSearch ARGS2( + CONST char *, keywords, + HTParentAnchor *, here) +{ +#define acceptable \ +"1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_" + + char *q, *u; + CONST char * p, *s, *e; /* Pointers into keywords */ + char * address = NULL; + BOOL result; + char * escaped = (char *)calloc(1, ((strlen(keywords)*3) + 1)); + static CONST BOOL isAcceptable[96] = + + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */ + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */ + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */ + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */ + + if (escaped == NULL) + outofmem(__FILE__, "HTSearch"); + + StrAllocCopy(address, here->isIndexAction); + + /* + ** Convert spaces to + and hex escape unacceptable characters. + */ + for (s = keywords; *s && WHITE(*s); s++) /* Scan */ + ; /* Skip white space */ + for (e = s + strlen(s); e > s && WHITE(*(e-1)); e--) /* Scan */ + ; /* Skip trailers */ + for (q = escaped, p = s; p < e; p++) { /* Scan stripped field */ + unsigned char c = (unsigned char)TOASCII(*p); + if (WHITE(*p)) { + *q++ = '+'; + } else if (HTCJK != NOCJK) { + *q++ = *p; + } else if (c>=32 && c<=(unsigned char)127 && isAcceptable[c-32]) { + *q++ = *p; /* 930706 TBL for MVS bug */ + } else { + *q++ = '%'; + *q++ = hex((int)(c >> 4)); + *q++ = hex((int)(c & 15)); + } + } /* Loop over string */ + *q = '\0'; /* Terminate escaped string */ + u = strchr(address, '?'); /* Find old search string */ + if (u != NULL) + *u = '\0'; /* Chop old search off */ + + StrAllocCat(address, "?"); + StrAllocCat(address, escaped); + FREE(escaped); + result = HTLoadRelative(address, here); + FREE(address); + + /* + ** If we got redirection, result will be NO, but use_this_url_instead + ** will be set. The calling routine should check both and do whatever + ** is appropriate. Only an http server (not a gopher or wais server) + ** could return redirection. Lynx will go all the way back to its + ** mainloop() and subject a redirecting URL to all of its security and + ** restrictions checks. - FM + */ + return result; +} + +/* Search Given Indexname. HTSearchAbsolute() +** ----------------------- +** +** Performs a keyword search on word given by the user. Adds the +** keyword to the end of the current address and attempts to open +** the new address. +** +** On Entry, +** *keywords space-separated keyword list or similar search list +** *addres is name of object search is to be done on. +*/ +PUBLIC BOOL HTSearchAbsolute ARGS2( + CONST char *, keywords, + CONST char *, indexname) +{ + DocAddress abs_doc; + HTParentAnchor * anchor; + abs_doc.address = (char *)indexname; + abs_doc.post_data = NULL; + abs_doc.post_content_type = NULL; + abs_doc.bookmark = NULL; + abs_doc.isHEAD = FALSE; + abs_doc.safe = FALSE; + + anchor = (HTParentAnchor*)HTAnchor_findAddress(&abs_doc); + return HTSearch(keywords, anchor); +} + +#ifdef NOT_USED_CODE +/* Generate the anchor for the home page. HTHomeAnchor() +** -------------------------------------- +** +** As it involves file access, this should only be done once +** when the program first runs. +** This is a default algorithm -- browser don't HAVE to use this. +** But consistency betwen browsers is STRONGLY recommended! +** +** Priority order is: +** 1 WWW_HOME environment variable (logical name, etc) +** 2 ~/WWW/default.html +** 3 /usr/local/bin/default.html +** 4 http://www.w3.org/default.html +*/ +PUBLIC HTParentAnchor * HTHomeAnchor NOARGS +{ + char * my_home_document = NULL; + char * home = (char *)getenv(LOGICAL_DEFAULT); + char * ref; + HTParentAnchor * anchor; + + if (home) { + StrAllocCopy(my_home_document, home); +#define MAX_FILE_NAME 1024 /* @@@ */ + } else if (HTClientHost) { /* Telnet server */ + /* + ** Someone telnets in, they get a special home. + */ + FILE * fp = fopen(REMOTE_POINTER, "r"); + char * status; + if (fp) { + my_home_document = (char*)calloc(1, MAX_FILE_NAME); + if (my_home_document == NULL) + outofmem(__FILE__, "HTHomeAnchor"); + status = fgets(my_home_document, MAX_FILE_NAME, fp); + if (!status) { + FREE(my_home_document); + } + fclose(fp); + } + if (my_home_document == NULL) + StrAllocCopy(my_home_document, REMOTE_ADDRESS); + } + +#ifdef unix + if (my_home_document == NULL) { + FILE * fp = NULL; + CONST char * home = (CONST char*)getenv("HOME"); + if (home != null) { + my_home_document = (char *)calloc(1, + (strlen(home) + 1 + strlen(PERSONAL_DEFAULT) + 1)); + if (my_home_document == NULL) + outofmem(__FILE__, "HTAnchorHome"); + sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT); + fp = fopen(my_home_document, "r"); + } + + if (!fp) { + StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE); + fp = fopen(my_home_document, "r"); + } + if (fp) { + fclose(fp); + } else { + if (TRACE) + fprintf(stderr, + "HTBrowse: No local home document ~/%s or %s\n", + PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE); + FREE(my_home_document); + } + } +#endif /* unix */ + ref = HTParse((my_home_document ? + my_home_document : (HTClientHost ? + REMOTE_ADDRESS : LAST_RESORT)), + "file:", + PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION); + if (my_home_document) { + if (TRACE) + fprintf(stderr, + "HTAccess: Using custom home page %s i.e. address %s\n", + my_home_document, ref); + FREE(my_home_document); + } + anchor = (HTParentAnchor*)HTAnchor_findAddress(ref); + FREE(ref); + return anchor; +} +#endif /* NOT_USED_CODE */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.h new file mode 100644 index 00000000000..2826d13aa0a --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.h @@ -0,0 +1,325 @@ +/* HTAccess: Access manager for libwww + ACCESS MANAGER + + This module keeps a list of valid protocol (naming scheme) specifiers with associated + access code. It allows documents to be loaded given various combinations of + parameters. New access protocols may be registered at any time. + + Part of the libwww library . + + */ +#ifndef HTACCESS_H +#define HTACCESS_H + +extern char * use_this_url_instead; + +/* Definition uses: +*/ +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "tcp.h" +#include "HTAnchor.h" +#include "HTFormat.h" + +#ifdef SHORT_NAMES +#define HTClientHost HTClHost +#define HTSearchAbsolute HTSeAbso +#define HTOutputStream HTOuStre +#define HTOutputFormat HTOuForm +#endif + +/* Return codes from load routines: +** +** These codes may be returned by the protocol modules, +** and by the HTLoad routines. +** In general, positive codes are OK and negative ones are bad. +*/ + +#define HT_NO_DATA -9999 /* return code: OK but no data was loaded */ + /* Typically, other app started or forked */ + +/* + +Default Addresses + + These control the home page selection. To mess with these for normal browses is asking + for user confusion. + + */ +#define LOGICAL_DEFAULT "WWW_HOME" /* Defined to be the home page */ + +#ifndef PERSONAL_DEFAULT +#define PERSONAL_DEFAULT "WWW/default.html" /* in home directory */ +#endif +#ifndef LOCAL_DEFAULT_FILE +#define LOCAL_DEFAULT_FILE "/usr/local/lib/WWW/default.html" +#endif +/* If one telnets to a www access point, + it will look in this file for home page */ +#ifndef REMOTE_POINTER +#define REMOTE_POINTER "/etc/www-remote.url" /* can't be file */ +#endif +/* and if that fails it will use this. */ +#ifndef REMOTE_ADDRESS +#define REMOTE_ADDRESS "http://www.w3.org/remote.html" /* can't be file */ +#endif + +/* If run from telnet daemon and no -l specified, use this file: +*/ +#ifndef DEFAULT_LOGFILE +#define DEFAULT_LOGFILE "/usr/adm/www-log/www-log" +#endif + +/* If the home page isn't found, use this file: +*/ +#ifndef LAST_RESORT +#define LAST_RESORT "http://www.w3.org/default.html" +#endif + + +/* + +Flags which may be set to control this module + + */ +#ifdef NOT +extern int HTDiag; /* Flag: load source as plain text */ +#endif /* NOT */ +extern char * HTClientHost; /* Name or number of telnetting host */ +extern FILE * HTlogfile; /* File to output one-liners to */ +extern BOOL HTSecure; /* Disable security holes? */ +extern HTStream* HTOutputStream; /* For non-interactive, set this */ +extern HTFormat HTOutputFormat; /* To convert on load, set this */ + +/* Check for proxy override. override_proxy() +** +** Check the no_proxy environment variable to get the list +** of hosts for which proxy server is not consulted. +** +** no_proxy is a comma- or space-separated list of machine +** or domain names, with optional :port part. If no :port +** part is present, it applies to all ports on that domain. +** +** Example: +** no_proxy="cern.ch,some.domain:8001" +** +** Use "*" to override all proxy service: +** no_proxy="*" +*/ +extern BOOL override_proxy PARAMS(( + CONST char * addr)); + +/* + +Load a document from relative name + + ON ENTRY, + + relative_name The relative address of the file to be accessed. + + here The anchor of the object being searched + + ON EXIT, + + returns YES Success in opening file + + NO Failure + + */ +extern BOOL HTLoadRelative PARAMS(( + CONST char * relative_name, + HTParentAnchor * here)); + + +/* + +Load a document from absolute name + + ON ENTRY, + + addr The absolute address of the document to be accessed. + + filter_it if YES, treat document as HTML + + */ + +/* + + ON EXIT, + + */ + +/* + + returns YES Success in opening document + + NO Failure + + */ +extern BOOL HTLoadAbsolute PARAMS((CONST DocAddress * addr)); + + +/* + +Load a document from absolute name to a stream + + ON ENTRY, + + addr The absolute address of the document to be accessed. + + filter_it if YES, treat document as HTML + + ON EXIT, + + returns YES Success in opening document + + NO Failure + + Note: This is equivalent to HTLoadDocument + + */ +extern BOOL HTLoadToStream PARAMS((CONST char * addr, BOOL filter_it, + HTStream * sink)); + + +/* + +Load if necessary, and select an anchor + + ON ENTRY, + + destination The child or parenet anchor to be loaded. + + */ + +/* + + ON EXIT, + + */ + +/* + + returns YES Success + + returns NO Failure + + */ + + + +extern BOOL HTLoadAnchor PARAMS((HTAnchor * destination)); + + +/* + +Make a stream for Saving object back + + ON ENTRY, + + anchor is valid anchor which has previously beeing loaded + + ON EXIT, + + returns 0 if error else a stream to save the object to. + + */ + + +extern HTStream * HTSaveStream PARAMS((HTParentAnchor * anchor)); + + +/* + +Search + + Performs a search on word given by the user. Adds the search words to the end of the + current address and attempts to open the new address. + + ON ENTRY, + + *keywords space-separated keyword list or similar search list + + here The anchor of the object being searched + + */ +extern BOOL HTSearch PARAMS((CONST char * keywords, HTParentAnchor* here)); + + +/* + +Search Given Indexname + + Performs a keyword search on word given by the user. Adds the keyword to the end of + the current address and attempts to open the new address. + + ON ENTRY, + + *keywords space-separated keyword list or similar search list + + *indexname is name of object search is to be done on. + + */ +extern BOOL HTSearchAbsolute PARAMS(( + CONST char * keywords, + CONST char * indexname)); + + +/* + +Register an access method + + */ + +typedef struct _HTProtocol { + char * name; + + int (*load)PARAMS(( + CONST char * full_address, + HTParentAnchor * anchor, + HTFormat format_out, + HTStream* sink)); + + HTStream* (*saveStream)PARAMS((HTParentAnchor * anchor)); + +} HTProtocol; + +extern BOOL HTRegisterProtocol PARAMS((HTProtocol * protocol)); + + +/* + +Generate the anchor for the home page + + */ + +/* + + As it involves file access, this should only be done once when the program first runs. + This is a default algorithm -- browser don't HAVE to use this. + + */ +extern HTParentAnchor * HTHomeAnchor NOPARAMS; + +/* + +Return Host Name + + */ +extern CONST char * HTHostName NOPARAMS; + +/* + +For registering protocols supported by Lynx + +*/ +extern void LYRegisterLynxProtocols NOARGS; + +extern void LYUCPushAssumed PARAMS(( + HTParentAnchor * anchor)); + +#endif /* HTACCESS_H */ +/* + + end of HTAccess */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.c new file mode 100644 index 00000000000..799db6cba5f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.c @@ -0,0 +1,126 @@ +/* Displaying messages and getting input for LineMode Browser +** ========================================================== +** +** REPLACE THIS MODULE with a GUI version in a GUI environment! +** +** History: +** Jun 92 Created May 1992 By C.T. Barker +** Feb 93 Simplified, portablised TBL +** Sep 93 Corrected 3 bugs in HTConfirm() :-( AL +*/ + + +#include "HTUtils.h" +#include "tcp.h" /* for TOUPPER */ + +#include "HTAlert.h" + +#include <ctype.h> /* for toupper - should be in tcp.h */ +#ifdef VMS +extern char * getpass PARAMS((CONST char *prompt)); +#endif /* VMS */ + +#include "LYLeaks.h" + +PUBLIC void HTAlert ARGS1(CONST char *, Msg) +{ +#ifdef NeXTStep + NXRunAlertPanel(NULL, "%s", NULL, NULL, NULL, Msg); +#else + fprintf(stderr, "WWW Alert: %s\n", Msg); +#endif +} + + +PUBLIC void HTProgress ARGS1(CONST char *, Msg) +{ + fprintf(stderr, " %s ...\n", Msg); +} + + +PUBLIC BOOL HTConfirm ARGS1(CONST char *, Msg) +{ + char Reply[4]; /* One more for terminating NULL -- AL */ + char *URep; + + fprintf(stderr, "WWW: %s (y/n) ", Msg); + /* (y/n) came twice -- AL */ + + fgets(Reply, 4, stdin); /* get reply, max 3 characters */ + URep=Reply; + while (*URep) { + if (*URep == '\n') { + *URep = (char)0; /* Overwrite newline */ + break; + } + *URep=TOUPPER(*URep); + URep++; /* This was previously embedded in the TOUPPER */ + /* call an it became evaluated twice because */ + /* TOUPPER is a macro -- AL */ + } + + if ((strcmp(Reply,"YES")==0) || (strcmp(Reply,"Y")==0)) + return(YES); + else + return(NO); +} + +/* Prompt for answer and get text back +*/ +PUBLIC char * HTPrompt ARGS2(CONST char *, Msg, CONST char *, deflt) +{ + char Tmp[200]; + char * rep = 0; + fprintf(stderr, "WWW: %s", Msg); + if (deflt) fprintf(stderr, " (RETURN for [%s]) ", deflt); + + fgets(Tmp, 200, stdin); + Tmp[strlen(Tmp)-1] = (char)0; /* Overwrite newline */ + + StrAllocCopy(rep, *Tmp ? Tmp : deflt); + return rep; +} + + +/* Prompt for password without echoing the reply +*/ +PUBLIC char * HTPromptPassword ARGS1(CONST char *, Msg) +{ + char *result = NULL; + char *pw = (char*)getpass(Msg ? Msg : "Password: "); + + StrAllocCopy(result, pw); + return result; +} + + +/* Prompt both username and password HTPromptUsernameAndPassword() +** --------------------------------- +** On entry, +** Msg is the prompting message. +** *username and +** *password are char pointers; they are changed +** to point to result strings. +** +** If *username is not NULL, it is taken +** to point to a default value. +** Initial value of *password is +** completely discarded. +** +** On exit, +** *username and *password point to newly allocated +** strings -- original strings pointed to by them +** are NOT freed. +** +*/ +PUBLIC void HTPromptUsernameAndPassword ARGS4(CONST char *, Msg, + char **, username, + char **, password, + BOOL, IsProxy) +{ + if (Msg) + fprintf(stderr, "WWW: %s\n", Msg); + *username = HTPrompt("Username: ", *username); + *password = HTPromptPassword("Password: "); +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.h new file mode 100644 index 00000000000..03b970b63e0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.h @@ -0,0 +1,128 @@ +/* */ + +/* Displaying messages and getting input for WWW Library +** ===================================================== +** +** May 92 Created By C.T. Barker +** Feb 93 Portablized etc TBL +*/ + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "tcp.h" + +/* Display a message and get the input +** +** On entry, +** Msg is the message. +** +** On exit, +** Return value is malloc'd string which must be freed. +*/ +extern char * HTPrompt PARAMS((CONST char * Msg, CONST char * deflt)); + + +/* Display a message, don't wait for input +** +** On entry, +** The input is a list of parameters for printf. +*/ +extern void HTAlert PARAMS((CONST char * Msg)); + + +/* Display a progress message for information (and diagnostics) only +** +** On entry, +** The input is a list of parameters for printf. +*/ +extern void HTProgress PARAMS((CONST char * Msg)); +extern BOOLEAN mustshow; +#define _HTProgress(msg) mustshow = TRUE, HTProgress(msg) + + +/* Display a message, then wait for 'yes' or 'no'. +** +** On entry, +** Takes a list of parameters for printf. +** +** On exit, +** If the user enters 'YES', returns TRUE, returns FALSE +** otherwise. +*/ +extern BOOL HTConfirm PARAMS ((CONST char * Msg)); + + +/* Prompt for password without echoing the reply +*/ +extern char * HTPromptPassword PARAMS((CONST char * Msg)); + +/* Prompt both username and password HTPromptUsernameAndPassword() +** --------------------------------- +** On entry, +** Msg is the prompting message. +** *username and +** *password are char pointers; they are changed +** to point to result strings. +** IsProxy should be TRUE if this is for +** proxy authentication. +** +** If *username is not NULL, it is taken +** to point to a default value. +** Initial value of *password is +** completely discarded. +** +** On exit, +** *username and *password point to newly allocated +** strings -- original strings pointed to by them +** are NOT freed. +** +*/ +extern void HTPromptUsernameAndPassword PARAMS(( + CONST char * Msg, + char ** username, + char ** password, + BOOL IsProxy)); + + +/* Confirm a cookie operation. HTConfirmCookie() +** --------------------------- +** +** On entry, +** server is the server sending the Set-Cookie. +** domain is the domain of the cookie. +** path is the path of the cookie. +** name is the name of the cookie. +** value is the value of the cookie. +** +** On exit, +** Returns FALSE on cancel, +** TRUE if the cookie should be set. +*/ +extern BOOL HTConfirmCookie PARAMS(( + void * dp, + CONST char * server, + CONST char * domain, + CONST char * path, + CONST char * name, + CONST char * value)); + + +/* Confirm redirection of POST. HTConfirmPostRedirect() +** ---------------------------- +** On entry, +** redirecting_url is the Location. +** server_status is the server status code. +** +** On exit, +** Returns 0 on cancel, +** 1 for redirect of POST with content, +** 303 for redirect as GET without content +*/ +extern int HTConfirmPostRedirect PARAMS(( + CONST char * redirecting_url_arg, + int server_status)); + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.c new file mode 100644 index 00000000000..6f8c0d3fbd1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.c @@ -0,0 +1,1325 @@ +/* Hypertext "Anchor" Object HTAnchor.c +** ========================== +** +** An anchor represents a region of a hypertext document which is linked to +** another anchor in the same or a different document. +** +** History +** +** Nov 1990 Written in Objective-C for the NeXT browser (TBL) +** 24-Oct-1991 (JFG), written in C, browser-independant +** 21-Nov-1991 (JFG), first complete version +** +** (c) Copyright CERN 1991 - See Copyright.html +*/ + +#define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */ + +#include "HTUtils.h" +#include "tcp.h" +#include <ctype.h> +#include "HTAnchor.h" +#include "HTParse.h" +#include "UCAux.h" +#include "UCMap.h" + +#include "LYCharSets.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#ifdef NOT_DEFINED +/* + * This is the hashing function used to determine which list in the + * adult_table a parent anchor should be put in. This is a + * much simpler function than the original used. + */ +#define HASH_FUNCTION(cp_address) ((unsigned short int)strlen(cp_address) *\ + (unsigned short int)TOUPPER(*cp_address) % HASH_SIZE) +#endif /* NOT_DEFINED */ +/* + * This is the original function. We'll use it again. - FM + */ +PRIVATE int HASH_FUNCTION ARGS1( + CONST char *, cp_address) +{ + int hash; + unsigned char *p; + + for (p = (unsigned char *)cp_address, hash = 0; *p; p++) + hash = (int) (hash * 3 + (*(unsigned char *)p)) % HASH_SIZE; + + return hash; +} + +typedef struct _HyperDoc Hyperdoc; +#ifdef VMS +struct _HyperDoc { + int junk; /* VMS cannot handle pointers to undefined structs */ +}; +#endif /* VMS */ + +PRIVATE HTList **adult_table = 0; /* Point to table of lists of all parents */ + +/* Creation Methods +** ================ +** +** Do not use "new" by itself outside this module. In order to enforce +** consistency, we insist that you furnish more information about the +** anchor you are creating : use newWithParent or newWithAddress. +*/ +PRIVATE HTParentAnchor * HTParentAnchor_new NOARGS +{ + HTParentAnchor *newAnchor = + (HTParentAnchor *)calloc(1, sizeof(HTParentAnchor)); /* zero-filled */ + newAnchor->parent = newAnchor; + newAnchor->bookmark = NULL; /* Bookmark filename. - FM */ + newAnchor->isISMAPScript = FALSE; /* Lynx appends ?0,0 if TRUE. - FM */ + newAnchor->isHEAD = FALSE; /* HEAD request if TRUE. - FM */ + newAnchor->safe = FALSE; /* Safe. - FM */ + newAnchor->FileCache = NULL; /* Path to a disk-cached copy. - FM */ + newAnchor->SugFname = NULL; /* Suggested filename. - FM */ + newAnchor->RevTitle = NULL; /* TITLE for a LINK with REV. - FM */ + newAnchor->cache_control = NULL; /* Cache-Control. - FM */ + newAnchor->no_cache = FALSE; /* no-cache? - FM */ + newAnchor->content_type = NULL; /* Content-Type. - FM */ + newAnchor->content_language = NULL; /* Content-Language. - FM */ + newAnchor->content_encoding = NULL; /* Compression algorith. - FM */ + newAnchor->content_base = NULL; /* Content-Base. - FM */ + newAnchor->content_disposition = NULL; /* Content-Disposition. - FM */ + newAnchor->content_location = NULL; /* Content-Location. - FM */ + newAnchor->content_md5 = NULL; /* Content-MD5. - FM */ + newAnchor->content_length = 0; /* Content-Length. - FM */ + newAnchor->date = NULL; /* Date. - FM */ + newAnchor->expires = NULL; /* Expires. - FM */ + newAnchor->last_modified = NULL; /* Last-Modified. - FM */ + newAnchor->server = NULL; /* Server. - FM */ + return newAnchor; +} + +PRIVATE HTChildAnchor * HTChildAnchor_new NOARGS +{ + return (HTChildAnchor *)calloc(1, sizeof(HTChildAnchor)); /* zero-filled */ +} + + +#ifdef CASE_INSENSITIVE_ANCHORS +/* Case insensitive string comparison +** ---------------------------------- +** On entry, +** s Points to one string, null terminated +** t points to the other. +** On exit, +** returns YES if the strings are equivalent ignoring case +** NO if they differ in more than their case. +*/ +PRIVATE BOOL HTEquivalent ARGS2( + CONST char *, s, + CONST char *, t) +{ + if (s && t) { /* Make sure they point to something */ + for (; *s && *t; s++, t++) { + if (TOUPPER(*s) != TOUPPER(*t)) { + return NO; + } + } + return TOUPPER(*s) == TOUPPER(*t); + } else { + return s == t; /* Two NULLs are equivalent, aren't they ? */ + } +} + +#else + +/* Case sensitive string comparison +** ---------------------------------- +** On entry, +** s Points to one string, null terminated +** t points to the other. +** On exit, +** returns YES if the strings are identical or both NULL +** NO if they differ. +*/ +PRIVATE BOOL HTIdentical ARGS2( + CONST char *, s, + CONST char *, t) +{ + if (s && t) { /* Make sure they point to something */ + for (; *s && *t; s++, t++) { + if (*s != *t) { + return NO; + } + } + return *s == *t; + } else { + return s == t; /* Two NULLs are identical, aren't they ? */ + } +} +#endif /* CASE_INSENSITIVE_ANCHORS */ + + +/* Create new or find old sub-anchor +** --------------------------------- +** +** Me one is for a new anchor being edited into an existing +** document. The parent anchor must already exist. +*/ +PUBLIC HTChildAnchor * HTAnchor_findChild ARGS2( + HTParentAnchor *, parent, + CONST char *, tag) +{ + HTChildAnchor *child; + HTList *kids; + + if (!parent) { + if (TRACE) + fprintf(stderr, "HTAnchor_findChild called with NULL parent.\n"); + return NULL; + } + if ((kids = parent->children) != 0) { + /* + ** Parent has children. Search them. + */ + if (tag && *tag) { /* TBL */ + while (NULL != (child=(HTChildAnchor *)HTList_nextObject(kids))) { +#ifdef CASE_INSENSITIVE_ANCHORS + if (HTEquivalent(child->tag, tag)) { /* Case insensitive */ +#else + if (HTIdentical(child->tag, tag)) { /* Case sensitive - FM */ +#endif /* CASE_INSENSITIVE_ANCHORS */ + if (TRACE) + fprintf(stderr, + "Child anchor %p of parent %p with name `%s' already exists.\n", + (void *)child, (void *)parent, tag); + return child; + } + } + } /* end if tag is void */ + } else { /* parent doesn't have any children yet : create family */ + parent->children = HTList_new(); + } + + child = HTChildAnchor_new(); + if (TRACE) + fprintf(stderr, + "new Anchor %p named `%s' is child of %p\n", + (void *)child, + tag ? tag : (CONST char *)"", + (void *)parent); /* int for apollo */ + HTList_addObject (parent->children, child); + child->parent = parent; + StrAllocCopy(child->tag, tag); + return child; +} + + +/* Create or find a child anchor with a possible link +** -------------------------------------------------- +** +** Create new anchor with a given parent and possibly +** a name, and possibly a link to a _relatively_ named anchor. +** (Code originally in ParseHTML.h) +*/ +PUBLIC HTChildAnchor * HTAnchor_findChildAndLink ARGS4( + HTParentAnchor *, parent, /* May not be 0 */ + CONST char *, tag, /* May be "" or 0 */ + CONST char *, href, /* May be "" or 0 */ + HTLinkType *, ltype) /* May be 0 */ +{ + HTChildAnchor * child = HTAnchor_findChild(parent, tag); + + if (TRACE) + fprintf(stderr,"Entered HTAnchor_findChildAndLink\n"); + + if (href && *href) { + char *relative_to = HTAnchor_address((HTAnchor *)parent); + DocAddress parsed_doc; + HTAnchor * dest; + + parsed_doc.address = HTParse(href, relative_to, PARSE_ALL); +#ifndef DONT_TRACK_INTERNAL_LINKS + if (ltype && parent->post_data && ltype == LINK_INTERNAL) { + /* for internal links, find a destination with the same + post data if the source of the link has post data. - kw */ + parsed_doc.post_data = parent->post_data; + parsed_doc.post_content_type = parent->post_content_type; + } else +#endif + { + parsed_doc.post_data = NULL; + parsed_doc.post_content_type = NULL; + } + parsed_doc.bookmark = NULL; + parsed_doc.isHEAD = FALSE; + parsed_doc.safe = FALSE; + dest = HTAnchor_findAddress(&parsed_doc); + + HTAnchor_link((HTAnchor *)child, dest, ltype); + FREE(parsed_doc.address); + FREE(relative_to); + } + return child; +} + +/* +** Function for freeing the adult hash table. - FM +*/ +PRIVATE void free_adult_table NOARGS +{ + int i_counter; + HTList * HTAp_freeme; + HTParentAnchor * parent; + /* + * Loop through all lists. + */ + for (i_counter = 0; i_counter < HASH_SIZE; i_counter++) { + /* + ** Loop through the list. + */ + while (adult_table[i_counter] != NULL) { + /* + ** Free off items - FM + */ + HTAp_freeme = adult_table[i_counter]; + adult_table[i_counter] = HTAp_freeme->next; + if (HTAp_freeme->object) { + parent = (HTParentAnchor *)HTAp_freeme->object; + HTAnchor_delete(parent); + } + FREE(HTAp_freeme); + } + } + FREE(adult_table); +} + +/* Create new or find old named anchor +** ----------------------------------- +** +** Me one is for a reference which is found in a document, and might +** not be already loaded. +** Note: You are not guaranteed a new anchor -- you might get an old one, +** like with fonts. +*/ +PUBLIC HTAnchor * HTAnchor_findAddress ARGS1( + CONST DocAddress *, newdoc) +{ + /* Anchor tag specified ? */ + char *tag = HTParse(newdoc->address, "", PARSE_ANCHOR); + + if (TRACE) + fprintf(stderr,"Entered HTAnchor_findAddress\n"); + + /* + ** If the address represents a sub-anchor, we recursively load its + ** parent, then we create a child anchor within that document. + */ + if (*tag) { + DocAddress parsed_doc; + HTParentAnchor * foundParent; + HTChildAnchor * foundAnchor; + + parsed_doc.address = HTParse(newdoc->address, "", + PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION); + parsed_doc.post_data = newdoc->post_data; + parsed_doc.post_content_type = newdoc->post_content_type; + parsed_doc.bookmark = newdoc->bookmark; + parsed_doc.isHEAD = newdoc->isHEAD; + parsed_doc.safe = newdoc->safe; + + foundParent = (HTParentAnchor *)HTAnchor_findAddress(&parsed_doc); + foundAnchor = HTAnchor_findChild (foundParent, tag); + FREE(parsed_doc.address); + FREE(tag); + return (HTAnchor *)foundAnchor; + } else { + /* + ** If the address has no anchor tag, + ** check whether we have this node. + */ + int hash; + HTList * adults; + HTList *grownups; + HTParentAnchor * foundAnchor; + + FREE(tag); + + /* + ** Select list from hash table, + */ + hash = HASH_FUNCTION(newdoc->address); + if (!adult_table) { + adult_table = (HTList **)calloc(HASH_SIZE, sizeof(HTList *)); + atexit(free_adult_table); + } + if (!adult_table[hash]) + adult_table[hash] = HTList_new(); + adults = adult_table[hash]; + + /* + ** Search list for anchor. + */ + grownups = adults; + while (NULL != (foundAnchor = + (HTParentAnchor *)HTList_nextObject(grownups))) { +#ifdef CASE_INSENSITIVE_ANCHORS + if (HTEquivalent(foundAnchor->address, newdoc->address) && + HTEquivalent(foundAnchor->post_data, newdoc->post_data) && + foundAnchor->isHEAD == newdoc->isHEAD) +#else + if (HTIdentical(foundAnchor->address, newdoc->address) && + HTIdentical(foundAnchor->post_data, newdoc->post_data) && + foundAnchor->isHEAD == newdoc->isHEAD) +#endif /* CASE_INSENSITIVE_ANCHORS */ + { + if (TRACE) + fprintf(stderr, + "Anchor %p with address `%s' already exists.\n", + (void *)foundAnchor, newdoc->address); + return (HTAnchor *)foundAnchor; + } + } + + /* + ** Node not found: create new anchor. + */ + foundAnchor = HTParentAnchor_new(); + if (TRACE) + fprintf(stderr, + "New anchor %p has hash %d and address `%s'\n", + (void *)foundAnchor, hash, newdoc->address); + StrAllocCopy(foundAnchor->address, newdoc->address); + if (newdoc->post_data) + StrAllocCopy(foundAnchor->post_data, newdoc->post_data); + if (newdoc->post_content_type) + StrAllocCopy(foundAnchor->post_content_type, + newdoc->post_content_type); + if (newdoc->bookmark) + StrAllocCopy(foundAnchor->bookmark, newdoc->bookmark); + foundAnchor->isHEAD = newdoc->isHEAD; + foundAnchor->safe = newdoc->safe; + HTList_addObject (adults, foundAnchor); + return (HTAnchor *)foundAnchor; + } +} + + +/* Delete an anchor and possibly related things (auto garbage collection) +** -------------------------------------------- +** +** The anchor is only deleted if the corresponding document is not loaded. +** All outgoing links from parent and children are deleted, and this anchor +** is removed from the sources list of all its targets. +** We also try to delete the targets whose documents are not loaded. +** If this anchor's source list is empty, we delete it and its children. +*/ +PRIVATE void deleteLinks ARGS1( + HTAnchor *, me) +{ + /* + * Memory leaks fixed. + * 05-27-94 Lynx 2-3-1 Garrett Arch Blythe + */ + + /* + * Anchor is NULL, do nothing. + */ + if (!me) { + return; + } + + /* + * Unregister me with our mainLink destination anchor's parent. + */ + if (me->mainLink.dest) { + HTParentAnchor *parent = me->mainLink.dest->parent; + + /* + * Remove me from the parent's sources so that the + * parent knows one less anchor is it's dest. + */ + if (!HTList_isEmpty(parent->sources)) { + /* + * Really should only need to deregister once. + */ + HTList_removeObject(parent->sources, (void *)me); + } + + /* + * Test here to avoid calling overhead. + * If the parent has no loaded document, then we should + * tell it to attempt to delete itself. + * Don't do this jass if the anchor passed in is the same + * as the anchor to delete. + * Also, don't do this if the destination parent is our + * parent. + */ + if (!parent->document && + parent != (HTParentAnchor *)me && + me->parent != parent) { + HTAnchor_delete(parent); + } + + /* + * At this point, we haven't a mainLink. Set it to be + * so. + * Leave the HTAtom pointed to by type up to other code to + * handle (reusable, near static). + */ + me->mainLink.dest = NULL; + me->mainLink.type = NULL; + } + + /* + * Check for extra destinations in our links list. + */ + if (!HTList_isEmpty(me->links)) { + HTLink *target; + HTParentAnchor *parent; + + /* + * Take out our extra non mainLinks one by one, calling + * their parents to know that they are no longer + * the destination of me's anchor. + */ + while ((target = (HTLink *)HTList_removeLastObject(me->links)) != 0) { + parent = target->dest->parent; + if (!HTList_isEmpty(parent->sources)) { + /* + * Only need to tell destination parent + * anchor once. + */ + HTList_removeObject(parent->sources, (void *)me); + } + + /* + * Avoid calling overhead. + * If the parent hasn't a loaded document, then + * we will attempt to have the parent + * delete itself. + * Don't call twice if this is the same anchor + * that we are trying to delete. + * Also, don't do this if we are trying to delete + * our parent. + */ + if (!parent->document && + (HTParentAnchor *)me != parent && + me->parent != parent) { + HTAnchor_delete(parent); + } + /* + * The link structure has to be deleted, too! + * That was missing, but this code probably never + * got exercised by Lynx. - KW + */ + FREE(target); + } + + /* + * At this point, me no longer has any destination in + * the links list. Get rid of it. + */ + if (me->links) { + HTList_delete(me->links); + me->links = NULL; + } + } + + /* + * Catch in case links list exists but nothing in it. + */ + if (me->links) { + HTList_delete(me->links); + me->links = NULL; + } +} + +PUBLIC BOOL HTAnchor_delete ARGS1( + HTParentAnchor *, me) +{ + /* + * Memory leaks fixed. + * 05-27-94 Lynx 2-3-1 Garrett Arch Blythe + */ + HTList *cur; + HTChildAnchor *child; + + /* + * Do nothing if nothing to do. + */ + if (!me) { + return(NO); + } + + /* + * Don't delete if document is loaded or being loaded. + */ + if (me->document || me->underway) { + return(NO); + } + + /* + * Recursively try to delete destination anchors of this parent. + * In any event, this will tell all destination anchors that we + * no longer consider them a destination. + */ + deleteLinks((HTAnchor *)me); + + /* + * There are still incoming links to this one (we are the + * destination of another anchor). + * Don't actually delete this anchor, but children are OK to + * delete their links. + */ + if (!HTList_isEmpty(me->sources)) { + /* + * Delete all outgoing links from children, do not + * delete the children, though. + */ + if (!HTList_isEmpty(me->children)) { + cur = me->children; + while ((child = (HTChildAnchor *)HTList_nextObject(cur)) != 0) { + if (child != NULL) { + deleteLinks((HTAnchor *)child); + } + } + } + + /* + * Can't delete parent, still have sources. + */ + return(NO); + } + + /* + * No more incoming links : kill everything + * First, recursively delete children and their links. + */ + if (!HTList_isEmpty(me->children)) { + while ((child = (HTChildAnchor *)HTList_removeLastObject( + me->children)) != 0) { + if (child) { + deleteLinks((HTAnchor *)child); + if (child->tag) { + FREE(child->tag); + } + FREE(child); + } + } + } + + /* + * Delete our empty list of children. + */ + if (me->children) { + HTList_delete(me->children); + me->children = NULL; + } + + /* + * Delete our empty list of sources. + */ + if (me->sources) { + HTList_delete(me->sources); + me->sources = NULL; + } + + /* + * Delete the methods list. + */ + if (me->methods) { + /* + * Leave what the methods point to up in memory for + * other code (near static stuff). + */ + HTList_delete(me->methods); + me->methods = NULL; + } + + /* + * Free up all allocated members. + */ + FREE(me->charset); + FREE(me->isIndexAction); + FREE(me->isIndexPrompt); + FREE(me->title); + FREE(me->physical); + FREE(me->post_data); + FREE(me->post_content_type); + FREE(me->bookmark); + FREE(me->owner); + FREE(me->RevTitle); + if (me->FileCache) { + FILE *fd; + if ((fd = fopen(me->FileCache, "r")) != NULL) { + fclose(fd); + remove(me->FileCache); + } + FREE(me->FileCache); + } + FREE(me->SugFname); + FREE(me->cache_control); + FREE(me->content_type); + FREE(me->content_language); + FREE(me->content_encoding); + FREE(me->content_base); + FREE(me->content_disposition); + FREE(me->content_location); + FREE(me->content_md5); + FREE(me->date); + FREE(me->expires); + FREE(me->last_modified); + FREE(me->server); +#ifdef USE_HASH + FREE(me->style); +#endif + + /* + * Remove ourselves from the hash table's list. + */ + if (adult_table) { + unsigned short int usi_hash = HASH_FUNCTION(me->address); + + if (adult_table[usi_hash]) { + HTList_removeObject(adult_table[usi_hash], (void *)me); + } + } + + /* + * Original code wanted a way to clean out the HTFormat if no + * longer needed (ref count?). I'll leave it alone since + * those HTAtom objects are a little harder to know where + * they are being referenced all at one time. (near static) + */ + + /* + * Free the address. + */ + FREE(me->address); + + FREE (me->UCStages); + ImageMapList_free(me->imaps); + + + /* + * Finally, kill the parent anchor passed in. + */ + FREE(me); + + return(YES); +} + + +/* Move an anchor to the head of the list of its siblings +** ------------------------------------------------------ +** +** This is to ensure that an anchor which might have already existed +** is put in the correct order as we load the document. +*/ +PUBLIC void HTAnchor_makeLastChild ARGS1( + HTChildAnchor *, me) +{ + if (me->parent != (HTParentAnchor *)me) { /* Make sure it's a child */ + HTList * siblings = me->parent->children; + HTList_removeObject (siblings, me); + HTList_addObject (siblings, me); + } +} + +/* Data access functions +** --------------------- +*/ +PUBLIC HTParentAnchor * HTAnchor_parent ARGS1( + HTAnchor *, me) +{ + return me ? me->parent : NULL; +} + +PUBLIC void HTAnchor_setDocument ARGS2( + HTParentAnchor *, me, + HyperDoc *, doc) +{ + if (me) + me->document = doc; +} + +PUBLIC HyperDoc * HTAnchor_document ARGS1( + HTParentAnchor *, me) +{ + return me ? me->document : NULL; +} + + +/* We don't want code to change an address after anchor creation... yet ? +PUBLIC void HTAnchor_setAddress ARGS2( + HTAnchor *, me, + char *, addr) +{ + if (me) + StrAllocCopy (me->parent->address, addr); +} +*/ + +PUBLIC char * HTAnchor_address ARGS1( + HTAnchor *, me) +{ + char *addr = NULL; + + if (me) { + if (((HTParentAnchor *)me == me->parent) || + !((HTChildAnchor *)me)->tag) { /* it's an adult or no tag */ + StrAllocCopy(addr, me->parent->address); + } else { /* it's a named child */ + addr = malloc(2 + + strlen(me->parent->address) + + strlen(((HTChildAnchor *)me)->tag)); + if (addr == NULL) + outofmem(__FILE__, "HTAnchor_address"); + sprintf(addr, "%s#%s", + me->parent->address, ((HTChildAnchor *)me)->tag); + } + } + return addr; +} + +PUBLIC void HTAnchor_setFormat ARGS2( + HTParentAnchor *, me, + HTFormat, form) +{ + if (me) + me->format = form; +} + +PUBLIC HTFormat HTAnchor_format ARGS1( + HTParentAnchor *, me) +{ + return me ? me->format : NULL; +} + +PUBLIC void HTAnchor_setIndex ARGS2( + HTParentAnchor *, me, + char *, address) +{ + if (me) { + me->isIndex = YES; + StrAllocCopy(me->isIndexAction, address); + } +} + +PUBLIC void HTAnchor_setPrompt ARGS2( + HTParentAnchor *, me, + char *, prompt) +{ + if (me) { + StrAllocCopy(me->isIndexPrompt, prompt); + } +} + +PUBLIC BOOL HTAnchor_isIndex ARGS1( + HTParentAnchor *, me) +{ + return me ? me->isIndex : NO; +} + +/* Whether Anchor has been designated as an ISMAP link +** (normally by presence of an ISMAP attribute on A or IMG) - KW +*/ +PUBLIC BOOL HTAnchor_isISMAPScript ARGS1( + HTAnchor *, me) +{ + return me ? me->parent->isISMAPScript : NO; +} + +PUBLIC BOOL HTAnchor_hasChildren ARGS1( + HTParentAnchor *, me) +{ + return me ? ! HTList_isEmpty(me->children) : NO; +} + +#if defined(USE_HASH) +/* Style handling. +*/ +PUBLIC CONST char * HTAnchor_style ARGS1( + HTParentAnchor *, me) +{ + return me ? me->style : NULL; +} + +PUBLIC void HTAnchor_setStyle ARGS2( + HTParentAnchor *, me, + CONST char *, style) +{ + if (me) { + StrAllocCopy(me->style, style); + } +} +#endif + + +/* Title handling. +*/ +PUBLIC CONST char * HTAnchor_title ARGS1( + HTParentAnchor *, me) +{ + return me ? me->title : NULL; +} + +PUBLIC void HTAnchor_setTitle ARGS2( + HTParentAnchor *, me, + CONST char *, title) +{ + int i; + + if (me) { + StrAllocCopy(me->title, title); + for (i = 0; me->title[i]; i++) { + if ((unsigned char)me->title[i] == 1 || + (unsigned char)me->title[i] == 2) { + me->title[i] = ' '; + } + } + } +} + +PUBLIC void HTAnchor_appendTitle ARGS2( + HTParentAnchor *, me, + CONST char *, title) +{ + int i; + + if (me) { + StrAllocCat(me->title, title); + for (i = 0; me->title[i]; i++) { + if ((unsigned char)me->title[i] == 1 || + (unsigned char)me->title[i] == 2) { + me->title[i] = ' '; + } + } + } +} + +/* Bookmark handling. +*/ +PUBLIC CONST char * HTAnchor_bookmark ARGS1( + HTParentAnchor *, me) +{ + return me ? me->bookmark : NULL; +} + +PUBLIC void HTAnchor_setBookmark ARGS2( + HTParentAnchor *, me, + CONST char *, bookmark) +{ + if (me) + StrAllocCopy(me->bookmark, bookmark); +} + +/* Owner handling. +*/ +PUBLIC CONST char * HTAnchor_owner ARGS1( + HTParentAnchor *, me) +{ + return (me ? me->owner : NULL); +} + +PUBLIC void HTAnchor_setOwner ARGS2( + HTParentAnchor *, me, + CONST char *, owner) +{ + if (me) { + StrAllocCopy(me->owner, owner); + } +} + +/* TITLE handling in LINKs with REV="made" or REV="owner". - FM +*/ +PUBLIC CONST char * HTAnchor_RevTitle ARGS1( + HTParentAnchor *, me) +{ + return (me ? me->RevTitle : NULL); +} + +PUBLIC void HTAnchor_setRevTitle ARGS2( + HTParentAnchor *, me, + CONST char *, title) +{ + int i; + + if (me) { + StrAllocCopy(me->RevTitle, title); + for (i = 0; me->RevTitle[i]; i++) { + if ((unsigned char)me->RevTitle[i] == 1 || + (unsigned char)me->RevTitle[i] == 2) { + me->RevTitle[i] = ' '; + } + } + } +} + +/* Suggested filename handling. - FM +** (will be loaded if we had a Content-Disposition +** header or META element with filename=name.suffix) +*/ +PUBLIC CONST char * HTAnchor_SugFname ARGS1( + HTParentAnchor *, me) +{ + return me ? me->SugFname : NULL; +} + +/* Content-Encoding handling. - FM +** (will be loaded if we had a Content-Encoding +** header.) +*/ +PUBLIC CONST char * HTAnchor_content_encoding ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_encoding : NULL; +} + +/* Content-Type handling. - FM +*/ +PUBLIC CONST char * HTAnchor_content_type ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_type : NULL; +} + +/* Last-Modified header handling. - FM +*/ +PUBLIC CONST char * HTAnchor_last_modified ARGS1( + HTParentAnchor *, me) +{ + return me ? me->last_modified : NULL; +} + +/* Date header handling. - FM +*/ +PUBLIC CONST char * HTAnchor_date ARGS1( + HTParentAnchor *, me) +{ + return me ? me->date : NULL; +} + +/* Server header handling. - FM +*/ +PUBLIC CONST char * HTAnchor_server ARGS1( + HTParentAnchor *, me) +{ + return me ? me->server : NULL; +} + +/* Safe header handling. - FM +*/ +PUBLIC BOOL HTAnchor_safe ARGS1( + HTParentAnchor *, me) +{ + return me ? me->safe : FALSE; +} + +/* Content-Base header handling. - FM +*/ +PUBLIC CONST char * HTAnchor_content_base ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_base : NULL; +} + +/* Content-Location header handling. - FM +*/ +PUBLIC CONST char * HTAnchor_content_location ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_location : NULL; +} + +/* Link me Anchor to another given one +** ------------------------------------- +*/ +PUBLIC BOOL HTAnchor_link ARGS3( + HTAnchor *, source, + HTAnchor *, destination, + HTLinkType *, type) +{ + if (!(source && destination)) + return NO; /* Can't link to/from non-existing anchor */ + if (TRACE) + fprintf(stderr, + "Linking anchor %p to anchor %p\n", source, destination); + if (!source->mainLink.dest) { + source->mainLink.dest = destination; + source->mainLink.type = type; + } else { + HTLink * newLink = (HTLink *)calloc (1, sizeof (HTLink)); + if (newLink == NULL) + outofmem(__FILE__, "HTAnchor_link"); + newLink->dest = destination; + newLink->type = type; + if (!source->links) + source->links = HTList_new(); + HTList_addObject (source->links, newLink); + } + if (!destination->parent->sources) + destination->parent->sources = HTList_new(); + HTList_addObject (destination->parent->sources, source); + return YES; /* Success */ +} + + +/* Manipulation of links +** --------------------- +*/ +PUBLIC HTAnchor * HTAnchor_followMainLink ARGS1( + HTAnchor *, me) +{ + return me->mainLink.dest; +} + +PUBLIC HTAnchor * HTAnchor_followTypedLink ARGS2( + HTAnchor *, me, + HTLinkType *, type) +{ + if (me->mainLink.type == type) + return me->mainLink.dest; + if (me->links) { + HTList *links = me->links; + HTLink *the_link; + while (NULL != (the_link=(HTLink *)HTList_nextObject(links))) { + if (the_link->type == type) { + return the_link->dest; + } + } + } + return NULL; /* No link of me type */ +} + + +/* Make main link +*/ +PUBLIC BOOL HTAnchor_makeMainLink ARGS2( + HTAnchor *, me, + HTLink *, movingLink) +{ + /* Check that everything's OK */ + if (!(me && HTList_removeObject (me->links, movingLink))) { + return NO; /* link not found or NULL anchor */ + } else { + /* First push current main link onto top of links list */ + HTLink *newLink = (HTLink *)calloc (1, sizeof (HTLink)); + if (newLink == NULL) + outofmem(__FILE__, "HTAnchor_makeMainLink"); + memcpy((void *)newLink, + (CONST char *)&me->mainLink, sizeof (HTLink)); + HTList_addObject (me->links, newLink); + + /* Now make movingLink the new main link, and free it */ + memcpy((void *)&me->mainLink, + (CONST void *)movingLink, sizeof (HTLink)); + FREE(movingLink); + return YES; + } +} + + +/* Methods List +** ------------ +*/ +PUBLIC HTList * HTAnchor_methods ARGS1( + HTParentAnchor *, me) +{ + if (!me->methods) { + me->methods = HTList_new(); + } + return me->methods; +} + +/* Protocol +** -------- +*/ +PUBLIC void * HTAnchor_protocol ARGS1( + HTParentAnchor *, me) +{ + return me->protocol; +} + +PUBLIC void HTAnchor_setProtocol ARGS2( + HTParentAnchor *, me, + void*, protocol) +{ + me->protocol = protocol; +} + +/* Physical Address +** ---------------- +*/ +PUBLIC char * HTAnchor_physical ARGS1( + HTParentAnchor *, me) +{ + return me->physical; +} + +PUBLIC void HTAnchor_setPhysical ARGS2( + HTParentAnchor *, me, + char *, physical) +{ + if (me) { + StrAllocCopy(me->physical, physical); + } +} + +/* +** We store charset info in the HTParentAnchor object, for several +** "stages". (See UCDefs.h) +** A stream method is supposed to know what stage in the model it is. +** +** General model MIME -> parser -> structured -> HText +** e.g., text/html +** from HTTP: HTMIME.c -> SGML.c -> HTML.c -> GridText.c +** text/plain +** from file: HTFile.c -> HTPlain.c -> GridText.c +** +** The lock/set_by is used to lock e.g. a charset set by an explicit +** HTTP MIME header against overriding by a HTML META tag - the MIME +** header has higher priority. Defaults (from -assume_.. options etc.) +** will not override charset explicitly given by server. +** +** Some advantages of keeping this in the HTAnchor: +** - Global variables are bad. +** - Can remember a charset given by META tag when toggling to SOURCE view. +** - Can remember a charset given by <A CHARSET=...> href in another doc. +** +** We don't modify the HTParentAnchor's charset element +** here, that one will only be set when explicitly given. +*/ +PUBLIC LYUCcharset * HTAnchor_getUCInfoStage ARGS2( + HTParentAnchor *, me, + int, which_stage) +{ + if (me && !me->UCStages) { + int i; + int chndl = UCLYhndl_for_unspec; + UCAnchorInfo * stages = (UCAnchorInfo*)calloc(1, + sizeof(UCAnchorInfo)); + if (stages == NULL) + outofmem(__FILE__, "HTAnchor_getUCInfoStage"); + for (i = 0; i < UCT_STAGEMAX; i++) { + stages->s[i].C.MIMEname = ""; + stages->s[i].LYhndl = -1; + } + if (me->charset) { + chndl = UCGetLYhndl_byMIME(me->charset); + if (chndl < 0) { + chndl = UCLYhndl_for_unrec; + } + } + if (chndl >= 0) { + memcpy(&stages->s[UCT_STAGE_MIME].C, &LYCharSet_UC[chndl], + sizeof(LYUCcharset)); + stages->s[UCT_STAGE_MIME].lock = UCT_SETBY_DEFAULT; + } else { + /* + * Should not happen... + */ + stages->s[UCT_STAGE_MIME].C.UChndl = -1; + stages->s[UCT_STAGE_MIME].lock = UCT_SETBY_NONE; + } + stages->s[UCT_STAGE_MIME].LYhndl = chndl; + me->UCStages = stages; + } + if (me) { + return &me->UCStages->s[which_stage].C; + } + return NULL; +} + +PUBLIC int HTAnchor_getUCLYhndl ARGS2( + HTParentAnchor *, me, + int, which_stage) +{ + if (me) { + if (!me->UCStages) { + /* + * This will allocate and initialize, if not yet done. + */ + (void) HTAnchor_getUCInfoStage(me, which_stage); + } + if (me->UCStages->s[which_stage].lock > UCT_SETBY_NONE) { + return me->UCStages->s[which_stage].LYhndl; + } + } + return -1; +} + +PUBLIC LYUCcharset * HTAnchor_setUCInfoStage ARGS4( + HTParentAnchor *, me, + int, LYhndl, + int, which_stage, + int, set_by) +{ + if (me) { + /* + * This will allocate and initialize, if not yet done. + */ + LYUCcharset * p = HTAnchor_getUCInfoStage(me, which_stage); + /* + * Can we override? + */ + if (set_by >= me->UCStages->s[which_stage].lock) { + me->UCStages->s[which_stage].lock = set_by; + me->UCStages->s[which_stage].LYhndl = LYhndl; + if (LYhndl >= 0) { + memcpy(p, &LYCharSet_UC[LYhndl], sizeof(LYUCcharset)); + } + else { + p->UChndl = -1; + } + return p; + } + } + return NULL; +} + +PUBLIC LYUCcharset * HTAnchor_resetUCInfoStage ARGS4( + HTParentAnchor *, me, + int, LYhndl, + int, which_stage, + int, set_by) +{ + if (!me || !me->UCStages) + return NULL; + me->UCStages->s[which_stage].lock = set_by; + me->UCStages->s[which_stage].LYhndl = LYhndl; + return &me->UCStages->s[which_stage].C; +} + +/* +** A set_by of (-1) means use the lock value from the from_stage. +*/ +PUBLIC LYUCcharset * HTAnchor_copyUCInfoStage ARGS4( + HTParentAnchor *, me, + int, to_stage, + int, from_stage, + int, set_by) +{ + if (me) { + /* + * This will allocate and initialize, if not yet done. + */ + LYUCcharset * p_from = HTAnchor_getUCInfoStage(me, from_stage); + LYUCcharset * p_to = HTAnchor_getUCInfoStage(me, to_stage); + /* + * Can we override? + */ + if (set_by == -1) + set_by = me->UCStages->s[from_stage].lock; + if (set_by == UCT_SETBY_NONE) + set_by = UCT_SETBY_DEFAULT; + if (set_by >= me->UCStages->s[to_stage].lock) { + me->UCStages->s[to_stage].lock = set_by; + me->UCStages->s[to_stage].LYhndl = + me->UCStages->s[from_stage].LYhndl; + if (p_to != p_from) + memcpy(p_to, p_from, sizeof(LYUCcharset)); + return p_to; + } + } + return NULL; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.h new file mode 100644 index 00000000000..e3847184045 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.h @@ -0,0 +1,447 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTAnchor.html + */ + +/* Hypertext "Anchor" Object HTAnchor.h +** ========================== +** +** An anchor represents a region of a hypertext document which is linked +** to another anchor in the same or a different document. +*/ + +#ifndef HTANCHOR_H +#define HTANCHOR_H + +/* Version 0 (TBL) written in Objective-C for the NeXT browser */ +/* Version 1 of 24-Oct-1991 (JFG), written in C, browser-independant */ + +#include "HTList.h" +#include "HTAtom.h" +#include "UCDefs.h" + +#ifdef SHORT_NAMES +#define HTAnchor_findChild HTAnFiCh +#define HTAnchor_findChildAndLink HTAnFiLi +#define HTAnchor_findAddress HTAnFiAd +#define HTAnchor_delete HTAnDele +#define HTAnchor_makeLastChild HTAnMaLa +#define HTAnchor_parent HTAnPare +#define HTAnchor_setDocument HTAnSeDo +#define HTAnchor_document HTAnDocu +#define HTAnchor_setFormat HTAnSeFo +#define HTAnchor_format HTAnForm +#define HTAnchor_setIndex HTAnSeIn +#define HTAnchor_setPrompt HTAnSePr +#define HTAnchor_isIndex HTAnIsIn +#define HTAnchor_address HTAnAddr +#define HTAnchor_hasChildren HTAnHaCh +#define HTAnchor_title HTAnTitl +#define HTAnchor_setTitle HTAnSeTi +#define HTAnchor_appendTitle HTAnApTi +#define HTAnchor_link HTAnLink +#define HTAnchor_followMainLink HTAnFoMa +#define HTAnchor_followTypedLink HTAnFoTy +#define HTAnchor_makeMainLink HTAnMaMa +#define HTAnchor_setProtocol HTAnSePr +#define HTAnchor_protocol HTAnProt +#define HTAnchor_physical HTAnPhys +#define HTAnchor_setPhysical HTAnSePh +#define HTAnchor_methods HtAnMeth +#endif /* SHORT_NAMES */ + +/* Main definition of anchor +** ========================= +*/ + +typedef struct _HyperDoc HyperDoc; /* Ready for forward references */ +typedef struct _HTAnchor HTAnchor; +typedef struct _HTParentAnchor HTParentAnchor; + +/* After definition of HTFormat: */ +#include "HTFormat.h" + +typedef HTAtom HTLinkType; + +typedef struct { + HTAnchor * dest; /* The anchor to which this leads */ + HTLinkType * type; /* Semantics of this link */ +} HTLink; + +struct _HTAnchor { /* Generic anchor : just links */ + HTLink mainLink; /* Main (or default) destination of this */ + HTList * links; /* List of extra links from this, if any */ + /* We separate the first link from the others to avoid too many small mallocs + involved by a list creation. Most anchors only point to one place. */ + HTParentAnchor * parent; /* Parent of this anchor (self for adults) */ +}; + +struct _HTParentAnchor { + /* Common part from the generic anchor structure */ + HTLink mainLink; /* Main (or default) destination of this */ + HTList * links; /* List of extra links from this, if any */ + HTParentAnchor * parent; /* Parent of this anchor (self) */ + + /* ParentAnchor-specific information */ + HTList * children; /* Subanchors of this, if any */ + HTList * sources; /* List of anchors pointing to this, if any */ + HyperDoc * document; /* The document within which this is an anchor */ + char * address; /* Absolute address of this node */ + char * post_data; /* Posting data */ + char * post_content_type; /* Type of post data */ + char * bookmark; /* Bookmark filname */ + HTFormat format; /* Pointer to node format descriptor */ + char * charset; /* Pointer to character set (kludge, for now */ + BOOL isIndex; /* Acceptance of a keyword search */ + char * isIndexAction; /* URL of isIndex server */ + char * isIndexPrompt; /* Prompt for isIndex query */ + char * title; /* Title of document */ + char * owner; /* Owner of document */ + char * RevTitle; /* TITLE in REV="made" or REV="owner" LINK */ +#ifdef USE_HASH + char * style; +#endif + + HTList* methods; /* Methods available as HTAtoms */ + void * protocol; /* Protocol object */ + char * physical; /* Physical address */ + BOOL underway; /* Document about to be attached to it */ + BOOL isISMAPScript; /* Script for clickable image map */ + BOOL isHEAD; /* Document is headers from a HEAD request */ + BOOL safe; /* Safe */ + char * FileCache; /* Path to a disk-cached copy */ + char * SugFname; /* Suggested filename */ + char * cache_control; /* Cache-Control */ + BOOL no_cache; /* Cache-Control, Pragma or META "no-cache"? */ + char * content_type; /* Content-Type */ + char * content_language; /* Content-Language */ + char * content_encoding; /* Compression algorithm */ + char * content_base; /* Content-Base */ + char * content_disposition; /* Content-Dispositon */ + char * content_location; /* Content-Location */ + char * content_md5; /* Content-MD5 */ + int content_length; /* Content-Length */ + char * date; /* Date */ + char * expires; /* Expires */ + char * last_modified; /* Last-Modified */ + char * server; /* Server */ + UCAnchorInfo *UCStages; /* chartrans stages */ + HTList * imaps; /* client side image maps */ +}; + +typedef struct { + /* Common part from the generic anchor structure */ + HTLink mainLink; /* Main (or default) destination of this */ + HTList * links; /* List of extra links from this, if any */ + HTParentAnchor * parent; /* Parent of this anchor */ + + /* ChildAnchor-specific information */ + char * tag; /* Address of this anchor relative to parent */ +} HTChildAnchor; + +/* +** DocAddress structure is used for loading an absolute anchor with all +** needed information including posting data and post content type. +*/ +typedef struct _DocAddress { + char * address; + char * post_data; + char * post_content_type; + char * bookmark; + BOOL isHEAD; + BOOL safe; +} DocAddress; + +/* "internal" means "within the same document, with certainty". + It includes a space so it cannot conflict with any (valid) "TYPE" + attributes on A elements. [According to which DTD, anyway??] - kw */ + +#define LINK_INTERNAL HTAtom_for("internal link") + +/* Create new or find old sub-anchor +** --------------------------------- +** +** This one is for a new anchor being edited into an existing +** document. The parent anchor must already exist. +*/ +extern HTChildAnchor * HTAnchor_findChild PARAMS(( + HTParentAnchor * parent, + CONST char * tag)); + +/* Create or find a child anchor with a possible link +** -------------------------------------------------- +** +** Create new anchor with a given parent and possibly +** a name, and possibly a link to a _relatively_ named anchor. +** (Code originally in ParseHTML.h) +*/ +extern HTChildAnchor * HTAnchor_findChildAndLink PARAMS(( + HTParentAnchor * parent, /* May not be 0 */ + CONST char * tag, /* May be "" or 0 */ + CONST char * href, /* May be "" or 0 */ + HTLinkType * ltype)); /* May be 0 */ + +/* Create new or find old named anchor +** ----------------------------------- +** +** This one is for a reference which is found in a document, and might +** not be already loaded. +** Note: You are not guaranteed a new anchor -- you might get an old one, +** like with fonts. +*/ +extern HTAnchor * HTAnchor_findAddress PARAMS(( + CONST DocAddress * address)); + +/* Delete an anchor and possibly related things (auto garbage collection) +** -------------------------------------------- +** +** The anchor is only deleted if the corresponding document is not loaded. +** All outgoing links from parent and children are deleted, and this anchor +** is removed from the sources list of all its targets. +** We also try to delete the targets whose documents are not loaded. +** If this anchor's source list is empty, we delete it and its children. +*/ +extern BOOL HTAnchor_delete PARAMS(( + HTParentAnchor * me)); + +/* Move an anchor to the head of the list of its siblings +** ------------------------------------------------------ +** +** This is to ensure that an anchor which might have already existed +** is put in the correct order as we load the document. +*/ +extern void HTAnchor_makeLastChild PARAMS(( + HTChildAnchor * me)); + +/* Data access functions +** --------------------- +*/ +extern HTParentAnchor * HTAnchor_parent PARAMS(( + HTAnchor * me)); + +extern void HTAnchor_setDocument PARAMS(( + HTParentAnchor * me, + HyperDoc * doc)); + +extern HyperDoc * HTAnchor_document PARAMS(( + HTParentAnchor * me)); + +/* We don't want code to change an address after anchor creation... yet ? +extern void HTAnchor_setAddress PARAMS(( + HTAnchor * me, + char * addr)); +*/ + +/* Returns the full URI of the anchor, child or parent +** as a malloc'd string to be freed by the caller. +*/ +extern char * HTAnchor_address PARAMS(( + HTAnchor * me)); + +extern void HTAnchor_setFormat PARAMS(( + HTParentAnchor * me, + HTFormat form)); + +extern HTFormat HTAnchor_format PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setIndex PARAMS(( + HTParentAnchor * me, + char * address)); + +extern void HTAnchor_setPrompt PARAMS(( + HTParentAnchor * me, + char * prompt)); + +extern BOOL HTAnchor_isIndex PARAMS(( + HTParentAnchor * me)); + +extern BOOL HTAnchor_isISMAPScript PARAMS(( + HTAnchor * me)); + +extern BOOL HTAnchor_hasChildren PARAMS(( + HTParentAnchor * me)); + +#if defined(USE_HASH) +extern CONST char * HTAnchor_style PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setStyle PARAMS(( + HTParentAnchor * me, + CONST char * style)); +#endif + +/* Title handling. +*/ +extern CONST char * HTAnchor_title PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setTitle PARAMS(( + HTParentAnchor * me, + CONST char * title)); + +extern void HTAnchor_appendTitle PARAMS(( + HTParentAnchor * me, + CONST char * title)); + +/* Bookmark handling. +*/ +extern CONST char * HTAnchor_bookmark PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setBookmark PARAMS(( + HTParentAnchor * me, + CONST char * bookmark)); + +/* Owner handling. +*/ +extern CONST char * HTAnchor_owner PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setOwner PARAMS(( + HTParentAnchor * me, + CONST char * owner)); + +/* TITLE handling in LINKs with REV="made" or REV="owner". - FM +*/ +extern CONST char * HTAnchor_RevTitle PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setRevTitle PARAMS(( + HTParentAnchor * me, + CONST char * title)); + +/* Suggested filename handling. - FM +** (will be loaded if we had a Content-Disposition +** header or META element with filename=name.suffix) +*/ +extern CONST char * HTAnchor_SugFname PARAMS(( + HTParentAnchor * me)); + +/* Content-Type handling. - FM +*/ +extern CONST char * HTAnchor_content_type PARAMS(( + HTParentAnchor * me)); + +/* Content-Encoding handling. - FM +** (will be loaded if we had a Content-Encoding +** header.) +*/ +extern CONST char * HTAnchor_content_encoding PARAMS(( + HTParentAnchor * me)); + +/* Last-Modified header handling. - FM +*/ +extern CONST char * HTAnchor_last_modified PARAMS(( + HTParentAnchor * me)); + +/* Date header handling. - FM +*/ +extern CONST char * HTAnchor_date PARAMS(( + HTParentAnchor * me)); + +/* Server header handling. - FM +*/ +extern CONST char * HTAnchor_server PARAMS(( + HTParentAnchor * me)); + +/* Safe header handling. - FM +*/ +extern BOOL HTAnchor_safe PARAMS(( + HTParentAnchor * me)); + +/* Content-Base header handling. - FM +*/ +extern CONST char * HTAnchor_content_base PARAMS(( + HTParentAnchor * me)); + +/* Content-Location header handling. - FM +*/ +extern CONST char * HTAnchor_content_location PARAMS(( + HTParentAnchor * me)); + +/* Link this Anchor to another given one +** ------------------------------------- +*/ +extern BOOL HTAnchor_link PARAMS(( + HTAnchor * source, + HTAnchor * destination, + HTLinkType * type)); + +/* Manipulation of links +** --------------------- +*/ +extern HTAnchor * HTAnchor_followMainLink PARAMS(( + HTAnchor * me)); + +extern HTAnchor * HTAnchor_followTypedLink PARAMS(( + HTAnchor * me, + HTLinkType * type)); + +extern BOOL HTAnchor_makeMainLink PARAMS(( + HTAnchor * me, + HTLink * movingLink)); + +/* Read and write methods +** ---------------------- +*/ +extern HTList * HTAnchor_methods PARAMS(( + HTParentAnchor * me)); + +/* Protocol +** -------- +*/ +extern void * HTAnchor_protocol PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setProtocol PARAMS(( + HTParentAnchor * me, + void * protocol)); + +/* Physical address +** ---------------- +*/ +extern char * HTAnchor_physical PARAMS(( + HTParentAnchor * me)); + +extern void HTAnchor_setPhysical PARAMS(( + HTParentAnchor * me, + char * protocol)); + +extern LYUCcharset * HTAnchor_getUCInfoStage PARAMS(( + HTParentAnchor * me, + int which_stage)); + +extern int HTAnchor_getUCLYhndl PARAMS(( + HTParentAnchor * me, + int which_stage)); + +extern LYUCcharset * HTAnchor_setUCInfoStage PARAMS(( + HTParentAnchor * me, + int LYhndl, + int which_stage, + int set_by)); + +extern LYUCcharset * HTAnchor_setUCInfoStage PARAMS(( + HTParentAnchor * me, + int LYhndl, + int which_stage, + int set_by)); + +extern LYUCcharset * HTAnchor_resetUCInfoStage PARAMS(( + HTParentAnchor * me, + int LYhndl, + int which_stage, + int set_by)); + +extern LYUCcharset * HTAnchor_copyUCInfoStage PARAMS(( + HTParentAnchor * me, + int to_stage, + int from_stage, + int set_by)); + +extern void ImageMapList_free PARAMS((HTList * list)); + +#endif /* HTANCHOR_H */ + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.c new file mode 100644 index 00000000000..e63c0213cb1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.c @@ -0,0 +1,87 @@ + +/* MODULE HTAssoc.c +** ASSOCIATION LIST FOR STORING NAME-VALUE PAIRS. +** NAMES NOT CASE SENSITIVE, AND ONLY COMMON LENGTH +** IS CHECKED (allows abbreviations; well, length is +** taken from lookup-up name, so if table contains +** a shorter abbrev it is not found). +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** +** +** BUGS: +** +** +*/ + + +#include "HTUtils.h" + +#include <string.h> + +#include "HTAAUtil.h" +#include "HTAssoc.h" +#include "HTString.h" + +#include "LYLeaks.h" + +PUBLIC HTAssocList *HTAssocList_new NOARGS +{ + return HTList_new(); +} + + +PUBLIC void HTAssocList_delete ARGS1(HTAssocList *, alist) +{ + if (alist) { + HTAssocList *cur = alist; + HTAssoc *assoc; + while (NULL != (assoc = (HTAssoc*)HTList_nextObject(cur))) { + FREE(assoc->name); + FREE(assoc->value); + FREE(assoc); + } + HTList_delete(alist); + alist = NULL; + } +} + + +PUBLIC void HTAssocList_add ARGS3(HTAssocList *, alist, + CONST char *, name, + CONST char *, value) +{ + HTAssoc *assoc; + + if (alist) { + if (!(assoc = (HTAssoc*)malloc(sizeof(HTAssoc)))) + outofmem(__FILE__, "HTAssoc_add"); + assoc->name = NULL; + assoc->value = NULL; + + if (name) + StrAllocCopy(assoc->name, name); + if (value) + StrAllocCopy(assoc->value, value); + HTList_addObject(alist, (void*)assoc); + } else if (TRACE) { + fprintf(stderr, "HTAssoc_add: ERROR: assoc list NULL!!\n"); + } +} + + +PUBLIC char *HTAssocList_lookup ARGS2(HTAssocList *, alist, + CONST char *, name) +{ + HTAssocList *cur = alist; + HTAssoc *assoc; + + while (NULL != (assoc = (HTAssoc*)HTList_nextObject(cur))) { + if (!strncasecomp(assoc->name, name, strlen(name))) + return assoc->value; + } + return NULL; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.h new file mode 100644 index 00000000000..71b0c9189c5 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.h @@ -0,0 +1,44 @@ +/* ASSOCIATION LIST FOR STORING NAME-VALUE PAIRS + + Lookups from assosiation list are not case-sensitive. + + */ + +#ifndef HTASSOC_H +#define HTASSOC_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTList.h" + + +#ifdef SHORT_NAMES +#define HTAL_new HTAssocList_new +#define HTAL_del HTAssocList_delete +#define HTAL_add HTAssocList_add +#define HTAL_lup HTAssocList_lookup +#endif /*SHORT_NAMES*/ + +typedef HTList HTAssocList; + +typedef struct { + char * name; + char * value; +} HTAssoc; + + +PUBLIC HTAssocList *HTAssocList_new NOPARAMS; +PUBLIC void HTAssocList_delete PARAMS((HTAssocList * alist)); + +PUBLIC void HTAssocList_add PARAMS((HTAssocList * alist, + CONST char * name, + CONST char * value)); + +PUBLIC char *HTAssocList_lookup PARAMS((HTAssocList * alist, + CONST char * name)); + +#endif /* not HTASSOC_H */ +/* + + End of file HTAssoc.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.c new file mode 100644 index 00000000000..8fc95d16565 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.c @@ -0,0 +1,169 @@ +/* Atoms: Names to numbers HTAtom.c +** ======================= +** +** Atoms are names which are given representative pointer values +** so that they can be stored more efficiently, and comparisons +** for equality done more efficiently. +** +** Atoms are kept in a hash table consisting of an array of linked lists. +** +** Authors: +** TBL Tim Berners-Lee, WorldWideWeb project, CERN +** (c) Copyright CERN 1991 - See Copyright.html +** +*/ +#include "HTUtils.h" + +#define HASH_SIZE 101 /* Tunable */ +#include "HTAtom.h" + +/*#include <stdio.h> included by HTUtils.h -- FM *//* joe@athena, TBL 921019 */ +#include <string.h> + +#include "HTList.h" + +#include "LYexit.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +PRIVATE HTAtom * hash_table[HASH_SIZE]; +PRIVATE BOOL initialised = NO; + +/* + * To free off all atoms. + */ +PRIVATE void free_atoms NOPARAMS; + +/* + * Alternate hashing function. + */ +#define HASH_FUNCTION(cp_hash) ((strlen(cp_hash) * (unsigned char)*cp_hash) % HASH_SIZE) + +PUBLIC HTAtom * HTAtom_for ARGS1(CONST char *, string) +{ + int hash; + HTAtom * a; + + /* First time around, clear hash table + */ + /* + * Memory leak fixed. + * 05-29-94 Lynx 2-3-1 Garrett Arch Blythe + */ + if (!initialised) { + int i; + for (i = 0; i < HASH_SIZE; i++) + hash_table[i] = (HTAtom *) 0; + initialised = YES; + atexit(free_atoms); + } + + /* Generate hash function + */ + hash = HASH_FUNCTION(string); + + /* Search for the string in the list + */ + for (a = hash_table[hash]; a; a = a->next) { + if (0 == strcasecomp(a->name, string)) { + /* if (TRACE) fprintf(stderr, + "HTAtom: Old atom %p for `%s'\n", a, string); */ + return a; /* Found: return it */ + } + } + + /* Generate a new entry + */ + a = (HTAtom *)malloc(sizeof(*a)); + if (a == NULL) + outofmem(__FILE__, "HTAtom_for"); + a->name = (char *)malloc(strlen(string)+1); + if (a->name == NULL) + outofmem(__FILE__, "HTAtom_for"); + strcpy(a->name, string); + a->next = hash_table[hash]; /* Put onto the head of list */ + hash_table[hash] = a; +#ifdef NOT_DEFINED + if (TRACE) + fprintf(stderr, "HTAtom: New atom %p for `%s'\n", a, string); +#endif /* NOT_DEFINED */ + return a; +} + +/* + * Purpose: Free off all atoms. + * Arguments: void + * Return Value: void + * Remarks/Portability/Dependencies/Restrictions: + * To be used at program exit. + * Revision History: + * 05-29-94 created Lynx 2-3-1 Garrett Arch Blythe + */ +PRIVATE void free_atoms NOARGS +{ + auto int i_counter; + HTAtom *HTAp_freeme; + /* + * Loop through all lists of atoms. + */ + for (i_counter = 0; i_counter < HASH_SIZE; i_counter++) { + /* + * Loop through the list. + */ + while (hash_table[i_counter] != NULL) { + /* + * Free off atoms and any members. + */ + HTAp_freeme = hash_table[i_counter]; + hash_table[i_counter] = HTAp_freeme->next; + FREE(HTAp_freeme->name); + FREE(HTAp_freeme); + } + } +} + +PRIVATE BOOL mime_match ARGS2(CONST char *, name, + CONST char *, templ) +{ + if (name && templ) { + static char *n1 = NULL; + static char *t1 = NULL; + char *n2; + char *t2; + + StrAllocCopy(n1, name); /* These also free the ones */ + StrAllocCopy(t1, templ); /* from previous call. */ + + if (!(n2 = strchr(n1, '/')) || !(t2 = strchr(t1, '/'))) + return NO; + + *(n2++) = (char)0; + *(t2++) = (char)0; + + if ((0 == strcmp(t1, "*") || 0 == strcmp(t1, n1)) && + (0 == strcmp(t2, "*") || 0 == strcmp(t2, n2))) + return YES; + } + return NO; +} + + +PUBLIC HTList *HTAtom_templateMatches ARGS1(CONST char *, templ) +{ + HTList *matches = HTList_new(); + + if (initialised && templ) { + int i; + HTAtom *cur; + + for (i = 0; i < HASH_SIZE; i++) { + for (cur = hash_table[i]; cur; cur = cur->next) { + if (mime_match(cur->name, templ)) + HTList_addObject(matches, (void*)cur); + } + } + } + return matches; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.h new file mode 100644 index 00000000000..b8dd10ec0b0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.h @@ -0,0 +1,49 @@ +/* */ + +/* Atoms: Names to numbers HTAtom.h +** ======================= +** +** Atoms are names which are given representative pointer values +** so that they can be stored more efficiently, and compaisons +** for equality done more efficiently. +** +** HTAtom_for(string) returns a representative value such that it +** will always (within one run of the program) return the same +** value for the same given string. +** +** Authors: +** TBL Tim Berners-Lee, WorldWideWeb project, CERN +** +** (c) Copyright CERN 1991 - See Copyright.html +** +*/ + +#ifndef HTATOM_H +#define HTATOM_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTList.h" + +#ifdef SHORT_NAMES +#define HTAt_for HTAtom_for +#define HTAt_tMa HTAtom_templateMatches +#endif /*SHORT_NAMES*/ + +typedef struct _HTAtom HTAtom; +struct _HTAtom { + HTAtom * next; + char * name; +}; /* struct _HTAtom */ + + +PUBLIC HTAtom * HTAtom_for PARAMS((CONST char * string)); +PUBLIC HTList * HTAtom_templateMatches PARAMS((CONST char * templ)); + +#define HTAtom_name(a) ((a)->name) + +#endif /* HTATOM_H */ +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.c new file mode 100644 index 00000000000..c3364db9fdf --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.c @@ -0,0 +1,210 @@ + +/* MODULE HTAuth.c +** USER AUTHENTICATION +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** AL 14.10.93 Fixed the colon-not-allowed-in-password-bug. +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include <string.h> +#include "HTPasswd.h" /* Password file routines */ +#include "HTAssoc.h" +#include "HTAuth.h" /* Implemented here */ +#include "HTUU.h" /* Uuencoding and uudecoding */ + +#include "LYLeaks.h" + +/* PRIVATE decompose_auth_string() +** DECOMPOSE AUTHENTICATION STRING +** FOR BASIC OR PUBKEY SCHEME +** ON ENTRY: +** authstring is the authorization string received +** from browser. +** +** ON EXIT: +** returns a node representing the user information +** (as always, this is automatically freed +** by AA package). +*/ +PRIVATE HTAAUser *decompose_auth_string ARGS2(char *, authstring, + HTAAScheme, scheme) +{ + static HTAAUser *user = NULL; + static char *cleartext = NULL; + char *username = NULL; + char *password = NULL; + char *i_net_adr = NULL; + char *timestamp = NULL; + char *browsers_key = NULL; + + if (!user && !(user = (HTAAUser*)malloc(sizeof(HTAAUser)))) /* Allocated */ + outofmem(__FILE__, "decompose_auth_string"); /* only once */ + + user->scheme = scheme; + user->username = NULL; /* Not freed, because freeing */ + user->password = NULL; /* cleartext also frees these */ + user->inet_addr = NULL; /* See below: || */ + user->timestamp = NULL; /* || */ + user->secret_key = NULL; /* || */ + /* \/ */ + FREE(cleartext); /* From previous call. */ + /* NOTE: parts of this memory are pointed to by */ + /* pointers in HTAAUser structure. Therefore, */ + /* this also frees all the strings pointed to */ + /* by the static 'user'. */ + + if (!authstring || !*authstring || + scheme != HTAA_BASIC || scheme == HTAA_PUBKEY) + return NULL; + + if (scheme == HTAA_PUBKEY) { /* Decrypt authentication string */ + int bytes_decoded; + char *ciphertext; + int len = strlen(authstring) + 1; + + if (!(ciphertext = (char*)malloc(len)) || + !(cleartext = (char*)malloc(len))) + outofmem(__FILE__, "decompose_auth_string"); + + bytes_decoded = HTUU_decode(authstring, + (unsigned char *)ciphertext, len); + ciphertext[bytes_decoded] = (char)0; +#ifdef PUBKEY + HTPK_decrypt(ciphertext, cleartext, private_key); +#endif + FREE(ciphertext); + } + else { /* Just uudecode */ + int bytes_decoded; + int len = strlen(authstring) + 1; + + if (!(cleartext = (char*)malloc(len))) + outofmem(__FILE__, "decompose_auth_string"); + bytes_decoded = HTUU_decode(authstring, + (unsigned char *)cleartext, len); + cleartext[bytes_decoded] = (char)0; + } + + +/* +** Extract username and password (for both schemes) +*/ + username = cleartext; + if (!(password = strchr(cleartext, ':'))) { + if (TRACE) + fprintf(stderr, "%s %s\n", + "decompose_auth_string: password field", + "missing in authentication string.\n"); + return NULL; + } + *(password++) = '\0'; + +/* +** Extract rest of the fields +*/ + if (scheme == HTAA_PUBKEY) { + if ( !(i_net_adr =strchr(password, ':')) || + (*(i_net_adr++) ='\0'), !(timestamp =strchr(i_net_adr,':')) || + (*(timestamp++) ='\0'), !(browsers_key=strchr(timestamp,':')) || + (*(browsers_key++)='\0')) { + + if (TRACE) fprintf(stderr, "%s %s\n", + "decompose_auth_string: Pubkey scheme", + "fields missing in authentication string"); + return NULL; + } + } + +/* +** Set the fields into the result +*/ + user->username = username; + user->password = password; + user->inet_addr = i_net_adr; + user->timestamp = timestamp; + user->secret_key = browsers_key; + + if (TRACE) { + if (scheme==HTAA_BASIC) + fprintf(stderr, "decompose_auth_string: %s (%s,%s)\n", + "Basic scheme authentication string:", + username, password); + else + fprintf(stderr, "decompose_auth_string: %s (%s,%s,%s,%s,%s)\n", + "Pubkey scheme authentication string:", + username, password, i_net_adr, timestamp, browsers_key); + } + + return user; +} + + + +PRIVATE BOOL HTAA_checkTimeStamp ARGS1(CONST char *, timestamp) +{ + return NO; /* This is just a stub */ +} + + +PRIVATE BOOL HTAA_checkInetAddress ARGS1(CONST char *, i_net_adr) +{ + return NO; /* This is just a stub */ +} + + +/* SERVER PUBLIC HTAA_authenticate() +** AUTHENTICATE USER +** ON ENTRY: +** scheme used authentication scheme. +** scheme_specifics the scheme specific parameters +** (authentication string for Basic and +** Pubkey schemes). +** prot is the protection information structure +** for the file. +** +** ON EXIT: +** returns NULL, if authentication failed. +** Otherwise a pointer to a structure +** representing authenticated user, +** which should not be freed. +*/ +PUBLIC HTAAUser *HTAA_authenticate ARGS3(HTAAScheme, scheme, + char *, scheme_specifics, + HTAAProt *, prot) +{ + if (HTAA_UNKNOWN == scheme || !prot || + -1 == HTList_indexOf(prot->valid_schemes, (void*)scheme)) + return NULL; + + switch (scheme) { + case HTAA_BASIC: + case HTAA_PUBKEY: + { + HTAAUser *user = decompose_auth_string(scheme_specifics, scheme); + /* Remember, user is auto-freed */ + if (user && + HTAA_checkPassword(user->username, + user->password, + HTAssocList_lookup(prot->values, "passw")) && + (HTAA_BASIC == scheme || + (HTAA_checkTimeStamp(user->timestamp) && + HTAA_checkInetAddress(user->inet_addr)))) + return user; + else + return NULL; + } + break; + default: + /* Other authentication routines go here */ + return NULL; + } +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.h new file mode 100644 index 00000000000..6dc4c51616d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.h @@ -0,0 +1,66 @@ +/* AUTHENTICATION MODULE + + This is the authentication module. By modifying the function HTAA_authenticate() it can + be made to support external authentication methods. + + */ + +#ifndef HTAUTH_H +#define HTAUTH_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTAAUtil.h" +#include "HTAAProt.h" + + +#ifdef SHORT_NAMES +#define HTAAauth HTAA_authenticate +#endif /* SHORT_NAMES */ + + +/* +** Server's representation of a user (fields in authentication string) +*/ +typedef struct { + HTAAScheme scheme; /* Scheme used to authenticate this user */ + char * username; + char * password; + char * inet_addr; + char * timestamp; + char * secret_key; +} HTAAUser; +/* + +User Authentication + + */ + +/* SERVER PUBLIC HTAA_authenticate() +** AUTHENTICATE USER +** ON ENTRY: +** scheme used authentication scheme. +** scheme_specifics the scheme specific parameters +** (authentication string for Basic and +** Pubkey schemes). +** prot is the protection information structure +** for the file. +** +** ON EXIT: +** returns NULL, if authentication failed. +** Otherwise a pointer to a structure +** representing authenticated user, +** which should not be freed. +*/ +PUBLIC HTAAUser *HTAA_authenticate PARAMS((HTAAScheme scheme, + char * scheme_specifics, + HTAAProt * prot)); +/* + + */ + +#endif /* not HTAUTH_H */ +/* + + End of file HTAuth.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.c new file mode 100644 index 00000000000..6515be77260 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.c @@ -0,0 +1,720 @@ +/* Binary Tree for sorting things +** ============================== +** Author: Arthur Secret +** +** 4 March 94: Bug fixed in the balancing procedure +** +*/ + + +#include "HTUtils.h" +#include "HTBTree.h" +#ifndef __STRICT_BSD__ +#include <stdlib.h> +#endif +#include <string.h> + +#define MAXIMUM(a,b) ((a)>(b)?(a):(b)) + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + + +PUBLIC HTBTree * HTBTree_new ARGS1(HTComparer, comp) + /********************************************************* + ** This function returns an HTBTree with memory allocated + ** for it when given a mean to compare things + */ +{ + HTBTree * tree = (HTBTree *)malloc(sizeof(HTBTree)); + if (tree==NULL) outofmem(__FILE__, "HTBTree_new"); + + tree->compare = comp; + tree->top = NULL; + + return tree; +} + + + + +PRIVATE void HTBTElement_free ARGS1(HTBTElement*, element) + /********************************************************** + ** This void will free the memory allocated for one element + */ +{ + if (element) { + if (element->left != NULL) + HTBTElement_free(element->left); + if (element->right != NULL) + HTBTElement_free(element->right); + FREE(element); + } +} + +PUBLIC void HTBTree_free ARGS1(HTBTree*, tree) + /************************************************************** + ** This void will free the memory allocated for the whole tree + */ +{ + HTBTElement_free(tree->top); + FREE(tree); +} + + + + +PRIVATE void HTBTElementAndObject_free ARGS1(HTBTElement*, element) + /********************************************************** + ** This void will free the memory allocated for one element + */ +{ + if (element) { /* Just in case nothing was in the tree anyway */ + if (element->left != NULL) + HTBTElementAndObject_free(element->left); + if (element->right != NULL) + HTBTElementAndObject_free(element->right); + FREE(element->object); + FREE(element); + } +} + +PUBLIC void HTBTreeAndObject_free ARGS1(HTBTree*, tree) + /************************************************************** + ** This void will free the memory allocated for the whole tree + */ +{ + HTBTElementAndObject_free(tree->top); + FREE(tree); +} + + + + +PUBLIC void HTBTree_add ARGS2( + HTBTree*, tree, + void*, object) + /********************************************************************** + ** This void is the core of HTBTree.c . It will + ** 1/ add a new element to the tree at the right place + ** so that the tree remains sorted + ** 2/ balance the tree to be as fast as possible when reading it + */ +{ + HTBTElement * father_of_element; + HTBTElement * added_element; + HTBTElement * forefather_of_element; + HTBTElement * father_of_forefather; + BOOL father_found,top_found; + int depth,depth2,corrections; + /* father_of_element is a pointer to the structure that is the father of the + ** new object "object". + ** added_element is a pointer to the structure that contains or will contain + ** the new object "object". + ** father_of_forefather and forefather_of_element are pointers that are used + ** to modify the depths of upper elements, when needed. + ** + ** father_found indicates by a value NO when the future father of "object" + ** is found. + ** top_found indicates by a value NO when, in case of a difference of depths + ** < 2, the top of the tree is encountered and forbids any further try to + ** balance the tree. + ** corrections is an integer used to avoid infinite loops in cases + ** such as: + ** + ** 3 3 + ** 4 4 + ** 5 5 + ** + ** 3 is used here to show that it need not be the top of the tree. + */ + + /* + ** 1/ Adding of the element to the binary tree + */ + + if (tree->top == NULL) + { + tree->top = (HTBTElement *)malloc(sizeof(HTBTElement)); + if (tree->top == NULL) outofmem(__FILE__, "HTBTree_add"); + tree->top->up = NULL; + tree->top->object = object; + tree->top->left = NULL; + tree->top->left_depth = 0; + tree->top->right = NULL; + tree->top->right_depth = 0; + } + else + { + father_found = YES; + father_of_element = tree->top; + added_element = NULL; + father_of_forefather = NULL; + forefather_of_element = NULL; + while (father_found) + { + if (tree->compare(object,father_of_element->object)<0) + { + if (father_of_element->left != NULL) + father_of_element = father_of_element->left; + else + { + father_found = NO; + father_of_element->left = + (HTBTElement *)malloc(sizeof(HTBTElement)); + if (father_of_element->left==NULL) + outofmem(__FILE__, "HTBTree_add"); + added_element = father_of_element->left; + added_element->up = father_of_element; + added_element->object = object; + added_element->left = NULL; + added_element->left_depth = 0; + added_element->right = NULL; + added_element->right_depth = 0; + } + } + if (tree->compare(object,father_of_element->object)>=0) + { + if (father_of_element->right != NULL) + father_of_element = father_of_element->right; + else + { + father_found = NO; + father_of_element->right = + (HTBTElement *)malloc(sizeof(HTBTElement)); + if (father_of_element->right==NULL) + outofmem(__FILE__, "HTBTree_add"); + added_element = father_of_element->right; + added_element->up = father_of_element; + added_element->object = object; + added_element->left = NULL; + added_element->left_depth = 0; + added_element->right = NULL; + added_element->right_depth = 0; + } + } + } + /* + ** Changing of all depths that need to be changed + */ + father_of_forefather = father_of_element; + forefather_of_element = added_element; + do + { + if (father_of_forefather->left == forefather_of_element) + { + depth = father_of_forefather->left_depth; + father_of_forefather->left_depth = 1 + + MAXIMUM(forefather_of_element->right_depth, + forefather_of_element->left_depth); + depth2 = father_of_forefather->left_depth; + } + else + { + depth = father_of_forefather->right_depth; + father_of_forefather->right_depth = 1 + + MAXIMUM(forefather_of_element->right_depth, + forefather_of_element->left_depth); + depth2 = father_of_forefather->right_depth; + } + forefather_of_element = father_of_forefather; + father_of_forefather = father_of_forefather->up; + } while ((depth != depth2) && (father_of_forefather != NULL)); + + + + /* + ** 2/ Balancing the binary tree, if necessary + */ + top_found = YES; + corrections = 0; + while ((top_found) && (corrections < 7)) + { + if ((abs(father_of_element->left_depth + - father_of_element->right_depth)) < 2) + { + if (father_of_element->up != NULL) + father_of_element = father_of_element->up; + else top_found = NO; + } + else + { /* We start the process of balancing */ + + corrections = corrections + 1; + /* + ** corrections is an integer used to avoid infinite + ** loops in cases such as: + ** + ** 3 3 + ** 4 4 + ** 5 5 + ** + ** 3 is used to show that it need not be the top of the tree + ** But let's avoid these two exceptions anyhow + ** with the two following conditions (4 March 94 - AS) + */ + + if ((father_of_element->left == NULL) + && (father_of_element->right->right == NULL) + && (father_of_element->right->left->left == NULL) + && (father_of_element->right->left->right == NULL)) + corrections = 7; + + if ((father_of_element->right == NULL) + && (father_of_element->left->left == NULL) + && (father_of_element->left->right->right == NULL) + && (father_of_element->left->right->left == NULL)) + corrections = 7; + + + if (father_of_element->left_depth > father_of_element->right_depth) + { + added_element = father_of_element->left; + father_of_element->left_depth = added_element->right_depth; + added_element->right_depth = 1 + + MAXIMUM(father_of_element->right_depth, + father_of_element->left_depth); + if (father_of_element->up != NULL) + { + /* Bug fixed in March 94 - AS */ + BOOL first_time; + + father_of_forefather = father_of_element->up; + forefather_of_element = added_element; + first_time = YES; + do + { + if (father_of_forefather->left + == forefather_of_element->up) + { + depth = father_of_forefather->left_depth; + if (first_time) + { + father_of_forefather->left_depth = 1 + + MAXIMUM(forefather_of_element->left_depth, + forefather_of_element->right_depth); + first_time = NO; + } + else + father_of_forefather->left_depth = 1 + + MAXIMUM(forefather_of_element->up->left_depth, + forefather_of_element->up->right_depth); + + depth2 = father_of_forefather->left_depth; + } + else + { + depth = father_of_forefather->right_depth; + if (first_time) + { + father_of_forefather->right_depth = 1 + + MAXIMUM(forefather_of_element->left_depth, + forefather_of_element->right_depth); + first_time = NO; + } + else + father_of_forefather->right_depth = 1 + + MAXIMUM(forefather_of_element->up->left_depth, + forefather_of_element->up->right_depth); + depth2 = father_of_forefather->right_depth; + } + forefather_of_element = forefather_of_element->up; + father_of_forefather = father_of_forefather->up; + } while ((depth != depth2) && + (father_of_forefather != NULL)); + father_of_forefather = father_of_element->up; + if (father_of_forefather->left == father_of_element) + { + /* + ** 3 3 + ** 4 5 + ** When tree 5 6 becomes 7 4 + ** 7 8 8 6 + ** + ** 3 is used to show that it may not be the top of the + ** tree. + */ + father_of_forefather->left = added_element; + father_of_element->left = added_element->right; + added_element->right = father_of_element; + } + if (father_of_forefather->right == father_of_element) + { + /* + ** 3 3 + ** 4 5 + ** When tree 5 6 becomes 7 4 + ** 7 8 8 6 + ** + ** 3 is used to show that it may not be the top of the + ** tree + */ + father_of_forefather->right = added_element; + father_of_element->left = added_element->right; + added_element->right = father_of_element; + } + added_element->up = father_of_forefather; + } + else + { + /* + ** + ** 1 2 + ** When tree 2 3 becomes 4 1 + ** 4 5 5 3 + ** + ** 1 is used to show that it is the top of the tree + */ + added_element->up = NULL; + father_of_element->left = added_element->right; + added_element->right = father_of_element; + } + father_of_element->up = added_element; + if (father_of_element->left != NULL) + father_of_element->left->up = father_of_element; + } + else + { + added_element = father_of_element->right; + father_of_element->right_depth = added_element->left_depth; + added_element->left_depth = 1 + + MAXIMUM(father_of_element->right_depth, + father_of_element->left_depth); + if (father_of_element->up != NULL) + /* Bug fixed in March 94 - AS */ + { + BOOL first_time; + + father_of_forefather = father_of_element->up; + forefather_of_element = added_element; + first_time = YES; + do + { + if (father_of_forefather->left + == forefather_of_element->up) + { + depth = father_of_forefather->left_depth; + if (first_time) + { + father_of_forefather->left_depth = 1 + + MAXIMUM(forefather_of_element->left_depth, + forefather_of_element->right_depth); + first_time = NO; + } + else + father_of_forefather->left_depth = 1 + + MAXIMUM(forefather_of_element->up->left_depth, + forefather_of_element->up->right_depth); + depth2 = father_of_forefather->left_depth; + } + else + { + depth = father_of_forefather->right_depth; + if (first_time) + { + father_of_forefather->right_depth = 1 + + MAXIMUM(forefather_of_element->left_depth, + forefather_of_element->right_depth); + first_time = NO; + } + else + father_of_forefather->right_depth = 1 + + MAXIMUM(forefather_of_element->up->left_depth, + forefather_of_element->up->right_depth); + depth2 = father_of_forefather->right_depth; + } + father_of_forefather = father_of_forefather->up; + forefather_of_element = forefather_of_element->up; + } while ((depth != depth2) && + (father_of_forefather != NULL)); + father_of_forefather = father_of_element->up; + if (father_of_forefather->left == father_of_element) + { + /* + ** 3 3 + ** 4 6 + ** When tree 5 6 becomes 4 8 + ** 7 8 5 7 + ** + ** 3 is used to show that it may not be the top of the + ** tree. + */ + father_of_forefather->left = added_element; + father_of_element->right = added_element->left; + added_element->left = father_of_element; + } + if (father_of_forefather->right == father_of_element) + { + /* + ** 3 3 + ** 4 6 + ** When tree 5 6 becomes 4 8 + ** 7 8 5 7 + ** + ** 3 is used to show that it may not be the top of the + ** tree + */ + father_of_forefather->right = added_element; + father_of_element->right = added_element->left; + added_element->left = father_of_element; + } + added_element->up = father_of_forefather; + } + else + { + /* + ** + ** 1 3 + ** When tree 2 3 becomes 1 5 + ** 4 5 2 4 + ** + ** 1 is used to show that it is the top of the tree. + */ + added_element->up = NULL; + father_of_element->right = added_element->left; + added_element->left = father_of_element; + } + father_of_element->up = added_element; + if (father_of_element->right != NULL) + father_of_element->right->up = father_of_element; + } + } + } + while (father_of_element->up != NULL) + { + father_of_element = father_of_element->up; + } + tree->top = father_of_element; + } +} + + + +PUBLIC HTBTElement * HTBTree_next ARGS2( + HTBTree*, tree, + HTBTElement*, ele) + /************************************************************************** + ** this function returns a pointer to the leftmost element if ele is NULL, + ** and to the next object to the right otherways. + ** If no elements left, returns a pointer to NULL. + */ +{ + HTBTElement * father_of_element; + HTBTElement * father_of_forefather; + + if (ele == NULL) + { + father_of_element = tree->top; + if (father_of_element != NULL) + while (father_of_element->left != NULL) + father_of_element = father_of_element->left; + } + else + { + father_of_element = ele; + if (father_of_element->right != NULL) + { + father_of_element = father_of_element->right; + while (father_of_element->left != NULL) + father_of_element = father_of_element->left; + } + else + { + father_of_forefather = father_of_element->up; + while (father_of_forefather && + (father_of_forefather->right == father_of_element)) + { + father_of_element = father_of_forefather; + father_of_forefather = father_of_element->up; + } + father_of_element = father_of_forefather; + } + } +#ifdef BTREE_TRACE + /* The option -DBTREE_TRACE will give much more information + ** about the way the process is running, for debugging matters + */ + if (father_of_element != NULL) + { + printf("\nObject = %s\t",(char *)father_of_element->object); + if (father_of_element->up != NULL) + printf("Objet du pere = %s\n", + (char *)father_of_element->up->object); + else printf("Pas de Pere\n"); + if (father_of_element->left != NULL) + printf("Objet du fils gauche = %s\t", + (char *)father_of_element->left->object); + else printf("Pas de fils gauche\t"); + if (father_of_element->right != NULL) + printf("Objet du fils droit = %s\n", + (char *)father_of_element->right->object); + else printf("Pas de fils droit\n"); + printf("Profondeur gauche = %d\t",father_of_element->left_depth); + printf("Profondeur droite = %d\n",father_of_element->right_depth); + printf(" **************\n"); + } +#endif + return father_of_element; +} + + +#ifdef TEST +main () + /****************************************************** + ** This is just a test to show how to handle HTBTree.c + */ +{ + HTBTree * tree; + HTBTElement * next_element; + + tree = HTBTree_new((HTComparer)strcasecomp); + HTBTree_add(tree,"hypertext"); + HTBTree_add(tree,"Addressing"); + HTBTree_add(tree,"X11"); + HTBTree_add(tree,"Tools"); + HTBTree_add(tree,"Proposal.wn"); + HTBTree_add(tree,"Protocols"); + HTBTree_add(tree,"NeXT"); + HTBTree_add(tree,"Daemon"); + HTBTree_add(tree,"Test"); + HTBTree_add(tree,"Administration"); + HTBTree_add(tree,"LineMode"); + HTBTree_add(tree,"DesignIssues"); + HTBTree_add(tree,"MarkUp"); + HTBTree_add(tree,"Macintosh"); + HTBTree_add(tree,"Proposal.rtf.wn"); + HTBTree_add(tree,"FIND"); + HTBTree_add(tree,"Paper"); + HTBTree_add(tree,"Tcl"); + HTBTree_add(tree,"Talks"); + HTBTree_add(tree,"Architecture"); + HTBTree_add(tree,"VMSHelp"); + HTBTree_add(tree,"Provider"); + HTBTree_add(tree,"Archive"); + HTBTree_add(tree,"SLAC"); + HTBTree_add(tree,"Project"); + HTBTree_add(tree,"News"); + HTBTree_add(tree,"Viola"); + HTBTree_add(tree,"Users"); + HTBTree_add(tree,"FAQ"); + HTBTree_add(tree,"WorkingNotes"); + HTBTree_add(tree,"Windows"); + HTBTree_add(tree,"FineWWW"); + HTBTree_add(tree,"Frame"); + HTBTree_add(tree,"XMosaic"); + HTBTree_add(tree,"People"); + HTBTree_add(tree,"All"); + HTBTree_add(tree,"Curses"); + HTBTree_add(tree,"Erwise"); + HTBTree_add(tree,"Carl"); + HTBTree_add(tree,"MidasWWW"); + HTBTree_add(tree,"XPM"); + HTBTree_add(tree,"MailRobot"); + HTBTree_add(tree,"Illustrations"); + HTBTree_add(tree,"VMClient"); + HTBTree_add(tree,"XPA"); + HTBTree_add(tree,"Clients.html"); + HTBTree_add(tree,"Library"); + HTBTree_add(tree,"CERNLIB_Distribution"); + HTBTree_add(tree,"libHTML"); + HTBTree_add(tree,"WindowsPC"); + HTBTree_add(tree,"tkWWW"); + HTBTree_add(tree,"tk2.3"); + HTBTree_add(tree,"CVS-RCS"); + HTBTree_add(tree,"DecnetSockets"); + HTBTree_add(tree,"SGMLStream"); + HTBTree_add(tree,"NextStep"); + HTBTree_add(tree,"CVSRepository_old"); + HTBTree_add(tree,"ArthurSecret"); + HTBTree_add(tree,"CVSROOT"); + HTBTree_add(tree,"HytelnetGate"); + HTBTree_add(tree,"cern.www.new.src"); + HTBTree_add(tree,"Conditions"); + HTBTree_add(tree,"HTMLGate"); + HTBTree_add(tree,"Makefile"); + HTBTree_add(tree,"Newsgroups.html"); + HTBTree_add(tree,"People.html"); + HTBTree_add(tree,"Bugs.html"); + HTBTree_add(tree,"Summary.html"); + HTBTree_add(tree,"zDesignIssues.wn"); + HTBTree_add(tree,"HT.draw"); + HTBTree_add(tree,"HTandCERN.wn"); + HTBTree_add(tree,"Ideas.wn"); + HTBTree_add(tree,"MarkUp.wn"); + HTBTree_add(tree,"Proposal.html"); + HTBTree_add(tree,"SearchPanel.draw"); + HTBTree_add(tree,"Comments.wn"); + HTBTree_add(tree,"Xanadu.html"); + HTBTree_add(tree,"Storinglinks.html"); + HTBTree_add(tree,"TheW3Book.html"); + HTBTree_add(tree,"Talk_Feb-91.html"); + HTBTree_add(tree,"JFosterEntry.txt"); + HTBTree_add(tree,"Summary.txt"); + HTBTree_add(tree,"Bibliography.html"); + HTBTree_add(tree,"HTandCern.txt"); + HTBTree_add(tree,"Talk.draw"); + HTBTree_add(tree,"zDesignNotes.html"); + HTBTree_add(tree,"Link.html"); + HTBTree_add(tree,"Status.html"); + HTBTree_add(tree,"http.txt"); + HTBTree_add(tree,"People.html~"); + HTBTree_add(tree,"TAGS"); + HTBTree_add(tree,"summary.txt"); + HTBTree_add(tree,"Technical.html"); + HTBTree_add(tree,"Terms.html"); + HTBTree_add(tree,"JANETAccess.html"); + HTBTree_add(tree,"People.txt"); + HTBTree_add(tree,"README.txt"); + HTBTree_add(tree,"CodingStandards.html"); + HTBTree_add(tree,"Copyright.txt"); + HTBTree_add(tree,"Status_old.html"); + HTBTree_add(tree,"patches~"); + HTBTree_add(tree,"RelatedProducts.html"); + HTBTree_add(tree,"Implementation"); + HTBTree_add(tree,"History.html"); + HTBTree_add(tree,"Makefile.bak"); + HTBTree_add(tree,"Makefile.old"); + HTBTree_add(tree,"Policy.html"); + HTBTree_add(tree,"WhatIs.html"); + HTBTree_add(tree,"TheProject.html"); + HTBTree_add(tree,"Notation.html"); + HTBTree_add(tree,"Helping.html"); + HTBTree_add(tree,"Cyber-WWW.sit.Hqx"); + HTBTree_add(tree,"Glossary.html"); + HTBTree_add(tree,"maketags.html"); + HTBTree_add(tree,"IntroCS.html"); + HTBTree_add(tree,"Contrib"); + HTBTree_add(tree,"Help.html"); + HTBTree_add(tree,"CodeManagExec"); + HTBTree_add(tree,"HT-0.1draz"); + HTBTree_add(tree,"Cello"); + HTBTree_add(tree,"TOPUB"); + HTBTree_add(tree,"BUILD"); + HTBTree_add(tree,"BUILDALL"); + HTBTree_add(tree,"Lynx"); + HTBTree_add(tree,"ArthurLibrary"); + HTBTree_add(tree,"RashtyClient"); + HTBTree_add(tree,"#History.html#"); + HTBTree_add(tree,"PerlServers"); + HTBTree_add(tree,"modules"); + HTBTree_add(tree,"NCSA_httpd"); + HTBTree_add(tree,"MAIL2HTML"); + HTBTree_add(tree,"core"); + HTBTree_add(tree,"EmacsWWW"); +#ifdef BTREE_TRACE + printf("\nTreeTopObject=%s\n\n",tree->top->object); +#endif + next_element = HTBTree_next(tree,NULL); + while (next_element != NULL) + { +#ifndef BTREE_TRACE + printf("The next element is %s\n",next_element->object); +#endif + next_element = HTBTree_next(tree,next_element); + } + HTBTree_free(tree); +} + + +#endif diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.h new file mode 100644 index 00000000000..55bfe6aba26 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.h @@ -0,0 +1,104 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTBTree.html + BALANCED BINARY TREE FOR SORTING THINGS + + Tree creation, traversal and freeing. User-supplied comparison routine. + + Author: Arthur Secret, CERN. Public domain. Please mail bugs and changes to + www-request@info.cern.ch + + part of libWWW + + */ +#ifdef SHORT_NAMES +#define HTBTree_new HTBTNew +#define HTBTree_free HTBTFree +#define HTBTreeAndObject_free HTBTAOFr +#define HTBTree_add HTBTAdd +#define HTBTree_next HTBTNext +/* #define HTBTree_object HTBTObje already a macro */ +#endif + + +/* + +Data structures + + */ +typedef struct _HTBTree_element { + void *object; /* User object */ + struct _HTBTree_element *up; + struct _HTBTree_element *left; + int left_depth; + struct _HTBTree_element *right; + int right_depth; +} HTBTElement; + +typedef int (*HTComparer) PARAMS((void * a, void * b)); + +typedef struct _HTBTree_top { + HTComparer compare; + struct _HTBTree_element *top; +} HTBTree; + + +/* + +Create a binary tree given its discrimination routine + + */ +extern HTBTree * HTBTree_new PARAMS((HTComparer comp)); + + + +/* + +Free storage of the tree but not of the objects + + */ +extern void HTBTree_free PARAMS((HTBTree* tree)); + + + +/* + +Free storage of the tree and of the objects + + */ +extern void HTBTreeAndObject_free PARAMS((HTBTree* tree)); + + + +/* + +Add an object to a binary tree + + */ + +extern void HTBTree_add PARAMS((HTBTree* tree, void * object)); + + +/* + +Find user object for element + + */ +#define HTBTree_object(element) ((element)->object) + + +/* + +Find next element in depth-first order + + ON ENTRY, + + ele if NULL, start with leftmost element. if != 0 give next object to + the right. + + returns Pointer to element ot NULL if none left. + + */ +extern HTBTElement * HTBTree_next PARAMS((HTBTree* tree, HTBTElement * ele)); + +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTCJK.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTCJK.h new file mode 100644 index 00000000000..c5fa51afac5 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTCJK.h @@ -0,0 +1,110 @@ +/* CJK character converter HTCJK.h +** ======================= +** +** Added 11-Jun-96 by FM, based on jiscode.h for +** Yutaka Sato's (ysato@etl.go.jp) SJIS.c, and +** Takuya ASADA's (asada@three-a.co.jp) CJK patches. +** (see SGML.c). +** +*/ + +#ifndef HTCJK_H +#define HTCJK_H + +/* +** STATUS CHANGE CODES +*/ +#ifdef ESC +#undef ESC +#endif /* ESC */ +#define ESC '\033' +#define TO_2BCODE '$' +#define TO_1BCODE '(' + +#define TO_KANA '\016' +#define TO_KANAOUT '\017' + +#define TO_KANJI "\033$B" +#define TO_HANJI "\033$A" +#define TO_HANGUL "\033$(C" +#define TO_ASCII "\033(B" + +#define IS_SJIS_LO(lo) ((0x40<=lo)&&(lo!=0x7F)&&(lo<=0xFC)) +#define IS_SJIS_HI1(hi) ((0x81<=hi)&&(hi<=0x9F)) /* 1st lev. */ +#define IS_SJIS_HI2(hi) ((0xE0<=hi)&&(hi<=0xEF)) /* 2nd lev. */ +#define IS_SJIS(hi,lo,in_sjis) (!IS_SJIS_LO(lo)?0:IS_SJIS_HI1(hi)?(in_sjis=1):in_sjis&&IS_SJIS_HI2(hi)) + +#define IS_EUC_LOS(lo) ((0x21<=lo)&&(lo<=0x7E)) /* standard */ +#define IS_EUC_LOX(lo) ((0xA1<=lo)&&(lo<=0xFE)) /* extended */ +#define IS_EUC_HI(hi) ((0xA1<=hi)&&(hi<=0xFE)) +#define IS_EUC(hi,lo) IS_EUC_HI(hi) && (IS_EUC_LOS(lo) || IS_EUC_LOX(lo)) + +#define IS_BIG5_LOS(lo) ((0x40<=lo)&&(lo<=0x7E)) /* standard */ +#define IS_BIG5_LOX(lo) ((0xA1<=lo)&&(lo<=0xFE)) /* extended */ +#define IS_BIG5_HI(hi) ((0xA1<=hi)&&(hi<=0xFE)) +#define IS_BIG5(hi,lo) IS_BIG5_HI(hi) && (IS_BIG5_LOS(lo) || IS_BIG5_LOX(lo)) + +typedef enum _HTkcode {NOKANJI, EUC, SJIS, JIS} HTkcode; +typedef enum _HTCJKlang {NOCJK, JAPANESE, CHINESE, KOREAN, TAIPEI} HTCJKlang; + +/* +** Function prototypes. +*/ +extern void JISx0201TO0208_EUC PARAMS(( + register unsigned char IHI, + register unsigned char ILO, + register unsigned char * OHI, + register unsigned char * OLO)); + +extern unsigned char * SJIS_TO_JIS1 PARAMS(( + register unsigned char HI, + register unsigned char LO, + register unsigned char * JCODE)); + +extern unsigned char * JIS_TO_SJIS1 PARAMS(( + register unsigned char HI, + register unsigned char LO, + register unsigned char * SJCODE)); + +extern unsigned char * EUC_TO_SJIS1 PARAMS(( + unsigned char HI, + unsigned char LO, + register unsigned char * SJCODE)); + +extern void JISx0201TO0208_SJIS PARAMS(( + register unsigned char I, + register unsigned char * OHI, + register unsigned char * OLO)); + +extern unsigned char * SJIS_TO_EUC1 PARAMS(( + unsigned char HI, + unsigned char LO, + unsigned char * EUCp)); + +extern unsigned char * SJIS_TO_EUC PARAMS(( + unsigned char * src, + unsigned char * dst)); + +extern unsigned char * EUC_TO_SJIS PARAMS(( + unsigned char * src, + unsigned char * dst)); + +extern unsigned char * EUC_TO_JIS PARAMS(( + unsigned char * src, + unsigned char * dst, + CONST char * toK, + CONST char * toA)); + +extern unsigned char * TO_EUC PARAMS(( + unsigned char * jis, + unsigned char * euc)); + +extern void TO_SJIS PARAMS(( + unsigned char * any, + unsigned char * sjis)); + +extern void TO_JIS PARAMS(( + unsigned char * any, + unsigned char * jis)); + +#endif /* HTCJK_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.c new file mode 100644 index 00000000000..fd66a482324 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.c @@ -0,0 +1,204 @@ +/* Chunk handling: Flexible arrays +** =============================== +** +*/ + +#include "HTUtils.h" +#include "HTChunk.h" +/*#include <stdio.h> included by HTUtils.h -- FM */ + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* Create a chunk with a certain allocation unit +** -------------- +*/ +PUBLIC HTChunk * HTChunkCreate ARGS1 (int,grow) +{ + HTChunk * ch = (HTChunk *) calloc(1, sizeof(HTChunk)); + if (ch == NULL) + outofmem(__FILE__, "creation of chunk"); + + ch->data = 0; + ch->growby = grow; + ch->size = 0; + ch->allocated = 0; + return ch; +} + +/* Create a chunk with a certain allocation unit and ensured size +** -------------- +*/ +PUBLIC HTChunk * HTChunkCreate2 ARGS2 (int,grow, size_t, needed) +{ + HTChunk * ch = (HTChunk *) calloc(1, sizeof(HTChunk)); + if (ch == NULL) + outofmem(__FILE__, "HTChunkCreate2"); + + ch->growby = grow; + if (needed > 0) { + ch->allocated = needed-1 - ((needed-1) % ch->growby) + + ch->growby; /* Round up */ + ch->data = (char *)calloc(1, ch->allocated); + if (!ch->data) + outofmem(__FILE__, "HTChunkCreate2 data"); + } + ch->size = 0; + return ch; +} + + +/* Clear a chunk of all data +** -------------------------- +*/ +PUBLIC void HTChunkClear ARGS1 (HTChunk *,ch) +{ + FREE(ch->data); + ch->size = 0; + ch->allocated = 0; +} + + +/* Free a chunk +** ------------ +*/ +PUBLIC void HTChunkFree ARGS1 (HTChunk *,ch) +{ + FREE(ch->data); + FREE(ch); +} + + +/* Append a character +** ------------------ +*/ +PUBLIC void HTChunkPutc ARGS2 (HTChunk *,ch, char,c) +{ + if (ch->size >= ch->allocated) { + ch->allocated = ch->allocated + ch->growby; + ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (!ch->data) + outofmem(__FILE__, "HTChunkPutc"); + } + ch->data[ch->size++] = c; +} + + +/* Ensure a certain size +** --------------------- +*/ +PUBLIC void HTChunkEnsure ARGS2 (HTChunk *,ch, int,needed) +{ + if (needed <= ch->allocated) return; + ch->allocated = needed-1 - ((needed-1) % ch->growby) + + ch->growby; /* Round up */ + ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (ch->data == NULL) + outofmem(__FILE__, "HTChunkEnsure"); +} + +PUBLIC void HTChunkPutb ARGS3 (HTChunk *,ch, CONST char *,b, int,l) +{ + int needed = ch->size + l; + if (l <= 0) return; + if (needed > ch->allocated) { + ch->allocated = needed-1 - ((needed-1) % ch->growby) + + ch->growby; /* Round up */ + ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (ch->data == NULL) + outofmem(__FILE__, "HTChunkPutb"); + } + memcpy(ch->data + ch->size, b, l); + ch->size += l; +} + +#define PUTC(code) ch->data[ch->size++] = (char)(code) +#define PUTC2(code) ch->data[ch->size++] = (char)(0x80|(0x3f &(code))) + +PUBLIC void HTChunkPutUtf8Char ARGS2( + HTChunk *, ch, + UCode_t, code) +{ + int utflen; + + if (code < 128) + utflen = 1; + else if (code < 0x800L) { + utflen = 2; + } else if (code < 0x10000L) { + utflen = 3; + } else if (code < 0x200000L) { + utflen = 4; + } else if (code < 0x4000000L) { + utflen = 5; + } else if (code<=0x7fffffffL) { + utflen = 6; + } else + utflen = 0; + + if (ch->size + utflen > ch->allocated) { + int growby = (ch->growby >= utflen) ? ch->growby : utflen; + ch->allocated = ch->allocated + growby; + ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (!ch->data) + outofmem(__FILE__, "HTChunkPutUtf8Char"); + } + + switch (utflen) { + case 0: + return; + case 1: + ch->data[ch->size++] = (char)code; + return; + case 2: + PUTC(0xc0 | (code>>6)); + break; + case 3: + PUTC(0xe0 | (code>>12)); + break; + case 4: + PUTC(0xf0 | (code>>18)); + break; + case 5: + PUTC(0xf8 | (code>>24)); + break; + case 6: + PUTC(0xfc | (code>>30)); + } + switch (utflen) { + case 6: + PUTC2(code>>24); + case 5: + PUTC2(code>>18); + case 4: + PUTC2(code>>12); + case 3: + PUTC2(code>>6); + case 2: + PUTC2(code); + } +} + +/* Terminate a chunk +** ----------------- +*/ +PUBLIC void HTChunkTerminate ARGS1 (HTChunk *,ch) +{ + HTChunkPutc(ch, (char)0); +} + + +/* Append a string +** --------------- +*/ +PUBLIC void HTChunkPuts ARGS2 (HTChunk *,ch, CONST char *,s) +{ + CONST char * p; + for (p=s; *p; p++) + HTChunkPutc(ch, *p); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.h new file mode 100644 index 00000000000..37ef890c95f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.h @@ -0,0 +1,171 @@ +/* HTChunk: Flexible array handling for libwww + CHUNK HANDLING: + FLEXIBLE ARRAYS + + This module implements a flexible array. It is a general utility module. A chunk is a + structure which may be extended. These routines create and append data to chunks, + automatically reallocating them as necessary. + + */ +#include "UCMap.h" + +typedef struct { + int size; /* In bytes */ + int growby; /* Allocation unit in bytes */ + int allocated; /* Current size of *data */ + char * data; /* Pointer to malloced area or 0 */ +} HTChunk; + + +#ifdef SHORT_NAMES +#define HTChunkClear HTChClea +#define HTChunkPutc HTChPutc +#define HTChunkPuts HTChPuts +#define HTChunkCreate HTChCrea +#define HTChunkTerminate HTChTerm +#define HTChunkEnsure HtChEnsu +#endif + + +/* + +Create new chunk + + ON ENTRY, + + growby The number of bytes to allocate at a time when the chunk is + later extended. Arbitrary but normally a trade-off time vs. + memory + + ON EXIT, + + returns A chunk pointer to the new chunk, + + */ + +extern HTChunk * HTChunkCreate PARAMS((int growby)); + +/* + * Like HTChunkCreate but with initial allocation - kw + * + */ +extern HTChunk * HTChunkCreate2 PARAMS((int growby, size_t needed)); + + +/* + +Free a chunk + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + ON EXIT, + + ch is invalid and may not be used. + + */ + +extern void HTChunkFree PARAMS((HTChunk * ch)); + + +/* + +Clear a chunk + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + ON EXIT, + + *ch The size of the chunk is zero. + + */ + +extern void HTChunkClear PARAMS((HTChunk * ch)); + + +/* + +Ensure a chunk has a certain space in + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + s The size required + + ON EXIT, + + *ch Has size at least s + + */ + +extern void HTChunkEnsure PARAMS((HTChunk * ch, int s)); + + +/* + +Append a character to a chunk + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + c The character to be appended + + ON EXIT, + + *ch Is one character bigger + + */ +extern void HTChunkPutc PARAMS((HTChunk * ch, char c)); + +extern void HTChunkPutb PARAMS((HTChunk * ch, CONST char *b, int l)); + +extern void HTChunkPutUtf8Char PARAMS((HTChunk * ch, UCode_t code)); + +/* +Append a string to a chunk + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + str Tpoints to a zero-terminated string to be appended + + ON EXIT, + + *ch Is bigger by strlen(str) + + */ + + +extern void HTChunkPuts PARAMS((HTChunk * ch, const char *str)); + + +/* + +Append a zero character to a chunk + + */ + +/* + + ON ENTRY, + + ch A valid chunk pointer made by HTChunkCreate() + + ON EXIT, + + *ch Is one character bigger + + */ + + +extern void HTChunkTerminate PARAMS((HTChunk * ch)); + +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.c new file mode 100644 index 00000000000..5e22915b1ed --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.c @@ -0,0 +1,94 @@ +/* DOS specific routines + + */ + +#include <mem.h> +#include <dos.h> + + +/* PUBLIC HTDOS_wwwName() +** CONVERTS DOS Name into WWW Name +** ON ENTRY: +** dosname DOS file specification (NO NODE) +** +** ON EXIT: +** returns WWW file specification +** +*/ +char * HTDOS_wwwName (char *dosname) +{ + static char wwwname[1024]; + char *cp_url = wwwname; + + strcpy(wwwname,dosname); + + for ( ; *cp_url != '\0' ; cp_url++) + if(*cp_url == '\\') *cp_url = '/'; /* convert dos backslash to unix-style */ + + if(strlen(wwwname) > 3 && *cp_url == '/') + *cp_url = '\0'; + + if(*cp_url == ':') + { + cp_url++; + *cp_url = '/'; + } + +/* + if((strlen(wwwname)>2)&&(wwwname[1]==':')) wwwname[1]='|'; + printf("\n\nwww: %s\n\ndos: %s\n\n",wwwname,dosname); + sleep(5); +*/ + return(wwwname); +} + + +/* PUBLIC HTDOS_name() +** CONVERTS WWW name into a DOS name +** ON ENTRY: +** wwwname WWW file name +** +** ON EXIT: +** returns DOS file specification +** +** Bug(?): Returns pointer to input string, which is modified +*/ +char * HTDOS_name(char *wwwname) +{ + static char cp_url[1024]; + int joe; + + memset(cp_url, 0, 1023); + sprintf(cp_url, "%s",wwwname); + + for(joe = 0; cp_url[joe] != '\0'; joe++) { + if(cp_url[joe] == '/') { + cp_url[joe] = '\\'; + } + } + +/* if(strlen(cp_url) < 4) cp_url[] = ':'; + if(strlen(cp_url) == 3) cp_url[3] = '\\'; + + if(strlen(cp_url) == 4) cp_url[4] = '.'; */ + + if((strlen(cp_url) > 2) && (cp_url[1] == '|')) + cp_url[1] = ':'; + + if((cp_url[1] == '\\') || (cp_url[0] != '\\')) + { +#if 0 + printf("\n\n%s = i%\n\n",cp_url,strlen(cp_url)); + sleep(5); +#endif + strcpy(wwwname, cp_url); + return(wwwname); /* return(cp_url); */ + } else { +#if 0 + printf("\n\n%s = %i\n\n",cp_url+1,strlen(cp_url)); + sleep(5); +#endif + strcpy(wwwname, cp_url+1); + return(wwwname); /* return(cp_url+1); */ + } +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.h new file mode 100644 index 00000000000..d2a2e0beec1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.h @@ -0,0 +1,32 @@ +/* DOS specific routines */ + +#ifndef HTDOS_H +#define HTDOS_H + + +/* PUBLIC HTDOS_wwwName() +** CONVERTS DOS Name into WWW Name +** ON ENTRY: +** dosname DOS file specification (NO NODE) +** +** ON EXIT: +** returns WWW file specification +** +*/ +char * HTDOS_wwwName (char * dosname); + + +/* PUBLIC HTDOS_name() +** CONVERTS WWW name into a DOS name +** ON ENTRY: +** wwwname WWW file name +** +** ON EXIT: +** returns DOS file specification +** +** Bug: Returns pointer to static -- non-reentrant +*/ +char * HTDOS_name (char * wwwname); + + +#endif /* HTDOS_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.c new file mode 100644 index 00000000000..8c014f76e9f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.c @@ -0,0 +1,3399 @@ +/* File Transfer Protocol (FTP) Client +** for a WorldWideWeb browser +** =================================== +** +** A cache of control connections is kept. +** +** Note: Port allocation +** +** It is essential that the port is allocated by the system, rather +** than chosen in rotation by us (POLL_PORTS), or the following +** problem occurs. +** +** It seems that an attempt by the server to connect to a port which has +** been used recently by a listen on the same socket, or by another +** socket this or another process causes a hangup of (almost exactly) +** one minute. Therefore, we have to use a rotating port number. +** The problem remains that if the application is run twice in quick +** succession, it will hang for what remains of a minute. +** +** Authors +** TBL Tim Berners-lee <timbl@info.cern.ch> +** DD Denis DeLaRoca 310 825-4580 <CSP1DWD@mvs.oac.ucla.edu> +** LM Lou Montulli <montulli@ukanaix.cc.ukans.edu> +** FM Foteos Macrides <macrides@sci.wfeb.edu> +** History: +** 2 May 91 Written TBL, as a part of the WorldWideWeb project. +** 15 Jan 92 Bug fix: close() was used for NETCLOSE for control soc +** 10 Feb 92 Retry if cached connection times out or breaks +** 8 Dec 92 Bug fix 921208 TBL after DD +** 17 Dec 92 Anon FTP password now just WWWuser@ suggested by DD +** fails on princeton.edu! +** 27 Dec 93 (FM) Fixed up so FTP now works with VMS hosts. Path +** must be Unix-style and cannot include the device +** or top directory. +** ?? ??? ?? (LM) Added code to prompt and send passwords for non +** anonymous FTP +** 25 Mar 94 (LM) Added code to recognize different ftp server types +** and code to parse dates and sizes on most hosts. +** 27 Mar 93 (FM) Added code for getting dates and sizes on VMS hosts. +** +** Options: +** LISTEN We listen, the other guy connects for data. +** Otherwise, other way round, but problem finding our +** internet address! +** +** Notes: +** Portions Copyright 1994 Trustees of Dartmouth College +** Code for recognizing different FTP servers and +** parsing "ls -l" output taken from Macintosh Fetch +** program with permission from Jim Matthews, +** Dartmouth Software Development Team. +*/ + +/* +** If LISTEN is not defined, PASV is used instead of PORT, and not +** all FTP servers support PASV, so define it unless there is no +** alternative for your system. +*/ +#ifndef NOPORT +#define LISTEN /* @@@@ Test LJM */ +#endif /* !NOPORT */ + +/* +BUGS: @@@ Limit connection cache size! + Error reporting to user. + 400 & 500 errors are acked by user with windows. + Use configuration file for user names + +** Note for portablility this version does not use select() and +** so does not watch the control and data channels at the +** same time. +*/ + +#ifdef DJGPP +#define u_long unsigned long +#endif + +#include "HTUtils.h" +#include "tcp.h" + +#include "HTAlert.h" + +#include "HTFTP.h" /* Implemented here */ + +/* this define should be in HTFont.h :( */ +#define HT_NON_BREAK_SPACE ((char)1) /* For now */ + +#define REPEAT_PORT /* Give the port number for each file */ +#define REPEAT_LISTEN /* Close each listen socket and open a new one */ + +/* define POLL_PORTS If allocation does not work, poll ourselves.*/ +#define LISTEN_BACKLOG 2 /* Number of pending connect requests (TCP)*/ + +#define FIRST_TCP_PORT 1024 /* Region to try for a listening port */ +#define LAST_TCP_PORT 5999 + +#define LINE_LENGTH 256 +#define COMMAND_LENGTH 256 + +#define INFINITY 512 + +#include "HTParse.h" +#include "HTTCP.h" +#include "HTAnchor.h" +#include "HTFile.h" /* For HTFileFormat() */ +#include "HTBTree.h" +#include "HTChunk.h" +#include "HTAlert.h" +#ifndef IPPORT_FTP +#define IPPORT_FTP 21 +#endif /* !IPORT_FTP */ + +#include "LYLeaks.h" + +typedef struct _connection { + struct _connection * next; /* Link on list */ + u_long addr; /* IP address */ + int socket; /* Socket number for communication */ + BOOL binary; /* Binary mode? */ +} connection; + +#ifndef NIL +#define NIL 0 +#endif /* !NIL */ + +/* Hypertext object building machinery +*/ +#include "HTML.h" + +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET (*targetClass._free)(target) +#define ABORT_TARGET (*targetClass._free)(target) +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern int HTCheckForInterrupt NOPARAMS; + + +/* Global Variables +** --------------------- +*/ +PUBLIC BOOLEAN HTfileSortMethod = FILE_BY_NAME; +PRIVATE char ThisYear[8]; +PRIVATE char LastYear[8]; +PRIVATE int TheDate; +PRIVATE BOOLEAN HaveYears = FALSE; +#ifdef SOCKS +extern BOOLEAN socks_flag; +extern unsigned long socks_bind_remoteAddr; +#endif /* SOCKS */ +extern char *personal_mail_address; + +/* Module-Wide Variables +** --------------------- +*/ +PRIVATE connection * connections = NULL;/* Linked list of connections */ +PRIVATE char response_text[LINE_LENGTH+1];/* Last response from ftp host */ +PRIVATE connection * control = NULL; /* Current connection */ +PRIVATE int data_soc = -1; /* Socket for data transfer =invalid */ +PRIVATE char *user_entered_password = NULL; +PRIVATE char *last_username_and_host = NULL; + +#define GENERIC_SERVER 0 +#define MACHTEN_SERVER 1 +#define UNIX_SERVER 2 +#define VMS_SERVER 3 +#define CMS_SERVER 4 +#define DCTS_SERVER 5 +#define TCPC_SERVER 6 +#define PETER_LEWIS_SERVER 7 +#define NCSA_SERVER 8 +#define WINDOWS_NT_SERVER 9 +#define MS_WINDOWS_SERVER 10 +#define MSDOS_SERVER 11 +#define APPLESHARE_SERVER 12 +#define NETPRESENZ_SERVER 13 + +PRIVATE int server_type = GENERIC_SERVER; /* the type of ftp host */ +PRIVATE int unsure_type = FALSE; /* sure about the type? */ +PRIVATE BOOLEAN use_list = FALSE; /* use the LIST command? */ + +PRIVATE int interrupted_in_next_data_char = FALSE; + +#ifdef POLL_PORTS +PRIVATE unsigned short port_number = FIRST_TCP_PORT; +#endif /* POLL_PORTS */ + +#ifdef LISTEN +PRIVATE int master_socket = -1; /* Listening socket = invalid */ +PRIVATE char port_command[255]; /* Command for setting the port */ +PRIVATE fd_set open_sockets; /* Mask of active channels */ +PRIVATE int num_sockets; /* Number of sockets to scan */ +#else +PRIVATE unsigned short passive_port; /* Port server specified for data */ +#endif /* LISTEN */ + + +#define NEXT_CHAR HTGetCharacter() /* Use function in HTFormat.c */ + +#define DATA_BUFFER_SIZE 2048 +PRIVATE char data_buffer[DATA_BUFFER_SIZE]; /* Input data buffer */ +PRIVATE char * data_read_pointer; +PRIVATE char * data_write_pointer; +#define NEXT_DATA_CHAR next_data_char() +PRIVATE int close_connection PARAMS(( + connection * con)); + + +/* +** This function frees module globals. - FM +*/ +PRIVATE void free_FTPGlobals NOARGS +{ + FREE(user_entered_password); + FREE(last_username_and_host); + if (control) { + if (control->socket != -1) + close_connection(control); + FREE(control); + } +} + +/* PUBLIC HTMake_VMS_name() +** CONVERTS WWW name into a VMS name +** ON ENTRY: +** nn Node Name (optional) +** fn WWW file name +** +** ON EXIT: +** returns vms file specification +** +** Bug: Returns pointer to static -- non-reentrant +*/ +PUBLIC char * HTMake_VMS_name ARGS2( + CONST char *, nn, + CONST char *, fn) +{ + +/* We try converting the filename into Files-11 syntax. That is, we assume +** first that the file is, like us, on a VMS node. We try remote +** (or local) DECnet access. Files-11, VMS, VAX and DECnet +** are trademarks of Digital Equipment Corporation. +** The node is assumed to be local if the hostname WITHOUT DOMAIN +** matches the local one. @@@ +*/ + static char vmsname[INFINITY]; /* returned */ + char * filename = (char*)malloc(strlen(fn)+1); + char * nodename = (char*)malloc(strlen(nn)+2+1); /* Copies to hack */ + char *second; /* 2nd slash */ + char *last; /* last slash */ + + CONST char * hostname = HTHostName(); + + if (!filename || !nodename) + outofmem(__FILE__, "HTVMSname"); + strcpy(filename, fn); + strcpy(nodename, ""); /* On same node? Yes if node names match */ + if (strncmp(nn, "localhost", 9)) { + CONST char *p; + char *q; + for (p = hostname, q = (char *)nn; + *p && *p != '.' && *q && *q != '.'; p++, q++){ + if (TOUPPER(*p) != TOUPPER(*q)) { + strcpy(nodename, nn); + q = strchr(nodename, '.'); /* Mismatch */ + if (q) + *q = '\0'; /* Chop domain */ + strcat(nodename, "::"); /* Try decnet anyway */ + break; + } + } + } + + second = strchr(filename+1, '/'); /* 2nd slash */ + last = strrchr(filename, '/'); /* last slash */ + + if (!second) { /* Only one slash */ + sprintf(vmsname, "%s%s", nodename, filename + 1); + } else if (second == last) { /* Exactly two slashes */ + *second = '\0'; /* Split filename from disk */ + sprintf(vmsname, "%s%s:%s", nodename, filename+1, second+1); + *second = '/'; /* restore */ + } else { /* More than two slashes */ + char * p; + *second = '\0'; /* Split disk from directories */ + *last = '\0'; /* Split dir from filename */ + sprintf(vmsname, "%s%s:[%s]%s", + nodename, filename+1, second+1, last+1); + *second = *last = '/'; /* restore filename */ + for (p = strchr(vmsname, '['); *p!=']'; p++) + if (*p == '/') + *p = '.'; /* Convert dir sep. to dots */ + } + FREE(nodename); + FREE(filename); + return vmsname; +} + +/* Procedure: Read a character from the data connection +** ---------------------------------------------------- +*/ +PRIVATE char next_data_char NOARGS +{ + int status; + if (data_read_pointer >= data_write_pointer) { + status = NETREAD(data_soc, data_buffer, DATA_BUFFER_SIZE); + if (status == HT_INTERRUPTED) + interrupted_in_next_data_char = 1; + if (status <= 0) + return (char)-1; + data_write_pointer = data_buffer + status; + data_read_pointer = data_buffer; + } +#ifdef NOT_ASCII + { + char c = *data_read_pointer++; + return FROMASCII(c); + } +#else + return *data_read_pointer++; +#endif /* NOT_ASCII */ +} + + +/* Close an individual connection +** +*/ +PRIVATE int close_connection ARGS1( + connection *, con) +{ + connection * scan; + int status = NETCLOSE(con->socket); + if (TRACE) { + fprintf(stderr, "HTFTP: Closing control socket %d\n", con->socket); +#ifdef UNIX + if (status != 0) + perror("HTFTP:close_connection"); +#endif + } + con->socket = -1; + if (connections == con) { + connections = con->next; + return status; + } + for (scan = connections; scan; scan = scan->next) { + if (scan->next == con) { + scan->next = con->next; /* Unlink */ + if (control == con) + control = (connection*)0; + return status; + } /*if */ + } /* for */ + return -1; /* very strange -- was not on list. */ +} + +PRIVATE char *help_message_buffer = NULL; /* global :( */ + +PRIVATE void init_help_message_cache NOARGS +{ + FREE(help_message_buffer); +} + +PRIVATE void help_message_cache_add ARGS1( + char *, string) +{ + if (help_message_buffer) + StrAllocCat(help_message_buffer, string); + else + StrAllocCopy(help_message_buffer, string); + + if (TRACE) + fprintf(stderr,"Adding message to help cache: %s\n",string); +} + +PRIVATE char *help_message_cache_non_empty NOARGS +{ + return(help_message_buffer); +} +PRIVATE char *help_message_cache_contents NOARGS +{ + return(help_message_buffer); +} + +/* Execute Command and get Response +** -------------------------------- +** +** See the state machine illustrated in RFC959, p57. This implements +** one command/reply sequence. It also interprets lines which are to +** be continued, which are marked with a "-" immediately after the +** status code. +** +** Continuation then goes on until a line with a matching reply code +** an a space after it. +** +** On entry, +** con points to the connection which is established. +** cmd points to a command, or is NIL to just get the response. +** +** The command is terminated with the CRLF pair. +** +** On exit, +** returns: The first digit of the reply type, +** or negative for communication failure. +*/ +PRIVATE int response ARGS1( + char *, cmd) +{ + int result; /* Three-digit decimal code */ + int continuation_response = -1; + int status; + + if (!control) { + if (TRACE) + fprintf(stderr, "HTFTP: No control connection set up!!\n"); + return -99; + } + + if (cmd) { + if (TRACE) + fprintf(stderr, " Tx: %s", cmd); +#ifdef NOT_ASCII + { + char * p; + for (p = cmd; *p; p++) { + *p = TOASCII(*p); + } + } +#endif /* NOT_ASCII */ + status = NETWRITE(control->socket, cmd, (int)strlen(cmd)); + if (status < 0) { + if (TRACE) + fprintf(stderr, + "HTFTP: Error %d sending command: closing socket %d\n", + status, control->socket); + close_connection(control); + return status; + } + } + + do { + char *p = response_text; + for (;;) { + if (((*p++ = NEXT_CHAR) == LF) + || (p == &response_text[LINE_LENGTH])) { + + char continuation; + + if (interrupted_in_htgetcharacter) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted in HTGetCharacter, apparently.\n"); + NETCLOSE (control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + + *p = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, " Rx: %s", response_text); + + /* Check for login or help messages */ + if (!strncmp(response_text,"230-",4) || + !strncmp(response_text,"250-",4) || + !strncmp(response_text,"220-",4)) + help_message_cache_add(response_text+4); + + sscanf(response_text, "%d%c", &result, &continuation); + if (continuation_response == -1) { + if (continuation == '-') /* start continuation */ + continuation_response = result; + } else { /* continuing */ + if (continuation_response == result && + continuation == ' ') + continuation_response = -1; /* ended */ + } + break; + } /* if end of line */ + + if (interrupted_in_htgetcharacter) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted in HTGetCharacter, apparently.\n"); + NETCLOSE (control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + + if (*(p-1) == (char) EOF) { + if (TRACE) + fprintf(stderr, "Error on rx: closing socket %d\n", + control->socket); + strcpy(response_text, "000 *** TCP read error on response\n"); + close_connection(control); + return -1; /* End of file on response */ + } + } /* Loop over characters */ + + } while (continuation_response != -1); + + if (result == 421) { + if (TRACE) + fprintf(stderr, "HTFTP: They close so we close socket %d\n", + control->socket); + close_connection(control); + return -1; + } + if ((result == 255 && server_type == CMS_SERVER) && + (0 == strncasecomp(cmd, "CWD", 3) || + 0 == strcasecomp(cmd, "CDUP"))) { + /* + ** Alas, CMS returns 255 on failure to CWD to parent of root. - PG + */ + result = 555; + } + return result/100; +} + +/* + * This function should try to set the macintosh server into binary mode. + * Some servers need an additional letter after the MACB command. + */ +PRIVATE int set_mac_binary ARGS1( + int, ServerType) +{ + /* try to set mac binary mode */ + if (ServerType == APPLESHARE_SERVER || + ServerType == NETPRESENZ_SERVER) { + /* + * Presumably E means "Enable". - KW + */ + return(2 == response("MACB E\r\n")); + } else { + return(2 == response("MACB\r\n")); + } +} + +/* This function gets the current working directory to help + * determine what kind of host it is + */ + +PRIVATE void get_ftp_pwd ARGS2( + int *, ServerType, + BOOLEAN *, UseList) +{ + + char *cp; + /* get the working directory (to see what it looks like) */ + int status = response("PWD\r\n"); + if (status < 0) { + return; + } else { + cp = strchr(response_text+5,'"'); + if (cp) + *cp = '\0'; + if (*ServerType == TCPC_SERVER) { + *ServerType = ((response_text[5] == '/') ? + NCSA_SERVER : TCPC_SERVER); + if (TRACE) + fprintf(stderr, "HTFTP: Treating as %s server.\n", + ((*ServerType == NCSA_SERVER) ? + "NCSA" : "TCPC")); + } else if (response_text[5] == '/') { + /* path names beginning with / imply Unix, + * right? + */ + if (set_mac_binary(*ServerType)) { + *ServerType = NCSA_SERVER; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as NCSA server.\n"); + } else { + *ServerType = UNIX_SERVER; + *UseList = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as Unix server.\n"); + } + return; + } else if (response_text[strlen(response_text)-1] == ']') { + /* path names ending with ] imply VMS, right? */ + *ServerType = VMS_SERVER; + *UseList = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as VMS server.\n"); + } else { + *ServerType = GENERIC_SERVER; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as Generic server.\n"); + } + + if ((*ServerType == NCSA_SERVER) || + (*ServerType == TCPC_SERVER) || + (*ServerType == PETER_LEWIS_SERVER) || + (*ServerType == NETPRESENZ_SERVER)) + set_mac_binary(*ServerType); + } +} + +/* Get a valid connection to the host +** ---------------------------------- +** +** On entry, +** arg points to the name of the host in a hypertext address +** On exit, +** returns <0 if error +** socket number if success +** +** This routine takes care of managing timed-out connections, and +** limiting the number of connections in use at any one time. +** +** It ensures that all connections are logged in if they exist. +** It ensures they have the port number transferred. +*/ +PRIVATE int get_connection ARGS2( + CONST char *, arg, + HTParentAnchor *, anchor) +{ + int status; + char * command; + connection * con; + char * username = NULL; + char * password = NULL; + static BOOLEAN firstuse = TRUE; + + if (firstuse) { + /* + ** Set up freeing at exit. - FM + */ + atexit(free_FTPGlobals); + firstuse = FALSE; + } + + if (control) { + /* + ** Reuse this object - KW, DW & FM + */ + if (control->socket != -1) { + NETCLOSE(control->socket); + } + con = control; + con->addr = 0; + con->binary = FALSE; + } else { + /* + ** Allocate and init control struct. + */ + con = (connection *)calloc(1, sizeof(connection)); + if (con == NULL) + outofmem(__FILE__, "get_connection"); + } + con->socket = -1; + + if (!arg) return -1; /* Bad if no name specified */ + if (!*arg) return -1; /* Bad if name had zero length */ + +/* Get node name: +*/ + { + char *p1 = HTParse(arg, "", PARSE_HOST); + char *p2 = strrchr(p1, '@'); /* user? */ + char * pw = NULL; + + if (p2 != NULL) { + username = p1; + *p2 = '\0'; /* terminate */ + p1 = p2+1; /* point to host */ + pw = strchr(username, ':'); + if (pw != NULL) { + *pw++ = '\0'; + password = HTUnEscape(pw); + } + if (*username) + HTUnEscape(username); + + /* + * If the password doesn't exist then we are going to have + * to ask the user for it. The only problem is that we + * don't want to ask for it every time, so we will store + * away in a primitive fashion. + */ + if (!password) { + char tmp[256]; + + sprintf(tmp, "%s@%s", username, p1); + /* + * If the user@host is not equal to the last time through + * or user_entered_password has no data then we need + * to ask the user for the password. + */ + if (!last_username_and_host || + strcmp(tmp, last_username_and_host) || + !user_entered_password) { + + StrAllocCopy(last_username_and_host, tmp); + sprintf(tmp, "Enter password for user %s@%s:", + username, p1); + FREE(user_entered_password); + user_entered_password = (char *)HTPromptPassword(tmp); + + } /* else we already know the password */ + password = user_entered_password; + } + } + + if (!username) + FREE(p1); + } /* scope of p1 */ + + status = HTDoConnect (arg, "FTP", IPPORT_FTP, (int *)&con->socket); + + if (status < 0) + { + if (TRACE) + { + if (status == HT_INTERRUPTED) + fprintf (stderr, + "HTFTP: Interrupted on connect\n"); + else + fprintf(stderr, + "HTFTP: Unable to connect to remote host for `%s'.\n", + arg); + } + if (status == HT_INTERRUPTED) { + _HTProgress ("Connection interrupted."); + status = HT_NOT_LOADED; + } else { + HTAlert("Unable to connect to FTP host."); + } + if (con->socket != -1) + { + NETCLOSE(con->socket); + } + + FREE(username); + if (control == con) + control = NULL; + FREE(con); + return status; /* Bad return */ + } + + if (TRACE) { + fprintf(stderr, "FTP connected, socket %d control %ld\n", + con->socket, (long)con); + } + control = con; /* Current control connection */ + + /* Initialise buffering for control connection */ + HTInitInput(control->socket); + init_help_message_cache(); /* Clear the login message buffer. */ + + +/* Now we log in Look up username, prompt for pw. +*/ + status = response((char *)0); /* Get greeting */ + + if (status == HT_INTERRUPTED) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted at beginning of login.\n"); + _HTProgress ("Connection interrupted."); + NETCLOSE(control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + server_type = GENERIC_SERVER; /* reset */ + if (status == 2) { /* Send username */ + char *cp; /* look at greeting text */ + + if (strlen(response_text) > 4) { + if ((cp = strstr(response_text, " awaits your command")) || + (cp = strstr(response_text, " ready."))) { + *cp = '\0'; + } + cp = response_text + 4; + if (!strncasecomp(cp, "NetPresenz", 10)) + server_type = NETPRESENZ_SERVER; + } else { + cp = response_text; + } + StrAllocCopy(anchor->server, cp); + + if (username && *username) { + command = (char*)malloc(10+strlen(username)+2+1); + if (command == NULL) + outofmem(__FILE__, "get_connection"); + sprintf(command, "USER %s%c%c", username, CR, LF); + } else { + command = (char*)malloc(24); + if (command == NULL) + outofmem(__FILE__, "get_connection"); + sprintf(command, "USER anonymous%c%c", CR, LF); + } + status = response(command); + FREE(command); + if (status == HT_INTERRUPTED) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted while sending username.\n"); + _HTProgress ("Connection interrupted."); + NETCLOSE(control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + } + if (status == 3) { /* Send password */ + if (password) { + /* + * We have non-zero length password, so send it. - FM + */ + command = (char*)malloc(10+strlen(password)+2+1); + if (command == NULL) + outofmem(__FILE__, "get_connection"); + sprintf(command, "PASS %s%c%c", password, CR, LF); + } else { + /* + * Create and send a mail address as the password. - FM + */ + char *user = NULL; + CONST char *host = NULL; + char * cp; + + if (personal_mail_address && *personal_mail_address) { + /* + * We have a non-zero length personal + * mail address, so use that. - FM + */ + StrAllocCopy(user, personal_mail_address); + if ((cp=strchr(user, '@')) != NULL) { + *cp++ = '\0'; + host = cp; + } else { + host = HTHostName(); + } + } else { + /* + * Use an environment variable and the host global. - FM + */ + if ((cp=getenv("USER")) != NULL) + StrAllocCopy(user, cp); + else + StrAllocCopy(user, "WWWuser"); + host = HTHostName(); + } + + /* + * If host is not fully qualified, suppress it + * as ftp.uu.net prefers a blank to a bad name + */ + if (!(host) || strchr(host, '.') == NULL) + host = ""; + + command = (char*)malloc(10+strlen(user)+1+strlen(host)+2+1); + if (command == NULL) + outofmem(__FILE__, "get_connection"); + sprintf(command, "PASS %s@%s%c%c", user, host, CR, LF); + FREE(user); + } + status = response(command); + FREE(command); + if (status == HT_INTERRUPTED) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted while sending password.\n"); + _HTProgress ("Connection interrupted."); + NETCLOSE(control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + } + FREE(username); + + if (status == 3) { + char temp[80]; + sprintf(temp, "ACCT noaccount%c%c", CR, LF); + status = response(temp); + if (status == HT_INTERRUPTED) + { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted while sending password.\n"); + _HTProgress ("Connection interrupted."); + NETCLOSE(control->socket); + control->socket = -1; + return HT_INTERRUPTED; + } + + } + if (status != 2) { + if (TRACE) + fprintf(stderr, "HTFTP: Login fail: %s", response_text); + /* if (control->socket > 0) close_connection(control->socket); */ + return -1; /* Bad return */ + } + if (TRACE) fprintf(stderr, "HTFTP: Logged in.\n"); + + /** Check for host type **/ + if (server_type != NETPRESENZ_SERVER) + server_type = GENERIC_SERVER; /* reset */ + use_list = FALSE; /* reset */ + if ((status=response("SYST\r\n")) == 2) { + /* we got a line -- what kind of server are we talking to? */ + if (strncmp(response_text+4, + "UNIX Type: L8 MAC-OS MachTen", 28) == 0) { + server_type = MACHTEN_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as MachTen server.\n"); + + } else if (strstr(response_text+4, "UNIX") != NULL || + strstr(response_text+4, "Unix") != NULL) { + server_type = UNIX_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as Unix server.\n"); + + } else if (strstr(response_text+4, "MSDOS") != NULL) { + server_type = MSDOS_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, + "HTFTP: Treating as MSDOS (Unix emulation) server.\n"); + + } else if (strncmp(response_text+4, "VMS", 3) == 0) { + server_type = VMS_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as VMS server.\n"); + + } else if ((strncmp(response_text+4, "VM/CMS", 6) == 0) || + (strncmp(response_text+4, "VM ", 3) == 0)) { + server_type = CMS_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as CMS server.\n"); + + } else if (strncmp(response_text+4, "DCTS", 4) == 0) { + server_type = DCTS_SERVER; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as DCTS server.\n"); + + } else if (strstr(response_text+4, "MAC-OS TCP/Connect II") != NULL) { + server_type = TCPC_SERVER; + if (TRACE) + fprintf(stderr, "HTFTP: Looks like a TCPC server.\n"); + get_ftp_pwd(&server_type, &use_list); + unsure_type = TRUE; + + } else if (server_type == NETPRESENZ_SERVER) { /* already set above */ + use_list = TRUE; + set_mac_binary(server_type); + if (TRACE) + fprintf(stderr, + "HTFTP: Treating as NetPresenz (MACOS) server.\n"); + + } else if (strncmp(response_text+4, "MACOS Peter's Server", 20) == 0) { + server_type = PETER_LEWIS_SERVER; + use_list = TRUE; + set_mac_binary(server_type); + if (TRACE) + fprintf(stderr, + "HTFTP: Treating as Peter Lewis (MACOS) server.\n"); + + } else if (strncmp(response_text+4, "Windows_NT", 10) == 0) { + server_type = WINDOWS_NT_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as Window_NT server.\n"); + + } else if (strncmp(response_text+4, "MS Windows", 10) == 0) { + server_type = MS_WINDOWS_SERVER; + use_list = TRUE; + if (TRACE) + fprintf(stderr, "HTFTP: Treating as MS Windows server.\n"); + + } else if (strncmp(response_text+4, + "MACOS AppleShare IP FTP Server", 30) == 0) { + server_type = APPLESHARE_SERVER; + use_list = TRUE; + set_mac_binary(server_type); + if (TRACE) + fprintf(stderr, + "HTFTP: Treating as AppleShare server.\n"); + + } else { + server_type = GENERIC_SERVER; + if (TRACE) + fprintf(stderr, "HTFTP: Ugh! A Generic server.\n"); + get_ftp_pwd(&server_type, &use_list); + unsure_type = TRUE; + } + } else { + /* SYST fails :( try to get the type from the PWD command */ + get_ftp_pwd(&server_type, &use_list); + } + +/* Now we inform the server of the port number we will listen on +*/ +#ifdef NOTREPEAT_PORT + { + int status = response(port_command); + if (status != 2) { + if (control->socket) + close_connection(control->socket); + return -status; /* Bad return */ + } + if (TRACE) + fprintf(stderr, "HTFTP: Port defined.\n"); + } +#endif /* NOTREPEAT_PORT */ + return con->socket; /* Good return */ +} + + +#ifdef LISTEN + +/* Close Master (listening) socket +** ------------------------------- +** +** +*/ +PRIVATE int close_master_socket NOARGS +{ + int status; + FD_CLR(master_socket, &open_sockets); + status = NETCLOSE(master_socket); + if (TRACE) + fprintf(stderr, "HTFTP: Closed master socket %d\n", master_socket); + master_socket = -1; + if (status < 0) + return HTInetStatus("close master socket"); + else + return status; +} + + +/* Open a master socket for listening on +** ------------------------------------- +** +** When data is transferred, we open a port, and wait for the server to +** connect with the data. +** +** On entry, +** master_socket Must be negative if not set up already. +** On exit, +** Returns socket number if good +** less than zero if error. +** master_socket is socket number if good, else negative. +** port_number is valid if good. +*/ +PRIVATE int get_listen_socket NOARGS +{ + struct sockaddr_in soc_address; /* Binary network address */ + struct sockaddr_in* soc_in = &soc_address; + int new_socket; /* Will be master_socket */ + + + FD_ZERO(&open_sockets); /* Clear our record of open sockets */ + num_sockets = 0; + +#ifndef REPEAT_LISTEN + if (master_socket >= 0) + return master_socket; /* Done already */ +#endif /* !REPEAT_LISTEN */ + +/* Create internet socket +*/ + new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (new_socket < 0) + return HTInetStatus("socket for master socket"); + + if (TRACE) + fprintf(stderr, "HTFTP: Opened master socket number %d\n", new_socket); + +/* Search for a free port. +*/ + soc_in->sin_family = AF_INET; /* Family = internet, host order */ + soc_in->sin_addr.s_addr = INADDR_ANY; /* Any peer address */ +#ifdef POLL_PORTS + { + unsigned short old_port_number = port_number; + for (port_number = (old_port_number+1); ; port_number++) { + int status; + if (port_number > LAST_TCP_PORT) + port_number = FIRST_TCP_PORT; + if (port_number == old_port_number) { + return HTInetStatus("bind"); + } + soc_address.sin_port = htons(port_number); +#ifdef SOCKS + if (socks_flag) + if ((status=Rbind(new_socket, + (struct sockaddr*)&soc_address, + /* Cast to generic sockaddr */ + sizeof(soc_address) +#ifndef SHORTENED_RBIND + ,socks_bind_remoteAddr +#endif /* !SHORTENED_RBIND */ + )) == 0) + break; + else +#endif /* SOCKS */ + if ((status=bind(new_socket, + (struct sockaddr*)&soc_address, + /* Cast to generic sockaddr */ + sizeof(soc_address))) == 0) + break; + if (TRACE) + fprintf(stderr, + "TCP bind attempt to port %d yields %d, errno=%d\n", + port_number, status, SOCKET_ERRNO); + } /* for */ + } +#else + { + int status; + int address_length = sizeof(soc_address); +#ifdef SOCKS + if (socks_flag) + status = Rgetsockname(control->socket, + (struct sockaddr *)&soc_address, + (void *)&address_length); + else +#endif /* SOCKS */ + status = getsockname(control->socket, + (struct sockaddr *)&soc_address, + (void *)&address_length); + if (status<0) return HTInetStatus("getsockname"); + CTRACE(tfp, "HTFTP: This host is %s\n", + HTInetString(soc_in)); + + soc_address.sin_port = 0; /* Unspecified: please allocate */ +#ifdef SOCKS + if (socks_flag) + status=Rbind(new_socket, + (struct sockaddr*)&soc_address, + /* Cast to generic sockaddr */ + sizeof(soc_address) +#ifndef SHORTENED_RBIND + ,socks_bind_remoteAddr +#endif /* !SHORTENED_RBIND */ + ); + else +#endif /* SOCKS */ + status=bind(new_socket, + (struct sockaddr*)&soc_address, + /* Cast to generic sockaddr */ + sizeof(soc_address)); + if (status<0) return HTInetStatus("bind"); + + address_length = sizeof(soc_address); +#ifdef SOCKS + if (socks_flag) + status = Rgetsockname(new_socket, + (struct sockaddr*)&soc_address, + (void *)&address_length); + else +#endif /* SOCKS */ + status = getsockname(new_socket, + (struct sockaddr*)&soc_address, + (void *)&address_length); + if (status<0) return HTInetStatus("getsockname"); + } +#endif /* POLL_PORTS */ + + CTRACE(tfp, "HTFTP: bound to port %d on %s\n", + (int)ntohs(soc_in->sin_port), + HTInetString(soc_in)); + +#ifdef REPEAT_LISTEN + if (master_socket >= 0) + (void) close_master_socket(); +#endif /* REPEAD_LISTEN */ + + master_socket = new_socket; + +/* Now we must find out who we are to tell the other guy +*/ + (void)HTHostName(); /* Make address valid - doesn't work*/ + sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d%c%c", + (int)*((unsigned char *)(&soc_in->sin_addr)+0), + (int)*((unsigned char *)(&soc_in->sin_addr)+1), + (int)*((unsigned char *)(&soc_in->sin_addr)+2), + (int)*((unsigned char *)(&soc_in->sin_addr)+3), + (int)*((unsigned char *)(&soc_in->sin_port)+0), + (int)*((unsigned char *)(&soc_in->sin_port)+1), + CR, LF); + + +/* Inform TCP that we will accept connections +*/ + { + int status; +#ifdef SOCKS + if (socks_flag) + status = Rlisten(master_socket, 1); + else +#endif /* SOCKS */ + status = listen(master_socket, 1); + if (status < 0) { + master_socket = -1; + return HTInetStatus("listen"); + } + } + CTRACE(tfp, "TCP: Master socket(), bind() and listen() all OK\n"); + FD_SET(master_socket, &open_sockets); + if ((master_socket+1) > num_sockets) + num_sockets = master_socket+1; + + return master_socket; /* Good */ + +} /* get_listen_socket */ +#endif /* LISTEN */ + +PRIVATE char * months[12] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +/* Procedure: Set the current and last year strings and date integer +** ----------------------------------------------------------------- +** +** Bug: +** This code is for sorting listings by date, if that option +** is selected in Lynx, and doesn't take into account time +** zones or ensure resetting at midnight, so the sort may not +** be perfect, but the actual date isn't changed in the display, +** i.e., the date is still correct. - FM +*/ +PRIVATE void set_years_and_date NOARGS +{ + char day[8], month[8], date[12]; + time_t NowTime; + int i; + + NowTime = time(NULL); + strncpy(day, (char *)ctime(&NowTime)+8, 2); + day[2] = '\0'; + if (day[0] == ' ') { + day[0] = '0'; + } + strncpy(month, (char *)ctime(&NowTime)+4, 3); + strncpy(month, (char *)ctime(&NowTime)+4, 3); + month[3] = '\0'; + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%s%d", (i < 10 ? "0" : ""), i); + sprintf(date, "9999%s%s", month, day); + TheDate = atoi(date); + strcpy(ThisYear, (char *)ctime(&NowTime)+20); + ThisYear[4] = '\0'; + sprintf(LastYear, "%d", (atoi(ThisYear) - 1)); + HaveYears = TRUE; +} + +typedef struct _EntryInfo { + char * filename; + char * type; + char * date; + unsigned int size; + BOOLEAN display; /* show this entry? */ +} EntryInfo; + +PRIVATE void free_entryinfo_struct_contents ARGS1( + EntryInfo *, entry_info) +{ + if (entry_info) { + FREE(entry_info->filename); + FREE(entry_info->type); + FREE(entry_info->date); + } + /* dont free the struct */ +} + +/* + * is_ls_date() -- + * Return TRUE if s points to a string of the form: + * "Sep 1 1990 " or + * "Sep 11 11:59 " or + * "Dec 12 1989 " or + * "FCv 23 1990 " ... + */ +PRIVATE BOOLEAN is_ls_date ARGS1( + char *, s) +{ + /* must start with three alpha characters */ + if (!isalpha(*s++) || !isalpha(*s++) || !isalpha(*s++)) + return FALSE; + + /* space or HT_NON_BREAK_SPACE */ + if (!(*s == ' ' || *s == HT_NON_BREAK_SPACE)) { + s++; + return FALSE; + } + s++; + + /* space or digit */ + if (!(*s == ' ' || isdigit(*s))) { + s++; + return FALSE; + } + s++; + + /* digit */ + if (!isdigit(*s++)) + return FALSE; + + /* space */ + if (*s++ != ' ') + return FALSE; + + /* space or digit */ + if (!(*s == ' ' || isdigit(*s))) { + s++; + return FALSE; + } + s++; + + /* digit */ + if (!isdigit(*s++)) + return FALSE; + + /* colon or digit */ + if (!(*s == ':' || isdigit(*s))) { + s++; + return FALSE; + } + s++; + + /* digit */ + if (!isdigit(*s++)) + return FALSE; + + /* space or digit */ + if (!(*s == ' ' || isdigit(*s))) { + s++; + return FALSE; + } + s++; + + /* space */ + if (*s++ != ' ') + return FALSE; + + return TRUE; +} /* is_ls_date() */ + +/* + * parse_eplf_line() -- + * Extract the name, size, and date from an EPLF line. - 08-06-96 DJB + */ +PRIVATE void parse_eplf_line ARGS2( + char *, line, + EntryInfo *, info) +{ + char *cp = line; + char ct[26]; + unsigned long size; + time_t secs; + static time_t base; /* time() value on this OS in 1970 */ + static int flagbase = 0; + + if (!flagbase) { + struct tm t; + t.tm_year = 70; t.tm_mon = 0; t.tm_mday = 0; + t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; + t.tm_isdst = -1; + base = mktime(&t); /* could return -1 */ + flagbase = 1; + } + + while (*cp) { + switch(*cp) { + case '\t': + StrAllocCopy(info->filename, cp + 1); + return; + case 's': + size = 0; + while (*(++cp) && (*cp != ',')) + size = (size * 10) + (*cp - '0'); + info->size = size; + break; + case 'm': + secs = 0; + while (*(++cp) && (*cp != ',')) + secs = (secs * 10) + (*cp - '0'); + secs += base; /* assumes that time_t is #seconds */ + strcpy(ct, ctime(&secs)); + ct[24] = 0; + StrAllocCopy(info->date, ct); + break; + case '/': + StrAllocCopy(info->type, "Directory"); + default: + while (*cp) { + if (*cp++ == ',') + break; + } + break; + } + } +} /* parse_eplf_line */ + +/* + * parse_ls_line() -- + * Extract the name, size, and date from an ls -l line. + */ +PRIVATE void parse_ls_line ARGS2( + char *, line, + EntryInfo *, entry_info) +{ + short i, j; + int base=1; + int size_num=0; + + for (i = strlen(line) - 1; + (i > 13) && (!isspace(line[i]) || !is_ls_date(&line[i-12])); i--) + ; /* null body */ + line[i] = '\0'; + if (i > 13) { + StrAllocCopy(entry_info->date, &line[i-12]); + /* replace the 4th location with nbsp if it is a space or zero */ + if (entry_info->date[4] == ' ' || entry_info->date[4] == '0') + entry_info->date[4] = HT_NON_BREAK_SPACE; + /* make sure year or time is flush right */ + if (entry_info->date[11] == ' ') { + for (j = 11; j > 6; j--) { + entry_info->date[j] = entry_info->date[j-1]; + } + } + } + j = i - 14; + while (isdigit(line[j])) { + size_num += (line[j] - '0') * base; + base *= 10; + j--; + } + entry_info->size = size_num; + StrAllocCopy(entry_info->filename, &line[i + 1]); +} /* parse_ls_line() */ + +/* + * parse_vms_dir_entry() + * Format the name, date, and size from a VMS LIST line + * into the EntryInfo structure - FM + */ +PRIVATE void parse_vms_dir_entry ARGS2( + char *, line, + EntryInfo *, entry_info) +{ + int i, j, ialloc; + char *cp, *cpd, *cps, date[16], *sp = " "; + + /** Get rid of blank lines, and information lines. **/ + /** Valid lines have the ';' version number token. **/ + if (!strlen(line) || (cp=strchr(line, ';')) == NULL) { + entry_info->display = FALSE; + return; + } + + /** Cut out file or directory name at VMS version number. **/ + *cp++ ='\0'; + StrAllocCopy(entry_info->filename,line); + + /** Cast VMS non-README file and directory names to lowercase. **/ + if (strstr(entry_info->filename, "READ") == NULL) { + for (i = 0; entry_info->filename[i]; i++) + entry_info->filename[i] = TOLOWER(entry_info->filename[i]); + } else { + i = ((strstr(entry_info->filename, "READ") - entry_info->filename) + 4); + if (!strncmp((char *)&entry_info->filename[i], "ME", 2)) { + i += 2; + while (entry_info->filename[i] && entry_info->filename[i] != '.') { + i++; + } + } else if (!strncmp((char *)&entry_info->filename[i], ".ME", 3)) { + i = strlen(entry_info->filename); + } else { + i = 0; + } + for (; entry_info->filename[i]; i++) + entry_info->filename[i] = TOLOWER(entry_info->filename[i]); + } + + /** Uppercase terminal .z's or _z's. **/ + if ((--i > 2) && + entry_info->filename[i] == 'z' && + (entry_info->filename[i-1] == '.' || + entry_info->filename[i-1] == '_')) + entry_info->filename[i] = 'Z'; + + /** Convert any tabs in rest of line to spaces. **/ + cps = cp-1; + while ((cps=strchr(cps+1, '\t')) != NULL) + *cps = ' '; + + /** Collapse serial spaces. **/ + i = 0; j = 1; + cps = cp; + while (cps[j] != '\0') { + if (cps[i] == ' ' && cps[j] == ' ') + j++; + else + cps[++i] = cps[j++]; + } + cps[++i] = '\0'; + + /* Set the years and date, if we don't have them yet. **/ + if (!HaveYears) { + set_years_and_date(); + } + + /** Track down the date. **/ + if ((cpd=strchr(cp, '-')) != NULL && + strlen(cpd) > 9 && isdigit(*(cpd-1)) && + isalpha(*(cpd+1)) && *(cpd+4) == '-') { + + /** Month **/ + *(cpd+4) = '\0'; + *(cpd+2) = TOLOWER(*(cpd+2)); + *(cpd+3) = TOLOWER(*(cpd+3)); + sprintf(date, "%s ", cpd+1); + *(cpd+4) = '-'; + + /** Day **/ + *cpd = '\0'; + if (isdigit(*(cpd-2))) + sprintf(date+4, "%s ", cpd-2); + else + sprintf(date+4, "%c%s ", HT_NON_BREAK_SPACE, cpd-1); + *cpd = '-'; + + /** Time or Year **/ + if (!strncmp(ThisYear, cpd+5, 4) && + strlen(cpd) > 15 && *(cpd+12) == ':') { + *(cpd+15) = '\0'; + sprintf(date+7, "%s", cpd+10); + *(cpd+15) = ' '; + } else { + *(cpd+9) = '\0'; + sprintf(date+7, " %s", cpd+5); + *(cpd+9) = ' '; + } + + StrAllocCopy(entry_info->date, date); + } + + /** Track down the size **/ + if ((cpd=strchr(cp, '/')) != NULL) { + /* Appears be in used/allocated format */ + cps = cpd; + while (isdigit(*(cps-1))) + cps--; + if (cps < cpd) + *cpd = '\0'; + entry_info->size = atoi(cps); + cps = cpd+1; + while (isdigit(*cps)) + cps++; + *cps = '\0'; + ialloc = atoi(cpd+1); + /* Check if used is in blocks or bytes */ + if (entry_info->size <= ialloc) + entry_info->size *= 512; + + } else if ((cps=strtok(cp, sp)) != NULL) { + /* We just initialized on the version number */ + /* Now let's hunt for a lone, size number */ + while ((cps=strtok(NULL, sp)) != NULL) { + cpd = cps; + while (isdigit(*cpd)) + cpd++; + if (*cpd == '\0') { + /* Assume it's blocks */ + entry_info->size = atoi(cps) * 512; + break; + } + } + } + + /** Wrap it up **/ + if (TRACE) + fprintf(stderr, "HTFTP: VMS filename: %s date: %s size: %d\n", + entry_info->filename, + entry_info->date ? entry_info->date : "", + entry_info->size); + return; +} /* parse_vms_dir_entry() */ + +/* + * parse_ms_windows_dir_entry() -- + * Format the name, date, and size from an MS_WINDOWS LIST line into + * the EntryInfo structure (assumes Chameleon NEWT format). - FM + */ +PRIVATE void parse_ms_windows_dir_entry ARGS2( + char *, line, + EntryInfo *, entry_info) +{ + char *cp = line; + char *cps, *cpd, date[16]; + char *end = line + strlen(line); + + /** Get rid of blank or junk lines. **/ + while (*cp && isspace(*cp)) + cp++; + if (!(*cp)) { + entry_info->display = FALSE; + return; + } + + /** Cut out file or directory name. **/ + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ ='\0'; + cpd = cps; + StrAllocCopy(entry_info->filename, cp); + + /** Track down the size **/ + if (cps < end) { + while (*cps && isspace(*cps)) + cps++; + cpd = cps; + while (*cpd && !isspace(*cpd)) + cpd++; + *cpd++ = '\0'; + if (isdigit(*cps)) { + entry_info->size = atoi(cps); + } else { + StrAllocCopy(entry_info->type, "Directory"); + } + } else { + StrAllocCopy(entry_info->type, ""); + } + + /* Set the years and date, if we don't have them yet. **/ + if (!HaveYears) { + set_years_and_date(); + } + + /** Track down the date. **/ + if (cpd < end) { + while (*cpd && isspace(*cpd)) + cpd++; + if (strlen(cpd) > 17) { + *(cpd+6) = '\0'; /* Month and Day */ + *(cpd+11) = '\0'; /* Year */ + *(cpd+17) = '\0'; /* Time */ + if (strcmp(ThisYear, cpd+7)) + /* Not this year, so show the year */ + sprintf(date, "%s %s", cpd, (cpd+7)); + else + /* Is this year, so show the time */ + sprintf(date, "%s %s", cpd, (cpd+12)); + StrAllocCopy(entry_info->date, date); + if (entry_info->date[4] == ' '|| entry_info->date[4] == '0') { + entry_info->date[4] = HT_NON_BREAK_SPACE; + } + } + } + + /** Wrap it up **/ + if (TRACE) + fprintf(stderr, "HTFTP: MS Windows filename: %s date: %s size: %d\n", + entry_info->filename, + entry_info->date ? entry_info->date : "", + entry_info->size); + return; +} /* parse_ms_windows_dir_entry */ + +/* + * parse_windows_nt_dir_entry() -- + * Format the name, date, and size from a WINDOWS_NT LIST line into + * the EntryInfo structure (assumes Chameleon NEWT format). - FM + */ +#ifdef NOTDEFINED +PRIVATE void parse_windows_nt_dir_entry ARGS2( + char *, line, + EntryInfo *, entry_info) +{ + char *cp = line; + char *cps, *cpd, date[16]; + char *end = line + strlen(line); + int i; + + /** Get rid of blank or junk lines. **/ + while (*cp && isspace(*cp)) + cp++; + if (!(*cp)) { + entry_info->display = FALSE; + return; + } + + /** Cut out file or directory name. **/ + cpd = cp; + cps = (end-1); + while (cps >= cpd && !isspace(*cps)) + cps--; + cp = (cps+1); + if (!strcmp(cp, ".") || !strcmp(cp, "..")) { + entry_info->display = FALSE; + return; + } + StrAllocCopy(entry_info->filename, cp); + if (cps < cpd) + return; + *cp = '\0'; + end = cp; + + /* Set the years and date, if we don't have them yet. **/ + if (!HaveYears) { + set_years_and_date(); + } + + /** Cut out the date. **/ + cp = cps = cpd; + while (*cps && !isspace(*cps)) + cps++; + *cps++ ='\0'; + if (cps > end) { + entry_info->display = FALSE; + return; + } + while (*cps && isspace(*cps)) + cps++; + cpd = cps; + while (*cps && !isspace(*cps)) + cps++; + *cps++ ='\0'; + if (cps > end || cpd == cps || strlen(cpd) < 7) { + entry_info->display = FALSE; + return; + } + if (strlen(cp) == 8 && + isdigit(*cp) && isdigit(*(cp+1)) && *(cp+2) == '-' && + isdigit(*(cp+3)) && isdigit(*(cp+4)) && *(cp+5) == '-') { + *(cp+2) = '\0'; /* Month */ + i = atoi(cp) - 1; + *(cp+5) = '\0'; /* Day */ + sprintf(date, "%s %s", months[i], (cp+3)); + if (date[4] == '0') + date[4] = ' '; + cp += 6; /* Year */ + if (strcmp((ThisYear+2), cp)) { + /* Not this year, so show the year */ + if (atoi(cp) < 70) { + sprintf((char *)&date[6], " 20%s", cp); + } else { + sprintf((char *)&date[6], " 19%s", cp); + } + } else { + /* Is this year, so show the time */ + *(cpd+2) = '\0'; /* Hour */ + i = atoi(cpd); + if (*(cpd+5) == 'P' || *(cpd+5) == 'p') + i += 12; + *(cpd+5) = '\0'; + sprintf((char*)&date[6], " %s%d:%s", + (i < 10 ? "0" : ""), i, (cpd+3)); + } + StrAllocCopy(entry_info->date, date); + if (entry_info->date[4] == ' '|| entry_info->date[4] == '0') { + entry_info->date[4] = HT_NON_BREAK_SPACE; + } + } + + /** Track down the size **/ + if (cps < end) { + while (*cps && isspace(*cps)) + cps++; + cpd = cps; + while (*cpd && !isspace(*cpd)) + cpd++; + *cpd = '\0'; + if (isdigit(*cps)) { + entry_info->size = atoi(cps); + } else { + StrAllocCopy(entry_info->type, "Directory"); + } + } else { + StrAllocCopy(entry_info->type, ""); + } + + /** Wrap it up **/ + if (TRACE) + fprintf(stderr, "HTFTP: Windows NT filename: %s date: %s size: %d\n", + entry_info->filename, + entry_info->date ? entry_info->date : "", + entry_info->size); + return; +} /* parse_windows_nt_dir_entry */ +#endif /* NOTDEFINED */ + +/* + * parse_cms_dir_entry() -- + * Format the name, date, and size from a VM/CMS line into + * the EntryInfo structure. - FM + */ +PRIVATE void parse_cms_dir_entry ARGS2( + char *, line, + EntryInfo *, entry_info) +{ + char *cp = line; + char *cps, *cpd, date[16]; + char *end = line + strlen(line); + int RecordLength = 0; + int Records = 0; + int i; + + /** Get rid of blank or junk lines. **/ + while (*cp && isspace(*cp)) + cp++; + if (!(*cp)) { + entry_info->display = FALSE; + return; + } + + /** Cut out file or directory name. **/ + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ ='\0'; + StrAllocCopy(entry_info->filename, cp); + if (strchr(entry_info->filename, '.') != NULL) + /** If we already have a dot, we did an NLST. **/ + return; + cp = cps; + while (*cp && isspace(*cp)) + cp++; + if (!(*cp)) { + /** If we don't have more, we've misparsed. **/ + FREE(entry_info->filename); + FREE(entry_info->type); + entry_info->display = FALSE; + return; + } + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ ='\0'; + if ((0 == strcasecomp(cp, "DIR")) && (cp - line) > 17) { + /** It's an SFS directory. **/ + StrAllocCopy(entry_info->type, "Directory"); + entry_info->size = 0; + } else { + /** It's a file. **/ + cp--; + *cp = '.'; + StrAllocCat(entry_info->filename, cp); + + /** Track down the VM/CMS RECFM or type. **/ + cp = cps; + if (cp < end) { + while (*cp && isspace(*cp)) + cp++; + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ = '\0'; + /** Check cp here, if it's relevant someday. **/ + } + } + + /** Track down the record length or dash. **/ + cp = cps; + if (cp < end) { + while (*cp && isspace(*cp)) + cp++; + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ = '\0'; + if (isdigit(*cp)) { + RecordLength = atoi(cp); + } + } + + /** Track down the number of records or the dash. **/ + cp = cps; + if (cps < end) { + while (*cp && isspace(*cp)) + cp++; + cps = cp; + while (*cps && !isspace(*cps)) + cps++; + *cps++ = '\0'; + if (isdigit(*cp)) { + Records = atoi(cp); + } + if (Records > 0 && RecordLength > 0) { + /** Compute an approximate size. **/ + entry_info->size = (Records * RecordLength); + } + } + + /** Set the years and date, if we don't have them yet. **/ + if (!HaveYears) { + set_years_and_date(); + } + + /** Track down the date. **/ + cpd = cps; + if (((cps < end) && + (cps = strchr(cpd, ':')) != NULL) && + (cps < (end - 3) && + isdigit(*(cps+1)) && isdigit(*(cps+2)) && *(cps+3) == ':')) { + cps += 3; + *cps = '\0'; + if ((cps - cpd) >= 14) { + cpd = (cps - 14); + *(cpd+2) = '\0'; /* Month */ + *(cpd+5) = '\0'; /* Day */ + *(cpd+8) = '\0'; /* Year */ + cps -= 5; /* Time */ + if (*cpd == ' ') + *cpd = '0'; + i = atoi(cpd) - 1; + sprintf(date, "%s %s", months[i], (cpd+3)); + if (date[4] == '0') + date[4] = ' '; + cpd += 6; /* Year */ + if (strcmp((ThisYear+2), cpd)) { + /* Not this year, so show the year. */ + if (atoi(cpd) < 70) { + sprintf((char *)&date[6], " 20%s", cpd); + } else { + sprintf((char *)&date[6], " 19%s", cpd); + } + } else { + /* Is this year, so show the time. */ + *(cps+2) = '\0'; /* Hour */ + i = atoi(cps); + sprintf((char*)&date[6], " %s%d:%s", + (i < 10 ? "0" : ""), i, (cps+3)); + } + StrAllocCopy(entry_info->date, date); + if (entry_info->date[4] == ' '|| entry_info->date[4] == '0') { + entry_info->date[4] = HT_NON_BREAK_SPACE; + } + } + } + + /** Wrap it up. **/ + if (TRACE) + fprintf(stderr, "HTFTP: VM/CMS filename: %s date: %s size: %d\n", + entry_info->filename, + entry_info->date ? entry_info->date : "", + entry_info->size); + return; +} /* parse_cms_dir_entry */ + +/* + * parse_dir_entry() + * Given a line of LIST/NLST output in entry, return results + * and a file/dir name in entry_info struct + * + * If first is true, this is the first name in a directory. + */ + +PRIVATE EntryInfo * parse_dir_entry ARGS2( + char *, entry, + BOOLEAN *, first) +{ + EntryInfo *entry_info; + int i; + int len; + BOOLEAN remove_size=FALSE; + char *cp; + + entry_info = (EntryInfo *)malloc(sizeof(EntryInfo)); + entry_info->filename = NULL; + entry_info->type = NULL; + entry_info->date = NULL; + entry_info->size = 0; + entry_info->display = TRUE; + + switch (server_type) { + case UNIX_SERVER: + case PETER_LEWIS_SERVER: + case MACHTEN_SERVER: + case MSDOS_SERVER: + case WINDOWS_NT_SERVER: + case APPLESHARE_SERVER: + case NETPRESENZ_SERVER: + /* + ** Check for EPLF output (local times). + */ + if (*entry == '+') { + parse_eplf_line(entry, entry_info); + break; + } + + /* + ** Interpret and edit LIST output from Unix server. + */ + len = strlen(entry); + if (*first) { + if (!strcmp(entry, "can not access directory .")) { + /* + * Don't reset *first, nothing real will follow. - KW + */ + entry_info->display = FALSE; + return(entry_info); + } + *first = FALSE; + if (!strncmp(entry, "total ", 6) || + strstr(entry, "not available") != NULL) { + entry_info->display=FALSE; + return(entry_info); + } else if (unsure_type) { + /* this isn't really a unix server! */ + server_type = GENERIC_SERVER; + entry_info->display=FALSE; + return(entry_info); + } + } + + /* + ** Check first character of ls -l output. + */ + if (TOUPPER(entry[0]) == 'D') { + /* + ** It's a directory. + */ + StrAllocCopy(entry_info->type, "Directory"); + remove_size=TRUE; /* size is not useful */ + } else if (entry[0] == 'l') { + /* + ** It's a symbolic link, does the user care about + ** knowing if it is symbolic? I think so since + ** it might be a directory. + */ + StrAllocCopy(entry_info->type, "Symbolic Link"); + remove_size=TRUE; /* size is not useful */ + + /* + ** Strip off " -> pathname". + */ + for (i = len - 1; (i > 3) && + (!isspace(entry[i]) || + (entry[i-1] != '>') || + (entry[i-2] != '-') || + (entry[i-3] != ' ')); i--) + ; /* null body */ + if (i > 3) { + entry[i-3] = '\0'; + len = i - 3; + } + } /* link */ + + parse_ls_line(entry, entry_info); + + if (!strcmp(entry_info->filename,"..") || + !strcmp(entry_info->filename,".")) + entry_info->display=FALSE; + /* + ** Goto the bottom and get real type. + */ + break; + + case VMS_SERVER: + /* + ** Interpret and edit LIST output from VMS server + ** and convert information lines to zero length. + */ + parse_vms_dir_entry(entry, entry_info); + + /* + ** Get rid of any junk lines. + */ + if (!entry_info->display) + return(entry_info); + + /* + ** Trim off VMS directory extensions. + */ + len = strlen(entry_info->filename); + if ((len > 4) && !strcmp(&entry_info->filename[len-4], ".dir")) { + entry_info->filename[len-4] = '\0'; + StrAllocCopy(entry_info->type, "Directory"); + remove_size=TRUE; /* size is not useful */ + } + /* + ** Goto the bottom and get real type. + */ + break; + + case MS_WINDOWS_SERVER: + /* + ** Interpret and edit LIST output from MS_WINDOWS server + ** and convert information lines to zero length. + */ + parse_ms_windows_dir_entry(entry, entry_info); + + /* + ** Get rid of any junk lines. + */ + if (!entry_info->display) + return(entry_info); + if (entry_info->type && *entry_info->type == '\0') { + FREE(entry_info->type); + return(entry_info); + } + /* + ** Goto the bottom and get real type. + */ + break; + +#ifdef NOTDEFINED + case WINDOWS_NT_SERVER: + /* + ** Interpret and edit LIST output from MS_WINDOWS server + ** and convert information lines to zero length. + */ + parse_windows_nt_dir_entry(entry, entry_info); + + /* + ** Get rid of any junk lines. + */ + if (!entry_info->display) + return(entry_info); + if (entry_info->type && *entry_info->type == '\0') { + FREE(entry_info->type); + return(entry_info); + } + /* + ** Goto the bottom and get real type. + */ + break; +#endif /* NOTDEFINED */ + + case CMS_SERVER: + { + /* + ** Interpret and edit LIST output from VM/CMS server + ** and convert any information lines to zero length. + */ + parse_cms_dir_entry(entry, entry_info); + + /* + ** Get rid of any junk lines. + */ + if (!entry_info->display) + return(entry_info); + if (entry_info->type && *entry_info->type == '\0') { + FREE(entry_info->type); + return(entry_info); + } + /* + ** Goto the bottom and get real type. + */ + break; + } + + case NCSA_SERVER: + case TCPC_SERVER: + /* + ** Directories identified by trailing "/" characters. + */ + StrAllocCopy(entry_info->filename, entry); + len = strlen(entry); + if (entry[len-1] == '/') { + /* + ** It's a dir, remove / and mark it as such. + */ + entry[len-1] = '\0'; + StrAllocCopy(entry_info->type, "Directory"); + remove_size=TRUE; /* size is not useful */ + } + /* + ** Goto the bottom and get real type. + */ + break; + + default: + /* + ** We can't tell if it is a directory since we only + ** did an NLST :( List bad file types anyways? NOT! + */ + StrAllocCopy(entry_info->filename, entry); + return(entry_info); /* mostly empty info */ + break; /* not needed */ + + } /* switch (server_type) */ + + if (remove_size && entry_info->size) { + entry_info->size = 0; + } + + if (entry_info->filename && strlen(entry_info->filename) > 3) { + if (((cp=strrchr(entry_info->filename, '.')) != NULL && + 0 == strncasecomp(cp, ".me", 3)) && + (cp[3] == '\0' || cp[3] == ';')) { + /* + ** Don't treat this as application/x-Troff-me + ** if it's a Unix server but has the string + ** "read.me", or if it's not a Unix server. - FM + */ + if ((server_type != UNIX_SERVER) || + (cp > (entry_info->filename + 3) && + 0 == strncasecomp((cp - 4), "read.me", 7))) { + StrAllocCopy(entry_info->type, "text/plain"); + } + } + } + + /* + ** Get real types eventually. + */ + if (!entry_info->type) { + CONST char *cp2; + HTFormat format; + HTAtom * encoding; /* @@ not used at all */ + format = HTFileFormat(entry_info->filename, &encoding, &cp2); + + if (cp2 == NULL) { + if (!strncmp(HTAtom_name(format), "application",11)) { + cp2 = HTAtom_name(format) + 12; + if (!strncmp(cp2,"x-",2)) + cp2 += 2; + } else { + cp2 = HTAtom_name(format); + } + } + + StrAllocCopy(entry_info->type, cp2); + } + + return(entry_info); +} /* parse_dir_entry */ + +PRIVATE int compare_EntryInfo_structs ARGS2( + EntryInfo *, entry1, + EntryInfo *, entry2) +{ + int i, status; + char date1[16], date2[16], time1[8], time2[8], month[4]; + + switch(HTfileSortMethod) { + case FILE_BY_SIZE: + /* both equal or both 0 */ + if (entry1->size == entry2->size) + return(strcmp(entry1->filename, entry2->filename)); + else + if (entry1->size > entry2->size) + return(1); + else + return(-1); + break; + + case FILE_BY_TYPE: + if (entry1->type && entry2->type) { + status = strcasecomp(entry1->type, entry2->type); + if (status) + return(status); + /* else fall to filename comparison */ + } + return (strcmp(entry1->filename, entry2->filename)); + break; + + case FILE_BY_DATE: + if (entry1->date && entry2->date) { + /* + ** Make sure we have the correct length. - FM + */ + if (strlen(entry1->date) != 12 || strlen(entry2->date) != 12) { + return(strcmp(entry1->filename, entry2->filename)); + } + /* + ** Set the years and date, + ** if we don't have them yet. + */ + if (!HaveYears) { + set_years_and_date(); + } + /* + ** Set up for sorting in reverse + ** chronological order. - FM + */ + if (entry1->date[9] == ':') { + strcpy(date1, "9999"); + strcpy(time1, (char *)&entry1->date[7]); + if (time1[0] == ' ') { + time1[0] = '0'; + } + } else { + strcpy(date1, (char *)&entry1->date[8]); + strcpy(time1, "00:00"); + } + strncpy(month, entry1->date, 3); + month[3] = '\0'; + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%s%d", (i < 10 ? "0" : ""), i); + strcat(date1, month); + strncat(date1, (char *)&entry1->date[4], 2); + date1[8] = '\0'; + if (date1[6] == ' ' || date1[6] == HT_NON_BREAK_SPACE) { + date1[6] = '0'; + } + if (date1[0] == '9' && atoi(date1) > TheDate) { + for (i = 0; i < 4; i++) { + date1[i] = LastYear[i]; + } + } + strcat(date1, time1); + if (entry2->date[9] == ':') { + strcpy(date2, "9999"); + strcpy(time2, (char *)&entry2->date[7]); + if (time2[0] == ' ') { + time2[0] = '0'; + } + } else { + strcpy(date2, (char *)&entry2->date[8]); + strcpy(time2, "00:00"); + } + strncpy(month, entry2->date, 3); + month[3] = '\0'; + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%s%d", (i < 10 ? "0" : ""), i); + strcat(date2, month); + strncat(date2, (char *)&entry2->date[4], 2); + date2[8] = '\0'; + if (date2[6] == ' ' || date2[6] == HT_NON_BREAK_SPACE) { + date2[6] = '0'; + } + if (date2[0] == '9' && atoi(date2) > TheDate) { + for (i = 0; i < 4; i++) { + date2[i] = LastYear[i]; + } + } + strcat(date2, time2); + /* + ** Do the comparison. - FM + */ + status = strcasecomp(date2, date1); + if (status) + return(status); + /* else fall to filename comparison */ + } + return (strcmp(entry1->filename, entry2->filename)); + break; + + case FILE_BY_NAME: + default: + return (strcmp(entry1->filename, entry2->filename)); + } +} + + +/* Read a directory into an hypertext object from the data socket +** -------------------------------------------------------------- +** +** On entry, +** anchor Parent anchor to link the this node to +** address Address of the directory +** On exit, +** returns HT_LOADED if OK +** <0 if error. +*/ +PRIVATE int read_directory ARGS4( + HTParentAnchor *, parent, + CONST char *, address, + HTFormat, format_out, + HTStream *, sink) +{ + int status; + BOOLEAN WasInterrupted = FALSE; + HTStructured* target = HTML_new(parent, format_out, sink); + HTStructuredClass targetClass; + char *filename = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION); + EntryInfo *entry_info; + BOOLEAN first = TRUE; + char string_buffer[64]; + char *lastpath = NULL;/* prefix for link, either "" (for root) or xxx */ + BOOL need_parent_link = FALSE; + BOOL tildeIsTop = FALSE; + + targetClass = *(target->isa); + + _HTProgress ("Receiving FTP directory."); + + /* + ** Check whether we always want the home + ** directory treated as Welcome. - FM + */ + if (server_type == VMS_SERVER) + tildeIsTop = TRUE; + + /* + ** This should always come back FALSE, since the + ** flag is set only for local directory listings + ** if LONG_LIST was defined on compilation, but + ** we could someday set up an equivalent listing + ** for Unix ftp servers. - FM + */ + need_parent_link = HTDirTitles(target, (HTAnchor*)parent, tildeIsTop); + + data_read_pointer = data_write_pointer = data_buffer; + + if (*filename == '\0') { /* Empty filename: use root. */ + StrAllocCopy (lastpath, "/"); + } else if (!strcmp(filename,"/")) { /* Root path. */ + StrAllocCopy (lastpath, "/foo/.."); + } else { + char * p = strrchr(filename, '/'); /* Find the lastslash. */ + char *cp; + + if (server_type == CMS_SERVER) { + StrAllocCopy(lastpath, filename); /* Use absolute path for CMS. */ + } else { + StrAllocCopy(lastpath, p+1); /* Take slash off the beginning. */ + } + if ((cp = strrchr(lastpath, ';')) != NULL) { /* Trim type= param. */ + if (!strncasecomp((cp+1), "type=", 5)) { + if (TOUPPER(*(cp+6)) == 'D' || + TOUPPER(*(cp+6)) == 'A' || + TOUPPER(*(cp+6)) == 'I') + *cp = '\0'; + } + } + } + FREE (filename); + + + { + HTBTree * bt = HTBTree_new((HTComparer)compare_EntryInfo_structs); + char c; + HTChunk * chunk = HTChunkCreate(128); + int BytesReceived = 0; + int BytesReported = 0; + char NumBytes[64]; + PUTS("\n"); /* prettier LJM */ + for (c = 0; c != (char)EOF;) { /* For each entry in the directory */ + HTChunkClear(chunk); + + if (HTCheckForInterrupt()) { + WasInterrupted = TRUE; + if (BytesReceived) { + goto unload_btree; /* unload btree */ + } else { + ABORT_TARGET; + HTBTreeAndObject_free(bt); + return HT_INTERRUPTED; + } + } + + /* read directory entry + */ + for (;;) { /* Read in one line as filename */ + c = NEXT_DATA_CHAR; +AgainForMultiNet: + if (interrupted_in_next_data_char) { + WasInterrupted = TRUE; + if (BytesReceived) { + goto unload_btree; /* unload btree */ + } else { + ABORT_TARGET; + HTBTreeAndObject_free(bt); + return HT_INTERRUPTED; + } + } else if (c == CR || c == LF) { /* Terminator? */ + if (chunk->size != 0) { /* got some text */ + /* Deal with MultiNet's wrapping of long lines */ + if (server_type == VMS_SERVER) { + /* Deal with MultiNet's wrapping of long lines - F.M. */ + if (data_read_pointer < data_write_pointer && + *(data_read_pointer+1) == ' ') + data_read_pointer++; + else if (data_read_pointer >= data_write_pointer) { + status = NETREAD(data_soc, data_buffer, + DATA_BUFFER_SIZE); + if (status == HT_INTERRUPTED) { + interrupted_in_next_data_char = 1; + goto AgainForMultiNet; + } + if (status <= 0) { + c = (char)EOF; + break; + } + data_write_pointer = data_buffer + status; + data_read_pointer = data_buffer; + if (*data_read_pointer == ' ') + data_read_pointer++; + else + break; + } + else + break; + } + else + break; /* finish getting one entry */ + } + } else if (c == (char)EOF) { + break; /* End of file */ + } else { + HTChunkPutc(chunk, c); + } + } + HTChunkTerminate(chunk); + + BytesReceived += chunk->size; + if (BytesReceived > BytesReported + 1024) { + sprintf(NumBytes,"Transferred %d bytes",BytesReceived); + HTProgress(NumBytes); + BytesReported = BytesReceived; + } + + if (c == (char) EOF && chunk->size == 1) + /* 1 means empty: includes terminating 0 */ + break; + if (TRACE) + fprintf(stderr, "HTFTP: Line in %s is %s\n", + lastpath, chunk->data); + + entry_info = parse_dir_entry(chunk->data, &first); + if (entry_info->display) { + if (TRACE) + fprintf(stderr, "Adding file to BTree: %s\n", + entry_info->filename); + HTBTree_add(bt, (EntryInfo *)entry_info); + } else { + FREE(entry_info); + } + + } /* next entry */ + +unload_btree: + + HTChunkFree(chunk); + + /* print out the handy help message if it exits :) */ + if (help_message_cache_non_empty()) { + START(HTML_PRE); + START(HTML_HR); + PUTS(help_message_cache_contents()); + init_help_message_cache(); /* to free memory */ + START(HTML_HR); + } else { + START(HTML_PRE); + PUTS("\n"); + } + + /* Put up header + */ + /* PUTS(" Date Type Size Filename\n"); + */ + + /* Run through tree printing out in order + */ + { + HTBTElement * ele; + int i; + for (ele = HTBTree_next(bt, NULL); + ele != NULL; + ele = HTBTree_next(bt, ele)) { + entry_info = (EntryInfo *)HTBTree_object(ele); + + if (entry_info->date) { + PUTS(entry_info->date); + PUTS(" "); + } else { + PUTS(" * "); + } + + if (entry_info->type) { + for (i = 0; entry_info->type[i] != '\0' && i < 15; i++) + PUTC(entry_info->type[i]); + for (; i < 17; i++) + PUTC(' '); + } + + /* start the anchor */ + HTDirEntry(target, lastpath, entry_info->filename); + PUTS(entry_info->filename); + END(HTML_A); + + if (entry_info->size) { + if (entry_info->size < 1024) + sprintf(string_buffer, " %d bytes", + entry_info->size); + else + sprintf(string_buffer, " %dKb", + entry_info->size/1024); + PUTS(string_buffer); + } + + PUTC('\n'); /* end of this entry */ + + free_entryinfo_struct_contents(entry_info); + } + } + END(HTML_PRE); + FREE_TARGET; + HTBTreeAndObject_free(bt); + } + + FREE(lastpath); + + if (server_type == APPLESHARE_SERVER || + server_type == NETPRESENZ_SERVER) { + /* + * Without closing the data socket first, + * the response(NIL) below hangs. - KW + */ + NETCLOSE(data_soc); + } + + if (WasInterrupted || HTCheckForInterrupt()) { + if (server_type != CMS_SERVER) + response(NIL); + _HTProgress("Data transfer interrupted."); + return HT_LOADED; + } + if (server_type != CMS_SERVER) + response(NIL); + return HT_LOADED; +#ifdef NOTDEFINED + return response(NIL) == 2 ? HT_LOADED : -1; +#endif /* NOTDEFINED */ +} + +/* Retrieve File from Server +** ------------------------- +** +** On entry, +** name WWW address of a file: document, including hostname +** On exit, +** returns Socket number for file if good. +** <0 if bad. +*/ +PUBLIC int HTFTPLoad ARGS4( + CONST char *, name, + HTParentAnchor *, anchor, + HTFormat, format_out, + HTStream *, sink) +{ + BOOL isDirectory = NO; + HTAtom * encoding = NULL; + int status; + int retry; /* How many times tried? */ + HTFormat format; + char command[LINE_LENGTH+1]; + + + /* set use_list to NOT since we don't know what kind of server + * this is yet. And set the type to GENERIC + */ + use_list = FALSE; + server_type = GENERIC_SERVER; + + for (retry = 0; retry < 2; retry++) { /* For timed out/broken connections */ + status = get_connection(name, anchor); + if (status < 0) + return status; + +#ifdef LISTEN + status = get_listen_socket(); + if (status < 0) { + NETCLOSE (control->socket); + control->socket = -1; + close_master_socket (); + /* HT_INTERRUPTED would fall through, if we could interrupt + somehow in the middle of it, which we currently can't. */ + return status; + } + +#ifdef REPEAT_PORT +/* Inform the server of the port number we will listen on +*/ + { + status = response(port_command); + if (status == HT_INTERRUPTED) { + if (TRACE) + fprintf (stderr, + "HTFTP: Interrupted in response (port_command)\n"); + _HTProgress ("Connection interrupted."); + NETCLOSE (control->socket); + control->socket = -1; + close_master_socket (); + return HT_INTERRUPTED; + } + if (status != 2) { /* Could have timed out */ + if (status < 0) + continue; /* try again - net error*/ + return -status; /* bad reply */ + } + if (TRACE) + fprintf(stderr, "HTFTP: Port defined.\n"); + } +#endif /* REPEAT_PORT */ +#else /* Use PASV */ +/* Tell the server to be passive +*/ + { + char *p; + int reply, h0, h1, h2, h3, p0, p1; /* Parts of reply */ + int status; + data_soc = status; + + sprintf(command, "PASV%c%c", CR, LF); + status = response(command); + if (status != 2) { + if (status < 0) + continue; /* retry or Bad return */ + return -status; /* bad reply */ + } + for (p = response_text; *p && *p != ','; p++) + ; /* null body */ + + while (--p > response_text && '0' <= *p && *p <= '9') + ; /* null body */ + + status = sscanf(p+1, "%d,%d,%d,%d,%d,%d", + &h0, &h1, &h2, &h3, &p0, &p1); + if (status < 4) { + fprintf(stderr, "HTFTP: PASV reply has no inet address!\n"); + return -99; + } + passive_port = (p0<<8) + p1; + if (TRACE) + fprintf(stderr, "HTFTP: Server is listening on port %d\n", + passive_port); + + +/* Open connection for data: +*/ + sprintf(command, + "ftp://%d.%d.%d.%d:%d/",h0,h1,h2,h3,passive_port); + status = HTDoConnect(name, "FTP", passive_port, &data_soc); + + if (status < 0) { + (void) HTInetStatus("connect for data"); + NETCLOSE(data_soc); + return status; /* Bad return */ + } + + if (TRACE) + fprintf(stderr, "FTP data connected, socket %d\n", data_soc); + } +#endif /* use PASV */ + status = 0; + break; /* No more retries */ + + } /* for retries */ + if (status < 0) + return status; /* Failed with this code */ + +/* Ask for the file: +*/ + { + char *filename = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); + char *fname = filename; /** Save for subsequent free() **/ + BOOL binary; + char *type = NULL; + char *cp; + + if (server_type == CMS_SERVER) { + /** If the unescaped path has a %2f, reject it as illegal. - FM **/ + if (((cp = strstr(filename, "%2")) != NULL) && + TOUPPER(cp[2]) == 'F') { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + if (TRACE) { + fprintf(stderr, + "HTFTP: Rejecting path due to illegal escaped slash.\n"); + } + return -1; + } + } + + if (!*filename) { + StrAllocCopy(filename, "/"); + type = "D"; + } else if ((type = strrchr(filename, ';')) != NULL) { + /* + ** Check and trim the type= parameter. - FM + */ + if (!strncasecomp((type+1), "type=", 5)) { + switch(TOUPPER(*(type+6))) { + case 'D': + *type = '\0'; + type = "D"; + break; + case 'A': + *type = '\0'; + type = "A"; + break; + case 'I': + *type = '\0'; + type = "I"; + break; + default: + type = ""; + break; + } + if (!*filename) { + *filename = '/'; + *(filename+1) = '\0'; + } + } + if (TRACE && *type != '\0') { + fprintf(stderr, "HTFTP: type=%s\n", type); + } + } + HTUnEscape(filename); + if (TRACE) + fprintf(stderr, "HTFTP: UnEscaped %s\n", filename); + if (filename[1] == '~') { + /* + ** Check if translation of HOME as tilde is supported, + ** and adjust filename if so. - FM + */ + char *cp2 = NULL; + char *fn = NULL; + + if ((cp2 = strchr((filename+1), '/')) != NULL) { + *cp2 = '\0'; + } + sprintf(command, "PWD%c%c", CR, LF); + status = response(command); + if (status == 2 && response_text[5] == '/') { + sprintf(command, "CWD %s%c%c", (filename+1), CR, LF); + status = response(command); + if (status == 2) { + StrAllocCopy(fn, (filename+1)); + if (cp2) { + *cp2 = '/'; + if (fn[strlen(fn)-1] != '/') { + StrAllocCat(fn, cp2); + } else { + StrAllocCat(fn, (cp2+1)); + } + cp2 = NULL; + } + FREE(fname); + fname = filename = fn; + } + } + if (cp2) { + *cp2 = '/'; + } + } + if (strlen(filename) > 3) { + char *cp2; + if (((cp2=strrchr(filename, '.')) != NULL && + 0 == strncasecomp(cp2, ".me", 3)) && + (cp2[3] == '\0' || cp2[3] == ';')) { + /* + ** Don't treat this as application/x-Troff-me + ** if it's a Unix server but has the string + ** "read.me", or if it's not a Unix server. - FM + */ + if ((server_type != UNIX_SERVER) || + (cp2 > (filename + 3) && + 0 == strncasecomp((cp2 - 4), "read.me", 7))) { + *cp2 = '\0'; + format = HTFileFormat(filename, &encoding, NULL); + *cp2 = '.'; + } else { + format = HTFileFormat(filename, &encoding, NULL); + } + } else { + format = HTFileFormat(filename, &encoding, NULL); + } + } else { + format = HTFileFormat(filename, &encoding, NULL); + } + format = HTCharsetFormat(format, anchor, -1); + binary = (encoding != HTAtom_for("8bit") && + encoding != HTAtom_for("7bit")); + if (!binary && + /* + ** Force binary if we're in source, download or dump + ** mode and this is not a VM/CMS server, so we don't + ** get CRLF instead of LF (or CR) for newlines in text + ** files. Can't do this for VM/CMS or we'll get + ** raw EBCDIC. - FM + */ + (format_out == WWW_SOURCE || + format_out == HTAtom_for("www/download") || + format_out == HTAtom_for("www/dump")) && + (server_type != CMS_SERVER)) + binary = TRUE; + if (!binary && type && *type == 'I') { + /* + ** Force binary if we had ;type=I - FM + */ + binary = TRUE; + } else if (binary && type && *type == 'A') { + /* + ** Force ASCII if we had ;type=A - FM + */ + binary = FALSE; + } + if (binary != control->binary) { + /* + ** Act on our setting if not alread set. - FM + */ + char * mode = binary ? "I" : "A"; + sprintf(command, "TYPE %s%c%c", mode, CR, LF); + status = response(command); + if (status != 2) { + init_help_message_cache(); /* to free memory */ + return ((status < 0) ? status : -status); + } + control->binary = binary; + } + switch (server_type) { + /* + ** Handle what for Lynx are special case servers, e.g., + ** for which we respect RFC 1738, or which have known + ** conflicts in suffix mappings. - FM + */ + case VMS_SERVER: + { + char *cp1, *cp2; + BOOL included_device = FALSE; + /** Accept only Unix-style filename **/ + if (strchr(filename, ':') != NULL || + strchr(filename, '[') != NULL) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + if (TRACE) { + fprintf(stderr, + "HTFTP: Rejecting path due to non-Unix-style syntax.\n"); + } + return -1; + } + /** Handle any unescaped "/%2F" path **/ + if (!strncmp(filename, "//", 2)) { + int i; + included_device = TRUE; + for (i = 0; filename[(i+1)]; i++) + filename[i] = filename[(i+1)]; + filename[i] = '\0'; + if (TRACE) { + fprintf(stderr, "HTFTP: Trimmed '%s'\n", filename); + } + cp = HTMake_VMS_name("", filename); + if (TRACE) { + fprintf(stderr, "HTFTP: VMSized '%s'\n", cp); + } + if ((cp1=strrchr(cp, ']')) != NULL) { + cp1++; + for (i = 0; cp1[i]; i++) + filename[i] = cp1[i]; + filename[i] = '\0'; + if (TRACE) { + fprintf(stderr, "HTFTP: Filename '%s'\n", filename); + } + *cp1 = '\0'; + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + if ((cp1=strchr(cp, '[')) != NULL) { + *cp1++ = '\0'; + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + sprintf(command, "CWD [.%s%c%c", cp1, CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } else { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } + } else if ((cp1=strchr(cp, ':')) != NULL && + strchr(cp, '[') == NULL && + strchr(cp, ']') == NULL) { + cp1++; + if (*cp1 != '\0') { + for (i = 0; cp1[i]; i++) + filename[i] = cp1[i]; + filename[i] = '\0'; + if (TRACE) { + fprintf(stderr, "HTFTP: Filename '%s'\n", filename); + } + *cp1 = '\0'; + strcat(cp, "["); + strcat(cp, filename); + strcat(cp, "]"); + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + *cp1 = '\0'; + strcat(cp, "[000000]"); + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + *cp1 = '\0'; + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } + } else { + strcpy(cp, "000000"); + filename = cp; + } + } + } else if (0==strcmp(cp, (filename+1))) { + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + strcat(cp, ":"); + sprintf(command, "CWD %s%c%c", cp, CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } + strcpy(cp, "000000"); + filename = cp; + } + } + /** Trim trailing slash if filename is not the top directory **/ + if (strlen(filename) > 1 && filename[strlen(filename)-1] == '/') + filename[strlen(filename)-1] = '\0'; + +#ifdef MAINTAIN_CONNECTION /* Don't need this if always new connection - F.M. */ + if (!included_device) { + /** Get the current default VMS device:[directory] **/ + sprintf(command, "PWD%c%c", CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + /** Go to the VMS account's top directory **/ + if ((cp=strchr(response_text, '[')) != NULL && + (cp1=strrchr(response_text, ']')) != NULL) { + sprintf(command, "CWD %s", cp); + if ((cp2=strchr(cp, '.')) != NULL && cp2 < cp1) + sprintf(command+(cp2-cp)+4, "]%c%c", CR, LF); + else + sprintf(command+(cp1-cp)+4, "]%c%c", CR, LF); + status = response (command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } + } +#endif /* MAINTAIN_CONNECTION */ + + /** If we want the VMS account's top directory, list it now **/ + if (!(strcmp(filename, "/~")) || + (included_device && 0==strcmp(filename, "000000")) || + (strlen(filename) == 1 && *filename == '/')) { + isDirectory = YES; + sprintf(command, "LIST%c%c", CR, LF); + status = response (command); + FREE(fname); + if (status != 1) { + /* Action not started */ + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + /** Big goto! **/ + goto listen; + } + /** Otherwise, go to appropriate directory and doctor filename **/ + if (!strncmp(filename, "/~", 2)) + filename += 2; + if (!included_device && + (cp = strchr(filename, '/')) != NULL && + (cp1 = strrchr(cp, '/')) != NULL && cp != cp1) { + sprintf(command, "CWD [.%s", cp+1); + sprintf(command+(cp1-cp)+5, "]%c%c", CR, LF); + while ((cp2 = strrchr(command, '/')) != NULL) + *cp2 = '.'; + status = response(command); + if (status != 2) { + FREE(fname); + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + filename = cp1+1; + } else { + if (!included_device) { + filename += 1; + } + } + break; + } + case CMS_SERVER: + { + /* + ** If we want the CMS account's top directory, or a base + ** SFS or anonymous directory path (i.e., without a slash), + ** list it now. FM + */ + if ((strlen(filename) == 1 && *filename == '/') || + ((0 == strncasecomp((filename+1), "vmsysu:", 7)) && + (cp = strchr((filename+1), '.')) != NULL && + strchr(cp, '/') == NULL) || + (0 == strncasecomp(filename+1, "anonymou.", 9) && + strchr(filename+1, '/') == NULL)) { + if (filename[1] != '\0') { + sprintf(command, "CWD %s%c%c", (filename+1), CR, LF); + status = response(command); + if (status != 2) { + /* Action not started */ + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + } + isDirectory = YES; + if (use_list) + sprintf(command, "LIST%c%c", CR, LF); + else + sprintf(command, "NLST%c%c", CR, LF); + status = response (command); + FREE(fname); + if (status != 1) { + /* Action not started */ + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + /** Big goto! **/ + goto listen; + } + filename++; + + /** Otherwise, go to appropriate directory and adjust filename **/ + while ((cp = strchr(filename, '/')) != NULL) { + *cp++ = '\0'; + sprintf(command, "CWD %s%c%c", filename, CR, LF); + status = response(command); + if (status == 2) { + if (*cp == '\0') { + isDirectory = YES; + if (use_list) + sprintf(command, "LIST%c%c", CR, LF); + else + sprintf(command, "NLST%c%c", CR, LF); + status = response (command); + FREE(fname); + if (status != 1) { + /** Action not started **/ + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + return ((status < 0) ? status : -status); + } + /** Clear any messages from the login directory **/ + init_help_message_cache(); + /** Big goto! **/ + goto listen; + } + filename = cp; + } + } + break; + } + default: + /** Shift for any unescaped "/%2F" path **/ + if (!strncmp(filename, "//", 2)) + filename++; + break; + } + /* + ** Act on a file or listing request, or try to figure out + ** which we're dealing with if we don't know yet. - FM + */ + if (!(type) || (type && *type != 'D')) { + sprintf(command, "RETR %s%c%c", filename, CR, LF); + status = response(command); + } else { + status = 5; /* Failed status set as flag. - FM */ + } + if (status != 1) { /* Failed : try to CWD to it */ + /** Clear any login messages if this isn't the login directory **/ + if (strcmp(filename, "/")) + init_help_message_cache(); + + sprintf(command, "CWD %s%c%c", filename, CR, LF); + status = response(command); + + if (status == 2) { /* Successed : let's NAME LIST it */ + isDirectory = YES; + if (use_list) + sprintf(command, "LIST%c%c", CR, LF); + else + sprintf(command, "NLST%c%c", CR, LF); + status = response (command); + } + } + FREE(fname); + if (status != 1) { + init_help_message_cache(); /* to free memory */ + NETCLOSE(control->socket); + control->socket = -1; + if (status < 0) + return status; + else + return -status; + } + } + +listen: +#ifdef LISTEN +/* Wait for the connection +*/ + { + struct sockaddr_in soc_address; + int soc_addrlen=sizeof(soc_address); +#ifdef SOCKS + if (socks_flag) + status = Raccept(master_socket, + (struct sockaddr *)&soc_address, + (void *)&soc_addrlen); + else +#endif /* SOCKS */ + status = accept(master_socket, + (struct sockaddr *)&soc_address, + (void *)&soc_addrlen); + if (status < 0) { + init_help_message_cache(); /* to free memory */ + return HTInetStatus("accept"); + } + CTRACE(tfp, "TCP: Accepted new socket %d\n", status); + data_soc = status; + } +#else +/* @@ */ +#endif /* LISTEN */ + if (isDirectory) { + status = read_directory (anchor, name, format_out, sink); + NETCLOSE(data_soc); + NETCLOSE(control->socket); + control->socket = -1; + init_help_message_cache(); /* to free memory */ + return status; + /* returns HT_LOADED or error */ + } else { + int rv; + int len; + char *FileName = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); + + /** Clear any login messages **/ + init_help_message_cache(); + + /** Fake a Content-Encoding for compressed files. - FM **/ + HTUnEscape(FileName); + if (!IsUnityEnc(encoding)) { + /* + * We already know from the call to HTFileFormat above that + * this is a compressed file, no need to look at the filename + * again. - kw + */ + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, HTAtom_name(encoding)); + format = HTAtom_for("www/compressed"); + + } else if ((len = strlen(FileName)) > 2) { + if ((FileName[len - 1] == 'Z') && + (FileName[len - 2] == '.' || + FileName[len - 2] == '-' || + FileName[len - 2] == '_')) { + + FileName[len - 2] = '\0'; + format = HTFileFormat(FileName, &encoding, NULL); + format = HTCharsetFormat(format, anchor, -1); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-compress"); + format = HTAtom_for("www/compressed"); + } else if ((len > 3) && + !strcasecomp((char *)&FileName[len - 2], "gz")) { + if (FileName[len - 3] == '.' || + FileName[len - 3] == '-' || + FileName[len - 3] == '_') { + FileName[len - 3] = '\0'; + format = HTFileFormat(FileName, &encoding, NULL); + format = HTCharsetFormat(format, anchor, -1); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-gzip"); + format = HTAtom_for("www/compressed"); + } + } + } + FREE(FileName); + + _HTProgress ("Receiving FTP file."); + rv = HTParseSocket(format, format_out, anchor, data_soc, sink); + + if (rv == HT_INTERRUPTED) + _HTProgress("Data transfer interrupted."); + + HTInitInput(control->socket); + /* Reset buffering to control connection DD 921208 */ + + status = NETCLOSE(data_soc); + if (TRACE) + fprintf(stderr, "HTFTP: Closing data socket %d\n", data_soc); + if (status < 0 && rv != HT_INTERRUPTED && rv != -1) { + (void) HTInetStatus("close"); /* Comment only */ + data_soc = -1; /* invalidate it */ + } else { + data_soc = -1; /* invalidate it */ + status = response(NIL); /* Pick up final reply */ + if (status != 2 && rv != HT_INTERRUPTED && rv != -1) { + init_help_message_cache(); /* to free memory */ + return HTLoadError(sink, 500, response_text); + } + } + + NETCLOSE(control->socket); + control->socket = -1; + init_help_message_cache(); /* to free memory */ + return HT_LOADED; + } +} /* open_file_read */ + +/* +** This function frees any user entered password, so that +** it must be entered again for a future request. - FM +*/ +PUBLIC void HTClearFTPPassword NOARGS +{ + /* + ** Need code to check cached documents from + ** non-anonymous ftp accounts and do something + ** to ensure that they no longer can be accessed + ** without a new retrieval. - FM + */ + + /* + ** Now free the current user entered password, + ** if any. - FM + */ + FREE(user_entered_password); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.h new file mode 100644 index 00000000000..814772d4acc --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.h @@ -0,0 +1,77 @@ +/* FTP access module for libwww + FTP ACCESS FUNCTIONS + + This isn't really a valid protocol module -- it is lumped together with HTFile . That + could be changed easily. + + Author: Tim Berners-Lee. Public Domain. Please mail changes to timbl@info.cern.ch + + */ +#ifndef HTFTP_H +#define HTFTP_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTAnchor.h" +#include "HTStream.h" +#include "HTParse.h" + +#define FILE_BY_NAME 0 +#define FILE_BY_TYPE 1 +#define FILE_BY_SIZE 2 +#define FILE_BY_DATE 3 +extern BOOLEAN HTfileSortMethod; /* specifies the method of sorting */ + + +/* PUBLIC HTMake_VMS_name() +** CONVERTS WWW name into a VMS name +** ON ENTRY: +** nn Node Name (optional) +** fn WWW file name +** +** ON EXIT: +** returns vms file specification +** +** Bug: Returns pointer to static -- non-reentrant +*/ +PUBLIC char * HTMake_VMS_name PARAMS(( + CONST char * nn, + CONST char * fn)); + + +/* + +Retrieve File from Server + + ON EXIT, + + returns Socket number for file if good.<0 if bad. + + */ +extern int HTFTPLoad PARAMS +(( + CONST char * name, + HTParentAnchor * anchor, + HTFormat format_out, + HTStream* sink +)); + +/* +** This function frees any user entered password, so that +** it must be entered again for a future request. - FM +*/ +extern void HTClearFTPPassword NOPARAMS; + +/* + +Return Host Name + + */ +extern CONST char * HTHostName NOPARAMS; + +#endif + +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.c new file mode 100644 index 00000000000..8ef9ba1b6e1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.c @@ -0,0 +1,358 @@ +/* FILE WRITER HTFWrite.h +** =========== +** +** This version of the stream object just writes to a C file. +** The file is assumed open and left open. +** +** Bugs: +** strings written must be less than buffer size. +*/ + +#include "HTUtils.h" + +#include "HTFWriter.h" + +#include "HTFormat.h" +#include "HTAlert.h" +#include "HTFile.h" + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* Stream Object +** ------------ +*/ + +struct _HTStream { + CONST HTStreamClass * isa; + + FILE * fp; + char * end_command; + char * remove_command; + BOOL announce; +}; + + +/*_________________________________________________________________________ +** +** B L A C K H O L E C L A S S +** +** There is only one black hole instance shared by anyone +** who wanst a black hole. These black holes don't radiate, +** they just absorb data. +*/ +PRIVATE void HTBlackHole_put_character ARGS2(HTStream *, me, char, c) +{} +PRIVATE void HTBlackHole_put_string ARGS2(HTStream *, me, CONST char*, s) +{} +PRIVATE void HTBlackHole_write ARGS3(HTStream *, me, CONST char*, s, int, l) +{} +PRIVATE void HTBlackHole_free ARGS1(HTStream *, me) +{} +PRIVATE void HTBlackHole_abort ARGS2(HTStream *, me, HTError, e) +{} + + +/* Black Hole stream +** ----------------- +*/ +PRIVATE CONST HTStreamClass HTBlackHoleClass = +{ + "BlackHole", + HTBlackHole_free, + HTBlackHole_abort, + HTBlackHole_put_character, HTBlackHole_put_string, + HTBlackHole_write +}; + +PRIVATE HTStream HTBlackHoleInstance = +{ + &HTBlackHoleClass, + NULL, + NULL, + NULL, + NO +}; + +/* Black hole craetion +*/ +PUBLIC HTStream * HTBlackHole NOARGS +{ + return &HTBlackHoleInstance; +} + + +/*_________________________________________________________________________ +** +** F I L E A C T I O N R O U T I N E S +** Bug: +** All errors are ignored. +*/ + +/* Character handling +** ------------------ +*/ + +PRIVATE void HTFWriter_put_character ARGS2(HTStream *, me, char, c) +{ + putc(c, me->fp); +} + + + +/* String handling +** --------------- +** +** Strings must be smaller than this buffer size. +*/ +PRIVATE void HTFWriter_put_string ARGS2(HTStream *, me, CONST char*, s) +{ + fputs(s, me->fp); +} + + +/* Buffer write. Buffers can (and should!) be big. +** ------------ +*/ +PRIVATE void HTFWriter_write ARGS3(HTStream *, me, CONST char*, s, int, l) +{ + fwrite(s, 1, l, me->fp); +} + + + + +/* Free an HTML object +** ------------------- +** +** Note that the SGML parsing context is freed, but the created +** object is not, +** as it takes on an existence of its own unless explicitly freed. +*/ +PRIVATE void HTFWriter_free ARGS1(HTStream *, me) +{ + fclose(me->fp); + if (me->end_command) { /* Temp file */ + _HTProgress(me->end_command); /* Tell user what's happening */ + system(me->end_command); + FREE(me->end_command); + if (me->remove_command) { + system(me->remove_command); + FREE(me->remove_command); + } + } + + FREE(me); +} + +/* End writing +*/ + +PRIVATE void HTFWriter_abort ARGS2(HTStream *, me, HTError, e) +{ + fclose(me->fp); + if (me->end_command) { /* Temp file */ + if (TRACE) fprintf(stderr, + "HTFWriter: Aborting: file not executed.\n"); + FREE(me->end_command); + if (me->remove_command) { + system(me->remove_command); + FREE(me->remove_command); + } + } + + FREE(me); +} + + + +/* Structured Object Class +** ----------------------- +*/ +PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */ +{ + "FileWriter", + HTFWriter_free, + HTFWriter_abort, + HTFWriter_put_character, HTFWriter_put_string, + HTFWriter_write +}; + + +/* Subclass-specific Methods +** ------------------------- +*/ + +PUBLIC HTStream* HTFWriter_new ARGS1(FILE *, fp) +{ + HTStream* me; + + if (!fp) return NULL; + + me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) outofmem(__FILE__, "HTML_new"); + me->isa = &HTFWriter; + + me->fp = fp; + me->end_command = NULL; + me->remove_command = NULL; + me->announce = NO; + + return me; +} + +/* Make system command from template +** --------------------------------- +** +** See mailcap spec for description of template. +*/ +/* @@ to be written. sprintfs will do for now. */ + + + +/* Take action using a system command +** ---------------------------------- +** +** originally from Ghostview handling by Marc Andreseen. +** Creates temporary file, writes to it, executes system command +** on end-document. The suffix of the temp file can be given +** in case the application is fussy, or so that a generic opener can +** be used. +*/ +PUBLIC HTStream* HTSaveAndExecute ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, /* Not used */ + HTStream *, sink) /* Not used */ + +#ifdef unix +#define REMOVE_COMMAND "/bin/rm -f %s\n" +#endif +#ifdef VMS +#define REMOVE_COMMAND "delete/noconfirm/nolog %s.." +#endif + +#ifdef REMOVE_COMMAND +{ + char *fnam; + CONST char * suffix; + + HTStream* me; + + if (HTClientHost) { + HTAlert("Can't save data to file -- please run WWW locally"); + return HTBlackHole(); + } + + me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) outofmem(__FILE__, "Save and execute"); + me->isa = &HTFWriter; + + /* Save the file under a suitably suffixed name */ + + suffix = HTFileSuffix(pres->rep); + + fnam = (char *)malloc (L_tmpnam + 16 + strlen(suffix)); + tmpnam (fnam); + if (suffix) strcat(fnam, suffix); + + me->fp = fopen (fnam, "w"); + if (!me->fp) { + HTAlert("Can't open temporary file!"); + FREE(fnam); + FREE(me); + return NULL; + } + +/* Make command to process file +*/ + me->end_command = (char *)malloc ( + (strlen (pres->command) + 10+ 3*strlen(fnam)) + * sizeof (char)); + if (me == NULL) outofmem(__FILE__, "SaveAndExecute"); + + sprintf (me->end_command, pres->command, fnam, fnam, fnam); + + me->remove_command = NULL; /* If needed, put into end_command */ +#ifdef NOPE +/* Make command to delete file +*/ + me->remove_command = (char *)malloc ( + (strlen (REMOVE_COMMAND) + 10+ strlen(fnam)) + * sizeof (char)); + if (me == NULL) outofmem(__FILE__, "SaveAndExecute"); + + sprintf (me->remove_command, REMOVE_COMMAND, fnam); +#endif + + me->announce = NO; + FREE(fnam); + return me; +} + +#else /* can do remove */ +{ return NULL; } +#endif + + +/* Save Locally +** ------------ +** +** Bugs: +** GUI Apps should open local Save panel here really. +** +*/ +PUBLIC HTStream* HTSaveLocally ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, /* Not used */ + HTStream *, sink) /* Not used */ + +{ + char *fnam; + char *answer; + CONST char * suffix; + + HTStream* me; + + if (HTClientHost) { + HTAlert("Can't save data to file -- please run WWW locally"); + return HTBlackHole(); + } + + me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) outofmem(__FILE__, "SaveLocally"); + me->isa = &HTFWriter; + me->end_command = NULL; + me->remove_command = NULL; /* If needed, put into end_command */ + me->announce = YES; + + /* Save the file under a suitably suffixed name */ + + suffix = HTFileSuffix(pres->rep); + + fnam = (char *)malloc (L_tmpnam + 16 + strlen(suffix)); + tmpnam (fnam); + if (suffix) strcat(fnam, suffix); + + /* Save Panel */ + answer = HTPrompt("Give name of file to save in", fnam); + + FREE(fnam); + + me->fp = fopen (answer, "w"); + if (!me->fp) { + HTAlert("Can't open local file to write into."); + FREE(answer); + FREE(me); + return NULL; + } + + FREE(answer); + return me; +} + + + +/* Format Converter using system command +** ------------------------------------- +*/ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.h new file mode 100644 index 00000000000..052bdd7e3a3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.h @@ -0,0 +1,37 @@ +/* File Writer for libwww + C FILE WRITER + + It is useful to have both FWriter and Writer for environments in which fdopen() doesn't + exist for example. + + */ +#ifndef HTFWRITE_H +#define HTFWRITE_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTStream.h" +/*#include <stdio.h> included by HTUtils.h -- FM */ +#include "HTFormat.h" + +#ifdef SHORT_NAMES +#define HTFWriter_new HTFWnew +#endif + +extern HTStream * HTFWriter_new PARAMS((FILE * fp)); + +extern HTStream * HTSaveAndExecute PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, /* Not used */ + HTStream * sink)); + +extern HTStream * HTSaveLocally PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, /* Not used */ + HTStream * sink)); + +#endif +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.c new file mode 100644 index 00000000000..89a93d14f81 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.c @@ -0,0 +1,2426 @@ +/* File Access HTFile.c +** =========== +** +** This is unix-specific code in general, with some VMS bits. +** These are routines for file access used by browsers. +** Development of this module for Unix DIRED_SUPPORT in Lynx +** regrettably has has been conducted in a manner with now +** creates a major impediment for hopes of adapting Lynx to +** a newer version of the library. +** +** History: +** Feb 91 Written Tim Berners-Lee CERN/CN +** Apr 91 vms-vms access included using DECnet syntax +** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP. +** Fixed access bug for relative names on VMS. +** Sep 93 (MD) Access to VMS files allows sharing. +** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C +** 27 Dec 93 (FM) FTP now works with VMS hosts. +** FTP path must be Unix-style and cannot include +** the device or top directory. +*/ + +#ifndef VMS +/* #define LONG_LIST */ /* Define this for long style unix listings (ls -l) */ +/* #define NO_PARENT_DIR_REFERENCE */ /* Define this for no parent links */ +#endif /* !VMS */ + +#ifdef DOSPATH +#define HAVE_READDIR 1 +#include <dirent.h> +#define USE_DIRENT +#include "HTDOS.h" +#endif /* DOSPATH */ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTFile.h" /* Implemented here */ +#ifdef VMS +#include <stat.h> +#endif /* VMS */ + +#ifndef VMS +#ifdef LONG_LIST +#include <pwd.h> +#include <grp.h> +#endif /* LONG_LIST */ +#endif /* !VMS */ + +#ifdef USE_ZLIB +#include <GridText.h> +#endif + +#define INFINITY 512 /* file name length @@ FIXME */ +#define MULTI_SUFFIX ".multi" /* Extension for scanning formats */ + +#define HT_EM_SPACE ((char)2) + +#define FREE(x) if (x) {free(x); x = NULL;} + +#ifdef VMS +#include "HTVMSUtils.h" +#endif /* VMS */ + +#include "HTParse.h" +#include "HTTCP.h" +#ifndef DECNET +#include "HTFTP.h" +#endif /* !DECNET */ +#include "HTAnchor.h" +#include "HTAtom.h" +#include "HTWriter.h" +#include "HTFWriter.h" +#include "HTInit.h" +#include "HTBTree.h" +#include "HTAlert.h" +#include "HTCJK.h" +#include "UCDefs.h" +#include "UCMap.h" +#include "UCAux.h" + +#include "LYexit.h" +#include "LYCharSets.h" +#include "LYGlobalDefs.h" +#include "LYUtils.h" +#include "LYLeaks.h" + +typedef struct _HTSuffix { + char * suffix; + HTAtom * rep; + HTAtom * encoding; + char * desc; + float quality; +} HTSuffix; + +#ifndef NGROUPS +#ifdef NGROUPS_MAX +#define NGROUPS NGROUPS_MAX +#else +#define NGROUPS 32 +#endif /* NGROUPS_MAX */ +#endif /* NGROUPS */ + +#include "HTML.h" /* For directory object building */ + +#define PUTC(c) (*target->isa->put_character)(target, c) +#define PUTS(s) (*target->isa->put_string)(target, s) +#define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*target->isa->end_element)(target, e, 0) +#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ + (*target->isa->end_element)(target, e, 0) +#define FREE_TARGET (*target->isa->_free)(target) +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; + +/* +** Controlling globals. +*/ +PUBLIC int HTDirAccess = HT_DIR_OK; + +#ifdef DIRED_SUPPORT +PUBLIC int HTDirReadme = HT_DIR_README_NONE; +#define FILES_FIRST 1 +#define MIXED_STYLE 2 +extern BOOLEAN lynx_edit_mode; +extern BOOLEAN dir_list_style; +#else +PUBLIC int HTDirReadme = HT_DIR_README_TOP; +#endif /* DIRED_SUPPORT */ + +extern BOOLEAN LYRawMode; +extern BOOL HTPassEightBitRaw; +extern HTCJKlang HTCJK; + +PRIVATE char *HTMountRoot = "/Net/"; /* Where to find mounts */ +#ifdef VMS +PRIVATE char *HTCacheRoot = "/WWW$SCRATCH"; /* Where to cache things */ +#else +PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */ +#endif /* VMS */ + +/*PRIVATE char *HTSaveRoot = "$(HOME)/WWW/";*/ /* Where to save things */ + +/* +** Suffix registration. +*/ +PRIVATE HTList * HTSuffixes = 0; +PRIVATE HTSuffix no_suffix = { "*", NULL, NULL, NULL, 1.0 }; +PRIVATE HTSuffix unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0}; + + +#ifdef _WINDOWS +int exists(char *filename) +{ + return (access(filename,0)==0); +} +#endif + + +/* To free up the suffixes at program exit. +** ---------------------------------------- +*/ +PRIVATE void free_suffixes NOPARAMS; + +#ifdef LONG_LIST +PRIVATE void LYListFmtParse ARGS5( + char *, fmtstr, + char *, file, + HTStructured *, target, + char *, entry, + char *, tail) +{ + char c; + char *s; + char *end; + char *start; + char *str = NULL; + struct stat st; + char buf[512]; + char fmt[512]; + char type; + struct passwd *p; + struct group *g; + time_t now; + char *datestr; + int len; +#define SEC_PER_YEAR (60 * 60 * 24 * 365) + static char *pbits[] = { "---", "--x", "-w-", "-wx", + "r--", "r-x", "rw-", "rwx", 0 }; + static char *psbits[] = { "--S", "--s", "-wS", "-ws", + "r-S", "r-s", "rwS", "rws", 0 }; +#define PBIT(a, n, s) (s) ? psbits[((a) >> (n)) & 0x7] : \ + pbits[((a) >> (n)) & 0x7] + + if (lstat(file, &st) < 0) + fmtstr = "%a"; /* can't stat so just do anchor */ + + StrAllocCopy(str, fmtstr); + s = str; + end = str + strlen(str); + START(HTML_PRE); + while (*s) { + start = s; + while (*s) { + if (*s == '%') { + if (*(s+1) == '%') /* literal % */ + s++; + else + break; + } + s++; + } + /* s is positioned either at a % or at \0 */ + *s = '\0'; + if (s > start) { /* some literal chars. */ + PUTS(start); + } + if (s == end) + break; + start = ++s; + while (isdigit(*s) || *s == '.' || *s == '-') + s++; + c = *s; /* the format char. or \0 */ + *s = '\0'; + + switch (c) { + case '\0': + break; + + case 'A': + case 'a': /* anchor */ + HTDirEntry(target, tail, entry); + sprintf(fmt, "%%%ss", start); + sprintf(buf, fmt, entry); + PUTS(buf); + END(HTML_A); +#ifdef S_IFLNK + if (c != 'A' && (st.st_mode & S_IFMT) == S_IFLNK && + (len = readlink(file, buf, sizeof(buf))) >= 0) { + PUTS(" -> "); + buf[len] = '\0'; + PUTS(buf); + } +#endif + *buf = '\0'; + break; + + case 'd': /* date */ + now = time(0); + datestr = ctime(&st.st_mtime); + if ((now - st.st_mtime) < SEC_PER_YEAR/2) + /* + ** MMM DD HH:MM + */ + sprintf(buf, "%.12s", datestr + 4); + else + /* + ** MMM DD YYYY + */ + sprintf(buf, "%.7s %.4s ", datestr + 4, + datestr + 20); + sprintf(fmt, "%%%ss", start); + sprintf(buf, fmt, buf); + break; + + case 's': /* size in bytes */ + sprintf(fmt, "%%%sd", start); + sprintf(buf, fmt, st.st_size); + break; + + case 'K': /* size in Kilobytes but not for directories */ + if ((st.st_mode & S_IFMT) == S_IFDIR) { + sprintf(fmt, "%%%ss ", start); + sprintf(buf, fmt, ""); + break; + } + /* FALL THROUGH */ + case 'k': /* size in Kilobytes */ + sprintf(fmt, "%%%sdK", start); + sprintf(buf, fmt, (st.st_size+1023)/1024); + break; + + case 'p': /* unix-style permission bits */ + switch(st.st_mode & S_IFMT) { + case S_IFIFO: type = 'p'; break; + case S_IFCHR: type = 'c'; break; + case S_IFDIR: type = 'd'; break; + case S_IFREG: type = '-'; break; +#ifdef S_IFBLK + case S_IFBLK: type = 'b'; break; +#endif +#ifdef S_IFLNK + case S_IFLNK: type = 'l'; break; +#endif +#ifdef S_IFSOCK +# ifdef S_IFIFO /* some older machines (e.g., apollo) have a conflict */ +# if S_IFIFO != S_IFSOCK + case S_IFSOCK: type = 's'; break; +# endif +# else + case S_IFSOCK: type = 's'; break; +# endif +#endif /* S_IFSOCK */ + default: type = '?'; break; + } + sprintf(buf, "%c%s%s%s", type, + PBIT(st.st_mode, 6, st.st_mode & S_ISUID), + PBIT(st.st_mode, 3, st.st_mode & S_ISGID), + PBIT(st.st_mode, 0, 0)); + sprintf(fmt, "%%%ss", start); + sprintf(buf, fmt, buf); + break; + + case 'o': /* owner */ + sprintf(fmt, "%%%ss", start); + p = getpwuid(st.st_uid); + if (p) { + sprintf(fmt, "%%%ss", start); + sprintf(buf, fmt, p->pw_name); + } else { + + sprintf(fmt, "%%%sd", start); + sprintf(buf, fmt, st.st_uid); + } + break; + + case 'g': /* group */ + g = getgrgid(st.st_gid); + if (g) { + sprintf(fmt, "%%%ss", start); + sprintf(buf, fmt, g->gr_name); + } else { + sprintf(fmt, "%%%sd", start); + sprintf(buf, fmt, st.st_gid); + } + break; + + case 'l': /* link count */ + sprintf(fmt, "%%%sd", start); + sprintf(buf, fmt, st.st_nlink); + break; + + default: + fprintf(stderr, + "Unknown format character `%c' in list format\n", c); + break; + } + PUTS(buf); + + s++; + } + END(HTML_PRE); + PUTS("\n"); + FREE(str); +} +#endif /* LONG_LIST */ + +/* Define the representation associated with a file suffix. +** -------------------------------------------------------- +** +** Calling this with suffix set to "*" will set the default +** representation. +** Calling this with suffix set to "*.*" will set the default +** representation for unknown suffix files which contain a ".". +** +** The encoding parameter can give a trivial (8bit, 7bit, binary) +** or real (gzip, compress) encoding. +** +** If filename suffix is already defined with the same encoding +** its previous definition is overridden. +*/ +PUBLIC void HTSetSuffix5 ARGS5( + CONST char *, suffix, + CONST char *, representation, + CONST char *, encoding, + CONST char *, desc, + float, value) +{ + HTSuffix * suff; + BOOL trivial_enc = IsUnityEncStr(encoding); + + if (strcmp(suffix, "*") == 0) + suff = &no_suffix; + else if (strcmp(suffix, "*.*") == 0) + suff = &unknown_suffix; + else { + HTList *cur = HTSuffixes; + + while (NULL != (suff = (HTSuffix*)HTList_nextObject(cur))) { + if (suff->suffix && 0 == strcmp(suff->suffix, suffix) && + ((trivial_enc && IsUnityEnc(suff->encoding)) || + (!trivial_enc && !IsUnityEnc(suff->encoding) && + strcmp(encoding, HTAtom_name(suff->encoding)) == 0))) + break; + } + if (!suff) { /* Not found -- create a new node */ + suff = (HTSuffix *) calloc(1, sizeof(HTSuffix)); + if (suff == NULL) + outofmem(__FILE__, "HTSetSuffix"); + + /* + ** Memory leak fixed. + ** 05-28-94 Lynx 2-3-1 Garrett Arch Blythe + */ + if (!HTSuffixes) { + HTSuffixes = HTList_new(); + atexit(free_suffixes); + } + + HTList_addObject(HTSuffixes, suff); + + StrAllocCopy(suff->suffix, suffix); + } + } + + if (representation) + suff->rep = HTAtom_for(representation); + + /* + ** Memory leak fixed. + ** 05-28-94 Lynx 2-3-1 Garrett Arch Blythe + ** Invariant code removed. + */ + suff->encoding = HTAtom_for(encoding); + + StrAllocCopy(suff->desc, desc); + + suff->quality = value; +} + +/* +** Purpose: Free all added suffixes. +** Arguments: void +** Return Value: void +** Remarks/Portability/Dependencies/Restrictions: +** To be used at program exit. +** Revision History: +** 05-28-94 created Lynx 2-3-1 Garrett Arch Blythe +*/ +PRIVATE void free_suffixes NOARGS +{ + HTSuffix * suff = NULL; + + /* + ** Loop through all suffixes. + */ + while (!HTList_isEmpty(HTSuffixes)) { + /* + ** Free off each item and its members if need be. + */ + suff = (HTSuffix *)HTList_removeLastObject(HTSuffixes); + FREE(suff->suffix); + FREE(suff->desc); + FREE(suff); + } + /* + ** Free off the list itself. + */ + HTList_delete(HTSuffixes); + HTSuffixes = NULL; +} + +/* Send README file. +** ----------------- +** +** If a README file exists, then it is inserted into the document here. +*/ +#ifdef HAVE_READDIR +PRIVATE void do_readme ARGS2(HTStructured *, target, CONST char *, localname) +{ + FILE * fp; + char * readme_file_name = + malloc(strlen(localname)+ 1 + strlen(HT_DIR_README_FILE) + 1); + if (readme_file_name == NULL) + outofmem(__FILE__, "do_readme"); + strcpy(readme_file_name, localname); + strcat(readme_file_name, "/"); + strcat(readme_file_name, HT_DIR_README_FILE); + + fp = fopen(readme_file_name, "r"); + + if (fp) { + HTStructuredClass targetClass; + + targetClass = *target->isa; /* (Can't init agregate in K&R) */ + START(HTML_PRE); + for (;;){ + char c = fgetc(fp); + if (c == (char)EOF) break; +#ifdef NOTDEFINED + switch (c) { + case '&': + case '<': + case '>': + PUTC('&'); + PUTC('#'); + PUTC((char)(c / 10)); + PUTC((char) (c % 10)); + PUTC(';'); + break; +/* case '\n': + PUTC('\r'); +Bug removed thanks to joe@athena.mit.edu */ + default: + PUTC(c); + } +#else + PUTC(c); +#endif /* NOTDEFINED */ + } + END(HTML_PRE); + fclose(fp); + } +} +#endif /* HAVE_READDIR */ + +/* Make the cache file name for a W3 document. +** ------------------------------------------- +** Make up a suitable name for saving the node in +** +** E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch +** /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx +** +** On exit: +** Returns a malloc'ed string which must be freed by the caller. +*/ +PUBLIC char * HTCacheFileName ARGS1( + CONST char *, name) +{ + char * acc_method = HTParse(name, "", PARSE_ACCESS); + char * host = HTParse(name, "", PARSE_HOST); + char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION); + + char * result; + result = (char *)malloc( + strlen(HTCacheRoot)+strlen(acc_method) + +strlen(host)+strlen(path)+6+1); + if (result == NULL) + outofmem(__FILE__, "HTCacheFileName"); + sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, acc_method, host, path); + FREE(path); + FREE(acc_method); + FREE(host); + return result; +} + +/* Open a file for write, creating the path. +** ----------------------------------------- +*/ +#ifdef NOT_IMPLEMENTED +PRIVATE int HTCreatePath ARGS1(CONST char *,path) +{ + return -1; +} +#endif /* NOT_IMPLEMENTED */ + +/* Convert filenames between local and WWW formats. +** ------------------------------------------------ +** Make up a suitable name for saving the node in +** +** E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch +** $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx +** +** On exit: +** Returns a malloc'ed string which must be freed by the caller. +*/ +PUBLIC char * HTLocalName ARGS1( + CONST char *, name) +{ + char * acc_method = HTParse(name, "", PARSE_ACCESS); + char * host = HTParse(name, "", PARSE_HOST); + char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION); + + HTUnEscape(path); /* Interpret % signs */ + + if (0 == strcmp(acc_method, "file")) { /* local file */ + FREE(acc_method); + if ((0 == strcasecomp(host, HTHostName())) || + (0 == strcasecomp(host, "localhost")) || !*host) { + FREE(host); + if (TRACE) + fprintf(stderr, "Node `%s' means path `%s'\n", name, path); +#ifdef DOSPATH + { + char *ret_path = NULL; + StrAllocCopy(ret_path, HTDOS_name(path)); + if (TRACE) { + fprintf(stderr, "HTDOS_name changed `%s' to `%s'\n", + path, ret_path); + } + FREE(path); + return(ret_path); + } +#else + return(path); +#endif /* DOSPATH */ + } else { + char * result = (char *)malloc( + strlen("/Net/")+strlen(host)+strlen(path)+1); + if (result == NULL) + outofmem(__FILE__, "HTLocalName"); + sprintf(result, "%s%s%s", "/Net/", host, path); + FREE(host); + FREE(path); + if (TRACE) + fprintf(stderr, "Node `%s' means file `%s'\n", name, result); + return result; + } + } else { /* other access */ + char * result; +#ifdef VMS + char * home = getenv("HOME"); + if (!home) + home = HTCacheRoot; + else + home = HTVMS_wwwName(home); +#else + CONST char * home = (CONST char*)getenv("HOME"); + if (!home) + home = "/tmp"; +#endif /* VMS */ + result = (char *)malloc( + strlen(home)+strlen(acc_method)+strlen(host)+strlen(path)+6+1); + if (result == NULL) + outofmem(__FILE__, "HTLocalName"); + sprintf(result, "%s/WWW/%s/%s%s", home, acc_method, host, path); + FREE(path); + FREE(acc_method); + FREE(host); + return result; + } +} + +/* Make a WWW name from a full local path name. +** -------------------------------------------- +** +** Bugs: +** At present, only the names of two network root nodes are hand-coded +** in and valid for the NeXT only. This should be configurable in +** the general case. +*/ +PUBLIC char * WWW_nameOfFile ARGS1( + CONST char *, name) +{ + char * result; +#ifdef NeXT + if (0 == strncmp("/private/Net/", name, 13)) { + result = (char *)malloc(7+strlen(name+13)+1); + if (result == NULL) + outofmem(__FILE__, "WWW_nameOfFile"); + sprintf(result, "file://%s", name+13); + } else +#endif /* NeXT */ + if (0 == strncmp(HTMountRoot, name, 5)) { + result = (char *)malloc(7+strlen(name+5)+1); + if (result == NULL) + outofmem(__FILE__, "WWW_nameOfFile"); + sprintf(result, "file://%s", name+5); + } else { + result = (char *)malloc(7+strlen(HTHostName())+strlen(name)+1); + if (result == NULL) + outofmem(__FILE__, "WWW_nameOfFile"); + sprintf(result, "file://%s%s", HTHostName(), name); + } + if (TRACE) + fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result); + return result; +} + +/* Determine a suitable suffix, given the representation. +** ------------------------------------------------------ +** +** On entry, +** rep is the atomized MIME style representation +** enc is an encoding, trivial (8bit, binary, etc.) or gzip etc. +** +** On exit: +** Returns a pointer to a suitable suffix string if one has been +** found, else "". +*/ +PUBLIC CONST char * HTFileSuffix ARGS2( + HTAtom*, rep, + CONST char *, enc) +{ + HTSuffix * suff; +#ifdef FNAMES_8_3 + HTSuffix * first_found = NULL; +#endif + BOOL trivial_enc; + int n; + int i; + +#define NO_INIT /* don't init anymore since I do it in Lynx at startup */ +#ifndef NO_INIT + if (!HTSuffixes) + HTFileInit(); +#endif /* !NO_INIT */ + + trivial_enc = IsUnityEncStr(enc); + n = HTList_count(HTSuffixes); + for (i = 0; i < n; i++) { + suff = (HTSuffix *)HTList_objectAt(HTSuffixes, i); + if (suff->rep == rep && +#if defined(VMS) || defined(FNAMES_8_3) + /* Don't return a suffix whose first char is a dot, and which + has more dots or asterisks after that, for + these systems - kw */ + (!suff->suffix || !suff->suffix[0] || suff->suffix[0] != '.' || + (strchr(suff->suffix + 1, '.') == NULL && + strchr(suff->suffix + 1, '*') == NULL)) && +#endif + ((trivial_enc && IsUnityEnc(suff->encoding)) || + (!trivial_enc && !IsUnityEnc(suff->encoding) && + strcmp(enc, HTAtom_name(suff->encoding)) == 0))) { +#ifdef FNAMES_8_3 + if (suff->suffix && (strlen(suff->suffix) <= 4)) { + /* + * If length of suffix (including dot) is 4 or smaller, + * return this one even if we found a longer one + * earlier - kw + */ + return suff->suffix; + } else if (!first_found) { + first_found = suff; /* remember this one */ + } +#else + return suff->suffix; /* OK -- found */ +#endif + } + } +#ifdef FNAMES_8_3 + if (first_found) + return first_found->suffix; +#endif + return ""; /* Dunno */ +} + +/* Determine file format from file name. +** ------------------------------------- +** +** This version will return the representation and also set +** a variable for the encoding. +** +** Encoding may be a unity encoding (binary, 8bit, etc.) or +** a content-coding like gzip, compress. +** +** It will handle for example x.txt, x.txt,Z, x.Z +*/ +PUBLIC HTFormat HTFileFormat ARGS3( + CONST char *, filename, + HTAtom **, pencoding, + CONST char**, pdesc) +{ + HTSuffix * suff; + int n; + int i; + int lf; +#ifdef VMS + char *semicolon = NULL; +#endif /* VMS */ + + if (pencoding) + *pencoding = NULL; + if (pdesc) + *pdesc = NULL; + if (LYforce_HTML_mode) { + if (pencoding) + *pencoding = WWW_ENC_8BIT; + return WWW_HTML; + } + +#ifdef VMS + /* + ** Trim at semicolon if a version number was + ** included, so it doesn't interfere with the + ** code for getting the MIME type. - FM + */ + if ((semicolon = strchr(filename, ';')) != NULL) + *semicolon = '\0'; +#endif /* VMS */ + +#ifndef NO_INIT + if (!HTSuffixes) + HTFileInit(); +#endif /* !NO_INIT */ + lf = strlen(filename); + n = HTList_count(HTSuffixes); + for (i = 0; i < n; i++) { + int ls; + suff = (HTSuffix *)HTList_objectAt(HTSuffixes, i); + ls = strlen(suff->suffix); + if ((ls <= lf) && 0 == strcasecomp(suff->suffix, filename + lf - ls)) { + int j; + if (pencoding) + *pencoding = suff->encoding; + if (pdesc) + *pdesc = suff->desc; + if (suff->rep) { +#ifdef VMS + if (semicolon != NULL) + *semicolon = ';'; +#endif /* VMS */ + return suff->rep; /* OK -- found */ + } + for (j = 0; j < n; j++) { /* Got encoding, need representation */ + int ls2; + suff = (HTSuffix *)HTList_objectAt(HTSuffixes, j); + ls2 = strlen(suff->suffix); + if ((ls + ls2 <= lf) && 0 == strncasecomp( + suff->suffix, filename + lf - ls -ls2, ls2)) { + if (suff->rep) { + if (pdesc && !(*pdesc)) + *pdesc = suff->desc; +#ifdef VMS + if (semicolon != NULL) + *semicolon = ';'; +#endif /* VMS */ + return suff->rep; + } + } + } + + } + } + + /* defaults tree */ + + suff = strchr(filename, '.') ? /* Unknown suffix */ + ( unknown_suffix.rep ? &unknown_suffix : &no_suffix) + : &no_suffix; + + /* + ** Set default encoding unless found with suffix already. + */ + if (pencoding && !*pencoding) + *pencoding = suff->encoding ? suff->encoding + : HTAtom_for("binary"); +#ifdef VMS + if (semicolon != NULL) + *semicolon = ';'; +#endif /* VMS */ + return suff->rep ? suff->rep : WWW_BINARY; +} + +/* Revise the file format in relation to the Lynx charset. - FM +** ------------------------------------------------------- +** +** This checks the format associated with an anchor for +** an extended MIME Content-Type, and if a charset is +** indicated, sets Lynx up for proper handling in relation +** to the currently selected character set. - FM +*/ +PUBLIC HTFormat HTCharsetFormat ARGS3( + HTFormat, format, + HTParentAnchor *, anchor, + int, default_LYhndl) +{ + char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; + BOOL chartrans_ok = FALSE; + int chndl = -1; + int i; + + FREE(anchor->charset); + StrAllocCopy(cp, format->name); + for (i = 0; cp[i]; i++) + cp[i] = TOLOWER(cp[i]); + if (((cp1 = strchr(cp, ';')) != NULL) && + (cp2 = strstr(cp1, "charset")) != NULL) { + if (TRACE) + fprintf(stderr, + "HTCharsetFormat: Extended MIME Content-Type is %s\n", + format->name); + cp2 += 7; + while (*cp2 == ' ' || *cp2 == '=') + cp2++; + StrAllocCopy(cp3, cp2); /* copy to mutilate more */ + for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' && + *cp4 != ';' && *cp4 != ':' && + !WHITE(*cp4)); cp4++) { + ; /* do nothing */ + } + *cp4 = '\0'; + cp4 = cp3; + chndl = UCGetLYhndl_byMIME(cp3); + if (UCCanTranslateFromTo(chndl, current_char_set)) { + chartrans_ok = YES; + *cp1 = '\0'; + format = HTAtom_for(cp); + StrAllocCopy(anchor->charset, cp4); + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_MIME); + } else if (chndl < 0) { + /* + ** Got something but we don't recognize it. + */ + chndl = UCLYhndl_for_unrec; + if (UCCanTranslateFromTo(chndl, current_char_set)) { + chartrans_ok = YES; + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + } + if (chartrans_ok) { + LYUCcharset *p_in = HTAnchor_getUCInfoStage(anchor, + UCT_STAGE_MIME); + LYUCcharset *p_out = HTAnchor_setUCInfoStage(anchor, + current_char_set, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + if (!p_out) { + /* + ** Try again. + */ + p_out = HTAnchor_getUCInfoStage(anchor, UCT_STAGE_HTEXT); + } + if (!strcmp(p_in->MIMEname, "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(anchor, + HTAnchor_getUCLYhndl(anchor, + UCT_STAGE_HTEXT), + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + if (!strcmp(p_out->MIMEname, "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(anchor, + HTAnchor_getUCLYhndl(anchor, + UCT_STAGE_MIME), + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + } + if (p_in->enc != UCT_ENC_CJK) { + HTCJK = NOCJK; + if (!(p_in->codepoints & + UCT_CP_SUBSETOF_LAT1) && + chndl == current_char_set) { + HTPassEightBitRaw = TRUE; + } + } else if (p_out->enc == UCT_ENC_CJK) { + if (LYRawMode) { + if ((!strcmp(p_in->MIMEname, "euc-jp") || + !strcmp(p_in->MIMEname, "shift_jis")) && + (!strcmp(p_out->MIMEname, "euc-jp") || + !strcmp(p_out->MIMEname, "shift_jis"))) { + HTCJK = JAPANESE; + } else if (!strcmp(p_in->MIMEname, "euc-cn") && + !strcmp(p_out->MIMEname, "euc-cn")) { + HTCJK = CHINESE; + } else if (!strcmp(p_in->MIMEname, "big-5") && + !strcmp(p_out->MIMEname, "big-5")) { + HTCJK = TAIPEI; + } else if (!strcmp(p_in->MIMEname, "euc-kr") && + !strcmp(p_out->MIMEname, "euc-kr")) { + HTCJK = KOREAN; + } else { + HTCJK = NOCJK; + } + } else { + HTCJK = NOCJK; + } + } + /* + ** Check for an iso-8859-# we don't know. - FM + */ + } else if (!strncmp(cp4, "iso-8859-", 9) && + isdigit((unsigned char)cp4[9]) && + !strncmp(LYchar_set_names[current_char_set], + "Other ISO Latin", 15)) { + /* + ** Hope it's a match, for now. - FM + */ + *cp1 = '\0'; + format = HTAtom_for(cp); + cp1 = &cp4[10]; + while (*cp1 && + isdigit((unsigned char)(*cp1))) + cp1++; + *cp1 = '\0'; + StrAllocCopy(anchor->charset, cp4); + HTPassEightBitRaw = TRUE; + HTAlert(anchor->charset); + } + FREE(cp3); + } else if (cp1 != NULL) { + /* + ** No charset parameter is present. + ** Ignore all other parameters, as + ** we do when charset is present. - FM + */ + *cp1 = '\0'; + format = HTAtom_for(cp); + } + FREE(cp); + + /* + ** Set up defaults, if needed. - FM + */ + if (!chartrans_ok && !anchor->charset && default_LYhndl >= 0) { + HTAnchor_setUCInfoStage(anchor, default_LYhndl, + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + HTAnchor_copyUCInfoStage(anchor, + UCT_STAGE_PARSER, + UCT_STAGE_MIME, + -1); + + return format; +} + +/* Determine value from file name. +** ------------------------------- +** +*/ +PUBLIC float HTFileValue ARGS1( + CONST char *, filename) +{ + HTSuffix * suff; + int n; + int i; + int lf = strlen(filename); + +#ifndef NO_INIT + if (!HTSuffixes) + HTFileInit(); +#endif /* !NO_INIT */ + n = HTList_count(HTSuffixes); + for (i = 0; i < n; i++) { + int ls; + suff = (HTSuffix *)HTList_objectAt(HTSuffixes, i); + ls = strlen(suff->suffix); + if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) { + if (TRACE) + fprintf(stderr, "File: Value of %s is %.3f\n", + filename, suff->quality); + return suff->quality; /* OK -- found */ + } + } + return 0.3; /* Dunno! */ +} + +/* Determine write access to a file. +** --------------------------------- +** +** On exit: +** Returns YES if file can be accessed and can be written to. +** +** Bugs: +** 1. No code for non-unix systems. +** 2. Isn't there a quicker way? +*/ + +#if defined(HAVE_CONFIG_H) + +#ifndef HAVE_GETGROUPS +#define NO_GROUPS +#endif + +#else + +#ifdef VMS +#define NO_GROUPS +#endif /* VMS */ +#ifdef NO_UNIX_IO +#define NO_GROUPS +#endif /* NO_UNIX_IO */ +#ifdef PCNFS +#define NO_GROUPS +#endif /* PCNFS */ +#ifdef NOUSERS +#define NO_GROUPS +#endif /* PCNFS */ + +#endif /* HAVE_CONFIG_H */ + +PUBLIC BOOL HTEditable ARGS1( + CONST char *, filename) +{ +#ifdef NO_GROUPS + return NO; /* Safe answer till we find the correct algorithm */ +#else +#ifdef NeXT + int groups[NGROUPS]; +#else + gid_t groups[NGROUPS]; +#endif /* NeXT */ + uid_t myUid; + int ngroups; /* The number of groups */ + struct stat fileStatus; + int i; + + if (stat(filename, &fileStatus)) /* Get details of filename */ + return NO; /* Can't even access file! */ + + ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */ + myUid = geteuid(); /* Get my user identifier */ + + if (TRACE) { + int i2; + fprintf(stderr, + "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (", + (unsigned int) fileStatus.st_mode, fileStatus.st_uid, + fileStatus.st_gid, + myUid, ngroups); + for (i2 = 0; i2 < ngroups; i2++) + fprintf(stderr, " %d", groups[i2]); + fprintf(stderr, ")\n"); + } + + if (fileStatus.st_mode & 0002) /* I can write anyway? */ + return YES; + + if ((fileStatus.st_mode & 0200) /* I can write my own file? */ + && (fileStatus.st_uid == myUid)) + return YES; + + if (fileStatus.st_mode & 0020) /* Group I am in can write? */ + { + for (i = 0; i < ngroups; i++) { + if (groups[i] == fileStatus.st_gid) + return YES; + } + } + if (TRACE) + fprintf(stderr, "\tFile is not editable.\n"); + return NO; /* If no excuse, can't do */ +#endif /* NO_GROUPS */ +} + +/* Make a save stream. +** ------------------- +** +** The stream must be used for writing back the file. +** @@@ no backup done +*/ +PUBLIC HTStream * HTFileSaveStream ARGS1( + HTParentAnchor *, anchor) +{ + CONST char * addr = HTAnchor_address((HTAnchor*)anchor); + char * localname = HTLocalName(addr); + + FILE* fp = fopen(localname, "w"); + if (!fp) + return NULL; + + return HTFWriter_new(fp); +} + +/* Output one directory entry. +** --------------------------- +*/ +PUBLIC void HTDirEntry ARGS3( + HTStructured *, target, + CONST char *, tail, + CONST char *, entry) +{ + char * relative = NULL; + char * escaped = NULL; + int len; + + if (0 == strcmp(entry,"../")) { + /* + ** Undo slash appending for anchor creation. + */ + StrAllocCopy(escaped,".."); + } else { + escaped = HTEscape(entry, URL_XPALPHAS); + if (((len = strlen(escaped)) > 2) && + escaped[(len - 3)] == '%' && + escaped[(len - 2)] == '2' && + TOUPPER(escaped[(len - 1)]) == 'F') { + escaped[(len - 3)] = '\0'; + } + } + + if (tail == NULL || *tail == '\0') { + /* + ** Handle extra slash at end of path. + */ + HTStartAnchor(target, NULL, (escaped[0] != '\0' ? escaped : "/")); + } else { + /* + ** If empty tail, gives absolute ref below. + */ + relative = (char*)malloc(strlen(tail) + strlen(escaped)+2); + if (relative == NULL) + outofmem(__FILE__, "HTDirEntry"); + sprintf(relative, "%s%s%s", + tail, + (*escaped != '\0' ? "/" : ""), + escaped); + HTStartAnchor(target, NULL, relative); + FREE(relative); + } + FREE(escaped); +} + +/* Output parent directory entry. +** ------------------------------ +** +** This gives the TITLE and H1 header, and also a link +** to the parent directory if appropriate. +** +** On exit: +** Returns TRUE if an "Up to <parent>" link was not created +** for a readable local directory because LONG_LIST is defined +** and NO_PARENT_DIR_REFERENCE is not defined, such that the +** calling function use LYListFmtParse() to create a link to +** the parent directory. Otherwise, it returns FALSE. - FM +*/ +PUBLIC BOOL HTDirTitles ARGS3( + HTStructured *, target, + HTAnchor *, anchor, + BOOL, tildeIsTop) +{ + char * logical = HTAnchor_address(anchor); + char * path = HTParse(logical, "", PARSE_PATH + PARSE_PUNCTUATION); + char * current; + char * cp = NULL; + BOOL need_parent_link = FALSE; + int i; + +#ifdef DOSPATH + BOOL local_link = FALSE; + if (logical[18] == ':') local_link = TRUE; +#endif + /* + ** Check tildeIsTop for treating home directory as Welcome + ** (assume the tilde is not followed by a username). - FM + */ + if (tildeIsTop && !strncmp(path, "/~", 2)) { + if (path[2] == '\0') { + path[1] = '\0'; + } else { + for (i = 0; path[(i + 2)]; i++) { + path[i] = path[(i + 2)]; + } + path[i] = '\0'; + } + } + + /* + ** Trim out the ;type= parameter, if present. - FM + */ + if ((cp = strrchr(path, ';')) != NULL) { + if (!strncasecomp((cp+1), "type=", 5)) { + if (TOUPPER(*(cp+6)) == 'D' || + TOUPPER(*(cp+6)) == 'A' || + TOUPPER(*(cp+6)) == 'I') + *cp = '\0'; + } + cp = NULL; + } + current = strrchr(path, '/'); /* last part or "" */ + + { + char * printable = NULL; + +#ifdef DIRED_SUPPORT + if (0 == strncasecomp(path, "/%2F", 4)) + StrAllocCopy(printable, (path+1)); + else + StrAllocCopy(printable, path); + if (0 == strncasecomp(printable, "/vmsysu%2b", 10) || + 0 == strncasecomp(printable, "/anonymou.", 10)) { + StrAllocCopy(cp, (printable+1)); + StrAllocCopy(printable, cp); + FREE(cp); + } +#else + StrAllocCopy(printable, (current ? current + 1 : "")); +#endif /* DIRED_SUPPORT */ + + START(HTML_HEAD); + PUTS("\n"); + HTUnEscape(printable); + START(HTML_TITLE); + PUTS(*printable ? printable : "Welcome"); + PUTS(" directory"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + +#ifdef DIRED_SUPPORT + START(HTML_H2); + PUTS(*printable ? "Current directory is " : ""); + PUTS(*printable ? printable : "Welcome"); + END(HTML_H2); + PUTS("\n"); +#else + START(HTML_H1); + PUTS(*printable ? printable : "Welcome"); + END(HTML_H1); + PUTS("\n"); +#endif /* DIRED_SUPPORT */ + if (((0 == strncasecomp(printable, "vmsysu:", 7)) && + (cp = strchr(printable, '.')) != NULL && + strchr(cp, '/') == NULL) || + (0 == strncasecomp(printable, "anonymou.", 9) && + strchr(printable, '/') == NULL)) { + FREE(printable); + FREE(logical); + FREE(path); + return(need_parent_link); + } + FREE(printable); + } + +#ifndef NO_PARENT_DIR_REFERENCE + /* + ** Make link back to parent directory. + */ + if (current && current[1]) { /* was a slash AND something else too */ + char * parent = NULL; + char * relative = NULL; + + *current++ = '\0'; + parent = strrchr(path, '/'); /* penultimate slash */ + + if ((parent && + (!strcmp(parent, "/..") || + !strncasecomp(parent, "/%2F", 4))) || + !strncasecomp(current, "%2F", 3)) { + FREE(logical); + FREE(path); + return(need_parent_link); + } + + relative = (char*) malloc(strlen(current) + 4); + if (relative == NULL) + outofmem(__FILE__, "HTDirTitles"); + sprintf(relative, "%s/..", current); + +#ifdef DOSPATH + if (local_link) + if (strlen(parent) == 3 ) + StrAllocCat(relative, "/."); +#endif + +#if !defined (VMS) +#ifdef DOSPATH + if(!local_link) +#endif + { + /* + ** On Unix, if it's not ftp and the directory cannot + ** be read, don't put out a link. + ** + ** On VMS, this problem is dealt with internally by + ** HTVMSBrowseDir(). + */ + DIR * dp = NULL; + + if (LYisLocalFile(logical)) { + /* + ** We need an absolute file path for the opendir. + ** We also need to unescape for this test. + ** Don't worry about %2F now, they presumably have been + ** dealt with above, and shouldn't appear for local + ** files anyway... Assume OS / filesystem will just + ** ignore superfluous slashes. - KW + */ + char * fullparentpath = NULL; + + /* + ** Path has been shortened above. + */ + StrAllocCopy(fullparentpath, *path ? path : "/"); + + /* + ** Guard against weirdness. + */ + if (0 == strcmp(current,"..")) { + StrAllocCat(fullparentpath,"/../.."); + } else if (0 == strcmp(current,".")) { + StrAllocCat(fullparentpath,"/.."); + } + + HTUnEscape(fullparentpath); + if ((dp = opendir(fullparentpath)) == NULL) { + FREE(fullparentpath); + FREE(logical); + FREE(relative); + FREE(path); + return(need_parent_link); + } + closedir(dp); + FREE(fullparentpath); +#ifdef LONG_LIST + need_parent_link = TRUE; + FREE(logical); + FREE(path); + FREE(relative); + return(need_parent_link); +#endif /* LONG_LIST */ + } + } +#endif /* !VMS */ + HTStartAnchor(target, "", relative); + FREE(relative); + + PUTS("Up to "); + if (parent) { + if ((0 == strcmp(current,".")) || + (0 == strcmp(current,".."))) { + /* + ** Should not happen, but if it does, + ** at least avoid giving misleading info. - KW + */ + PUTS(".."); + } else { + char * printable = NULL; + StrAllocCopy(printable, parent + 1); + HTUnEscape(printable); + PUTS(printable); + FREE(printable); + } + } else { + PUTS("/"); + } + END(HTML_A); + } +#endif /* !NO_PARENT_DIR_REFERENCE */ + + FREE(logical); + FREE(path); + return(need_parent_link); +} + +/* Load a document. +** ---------------- +** +** On entry: +** addr must point to the fully qualified hypertext reference. +** This is the physical address of the file +** +** On exit: +** returns <0 Error has occurred. +** HTLOADED OK +** +*/ +PUBLIC int HTLoadFile ARGS4( + CONST char *, addr, + HTParentAnchor *, anchor, + HTFormat, format_out, + HTStream *, sink) +{ + char * filename = NULL; + char * acc_method = NULL; + HTFormat format; + char * nodename = NULL; + char * newname = NULL; /* Simplified name of file */ + HTAtom * encoding; /* @@ not used yet */ + HTAtom * myEncoding = NULL; /* enc of this file, may be gzip etc. */ + int status; +#ifdef VMS + struct stat stat_info; +#endif /* VMS */ +#ifdef USE_ZLIB + gzFile gzfp = 0; + BOOL use_gzread = NO; +#endif /* USE_ZLIB */ + + /* + ** Reduce the filename to a basic form (hopefully unique!). + */ + StrAllocCopy(newname, addr); + filename=HTParse(newname, "", PARSE_PATH|PARSE_PUNCTUATION); + nodename=HTParse(newname, "", PARSE_HOST); + + /* + ** If access is ftp, or file is on another host, invoke ftp now. + */ + acc_method = HTParse(newname, "", PARSE_ACCESS); + if (strcmp("ftp", acc_method) == 0 || + (strcmp("localhost", nodename) != 0 && +#ifdef VMS + strcasecomp(nodename, HTHostName()) != 0 +#else + strcmp(nodename, HTHostName()) != 0 +#endif /* VMS */ + )) { + FREE(newname); + FREE(filename); + FREE(nodename); + FREE(acc_method); + return HTFTPLoad(addr, anchor, format_out, sink); + } else { + FREE(newname); + FREE(acc_method); + } +#ifdef VMS + HTUnEscape(filename); +#endif /* VMS */ + + /* + ** Determine the format and encoding mapped to any suffix. + */ + if (anchor->content_type && anchor->content_encoding) { + /* + * If content_type and content_encoding are BOTH already set + * in the anchor object, we believe it and don't try to + * derive format and encoding from the filename. - kw + */ + format = HTAtom_for(anchor->content_type); + myEncoding = HTAtom_for(anchor->content_encoding); + } else { + format = HTFileFormat(filename, &myEncoding, NULL); + + /* + ** Check the format for an extended MIME charset value, and + ** act on it if present. Otherwise, assume what is indicated + ** by the last parameter (fallback will effectively be + ** UCLYhndl_for_unspec, by default ISO-8859-1). - kw + */ + format = HTCharsetFormat(format, anchor, UCLYhndl_HTFile_for_unspec); + } + +#ifdef VMS + /* + ** Check to see if the 'filename' is in fact a directory. If it is + ** create a new hypertext object containing a list of files and + ** subdirectories contained in the directory. All of these are links + ** to the directories or files listed. + */ + if (HTStat(filename, &stat_info) == -1) { + if (TRACE) + fprintf(stderr, "HTLoadFile: Can't stat %s\n", filename); + } else { + if (((stat_info.st_mode) & S_IFMT) == S_IFDIR) { + if (HTDirAccess == HT_DIR_FORBID) { + FREE(filename); + FREE(nodename); + return HTLoadError(sink, 403, + "Directory browsing is not allowed."); + } + + if (HTDirAccess == HT_DIR_SELECTIVE) { + char * enable_file_name = + malloc(strlen(filename)+ 1 + + strlen(HT_DIR_ENABLE_FILE) + 1); + if (enable_file_name == NULL) + outofmem(__FILE__, "HTLoadFile"); + strcpy(enable_file_name, filename); + strcat(enable_file_name, "/"); + strcat(enable_file_name, HT_DIR_ENABLE_FILE); + if (HTStat(enable_file_name, &stat_info) == -1) { + FREE(filename); + FREE(nodename); + return HTLoadError(sink, 403, + "Selective access is not enabled for this directory"); + } + } + + FREE(filename); + FREE(nodename); + return HTVMSBrowseDir(addr, anchor, format_out, sink); + } + } + + /* + ** Assume that the file is in Unix-style syntax if it contains a '/' + ** after the leading one. @@ + */ + { + FILE * fp; + char * vmsname = strchr(filename + 1, '/') ? + HTVMS_name(nodename, filename) : filename + 1; + fp = fopen(vmsname, "r", "shr=put", "shr=upd"); + + /* + ** If the file wasn't VMS syntax, then perhaps it is Ultrix. + */ + if (!fp) { + char ultrixname[INFINITY]; + if (TRACE) + fprintf(stderr, "HTLoadFile: Can't open as %s\n", vmsname); + sprintf(ultrixname, "%s::\"%s\"", nodename, filename); + fp = fopen(ultrixname, "r", "shr=put", "shr=upd"); + if (!fp) { + if (TRACE) + fprintf(stderr, "HTLoadFile: Can't open as %s\n", + ultrixname); + } + } + if (fp) { + int len; + char *cp = NULL; + char *semicolon = NULL; + + if (HTEditable(vmsname)) { + HTAtom * put = HTAtom_for("PUT"); + HTList * methods = HTAnchor_methods(anchor); + if (HTList_indexOf(methods, put) == (-1)) { + HTList_addObject(methods, put); + } + } + /* + ** Trim vmsname at semicolon if a version number was + ** included, so it doesn't interfere with the check + ** for a compressed file. - FM + */ + if ((semicolon = strchr(vmsname, ';')) != NULL) + *semicolon = '\0'; + /* + ** Fake a Content-Encoding for compressed files. - FM + */ + if (!IsUnityEnc(myEncoding)) { + /* + * We already know from the call to HTFileFormat above + * that this is a compressed file, no need to look at + * the filename again. - kw + */ +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0 && + (!strcmp(HTAtom_name(myEncoding), "gzip") || + !strcmp(HTAtom_name(myEncoding), "x-gzip"))) { + fclose(fp); + if (semicolon != NULL) + *semicolon = ';'; + gzfp = gzopen(vmsname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + vmsname, (void*)gzfp); + use_gzread = YES; + } else +#endif /* USE_ZLIB */ + { + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); + format = HTAtom_for("www/compressed"); + } + } else if ((len = strlen(vmsname)) > 2) { + if ((vmsname[len - 1] == 'Z') && + (vmsname[len - 2] == '.' || + vmsname[len - 2] == '-' || + vmsname[len - 2] == '_') && + vmsname[len - 3] != ']' && + vmsname[len - 3] != ':') { + StrAllocCopy(cp, vmsname); + cp[len - 2] = '\0'; + format = HTFileFormat(cp, &encoding, NULL); + FREE(cp); + format = HTCharsetFormat(format, anchor, + UCLYhndl_HTFile_for_unspec); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-compress"); + format = HTAtom_for("www/compressed"); + } else if ((len > 3) && + !strcasecomp((char *)&vmsname[len - 2], "gz")) { + if (vmsname[len - 3] == '.' || + vmsname[len - 3] == '-' || + vmsname[len - 3] == '_') { + StrAllocCopy(cp, vmsname); + cp[len - 3] = '\0'; + format = HTFileFormat(cp, &encoding, NULL); + FREE(cp); + format = HTCharsetFormat(format, anchor, + UCLYhndl_HTFile_for_unspec); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-gzip"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + if (semicolon != NULL) + *semicolon = ';'; + gzfp = gzopen(vmsname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + vmsname, (void*)gzfp); + use_gzread = YES; + } +#else /* USE_ZLIB */ + format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ + } + } + } + if (semicolon != NULL) + *semicolon = ';'; + FREE(filename); + FREE(nodename); +#ifdef USE_ZLIB + if (use_gzread) { + if (gzfp) { + char * sugfname = NULL; + if (anchor->SugFname) { + StrAllocCopy(sugfname, anchor->SugFname); + } else { + char * anchor_path = HTParse(anchor->address, "", + PARSE_PATH + PARSE_PUNCTUATION); + char * lastslash; + HTUnEscape(anchor_path); + lastslash = strrchr(anchor_path, '/'); + if (lastslash) + StrAllocCopy(sugfname, lastslash + 1); + FREE(anchor_path); + } + FREE(anchor->content_encoding); + if (sugfname && *sugfname) + HTCheckFnameForCompression(&sugfname, anchor, + TRUE); + if (sugfname && *sugfname) + StrAllocCopy(anchor->SugFname, sugfname); + FREE(sugfname); + status = HTParseGzFile(format, format_out, + anchor, + gzfp, sink); + } else { + status = HTLoadError(NULL, + -(HT_ERROR), + "Could not open file for decompression!"); + } + } else +#endif /* USE_ZLIB */ + { + status = HTParseFile(format, format_out, anchor, fp, sink); + fclose(fp); + } + return status; + } /* If successful open */ + FREE(filename); + } + +#else /* Unix: */ + + FREE(filename); + + /* + ** For unix, we try to translate the name into the name of a + ** transparently mounted file. + ** + ** Not allowed in secure (HTClienntHost) situations. TBL 921019 + */ +#ifndef NO_UNIX_IO + /* Need protection here for telnet server but not httpd server. */ + + if (!HTSecure) { /* try local file system */ + char * localname = HTLocalName(addr); + struct stat dir_info; + +#ifdef HAVE_READDIR + /* + ** Multiformat handling. + ** + ** If needed, scan directory to find a good file. + ** Bug: We don't stat the file to find the length. + */ + if ((strlen(localname) > strlen(MULTI_SUFFIX)) && + (0 == strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX), + MULTI_SUFFIX))) { + DIR *dp; + BOOL forget_multi = NO; + + STRUCT_DIRENT * dirbuf; + float best = NO_VALUE_FOUND; /* So far best is bad */ + HTFormat best_rep = NULL; /* Set when rep found */ + HTAtom * best_enc = NULL; + char * best_name = NULL; /* Best dir entry so far */ + + char *base = strrchr(localname, '/'); + int baselen = 0; + + if (!base || base == localname) { + forget_multi = YES; + } else { + *base++ = '\0'; /* Just got directory name */ + baselen = strlen(base)- strlen(MULTI_SUFFIX); + base[baselen] = '\0'; /* Chop off suffix */ + + dp = opendir(localname); + } + if (forget_multi || !dp) { + FREE(localname); + FREE(nodename); + return HTLoadError(sink, 500, + "Multiformat: directory scan failed."); + } + + while ((dirbuf = readdir(dp)) != NULL) { + /* + ** While there are directory entries to be read... + */ +#ifndef DOSPATH + if (dirbuf->d_ino == 0) + continue; /* if the entry is not being used, skip it */ +#endif + if ((int)strlen(dirbuf->d_name) > baselen && /* Match? */ + !strncmp(dirbuf->d_name, base, baselen)) { + HTAtom * enc; + HTFormat rep = HTFileFormat(dirbuf->d_name, &enc, NULL); + float filevalue = HTFileValue(dirbuf->d_name); + float value = HTStackValue(rep, format_out, + filevalue, + 0L /* @@@@@@ */); + if (value <= 0.0) { + char * cp = NULL; + int len = strlen(dirbuf->d_name); + enc = NULL; + if (len > 2 && + dirbuf->d_name[len - 1] == 'Z' && + dirbuf->d_name[len - 2] == '.') { + StrAllocCopy(cp, dirbuf->d_name); + cp[len - 2] = '\0'; + format = HTFileFormat(cp, NULL, NULL); + FREE(cp); + value = HTStackValue(format, format_out, + filevalue, 0); + if (value <= 0.0) { + format = HTAtom_for("application/x-compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + if (value <= 0.0) { + format = HTAtom_for("www/compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + } else if ((len > 3) && + !strcasecomp((char *)&dirbuf->d_name[len - 2], + "gz") && + dirbuf->d_name[len - 3] == '.') { + StrAllocCopy(cp, dirbuf->d_name); + cp[len - 3] = '\0'; + format = HTFileFormat(cp, NULL, NULL); + FREE(cp); + value = HTStackValue(format, format_out, + filevalue, 0); + if (value <= 0.0) { + format = HTAtom_for("application/x-gzip"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + if (value <= 0.0) { + format = HTAtom_for("www/compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + } + } + if (value != NO_VALUE_FOUND) { + if (TRACE) + fprintf(stderr, + "HTLoadFile: value of presenting %s is %f\n", + HTAtom_name(rep), value); + if (value > best) { + best_rep = rep; + best_enc = enc; + best = value; + StrAllocCopy(best_name, dirbuf->d_name); + } + } /* if best so far */ + } /* if match */ + + } /* end while directory entries left to read */ + closedir(dp); + + if (best_rep) { + format = best_rep; + myEncoding = best_enc; + base[-1] = '/'; /* Restore directory name */ + base[0] = '\0'; + StrAllocCat(localname, best_name); + FREE(best_name); + } else { /* If not found suitable file */ + FREE(localname); + FREE(nodename); + return HTLoadError(sink, 403, /* List formats? */ + "Could not find suitable representation for transmission."); + } + /*NOTREACHED*/ + } /* if multi suffix */ + + /* + ** Check to see if the 'localname' is in fact a directory. If it + ** is create a new hypertext object containing a list of files and + ** subdirectories contained in the directory. All of these are + ** links to the directories or files listed. + ** NB This assumes the existence of a type 'STRUCT_DIRENT', which + ** will hold the directory entry, and a type 'DIR' which is used + ** to point to the current directory being read. + */ +#ifdef _WINDOWS + if (!exists(localname)) +#else + if (stat(localname,&dir_info) == -1) /* get file information */ +#endif + { + /* if can't read file information */ + if (TRACE) + fprintf(stderr, "HTLoadFile: can't stat %s\n", localname); + + } else { /* Stat was OK */ + +#ifdef _WINDOWS + if (stat(localname,&dir_info) == -1) dir_info.st_mode = S_IFDIR; +#endif + + if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) { + /* + ** If localname is a directory. + */ + HTStructured *target; /* HTML object */ + HTStructuredClass targetClass; + DIR *dp; + STRUCT_DIRENT * dirbuf; + char *logical = NULL; + char *pathname = NULL; + char *tail = NULL; + BOOL present[HTML_A_ATTRIBUTES]; + char * tmpfilename = NULL; + BOOL need_parent_link = FALSE; + struct stat file_info; + + if (TRACE) + fprintf(stderr, "%s is a directory\n", localname); + + /* + ** Check directory access. + ** Selective access means only those directories containing + ** a marker file can be browsed. + */ + if (HTDirAccess == HT_DIR_FORBID) { + FREE(localname); + FREE(nodename); + return HTLoadError(sink, 403, + "Directory browsing is not allowed."); + } + + + if (HTDirAccess == HT_DIR_SELECTIVE) { + char * enable_file_name = + malloc(strlen(localname)+ 1 + + strlen(HT_DIR_ENABLE_FILE) + 1); + if (enable_file_name == NULL) + outofmem(__FILE__, "HTLoadFile"); + strcpy(enable_file_name, localname); + strcat(enable_file_name, "/"); + strcat(enable_file_name, HT_DIR_ENABLE_FILE); + if (stat(enable_file_name, &file_info) != 0) { + FREE(localname); + FREE(nodename); + return HTLoadError(sink, 403, + "Selective access is not enabled for this directory"); + } + } + + dp = opendir(localname); + if (!dp) { + FREE(localname); + FREE(nodename); + return HTLoadError(sink, 403, + "This directory is not readable."); + } + + /* + ** Directory access is allowed and possible. + */ + logical = HTAnchor_address((HTAnchor*)anchor); + pathname = HTParse(logical, "", + PARSE_PATH + PARSE_PUNCTUATION); + + if (!strcmp(pathname,"/")) { + /* + ** Root path. + */ + StrAllocCopy (tail, "/foo/.."); + } else { + char *p = strrchr(pathname, '/'); /* find last slash */ + + if (!p) { + /* + ** This probably should not happen, + ** but be prepared if it does. - KW + */ + StrAllocCopy (tail, "/foo/.."); + } else { + /* + ** Take slash off the beginning. + */ + StrAllocCopy(tail, (p + 1)); + } + } + FREE(pathname); + + if (UCLYhndl_HTFile_for_unspec >= 0) { + HTAnchor_setUCInfoStage(anchor, + UCLYhndl_HTFile_for_unspec, + UCT_STAGE_PARSER, + UCT_SETBY_DEFAULT); + } + + target = HTML_new(anchor, format_out, sink); + targetClass = *target->isa; /* Copy routine entry points */ + + { int i; + for (i = 0; i < HTML_A_ATTRIBUTES; i++) + present[i] = (i == HTML_A_HREF); + } + + /* + ** The need_parent_link flag will be set if an + ** "Up to <parent>" link was not created for a + ** readable parent in HTDirTitles() because + ** LONG_LIST is defined and NO_PARENT_DIR_REFERENCE + ** is not defined so that need we to create the + ** link via an LYListFmtParse() call. - FM + */ + need_parent_link = HTDirTitles(target, + (HTAnchor *)anchor, FALSE); + +#ifdef DIRED_SUPPORT + if (strncmp(anchor->address, "lynxcgi:", 8)) { + HTAnchor_setFormat((HTParentAnchor *) anchor, WWW_DIRED); + lynx_edit_mode = TRUE; + } +#endif /* DIRED_SUPPORT */ + if (HTDirReadme == HT_DIR_README_TOP) + do_readme(target, localname); + { + HTBTree * bt = HTBTree_new((HTComparer)strcmp); + + while ((dirbuf = readdir(dp)) != NULL) { + /* + ** While there are directory entries to be read... + */ + char * dirname = NULL; + +#ifndef DOSPATH + if (dirbuf->d_ino == 0) + /* + ** If the entry is not being used, skip it. + */ + continue; +#endif + /* + ** Skip self, parent if handled in HTDirTitles() + ** or if NO_PARENT_DIR_REFERENCE is not defined, + ** and any dot files if no_dotfiles is set or + ** show_dotfiles is not set. - FM + */ + if (!strcmp(dirbuf->d_name, ".") /* self */ || + (!strcmp(dirbuf->d_name, "..") /* parent */ && + need_parent_link == FALSE) || + ((strcmp(dirbuf->d_name, "..")) && + (dirbuf->d_name[0] == '.' && + (no_dotfiles || !show_dotfiles)))) + continue; + + dirname = (char *)malloc(strlen(dirbuf->d_name) + 4); + if (dirname == NULL) + outofmem(__FILE__, "HTLoadFile"); + StrAllocCopy(tmpfilename, localname); + if (strcmp(localname, "/")) + /* + ** If filename is not root directory. + */ + StrAllocCat(tmpfilename, "/"); + + StrAllocCat(tmpfilename, dirbuf->d_name); + stat(tmpfilename, &file_info); + if (((file_info.st_mode) & S_IFMT) == S_IFDIR) +#ifndef DIRED_SUPPORT + sprintf((char *)dirname, "D%s",dirbuf->d_name); + else + sprintf((char *)dirname, "F%s",dirbuf->d_name); + /* D & F to have first directories, then files */ +#else + if (dir_list_style == MIXED_STYLE) + sprintf((char *)dirname, + " %s/", dirbuf->d_name); + else if (!strcmp(dirbuf->d_name, "..")) + sprintf((char *)dirname, + "A%s", dirbuf->d_name); + else + sprintf((char *)dirname, + "D%s", dirbuf->d_name); + else if (dir_list_style == MIXED_STYLE) + sprintf((char *)dirname, " %s", dirbuf->d_name); + else if (dir_list_style == FILES_FIRST) + sprintf((char *)dirname, "C%s", dirbuf->d_name); + /* C & D to have first files, then directories */ + else + sprintf((char *)dirname, "F%s", dirbuf->d_name); +#endif /* !DIRED_SUPPORT */ + /* + ** Sort dirname in the tree bt. + */ + HTBTree_add(bt, dirname); + } + + /* + ** Run through tree printing out in order. + */ + { + HTBTElement * next_element = HTBTree_next(bt,NULL); + /* pick up the first element of the list */ + char state; + /* I for initial (.. file), + D for directory file, + F for file */ + +#ifdef DIRED_SUPPORT + char test; +#endif /* DIRED_SUPPORT */ + state = 'I'; + + while (next_element != NULL) { + char *entry, *file_extra; + + StrAllocCopy(tmpfilename,localname); + if (strcmp(localname, "/")) + /* + ** If filename is not root directory. + */ + StrAllocCat(tmpfilename, "/"); + + StrAllocCat(tmpfilename, + (char *)HTBTree_object(next_element)+1); + /* + ** Append the current entry's filename + ** to the path. + */ + HTSimplify(tmpfilename); + /* + ** Output the directory entry. + */ + if (strcmp((char *) + (HTBTree_object(next_element)), "D..") && + strcmp((char *) + (HTBTree_object(next_element)), "A..")) + { +#ifdef DIRED_SUPPORT + test = (*(char *)(HTBTree_object(next_element)) + == 'D' ? 'D' : 'F'); + if (state != test) { +#ifndef LONG_LIST + if (dir_list_style == FILES_FIRST) { + if (state == 'F') + END(HTML_DIR); + } else if (dir_list_style != MIXED_STYLE) + if (state == 'D') + END(HTML_DIR); +#endif /* !LONG_LIST */ + state = + (*(char *)(HTBTree_object(next_element)) + == 'D' ? 'D' : 'F'); + START(HTML_H2); + if (dir_list_style != MIXED_STYLE) { + START(HTML_EM); + PUTS(state == 'D' ? + "Subdirectories:" : "Files:"); + END(HTML_EM); + } + END(HTML_H2); +#ifndef LONG_LIST + START(HTML_DIR); +#endif /* !LONG_LIST */ + } +#else + if (state != *(char *)(HTBTree_object( + next_element))) { +#ifndef LONG_LIST + if (state == 'D') + END(HTML_DIR); +#endif /* !LONG_LIST */ + state = + (*(char *)(HTBTree_object(next_element)) + == 'D' ? 'D' : 'F'); + START(HTML_H2); + START(HTML_EM); + PUTS(state == 'D' ? + "Subdirectories:" : "Files:"); + END(HTML_EM); + END(HTML_H2); +#ifndef LONG_LIST + START(HTML_DIR); +#endif /* !LONG_LIST */ + } +#endif /* DIRED_SUPPORT */ +#ifndef LONG_LIST + START(HTML_LI); +#endif /* !LONG_LIST */ + } + entry = (char*)HTBTree_object(next_element)+1; + file_extra = NULL; + +#ifdef LONG_LIST + LYListFmtParse(list_format, tmpfilename, target, + entry, tail); +#else + HTDirEntry(target, tail, entry); + PUTS(entry); + END(HTML_A); + if (file_extra) { + PUTS(file_extra); + FREE(file_extra); + } + MAYBE_END(HTML_LI); +#endif /* LONG_LIST */ + + next_element = HTBTree_next(bt, next_element); + /* pick up the next element of the list; + if none, return NULL*/ + } + if (state == 'I') { + START(HTML_P); + PUTS("Empty Directory"); + } +#ifndef LONG_LIST + else + END(HTML_DIR); +#endif /* !LONG_LIST */ + } + /* end while directory entries left to read */ + closedir(dp); + FREE(logical); + FREE(tmpfilename); + FREE(tail); + HTBTreeAndObject_free(bt); + + if (HTDirReadme == HT_DIR_README_BOTTOM) + do_readme(target, localname); + FREE_TARGET; + FREE(localname); + FREE(nodename); + return HT_LOADED; /* document loaded */ + } + + } /* end if localname is directory */ + + } /* end if file stat worked */ + +/* End of directory reading section +*/ +#endif /* HAVE_READDIR */ + { + FILE * fp = fopen(localname, "r"); + + if (TRACE) + fprintf (stderr, "HTLoadFile: Opening `%s' gives %p\n", + localname, (void*)fp); + if (fp) { /* Good! */ + int len; + char *cp = NULL; + + if (HTEditable(localname)) { + HTAtom * put = HTAtom_for("PUT"); + HTList * methods = HTAnchor_methods(anchor); + if (HTList_indexOf(methods, put) == (-1)) { + HTList_addObject(methods, put); + } + } + /* + ** Fake a Content-Encoding for compressed files. - FM + */ + if (!IsUnityEnc(myEncoding)) { + /* + * We already know from the call to HTFileFormat above + * that this is a compressed file, no need to look at + * the filename again. - kw + */ +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0 && + (!strcmp(HTAtom_name(myEncoding), "gzip") || + !strcmp(HTAtom_name(myEncoding), "x-gzip"))) { + fclose(fp); + gzfp = gzopen(localname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + localname, (void*)gzfp); + use_gzread = YES; + } else +#endif /* USE_ZLIB */ + { + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); + format = HTAtom_for("www/compressed"); + } + } else if ((len = strlen(localname)) > 2) { + if (localname[len - 1] == 'Z' && + localname[len - 2] == '.') { + StrAllocCopy(cp, localname); + cp[len - 2] = '\0'; + format = HTFileFormat(cp, &encoding, NULL); + FREE(cp); + format = HTCharsetFormat(format, anchor, + UCLYhndl_HTFile_for_unspec); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-compress"); + format = HTAtom_for("www/compressed"); + } else if ((len > 3) && + !strcasecomp((char *)&localname[len - 2], + "gz") && + localname[len - 3] == '.') { + StrAllocCopy(cp, localname); + cp[len - 3] = '\0'; + format = HTFileFormat(cp, &encoding, NULL); + FREE(cp); + format = HTCharsetFormat(format, anchor, + UCLYhndl_HTFile_for_unspec); + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, "x-gzip"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + gzfp = gzopen(localname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + localname, (void*)gzfp); + use_gzread = YES; + } +#else /* USE_ZLIB */ + format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ + } + } + FREE(localname); + FREE(nodename); +#ifdef USE_ZLIB + if (use_gzread) { + if (gzfp) { + char * sugfname = NULL; + if (anchor->SugFname) { + StrAllocCopy(sugfname, anchor->SugFname); + } else { + char * anchor_path = HTParse(anchor->address, "", + PARSE_PATH + PARSE_PUNCTUATION); + char * lastslash; + HTUnEscape(anchor_path); + lastslash = strrchr(anchor_path, '/'); + if (lastslash) + StrAllocCopy(sugfname, lastslash + 1); + FREE(anchor_path); + } + FREE(anchor->content_encoding); + if (sugfname && *sugfname) + HTCheckFnameForCompression(&sugfname, anchor, + TRUE); + if (sugfname && *sugfname) + StrAllocCopy(anchor->SugFname, sugfname); + FREE(sugfname); + status = HTParseGzFile(format, format_out, + anchor, + gzfp, sink); + } else { + status = HTLoadError(NULL, + -(HT_ERROR), + "Could not open file for decompression!"); + } + } else +#endif /* USE_ZLIB */ + { + status = HTParseFile(format, format_out, anchor, fp, sink); + fclose(fp); + } + return status; + } /* If successful open */ + FREE(localname); + } /* scope of fp */ + } /* local unix file system */ +#endif /* !NO_UNIX_IO */ +#endif /* VMS */ + +#ifndef DECNET + /* + ** Now, as transparently mounted access has failed, we try FTP. + */ + { + /* + ** Deal with case-sensitivity differences on VMS versus Unix. + */ +#ifdef VMS + if (strcasecomp(nodename, HTHostName()) != 0) +#else + if (strcmp(nodename, HTHostName()) != 0) +#endif /* VMS */ + { + FREE(nodename); + if (!strncmp(addr, "file://localhost", 16)) { + return -1; /* never go to ftp site when URL + * is file://localhost + */ + } else { + return HTFTPLoad(addr, anchor, format_out, sink); + } + } + FREE(nodename); + } +#endif /* !DECNET */ + + /* + ** All attempts have failed. + */ + { + if (TRACE) + fprintf(stderr, "Can't open `%s', errno=%d\n", addr, SOCKET_ERRNO); + + return HTLoadError(sink, 403, "Can't access requested file."); + } +} + +/* +** Protocol descriptors +*/ +#ifdef GLOBALDEF_IS_MACRO +#define _HTFILE_C_1_INIT { "ftp", HTLoadFile, 0 } +GLOBALDEF (HTProtocol,HTFTP,_HTFILE_C_1_INIT); +#define _HTFILE_C_2_INIT { "file", HTLoadFile, HTFileSaveStream } +GLOBALDEF (HTProtocol,HTFile,_HTFILE_C_2_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTFTP = { "ftp", HTLoadFile, 0 }; +GLOBALDEF PUBLIC HTProtocol HTFile = { "file", HTLoadFile, HTFileSaveStream }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.h new file mode 100644 index 00000000000..b65c17e73f4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.h @@ -0,0 +1,210 @@ +/* File access in libwww +** FILE ACCESS +** +** These are routines for local file access used by WWW browsers and servers. +** Implemented by HTFile.c. +** +** If the file is not a local file, then we pass it on to HTFTP in case it +** can be reached by FTP. +*/ +#ifndef HTFILE_H +#define HTFILE_H + +#include "HTFormat.h" +#include "HTAccess.h" +#ifndef HTML_H +#include "HTML.h" /* SCW */ +#endif /* HTML_H */ + +/* +** Controlling globals +** +** These flags control how directories and files are represented as +** hypertext, and are typically set by the application from command +** line options, etc. +*/ +extern int HTDirAccess; /* Directory access level */ + +#define HT_DIR_FORBID 0 /* Altogether forbidden */ +#define HT_DIR_SELECTIVE 1 /* If HT_DIR_ENABLE_FILE exists */ +#define HT_DIR_OK 2 /* Any accesible directory */ + +#define HT_DIR_ENABLE_FILE ".www_browsable" /* If exists, can browse */ + +extern int HTDirReadme; /* Include readme files in listing? */ + /* Values: */ +#define HT_DIR_README_NONE 0 /* No */ +#define HT_DIR_README_TOP 1 /* Yes, first */ +#define HT_DIR_README_BOTTOM 2 /* Yes, at the end */ + +#define HT_DIR_README_FILE "README" + +/* +** Convert filenames between local and WWW formats +*/ +extern char * HTLocalName PARAMS((CONST char * name)); + +/* +** Make a WWW name from a full local path name +*/ +extern char * WWW_nameOfFile PARAMS((const char * name)); + +/* +** Generate the name of a cache file +*/ +extern char * HTCacheFileName PARAMS((CONST char * name)); + +/* +** Output directory titles +** +** This is (like the next one) used by HTFTP. It is common code to generate +** the title and heading 1 and the parent directory link for any anchor. +** +** changed to return TRUE if parent directory link was generated, +** FALSE otherwise - KW +*/ +extern BOOL HTDirTitles PARAMS(( + HTStructured * target, + HTAnchor * anchor, + BOOL tildeIsTop)); + +/* Load a document. +** ---------------- +*/ +extern int HTLoadFile PARAMS(( + CONST char * addr, + HTParentAnchor * anchor, + HTFormat format_out, + HTStream * sink)); + +/* +** Output a directory entry +** +** This is used by HTFTP.c for example -- it is a common routine for +** generating a linked directory entry. +*/ +extern void HTDirEntry PARAMS(( + HTStructured * target, /* in which to put the linked text */ + CONST char * tail, /* last part of directory name */ + CONST char * entry)); /* name of this entry */ + +/* +** HTSetSuffix: Define the representation for a file suffix +** +** This defines a mapping between local file suffixes and file content +** types and encodings. +** +** ON ENTRY, +** +** suffix includes the "." if that is important (normally, yes!) +** +** representation is MIME-style content-type +** +** encoding is MIME-style content-transfer-encoding +** (8bit, 7bit, etc) or HTTP-style content-encoding +** (gzip, compress etc.) +** +** quality an a priori judgement of the quality of such files +** (0.0..1.0) +** +** HTSetSuffix5 has one more parameter for a short description of the type +** which is otherwise derived from the representation: +** +** desc is a short textual description, or NULL +** +** Examples: HTSetSuffix(".ps", "application/postscript", "8bit", 1.0); +** Examples: HTSetSuffix(".psz", "application/postscript", "gzip", 1.0); +** A MIME type could also indicate a non-trivial encoding on its own +** ("application/x-compressed-tar"), but in that case don't use enconding +** to also indicate it but use "binary" etc. +*/ +extern void HTSetSuffix5 PARAMS(( + CONST char * suffix, + CONST char * representation, + CONST char * encoding, + CONST char * desc, + float quality)); + +#define HTSetSuffix(suff,rep,enc,q) HTSetSuffix5(suff, rep, enc, NULL, q) + +/* +** HTFileFormat: Get Representation and Encoding from file name. +** +** ON EXIT, +** +** return The represntation it imagines the file is in. +** +** *pEncoding The encoding (binary, 7bit, etc). See HTSetSuffix. +*/ +extern HTFormat HTFileFormat PARAMS(( + CONST char * filename, + HTAtom ** pEncoding, + CONST char ** pDesc)); + +/* +** HTCharsetFormat: Revise the file format in relation to the Lynx charset. +** +** This checks the format associated with an anchor for +** for an extended MIME Content-Type, and if a charset is +** indicated, sets Lynx up for proper handling in relation +** to the currently selected character set. - FM +*/ +extern HTFormat HTCharsetFormat PARAMS(( + HTFormat format, + HTParentAnchor * anchor, + int default_LYhndl)); + +/* +** Determine file value from file name. +*/ +extern float HTFileValue PARAMS(( + CONST char * filename)); + +/* +** Determine write access to a file. +** +** ON EXIT, +** +** return value YES if file can be accessed and can be written to. +** +** BUGS +** +** Isn't there a quicker way? +*/ +extern BOOL HTEditable PARAMS((CONST char * filename)); + +/* Make a save stream. +** ------------------- +*/ +extern HTStream * HTFileSaveStream PARAMS(( + HTParentAnchor * anchor)); + +/* +** Determine a suitable suffix, given the representation. +** +** ON ENTRY, +** +** rep is the atomized MIME style representation +** enc is an encoding (8bit, binary, gzip, compress,..) +** +** ON EXIT, +** +** returns a pointer to a suitable suffix string if one has +** been found, else NULL. +*/ +extern CONST char * HTFileSuffix PARAMS(( + HTAtom* rep, + CONST char* enc)); + +/* +** The Protocols +*/ +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF (HTProtocol,HTFTP); +extern GLOBALREF (HTProtocol,HTFile); +#else +GLOBALREF HTProtocol HTFTP, HTFile; +#endif /* GLOBALREF_IS_MACRO */ +#endif /* HTFILE_H */ + +/* end of HTFile */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.c new file mode 100644 index 00000000000..e714e0d20f0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.c @@ -0,0 +1,441 @@ +/* FINGER ACCESS HTFinger.c +** ============= +** Authors: +** ARB Andrew Brooks +** +** History: +** 21 Apr 94 First version (ARB, from HTNews.c by TBL) +** 12 Mar 96 Made the URL and command buffering secure from +** stack modifications, beautified the HTLoadFinger() +** and response() functions, and added support for the +** following URL formats for sending a "", "/w", +** "username[@host]", or "/w username[@host]" command +** to the server: +** finger://host +** finger://host/ +** finger://host/%2fw +** finger://host/%2fw%20username[@host] +** finger://host/w/username[@host] +** finger://host/username[@host] +** finger://host/username[@host]/w +** finger://username@host +** finger://username@host/ +** finger://username@host/w +** 15 Mar 96 Added support for port 79 gtype 0 gopher URLs +** relayed from HTLoadGopher. - FM +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTAlert.h" +#include "HTML.h" +#include "HTParse.h" +#include "HTFormat.h" +#include "HTTCP.h" +#include "HTString.h" +#include "HTFinger.h" + +#include "LYLeaks.h" + +/* #define TRACE 1 */ + +#define FINGER_PORT 79 /* See rfc742 */ +#define BIG 1024 /* Bug */ + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET (*targetClass._free)(target) +#define NEXT_CHAR HTGetCharacter() + + +/* Module-wide variables +*/ +PRIVATE int s; /* Socket for FingerHost */ + +struct _HTStructured { + CONST HTStructuredClass * isa; /* For gopher streams */ + /* ... */ +}; + +PRIVATE HTStructured * target; /* The output sink */ +PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */ + +/* Initialisation for this module +** ------------------------------ +*/ +PRIVATE BOOL initialized = NO; +PRIVATE BOOL initialize NOARGS +{ + s = -1; /* Disconnected */ + return YES; +} + + + +/* Start anchor element +** -------------------- +*/ +PRIVATE void start_anchor ARGS1(CONST char *, href) +{ + BOOL present[HTML_A_ATTRIBUTES]; + CONST char* value[HTML_A_ATTRIBUTES]; + + { + int i; + for(i=0; i<HTML_A_ATTRIBUTES; i++) + present[i] = (i==HTML_A_HREF); + } + ((CONST char **)value)[HTML_A_HREF] = href; + (*targetClass.start_element)(target, HTML_A, present, + (CONST char **)value, -1, 0); + +} + +/* Send Finger Command line to remote host & Check Response +** -------------------------------------------------------- +** +** On entry, +** command points to the command to be sent, including CRLF, or is null +** pointer if no command to be sent. +** On exit, +** Negative status indicates transmission error, socket closed. +** Positive status is a Finger status. +*/ + + +PRIVATE int response ARGS5( + CONST char *, command, + char *, sitename, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) +{ + int status; + int length = strlen(command); + int ch, i; + char line[BIG], *l, *cmd=NULL; + char *p = line, *href=NULL; + + if (length == 0) + return(-1); + + /* Set up buffering. + */ + HTInitInput(s); + + /* Send the command. + */ + if (TRACE) + fprintf(stderr, "HTFinger command to be sent: %s", command); + status = NETWRITE(s, (char *)command, length); + if (status < 0) { + if (TRACE) + fprintf(stderr, + "HTFinger: Unable to send command. Disconnecting.\n"); + NETCLOSE(s); + s = -1; + return status; + } /* if bad status */ + + /* Make a hypertext object with an anchor list. + */ + target = HTML_new(anAnchor, format_out, sink); + targetClass = *target->isa; /* Copy routine entry points */ + + /* Create the results report. + */ + if (TRACE) + fprintf(stderr,"HTFinger: Reading finger information\n"); + START(HTML_HTML); + PUTS("\n"); + START(HTML_HEAD); + PUTS("\n"); + START(HTML_TITLE); + PUTS("Finger server on "); + PUTS(sitename); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + START(HTML_BODY); + PUTS("\n"); + START(HTML_H1); + PUTS("Finger server on "); + START(HTML_EM); + PUTS(sitename); + END(HTML_EM); + PUTS(": "); + if (command) { + StrAllocCopy(cmd, command); + } else { + StrAllocCopy(cmd, ""); + } + for (i = (strlen(cmd) - 1); i >= 0; i--) { + if (cmd[i] == LF || cmd[i] == CR) { + cmd[i] = '\0'; + } else { + break; + } + } + PUTS(cmd); + FREE(cmd); + END(HTML_H1); + PUTS("\n"); + START(HTML_PRE); + + while ((ch=NEXT_CHAR) != (char)EOF) { + + if (interrupted_in_htgetcharacter) { + if (TRACE) { + fprintf(stderr, + "HTFinger: Interrupted in HTGetCharacter, apparently.\n"); + } + _HTProgress ("Connection interrupted."); + goto end_html; + } + + if (ch != LF) { + *p = ch; /* Put character in line */ + if (p < &line[BIG-1]) { + p++; + } + } else { + *p = '\0'; /* Terminate line */ + /* + * OK we now have a line. + * Load it as 'l' and parse it. + */ + p = l = line; + while (*l) { + if (strncmp(l, "news:", 5) && + strncmp(l, "snews://", 8) && + strncmp(l, "nntp://", 7) && + strncmp(l, "snewspost:", 10) && + strncmp(l, "snewsreply:", 11) && + strncmp(l, "newspost:", 9) && + strncmp(l, "newsreply:", 10) && + strncmp(l, "ftp://", 6) && + strncmp(l, "file:/", 6) && + strncmp(l, "finger://", 9) && + strncmp(l, "http://", 7) && + strncmp(l, "https://", 8) && + strncmp(l, "wais://", 7) && + strncmp(l, "mailto:", 7) && + strncmp(l, "cso://", 6) && + strncmp(l, "gopher://", 9)) + PUTC(*l++); + else { + StrAllocCopy(href, l); + start_anchor(strtok(href, " \r\n\t,>)\"")); + while (*l && !strchr(" \r\n\t,>)\"", *l)) + PUTC(*l++); + END(HTML_A); + FREE(href); + } + } + PUTC('\n'); + } + } + NETCLOSE(s); + s = -1; + +end_html: + END(HTML_PRE); + PUTS("\n"); + END(HTML_BODY); + PUTS("\n"); + END(HTML_HTML); + PUTS("\n"); + FREE_TARGET; + return(0); +} + + +/* Load by name HTLoadFinger +** ============ +*/ +PUBLIC int HTLoadFinger ARGS4( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, stream) +{ + char *username, *sitename, *colon; /* Fields extracted from URL */ + char *slash, *at_sign; /* Fields extracted from URL */ + char *command, *str; /* Buffers */ + int port; /* Port number from URL */ + int status; /* tcp return */ + + if (TRACE) { + fprintf(stderr, "HTFinger: Looking for %s\n", (arg ? arg : "NULL")); + } + + if (!(arg && *arg)) { + HTAlert("Could not load data."); + return HT_NOT_LOADED; /* Ignore if no name */ + } + + if (!initialized) + initialized = initialize(); + if (!initialized) { + HTAlert ("Could not set up finger connection."); + return HT_NOT_LOADED; /* FAIL */ + } + + { + CONST char * p1=arg; + BOOL IsGopherURL = FALSE; + + /* Set up the host and command fields. + */ + if (!strncasecomp(arg, "finger://", 9)) { + p1 = arg + 9; /* Skip "finger://" prefix */ + } else if (!strncasecomp(arg, "gopher://", 9)) { + p1 = arg + 9; /* Skip "gopher://" prefix */ + IsGopherURL = TRUE; + } + sitename = (char *)p1; + + if ((slash = strchr(sitename, '/')) != NULL) { + *slash++ = '\0'; + HTUnEscape(slash); + if (IsGopherURL) { + if (*slash != '0') { + HTAlert("Could not load data."); + return HT_NOT_LOADED; /* FAIL */ + } + *slash++ = '\0'; + } + } + if ((at_sign = strchr(sitename, '@')) != NULL) { + if (IsGopherURL) { + HTAlert("Could not load data."); + return HT_NOT_LOADED; /* FAIL */ + } + *at_sign++ = '\0'; + username = sitename; + sitename = at_sign; + HTUnEscape(username); + } else if (slash) { + username = slash; + } else { + username = ""; + } + + if (*sitename == '\0') { + HTAlert("Could not load data (no sitename in finger URL)"); + return HT_NOT_LOADED; /* Ignore if no name */ + } + + if ((colon = strchr(sitename, ':')) != NULL) { + *colon++ = '\0'; + port = atoi(colon); + if (port != 79) { + HTAlert("Invalid port number - will only use port 79!"); + return HT_NOT_LOADED; /* Ignore if wrong port */ + } + } + + /* Load the string for making a connection/ + */ + str = (char *)calloc(1, (strlen(sitename) + 10)); + if (str == NULL) + outofmem(__FILE__, "HTLoadFinger"); + sprintf(str, "lose://%s/", sitename); + + /* Load the command for the finger server. + */ + command = (char *)calloc(1, (strlen(username) + 10)); + if (command == NULL) + outofmem(__FILE__, "HTLoadFinger"); + if (at_sign && slash) { + if (*slash == 'w' || *slash == 'W') { + sprintf(command, "/w %s%c%c", username, CR, LF); + } else { + sprintf(command, "%s%c%c", username, CR, LF); + } + } else if (at_sign) { + sprintf(command, "%s%c%c", username, CR, LF); + } else if (*username == '/') { + if ((slash = strchr((username+1), '/')) != NULL) { + *slash = ' '; + } + sprintf(command, "%s%c%c", username, CR, LF); + } else if ((*username == 'w' || *username == 'W') && + *(username+1) == '/') { + if (*username+2 != '\0') { + *(username+1) = ' '; + } else { + *(username+1) = '\0'; + } + sprintf(command, "/%s%c%c", username, CR, LF); + } else if ((*username == 'w' || *username == 'W') && + *(username+1) == '\0') { + sprintf(command, "/%s%c%c", username, CR, LF); + } else if ((slash = strchr(username, '/')) != NULL) { + *slash++ = '\0'; + if (*slash == 'w' || *slash == 'W') { + sprintf(command, "/w %s%c%c", username, CR, LF); + } else { + sprintf(command, "%s%c%c", username, CR, LF); + } + } else { + sprintf(command, "%s%c%c", username, CR, LF); + } + } /* scope of p1 */ + + /* Now, let's get a stream setup up from the FingerHost: + ** CONNECTING to finger host + */ + if (TRACE) + fprintf(stderr, "HTFinger: doing HTDoConnect on '%s'\n", str); + status = HTDoConnect(str, "finger", FINGER_PORT, &s); + if (TRACE) + fprintf(stderr, "HTFinger: Done DoConnect; status %d\n", status); + + if (status == HT_INTERRUPTED) { + /* Interrupt cleanly */ + if (TRACE) + fprintf(stderr, + "HTFinger: Interrupted on connect; recovering cleanly.\n"); + HTProgress ("Connection interrupted."); + FREE(str); + FREE(command); + return HT_NOT_LOADED; + } + if (status < 0) { + NETCLOSE(s); + s = -1; + if (TRACE) + fprintf(stderr, "HTFinger: Unable to connect to finger host.\n"); + HTAlert("Could not access finger host."); + FREE(str); + FREE(command); + return HT_NOT_LOADED; /* FAIL */ + } + if (TRACE) + fprintf(stderr, "HTFinger: Connected to finger host '%s'.\n", str); + FREE(str); + + /* Send the command, and process response if successful. + */ + if (response(command, sitename, anAnchor, format_out, stream) != 0) { + HTAlert("No response from finger server."); + FREE(command); + return HT_NOT_LOADED; + } + + FREE(command); + return HT_LOADED; +} + +#ifdef GLOBALDEF_IS_MACRO +#define _HTFINGER_C_1_INIT { "finger", HTLoadFinger, NULL } +GLOBALDEF (HTProtocol, HTFinger, _HTFINGER_C_1_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTFinger = { "finger", HTLoadFinger, NULL }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.h new file mode 100644 index 00000000000..98d98070900 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.h @@ -0,0 +1,24 @@ +/* Finger protocol module for the WWW library */ +/* History: +** 21 Apr 94 Andrew Brooks +*/ + +#ifndef HTFINGER_H +#define HTFINGER_H + +#include "HTAccess.h" +#include "HTAnchor.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF (HTProtocol, HTFinger); +#else +GLOBALREF HTProtocol HTFinger; +#endif /* GLOBALREF_IS_MACRO */ + +extern int HTLoadFinger PARAMS(( + CONST char * arg, + HTParentAnchor * anAnchor, + HTFormat format_out, + HTStream * stream)); + +#endif /* HTFINGER_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.c new file mode 100644 index 00000000000..c05af1fa255 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.c @@ -0,0 +1,1093 @@ +/* Manage different file formats HTFormat.c +** ============================= +** +** Bugs: +** Not reentrant. +** +** Assumes the incoming stream is ASCII, rather than a local file +** format, and so ALWAYS converts from ASCII on non-ASCII machines. +** Therefore, non-ASCII machines can't read local files. +** +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTAccess.h" + +/* Implements: +*/ +#include "HTFormat.h" + +PUBLIC float HTMaxSecs = 1e10; /* No effective limit */ +PUBLIC float HTMaxLength = 1e10; /* No effective limit */ +PUBLIC long int HTMaxBytes = 0; /* No effective limit */ + +#ifdef unix +#ifdef NeXT +#define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n" +#else +#define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n" + /* Full pathname would be better! */ +#endif /* NeXT */ +#endif /* unix */ + +#include "HTML.h" +#include "HTMLDTD.h" +#include "HText.h" +#include "HTAlert.h" +#include "HTList.h" +#include "HTInit.h" +#include "HTTCP.h" +/* Streams and structured streams which we use: +*/ +#include "HTFWriter.h" +#include "HTPlain.h" +#include "SGML.h" +#include "HTML.h" +#include "HTMLGen.h" + +#include "LYexit.h" +#include "LYUtils.h" +#include "LYGlobalDefs.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern int HTCheckForInterrupt NOPARAMS; + +PUBLIC BOOL HTOutputSource = NO; /* Flag: shortcut parser to stdout */ +/* extern BOOL interactive; LJM */ + +#ifdef ORIGINAL +struct _HTStream { + CONST HTStreamClass* isa; + /* ... */ +}; +#endif /* ORIGINAL */ + +/* this version used by the NetToText stream */ +struct _HTStream { + CONST HTStreamClass * isa; + BOOL had_cr; + HTStream * sink; +}; + +/* Presentation methods +** -------------------- +*/ +PUBLIC HTList * HTPresentations = NULL; +PUBLIC HTPresentation * default_presentation = NULL; + +/* + * To free off the presentation list. + */ +PRIVATE void HTFreePresentations NOPARAMS; + +/* Define a presentation system command for a content-type +** ------------------------------------------------------- +*/ +PUBLIC void HTSetPresentation ARGS6( + CONST char *, representation, + CONST char *, command, + float, quality, + float, secs, + float, secs_per_byte, + long int, maxbytes) +{ + HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation)); + if (pres == NULL) + outofmem(__FILE__, "HTSetPresentation"); + + pres->rep = HTAtom_for(representation); + pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */ + pres->converter = HTSaveAndExecute; /* Fixed for now ... */ + pres->quality = quality; + pres->secs = secs; + pres->secs_per_byte = secs_per_byte; + pres->maxbytes = maxbytes; + pres->command = NULL; + StrAllocCopy(pres->command, command); + + /* + * Memory leak fixed. + * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe + */ + if (!HTPresentations) { + HTPresentations = HTList_new(); + atexit(HTFreePresentations); + } + + if (strcmp(representation, "*")==0) { + FREE(default_presentation); + default_presentation = pres; + } else { + HTList_addObject(HTPresentations, pres); + } +} + +/* Define a built-in function for a content-type +** --------------------------------------------- +*/ +PUBLIC void HTSetConversion ARGS7( + CONST char *, representation_in, + CONST char *, representation_out, + HTConverter*, converter, + float, quality, + float, secs, + float, secs_per_byte, + long int, maxbytes) +{ + HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation)); + if (pres == NULL) + outofmem(__FILE__, "HTSetConversion"); + + pres->rep = HTAtom_for(representation_in); + pres->rep_out = HTAtom_for(representation_out); + pres->converter = converter; + pres->command = NULL; /* Fixed */ + pres->quality = quality; + pres->secs = secs; + pres->secs_per_byte = secs_per_byte; + pres->maxbytes = maxbytes; + pres->command = NULL; + + /* + * Memory Leak fixed. + * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe + */ + if (!HTPresentations) { + HTPresentations = HTList_new(); + atexit(HTFreePresentations); + } + + HTList_addObject(HTPresentations, pres); +} + +/* +** Purpose: Free the presentation list. +** Arguments: void +** Return Value: void +** Remarks/Portability/Dependencies/Restrictions: +** Made to clean up Lynx's bad leakage. +** Revision History: +** 05-28-94 created Lynx 2-3-1 Garrett Arch Blythe +*/ +PRIVATE void HTFreePresentations NOARGS +{ + HTPresentation * pres = NULL; + + /* + * Loop through the list. + */ + while (!HTList_isEmpty(HTPresentations)) { + /* + * Free off each item. + * May also need to free off it's items, but not sure + * as of yet. + */ + pres = (HTPresentation *)HTList_removeLastObject(HTPresentations); + FREE(pres->command); + FREE(pres); + } + /* + * Free the list itself. + */ + HTList_delete(HTPresentations); + HTPresentations = NULL; +} + +/* File buffering +** -------------- +** +** The input file is read using the macro which can read from +** a socket or a file. +** The input buffer size, if large will give greater efficiency and +** release the server faster, and if small will save space on PCs etc. +*/ +#define INPUT_BUFFER_SIZE 4096 /* Tradeoff */ +PRIVATE char input_buffer[INPUT_BUFFER_SIZE]; +PRIVATE char * input_pointer; +PRIVATE char * input_limit; +PRIVATE int input_file_number; + +/* Set up the buffering +** +** These routines are public because they are in fact needed by +** many parsers, and on PCs and Macs we should not duplicate +** the static buffer area. +*/ +PUBLIC void HTInitInput ARGS1 (int,file_number) +{ + input_file_number = file_number; + input_pointer = input_limit = input_buffer; +} + +PUBLIC int interrupted_in_htgetcharacter = 0; +PUBLIC char HTGetCharacter NOARGS +{ + char ch; + interrupted_in_htgetcharacter = 0; + do { + if (input_pointer >= input_limit) { + int status = NETREAD(input_file_number, + input_buffer, INPUT_BUFFER_SIZE); + if (status <= 0) { + if (status == 0) + return (char)EOF; + if (status == HT_INTERRUPTED) { + if (TRACE) + fprintf(stderr, + "HTFormat: Interrupted in HTGetCharacter\n"); + interrupted_in_htgetcharacter = 1; + return (char)EOF; + } + if (TRACE) + fprintf(stderr, "HTFormat: File read error %d\n", status); + return (char)EOF; /* -1 is returned by UCX + at end of HTTP link */ + } + input_pointer = input_buffer; + input_limit = input_buffer + status; + } + ch = *input_pointer++; + } while (ch == (char) 13); /* Ignore ASCII carriage return */ + + return FROMASCII(ch); +} + +/* Match maintype to any MIME type starting with maintype, + * for example: image/gif should match image + */ +PRIVATE int half_match ARGS2(char *,trial_type, char *,target) +{ + char *cp=strchr(trial_type,'/'); + + /* if no '/' or no '*' */ + if (!cp || *(cp+1) != '*') + return 0; + + if (TRACE) + fprintf(stderr,"HTFormat: comparing %s and %s for half match\n", + trial_type, target); + + /* main type matches */ + if (!strncmp(trial_type, target, (cp-trial_type)-1)) + return 1; + + return 0; +} + +/* Look up a presentation +** ---------------------- +** +** If fill_in is NULL, only look for an exact match. +** If a wildcard match is made, *fill_in is used to store +** a possibly modified presentation, and a pointer to it is +** returned. For an exact match, a pointer to the presentation +** in the HTPresentations list is returned. Returns NULL if +** nothing found. - kw +** +*/ +PRIVATE HTPresentation * HTFindPresentation ARGS3( + HTFormat, rep_in, + HTFormat, rep_out, + HTPresentation*, fill_in) +{ + HTAtom * wildcard = HTAtom_for("*"); + + if (TRACE) + fprintf(stderr, + "HTFormat: Looking up presentation for %s to %s\n", + HTAtom_name(rep_in), HTAtom_name(rep_out)); + + /* don't do anymore do it in the Lynx code at startup LJM */ + /* if (!HTPresentations) HTFormatInit(); */ /* set up the list */ + + { + int n = HTList_count(HTPresentations); + int i; + HTPresentation * pres, *match, + *strong_wildcard_match=0, + *weak_wildcard_match=0, + *last_default_match=0, + *strong_subtype_wildcard_match=0; + + for (i = 0; i < n; i++) { + pres = (HTPresentation *)HTList_objectAt(HTPresentations, i); + if (pres->rep == rep_in) { + if (pres->rep_out == rep_out) { + if (TRACE) + fprintf(stderr, + "FindPresentation: found exact match: %s\n", + HTAtom_name(pres->rep)); + return pres; + + } else if (!fill_in) { + continue; + } else if (pres->rep_out == wildcard) { + if (!strong_wildcard_match) + strong_wildcard_match = pres; + /* otherwise use the first one */ + if (TRACE) + fprintf(stderr, + "StreamStack: found strong wildcard match: %s\n", + HTAtom_name(pres->rep)); + } + + } else if (!fill_in) { + continue; + + } else if (half_match(HTAtom_name(pres->rep), + HTAtom_name(rep_in))) { + if (pres->rep_out == rep_out) { + if (!strong_subtype_wildcard_match) + strong_subtype_wildcard_match = pres; + /* otherwise use the first one */ + if (TRACE) + fprintf(stderr, + "StreamStack: found strong subtype wildcard match: %s\n", + HTAtom_name(pres->rep)); + } + } + + if (pres->rep == WWW_SOURCE) { + if (pres->rep_out == rep_out) { + if (!weak_wildcard_match) + weak_wildcard_match = pres; + /* otherwise use the first one */ + if (TRACE) + fprintf(stderr, + "StreamStack: found weak wildcard match: %s\n", + HTAtom_name(pres->rep_out)); + } + if (pres->rep_out == wildcard) { + if (!last_default_match) + last_default_match = pres; + /* otherwise use the first one */ + } + } + } + + match = strong_subtype_wildcard_match ? strong_subtype_wildcard_match : + strong_wildcard_match ? strong_wildcard_match : + weak_wildcard_match ? weak_wildcard_match : + last_default_match; + + if (match) { + *fill_in = *match; /* Specific instance */ + fill_in->rep = rep_in; /* yuk */ + fill_in->rep_out = rep_out; /* yuk */ + return fill_in; + } + } + + return NULL; +} + +/* Create a filter stack +** --------------------- +** +** If a wildcard match is made, a temporary HTPresentation +** structure is made to hold the destination format while the +** new stack is generated. This is just to pass the out format to +** MIME so far. Storing the format of a stream in the stream might +** be a lot neater. +** +*/ +PUBLIC HTStream * HTStreamStack ARGS4( + HTFormat, rep_in, + HTFormat, rep_out, + HTStream*, sink, + HTParentAnchor*, anchor) +{ + HTPresentation temp; + HTPresentation *match; + + if (TRACE) + fprintf(stderr, + "HTFormat: Constructing stream stack for %s to %s\n", + HTAtom_name(rep_in), HTAtom_name(rep_out)); + + /* don't return on WWW_SOURCE some people might like + * to make use of the source!!!! LJM + *//* + if (rep_out == WWW_SOURCE || rep_out == rep_in) + return sink; LJM */ + + if (rep_out == rep_in) + return sink; + + if ((match = HTFindPresentation(rep_in, rep_out, &temp))) { + if (match == &temp) { + if (TRACE) + fprintf(stderr, + "StreamStack: Using %s\n", HTAtom_name(temp.rep_out)); + } else { + if (TRACE) + fprintf(stderr, + "StreamStack: found exact match: %s\n", + HTAtom_name(match->rep)); + } + return (*match->converter)(match, anchor, sink); + } else { + return NULL; + } +} + +/* Put a presentation near start of list +** ------------------------------------- +** +** Look up a presentation (exact match only) and, if found, reorder +** it to the start of the HTPresentations list. - kw +*/ +PUBLIC void HTReorderPresentation ARGS2( + HTFormat, rep_in, + HTFormat, rep_out) +{ + HTPresentation *match; + if ((match = HTFindPresentation(rep_in, rep_out, NULL))) { + HTList_removeObject(HTPresentations, match); + HTList_addObject(HTPresentations, match); + } +} +/* Find the cost of a filter stack +** ------------------------------- +** +** Must return the cost of the same stack which StreamStack would set up. +** +** On entry, +** length The size of the data to be converted +*/ +PUBLIC float HTStackValue ARGS4( + HTFormat, rep_in, + HTFormat, rep_out, + float, initial_value, + long int, length) +{ + HTAtom * wildcard = HTAtom_for("*"); + + if (TRACE) + fprintf(stderr, + "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n", + HTAtom_name(rep_in), initial_value, HTAtom_name(rep_out)); + + if (rep_out == WWW_SOURCE || rep_out == rep_in) + return 0.0; + + /* don't do anymore do it in the Lynx code at startup LJM */ + /* if (!HTPresentations) HTFormatInit(); */ /* set up the list */ + + { + int n = HTList_count(HTPresentations); + int i; + HTPresentation * pres; + for (i = 0; i < n; i++) { + pres = (HTPresentation *)HTList_objectAt(HTPresentations, i); + if (pres->rep == rep_in && + (pres->rep_out == rep_out || pres->rep_out == wildcard)) { + float value = initial_value * pres->quality; + if (HTMaxSecs != 0.0) + value = value - (length*pres->secs_per_byte + pres->secs) + /HTMaxSecs; + return value; + } + } + } + + return -1e30; /* Really bad */ + +} + +/* Push data from a socket down a stream +** ------------------------------------- +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** The file number given is assumed to be a TELNET stream ie containing +** CRLF at the end of lines which need to be stripped to LF for unix +** when the format is textual. +** +*/ +PUBLIC int HTCopy ARGS4( + HTParentAnchor *, anchor, + int, file_number, + void*, handle GCC_UNUSED, + HTStream*, sink) +{ + HTStreamClass targetClass; + char line[256]; + int bytes = 0; + int rv = 0; + + /* Push the data down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + /* Push binary from socket down sink + ** + ** This operation could be put into a main event loop + */ + for (;;) { + int status; + + if (LYCancelDownload) { + LYCancelDownload = FALSE; + (*targetClass._abort)(sink, NULL); + rv = -1; + goto finished; + } + + if (HTCheckForInterrupt()) { + _HTProgress ("Data transfer interrupted."); + (*targetClass._abort)(sink, NULL); + if (bytes) + rv = HT_INTERRUPTED; + else + rv = -1; + goto finished; + } + + status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE); + + if (status <= 0) { + if (status == 0) { + break; + } else if (status == HT_INTERRUPTED) { + _HTProgress ("Data transfer interrupted."); + (*targetClass._abort)(sink, NULL); + if (bytes) + rv = HT_INTERRUPTED; + else + rv = -1; + goto finished; + } else if (SOCKET_ERRNO == ENOTCONN || + SOCKET_ERRNO == ECONNRESET || + SOCKET_ERRNO == EPIPE) { + /* + * Arrrrgh, HTTP 0/1 compability problem, maybe. + */ + if (bytes <= 0) { + /* + * Don't have any data, so let the calling + * function decide what to do about it. - FM + */ + rv = -2; + goto finished; + } else { + /* + * Treat what we've gotten already + * as the complete transmission. - FM + */ + if (TRACE) + fprintf(stderr, + "HTCopy: Unexpected server disconnect. Treating as completed.\n"); + status = 0; + break; + } + } + break; + } + +#ifdef NOT_ASCII + { + char * p; + for (p = input_buffer; p < input_buffer+status; p++) { + *p = FROMASCII(*p); + } + } +#endif /* NOT_ASCII */ + + (*targetClass.put_block)(sink, input_buffer, status); + + bytes += status; + if (anchor && anchor->content_length > 0) + sprintf(line, "Read %d of %d bytes of data.", + bytes, anchor->content_length); + else + sprintf(line, "Read %d bytes of data.", bytes); + HTProgress(line); + + } /* next bufferload */ + + _HTProgress("Data transfer complete"); + (void)NETCLOSE(file_number); + rv = HT_LOADED; + +finished: + return(rv); +} + +/* Push data from a file pointer down a stream +** ------------------------------------- +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** +*/ +PUBLIC int HTFileCopy ARGS2( + FILE *, fp, + HTStream*, sink) +{ + HTStreamClass targetClass; + char line[256]; + int status, bytes = 0, nreads = 0, nprogr = 0; + int rv = HT_OK; + + /* Push the data down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + /* Push binary from socket down sink + */ + for (;;) { + status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, fp); + nreads++; + if (status == 0) { /* EOF or error */ + if (ferror(fp) == 0) { + rv = HT_LOADED; + break; + } + if (TRACE) + fprintf(stderr, + "HTFormat: Read error, read returns %d\n", + ferror(fp)); + if (bytes) { + rv = HT_PARTIAL_CONTENT; + } else { + rv = -1; + } + break; + } + (*targetClass.put_block)(sink, input_buffer, status); + + bytes += status; + if (nreads >= 100) { + /* + ** Show progress messages for local files, and check for + ** user interruption. Start doing so only after a certain + ** number of reads have been done, and don't update it on + ** every read (normally reading in a local file should be + ** speedy). - KW + */ + if (nprogr == 0) { + if (bytes < 1024000) { + sprintf(line, "Read %d bytes of data.", bytes); + } else { + sprintf(line, "Read %d KB of data. %s", + bytes/1024, + "(Press 'z' if you want to abort loading.)"); + } + HTProgress(line); + if (HTCheckForInterrupt()) { + _HTProgress ("Data transfer interrupted."); + if (bytes) { + rv = HT_INTERRUPTED; + } else { + rv = -1; + } + break; + } + nprogr++; + } else if (nprogr == 25) { + nprogr = 0; + } else { + nprogr++; + } + } + } /* next bufferload */ + + return rv; +} + +#ifdef USE_ZLIB +/* Push data from a gzip file pointer down a stream +** ------------------------------------- +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** +*/ +PRIVATE int HTGzFileCopy ARGS2( + gzFile, gzfp, + HTStream*, sink) +{ + HTStreamClass targetClass; + char line[256]; + int status, bytes = 0, nreads = 0, nprogr = 0; + int gzerrnum; + int rv = HT_OK; + + /* Push the data down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + /* read and inflate gzipped file, and push binary down sink + */ + for (;;) { + status = gzread(gzfp, input_buffer, INPUT_BUFFER_SIZE); + nreads++; + if (status <= 0) { /* EOF or error */ + if (status == 0) { + rv = HT_LOADED; + break; + } + if (TRACE) { + fprintf(stderr, + "HTGzFileCopy: Read error, gzread returns %d\n", + status); + fprintf(stderr, + "gzerror : %s\n", + gzerror(gzfp, &gzerrnum)); + if (gzerrnum == Z_ERRNO) + perror("gzerror "); + } + if (bytes) { + rv = HT_PARTIAL_CONTENT; + } else { + rv = -1; + } + break; + } + (*targetClass.put_block)(sink, input_buffer, status); + + bytes += status; + if (nreads >= 100) { + /* + ** Show progress messages for local files, and check for + ** user interruption. Start doing so only after a certain + ** number of reads have been done, and don't update it on + ** every read (normally reading in a local file should be + ** speedy). - KW + */ + if (nprogr == 0) { + if (bytes < 1024000) { + sprintf(line, + "Read %d uncompressed bytes of data.", bytes); + } else { + sprintf(line, "Read %d uncompressed KB of data. %s", + bytes/1024, + "(Press 'z' to abort.)"); + } + HTProgress(line); + if (HTCheckForInterrupt()) { + _HTProgress ("Data transfer interrupted."); + if (bytes) { + rv = HT_INTERRUPTED; + } else { + rv = -1; + } + break; + } + nprogr++; + } else if (nprogr == 25) { + nprogr = 0; + } else { + nprogr++; + } + } + } /* next bufferload */ + + return rv; +} +#endif /* USE_ZLIB */ + +/* Push data from a socket down a stream STRIPPING CR +** -------------------------------------------------- +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the socket. +** +** The file number given is assumed to be a TELNET stream ie containing +** CRLF at the end of lines which need to be stripped to LF for unix +** when the format is textual. +** +*/ +PUBLIC void HTCopyNoCR ARGS3( + HTParentAnchor *, anchor GCC_UNUSED, + int, file_number, + HTStream*, sink) +{ + HTStreamClass targetClass; + char character; + + /* Push the data, ignoring CRLF, down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + /* Push text from telnet socket down sink + ** + ** @@@@@ To push strings could be faster? (especially is we + ** cheat and don't ignore CR! :-} + */ + HTInitInput(file_number); + for (;;) { + character = HTGetCharacter(); + if (character == (char)EOF) + break; + (*targetClass.put_character)(sink, character); + } +} + +/* Parse a socket given format and file number +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** The file number given is assumed to be a TELNET stream ie containing +** CRLF at the end of lines which need to be stripped to LF for unix +** when the format is textual. +** +*/ +PUBLIC int HTParseSocket ARGS5( + HTFormat, rep_in, + HTFormat, format_out, + HTParentAnchor *, anchor, + int, file_number, + HTStream*, sink) +{ + HTStream * stream; + HTStreamClass targetClass; + int rv; + + stream = HTStreamStack(rep_in, format_out, sink, anchor); + + if (!stream) { + char buffer[1024]; /* @@@@@@@@ */ + if (LYCancelDownload) { + LYCancelDownload = FALSE; + return -1; + } + sprintf(buffer, "Sorry, can't convert from %s to %s.", + HTAtom_name(rep_in), HTAtom_name(format_out)); + if (TRACE) + fprintf(stderr, "HTFormat: %s\n", buffer); + return HTLoadError(sink, 501, buffer); /* returns -501 */ + } + + /* + ** Push the data, don't worry about CRLF we can strip them later. + */ + targetClass = *(stream->isa); /* Copy pointers to procedures */ + rv = HTCopy(anchor, file_number, NULL, stream); + if (rv != -1 && rv != HT_INTERRUPTED) + (*targetClass._free)(stream); + + return rv; /* full: HT_LOADED; partial: HT_INTERRUPTED; no bytes: -1 */ +} + +/* Parse a file given format and file pointer +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** The file number given is assumed to be a TELNET stream ie containing +** CRLF at the end of lines which need to be stripped to \n for unix +** when the format is textual. +** +*/ +PUBLIC int HTParseFile ARGS5( + HTFormat, rep_in, + HTFormat, format_out, + HTParentAnchor *, anchor, + FILE *, fp, + HTStream*, sink) +{ + HTStream * stream; + HTStreamClass targetClass; + int rv; + + stream = HTStreamStack(rep_in, + format_out, + sink , anchor); + + if (!stream) { + char buffer[1024]; /* @@@@@@@@ */ + if (LYCancelDownload) { + LYCancelDownload = FALSE; + return -1; + } + sprintf(buffer, "Sorry, can't convert from %s to %s.", + HTAtom_name(rep_in), HTAtom_name(format_out)); + if (TRACE) + fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer); + return HTLoadError(sink, 501, buffer); + } + + /* Push the data down the stream + ** + ** @@ Bug: This decision ought to be made based on "encoding" + ** rather than on content-type. @@@ When we handle encoding. + ** The current method smells anyway. + */ + targetClass = *(stream->isa); /* Copy pointers to procedures */ + rv = HTFileCopy(fp, stream); + if (rv == -1 || rv == HT_INTERRUPTED) { + (*targetClass._abort)(stream, NULL); + } else { + (*targetClass._free)(stream); + } + + if (rv == -1) + return HT_NO_DATA; + else if (rv == HT_INTERRUPTED || (rv > 0 && rv != HT_LOADED)) + return HT_PARTIAL_CONTENT; + else + return HT_LOADED; +} + +#ifdef USE_ZLIB +PRIVATE int HTCloseGzFile ARGS1( + gzFile, gzfp) +{ + int gzres; + if (gzfp == NULL) + return 0; + gzres = gzclose(gzfp); + if (TRACE) { + if (gzres == Z_ERRNO) { + perror("gzclose "); + } else if (gzres != Z_OK) { + fprintf(stderr, "gzclose : error number %d\n", gzres); + } + } + return(gzres); +} + +PUBLIC int HTParseGzFile ARGS5( + HTFormat, rep_in, + HTFormat, format_out, + HTParentAnchor *, anchor, + gzFile, gzfp, + HTStream*, sink) +{ + HTStream * stream; + HTStreamClass targetClass; + int rv; + + stream = HTStreamStack(rep_in, + format_out, + sink , anchor); + + if (!stream) { + char buffer[1024]; /* @@@@@@@@ */ + extern char LYCancelDownload; + HTCloseGzFile(gzfp); + if (LYCancelDownload) { + LYCancelDownload = FALSE; + return -1; + } + sprintf(buffer, "Sorry, can't convert from %s to %s.", + HTAtom_name(rep_in), HTAtom_name(format_out)); + if (TRACE) + fprintf(stderr, "HTFormat(in HTParseGzFile): %s\n", buffer); + return HTLoadError(sink, 501, buffer); + } + + /* Push the data down the stream + ** + ** @@ Bug: This decision ought to be made based on "encoding" + ** rather than on content-type. @@@ When we handle encoding. + ** The current method smells anyway. + */ + targetClass = *(stream->isa); /* Copy pointers to procedures */ + rv = HTGzFileCopy(gzfp, stream); + if (rv == -1 || rv == HT_INTERRUPTED) { + (*targetClass._abort)(stream, NULL); + } else { + (*targetClass._free)(stream); + } + + HTCloseGzFile(gzfp); + if (rv == -1) + return HT_NO_DATA; + else if (rv == HT_INTERRUPTED || (rv > 0 && rv != HT_LOADED)) + return HT_PARTIAL_CONTENT; + else + return HT_LOADED; +} +#endif /* USE_ZLIB */ + +/* Converter stream: Network Telnet to internal character text +** ----------------------------------------------------------- +** +** The input is assumed to be in ASCII, with lines delimited +** by (13,10) pairs, These pairs are converted into (CR,LF) +** pairs in the local representation. The (CR,LF) sequence +** when found is changed to a '\n' character, the internal +** C representation of a new line. +*/ + +PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char) +{ + char c = FROMASCII(net_char); + if (me->had_cr) { + if (c == LF) { + me->sink->isa->put_character(me->sink, '\n'); /* Newline */ + me->had_cr = NO; + return; + } else { + me->sink->isa->put_character(me->sink, CR); /* leftover */ + } + } + me->had_cr = (c == CR); + if (!me->had_cr) + me->sink->isa->put_character(me->sink, c); /* normal */ +} + +PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s) +{ + CONST char * p; + + for (p = s; *p; p++) + NetToText_put_character(me, *p); +} + +PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l) +{ + CONST char * p; + + for (p = s; p < (s+l); p++) + NetToText_put_character(me, *p); +} + +PRIVATE void NetToText_free ARGS1(HTStream *, me) +{ + (me->sink->isa->_free)(me->sink); /* Close rest of pipe */ + FREE(me); +} + +PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e) +{ + me->sink->isa->_abort(me->sink,e); /* Abort rest of pipe */ + FREE(me); +} + +/* The class structure +*/ +PRIVATE HTStreamClass NetToTextClass = { + "NetToText", + NetToText_free, + NetToText_abort, + NetToText_put_character, + NetToText_put_string, + NetToText_put_block +}; + +/* The creation method +*/ +PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink) +{ + HTStream* me = (HTStream*)malloc(sizeof(*me)); + + if (me == NULL) + outofmem(__FILE__, "NetToText"); + me->isa = &NetToTextClass; + + me->had_cr = NO; + me->sink = sink; + return me; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.h new file mode 100644 index 00000000000..225456b6eca --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.h @@ -0,0 +1,441 @@ +/* HTFormat: The format manager in the WWW Library + MANAGE DIFFERENT DOCUMENT FORMATS + + Here we describe the functions of the HTFormat module which handles conversion between + different data representations. (In MIME parlance, a representation is known as a + content-type. In WWW the term "format" is often used as it is shorter). + + This module is implemented by HTFormat.c . This hypertext document is used to generate + the HTFormat.h include file. Part of the WWW library . + +Preamble + + */ +#ifndef HTFORMAT_H +#define HTFORMAT_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTStream.h" +#include "HTAtom.h" +#include "HTList.h" + +#ifdef SHORT_NAMES +#define HTOutputSource HTOuSour +#define HTOutputBinary HTOuBina +#endif + +/* + +The HTFormat type + + We use the HTAtom object for holding representations. This allows faster manipulation + (comparison and copying) that if we stayed with strings. + + */ +typedef HTAtom * HTFormat; + +/* + + These macros (which used to be constants) define some basic internally referenced + representations. The www/xxx ones are of course not MIME standard. + + www/source is an output format which leaves the input untouched. It is useful for + diagnostics, and for users who want to see the original, whatever it is. + + */ + /* Internal ones */ +#define WWW_SOURCE HTAtom_for("www/source") /* Whatever it was originally*/ + +/* + + www/present represents the user's perception of the document. If you convert to + www/present, you present the material to the user. + + */ +#define WWW_PRESENT HTAtom_for("www/present") /* The user's perception */ + +/* + + The message/rfc822 format means a MIME message or a plain text message with no MIME + header. This is what is returned by an HTTP server. + + */ +#define WWW_MIME HTAtom_for("www/mime") /* A MIME message */ + +/* + + www/print is like www/present except it represents a printed copy. + + */ +#define WWW_PRINT HTAtom_for("www/print") /* A printed copy */ + +/* + + www/unknown is a really unknown type. Some default action is appropriate. + + */ +#define WWW_UNKNOWN HTAtom_for("www/unknown") + +#ifdef DIRED_SUPPORT +/* + www/dired signals directory edit mode. +*/ +#define WWW_DIRED HTAtom_for("www/dired") +#endif + +/* + + These are regular MIME types. HTML is assumed to be added by the W3 code. + application/octet-stream was mistakenly application/binary in earlier libwww versions + (pre 2.11). + + */ +#define WWW_PLAINTEXT HTAtom_for("text/plain") +#define WWW_POSTSCRIPT HTAtom_for("application/postscript") +#define WWW_RICHTEXT HTAtom_for("application/rtf") +#define WWW_AUDIO HTAtom_for("audio/basic") +#define WWW_HTML HTAtom_for("text/html") +#define WWW_BINARY HTAtom_for("application/octet-stream") + +/* + + We must include the following file after defining HTFormat, to which it makes + reference. + +The HTEncoding type + + */ +typedef HTAtom* HTEncoding; + +/* + + The following are values for the MIME types: + + */ +#define WWW_ENC_7BIT HTAtom_for("7bit") +#define WWW_ENC_8BIT HTAtom_for("8bit") +#define WWW_ENC_BINARY HTAtom_for("binary") + +/* + + We also add + + */ +#define WWW_ENC_COMPRESS HTAtom_for("compress") + +/* + Does a string designate a real encoding, or is it just + a "dummy" as for example 7bit, 8bit, and binary? + */ +#define IsUnityEncStr(senc) \ + ((senc)==NULL || *(senc)=='\0' || !strcmp(senc,"identity") ||\ + !strcmp(senc,"8bit") || !strcmp(senc,"binary") || !strcmp(senc,"7bit")) + +#define IsUnityEnc(enc) \ + ((enc)==NULL || (enc)==HTAtom_for("identity") ||\ + (enc)==WWW_ENC_8BIT || (enc)==WWW_ENC_BINARY || (enc)==WWW_ENC_7BIT) + + +#include "HTAnchor.h" + +/* + +The HTPresentation and HTConverter types + + This HTPresentation structure represents a possible conversion algorithm from one + format to annother. It includes a pointer to a conversion routine. The conversion + routine returns a stream to which data should be fed. See also HTStreamStack which + scans the list of registered converters and calls one. See the initialisation module + for a list of conversion routines. + + */ +typedef struct _HTPresentation HTPresentation; + +typedef HTStream * HTConverter PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + +struct _HTPresentation { + HTAtom * rep; /* representation name atmoized */ + HTAtom * rep_out; /* resulting representation */ + HTConverter * converter; /* The routine to gen the stream stack */ + char * command; /* MIME-format string */ + float quality; /* Between 0 (bad) and 1 (good) */ + float secs; + float secs_per_byte; + long int maxbytes; +}; + +/* + + The list of presentations is kept by this module. It is also scanned by modules which + want to know the set of formats supported. for example. + + */ +extern HTList * HTPresentations; + +/* + + The default presentation is used when no other is appriporate + + */ +extern HTPresentation* default_presentation; + +/* + +HTSetPresentation: Register a system command to present a format + + ON ENTRY, + + rep is the MIME - style format name + + command is the MAILCAP - style command template + + quality A degradation faction 0..1.0 + + secs A limit on the time user will wait (0.0 for infinity) + secs_per_byte + + maxbytes A limit on the length acceptable as input (0 infinite) + + */ +extern void HTSetPresentation PARAMS(( + CONST char * representation, + CONST char * command, + float quality, + float secs, + float secs_per_byte, + long int maxbytes +)); + + +/* + +HTSetConversion: Register a converstion routine + + ON ENTRY, + + rep_in is the content-type input + + rep_out is the resulting content-type + + converter is the routine to make the stream to do it + + */ + +extern void HTSetConversion PARAMS(( + CONST char * rep_in, + CONST char * rep_out, + HTConverter * converter, + float quality, + float secs, + float secs_per_byte, + long int maxbytes +)); + + +/* + +HTStreamStack: Create a stack of streams + + This is the routine which actually sets up the conversion. It currently checks only for + direct conversions, but multi-stage conversions are forseen. It takes a stream into + which the output should be sent in the final format, builds the conversion stack, and + returns a stream into which the data in the input format should be fed. The anchor is + passed because hypertxet objects load information into the anchor object which + represents them. + + */ +extern HTStream * HTStreamStack PARAMS(( + HTFormat format_in, + HTFormat format_out, + HTStream* stream_out, + HTParentAnchor* anchor)); + +/* +HTReorderPresentation: put presentation near head of list + + Look up a presentation (exact match only) and, if found, reorder + it to the start of the HTPresentations list. - kw + */ + +extern void HTReorderPresentation PARAMS(( + HTFormat format_in, + HTFormat format_out)); + +/* + +HTStackValue: Find the cost of a filter stack + + Must return the cost of the same stack which HTStreamStack would set up. + + ON ENTRY, + + format_in The fomat of the data to be converted + + format_out The format required + + initial_value The intrinsic "value" of the data before conversion on a scale + from 0 to 1 + + length The number of bytes expected in the input format + + */ +extern float HTStackValue PARAMS(( + HTFormat format_in, + HTFormat rep_out, + float initial_value, + long int length)); + +#define NO_VALUE_FOUND -1e20 /* returned if none found */ + +/* + +HTCopy: Copy a socket to a stream + + This is used by the protocol engines to send data down a stream, typically one which + has been generated by HTStreamStack. + + */ +extern int HTCopy PARAMS(( + HTParentAnchor * anchor, + int file_number, + void* handle, + HTStream* sink)); + + +/* + +HTFileCopy: Copy a file to a stream + + This is used by the protocol engines to send data down a stream, typically one which + has been generated by HTStreamStack. It is currently called by HTParseFile + + */ +extern int HTFileCopy PARAMS(( + FILE* fp, + HTStream* sink)); + + +/* + +HTCopyNoCR: Copy a socket to a stream, stripping CR characters. + + It is slower than HTCopy . + + */ + +extern void HTCopyNoCR PARAMS(( + HTParentAnchor * anchor, + int file_number, + HTStream* sink)); + + +/* + +Clear input buffer and set file number + + This routine and the one below provide simple character input from sockets. (They are + left over from the older architecure and may not be used very much.) The existence of + a common routine and buffer saves memory space in small implementations. + + */ +extern void HTInitInput PARAMS((int file_number)); + +/* + +Get next character from buffer + + */ +extern int interrupted_in_htgetcharacter; +extern char HTGetCharacter NOPARAMS; + + +/* + +HTParseSocket: Parse a socket given its format + + This routine is called by protocol modules to load an object. uses HTStreamStack and + the copy routines above. Returns HT_LOADED if succesful, <0 if not. + + */ +extern int HTParseSocket PARAMS(( + HTFormat format_in, + HTFormat format_out, + HTParentAnchor *anchor, + int file_number, + HTStream* sink)); + +/* + +HTParseFile: Parse a File through a file pointer + + This routine is called by protocols modules to load an object. uses HTStreamStack and + HTFileCopy . Returns HT_LOADED if succesful, <0 if not. + + */ +extern int HTParseFile PARAMS(( + HTFormat format_in, + HTFormat format_out, + HTParentAnchor *anchor, + FILE *fp, + HTStream* sink)); + +#ifdef USE_ZLIB + +#ifdef USE_ZLIB +#include <zlib.h> +#endif /* USE_ZLIB */ +/* +HTParseGzFile: Parse a gzipped File through a file pointer + + This routine is called by protocols modules to load an object. uses HTStreamStack and + HTGzFileCopy . Returns HT_LOADED if succesful, <0 if not. + */ +extern int HTParseGzFile PARAMS(( + HTFormat format_in, + HTFormat format_out, + HTParentAnchor *anchor, + gzFile gzfp, + HTStream* sink)); + +#endif /* USE_ZLIB */ + +/* + +HTNetToText: Convert Net ASCII to local representation + + This is a filter stream suitable for taking text from a socket and passing it into a + stream which expects text in the local C representation. It does ASCII and newline + conversion. As usual, pass its output stream to it when creating it. + + */ +extern HTStream * HTNetToText PARAMS ((HTStream * sink)); + +/* + +HTFormatInit: Set up default presentations and conversions + + These are defined in HTInit.c or HTSInit.c if these have been replaced. If you don't + call this routine, and you don't define any presentations, then this routine will + automatically be called the first time a conversion is needed. However, if you + explicitly add some conversions (eg using HTLoadRules) then you may want also to + explicitly call this to get the defaults as well. + + */ +extern void HTFormatInit NOPARAMS; + +/* + +Epilogue + + */ +extern BOOL HTOutputSource; /* Flag: shortcut parser */ +#endif + +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.c new file mode 100644 index 00000000000..23e8f9d07b7 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.c @@ -0,0 +1,2004 @@ +/* GOPHER ACCESS HTGopher.c +** ============= +** +** History: +** 26 Sep 90 Adapted from other accesses (News, HTTP) TBL +** 29 Nov 91 Downgraded to C, for portable implementation. +** 10 Mar 96 Foteos Macrides (macrides@sci.wfbr.edu). Added a +** form-based CSO/PH gateway. Can be invoked via a +** "cso://host[:port]/" or "gopher://host:105/2" +** URL. If a gopher URL is used with a query token +** ('?'), the old ISINDEX procedure will be used +** instead of the form-based gateway. +** 15 Mar 96 Foteos Macrides (macrides@sci.wfbr.edu). Pass +** port 79, gtype 0 gopher URLs to the finger +** gateway. +*/ + +#include "HTUtils.h" /* Coding convention macros */ +#include "tcp.h" +#include "HTAlert.h" +#include "HTParse.h" +#include "HTTCP.h" +#include "HTFinger.h" + +/* +** Implements. +*/ +#include "HTGopher.h" + +#define HT_EM_SPACE ((char)2) /* For now */ + +#define GOPHER_PORT 70 /* See protocol spec */ +#define CSO_PORT 105 /* See protocol spec */ +#define BIG 1024 /* Bug */ +#define LINE_LENGTH 256 /* Bug */ + +/* +** Gopher entity types. +*/ +#define GOPHER_TEXT '0' +#define GOPHER_MENU '1' +#define GOPHER_CSO '2' +#define GOPHER_ERROR '3' +#define GOPHER_MACBINHEX '4' +#define GOPHER_PCBINARY '5' +#define GOPHER_UUENCODED '6' +#define GOPHER_INDEX '7' +#define GOPHER_TELNET '8' +#define GOPHER_BINARY '9' +#define GOPHER_GIF 'g' +#define GOPHER_HTML 'h' /* HTML */ +#define GOPHER_CHTML 'H' /* HTML */ +#define GOPHER_SOUND 's' +#define GOPHER_WWW 'w' /* W3 address */ +#define GOPHER_IMAGE 'I' +#define GOPHER_TN3270 'T' +#define GOPHER_INFO 'i' +#define GOPHER_DUPLICATE '+' +#define GOPHER_PLUS_IMAGE ':' /* Addition from Gopher Plus */ +#define GOPHER_PLUS_MOVIE ';' +#define GOPHER_PLUS_SOUND '<' +#define GOPHER_PLUS_PDF 'P' + +#include <ctype.h> + +#include "HTParse.h" +#include "HTFormat.h" +#include "HTTCP.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* +** Hypertext object building machinery. +*/ +#include "HTML.h" + +#include "LYLeaks.h" + +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET (*targetClass._free)(target) + +#define GOPHER_PROGRESS(foo) HTAlert(foo) + +#define NEXT_CHAR HTGetCharacter() + +/* +** Module-wide variables. +*/ +PRIVATE int s; /* Socket for gopher or CSO host */ + +struct _HTStructured { + CONST HTStructuredClass * isa; /* For gopher streams */ + /* ... */ +}; + +PRIVATE HTStructured *target; /* the new gopher hypertext */ +PRIVATE HTStructuredClass targetClass; /* Its action routines */ + +struct _HTStream +{ + HTStreamClass * isa; /* For form-based CSO gateway - FM */ +}; + +typedef struct _CSOfield_info { /* For form-based CSO gateway - FM */ + struct _CSOfield_info * next; + char * name; + char * attributes; + char * description; + int id; + int lookup; + int indexed; + int url; + int max_size; + int defreturn; + int explicit_return; + int reserved; + int public; + char name_buf[16]; /* Avoid malloc if we can */ + char desc_buf[32]; /* Avoid malloc if we can */ + char attr_buf[80]; /* Avoid malloc if we can */ +} CSOfield_info; + +PRIVATE CSOfield_info *CSOfields = NULL; /* For form-based CSO gateway - FM */ + +typedef struct _CSOformgen_context { /* For form-based CSO gateway - FM */ + char * host; + char * seek; + CSOfield_info * fld; + int port; + int cur_line; + int cur_off; + int rep_line; + int rep_off; + int public_override; + int field_select; +} CSOformgen_context; + +/* Matrix of allowed characters in filenames +** ========================================= +*/ +PRIVATE BOOL acceptable[256]; +PRIVATE BOOL acceptable_inited = NO; + +PRIVATE void init_acceptable NOARGS +{ + unsigned int i; + char * good = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$"; + for(i = 0; i < 256; i++) + acceptable[i] = NO; + for(; *good; good++) + acceptable[(unsigned int)*good] = YES; + acceptable_inited = YES; +} + +/* Decode one hex character +** ======================== +*/ +PRIVATE CONST char hex[17] = "0123456789abcdef"; + +PRIVATE char from_hex ARGS1(char, c) +{ + return (c>='0')&&(c<='9') ? c-'0' + : (c>='A')&&(c<='F') ? c-'A'+10 + : (c>='a')&&(c<='f') ? c-'a'+10 + : 0; +} + +/* Paste in an Anchor +** ================== +** +** The title of the destination is set, as there is no way +** of knowing what the title is when we arrive. +** +** On entry, +** HT is in append mode. +** text points to the text to be put into the file, 0 terminated. +** addr points to the hypertext refernce address 0 terminated. +*/ +PUBLIC BOOLEAN HT_Is_Gopher_URL=FALSE; + +PRIVATE void write_anchor ARGS2(CONST char *,text, CONST char *,addr) +{ + BOOL present[HTML_A_ATTRIBUTES]; + CONST char * value[HTML_A_ATTRIBUTES]; + + int i; + + for (i = 0; i < HTML_A_ATTRIBUTES; i++) + present[i] = 0; + present[HTML_A_HREF] = YES; + ((CONST char **)value)[HTML_A_HREF] = addr; + present[HTML_A_TITLE] = YES; + ((CONST char **)value)[HTML_A_TITLE] = text; + + if(TRACE) + fprintf(stderr,"HTGopher: adding URL: %s\n",addr); + + HT_Is_Gopher_URL = TRUE; /* tell HTML.c that this is a Gopher URL */ + (*targetClass.start_element)(target, HTML_A, present, + (CONST char **)value, -1, 0); + + PUTS(text); + END(HTML_A); +} + +/* Parse a Gopher Menu document +** ============================ +*/ +PRIVATE void parse_menu ARGS2( + CONST char *, arg GCC_UNUSED, + HTParentAnchor *, anAnchor) +{ + char gtype; + char ch; + char line[BIG]; + char address[BIG]; + char *name = NULL, *selector = NULL; /* Gopher menu fields */ + char *host = NULL; + char *port; + char *p = line; + CONST char *title; + int bytes = 0; + int BytesReported = 0; + char buffer[128]; + +#define TAB '\t' +#define HEX_ESCAPE '%' + + + START(HTML_HTML); + PUTS("\n"); + START(HTML_HEAD); + PUTS("\n"); + START(HTML_TITLE); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else + PUTS("Gopher Menu"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + + START(HTML_BODY); + PUTS("\n"); + START(HTML_H1); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else + PUTS("Gopher Menu"); + END(HTML_H1); + PUTS("\n"); + START(HTML_PRE); + while ((ch=NEXT_CHAR) != (char)EOF) { + + if (interrupted_in_htgetcharacter) { + if (TRACE) + fprintf(stderr, + "HTGopher: Interrupted in HTGetCharacter, apparently.\n"); + goto end_html; + } + + if (ch != LF) { + *p = ch; /* Put character in line */ + if (p< &line[BIG-1]) p++; + + } else { + *p++ = '\0'; /* Terminate line */ + bytes += p-line; /* add size */ + p = line; /* Scan it to parse it */ + port = 0; /* Flag "not parsed" */ + if (TRACE) + fprintf(stderr, "HTGopher: Menu item: %s\n", line); + gtype = *p++; + + if (bytes > BytesReported + 1024) { + sprintf(buffer, "Transferred %d bytes", bytes); + HTProgress(buffer); + BytesReported = bytes; + } + + /* Break on line with a dot by itself */ + if ((gtype=='.') && ((*p=='\r') || (*p==0))) + break; + + if (gtype && *p) { + name = p; + selector = strchr(name, TAB); + if (selector) { + *selector++ = '\0'; /* Terminate name */ + /* + * Gopher+ Type=0+ objects can be binary, and will + * have 9 or 5 beginning their selector. Make sure + * we don't trash the terminal by treating them as + * text. - FM + */ + if (gtype == GOPHER_TEXT && (*selector == GOPHER_BINARY || + *selector == GOPHER_PCBINARY)) + gtype = *selector; + host = strchr(selector, TAB); + if (host) { + *host++ = '\0'; /* Terminate selector */ + port = strchr(host, TAB); + if (port) { + char *junk; + port[0] = ':'; /* delimit host a la W3 */ + junk = strchr(port, TAB); + if (junk) *junk++ = '\0'; /* Chop port */ + if ((port[1]=='0') && (!port[2])) + port[0] = '\0'; /* 0 means none */ + } /* no port */ + } /* host ok */ + } /* selector ok */ + } /* gtype and name ok */ + + /* Nameless files are a separator line */ + if (gtype == GOPHER_TEXT) { + int i = strlen(name)-1; + while (name[i] == ' ' && i >= 0) + name[i--] = '\0'; + if (i < 0) + gtype = GOPHER_INFO; + } + + if (gtype == GOPHER_WWW) { /* Gopher pointer to W3 */ + PUTS("(HTML) "); + write_anchor(name, selector); + + } else if (gtype == GOPHER_INFO) { + /* Information or separator line */ + PUTS(" "); + PUTS(name); + + } else if (port) { /* Other types need port */ + if (gtype == GOPHER_TELNET) { + PUTS(" (TEL) "); + if (*selector) sprintf(address, "telnet://%s@%s/", + selector, host); + else sprintf(address, "telnet://%s/", host); + } + else if (gtype == GOPHER_TN3270) + { + PUTS("(3270) "); + if (*selector) + sprintf(address, "tn3270://%s@%s/", + selector, host); + else + sprintf(address, "tn3270://%s/", host); + } + else { /* If parsed ok */ + char *q; + char *r; + + switch(gtype) { + case GOPHER_TEXT: + PUTS("(FILE) "); + break; + case GOPHER_MENU: + PUTS(" (DIR) "); + break; + case GOPHER_CSO: + PUTS(" (CSO) "); + break; + case GOPHER_PCBINARY: + PUTS(" (BIN) "); + break; + case GOPHER_UUENCODED: + PUTS(" (UUE) "); + break; + case GOPHER_INDEX: + PUTS(" (?) "); + break; + case GOPHER_BINARY: + PUTS(" (BIN) "); + break; + case GOPHER_GIF: + case GOPHER_IMAGE: + case GOPHER_PLUS_IMAGE: + PUTS(" (IMG) "); + break; + case GOPHER_SOUND: + case GOPHER_PLUS_SOUND: + PUTS(" (SND) "); + break; + case GOPHER_MACBINHEX: + PUTS(" (HQX) "); + break; + case GOPHER_HTML: + case GOPHER_CHTML: + PUTS("(HTML) "); + break; + case 'm': + PUTS("(MIME) "); + break; + case GOPHER_PLUS_MOVIE: + PUTS(" (MOV) "); + break; + case GOPHER_PLUS_PDF: + PUTS(" (PDF) "); + break; + default: + PUTS("(UNKN) "); + break; + } + + sprintf(address, "//%s/%c", host, gtype); + + q = address+ strlen(address); + for(r=selector; *r; r++) { /* Encode selector string */ + if (acceptable[(unsigned char)*r]) *q++ = *r; + else { + *q++ = HEX_ESCAPE; /* Means hex coming */ + *q++ = hex[(TOASCII(*r)) >> 4]; + *q++ = hex[(TOASCII(*r)) & 15]; + } + } + + *q++ = '\0'; /* terminate address */ + } + /* Error response from Gopher doesn't deserve to + be a hyperlink. */ + if (strcmp (address, "gopher://error.host:1/0")) + write_anchor(name, address); + else + PUTS(name); + } else { /* parse error */ + if (TRACE) + fprintf(stderr, "HTGopher: Bad menu item.\n"); + PUTS(line); + + } /* parse error */ + + PUTS("\n"); + p = line; /* Start again at beginning of line */ + + } /* if end of line */ + + } /* Loop over characters */ + +end_html: + END(HTML_PRE); + PUTS("\n"); + END(HTML_BODY); + PUTS("\n"); + END(HTML_HTML); + PUTS("\n"); + FREE_TARGET; + + return; +} + +/* Parse a Gopher CSO document from an ISINDEX query. +** ================================================== +** +** Accepts an open socket to a CSO server waiting to send us +** data and puts it on the screen in a reasonable manner. +** +** Perhaps this data can be automatically linked to some +** other source as well??? +** +** Taken from hacking by Lou Montulli@ukanaix.cc.ukans.edu +** on XMosaic-1.1, and put on libwww 2.11 by Arthur Secret, +** secret@dxcern.cern.ch . +*/ +PRIVATE void parse_cso ARGS2( + CONST char *, arg, + HTParentAnchor *, anAnchor) +{ + char ch; + char line[BIG]; + char *p = line; + char *second_colon, last_char='\0'; + CONST char *title; + + START(HTML_HEAD); + PUTS("\n"); + START(HTML_TITLE); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else + PUTS("CSO Search Results"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + START(HTML_H1); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else { + PUTS(arg); + PUTS(" Search Results"); + } + END(HTML_H1); + PUTS("\n"); + START(HTML_PRE); + + /* + ** Start grabbing chars from the network. + */ + while ((ch=NEXT_CHAR) != (char)EOF) + { + if (ch != LF) + { + *p = ch; /* Put character in line */ + if (p< &line[BIG-1]) p++; + } + else + { + *p = '\0'; /* Terminate line */ + p = line; /* Scan it to parse it */ + /* + ** OK we now have a line in 'p'. + ** Lets parse it and print it. + */ + + /* + ** Break on line that begins with a 2. + ** It's the end of data. + */ + if (*p == '2') + break; + + /* + ** Lines beginning with 5 are errors. + ** Print them and quit. + */ + if (*p == '5') { + START(HTML_H2); + PUTS(p+4); + END(HTML_H2); + break; + } + + if (*p == '-') { + /* + ** Data lines look like -200:#: + ** where # is the search result number and can be + ** multiple digits (infinite?). + ** Find the second colon and check the digit to the + ** left of it to see if they are diferent. + ** If they are then a different person is starting. + ** Make this line an <h2>. + */ + + /* + ** Find the second_colon. + */ + second_colon = strchr( strchr(p,':')+1, ':'); + + if(second_colon != NULL) { /* error check */ + + if (*(second_colon-1) != last_char) + /* print seperator */ + { + END(HTML_PRE); + START(HTML_H2); + } + + + /* + ** Right now the record appears with the alias + ** (first line) as the header and the rest as + ** <pre> text. + ** It might look better with the name as the + ** header and the rest as a <ul> with <li> tags. + ** I'm not sure whether the name field comes in + ** any special order or if its even required in + ** a record, so for now the first line is the + ** header no matter what it is (it's almost + ** always the alias). + ** A <dl> with the first line as the <DT> and + ** the rest as some form of <DD> might good also? + */ + + /* + ** Print data. + */ + PUTS(second_colon+1); + PUTS("\n"); + + if (*(second_colon-1) != last_char) + /* end seperator */ + { + END(HTML_H2); + START(HTML_PRE); + } + + /* + ** Save the char before the second colon + ** for comparison on the next pass. + */ + last_char = *(second_colon-1) ; + + } /* end if second_colon */ + } /* end if *p == '-' */ + } /* if end of line */ + + } /* Loop over characters */ + + /* end the text block */ + PUTS("\n"); + END(HTML_PRE); + PUTS("\n"); + FREE_TARGET; + + return; /* all done */ +} /* end of procedure */ + +/* Display a Gopher CSO ISINDEX cover page. +** ======================================== +*/ +PRIVATE void display_cso ARGS2( + CONST char *, arg, + HTParentAnchor *, anAnchor) +{ + CONST char * title; + + START(HTML_HEAD); + PUTS("\n"); + START(HTML_TITLE); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else + PUTS("CSO index"); + END(HTML_TITLE); + PUTS("\n"); + START(HTML_ISINDEX); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + START(HTML_H1); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else { + PUTS(arg); + PUTS(" index"); + } + END(HTML_H1); + PUTS("\nThis is a searchable index of a CSO database.\n"); + START(HTML_P); + PUTS("\nPress the 's' key and enter search keywords.\n"); + START(HTML_P); + PUTS("\nThe keywords that you enter will allow you to search on a"); + PUTS(" person's name in the database.\n"); + + if (!HTAnchor_title(anAnchor)) + HTAnchor_setTitle(anAnchor, arg); + + FREE_TARGET; + return; +} + +/* Display a Gopher Index document. +** ================================ +*/ +PRIVATE void display_index ARGS2( + CONST char *, arg, + HTParentAnchor *,anAnchor) +{ + CONST char * title; + + START(HTML_HEAD); + PUTS("\n"); + PUTS("\n"); + START(HTML_TITLE); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else + PUTS("Gopher index"); + END(HTML_TITLE); + PUTS("\n"); + START(HTML_ISINDEX); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + START(HTML_H1); + if ((title = HTAnchor_title(anAnchor))) + PUTS(title); + else { + PUTS(arg); + PUTS(" index"); + } + END(HTML_H1); + PUTS("\nThis is a searchable Gopher index.\n"); + START(HTML_P); + PUTS("\nPlease enter search keywords.\n"); + + if (!HTAnchor_title(anAnchor)) + HTAnchor_setTitle(anAnchor, arg); + + FREE_TARGET; + return; +} + +/* De-escape a selector into a command. +** ==================================== +** +** The % hex escapes are converted. Otheriwse, the string is copied. +*/ +PRIVATE void de_escape ARGS2(char *, command, CONST char *, selector) +{ + CONST char * p = selector; + char * q = command; + if (command == NULL) + outofmem(__FILE__, "HTLoadGopher"); + while (*p) { /* Decode hex */ + if (*p == HEX_ESCAPE) { + char c; + unsigned int b; + p++; + c = *p++; + b = from_hex(c); + c = *p++; + if (!c) break; /* Odd number of chars! */ + *q++ = FROMASCII((b<<4) + from_hex(c)); + } else { + *q++ = *p++; /* Record */ + } + } + *q++ = '\0'; /* Terminate command */ +} + + +/* Free the CSOfields structures. - FM +** =================================== +*/ +PRIVATE void free_CSOfields NOPARAMS +{ + CSOfield_info *cur = CSOfields; + CSOfield_info *prev; + + while (cur) { + if (cur->name != cur->name_buf) + FREE(cur->name); + if (cur->attributes != cur->attr_buf) + FREE(cur->attributes); + if (cur->description != cur->desc_buf) + FREE(cur->description); + prev = cur; + cur = cur->next; + FREE(prev); + } + + return; +} + +/* Interpret CSO/PH form template keys. - FM +** ========================================= +*/ +PRIVATE int interpret_cso_key ARGS5( + char *, key, + char *, buf, + int *, length, + CSOformgen_context *, ctx, + HTStream *, Target) +{ + CSOfield_info *fld; + + if ((fld = ctx->fld) != 0) { + /* + ** Most substitutions only recognized inside of loops. + */ + int error = 0; + if (0 == strncmp(key, "$(FID)", 6)) { + sprintf(buf, "%d", fld->id); + } else if (0 == strncmp(key, "$(FDESC)", 8)) { + sprintf(buf, "%s%s%s", fld->description, + ctx->public_override ? /***" "***/"" : "", + ctx->public_override ? /***fld->attributes***/"" : ""); + } else if (0 == strncmp(key, "$(FDEF)", 7)) { + strcpy(buf, fld->defreturn ? " checked" : ""); + } else if (0 == strncmp(key, "$(FNDX)", 7)) { + strcpy(buf, fld->indexed ? "*" : ""); + } else if (0 == strncmp(key, "$(FSIZE)", 8)) { + sprintf(buf, " size=%d maxlength=%d", + fld->max_size > 55 ? 55 : fld->max_size, + fld->max_size); + } else if (0 == strncmp(key, "$(FSIZE2)", 9)) { + sprintf(buf, " maxlength=%d", fld->max_size); + } else { + error = 1; + } + if (!error) { + *length = strlen(buf); + return -1; + } + } + buf[0] = '\0'; + if (0 == strncmp(key, "$(NEXTFLD)", 10)) { + if (!ctx->fld) + fld = CSOfields; + else + fld = ctx->fld->next; + switch (ctx->field_select) { + case 0: + /* + ** 'Query' fields, public and lookup attributes. + */ + for (; fld; fld = fld->next) + if (fld->public && (fld->lookup==1)) + break; + break; + case 1: + /* + ** 'Query' fields, accept lookup attribute. + */ + for (; fld; fld = fld->next) + if (fld->lookup == 1) + break; + break; + case 2: + /* + ** 'Return' fields, public only. + */ + for (; fld; fld = fld->next) + if (fld->public) + break; + break; + case 3: + /* + ** All fields. + */ + break; + } + if (fld) { + ctx->cur_line = ctx->rep_line; + ctx->cur_off = ctx->rep_off; + } + ctx->fld = fld; + + } else if ((0 == strncmp(key, "$(QFIELDS)", 10)) || + (0 == strncmp(key, "$(RFIELDS)", 10))) { + /* + ** Begin iteration sequence. + */ + ctx->rep_line = ctx->cur_line; + ctx->rep_off = ctx->cur_off; + ctx->fld = (CSOfield_info *) 0; + ctx->seek = "$(NEXTFLD)"; + ctx->field_select = (key[2] == 'Q') ? 0 : 2; + if (ctx->public_override) + ctx->field_select++; + + } else if (0 == strncmp(key, "$(NAMEFLD)", 10)) { + /* + ** Special, locate name field. Flag lookup so QFIELDS will skip it. + */ + for (fld = CSOfields; fld; fld = fld->next) + if (strcmp(fld->name, "name") == 0 || + strcmp(fld->name, "Name") == 0) { + if (fld->lookup) + fld->lookup = 2; + break; + } + ctx->fld = fld; + } else if (0 == strncmp (key, "$(HOST)", 7)) { + strcpy (buf, ctx->host); + } else if (0 == strncmp (key, "$(PORT)", 7)) { + sprintf(buf, "%d", ctx->port); + } else { + /* + ** No match, dump key to buffer so client sees it for debugging. + */ + size_t out = 0; + while (*key && (*key != ')')) { + buf[out++] = (*key++); + if (out > sizeof(buf)-2) { + buf[out] = '\0'; + (*Target->isa->put_block)(Target, buf, strlen(buf)); + out = 0; + } + } + buf[out++] = ')'; + buf[out] = '\0'; + *length = strlen(buf); + return -1; + } + *length = strlen(buf); + return 0; +} + +/* Parse the elements in a CSO/PH fields structure. - FM +** ===================================================== +*/ +PRIVATE int parse_cso_field_info ARGS1( + CSOfield_info *, blk) +{ + int i; + char *info, *max_spec; + + /* + ** Initialize all fields to default values. + */ + blk->indexed = blk->lookup = blk->reserved = blk->max_size = blk->url = 0; + blk->defreturn = blk->explicit_return = blk->public = 0; + + /* + ** Search for keywords in info string and set values. Attributes + ** are converted to all lower-case for comparison. + */ + info = blk->attributes; + for (i = 0; info[i]; i++) + info[i] = TOLOWER(info[i]); + if (strstr(info, "indexed ")) + blk->indexed = 1; + if (strstr(info, "default ")) + blk->defreturn = 1; + if (strstr(info, "public ")) + blk->public = 1; + if (strstr(info, "lookup ")) + blk->lookup = 1; + if (strstr(info, "url ")) { + blk->url = 1; + blk->defreturn = 1; + } + max_spec = strstr(info, "max "); + if (max_spec) { + sscanf(&max_spec[4], "%d", &blk->max_size); + } else { + blk->max_size = 32; + } + + return 0; +} + +/* Parse a reply from a CSO/PH fields request. - FM +** ================================================ +*/ +PRIVATE int parse_cso_fields ARGS2( + char *, buf, + int, size) +{ + char ch; + char *p = buf; + int i, code = 0, prev_code; + size_t alen; + char *indx, *name; + CSOfield_info *last, *new; + + last = CSOfields = (CSOfield_info *) 0; + prev_code = -2555; + buf[0] = '\0'; + + /* + ** Start grabbing chars from the network. + */ + while ((ch = NEXT_CHAR) != (char)EOF) { + if (interrupted_in_htgetcharacter) { + if (TRACE) { + fprintf(stderr, + "HTLoadCSO: Interrupted in HTGetCharacter, apparently.\n"); + } + free_CSOfields(); + buf[0] = '\0'; + return HT_INTERRUPTED; + } + + if (ch != LF) { + *p = ch; /* Put character in buffer */ + if (p < &buf[size-1]) { + p++; + } + } else { + *p = '\0'; /* Terminate line */ + p = buf; /* Scan it to parse it */ + + /* OK we now have a line in 'p' lets parse it. + */ + + /* + ** Break on line that begins with a 2. + ** It's the end of data. + */ + if (*p == '2') + break; + + /* + ** Lines beginning with 5 are errors. + ** Print them and quit. + */ + if (*p == '5') { + strcpy (buf, p); + return 5; + } + + if (*p == '-') { + /* + ** Data lines look like -200:#: + ** where # is the search result number and can be + ** multiple digits (infinite?). + */ + + /* + ** Check status, ignore any non-success. + */ + if (p[1] != '2' ) + continue; + + /* + ** Parse fields within returned line into status, ndx, name, data. + */ + indx = NULL; + name = NULL; + for (i = 0; p[i]; i++) + if (p[i] == ':' ) { + p[i] = '\0'; + if (!indx) { + indx = (char *)&p[i+1]; + code = atoi (indx); + } else if (!name) { + name = (char *)&p[i+1]; + } else { + i++; + break; + } + } + /* + ** Add data to field structure. + */ + if (name) { + if (code == prev_code) { + /* + ** Remaining data are description. + ** Save in current info block. + */ + alen = strlen((char *)&p[i]) + 1; + if (alen > sizeof(last->desc_buf)) { + if (last->description != last->desc_buf) + FREE(last->description); + if (!(last->description = (char *)malloc(alen))) { + outofmem(__FILE__, "HTLoadCSO"); + } + } + strcpy(last->description, (char *)&p[i]); + } else { + /* + ** Initialize new block, append to end of list + ** to preserve order. + */ + new = (CSOfield_info *)calloc(1, sizeof(CSOfield_info)); + if (!new) { + outofmem(__FILE__, "HTLoadCSO"); + } + if (last) + last->next = new; + else + CSOfields = new; + last = new; + + new->next = (CSOfield_info *) 0; + new->name = new->name_buf; + alen = strlen(name) + 1; + if (alen > sizeof(new->name_buf)) { + if (!(new->name = (char *)malloc(alen))) { + outofmem(__FILE__, "HTLoadCSO"); + } + } + strcpy (new->name, name); + + new->attributes = new->attr_buf; + alen = strlen((char *)&p[i]) + 2; + if (alen > sizeof(new->attr_buf)) { + if (!(new->attributes = (char *)malloc(alen))) { + outofmem(__FILE__, "HTLoadCSO"); + } + } + strcpy(new->attributes, (char *)&p[i]); + strcpy((char *)&new->attributes[alen-2], " "); + new->description = new->desc_buf; + new->desc_buf[0] = '\0'; + new->id = atoi(indx); + /* + ** Scan for keywords. + */ + parse_cso_field_info(new); + } + prev_code = code; + } else + break; + } /* end if *p == '-' */ + } /* if end of line */ + + } /* Loop over characters */ + + /* end the text block */ + + if (buf[0] == '\0') { + return -1; /* no response */ + } + buf[0] = '\0'; + return 0; /* all done */ +} /* end of procedure */ + +/* Generate a form for submitting CSO/PH searches. - FM +** ==================================================== +*/ +PRIVATE int generate_cso_form ARGS4( + char *, host, + int, port, + char *, buf, + HTStream *, Target) +{ + int i, j, length; + size_t out; + int full_flag = 1; + char *key, *line; + CSOformgen_context ctx; + static char *template[] = { + "<HEAD>\n<TITLE>CSO/PH Query Form for $(HOST)</TITLE>\n</HEAD>\n<BODY>", + "<H2><I>CSO/PH Query Form</I> for <EM>$(HOST)</EM></H2>", + "To search the database for a name, fill in one or more of the fields", + "in the form below and activate the 'Submit query' button. At least", + "one of the entered fields must be flagged as indexed.", + "<HR><FORM method=\"POST\" action=\"cso://$(HOST)/\">", + "[ <input type=\"submit\" value=\"Submit query\"> | ", + "<input type=\"reset\" value=\"Clear fields\"> ]", + "<P><DL>", + " <DT>Search parameters (* indicates indexed field):", + " <DD>", "$(NAMEFLD) <DL COMPACT>\n <DT><I>$(FDESC)</I>$(FNDX)", + " <DD>Last: <input name=\"q_$(FID)\" type=\"text\" size=49$(FSIZE2)>", + " <DD>First: <input name=\"q_$(FID)\" type=\"text\" size=48$(FSIZE2)>", + "$(QFIELDS) <DT><I>$(FDESC)</I>$(FNDX)", + " <DD><input name=\"q_$(FID)\" type=\"text\" $(FSIZE)>\n$(NEXTFLD)", + " </DL>", + " </DL>\n<P><DL>", + " <DT>Output format:", + " <DD>Returned data option: <select name=\"return\">", + " <option>default<option selected>all<option>selected</select><BR>", + "$(RFIELDS) <input type=\"checkbox\" name=\"r_$(FID)\"$(FDEF)> $(FDESC)<BR>", + "$(NEXTFLD) ", + " </DL></FORM><HR>\n</BODY>\n</HTML>", + (char *) 0 + }; + + out = 0; + ctx.host = host; + ctx.seek = (char *) 0; + ctx.port = port; + ctx.fld = (CSOfield_info *) 0; + ctx.public_override = full_flag; + /* + ** Parse the strings in the template array to produce HTML document + ** to send to client. First line is skipped for 'full' lists. + */ + out = 0; + buf[out] = '\0'; + for (i = full_flag ? /***1***/ 0 : 0; template[i]; i++) { + /* + ** Search the current string for substitution, flagged by $( + */ + for (line=template[i], j = 0; line[j]; j++) { + if ((line[j] == '$') && (line[j+1] == '(')) { + /* + ** Command detected, flush output buffer and find closing ')' + ** that delimits the command. + */ + buf[out] = '\0'; + if (out > 0) + (*Target->isa->put_block)(Target, buf, strlen(buf)); + out = 0; + for (key = &line[j]; line[j+1] && (line[j] != ')'); j++) + ; + /* + ** Save context, interpet command and restore updated context. + */ + ctx.cur_line = i; + ctx.cur_off = j; + interpret_cso_key(key, buf, &length, &ctx, Target); + i = ctx.cur_line; + j = ctx.cur_off; + line = template[i]; + out = length; + + if (ctx.seek) { + /* + ** Command wants us to skip (forward) to indicated token. + ** Start at current position. + */ + int slen = strlen(ctx.seek); + for (; template[i]; i++) { + for (line = template[i]; line[j]; j++) { + if (line[j] == '$') + if (0 == strncmp(ctx.seek, &line[j], slen)) { + if (j == 0) + j = strlen(template[--i])-1; + else + --j; + line = template[i]; + ctx.seek = (char *) 0; + break; + } + } + if (!ctx.seek) + break; + j = 0; + } + if (ctx.seek) { + char *temp = (char *)malloc(strlen(ctx.seek) + 20); + if (temp) { + outofmem(__FILE__, "HTLoadCSO"); + } + sprintf(temp, "Seek fail on %s\n", ctx.seek); + (*Target->isa->put_block)(Target, temp, strlen(temp)); + FREE(temp); + } + } + } else { + /* + ** Non-command text, add to output buffer. + */ + buf[out++] = line[j]; + if (out > (sizeof(buf)-3)) { + buf[out] = '\0'; + (*Target->isa->put_block)(Target, buf, strlen(buf)); + out = 0; + } + } + } + buf[out++] = '\n'; + buf[out] = '\0'; + } + if (out > 0) + (*Target->isa->put_block)(Target, buf, strlen(buf)); + + return 0; +} + +/* Generate a results report for CSO/PH form-based searches. - FM +** ============================================================== +*/ +PRIVATE int generate_cso_report ARGS2( + char *, buf, + HTStream *, Target) +{ + char ch; + char line[BIG]; + char *p = line, *href = NULL; + int len, i, prev_ndx, ndx; + char *rcode, *ndx_str, *fname, *fvalue, *l; + CSOfield_info *fld; + BOOL stop = FALSE; + + /* + ** Read lines until non-negative status. + */ + prev_ndx = -100; + /* + ** Start grabbing chars from the network. + */ + while (!stop && (ch = NEXT_CHAR) != (char)EOF) { + if (interrupted_in_htgetcharacter) { + buf[0] = '\0'; + if (TRACE) { + fprintf(stderr, + "HTLoadCSO: Interrupted in HTGetCharacter, apparently.\n"); + } + _HTProgress ("Connection interrupted."); + goto end_CSOreport; + } + + if (ch != LF) { + *p = ch; /* Put character in line */ + if (p < &line[BIG-1]) { + p++; + } + } else { + *p = '\0'; /* Terminate line */ + /* + ** OK we now have a line. + ** Load it as 'p' and parse it. + */ + p = line; + if (p[0] != '-' && p[0] != '1') { + stop = TRUE; + } + rcode = (p[0] == '-') ? &p[1] : p; + ndx_str = fname = NULL; + len = strlen(p); + for (i = 0; i < len; i++) { + if (p[i] == ':') { + p[i] = '\0'; + if (!ndx_str) { + fname = ndx_str = &p[i+1]; + } else { + fname = &p[i+1]; + break; + } + } + } + if (ndx_str) { + ndx = atoi(ndx_str); + if (prev_ndx != ndx) { + if (prev_ndx != -100) { + strcpy(buf, "</DL></DL>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + if (ndx == 0) { + strcpy(buf, + "<HR><DL><DT>Information/status<DD><DL><DT>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } else { + sprintf(buf, + "<HR><DL><DT>Entry %d:<DD><DL COMPACT><DT>\n", ndx); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + prev_ndx = ndx; + } + } else { + sprintf(buf, "<DD>%s\n", rcode); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + continue; + } + if ((*rcode >= '2') && (*rcode <= '5') && (fname != ndx_str)) { + while (*fname == ' ') { + fname++; /* trim leading spaces */ + } + for (fvalue = fname; *fvalue; fvalue++) { + if (*fvalue == ':') { + *fvalue++ = '\0'; + i = strlen(fname) - 1; + while (i >= 0 && fname[i] == ' ') { + fname[i--] = '\0'; /* trim trailing */ + } + break; + } + } + if (fvalue) { + while (*fvalue == ' ') { + fvalue++; /* trim leading spaces */ + } + } + if (*fname) { + for (fld = CSOfields; fld; fld = fld->next) { + if (!strcmp(fld->name, fname)) { + if (fld->description) { + fname = fld->description; + } + break; + } + } + if (fld && fld->url) { + sprintf(buf, + "<DT><I>%s</I><DD><A HREF=\"%s\">%s</A>\n", + fname, fvalue, fvalue); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } else { + sprintf(buf, "<DT><I>%s</I><DD>", fname); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + i = 0; + buf[i] = '\0'; + l = fvalue; + while (*l) { + if (*l == '<') { + strcat(buf, "<"); + l++; + i += 4; + buf[i] = '\0'; + } else if (*l == '>') { + strcat(buf, ">"); + l++; + i += 4; + buf[i] = '\0'; + } else if (strncmp(l, "news:", 5) && + strncmp(l, "snews://", 8) && + strncmp(l, "nntp://", 7) && + strncmp(l, "snewspost:", 10) && + strncmp(l, "snewsreply:", 11) && + strncmp(l, "newspost:", 9) && + strncmp(l, "newsreply:", 10) && + strncmp(l, "ftp://", 6) && + strncmp(l, "file:/", 6) && + strncmp(l, "finger://", 9) && + strncmp(l, "http://", 7) && + strncmp(l, "https://", 8) && + strncmp(l, "wais://", 7) && + strncmp(l, "mailto:", 7) && + strncmp(l, "cso://", 6) && + strncmp(l, "gopher://", 9)) { + buf[i++] = *l++; + buf[i] = '\0'; + } else { + strcat(buf, "<a href=\""); + i += 9; + buf[i] = '\0'; + StrAllocCopy(href, l); + strcat(buf, strtok(href, " \r\n\t,>)\"")); + strcat(buf, "\">"); + i = strlen(buf); + while (*l && !strchr(" \r\n\t,>)\"", *l)) { + buf[i++] = *l++; + } + buf[i] = '\0'; + strcat(buf, "</a>"); + i += 4; + FREE(href); + } + } + strcat(buf, "\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + } else { + sprintf(buf, "<DD>"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + i = 0; + buf[i] = '\0'; + l = fvalue; + while (*l) { + if (*l == '<') { + strcat(buf, "<"); + l++; + i += 4; + buf[i] = '\0'; + } else if (*l == '>') { + strcat(buf, ">"); + l++; + i += 4; + buf[i] = '\0'; + } else if (strncmp(l, "news:", 5) && + strncmp(l, "snews://", 8) && + strncmp(l, "nntp://", 7) && + strncmp(l, "snewspost:", 10) && + strncmp(l, "snewsreply:", 11) && + strncmp(l, "newspost:", 9) && + strncmp(l, "newsreply:", 10) && + strncmp(l, "ftp://", 6) && + strncmp(l, "file:/", 6) && + strncmp(l, "finger://", 9) && + strncmp(l, "http://", 7) && + strncmp(l, "https://", 8) && + strncmp(l, "wais://", 7) && + strncmp(l, "mailto:", 7) && + strncmp(l, "cso://", 6) && + strncmp(l, "gopher://", 9)) { + buf[i++] = *l++; + buf[i] = '\0'; + } else { + strcat(buf, "<a href=\""); + i += 9; + buf[i] = '\0'; + StrAllocCopy(href, l); + strcat(buf, strtok(href, " \r\n\t,>)\"")); + strcat(buf, "\">"); + i = strlen(buf); + while (*l && !strchr(" \r\n\t,>)\"", *l)) { + buf[i++] = *l++; + } + buf[i] = '\0'; + strcat(buf, "</a>"); + i += 4; + FREE(href); + } + } + strcat(buf, "\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + } else { + sprintf(buf, "<DD>%s\n", fname ? fname : rcode ); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + } + } +end_CSOreport: + if (prev_ndx != -100) { + sprintf(buf, "</DL></DL>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + } + return 0; +} + +/* CSO/PH form-based search gateway - FM HTLoadCSO +** ===================================== +*/ +PRIVATE int HTLoadCSO ARGS4( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) +{ + char *host, *cp; + int port = CSO_PORT; + int status; /* tcp return */ + char *command = NULL; + char *content = NULL; + int len, i, j, start, finish, flen, ndx, clen; + int return_type, has_indexed; + CSOfield_info *fld; + char buf[2048]; + HTFormat format_in = WWW_HTML; + HTStream *Target = NULL; + + if (!acceptable_inited) + init_acceptable(); + + if (!arg) + return -3; /* Bad if no name sepcified */ + if (!*arg) + return -2; /* Bad if name had zero length */ + if (TRACE) + fprintf(stderr, "HTLoadCSO: Looking for %s\n", arg); + + /* + ** Set up a socket to the server for the data. + */ + status = HTDoConnect (arg, "cso", CSO_PORT, &s); + if (status == HT_INTERRUPTED) { + /* + ** Interrupt cleanly. + */ + if (TRACE) + fprintf(stderr, + "HTLoadCSO: Interrupted on connect; recovering cleanly.\n"); + _HTProgress ("Connection interrupted."); + return HT_NOT_LOADED; + } + if (status < 0) { + if (TRACE) + fprintf(stderr, + "HTLoadCSO: Unable to connect to remote host for `%s'.\n", + arg); + return HTInetStatus("connect"); + } + + HTInitInput(s); /* Set up input buffering */ + + if ((command = (char *)malloc(12)) == NULL) + outofmem(__FILE__, "HTLoadCSO"); + sprintf(command, "fields%c%c", CR, LF); + if (TRACE) + fprintf(stderr, + "HTLoadCSO: Connected, writing command `%s' to socket %d\n", + command, s); + _HTProgress ("Sending CSO/PH request."); + status = NETWRITE(s, command, (int)strlen(command)); + FREE(command); + if (status < 0) { + if (TRACE) + fprintf(stderr, "HTLoadCSO: Unable to send command.\n"); + return HTInetStatus("send"); + } + _HTProgress ("CSO/PH request sent; waiting for response."); + + /* + ** Now read the data from the socket. + */ + status = parse_cso_fields(buf, sizeof(buf)); + if (status) { + NETCLOSE(s); + if (status == HT_INTERRUPTED) { + _HTProgress ("Connection interrupted."); + } else if (buf[0] != '\0') { + HTAlert(buf); + } else { + HTAlert("No response from server!"); + } + return HT_NOT_LOADED; + } + Target = HTStreamStack(format_in, + format_out, + sink, anAnchor); + if (!Target || Target == NULL) { + char *temp = (char *)malloc(256); + if (!temp) { + outofmem(__FILE__, "HTLoadCSO"); + } + sprintf(temp, "Sorry, no known way of converting %s to %s.", + HTAtom_name(format_in), HTAtom_name(format_out)); + HTAlert(temp); + FREE(temp); + NETCLOSE(s); + return HT_NOT_LOADED; + } + host = HTParse(arg, "", PARSE_HOST); + if ((cp=strchr(host, ':')) != NULL) { + if (cp[1] >= '0' && cp[1] <= '9') { + port = atoi((cp+1)); + if (port == CSO_PORT) { + *cp = '\0'; + } + } + } + anAnchor->safe = TRUE; + if (!(anAnchor->post_data && *anAnchor->post_data)) { + generate_cso_form(host, port, buf, Target); + (*Target->isa->_free)(Target); + FREE(host); + NETCLOSE(s); + free_CSOfields(); + return HT_LOADED; + } + sprintf(buf, + "<HTML>\n<HEAD>\n<TITLE>CSO/PH Results on %s</TITLE>\n</HEAD>\n<BODY>\n", + host); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + FREE(host); + StrAllocCopy(content, anAnchor->post_data); + if (content[strlen(content)-1] != '&') + StrAllocCat(content, "&"); + len = strlen(content); + for (i = 0; i < len; i++) { + if (content[i] == '+') { + content[i] = ' '; + } + } + HTUnEscape(content); + len = strlen(content); + return_type = 0; + has_indexed = 0; + start = finish = clen = 0; + for (i = 0; i < len; i++) { + if (!content[i] || content[i] == '&') { + /* + ** Value parsed. Unescape characters and look for first '=' + ** to delimit field name from value. + */ + flen = i - start; + finish = start + flen; + content[finish] = '\0'; + for (j = start; j < finish; j++) { + if (content[j] == '=') { + /* + ** content[start..j-1] is field name, + ** [j+1..finish-1] is value. + */ + if ((content[start+1] == '_') && + ((content[start] == 'r') || (content[start] == 'q'))) { + /* + ** Decode fields number and lookup field info. + */ + sscanf (&content[start+2], "%d=", &ndx); + for (fld = CSOfields; fld; fld = fld->next) { + if (ndx==fld->id) { + if ((j+1) >= finish) + break; /* ignore nulls */ + if (content[start] == 'q') { + /* + * Append field to query line. + */ + if (fld->lookup) { + if (fld->indexed) + has_indexed = 1; + if (clen == 0) { + StrAllocCopy(command, "query "); + clen = 6; + } else { + StrAllocCat(command, " "); + clen++; + } + sprintf(buf, "%s=\"%s\"", + fld->name, &content[j+1]); + StrAllocCat(command, buf); + clen += strlen(buf); + } else { + strcpy(buf, + "Warning: non-lookup field ignored<BR>\n"); + (*Target->isa->put_block)(Target, + buf, + strlen(buf)); + } + } else if (content[start] == 'r') { + fld->explicit_return = 1; + } + break; + } + } + } else if (!strncmp(&content[start],"return=",7)) { + if (!strcmp(&content[start+7],"all")) { + return_type = 1; + } else if (!strcmp(&content[start+7],"selected")) { + return_type = 2; + } + } + } + } + start = i + 1; + } + } + FREE(content); + if ((clen == 0) || !has_indexed) { + NETCLOSE(s); + strcpy(buf, + "<EM>Error:</EM> At least one indexed field value must be specified!\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + strcpy(buf, "</BODY>\n</HTML>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + (*Target->isa->_free)(Target); + free_CSOfields(); + return HT_LOADED; + } + /* + ** Append return fields. + */ + if (return_type == 1) { + StrAllocCat(command, " return all"); + clen += 11; + } else if (return_type == 2) { + StrAllocCat(command, " return"); + clen += 7; + for (fld = CSOfields; fld; fld = fld->next) { + if (fld->explicit_return) { + sprintf(buf, " %s", fld->name); + StrAllocCat(command, buf); + clen += strlen(buf); + } + } + } + sprintf(buf, "%c%c", CR, LF); + StrAllocCat(command, buf); + clen += strlen(buf); + strcpy(buf, "<H2>\n<EM>CSO/PH command:</EM> "); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + (*Target->isa->put_block)(Target, command, clen); + strcpy(buf, "</H2>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + if (TRACE) + fprintf(stderr, + "HTLoadCSO: Writing command `%s' to socket %d\n", + command, s); + status = NETWRITE(s, command, clen); + FREE(command); + if (status < 0) { + if (TRACE) + fprintf(stderr, "HTLoadCSO: Unable to send command.\n"); + free_CSOfields(); + return HTInetStatus("send"); + } + generate_cso_report(buf, Target); + NETCLOSE(s); + strcpy(buf, "</BODY>\n</HTML>\n"); + (*Target->isa->put_block)(Target, buf, strlen(buf)); + (*Target->isa->_free)(Target); + FREE(host); + free_CSOfields(); + return HT_LOADED; +} + +/* Load by name. HTLoadGopher +** ============= +** +** Bug: No decoding of strange data types as yet. +** +*/ +PRIVATE int HTLoadGopher ARGS4( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) +{ + char *command; /* The whole command */ + int status; /* tcp return */ + char gtype; /* Gopher Node type */ + char * selector; /* Selector string */ + + if (!acceptable_inited) + init_acceptable(); + + if (!arg) + return -3; /* Bad if no name sepcified */ + if (!*arg) + return -2; /* Bad if name had zero length */ + if (TRACE) + fprintf(stderr, "HTGopher: Looking for %s\n", arg); + + /* + ** If it's a port 105 GOPHER_CSO gtype with no ISINDEX token ('?'), + ** use the form-based CSO gateway (otherwise, return an ISINDEX + ** cover page or do the ISINDEX search). - FM + */ + { + int len; + + if ((len = strlen(arg)) > 5) { + if (0 == strcmp((CONST char *)&arg[len-6], ":105/2")) { + /* Use CSO gateway. */ + if (TRACE) + fprintf(stderr, "HTGopher: Passing to CSO/PH gateway.\n"); + return HTLoadCSO(arg, anAnchor, format_out, sink); + } + } + } + + /* + ** If it's a port 79/0[/...] URL, use the finger gateway. - FM + */ + if (strstr(arg, ":79/0") != NULL) { + if (TRACE) + fprintf(stderr, "HTGopher: Passing to finger gateway.\n"); + return HTLoadFinger(arg, anAnchor, format_out, sink); + } + + /* + ** Get entity type, and selector string. + */ + { + char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); + gtype = '1'; /* Default = menu */ + selector = p1; + if ((*selector++=='/') && (*selector)) { /* Skip first slash */ + gtype = *selector++; /* Pick up gtype */ + } + if (gtype == GOPHER_INDEX) { + char * query; + /* + ** Search is allowed. + */ + HTAnchor_setIndex(anAnchor, anAnchor->address); + query = strchr(selector, '?'); /* Look for search string */ + if (!query || !query[1]) { /* No search required */ + target = HTML_new(anAnchor, format_out, sink); + targetClass = *target->isa; + display_index(arg, anAnchor); /* Display "cover page" */ + return HT_LOADED; /* Local function only */ + } + *query++ = '\0'; /* Skip '?' */ + command = + (char *)malloc(strlen(selector)+ 1 + strlen(query)+ 2 + 1); + if (command == NULL) + outofmem(__FILE__, "HTLoadGopher"); + + de_escape(command, selector); /* Bug fix TBL 921208 */ + + strcat(command, "\t"); + + { /* Remove plus signs 921006 */ + char *p; + for (p=query; *p; p++) { + if (*p == '+') *p = ' '; + } + } + + de_escape(&command[strlen(command)], query);/* bug fix LJM 940415 */ + } else if (gtype == GOPHER_CSO) { + char * query; + /* + ** Search is allowed. + */ + query = strchr(selector, '?'); /* Look for search string */ + if (!query || !query[1]) { /* No search required */ + target = HTML_new(anAnchor, format_out, sink); + targetClass = *target->isa; + display_cso(arg, anAnchor); /* Display "cover page" */ + return HT_LOADED; /* Local function only */ + } + HTAnchor_setIndex(anAnchor, anAnchor->address); + *query++ = '\0'; /* Skip '?' */ + command = (char *)malloc(strlen("query")+1 + strlen(query)+2+1); + if (command == NULL) + outofmem(__FILE__, "HTLoadGopher"); + + de_escape(command, selector); /* Bug fix TBL 921208 */ + + strcpy(command, "query "); + + { /* Remove plus signs 921006 */ + char *p; + for (p=query; *p; p++) { + if (*p == '+') *p = ' '; + } + } + de_escape(&command[strlen(command)], query);/* bug fix LJM 940415 */ + + } else { /* Not index */ + command = (char *)malloc(strlen(selector)+2+1); + de_escape(command, selector); + } + FREE(p1); + } + + { + char * p = command + strlen(command); + *p++ = CR; /* Macros to be correct on Mac */ + *p++ = LF; + *p++ = '\0'; + } + + /* + ** Set up a socket to the server for the data. + */ + status = HTDoConnect (arg, "gopher", GOPHER_PORT, &s); + if (status == HT_INTERRUPTED) { + /* + ** Interrupt cleanly. + */ + if (TRACE) + fprintf(stderr, + "HTGopher: Interrupted on connect; recovering cleanly.\n"); + _HTProgress ("Connection interrupted."); + FREE(command); + return HT_NOT_LOADED; + } + if (status < 0) { + if (TRACE) + fprintf(stderr, + "HTGopher: Unable to connect to remote host for `%s'.\n", + arg); + FREE(command); + return HTInetStatus("connect"); + } + + HTInitInput(s); /* Set up input buffering */ + + if (TRACE) + fprintf(stderr, + "HTGopher: Connected, writing command `%s' to socket %d\n", + command, s); + +#ifdef NOT_ASCII + { + char * p; + for (p = command; *p; p++) { + *p = TOASCII(*p); + } + } +#endif + + _HTProgress ("Sending Gopher request."); + + status = NETWRITE(s, command, (int)strlen(command)); + FREE(command); + if (status < 0) { + if (TRACE) + fprintf(stderr, "HTGopher: Unable to send command.\n"); + return HTInetStatus("send"); + } + + _HTProgress ("Gopher request sent; waiting for response."); + + /* + ** Now read the data from the socket. + */ + switch (gtype) { + + case GOPHER_TEXT : + HTParseSocket(WWW_PLAINTEXT, format_out, anAnchor, s, sink); + break; + + case GOPHER_HTML : + case GOPHER_CHTML : + HTParseSocket(WWW_HTML, format_out, anAnchor, s, sink); + break; + + case GOPHER_GIF: + case GOPHER_IMAGE: + case GOPHER_PLUS_IMAGE: + HTParseSocket(HTAtom_for("image/gif"), + format_out, anAnchor, s, sink); + break; + + case GOPHER_MENU : + case GOPHER_INDEX : + target = HTML_new(anAnchor, format_out, sink); + targetClass = *target->isa; + parse_menu(arg, anAnchor); + break; + + case GOPHER_CSO: + target = HTML_new(anAnchor, format_out, sink); + targetClass = *target->isa; + parse_cso(arg, anAnchor); + break; + + case GOPHER_SOUND : + case GOPHER_PLUS_SOUND : + HTParseSocket(WWW_AUDIO, format_out, anAnchor, s, sink); + break; + + case GOPHER_PLUS_MOVIE: + HTParseSocket(HTAtom_for("video/mpeg"), format_out, anAnchor, s, sink); + break; + + case GOPHER_PLUS_PDF: + HTParseSocket(HTAtom_for("application/pdf"), format_out, anAnchor, + s, sink); + break; + + case GOPHER_MACBINHEX: + case GOPHER_PCBINARY: + case GOPHER_UUENCODED: + case GOPHER_BINARY: + default: + /* + ** Specifying WWW_UNKNOWN forces dump to local disk. + */ + HTParseSocket (WWW_UNKNOWN, format_out, anAnchor, s, sink); + break; + + } /* switch(gtype) */ + + NETCLOSE(s); + return HT_LOADED; +} + +#ifdef GLOBALDEF_IS_MACRO +#define _HTGOPHER_C_1_INIT { "gopher", HTLoadGopher, NULL } +GLOBALDEF (HTProtocol, HTGopher, _HTGOPHER_C_1_INIT); +#define _HTCSO_C_1_INIT { "cso", HTLoadCSO, NULL } +GLOBALDEF (HTProtocol, HTCSO, _HTCSO_C_1_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTGopher = { "gopher", HTLoadGopher, NULL }; +GLOBALDEF PUBLIC HTProtocol HTCSO = { "cso", HTLoadCSO, NULL }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.h new file mode 100644 index 00000000000..947bd3e93c6 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.h @@ -0,0 +1,27 @@ +/* Gopher protocol module for libwww + GOPHER ACCESS + + HISTORY: + + 8 Jan 92 Adapted from HTTP TBL + + */ + + +#ifndef HTGOPHER_H +#define HTGOPHER_H + +#include "HTAccess.h" +#include "HTAnchor.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF (HTProtocol, HTGopher); +#else +GLOBALREF HTProtocol HTGopher; +#endif /* GLOBALREF_IS_MACRO */ + +#endif /* HTGOPHER_H */ + +/* + + end of gopher module */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.c new file mode 100644 index 00000000000..f6b1757868a --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.c @@ -0,0 +1,772 @@ + +/* MODULE HTGroup.c +** GROUP FILE ROUTINES +** +** Contains group file parser and routines to match IP +** address templates and to find out group membership. +** +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** +** +** BUGS: +** +** +** +** GROUP DEFINITION GRAMMAR: +** +** string = "sequence of alphanumeric characters" +** user_name ::= string +** group_name ::= string +** group_ref ::= group_name +** user_def ::= user_name | group_ref +** user_def_list ::= user_def { ',' user_def } +** user_part = user_def | '(' user_def_list ')' +** +** templ = "sequence of alphanumeric characters and '*'s" +** ip_number_mask ::= templ '.' templ '.' templ '.' templ +** domain_name_mask ::= templ { '.' templ } +** address ::= ip_number_mask | domain_name_mask +** address_def ::= address +** address_def_list ::= address_def { ',' address_def } +** address_part = address_def | '(' address_def_list ')' +** +** item ::= [user_part] ['@' address_part] +** item_list ::= item { ',' item } +** group_def ::= item_list +** group_decl ::= group_name ':' group_def +** +*/ + + + +#include "HTUtils.h" +#include <string.h> +#include "HTAAUtil.h" +#include "HTLex.h" /* Lexical analysor */ +#include "HTGroup.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* +** Group file parser +*/ + +typedef HTList UserDefList; +typedef HTList AddressDefList; + +typedef struct { + UserDefList * user_def_list; + AddressDefList * address_def_list; +} Item; + +typedef struct { + char * name; + GroupDef * translation; +} Ref; + + + +PRIVATE void syntax_error ARGS3(FILE *, fp, + char *, msg, + LexItem, lex_item) +{ + char buffer[41]; + int cnt = 0; + int ch; + + while ((ch = getc(fp)) != EOF && ch != '\n') + if (cnt < 40) buffer[cnt++] = ch; + buffer[cnt] = (char)0; + + if (TRACE) + fprintf(stderr, "%s %d before: '%s'\nHTGroup.c: %s (got %s)\n", + "HTGroup.c: Syntax error in rule file at line", + HTlex_line, buffer, msg, lex_verbose(lex_item)); + HTlex_line++; +} + + +PRIVATE AddressDefList *parse_address_part ARGS1(FILE *, fp) +{ + AddressDefList *address_def_list = NULL; + LexItem lex_item; + BOOL only_one = NO; + + lex_item = lex(fp); + if (lex_item == LEX_ALPH_STR || lex_item == LEX_TMPL_STR) + only_one = YES; + else if (lex_item != LEX_OPEN_PAREN || + ((lex_item = lex(fp)) != LEX_ALPH_STR && + lex_item != LEX_TMPL_STR)) { + syntax_error(fp, "Expecting a single address or '(' beginning list", + lex_item); + return NULL; + } + address_def_list = HTList_new(); + + for(;;) { + Ref *ref = (Ref*)calloc(1, sizeof(Ref)); + ref->name = NULL; + ref->translation = NULL; + StrAllocCopy(ref->name, HTlex_buffer); + + HTList_addObject(address_def_list, (void*)ref); + + if (only_one || (lex_item = lex(fp)) != LEX_ITEM_SEP) + break; + /* + ** Here lex_item == LEX_ITEM_SEP; after item separator it + ** is ok to have one or more newlines (LEX_REC_SEP) and + ** they are ignored (continuation line). + */ + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); + + if (lex_item != LEX_ALPH_STR && lex_item != LEX_TMPL_STR) { + syntax_error(fp, "Expecting an address template", lex_item); + HTList_delete(address_def_list); + address_def_list = NULL; + return NULL; + } + } + + if (!only_one && lex_item != LEX_CLOSE_PAREN) { + HTList_delete(address_def_list); + address_def_list = NULL; + syntax_error(fp, "Expecting ')' closing address list", lex_item); + return NULL; + } + return address_def_list; +} + + +PRIVATE UserDefList *parse_user_part ARGS1(FILE *, fp) +{ + UserDefList *user_def_list = NULL; + LexItem lex_item; + BOOL only_one = NO; + + lex_item = lex(fp); + if (lex_item == LEX_ALPH_STR) + only_one = YES; + else if (lex_item != LEX_OPEN_PAREN || + (lex_item = lex(fp)) != LEX_ALPH_STR) { + syntax_error(fp, "Expecting a single name or '(' beginning list", + lex_item); + return NULL; + } + user_def_list = HTList_new(); + + for (;;) { + Ref *ref = (Ref*)calloc(1, sizeof(Ref)); + ref->name = NULL; + ref->translation = NULL; + StrAllocCopy(ref->name, HTlex_buffer); + + HTList_addObject(user_def_list, (void*)ref); + + if (only_one || (lex_item = lex(fp)) != LEX_ITEM_SEP) + break; + /* + ** Here lex_item == LEX_ITEM_SEP; after item separator it + ** is ok to have one or more newlines (LEX_REC_SEP) and + ** they are ignored (continuation line). + */ + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); + + if (lex_item != LEX_ALPH_STR) { + syntax_error(fp, "Expecting user or group name", lex_item); + HTList_delete(user_def_list); + user_def_list = NULL; + return NULL; + } + } + + if (!only_one && lex_item != LEX_CLOSE_PAREN) { + HTList_delete(user_def_list); + user_def_list = NULL; + syntax_error(fp, "Expecting ')' closing user/group list", lex_item); + return NULL; + } + return user_def_list; +} + + +PRIVATE Item *parse_item ARGS1(FILE *, fp) +{ + Item *item = NULL; + UserDefList *user_def_list = NULL; + AddressDefList *address_def_list = NULL; + LexItem lex_item; + + lex_item = lex(fp); + if (lex_item == LEX_ALPH_STR || lex_item == LEX_OPEN_PAREN) { + unlex(lex_item); + user_def_list = parse_user_part(fp); + lex_item = lex(fp); + } + + if (lex_item == LEX_AT_SIGN) { + lex_item = lex(fp); + if (lex_item == LEX_ALPH_STR || lex_item == LEX_TMPL_STR || + lex_item == LEX_OPEN_PAREN) { + unlex(lex_item); + address_def_list = parse_address_part(fp); + } + else { + if (user_def_list) { + HTList_delete(user_def_list); /* @@@@ */ + user_def_list = NULL; + } + syntax_error(fp, "Expected address part (single address or list)", + lex_item); + return NULL; + } + } + else unlex(lex_item); + + if (!user_def_list && !address_def_list) { + syntax_error(fp, "Empty item not allowed", lex_item); + return NULL; + } + item = (Item*)calloc(1, sizeof(Item)); + item->user_def_list = user_def_list; + item->address_def_list = address_def_list; + return item; +} + + +PRIVATE ItemList *parse_item_list ARGS1(FILE *, fp) +{ + ItemList *item_list = HTList_new(); + Item *item; + LexItem lex_item; + + for(;;) { + if (!(item = parse_item(fp))) { + HTList_delete(item_list); /* @@@@ */ + item_list = NULL; + return NULL; + } + HTList_addObject(item_list, (void*)item); + lex_item = lex(fp); + if (lex_item != LEX_ITEM_SEP) { + unlex(lex_item); + return item_list; + } + /* + ** Here lex_item == LEX_ITEM_SEP; after item separator it + ** is ok to have one or more newlines (LEX_REC_SEP) and + ** they are ignored (continuation line). + */ + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); + unlex(lex_item); + } +} + + +PUBLIC GroupDef *HTAA_parseGroupDef ARGS1(FILE *, fp) +{ + ItemList *item_list = NULL; + GroupDef *group_def = NULL; + LexItem lex_item; + + if (!(item_list = parse_item_list(fp))) { + return NULL; + } + group_def = (GroupDef*)calloc(1, sizeof(GroupDef)); + group_def->group_name = NULL; + group_def->item_list = item_list; + + if ((lex_item = lex(fp)) != LEX_REC_SEP) { + syntax_error(fp, "Garbage after group definition", lex_item); + } + + return group_def; +} + + +PRIVATE GroupDef *parse_group_decl ARGS1(FILE *, fp) +{ + char *group_name = NULL; + GroupDef *group_def = NULL; + LexItem lex_item; + + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); /* Ignore empty lines */ + + if (lex_item != LEX_ALPH_STR) { + if (lex_item != LEX_EOF) + syntax_error(fp, "Expecting group name", lex_item); + return NULL; + } + StrAllocCopy(group_name, HTlex_buffer); + + if (LEX_FIELD_SEP != (lex_item = lex(fp))) { + syntax_error(fp, "Expecting field separator", lex_item); + FREE(group_name); + return NULL; + } + + if (!(group_def = HTAA_parseGroupDef(fp))) { + FREE(group_name); + return NULL; + } + group_def->group_name = group_name; + + return group_def; +} + + + +/* +** Group manipulation routines +*/ + +PRIVATE GroupDef *find_group_def ARGS2(GroupDefList *, group_list, + CONST char *, group_name) +{ + if (group_list && group_name) { + GroupDefList *cur = group_list; + GroupDef *group_def; + + while (NULL != (group_def = (GroupDef*)HTList_nextObject(cur))) { + if (!strcmp(group_name, group_def->group_name)) { + return group_def; + } + } + } + return NULL; +} + + +PUBLIC void HTAA_resolveGroupReferences ARGS2(GroupDef *, group_def, + GroupDefList *, group_def_list) +{ + if (group_def && group_def->item_list && group_def_list) { + ItemList *cur1 = group_def->item_list; + Item *item; + + while (NULL != (item = (Item*)HTList_nextObject(cur1))) { + UserDefList *cur2 = item->user_def_list; + Ref *ref; + + while (NULL != (ref = (Ref*)HTList_nextObject(cur2))) + ref->translation = find_group_def(group_def_list, ref->name); + + /* Does NOT translate address_def_list */ + } + } +} + + +PRIVATE void add_group_def ARGS2(GroupDefList *, group_def_list, + GroupDef *, group_def) +{ + HTAA_resolveGroupReferences(group_def, group_def_list); + HTList_addObject(group_def_list, (void*)group_def); +} + + +PRIVATE GroupDefList *parse_group_file ARGS1(FILE *, fp) +{ + GroupDefList *group_def_list = HTList_new(); + GroupDef *group_def; + + while (NULL != (group_def = parse_group_decl(fp))) + add_group_def(group_def_list, group_def); + + return group_def_list; +} + + +/* +** Trace functions +*/ + +PRIVATE void print_item ARGS1(Item *, item) +{ + if (!item) + fprintf(stderr, "\tNULL-ITEM\n"); + else { + UserDefList *cur1 = item->user_def_list; + AddressDefList *cur2 = item->address_def_list; + Ref *user_ref = (Ref*)HTList_nextObject(cur1); + Ref *addr_ref = (Ref*)HTList_nextObject(cur2); + + if (user_ref) { + fprintf(stderr, "\t[%s%s", user_ref->name, + (user_ref->translation ? "*REF*" : "")); + while (NULL != (user_ref = (Ref*)HTList_nextObject(cur1))) + fprintf(stderr, "; %s%s", user_ref->name, + (user_ref->translation ? "*REF*" : "")); + fprintf(stderr, "] "); + } else fprintf(stderr, "\tANYBODY "); + + if (addr_ref) { + fprintf(stderr, "@ [%s", addr_ref->name); + while (NULL != (addr_ref = (Ref*)HTList_nextObject(cur2))) + fprintf(stderr, "; %s", addr_ref->name); + fprintf(stderr, "]\n"); + } else fprintf(stderr, "@ ANYADDRESS\n"); + } +} + + +PRIVATE void print_item_list ARGS1(ItemList *, item_list) +{ + ItemList *cur = item_list; + Item *item; + + if (!item_list) + fprintf(stderr, "EMPTY"); + else while (NULL != (item = (Item*)HTList_nextObject(cur))) + print_item(item); +} + + +PUBLIC void HTAA_printGroupDef ARGS1(GroupDef *, group_def) +{ + if (!group_def) { + fprintf(stderr, "\nNULL RECORD\n"); + return; + } + + fprintf(stderr, "\nGroup %s:\n", + (group_def->group_name ? group_def->group_name : "NULL")); + + print_item_list(group_def->item_list); + fprintf(stderr, "\n"); +} + + +PRIVATE void print_group_def_list ARGS1(GroupDefList *, group_list) +{ + GroupDefList *cur = group_list; + GroupDef *group_def; + + while (NULL != (group_def = (GroupDef*)HTList_nextObject(cur))) + HTAA_printGroupDef(group_def); +} + + + +/* +** IP address template matching +*/ + +/* PRIVATE part_match() +** MATCH ONE PART OF INET ADDRESS AGAIST +** A PART OF MASK (inet address has 4 parts) +** ON ENTRY: +** tcur pointer to the beginning of template part. +** icur pointer to the beginning of actual inet +** number part. +** +** ON EXIT: +** returns YES, if match. +*/ +PRIVATE BOOL part_match ARGS2(CONST char *, tcur, + CONST char *, icur) +{ + char required[4]; + char actual[4]; + CONST char *cur; + int cnt; + + if (!tcur || !icur) return NO; + + cur=tcur; + cnt=0; + while (cnt < 3 && *cur && *cur != '.') + required[cnt++] = *(cur++); + required[cnt] = (char)0; + + cur=icur; + cnt=0; + while (cnt < 3 && *cur && *cur != '.') + actual[cnt++] = *(cur++); + actual[cnt] = (char)0; + + if (TRACE) { + BOOL status = HTAA_templateMatch(required, actual); + fprintf(stderr, "part_match: req: '%s' act: '%s' match: %s\n", + required, actual, (status ? "yes" : "no")); + return status; + } + + return HTAA_templateMatch(required, actual); +} + + + +/* PRIVATE ip_number_match() +** MATCH INET NUMBER AGAINST AN INET NUMBER MASK +** ON ENTRY: +** template mask to match agaist, e.g. 128.141.*.* +** the_inet_addr actual inet address, e.g. 128.141.201.74 +** +** ON EXIT: +** returns YES, if match; NO, if not. +*/ +PRIVATE BOOL ip_number_match ARGS2(CONST char *, template, + CONST char *, the_inet_addr) +{ + CONST char *tcur = template; + CONST char *icur = the_inet_addr; + int cnt; + + for (cnt=0; cnt<4; cnt++) { + if (!tcur || !icur || !part_match(tcur, icur)) + return NO; + if (NULL != (tcur = strchr(tcur, '.'))) tcur++; + if (NULL != (icur = strchr(icur, '.'))) icur++; + } + return YES; +} + + + +/* PRIVATE is_domain_mask() +** DETERMINE IF A GIVEN MASK IS A +** DOMAIN NAME MASK OR AN INET NUMBER MASK +** ON ENTRY: +** mask either a domain name mask, +** e.g. +** *.cern.ch +** +** or an inet number mask, +** e.g. +** 128.141.*.* +** +** ON EXIT: +** returns YES, if mask is a domain name mask. +** NO, if it is an inet number mask. +*/ +PRIVATE BOOL is_domain_mask ARGS1(CONST char *, mask) +{ + CONST char *cur = mask; + + if (!mask) return NO; + + while (*cur) { + if (*cur != '.' && *cur != '*' && (*cur < '0' || *cur > '9')) + return YES; /* Even one non-digit makes it a domain name mask */ + cur++; + } + return NO; /* All digits and dots, so it is an inet number mask */ +} + + + +/* PRIVATE ip_mask_match() +** MATCH AN IP NUMBER MASK OR IP NAME MASK +** AGAINST ACTUAL IP NUMBER OR IP NAME +** +** ON ENTRY: +** mask mask. Mask may be either an inet number +** mask or a domain name mask, +** e.g. +** 128.141.*.* +** or +** *.cern.ch +** +** ip_number IP number of connecting host. +** ip_name IP name of the connecting host. +** +** ON EXIT: +** returns YES, if hostname/internet number +** matches the mask. +** NO, if no match (no fire). +*/ +PRIVATE BOOL ip_mask_match ARGS3(CONST char *, mask, + CONST char *, ip_number, + CONST char *, ip_name) +{ + if (mask && (ip_number || ip_name)) { + if (is_domain_mask(mask)) { + if (HTAA_templateMatch(mask, ip_name)) + return YES; + } + else { + if (ip_number_match(mask, ip_number)) + return YES; + } + } + return NO; +} + + + + +PRIVATE BOOL ip_in_def_list ARGS3(AddressDefList *, address_def_list, + char *, ip_number, + char *, ip_name) +{ + if (address_def_list && (ip_number || ip_name)) { + AddressDefList *cur = address_def_list; + Ref *ref; + + while (NULL != (ref = (Ref*)HTList_nextObject(cur))) { + /* Value of ref->translation is ignored, i.e. */ + /* no recursion for ip address tamplates. */ + if (ip_mask_match(ref->name, ip_number, ip_name)) + return YES; + } + } + return NO; +} + + +/* +** Group file cached reading +*/ + +typedef struct { + char * group_filename; + GroupDefList * group_list; +} GroupCache; + +typedef HTList GroupCacheList; + +PRIVATE GroupCacheList *group_cache_list = NULL; + + +PUBLIC GroupDefList *HTAA_readGroupFile ARGS1(CONST char *, filename) +{ + FILE *fp; + GroupCache *group_cache; + + if (!filename || !*filename) return NULL; + + if (!group_cache_list) + group_cache_list = HTList_new(); + else { + GroupCacheList *cur = group_cache_list; + + while (NULL != (group_cache = (GroupCache*)HTList_nextObject(cur))) { + if (!strcmp(filename, group_cache->group_filename)) { + if (TRACE) fprintf(stderr, "%s '%s' %s\n", + "HTAA_readGroupFile: group file", + filename, "already found in cache"); + return group_cache->group_list; + } /* if cache match */ + } /* while cached files remain */ + } /* cache exists */ + + if (TRACE) fprintf(stderr, "HTAA_readGroupFile: reading group file `%s'\n", + filename); + + if (!(fp = fopen(filename, "r"))) { + if (TRACE) fprintf(stderr, "%s '%s'\n", + "HTAA_readGroupFile: unable to open group file", + filename); + return NULL; + } + + if (!(group_cache = (GroupCache*)calloc(1, sizeof(GroupCache)))) + outofmem(__FILE__, "HTAA_readGroupFile"); + + group_cache->group_filename = NULL; + StrAllocCopy(group_cache->group_filename, filename); + group_cache->group_list = parse_group_file(fp); + HTList_addObject(group_cache_list, (void*)group_cache); + fclose(fp); + + if (TRACE) { + fprintf(stderr, "Read group file '%s', results follow:\n", filename); + print_group_def_list(group_cache->group_list); + } + + return group_cache->group_list; +} + + +/* PUBLIC HTAA_userAndInetInGroup() +** CHECK IF USER BELONGS TO TO A GIVEN GROUP +** AND THAT THE CONNECTION COMES FROM AN +** ADDRESS THAT IS ALLOWED BY THAT GROUP +** ON ENTRY: +** group the group definition structure. +** username connecting user. +** ip_number browser host IP number, optional. +** ip_name browser host IP name, optional. +** However, one of ip_number or ip_name +** must be given. +** ON EXIT: +** returns HTAA_IP_MASK, if IP address mask was +** reason for failing. +** HTAA_NOT_MEMBER, if user does not belong +** to the group. +** HTAA_OK if both IP address and user are ok. +*/ +PUBLIC HTAAFailReasonType HTAA_userAndInetInGroup ARGS4(GroupDef *, group, + char *, username, + char *, ip_number, + char *, ip_name) +{ + HTAAFailReasonType reason = HTAA_NOT_MEMBER; + + if (group && username) { + ItemList *cur1 = group->item_list; + Item *item; + + while (NULL != (item = (Item*)HTList_nextObject(cur1))) { + if (!item->address_def_list || /* Any address allowed */ + ip_in_def_list(item->address_def_list, ip_number, ip_name)) { + + if (!item->user_def_list) /* Any user allowed */ + return HTAA_OK; + else { + UserDefList *cur2 = item->user_def_list; + Ref *ref; + + while (NULL != (ref = (Ref*)HTList_nextObject(cur2))) { + + if (ref->translation) { /* Group, check recursively */ + reason = HTAA_userAndInetInGroup(ref->translation, + username, + ip_number,ip_name); + if (reason == HTAA_OK) + return HTAA_OK; + } + else { /* Username, check directly */ + if (username && *username && + 0==strcmp(ref->name, username)) + return HTAA_OK; + } + } /* Every user/group name in this group */ + } /* search for username */ + } /* IP address ok */ + else { + reason = HTAA_IP_MASK; + } + } /* while items in group */ + } /* valid parameters */ + + return reason; /* No match, or invalid parameters */ +} + + +PUBLIC void GroupDef_delete ARGS1(GroupDef *, group_def) +{ + if (group_def) { + FREE(group_def->group_name); + if (group_def->item_list) { + HTList_delete(group_def->item_list); /* @@@@ */ + group_def->item_list = NULL; + } + FREE(group_def); + } +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.h new file mode 100644 index 00000000000..496a5077ad0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.h @@ -0,0 +1,189 @@ +/* GROUP FILE ROUTINES + + */ + +#ifndef HTGROUP_H +#define HTGROUP_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTList.h" + +#ifdef SHORT_NAMES +#define HTAApGrD HTAA_parseGroupDef +#define HTAArGrR HTAA_resolveGroupReferences +#define HTAApGrD HTAA_printGroupDef +#define HTAAGD_d GroupDef_delete +#define HTAAuIIG HTAA_userAndInetInGroup +#endif /* SHORT_NAMES */ + +typedef HTList GroupDefList; +typedef HTList ItemList; + +typedef struct { + char * group_name; + ItemList * item_list; +} GroupDef; + + +/* +** Access Authorization failure reasons +*/ +typedef enum { + HTAA_OK, /* 200 OK */ + HTAA_OK_GATEWAY, /* 200 OK, acting as a gateway */ + HTAA_NO_AUTH, /* 401 Unauthorized, not authenticated */ + HTAA_NOT_MEMBER, /* 401 Unauthorized, not authorized */ + HTAA_IP_MASK, /* 403 Forbidden by IP mask */ + HTAA_BY_RULE, /* 403 Forbidden by rule */ + HTAA_NO_ACL, /* 403 Forbidden, ACL non-existent */ + HTAA_NO_ENTRY, /* 403 Forbidden, no ACL entry */ + HTAA_SETUP_ERROR, /* 403 Forbidden, server setup error */ + HTAA_DOTDOT, /* 403 Forbidden, URL with /../ illegal */ + HTAA_HTBIN, /* 403 Forbidden, /htbin not enabled */ + HTAA_NOT_FOUND /* 404 Not found, or read protected */ +} HTAAFailReasonType; + +/* + +Group definition grammar + + string + "sequence of alphanumeric characters" + + user_name + string + + group_name + string + + group_ref + group_name + + user_def + user_name | group_ref + + user_def_list + user_def { ',' user_def } + + user_part + user_def | '(' user_def_list ')' + + templ + + "sequence of alphanumeric characters and '*'s" + + ip_number_mask + templ '.' templ '.' templ '.' templ + + domain_name_mask + templ { '.' templ } + + address + + ip_number_mask | domain_name_mask + + address_def + + address + + address_def_list + address_def { ',' address_def } + + address_part + address_def | '(' address_def_list ')' + + item + [user_part] ['@' address_part] + + item_list + item { ',' item } + + group_def + item_list + + group_decl + group_name ':' group_def + + PARSE GROUP DEFINITION + + */ + +PUBLIC GroupDef *HTAA_parseGroupDef PARAMS((FILE * fp)); +/* + +Fill in Pointers to referenced Group Definitions in a Group Definition + + References to groups (by their name) are resolved from group_def_list and pointers to + those structures are added to group_def. + + */ + +PUBLIC void HTAA_resolveGroupReferences PARAMS((GroupDef * group_def, + GroupDefList * group_def_list)); +/* + +Read Group File (and do caching) + + If group file is already in cache returns a pointer to previously read group definition + list. + + */ + +PUBLIC GroupDefList *HTAA_readGroupFile PARAMS((CONST char * filename)); +/* + +Delete Group Definition + + Groups in cache should never be freed by this function. This should only be used to + free group definitions read by HTAA_parseGroupDef. + + */ + +PUBLIC void GroupDef_delete PARAMS((GroupDef * group_def)); +/* + +Print Out Group Definition (for trace purposes) + + */ + +PUBLIC void HTAA_printGroupDef PARAMS((GroupDef * group_def)); +/* + +Does a User Belong to a Given Set of Groups + + This function checks both the username and the internet address. + + */ + +/* PUBLIC HTAA_userAndInetInGroup() +** CHECK IF USER BELONGS TO TO A GIVEN GROUP +** AND THAT THE CONNECTION COMES FROM AN +** ADDRESS THAT IS ALLOWED BY THAT GROUP +** ON ENTRY: +** group the group definition structure. +** username connecting user. +** ip_number browser host IP number, optional. +** ip_name browser host IP name, optional. +** However, one of ip_number or ip_name +** must be given. +** ON EXIT: +** returns HTAA_IP_MASK, if IP address mask was +** reason for failing. +** HTAA_NOT_MEMBER, if user does not belong +** to the group. +** HTAA_OK if both IP address and user are ok. +*/ +PUBLIC HTAAFailReasonType HTAA_userAndInetInGroup PARAMS((GroupDef * group, + char * username, + char * ip_number, + char * ip_name)); +/* + + */ + +#endif /* not HTGROUP_H */ +/* + + End of file HTGroup.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.c new file mode 100644 index 00000000000..726380a6f02 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.c @@ -0,0 +1,157 @@ +#include "HTUtils.h" +#include "tcp.h" /* for standard io */ + +#include "HTHistory.h" + +#include "LYLeaks.h" + +static HTList * history; /* List of visited anchors */ + + +/* Navigation +** ========== +*/ + +/* Record the jump to an anchor +** ---------------------------- +*/ + +void HTHistory_record + ARGS1 (HTAnchor *,destination) +{ + if (destination) { + if (! history) + history = HTList_new(); + HTList_addObject (history, destination); + } +} + +/* Go back in history (find the last visited node) +** ------------------ +*/ + +HTAnchor * HTHistory_backtrack + NOARGS /* FIXME: Should we add a `sticky' option ? */ +{ + if (HTHistory_canBacktrack()) + HTList_removeLastObject(history); + return(HTAnchor *)HTList_lastObject(history); /* is Home if can't backtrack */ +} + +BOOL HTHistory_canBacktrack + NOARGS +{ + return (HTList_objectAt (history, 1) != NULL); +} + +/* Browse through references in the same parent node +** ------------------------------------------------- +** +** Take the n-th child's link after or before the one we took to get here. +** Positive offset means go towards most recently added children. +*/ + +HTAnchor * HTHistory_moveBy + ARGS1 (int,offset) +{ + HTAnchor * last = (HTAnchor *)HTList_objectAt (history, 1); + if (! last) + return NULL; /* No last visited node */ + if (last != (HTAnchor *) last->parent) { /* Was a child */ + HTList * kids = last->parent->children; + int i = HTList_indexOf (kids, last); + HTAnchor * nextOne = (HTAnchor *)HTList_objectAt (kids, i - offset); + if (nextOne) { + HTAnchor * destination = HTAnchor_followMainLink (nextOne); + if (destination) { + HTList_removeLastObject (history); + HTList_removeLastObject (history); + HTList_addObject (history, nextOne); + HTList_addObject (history, destination); + } + return destination; + } else { + if (TRACE) fprintf(stderr, + "HTHistory_moveBy: offset by %+d goes out of list %p.\n", + offset, (void*)kids); + return NULL; + } + } else { /* Was a parent */ + return NULL; /* FIXME we could possibly follow the next link... */ + } +} + +BOOL HTHistory_canMoveBy + ARGS1 (int,offset) +{ + HTAnchor * last = (HTAnchor *)HTList_objectAt (history, 1); + if (! last) + return NO; /* No last visited node */ + if (last != (HTAnchor *) last->parent) { /* Was a child */ + HTList * kids = last->parent->children; + int i = HTList_indexOf (kids, last); + return (HTList_objectAt (kids, i - offset) != NULL); + } else { /* Was a parent */ + return NO; /* FIXME we could possibly follow the next link... */ + } +} + + +/* Retrieval +** ========= +*/ + +/* Read numbered visited anchor (1 is the oldest) +** ---------------------------- +*/ + +HTAnchor * HTHistory_read + ARGS1 (int,number) +{ + return (HTAnchor *)HTList_objectAt(history, HTList_count (history) - number); +} + + +/* Recall numbered visited anchor (1 is the oldest) +** ------------------------------ +** This reads the anchor and stores it again in the list, except if last. +*/ + +HTAnchor * HTHistory_recall + ARGS1 (int,number) +{ + HTAnchor * destination = + (HTAnchor *)HTList_objectAt (history, HTList_count (history) - number); + if (destination && destination != (HTAnchor *)HTList_lastObject (history)) + HTList_addObject (history, destination); + return destination; +} + +/* Number of Anchors stored +** ------------------------ +** +** This is needed in order to check the validity of certain commands +** for menus, etc. +(not needed for now. Use canBacktrack, etc.) +int HTHistory_count + NOARGS +{ + return HTList_count (history); +} +*/ + +/* Change last history entry +** ------------------------- +** +** Sometimes we load a node by one anchor but leave by a different +** one, and it is the one we left from which we want to remember. +*/ + +void HTHistory_leavingFrom + ARGS1 (HTAnchor *,anchor) +{ + if (HTList_removeLastObject (history)) + HTList_addObject (history, anchor); + else + if (TRACE) fprintf(stderr, "HTHistory_leavingFrom: empty history !\n"); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.h new file mode 100644 index 00000000000..a93781e96d5 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.h @@ -0,0 +1,112 @@ +/* */ + +#ifndef HTHISTORY_H +#define HTHISTORY_H + +#include "HTAnchor.h" + +#ifdef SHORT_NAMES +#define HTHistory_record HTHiReco +#define HTHistory_backtrack HTHiBack +#define HTHistory_canBacktrack HTHiCaBa +#define HTHistory_moveBy HTHiMoBy +#define HTHistory_canMoveBy HTHiCaMo +#define HTHistory_read HTHiRead +#define HTHistory_recall HTHiReca +#define HTHistory_count HTHiCoun +#define HTHistory_leavingFrom HTHiLeFr +#endif + +/* Navigation +** ========== +*/ + +/* Record the jump to an anchor +** ---------------------------- +*/ + +extern void HTHistory_record + PARAMS( + (HTAnchor * destination) + ); + +/* Go back in history (find the last visited node) +** ------------------ +*/ + +extern HTAnchor * HTHistory_backtrack + NOPARAMS; /* FIXME: Should we add a `sticky' option ? */ + +extern BOOL HTHistory_canBacktrack + NOPARAMS; + +/* Browse through references in the same parent node +** ------------------------------------------------- +** +** Take the n-th child's link after or before the one we took to get here. +** Positive offset means go towards most recently added children. +*/ + +extern HTAnchor * HTHistory_moveBy + PARAMS( + (int offset) + ); + +extern BOOL HTHistory_canMoveBy + PARAMS( + (int offset) + ); + +#define HTHistory_next (HTHistory_moveBy (+1)) +#define HTHistory_canNext (HTHistory_canMoveBy (+1)) +#define HTHistory_previous (HTHistory_moveBy (-1)) +#define HTHistory_canPrevious (HTHistory_canMoveBy (-1)) + + +/* Retrieval +** ========= +*/ + +/* Read numbered visited anchor (1 is the oldest) +** ---------------------------- +*/ + +extern HTAnchor * HTHistory_read + PARAMS( + (int number) + ); + +/* Recall numbered visited anchor (1 is the oldest) +** ------------------------------ +** This reads the anchor and stores it again in the list, except if last. +*/ + +extern HTAnchor * HTHistory_recall + PARAMS( + (int number) + ); + +/* Number of Anchors stored +** ------------------------ +** +** This is needed in order to check the validity of certain commands +** for menus, etc. +(not needed for now. Use canBacktrack, etc.) +extern int HTHistory_count NOPARAMS; +*/ + +/* Change last history entry +** ------------------------- +** +** Sometimes we load a node by one anchor but leave by a different +** one, and it is the one we left from which we want to remember. +*/ +extern void HTHistory_leavingFrom + PARAMS( + (HTAnchor * anchor) + ); + +#endif /* HTHISTORY_H */ +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.c new file mode 100644 index 00000000000..764da7b556d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.c @@ -0,0 +1,176 @@ +/* Configuration-specific Initialialization HTInit.c +** ---------------------------------------- +*/ + +/* Define a basic set of suffixes and presentations +** ------------------------------------------------ +** +*/ + +#include "HTUtils.h" + +/* Implements: +*/ +#include "HTInit.h" + +#include "HTML.h" +#include "HTPlain.h" +#include "HTMLGen.h" +#include "HTFile.h" +#include "HTFormat.h" +#include "HTMIME.h" +#include "HTWSRC.h" +#include "HTFWriter.h" + +#include "LYLeaks.h" + +PUBLIC void HTFormatInit NOARGS +{ +#ifdef NeXT + HTSetPresentation("application/postscript", "open %s", 1.0, 2.0, 0.0, 0); + /* The following needs the GIF previewer -- you might not have it. */ + HTSetPresentation("image/gif", "open %s", 0.3, 2.0, 0.0, 0); + HTSetPresentation("image/x-tiff", "open %s", 1.0, 2.0, 0.0, 0); + HTSetPresentation("audio/basic", "open %s", 1.0, 2.0, 0.0, 0); + HTSetPresentation("*", "open %s", 1.0, 0.0, 0.0, 0); +#else + if (getenv("DISPLAY")) { /* Must have X11 */ + HTSetPresentation("application/postscript", "ghostview %s", + 1.0, 3.0, 0.0, 0); + HTSetPresentation("image/gif", "xv %s", 1.0, 3.0, 0.0, 0); + HTSetPresentation("image/x-tiff", "xv %s", 1.0, 3.0, 0.0, 0); + HTSetPresentation("image/jpeg", "xv %s", 1.0, 3.0, 0.0, 0); + } +#endif + HTSetConversion("www/mime", "*", HTMIMEConvert, + 1.0, 0.0, 0.0, 0); + HTSetConversion("application/x-wais-source","*", HTWSRCConvert, + 1.0, 0.0, 0.0, 0); + HTSetConversion("text/html", "text/x-c", HTMLToC, + 0.5, 0.0, 0.0, 0); + HTSetConversion("text/html", "text/plain", HTMLToPlain, + 0.5, 0.0, 0.0, 0); + HTSetConversion("text/html", "www/present", HTMLPresent, + 1.0, 0.0, 0.0, 0); + HTSetConversion("text/plain", "text/html", HTPlainToHTML, + 1.0, 0.0, 0.0, 0); + HTSetConversion("text/plain", "www/present", HTPlainPresent, + 1.0, 0.0, 0.0, 0); + HTSetConversion("application/octet-stream", "www/present", HTSaveLocally, + 0.1, 0.0, 0.0, 0); + HTSetConversion("www/unknown", "www/present", HTSaveLocally, + 0.3, 0.0, 0.0, 0); + HTSetConversion("www/source", "www/present", HTSaveLocally, + 0.3, 0.0, 0.0, 0); +} + + + +/* Define a basic set of suffixes +** ------------------------------ +** +** The LAST suffix for a type is that used for temporary files +** of that type. +** The quality is an apriori bias as to whether the file should be +** used. Not that different suffixes can be used to represent files +** which are of the same format but are originals or regenerated, +** with different values. +*/ + +#ifndef NO_INIT +PUBLIC void HTFileInit NOARGS +{ + /* Suffix Contenet-Type Content-Encoding Quality */ + + HTSetSuffix(".mime", "www/mime", "8bit", 1.0); /* Internal -- MIME is */ + /* not recursive */ + HTSetSuffix(".bin", "application/octet-stream", "binary", 1.0); /* Uninterpreted binary */ + HTSetSuffix(".oda", "application/oda", "binary", 1.0); + HTSetSuffix(".pdf", "application/pdf", "binary", 1.0); + HTSetSuffix(".ai", "application/postscript", "8bit", 0.5); /* Adobe Illustrator */ + HTSetSuffix(".PS", "application/postscript", "8bit", 0.8); /* PostScript */ + HTSetSuffix(".eps", "application/postscript", "8bit", 0.8); + HTSetSuffix(".ps", "application/postscript", "8bit", 0.8); + HTSetSuffix(".rtf", "application/x-rtf", "7bit", 1.0); /* RTF */ + HTSetSuffix(".Z", "application/x-compressed", "binary", 1.0); /* Compressed data */ + HTSetSuffix(".csh", "application/x-csh", "7bit", 0.5); /* C-shell script */ + HTSetSuffix(".dvi", "application/x-dvi", "binary", 1.0); /* TeX DVI */ + HTSetSuffix(".hdf", "application/x-hdf", "binary", 1.0); /* NCSA HDF data file */ + HTSetSuffix(".latex", "application/x-latex", "8bit", 1.0); /* LaTeX source */ + HTSetSuffix(".nc", "application/x-netcdf", "binary", 1.0); /* Unidata netCDF data */ + HTSetSuffix(".cdf", "application/x-netcdf", "binary", 1.0); + HTSetSuffix(".sh", "application/x-sh", "7bit", 0.5); /* Shell-script */ + HTSetSuffix(".tcl", "application/x-tcl", "7bit", 0.5); /* TCL-script */ + HTSetSuffix(".tex", "application/x-tex", "8bit", 1.0); /* TeX source */ + HTSetSuffix(".texi", "application/x-texinfo", "7bit", 1.0); /* Texinfo */ + HTSetSuffix(".texinfo","application/x-texinfo", "7bit", 1.0); + HTSetSuffix(".t", "application/x-troff", "7bit", 0.5); /* Troff */ + HTSetSuffix(".roff", "application/x-troff", "7bit", 0.5); + HTSetSuffix(".tr", "application/x-troff", "7bit", 0.5); + HTSetSuffix(".man", "application/x-troff-man", "7bit", 0.5); /* Troff with man macros*/ + HTSetSuffix(".me", "application/x-troff-me", "7bit", 0.5); /* Troff with me macros */ + HTSetSuffix(".ms", "application/x-troff-ms", "7bit", 0.5); /* Troff with ms macros */ + HTSetSuffix(".src", "application/x-wais-source", "7bit", 1.0); /* WAIS source */ + HTSetSuffix(".zip", "application/zip", "binary", 1.0); /* PKZIP */ + HTSetSuffix(".bcpio", "application/x-bcpio", "binary", 1.0); /* Old binary CPIO */ + HTSetSuffix(".cpio", "application/x-cpio", "binary", 1.0); /* POSIX CPIO */ + HTSetSuffix(".gtar", "application/x-gtar", "binary", 1.0); /* Gnu tar */ + HTSetSuffix(".shar", "application/x-shar", "8bit", 1.0); /* Shell archive */ + HTSetSuffix(".sv4cpio","application/x-sv4cpio", "binary", 1.0); /* SVR4 CPIO */ + HTSetSuffix(".sv4crc", "application/x-sv4crc", "binary", 1.0); /* SVR4 CPIO with CRC */ + HTSetSuffix(".tar", "application/x-tar", "binary", 1.0); /* 4.3BSD tar */ + HTSetSuffix(".ustar", "application/x-ustar", "binary", 1.0); /* POSIX tar */ + HTSetSuffix(".snd", "audio/basic", "binary", 1.0); /* Audio */ + HTSetSuffix(".au", "audio/basic", "binary", 1.0); + HTSetSuffix(".aiff", "audio/x-aiff", "binary", 1.0); + HTSetSuffix(".aifc", "audio/x-aiff", "binary", 1.0); + HTSetSuffix(".aif", "audio/x-aiff", "binary", 1.0); + HTSetSuffix(".wav", "audio/x-wav", "binary", 1.0); /* Windows+ WAVE format */ + HTSetSuffix(".gif", "image/gif", "binary", 1.0); /* GIF */ + HTSetSuffix(".ief", "image/ief", "binary", 1.0); /* Image Exchange fmt */ + HTSetSuffix(".jpg", "image/jpeg", "binary", 1.0); /* JPEG */ + HTSetSuffix(".JPG", "image/jpeg", "binary", 1.0); + HTSetSuffix(".JPE", "image/jpeg", "binary", 1.0); + HTSetSuffix(".jpe", "image/jpeg", "binary", 1.0); + HTSetSuffix(".JPEG", "image/jpeg", "binary", 1.0); + HTSetSuffix(".jpeg", "image/jpeg", "binary", 1.0); + HTSetSuffix(".tif", "image/tiff", "binary", 1.0); /* TIFF */ + HTSetSuffix(".tiff", "image/tiff", "binary", 1.0); + HTSetSuffix(".ras", "image/cmu-raster", "binary", 1.0); + HTSetSuffix(".pnm", "image/x-portable-anymap", "binary", 1.0); /* PBM Anymap format */ + HTSetSuffix(".pbm", "image/x-portable-bitmap", "binary", 1.0); /* PBM Bitmap format */ + HTSetSuffix(".pgm", "image/x-portable-graymap", "binary", 1.0); /* PBM Graymap format */ + HTSetSuffix(".ppm", "image/x-portable-pixmap", "binary", 1.0); /* PBM Pixmap format */ + HTSetSuffix(".rgb", "image/x-rgb", "binary", 1.0); + HTSetSuffix(".xbm", "image/x-xbitmap", "binary", 1.0); /* X bitmap */ + HTSetSuffix(".xpm", "image/x-xpixmap", "binary", 1.0); /* X pixmap format */ + HTSetSuffix(".xwd", "image/x-xwindowdump", "binary", 1.0); /* X window dump (xwd) */ + HTSetSuffix(".html", "text/html", "8bit", 1.0); /* HTML */ + HTSetSuffix(".c", "text/plain", "7bit", 0.5); /* C source */ + HTSetSuffix(".h", "text/plain", "7bit", 0.5); /* C headers */ + HTSetSuffix(".C", "text/plain", "7bit", 0.5); /* C++ source */ + HTSetSuffix(".cc", "text/plain", "7bit", 0.5); /* C++ source */ + HTSetSuffix(".hh", "text/plain", "7bit", 0.5); /* C++ headers */ + HTSetSuffix(".m", "text/plain", "7bit", 0.5); /* Objective-C source */ + HTSetSuffix(".f90", "text/plain", "7bit", 0.5); /* Fortran 90 source */ + HTSetSuffix(".txt", "text/plain", "7bit", 0.5); /* Plain text */ + HTSetSuffix(".rtx", "text/richtext", "7bit", 1.0); /* MIME Richtext format */ + HTSetSuffix(".tsv", "text/tab-separated-values", "7bit", 1.0); /* Tab-separated values */ + HTSetSuffix(".etx", "text/x-setext", "7bit", 0.9); /* Struct Enchanced Txt */ + HTSetSuffix(".MPG", "video/mpeg", "binary", 1.0); /* MPEG */ + HTSetSuffix(".mpg", "video/mpeg", "binary", 1.0); + HTSetSuffix(".MPE", "video/mpeg", "binary", 1.0); + HTSetSuffix(".mpe", "video/mpeg", "binary", 1.0); + HTSetSuffix(".MPEG", "video/mpeg", "binary", 1.0); + HTSetSuffix(".mpeg", "video/mpeg", "binary", 1.0); + HTSetSuffix(".qt", "video/quicktime", "binary", 1.0); /* QuickTime */ + HTSetSuffix(".mov", "video/quicktime", "binary", 1.0); + HTSetSuffix(".avi", "video/x-msvideo", "binary", 1.0); /* MS Video for Windows */ + HTSetSuffix(".movie", "video/x-sgi-movie", "binary", 1.0); /* SGI "moviepalyer" */ + + HTSetSuffix("*.*", "application/octet-stream", "binary", 0.1); + HTSetSuffix("*", "text/plain", "7bit", 0.5); + +} +#endif /* NO_INIT */ + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.h new file mode 100644 index 00000000000..61c7d776a57 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.h @@ -0,0 +1,23 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTInit.html + INITIALISATION MODULE + + This module resisters all the plug & play software modules which will be used in the + program. This is for a browser. + + To override this, just copy it and link in your version befoe you link with the + library. + + Implemented by HTInit.c by default. + + */ +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +extern void HTFormatInit NOPARAMS; +extern void HTPreparsedFormatInit NOPARAMS; +extern void HTFileInit NOPARAMS; + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.c new file mode 100644 index 00000000000..268701704d1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.c @@ -0,0 +1,142 @@ + +/* MODULE HTLex.c +** LEXICAL ANALYSOR +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include "HTAAUtil.h" +#include "HTLex.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* +** Global variables +*/ +PUBLIC char HTlex_buffer[40]; /* Read lexical string */ +PUBLIC int HTlex_line = 1; /* Line number in source file */ + + +/* +** Module-wide variables +*/ +PRIVATE int lex_cnt; +PRIVATE BOOL lex_template; +PRIVATE LexItem lex_pushed_back = LEX_NONE; +PRIVATE FILE *cache = NULL; + + +PUBLIC void unlex ARGS1(LexItem, lex_item) +{ + lex_pushed_back = lex_item; +} + + +PUBLIC LexItem lex ARGS1(FILE *, fp) +{ + int ch; + + if (fp != cache) { /* This cache doesn't work ok because the system */ + cache = fp; /* often assign same FILE structure the next open */ + HTlex_line = 1; /* file. So, if there are syntax errors in setup */ + } /* files it may confuse things later on. */ + + if (lex_pushed_back != LEX_NONE) { + LexItem ret = lex_pushed_back; + lex_pushed_back = LEX_NONE; + return ret; + } + + lex_cnt = 0; + lex_template = NO; + + for(;;) { + switch (ch = getc(fp)) { + case EOF: + case ' ': + case '\t': + case '\r': + case '\n': + case ':': + case ',': + case '(': + case ')': + case '@': + if (lex_cnt > 0) { + if (ch != EOF) ungetc(ch,fp); + if (lex_template) return LEX_TMPL_STR; + else return LEX_ALPH_STR; + } + else switch(ch) { + case EOF: return LEX_EOF; break; + case '\n': + HTlex_line++; return LEX_REC_SEP; break; + case ':': return LEX_FIELD_SEP; break; + case ',': return LEX_ITEM_SEP; break; + case '(': return LEX_OPEN_PAREN; break; + case ')': return LEX_CLOSE_PAREN; break; + case '@': return LEX_AT_SIGN; break; + default: ; /* Leading white space ignored (SP,TAB,CR) */ + } + break; + default: + HTlex_buffer[lex_cnt++] = ch; + HTlex_buffer[lex_cnt] = '\0'; + if ('*' == ch) lex_template = YES; + } /* switch ch */ + } /* forever */ +} + + +PUBLIC char *lex_verbose ARGS1(LexItem, lex_item) +{ + static char msg[100]; + + switch (lex_item) { + case LEX_NONE: /* Internally used */ + return "NO-LEX-ITEM"; + break; + case LEX_EOF: /* End of file */ + return "end-of-file"; + break; + case LEX_REC_SEP: /* Record separator */ + return "record separator (newline)"; + break; + case LEX_FIELD_SEP: /* Field separator */ + return "field separator ':'"; + break; + case LEX_ITEM_SEP: /* List item separator */ + return "item separator ','"; + break; + case LEX_OPEN_PAREN: /* Group start tag */ + return "'('"; + break; + case LEX_CLOSE_PAREN: /* Group end tag */ + return "')'"; + break; + case LEX_AT_SIGN: /* Address qualifier */ + return "address qualifier '@'"; + break; + case LEX_ALPH_STR: /* Alphanumeric string */ + sprintf(msg, "alphanumeric string '%s'", HTlex_buffer); + return msg; + break; + case LEX_TMPL_STR: /* Template string */ + sprintf(msg, "template string '%s'", HTlex_buffer); + return msg; + break; + default: + return "UNKNOWN-LEX-ITEM"; + break; + } +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.h new file mode 100644 index 00000000000..5895579bccb --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.h @@ -0,0 +1,64 @@ +/* LEXICAL ANALYSOR (MAINLY FOR CONFIG FILES) + + */ + +#ifndef HTLEX_H +#define HTLEX_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + + +#ifdef SHORT_NAMES +#define lex_verb lex_verbose +#endif /*SHORT_NAMES*/ + + +typedef enum { + LEX_NONE, /* Internally used */ + LEX_EOF, /* End of file */ + LEX_REC_SEP, /* Record separator */ + LEX_FIELD_SEP, /* Field separator */ + LEX_ITEM_SEP, /* List item separator */ + LEX_OPEN_PAREN, /* Group start tag */ + LEX_CLOSE_PAREN, /* Group end tag */ + LEX_AT_SIGN, /* Address qualifier */ + LEX_ALPH_STR, /* Alphanumeric string */ + LEX_TMPL_STR /* Template string */ +} LexItem; + +extern char HTlex_buffer[]; /* Read lexical string */ +extern int HTlex_line; /* Line number in source file */ + +/* + +Get Next Lexical Item + + If returns LEX_ALPH_STR or LEX_TMPL_STR the string is in global buffer lex_buffer. + + */ + +PUBLIC LexItem lex PARAMS((FILE * fp)); +/* + +Push Back Latest Item + + */ + +PUBLIC void unlex PARAMS((LexItem lex_item)); +/* + +Get the Name for Lexical Item + + */ + +PUBLIC char *lex_verbose PARAMS((LexItem lex_item)); +/* + + */ + +#endif /* not HTLEX_H */ +/* + + End of file HTLex.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.c new file mode 100644 index 00000000000..839e961ddb5 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.c @@ -0,0 +1,314 @@ +/* A small List class HTList.c +** ================== +** +** A list is represented as a sequence of linked nodes of type HTList. +** The first node is a header which contains no object. +** New nodes are inserted between the header and the rest of the list. +*/ + +#include "HTUtils.h" +#include "HTList.h" + +/*#include <stdio.h> included by HTUtils.h -- FM *//* joe@athena, TBL 921019 */ + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + + +/* Create list. +*/ +PUBLIC HTList * HTList_new NOARGS +{ + HTList *newList; + + if ((newList = (HTList *)calloc(1, sizeof(HTList))) == NULL) + outofmem(__FILE__, "HTList_new"); + + newList->object = NULL; + newList->next = NULL; + + return newList; +} + + +/* Delete list. +*/ +PUBLIC void HTList_delete ARGS1( + HTList *, me) +{ + HTList *current; + + while ((current = me)) { + me = me->next; + FREE (current); + } + + return; +} + + +/* Add object to START of list (so it is pointed to by the head). +*/ +PUBLIC void HTList_addObject ARGS2( + HTList *, me, + void *, newObject) +{ + HTList *newNode; + + if (me) { + if ((newNode = (HTList *)calloc(1, sizeof(HTList))) == NULL) + outofmem(__FILE__, "HTList_addObject"); + newNode->object = newObject; + newNode->next = me->next; + me->next = newNode; + + } else if (TRACE) { + fprintf(stderr, + "HTList: Trying to add object %p to a nonexisting list\n", + newObject); + } + + return; +} + + +/* Append object to END of list (furthest from the head). +*/ +PUBLIC void HTList_appendObject ARGS2( + HTList *, me, + void *, newObject) +{ + HTList *temp = me; + + if (temp && newObject) { + while (temp->next) + temp = temp->next; + HTList_addObject(temp, newObject); + } + + return; +} + + +/* Insert an object into the list at a specified position. +** If position is 0, this places the object at the head of the list +** and is equivalent to HTList_addObject(). +*/ +PUBLIC void HTList_insertObjectAt ARGS3( + HTList *, me, + void *, newObject, + int, pos) +{ + HTList * newNode; + HTList * temp = me; + HTList * prevNode; + int Pos = pos; + + if (!temp) { + if (TRACE) { + fprintf(stderr, + "HTList: Trying to add object %p to a nonexisting list\n", + newObject); + } + return; + } + if (Pos < 0) { + Pos = 0; + if (TRACE) { + fprintf(stderr, + "HTList: Treating negative object position %d as %d.\n", + pos, Pos); + } + } + + prevNode = temp; + while ((temp = temp->next)) { + if (Pos == 0) { + if ((newNode = (HTList *)calloc(1, sizeof(HTList))) == NULL) + outofmem(__FILE__, "HTList_addObjectAt"); + newNode->object = newObject; + newNode->next = temp; + if (prevNode) + prevNode->next = newNode; + return; + } + prevNode = temp; + Pos--; + } + if (Pos >= 0) + HTList_addObject(prevNode, newObject); + + return; +} + + +/* Remove specified object from list. +*/ +PUBLIC BOOL HTList_removeObject ARGS2( + HTList *, me, + void *, oldObject) +{ + HTList *temp = me; + HTList *prevNode; + + if (temp && oldObject) { + while (temp->next) { + prevNode = temp; + temp = temp->next; + if (temp->object == oldObject) { + prevNode->next = temp->next; + FREE (temp); + return YES; /* Success */ + } + } + } + return NO; /* object not found or NULL list */ +} + + +/* Remove object at a given position in the list, where 0 is the +** object pointed to by the head (returns a pointer to the element +** (->object) for the object, and NULL if the list is empty, or +** if it doesn't exist - Yuk!). +*/ +PUBLIC void * HTList_removeObjectAt ARGS2( + HTList *, me, + int, position) +{ + HTList * temp = me; + HTList * prevNode; + int pos = position; + + if (!temp || pos < 0) + return NULL; + + prevNode = temp; + while ((temp = temp->next)) { + if (pos == 0) { + prevNode->next = temp->next; + prevNode = temp; + FREE(temp); + return prevNode->object; + } + prevNode = temp; + pos--; + } + + return NULL; /* Reached the end of the list */ +} + + +/* Remove object from START of list (the Last one inserted +** via HTList_addObject(), and pointed to by the head). +*/ +PUBLIC void * HTList_removeLastObject ARGS1( + HTList *, me) +{ + HTList * lastNode; + void * lastObject; + + if (me && me->next) { + lastNode = me->next; + lastObject = lastNode->object; + me->next = lastNode->next; + FREE (lastNode); + return lastObject; + + } else { /* Empty list */ + return NULL; + } +} + + +/* Remove object from END of list (the First one inserted +** via HTList_addObject(), and furthest from the head). +*/ +PUBLIC void * HTList_removeFirstObject ARGS1( + HTList *, me) +{ + HTList * temp = me; + HTList * prevNode; + void *firstObject; + + if (!temp) + return NULL; + + prevNode = temp; + if (temp->next) { + while (temp->next) { + prevNode = temp; + temp = temp->next; + } + firstObject = temp->object; + prevNode->next = NULL; + FREE (temp); + return firstObject; + + } else { /* Empty list */ + return NULL; + } +} + + +/* Determine total number of objects in the list, +** not counting the head. +*/ +PUBLIC int HTList_count ARGS1( + HTList *, me) +{ + HTList * temp = me; + int count = 0; + + if (temp) + while ((temp = temp->next)) + count++; + + return count; +} + + +/* Determine position of an object in the list (a value of 0 +** means it is pointed to by the head; returns -1 if not found). +*/ +PUBLIC int HTList_indexOf ARGS2( + HTList *, me, + void *, object) +{ + HTList * temp = me; + int position = 0; + + if (temp) { + while ((temp = temp->next)) { + if (temp->object == object) + return position; + position++; + } + } + + return -1; /* Object not in the list */ +} + + +/* Return pointer to the object at a specified position in the list, +** where 0 is the object pointed to by the head (returns NULL if +** the list is empty, or if it doesn't exist - Yuk!). +*/ +PUBLIC void * HTList_objectAt ARGS2( + HTList *, me, + int, position) +{ + HTList * temp = me; + int pos = position; + + if (!temp || pos < 0) + return NULL; + + while ((temp = temp->next)) { + if (pos == 0) + return temp->object; + pos--; + } + + return NULL; /* Reached the end of the list */ +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.h new file mode 100644 index 00000000000..89c0e62bbc9 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.h @@ -0,0 +1,146 @@ + +/* List object +** +** The list object is a generic container for storing collections +** of things in order. +*/ +#ifndef HTLIST_H +#define HTLIST_H + +#ifndef HTUTILS_H +#include "HTUtils.h" /* for BOOL type and PARAMS and ARGS*/ +#endif /* HTUTILS_H */ + +typedef struct _HTList HTList; + +struct _HTList { + void * object; + HTList * next; +}; + +#ifdef SHORT_NAMES +#define HTList_new HTLiNew +#define HTList_delete HTLiDele +#define HTList_addObject HTLiAdOb +#define HTList_removeObject HTLiReOb +#define HTList_removeObjectAt HTLiReAt +#define HTList_removeLastObject HTLiReLa +#define HTList_removeFirstObject HTLiReFi +#define HTList_count HTLiCoun +#define HTList_indexOf HTLiInOf +#define HTList_objectAt HTLiObAt +#endif /* SHORT_NAMES */ + + +/* Fast macro to traverse a list. Call it first with copy of the list +** header. It returns the first object and increments the passed list +** pointer. Call it with the same variable until it returns NULL. +*/ +#define HTList_nextObject(me) \ + ((me) && ((me) = (me)->next) ? (me)->object : NULL) + + +/* Macro to find object pointed to by the head (returns NULL +** if list is empty, OR if it doesn't exist - Yuk!) +*/ +#define HTList_lastObject(me) \ + ((me) && (me)->next ? (me)->next->object : NULL) + + +/* Macro to check if a list is empty (or doesn't exist - Yuk!) +*/ +#define HTList_isEmpty(me) ((me) ? ((me)->next == NULL) : YES) + + +/* Create list. +*/ +extern HTList * HTList_new NOPARAMS; + + +/* Delete list. +*/ +extern void HTList_delete PARAMS(( + HTList * me)); + + +/* Add object to START of list (so it is pointed to by the head). +*/ +extern void HTList_addObject PARAMS(( + HTList * me, + void * newObject)); + + +/* Append object to END of list (furthest from the head). +*/ +extern void HTList_appendObject PARAMS(( + HTList * me, + void * newObject)); + + +/* Insert an object into the list at a specified position. +** If position is 0, this places the object at the head of the list +** and is equivalent to HTList_addObject(). +*/ +extern void HTList_insertObjectAt PARAMS(( + HTList * me, + void * newObject, + int pos)); + + +/* Remove specified object from list. +*/ +extern BOOL HTList_removeObject PARAMS(( + HTList * me, + void * oldObject)); + + +/* Remove object at a given position in the list, where 0 is the +** object pointed to by the head (returns a pointer to the element +** (->object) for the object, and NULL if the list is empty, or +** if it doesn't exist - Yuk!). +*/ +extern void * HTList_removeObjectAt PARAMS(( + HTList * me, + int position)); + + +/* Remove object from START of list (the Last one inserted +** via HTList_addObject(), and pointed to by the head). +*/ +extern void * HTList_removeLastObject PARAMS(( + HTList * me)); + + +/* Remove object from END of list (the First one inserted +** via HTList_addObject(), and furthest from the head). +*/ +extern void * HTList_removeFirstObject PARAMS(( + HTList * me)); + + +/* Determine total number of objects in the list, +** not counting the head. +*/ +extern int HTList_count PARAMS(( + HTList * me)); + + +/* Determine position of an object in the list (a value of 0 +** means it is pointed to by the head; returns -1 if not found). +*/ +extern int HTList_indexOf PARAMS(( + HTList * me, + void * object)); + + +/* Return pointer to the object at a specified position in the list, +** where 0 is the object pointed to by the head (returns NULL if +** the list is empty, or if it doesn't exist - Yuk!). +*/ +extern void * HTList_objectAt PARAMS(( + HTList * me, + int position)); + + +#endif /* HTLIST_H */ + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.c new file mode 100644 index 00000000000..1041bdff789 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.c @@ -0,0 +1,2599 @@ +/* MIME Message Parse HTMIME.c +** ================== +** +** This is RFC 1341-specific code. +** The input stream pushed into this parser is assumed to be +** stripped on CRs, ie lines end with LF, not CR LF. +** (It is easy to change this except for the body part where +** conversion can be slow.) +** +** History: +** Feb 92 Written Tim Berners-Lee, CERN +** +*/ +#include "HTUtils.h" +#include "HTMIME.h" /* Implemented here */ +#include "HTAlert.h" +#include "HTCJK.h" +#include "UCMap.h" +#include "UCDefs.h" +#include "UCAux.h" + +#include "LYCharSets.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern CONST char *LYchar_set_names[]; +extern BOOLEAN LYRawMode; +extern BOOL HTPassEightBitRaw; +extern HTCJKlang HTCJK; + +extern void LYSetCookie PARAMS(( + CONST char * SetCookie, + CONST char * SetCookie2, + CONST char * address)); +extern time_t LYmktime PARAMS((char *string, BOOL absolute)); + + +/* MIME Object +** ----------- +*/ + +typedef enum _MIME_state { + MIME_TRANSPARENT, /* put straight through to target ASAP! */ + miBEGINNING_OF_LINE, /* first character and not a continuation */ + miA, + miACCEPT_RANGES, + miAGE, + miAL, + miALLOW, + miALTERNATES, + miC, + miCACHE_CONTROL, + miCO, + miCOOKIE, + miCON, + miCONNECTION, + miCONTENT_, + miCONTENT_BASE, + miCONTENT_DISPOSITION, + miCONTENT_ENCODING, + miCONTENT_FEATURES, + miCONTENT_L, + miCONTENT_LANGUAGE, + miCONTENT_LENGTH, + miCONTENT_LOCATION, + miCONTENT_MD5, + miCONTENT_RANGE, + miCONTENT_T, + miCONTENT_TRANSFER_ENCODING, + miCONTENT_TYPE, + miDATE, + miE, + miETAG, + miEXPIRES, + miKEEP_ALIVE, + miL, + miLAST_MODIFIED, + miLINK, + miLOCATION, + miP, + miPR, + miPRAGMA, + miPROXY_AUTHENTICATE, + miPUBLIC, + miRETRY_AFTER, + miS, + miSAFE, + miSE, + miSERVER, + miSET_COOKIE, + miSET_COOKIE1, + miSET_COOKIE2, + miT, + miTITLE, + miTRANSFER_ENCODING, + miU, + miUPGRADE, + miURI, + miV, + miVARY, + miVIA, + miW, + miWARNING, + miWWW_AUTHENTICATE, + miSKIP_GET_VALUE, /* Skip space then get value */ + miGET_VALUE, /* Get value till white space */ + miJUNK_LINE, /* Ignore the rest of this folded line */ + miNEWLINE, /* Just found a LF .. maybe continuation */ + miCHECK, /* check against check_pointer */ + MIME_NET_ASCII, /* Translate from net ascii */ + MIME_IGNORE /* Ignore entire file */ + /* TRANSPARENT and IGNORE are defined as stg else in _WINDOWS */ +} MIME_state; + +#define VALUE_SIZE 1024 /* @@@@@@@ Arbitrary? */ +struct _HTStream { + CONST HTStreamClass * isa; + + BOOL net_ascii; /* Is input net ascii? */ + MIME_state state; /* current state */ + MIME_state if_ok; /* got this state if match */ + MIME_state field; /* remember which field */ + MIME_state fold_state; /* state on a fold */ + CONST char * check_pointer; /* checking input */ + + char * value_pointer; /* storing values */ + char value[VALUE_SIZE]; + + HTParentAnchor * anchor; /* Given on creation */ + HTStream * sink; /* Given on creation */ + + char * boundary; /* For multipart */ + char * set_cookie; /* Set-Cookie */ + char * set_cookie2; /* Set-Cookie2 */ + + HTFormat encoding; /* Content-Transfer-Encoding */ + char * compression_encoding; + HTFormat format; /* Content-Type */ + HTStream * target; /* While writing out */ + HTStreamClass targetClass; + + HTAtom * targetRep; /* Converting into? */ +}; + +/* +** This function is for trimming off any paired +** open- and close-double quotes from header values. +** It does not parse the string for embedded quotes, +** and will not modify the string unless both the +** first and last characters are double-quotes. - FM +*/ +PUBLIC void HTMIME_TrimDoubleQuotes ARGS1( + char *, value) +{ + int i; + char *cp = value; + + if (!(cp && *cp) || *cp != '\"') + return; + + i = strlen(cp); + if (cp[(i - 1)] != '\"') + return; + else + cp[(i - 1)] = '\0'; + + for (i = 0; value[i]; i++) + value[i] = cp[(i +1)]; +} + +/*_________________________________________________________________________ +** +** A C T I O N R O U T I N E S +*/ + +/* Character handling +** ------------------ +** +** This is a FSM parser which is tolerant as it can be of all +** syntax errors. It ignores field names it does not understand, +** and resynchronises on line beginnings. +*/ +PRIVATE void HTMIME_put_character ARGS2( + HTStream *, me, + char, c) +{ + int i, j; + + if (me->state == MIME_TRANSPARENT) { + (*me->targetClass.put_character)(me->target, c);/* MUST BE FAST */ + return; + } + + /* + ** This slightly simple conversion just strips CR and turns LF to + ** newline. On unix LF is \n but on Mac \n is CR for example. + ** See NetToText for an implementation which preserves single CR or LF. + */ + if (me->net_ascii) { + c = FROMASCII(c); + if (c == CR) + return; + else if (c == LF) + c = '\n'; + } + + switch(me->state) { + + case MIME_IGNORE: + return; + + case MIME_TRANSPARENT: /* Not reached see above */ + (*me->targetClass.put_character)(me->target, c); + return; + + case MIME_NET_ASCII: + (*me->targetClass.put_character)(me->target, c); /* MUST BE FAST */ + return; + + case miNEWLINE: + if (c != '\n' && WHITE(c)) { /* Folded line */ + me->state = me->fold_state; /* pop state before newline */ + break; + } + + /* else Falls through */ + + case miBEGINNING_OF_LINE: + me->net_ascii = YES; + switch (c) { + case 'a': + case 'A': + me->state = miA; + if (TRACE) + fprintf(stderr, + "HTMIME: Got 'A' at beginning of line, state now A\n"); + break; + + case 'c': + case 'C': + me->state = miC; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'C' at beginning of line, state now C\n"); + break; + + case 'd': + case 'D': + me->check_pointer = "ate:"; + me->if_ok = miDATE; + me->state = miCHECK; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'D' at beginning of line, checking for 'ate:'\n"); + break; + + case 'e': + case 'E': + me->state = miE; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'E' at beginning of line, state now E\n"); + break; + + case 'k': + case 'K': + me->check_pointer = "eep-alive:"; + me->if_ok = miKEEP_ALIVE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Got 'K' at beginning of line, checking for 'eep-alive:'\n"); + break; + + case 'l': + case 'L': + me->state = miL; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'L' at beginning of line, state now L\n"); + break; + + case 'p': + case 'P': + me->state = miP; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'P' at beginning of line, state now P\n"); + break; + + case 'r': + case 'R': + me->check_pointer = "etry-after:"; + me->if_ok = miRETRY_AFTER; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Got 'R' at beginning of line, checking for 'etry-after'\n"); + break; + + case 's': + case 'S': + me->state = miS; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'S' at beginning of line, state now S\n"); + break; + + case 't': + case 'T': + me->state = miT; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'T' at beginning of line, state now T\n"); + break; + + case 'u': + case 'U': + me->state = miU; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'U' at beginning of line, state now U\n"); + break; + + case 'v': + case 'V': + me->state = miV; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'V' at beginning of line, state now V\n"); + break; + + case 'w': + case 'W': + me->state = miW; + if (TRACE) + fprintf (stderr, + "HTMIME: Got 'W' at beginning of line, state now W\n"); + break; + + case '\n': /* Blank line: End of Header! */ + { + me->net_ascii = NO; + if (strchr(HTAtom_name(me->format), ';') != NULL) { + char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; + + if (TRACE) + fprintf(stderr, + "HTMIME: Extended MIME Content-Type is %s\n", + HTAtom_name(me->format)); + StrAllocCopy(cp, HTAtom_name(me->format)); + /* + ** Note that the Content-Type value was converted + ** to lower case when we loaded into me->format, + ** but there may have been a mixed or upper-case + ** atom, so we'll force lower-casing again. We + ** also stripped spaces and double-quotes, but + ** we'll make sure they're still gone from any + ** charset parameter we check. - FM + */ + for (i = 0; cp[i]; i++) + cp[i] = TOLOWER(cp[i]); + if ((cp1 = strchr(cp, ';')) != NULL) { + BOOL chartrans_ok = NO; + if ((cp2 = strstr(cp1, "charset")) != NULL) { + int chndl; + + cp2 += 7; + while (*cp2 == ' ' || *cp2 == '=' || *cp2 == '\"') + cp2++; + StrAllocCopy(cp3, cp2); /* copy to mutilate more */ + for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '\"' && + *cp4 != ';' && *cp4 != ':' && + !WHITE(*cp4)); cp4++) + ; /* do nothing */ + *cp4 = '\0'; + cp4 = cp3; + chndl = UCGetLYhndl_byMIME(cp3); + if (UCCanTranslateFromTo(chndl, + current_char_set)) { + chartrans_ok = YES; + *cp1 = '\0'; + me->format = HTAtom_for(cp); + StrAllocCopy(me->anchor->charset, cp4); + HTAnchor_setUCInfoStage(me->anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_MIME); + } + else if (chndl < 0) {/* got something but we don't + recognize it */ + chndl = UCLYhndl_for_unrec; + if (UCCanTranslateFromTo(chndl, + current_char_set)) { + chartrans_ok = YES; + *cp1 = '\0'; + me->format = HTAtom_for(cp); + HTAnchor_setUCInfoStage(me->anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + } + FREE(cp3); + if (chartrans_ok) { + LYUCcharset * p_in = + HTAnchor_getUCInfoStage(me->anchor, + UCT_STAGE_MIME); + LYUCcharset * p_out = + HTAnchor_setUCInfoStage(me->anchor, + current_char_set, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + if (!p_out) + /* + ** Try again. + */ + p_out = + HTAnchor_getUCInfoStage(me->anchor, + UCT_STAGE_HTEXT); + + if (!strcmp(p_in->MIMEname, + "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->anchor, + HTAnchor_getUCLYhndl(me->anchor, + UCT_STAGE_HTEXT), + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + if (!strcmp(p_out->MIMEname, + "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->anchor, + HTAnchor_getUCLYhndl(me->anchor, + UCT_STAGE_MIME), + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + } + if (p_in->enc != UCT_ENC_CJK) { + HTCJK = NOCJK; + if (!(p_in->codepoints & + UCT_CP_SUBSETOF_LAT1) && + chndl == current_char_set) { + HTPassEightBitRaw = TRUE; + } + } else if (p_out->enc == UCT_ENC_CJK) { + if (LYRawMode) { + if ((!strcmp(p_in->MIMEname, + "euc-jp") || + !strcmp(p_in->MIMEname, + "shift_jis")) && + (!strcmp(p_out->MIMEname, + "euc-jp") || + !strcmp(p_out->MIMEname, + "shift_jis"))) { + HTCJK = JAPANESE; + } else if (!strcmp(p_in->MIMEname, + "euc-cn") && + !strcmp(p_out->MIMEname, + "euc-cn")) { + HTCJK = CHINESE; + } else if (!strcmp(p_in->MIMEname, + "big-5") && + !strcmp(p_out->MIMEname, + "big-5")) { + HTCJK = TAIPEI; + } else if (!strcmp(p_in->MIMEname, + "euc-kr") && + !strcmp(p_out->MIMEname, + "euc-kr")) { + HTCJK = KOREAN; + } else { + HTCJK = NOCJK; + } + } else { + HTCJK = NOCJK; + } + } + /* + ** Check for an iso-8859-# we don't know. - FM + */ + } else if + (!strncmp(cp4, "iso-8859-", 9) && + isdigit((unsigned char)cp4[9]) && + !strncmp(LYchar_set_names[current_char_set], + "Other ISO Latin", 15)) { + /* + ** Hope it's a match, for now. - FM + */ + *cp1 = '\0'; + me->format = HTAtom_for(cp); + cp1 = &cp4[10]; + while (*cp1 && + isdigit((unsigned char)(*cp1))) + cp1++; + *cp1 = '\0'; + StrAllocCopy(me->anchor->charset, cp4); + HTPassEightBitRaw = TRUE; + HTAlert(me->anchor->charset); + } + FREE(cp3); + } else { + /* + ** No charset parameter is present. + ** Ignore all other parameters, as + ** we do when charset is present. - FM + */ + *cp1 = '\0'; + me->format = HTAtom_for(cp); + } + } + FREE(cp); + } + /* + ** If we have an Expires header and haven't + ** already set the no_cache element for the + ** anchor, check if we should set it based + ** on that header. - FM + */ + if (me->anchor->no_cache == FALSE && + me->anchor->expires != NULL) { + if (!strcmp(me->anchor->expires, "0")) { + /* + * The value is zero, which we treat as + * an absolute no-cache directive. - FM + */ + me->anchor->no_cache = TRUE; + } else if (me->anchor->date != NULL) { + /* + ** We have a Date header, so check if + ** the value is less than or equal to + ** that. - FM + */ + if (LYmktime(me->anchor->expires, TRUE) <= + LYmktime(me->anchor->date, TRUE)) { + me->anchor->no_cache = TRUE; + } + } else if (LYmktime(me->anchor->expires, FALSE) <= 0) { + /* + ** We don't have a Date header, and + ** the value is in past for us. - FM + */ + me->anchor->no_cache = TRUE; + } + } + StrAllocCopy(me->anchor->content_type, + HTAtom_name(me->format)); + if (!me->compression_encoding) { + if (TRACE) { + fprintf(stderr, + "HTMIME: MIME Content-Type is '%s', converting to '%s'\n", + HTAtom_name(me->format), HTAtom_name(me->targetRep)); + } + } else { + /* + ** Change the format to that for "www/compressed" + ** and set up a stream to deal with it. - FM + */ + if (TRACE) { + fprintf(stderr, + "HTMIME: MIME Content-Type is '%s',\n", HTAtom_name(me->format)); + } + me->format = HTAtom_for("www/compressed"); + if (TRACE) { + fprintf(stderr, + " Treating as '%s'. Converting to '%s'\n", + HTAtom_name(me->format), HTAtom_name(me->targetRep)); + } + } + if (me->set_cookie != NULL || me->set_cookie2 != NULL) { + LYSetCookie(me->set_cookie, + me->set_cookie2, + me->anchor->address); + FREE(me->set_cookie); + FREE(me->set_cookie2); + } + me->target = HTStreamStack(me->format, me->targetRep, + me->sink , me->anchor); + if (!me->target) { + if (TRACE) + fprintf(stderr, "HTMIME: Can't translate! ** \n"); + me->target = me->sink; /* Cheat */ + } + if (me->target) { + me->targetClass = *me->target->isa; + /* + ** Check for encoding and select state from there, + ** someday, but until we have the relevant code, + ** from now push straight through. - FM + */ + me->state = MIME_TRANSPARENT; + } else { + me->state = MIME_IGNORE; /* What else to do? */ + } + FREE(me->compression_encoding); + } + break; + + default: + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miA: /* Check for 'c','g' or 'l' */ + switch (c) { + case 'c': + case 'C': + me->check_pointer = "cept-ranges:"; + me->if_ok = miACCEPT_RANGES; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was A, found C, checking for 'cept-ranges:'\n"); + break; + + case 'g': + case 'G': + me->check_pointer = "e:"; + me->if_ok = miAGE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was A, found G, checking for 'e:'\n"); + break; + + case 'l': + case 'L': + me->state = miAL; + if (TRACE) + fprintf(stderr, "HTMIME: Was A, found L, state now AL'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'g' or 'l'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miAL: /* Check for 'l' or 't' */ + switch (c) { + case 'l': + case 'L': + me->check_pointer = "ow:"; + me->if_ok = miALLOW; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was AL, found L, checking for 'ow:'\n"); + break; + + case 't': + case 'T': + me->check_pointer = "ernates:"; + me->if_ok = miALTERNATES; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was AL, found T, checking for 'ernates:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'l' or 't'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miC: /* Check for 'a' or 'o' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "che-control:"; + me->if_ok = miCACHE_CONTROL; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was C, found A, checking for 'che-control:'\n"); + break; + + case 'o': + case 'O': + me->state = miCO; + if (TRACE) + fprintf(stderr, "HTMIME: Was C, found O, state now CO'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a' or 'o'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miCO: /* Check for 'n' or 'o' */ + switch (c) { + case 'n': + case 'N': + me->state = miCON; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CO, found N, state now CON\n"); + break; + + case 'o': + case 'O': + me->check_pointer = "kie:"; + me->if_ok = miCOOKIE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CO, found O, checking for 'kie:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'n' or 'o'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miCON: /* Check for 'n' or 't' */ + switch (c) { + case 'n': + case 'N': + me->check_pointer = "ection:"; + me->if_ok = miCONNECTION; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CON, found N, checking for 'ection:'\n"); + break; + + case 't': + case 'T': + me->check_pointer = "ent-"; + me->if_ok = miCONTENT_; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CON, found T, checking for 'ent-'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'n' or 't'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miE: /* Check for 't' or 'x' */ + switch (c) { + case 't': + case 'T': + me->check_pointer = "ag:"; + me->if_ok = miETAG; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was E, found T, checking for 'ag:'\n"); + break; + + case 'x': + case 'X': + me->check_pointer = "pires:"; + me->if_ok = miEXPIRES; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was E, found X, checking for 'pires:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'t' or 'x'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miL: /* Check for 'a', 'i' or 'o' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "st-modified:"; + me->if_ok = miLAST_MODIFIED; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was L, found A, checking for 'st-modified:'\n"); + break; + + case 'i': + case 'I': + me->check_pointer = "nk:"; + me->if_ok = miLINK; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was L, found I, checking for 'nk:'\n"); + break; + + case 'o': + case 'O': + me->check_pointer = "cation:"; + me->if_ok = miLOCATION; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was L, found O, checking for 'cation:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a', 'i' or 'o'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miP: /* Check for 'r' or 'u' */ + switch (c) { + case 'r': + case 'R': + me->state = miPR; + if (TRACE) + fprintf(stderr, "HTMIME: Was P, found R, state now PR'\n"); + break; + + case 'u': + case 'U': + me->check_pointer = "blic:"; + me->if_ok = miPUBLIC; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was P, found U, checking for 'blic:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'r' or 'u'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miPR: /* Check for 'a' or 'o' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "gma:"; + me->if_ok = miPRAGMA; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was PR, found A, checking for 'gma'\n"); + break; + + case 'o': + case 'O': + me->check_pointer = "xy-authenticate:"; + me->if_ok = miPROXY_AUTHENTICATE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was PR, found O, checking for 'xy-authenticate'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a' or 'o'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miS: /* Check for 'a' or 'e' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "fe:"; + me->if_ok = miSAFE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, "HTMIME: Was S, found A, checking for 'fe:'\n"); + break; + + case 'e': + case 'E': + me->state = miSE; + if (TRACE) + fprintf(stderr, "HTMIME: Was S, found E, state now SE'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a' or 'e'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miSE: /* Check for 'r' or 't' */ + switch (c) { + case 'r': + case 'R': + me->check_pointer = "ver:"; + me->if_ok = miSERVER; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was SE, found R, checking for 'ver'\n"); + break; + + case 't': + case 'T': + me->check_pointer = "-cookie"; + me->if_ok = miSET_COOKIE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was SE, found T, checking for '-cookie'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'r' or 't'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miSET_COOKIE: /* Check for ':' or '2' */ + switch (c) { + case ':': + me->field = miSET_COOKIE1; /* remember it */ + me->state = miSKIP_GET_VALUE; + if (TRACE) + fprintf(stderr, + "HTMIME: Was SET_COOKIE, found :, processing\n"); + break; + + case '2': + me->check_pointer = ":"; + me->if_ok = miSET_COOKIE2; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was SET_COOKIE, found 2, checking for ':'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "':' or '2'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miT: /* Check for 'i' or 'r' */ + switch (c) { + case 'i': + case 'I': + me->check_pointer = "tle:"; + me->if_ok = miTITLE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was T, found I, checking for 'tle:'\n"); + break; + + case 'r': + case 'R': + me->check_pointer = "ansfer-encoding:"; + me->if_ok = miTRANSFER_ENCODING; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was T, found R, checking for 'ansfer-encoding'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'i' or 'r'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miU: /* Check for 'p' or 'r' */ + switch (c) { + case 'p': + case 'P': + me->check_pointer = "grade:"; + me->if_ok = miUPGRADE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was U, found P, checking for 'grade:'\n"); + break; + + case 'r': + case 'R': + me->check_pointer = "i:"; + me->if_ok = miURI; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was U, found R, checking for 'i:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'p' or 'r'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miV: /* Check for 'a' or 'i' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "ry:"; + me->if_ok = miVARY; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was V, found A, checking for 'ry:'\n"); + break; + + case 'i': + case 'I': + me->check_pointer = "a:"; + me->if_ok = miVIA; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was V, found I, checking for 'a:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a' or 'i'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miW: /* Check for 'a' or 'w' */ + switch (c) { + case 'a': + case 'A': + me->check_pointer = "rning:"; + me->if_ok = miWARNING; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was W, found A, checking for 'rning:'\n"); + break; + + case 'w': + case 'W': + me->check_pointer = "w-authenticate:"; + me->if_ok = miWWW_AUTHENTICATE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was W, found W, checking for 'w-authenticate:'\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, "'a' or 'w'"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miCHECK: /* Check against string */ + if (TOLOWER(c) == *(me->check_pointer)++) { + if (!*me->check_pointer) + me->state = me->if_ok; + } else { /* Error */ + if (TRACE) + fprintf(stderr, + "HTMIME: Bad character `%c' found where `%s' expected\n", + c, me->check_pointer - 1); + goto bad_field_name; + } + break; + + case miCONTENT_: + if (TRACE) + fprintf (stderr, + "HTMIME: in case CONTENT_\n"); + switch(c) { + case 'b': + case 'B': + me->check_pointer = "ase:"; + me->if_ok = miCONTENT_BASE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found B, checking for 'ase:'\n"); + break; + + case 'd': + case 'D': + me->check_pointer = "isposition:"; + me->if_ok = miCONTENT_DISPOSITION; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found D, checking for 'isposition:'\n"); + break; + + case 'e': + case 'E': + me->check_pointer = "ncoding:"; + me->if_ok = miCONTENT_ENCODING; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found E, checking for 'ncoding:'\n"); + break; + + case 'f': + case 'F': + me->check_pointer = "eatures:"; + me->if_ok = miCONTENT_FEATURES; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found F, checking for 'eatures:'\n"); + break; + + case 'l': + case 'L': + me->state = miCONTENT_L; + if (TRACE) + fprintf (stderr, + "HTMIME: Was CONTENT_, found L, state now CONTENT_L\n"); + break; + + case 'm': + case 'M': + me->check_pointer = "d5:"; + me->if_ok = miCONTENT_MD5; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found M, checking for 'd5:'\n"); + break; + + case 'r': + case 'R': + me->check_pointer = "ange:"; + me->if_ok = miCONTENT_RANGE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found R, checking for 'ange:'\n"); + break; + + case 't': + case 'T': + me->state = miCONTENT_T; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found T, state now CONTENT_T\n"); + break; + + default: + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_, found nothing; bleah\n"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miCONTENT_L: + if (TRACE) + fprintf (stderr, + "HTMIME: in case CONTENT_L\n"); + switch(c) { + case 'a': + case 'A': + me->check_pointer = "nguage:"; + me->if_ok = miCONTENT_LANGUAGE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_L, found A, checking for 'nguage:'\n"); + break; + + case 'e': + case 'E': + me->check_pointer = "ngth:"; + me->if_ok = miCONTENT_LENGTH; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_L, found E, checking for 'ngth:'\n"); + break; + + case 'o': + case 'O': + me->check_pointer = "cation:"; + me->if_ok = miCONTENT_LOCATION; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_L, found O, checking for 'cation:'\n"); + break; + + default: + if (TRACE) + fprintf (stderr, + "HTMIME: Was CONTENT_L, found nothing; bleah\n"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miCONTENT_T: + if (TRACE) + fprintf (stderr, + "HTMIME: in case CONTENT_T\n"); + switch(c) { + case 'r': + case 'R': + me->check_pointer = "ansfer-encoding:"; + me->if_ok = miCONTENT_TRANSFER_ENCODING; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_T, found R, checking for 'ansfer-encoding:'\n"); + break; + + case 'y': + case 'Y': + me->check_pointer = "pe:"; + me->if_ok = miCONTENT_TYPE; + me->state = miCHECK; + if (TRACE) + fprintf(stderr, + "HTMIME: Was CONTENT_T, found Y, checking for 'pe:'\n"); + break; + + default: + if (TRACE) + fprintf (stderr, + "HTMIME: Was CONTENT_T, found nothing; bleah\n"); + goto bad_field_name; + break; + + } /* switch on character */ + break; + + case miACCEPT_RANGES: + case miAGE: + case miALLOW: + case miALTERNATES: + case miCACHE_CONTROL: + case miCOOKIE: + case miCONNECTION: + case miCONTENT_BASE: + case miCONTENT_DISPOSITION: + case miCONTENT_ENCODING: + case miCONTENT_FEATURES: + case miCONTENT_LANGUAGE: + case miCONTENT_LENGTH: + case miCONTENT_LOCATION: + case miCONTENT_MD5: + case miCONTENT_RANGE: + case miCONTENT_TRANSFER_ENCODING: + case miCONTENT_TYPE: + case miDATE: + case miETAG: + case miEXPIRES: + case miKEEP_ALIVE: + case miLAST_MODIFIED: + case miLINK: + case miLOCATION: + case miPRAGMA: + case miPROXY_AUTHENTICATE: + case miPUBLIC: + case miRETRY_AFTER: + case miSAFE: + case miSERVER: + case miSET_COOKIE1: + case miSET_COOKIE2: + case miTITLE: + case miTRANSFER_ENCODING: + case miUPGRADE: + case miURI: + case miVARY: + case miVIA: + case miWARNING: + case miWWW_AUTHENTICATE: + me->field = me->state; /* remember it */ + me->state = miSKIP_GET_VALUE; + /* Fall through! */ + + case miSKIP_GET_VALUE: + if (c == '\n') { + me->fold_state = me->state; + me->state = miNEWLINE; + break; + } + if (WHITE(c)) + /* + ** Skip white space. + */ + break; + + me->value_pointer = me->value; + me->state = miGET_VALUE; + /* Fall through to store first character */ + + case miGET_VALUE: + if (WHITE(c) && c != 32) { /* End of field */ + char *cp; + *me->value_pointer = '\0'; + cp = (me->value_pointer - 1); + while ((cp >= me->value) && *cp == 32) + /* + ** Trim trailing spaces. + */ + *cp = '\0'; + switch (me->field) { + case miACCEPT_RANGES: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Accept-Ranges: '%s'\n", + me->value); + break; + case miAGE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Age: '%s'\n", + me->value); + break; + case miALLOW: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Allow: '%s'\n", + me->value); + break; + case miALTERNATES: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Alternates: '%s'\n", + me->value); + break; + case miCACHE_CONTROL: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Cache-Control: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + for (i = 0; me->value[i]; i++) + me->value[i] = TOLOWER(me->value[i]); + StrAllocCopy(me->anchor->cache_control, me->value); + /* + ** Check whether to set no_cache for the anchor. - FM + */ + { + char *cp1, *cp0 = me->value; + + while ((cp1 = strstr(cp0, "no-cache")) != NULL) { + cp1 += 8; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (*cp1 == '\0' || *cp1 == ';') { + me->anchor->no_cache = TRUE; + break; + } + cp0 = cp1; + } + if (me->anchor->no_cache == TRUE) + break; + cp0 = me->value; + while ((cp1 = strstr(cp0, "max-age")) != NULL) { + cp1 += 7; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (*cp1 == '=') { + cp1++; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (isdigit((unsigned char)*cp1)) { + cp0 = cp1; + while (isdigit((unsigned char)*cp1)) + cp1++; + if (*cp0 == '0' && cp1 == (cp0 + 1)) { + me->anchor->no_cache = TRUE; + break; + } + } + } + cp0 = cp1; + } + } + break; + case miCOOKIE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Cookie: '%s'\n", + me->value); + break; + case miCONNECTION: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Connection: '%s'\n", + me->value); + break; + case miCONTENT_BASE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Base: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_base, me->value); + break; + case miCONTENT_DISPOSITION: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Disposition: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_disposition, me->value); + /* + ** It's not clear yet from existing RFCs and IDs + ** whether we should be looking for file;, attachment;, + ** and/or inline; before the filename=value, so we'll + ** just search for "filename" followed by '=' and just + ** hope we get the intended value. It is purely a + ** suggested name, anyway. - FM + */ + cp = me->anchor->content_disposition; + while (*cp != '\0' && strncasecomp(cp, "filename", 8)) + cp++; + if (*cp == '\0') + break; + cp += 8; + while ((*cp != '\0') && (WHITE(*cp) || *cp == '=')) + cp++; + if (*cp == '\0') + break; + while (*cp != '\0' && WHITE(*cp)) + cp++; + if (*cp == '\0') + break; + StrAllocCopy(me->anchor->SugFname, cp); + if (*me->anchor->SugFname == '\"') { + if ((cp = strchr((me->anchor->SugFname + 1), + '\"')) != NULL) { + *(cp + 1) = '\0'; + HTMIME_TrimDoubleQuotes(me->anchor->SugFname); + } else { + FREE(me->anchor->SugFname); + break; + } + } + cp = me->anchor->SugFname; + while (*cp != '\0' && !WHITE(*cp)) + cp++; + *cp = '\0'; + if (*me->anchor->SugFname == '\0') + FREE(me->anchor->SugFname); + break; + case miCONTENT_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Encoding: '%s'\n", + me->value); + if (!(me->value && *me->value) || + !strcasecomp(me->value, "identity")) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + for (i = 0; me->value[i]; i++) + me->value[i] = TOLOWER(me->value[i]); + StrAllocCopy(me->anchor->content_encoding, me->value); + FREE(me->compression_encoding); + if (!strcmp(me->value, "8bit") || + !strcmp(me->value, "7bit") || + !strcmp(me->value, "binary")) { + /* + ** Some server indicated "8bit", "7bit" or "binary" + ** inappropriately. We'll ignore it. - FM + */ + if (TRACE) + fprintf(stderr, + " Ignoring it!\n"); + } else { + /* + ** Save it to use as a flag for setting + ** up a "www/compressed" target. - FM + */ + StrAllocCopy(me->compression_encoding, me->value); + } + break; + case miCONTENT_FEATURES: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Features: '%s'\n", + me->value); + break; + case miCONTENT_LANGUAGE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Language: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + for (i = 0; me->value[i]; i++) + me->value[i] = TOLOWER(me->value[i]); + StrAllocCopy(me->anchor->content_language, me->value); + break; + case miCONTENT_LENGTH: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Length: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Convert to integer and indicate in anchor. - FM + */ + me->anchor->content_length = atoi(me->value); + if (me->anchor->content_length < 0) + me->anchor->content_length = 0; + if (TRACE) + fprintf(stderr, + " Converted to integer: '%d'\n", + me->anchor->content_length); + break; + case miCONTENT_LOCATION: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Location: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_location, me->value); + break; + case miCONTENT_MD5: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-MD5: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_md5, me->value); + break; + case miCONTENT_RANGE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Range: '%s'\n", + me->value); + break; + case miCONTENT_TRANSFER_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Transfer-Encoding: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Force the Content-Transfer-Encoding value + ** to all lower case. - FM + */ + for (i = 0; me->value[i]; i++) + me->value[i] = TOLOWER(me->value[i]); + me->encoding = HTAtom_for(me->value); + break; + case miCONTENT_TYPE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Content-Type: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Force the Content-Type value to all lower case + ** and strip spaces and double-quotes. - FM + */ + for (i = 0, j = 0; me->value[i]; i++) { + if (me->value[i] != ' ' && me->value[i] != '\"') { + me->value[j++] = TOLOWER(me->value[i]); + } + } + me->value[j] = '\0'; + me->format = HTAtom_for(me->value); + break; + case miDATE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Date: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->date, me->value); + break; + case miETAG: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP ETag: '%s'\n", + me->value); + break; + case miEXPIRES: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Expires: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->expires, me->value); + break; + case miKEEP_ALIVE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Keep-Alive: '%s'\n", + me->value); + break; + case miLAST_MODIFIED: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Last-Modified: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->last_modified, me->value); + break; + case miLINK: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Link: '%s'\n", + me->value); + break; + case miLOCATION: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Location: '%s'\n", + me->value); + break; + case miPRAGMA: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Pragma: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Check whether to set no_cache for the anchor. - FM + */ + if (!strcmp(me->value, "no-cache")) + me->anchor->no_cache = TRUE; + break; + case miPROXY_AUTHENTICATE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Proxy-Authenticate: '%s'\n", + me->value); + break; + case miPUBLIC: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Public: '%s'\n", + me->value); + break; + case miRETRY_AFTER: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Retry-After: '%s'\n", + me->value); + break; + case miSAFE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Safe: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor if "YES" or "TRUE". - FM + */ + if (!strcasecomp(me->value, "YES") || + !strcasecomp(me->value, "TRUE")) { + me->anchor->safe = TRUE; + } + break; + case miSERVER: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Server: '%s'\n", + me->value); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->server, me->value); + break; + case miSET_COOKIE1: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Set-Cookie: '%s'\n", + me->value); + if (me->set_cookie == NULL) { + StrAllocCopy(me->set_cookie, me->value); + } else { + StrAllocCat(me->set_cookie, ", "); + StrAllocCat(me->set_cookie, me->value); + } + break; + case miSET_COOKIE2: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Set-Cookie2: '%s'\n", + me->value); + if (me->set_cookie2 == NULL) { + StrAllocCopy(me->set_cookie2, me->value); + } else { + StrAllocCat(me->set_cookie2, ", "); + StrAllocCat(me->set_cookie2, me->value); + } + break; + case miTITLE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Title: '%s'\n", + me->value); + break; + case miTRANSFER_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Transfer-Encoding: '%s'\n", + me->value); + break; + case miUPGRADE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Upgrade: '%s'\n", + me->value); + break; + case miURI: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP URI: '%s'\n", + me->value); + break; + case miVARY: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Vary: '%s'\n", + me->value); + break; + case miVIA: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Via: '%s'\n", + me->value); + break; + case miWARNING: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP Warning: '%s'\n", + me->value); + break; + case miWWW_AUTHENTICATE: + HTMIME_TrimDoubleQuotes(me->value); + if (TRACE) + fprintf(stderr, + "HTMIME: PICKED UP WWW-Authenticate: '%s'\n", + me->value); + break; + default: /* Should never get here */ + break; + } + } else { + if (me->value_pointer < me->value + VALUE_SIZE - 1) { + *me->value_pointer++ = c; + break; + } else { + goto value_too_long; + } + } + /* Fall through */ + + case miJUNK_LINE: + if (c == '\n') { + me->state = miNEWLINE; + me->fold_state = me->state; + } + break; + + + } /* switch on state*/ + + return; + +value_too_long: + if (TRACE) + fprintf(stderr, "HTMIME: *** Syntax error. (string too long)\n"); + +bad_field_name: /* Ignore it */ + me->state = miJUNK_LINE; + return; + +} + + + +/* String handling +** --------------- +** +** Strings must be smaller than this buffer size. +*/ +PRIVATE void HTMIME_put_string ARGS2( + HTStream *, me, + CONST char *, s) +{ + CONST char * p; + + if (me->state == MIME_TRANSPARENT) { /* Optimisation */ + (*me->targetClass.put_string)(me->target,s); + + } else if (me->state != MIME_IGNORE) { + if (TRACE) + fprintf(stderr, "HTMIME: %s\n", s); + + for (p=s; *p; p++) + HTMIME_put_character(me, *p); + } +} + + +/* Buffer write. Buffers can (and should!) be big. +** ------------ +*/ +PRIVATE void HTMIME_write ARGS3( + HTStream *, me, + CONST char *, s, + int, l) +{ + CONST char * p; + + if (me->state == MIME_TRANSPARENT) { /* Optimisation */ + (*me->targetClass.put_block)(me->target, s, l); + + } else { + if (TRACE) + fprintf(stderr, "HTMIME: %.*s\n", l, s); + + for (p = s; p < s+l; p++) + HTMIME_put_character(me, *p); + } +} + + +/* Free an HTML object +** ------------------- +** +*/ +PRIVATE void HTMIME_free ARGS1( + HTStream *, me) +{ + if (me->target) + (*me->targetClass._free)(me->target); + FREE(me); +} + +/* End writing +*/ +PRIVATE void HTMIME_abort ARGS2( + HTStream *, me, + HTError, e) +{ + if (me->target) + (*me->targetClass._abort)(me->target, e); + FREE(me); +} + + +/* Structured Object Class +** ----------------------- +*/ +PRIVATE CONST HTStreamClass HTMIME = +{ + "MIMEParser", + HTMIME_free, + HTMIME_abort, + HTMIME_put_character, + HTMIME_put_string, + HTMIME_write +}; + + +/* Subclass-specific Methods +** ------------------------- +*/ +PUBLIC HTStream* HTMIMEConvert ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, + HTStream *, sink) +{ + HTStream* me; + + me = (HTStream *)calloc(1, sizeof(*me)); + if (me == NULL) + outofmem(__FILE__, "HTMIMEConvert"); + me->isa = &HTMIME; + me->sink = sink; + me->anchor = anchor; + me->anchor->safe = FALSE; + me->anchor->no_cache = FALSE; + FREE(me->anchor->cache_control); + FREE(me->anchor->SugFname); + FREE(me->anchor->charset); + FREE(me->anchor->content_language); + FREE(me->anchor->content_encoding); + FREE(me->anchor->content_base); + FREE(me->anchor->content_disposition); + FREE(me->anchor->content_location); + FREE(me->anchor->content_md5); + me->anchor->content_length = 0; + FREE(me->anchor->date); + FREE(me->anchor->expires); + FREE(me->anchor->last_modified); + FREE(me->anchor->server); + me->target = NULL; + me->state = miBEGINNING_OF_LINE; + /* + * Sadly enough, change this to always default to WWW_HTML + * to parse all text as HTML for the users. + * GAB 06-30-94 + * Thanks to Robert Rowland robert@cyclops.pei.edu + * + * After discussion of the correct handline, should be application/octet- + * stream or unknown; causing servers to send a correct content + * type. + * + * The consequence of using WWW_UNKNOWN is that you end up downloading + * as a binary file what 99.9% of the time is an HTML file, which should + * have been rendered or displayed. So sadly enough, I'm changing it + * back to WWW_HTML, and it will handle the situation like Mosaic does, + * and as Robert Rowland suggested, because being functionally correct + * 99.9% of the time is better than being technically correct but + * functionally nonsensical. - FM + *//*** + me->format = WWW_UNKNOWN; + ***/ + me->format = WWW_HTML; + me->targetRep = pres->rep_out; + me->boundary = NULL; /* Not set yet */ + me->set_cookie = NULL; /* Not set yet */ + me->set_cookie2 = NULL; /* Not set yet */ + me->encoding = 0; /* Not set yet */ + me->compression_encoding = NULL; /* Not set yet */ + me->net_ascii = NO; /* Local character set */ + HTAnchor_setUCInfoStage(me->anchor, current_char_set, + UCT_STAGE_STRUCTURED, + UCT_SETBY_DEFAULT); + HTAnchor_setUCInfoStage(me->anchor, current_char_set, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + return me; +} + +PUBLIC HTStream* HTNetMIME ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, + HTStream *, sink) +{ + HTStream* me = HTMIMEConvert(pres,anchor, sink); + if (!me) + return NULL; + + me->net_ascii = YES; + return me; +} + +/* Japanese header handling functions +** ================================== +** +** K&Rized and added 07-Jun-96 by FM, based on: +** +//////////////////////////////////////////////////////////////////////// +** +** ISO-2022-JP handling routines +** & +** MIME decode routines (quick hack just for ISO-2022-JP) +** +** Thu Jan 25 10:11:42 JST 1996 +** +** Copyright (C) 1994, 1995, 1996 +** Shuichi Ichikawa (ichikawa@nuee.nagoya-u.ac.jp) +** +** 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 versions 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 SKK, see the file COPYING. If not, write to the Free +** Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* #include <stdio.h> */ /* Included via previous headers. - FM */ +/* #include <string.h> */ /* Included via previous headers. - FM */ + +/* +** MIME decoding routines +** +** Written by S. Ichikawa, +** partially inspired by encdec.c of <jh@efd.lth.se>. +*/ +#define BUFLEN 1024 +#ifdef ESC +#undef ESC +#endif /* ESC */ +#define ESC '\033' + +PRIVATE char HTmm64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ; +PRIVATE char HTmmquote[] = "0123456789ABCDEF"; +PRIVATE int HTmmcont = 0; + +PUBLIC void HTmmdec_base64 ARGS2( + char *, t, + char *, s) +{ + int d, count, j, val; + char buf[BUFLEN], *bp, nw[4], *p; + + for (bp = buf; *s; s += 4) { + val = 0; + if (s[2] == '=') + count = 1; + else if (s[3] == '=') + count = 2; + else + count = 3; + + for (j = 0; j <= count; j++) { + if (!(p = strchr(HTmm64, s[j]))) { + return; + } + d = p - HTmm64; + d <<= (3-j)*6; + val += d; + } + for (j = 2; j >= 0; j--) { + nw[j] = val & 255; + val >>= 8; + } + if (count--) + *bp++ = nw[0]; + if (count--) + *bp++ = nw[1]; + if (count) + *bp++ = nw[2]; + } + *bp = '\0'; + strcpy(t, buf); +} + +PUBLIC void HTmmdec_quote ARGS2( + char *, t, + char *, s) +{ + char buf[BUFLEN], cval, *bp, *p; + + for (bp = buf; *s; ) { + if (*s == '=') { + cval = 0; + if (s[1] && (p = strchr(HTmmquote, s[1]))) { + cval += (p - HTmmquote); + } else { + *bp++ = *s++; + continue; + } + if (s[2] && (p = strchr(HTmmquote, s[2]))) { + cval <<= 4; + cval += (p - HTmmquote); + *bp++ = cval; + s += 3; + } else { + *bp++ = *s++; + } + } else if (*s == '_') { + *bp++ = 0x20; + s++; + } else { + *bp++ = *s++; + } + } + *bp = '\0'; + strcpy(t, buf); +} + +#ifdef NOTDEFINED +/* +** Generalized HTmmdecode for chartrans - K. Weide 1997-03-06 +*/ +PUBLIC void HTmmdecode ARGS2( + char *, trg, + char *, str) +{ + char buf[BUFLEN], mmbuf[BUFLEN]; + char *s, *t, *u, *qm2; + int base64, quote; + + buf[0] = '\0'; + + /* + ** Encoded-words look like + ** =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= + */ + for (s = str, u = buf; *s; ) { + base64 = quote = 0; + if (*s == '=' && s[1] == '?' && + (s == str || *(s-1) == '(' || WHITE(*(s-1)))) + { /* must be beginning of word */ + qm2 = strchr(s+2, '?'); /* 2nd question mark */ + if (qm2 && + (qm2[1] == 'B' || qm2[1] == 'b' || qm2[1] == 'Q' || + qm2[1] == 'q') && + qm2[2] == '?') { /* 3rd question mark */ + char * qm4 = strchr(qm2 + 3, '?'); /* 4th question mark */ + if (qm4 && qm4 - s < 74 && /* RFC 2047 length restriction */ + qm4[1] == '=') { + char *p; + BOOL invalid = NO; + for (p = s+2; p < qm4; p++) + if (WHITE(*p)) { + invalid = YES; + break; + } + if (!invalid) { + int LYhndl; + + *qm2 = '\0'; + for (p = s+2; *p; p++) + *p = TOLOWER(*p); + invalid = ((LYhndl = UCGetLYhndl_byMIME(s+2)) < 0 || + UCCanTranslateFromTo(LYhndl, + current_char_set)); + *qm2 = '?'; + } + if (!invalid) { + if (qm2[1] == 'B' || qm2[1] == 'b') + base64 = 1; + else if (qm2[1] == 'Q' || qm2[1] == 'q') + quote = 1; + } + } + } + } + if (base64 || quote) { + if (HTmmcont) { + for (t = s - 1; + t >= str && (*t == ' ' || *t == '\t'); t--) { + u--; + } + } + for (s = qm2 + 3, t = mmbuf; *s; ) { + if (s[0] == '?' && s[1] == '=') { + break; + } else { + *t++ = *s++; + } + } + if (s[0] != '?' || s[1] != '=') { + goto end; + } else { + s += 2; + *t = '\0'; + } + if (base64) + HTmmdec_base64(mmbuf, mmbuf); + if (quote) + HTmmdec_quote(mmbuf, mmbuf); + for (t = mmbuf; *t; ) + *u++ = *t++; + HTmmcont = 1; + /* if (*s == ' ' || *s == '\t') *u++ = *s; */ + /* for ( ; *s == ' ' || *s == '\t'; s++) ; */ + } else { + if (*s != ' ' && *s != '\t') + HTmmcont = 0; + *u++ = *s++; + } + } + *u = '\0'; +end: + strcpy(trg, buf); +} +#else +/* +** HTmmdecode for ISO-2022-JP - FM +*/ +PUBLIC void HTmmdecode ARGS2( + char *, trg, + char *, str) +{ + char buf[BUFLEN], mmbuf[BUFLEN]; + char *s, *t, *u; + int base64, quote; + + buf[0] = '\0'; + + for (s = str, u = buf; *s; ) { + if (!strncasecomp(s, "=?ISO-2022-JP?B?", 16)) { + base64 = 1; + } else { + base64 = 0; + } + if (!strncasecomp(s, "=?ISO-2022-JP?Q?", 16)) { + quote = 1; + } else { + quote = 0; + } + if (base64 || quote) { + if (HTmmcont) { + for (t = s - 1; + t >= str && (*t == ' ' || *t == '\t'); t--) { + u--; + } + } + for (s += 16, t = mmbuf; *s; ) { + if (s[0] == '?' && s[1] == '=') { + break; + } else { + *t++ = *s++; + } + } + if (s[0] != '?' || s[1] != '=') { + goto end; + } else { + s += 2; + *t = '\0'; + } + if (base64) + HTmmdec_base64(mmbuf, mmbuf); + if (quote) + HTmmdec_quote(mmbuf, mmbuf); + for (t = mmbuf; *t; ) + *u++ = *t++; + HTmmcont = 1; + /* if (*s == ' ' || *s == '\t') *u++ = *s; */ + /* for ( ; *s == ' ' || *s == '\t'; s++) ; */ + } else { + if (*s != ' ' && *s != '\t') + HTmmcont = 0; + *u++ = *s++; + } + } + *u = '\0'; +end: + strcpy(trg, buf); +} +#endif /* NOTDEFINED */ + +/* +** Modified for Lynx-jp by Takuya ASADA (and K&Rized by FM). +*/ +#if NOTDEFINED +PUBLIC int main ARGS2( + int, ac, + char **, av) +{ + FILE *fp; + char buf[BUFLEN]; + char header = 1, body = 0, r_jis = 0; + int i, c; + + for (i = 1; i < ac; i++) { + if (strcmp(av[i], "-B") == NULL) + body = 1; + else if (strcmp(av[i], "-r") == NULL) + r_jis = 1; + else + break; + } + + if (i >= ac) { + fp = stdin; + } else { + if ((fp = fopen(av[i], "r")) == NULL) { + fprintf(stderr, "%s: cannot open %s\n", av[0], av[i]); + exit(1); + } + } + + while (fgets(buf, BUFLEN, fp)) { + if (buf[0] == '\n' && buf[1] == '\0') + header = 0; + if (header) { + c = fgetc(fp); + if (c == ' ' || c == '\t') { + buf[strlen(buf)-1] = '\0'; + ungetc(c, fp); + } else { + ungetc(c, fp); + } + } + if (header || body) + HTmmdecode(buf, buf); + if (r_jis) + HTrjis(buf, buf); + fprintf(stdout, "%s", buf); + } + + close(fp); + exit(0); +} +#endif /* NOTDEFINED */ + +/* +** Insert ESC where it seems lost. +** (The author of this function "rjis" is S. Ichikawa.) +*/ +PUBLIC int HTrjis ARGS2( + char *, t, + char *, s) +{ + char *p, buf[BUFLEN]; + int kanji = 0; + + if (strchr(s, ESC) || !strchr(s, '$')) { + if (s != t) + strcpy(t, s); + return 1; + } + for (p = buf; *s; ) { + if (!kanji && s[0] == '$' && (s[1] == '@' || s[1] == 'B')) { + if (HTmaybekanji((int)s[2], (int)s[3])) { + kanji = 1; + *p++ = ESC; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + continue; + } + *p++ = *s++; + continue; + } + if (kanji && s[0] == '(' && (s[1] == 'J' || s[1] == 'B')) { + kanji = 0; + *p++ = ESC; + *p++ = *s++; + *p++ = *s++; + continue; + } + *p++ = *s++; + } + *p = *s; /* terminate string */ + + strcpy(t, buf); + return 0; +} + +/* +** The following function "maybekanji" is derived from +** RJIS-1.0 by Mr. Hironobu Takahashi. +** Maybekanji() is included here under the courtesy of the author. +** The original comment of rjis.c is also included here. +*/ +/* + * RJIS ( Recover JIS code from broken file ) + * $Header: /cvs/OpenBSD/src/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.c,v 1.1 1998/03/11 17:47:45 maja Exp $ + * Copyright (C) 1992 1994 + * Hironobu Takahashi (takahasi@tiny.or.jp) + * + * 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 versions 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 SKK, see the file COPYING. If not, write to the Free + * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +PUBLIC int HTmaybekanji ARGS2( + int, c1, + int, c2) +{ + + if ((c2 < 33) || (c2 > 126)) + return 0; + if ((c1 < 33) || ((40 < c1) && (c1 < 48)) || (116 < c1)) + return 0; + c2 -= 32; + switch(c1-32) { + case 2: + if ((14 < c2) && ( c2 < 26)) + return 0; + if ((33 < c2) && ( c2 < 42)) + return 0; + if ((48 < c2) && ( c2 < 60)) + return 0; + if ((74 < c2) && ( c2 < 82)) + return 0; + if ((89 < c2) && ( c2 < 94)) + return 0; + break; + case 3: + if (c2 < 16) + return 0; + if ((25 < c2) && ( c2 < 33)) + return 0; + if ((58 < c2) && ( c2 < 65)) + return 0; + if (90 < c2) + return 0; + break; + case 4: + if (83 < c2) + return 0; + break; + case 5: + if (86 < c2) + return 0; + break; + case 6: + if ((24 < c2) && ( c2 < 33)) + return 0; + if (56 < c2) + return 0; + break; + case 7: + if ((33 < c2) && ( c2 < 49)) + return 0; + if (81 < c2) + return 0; + break; + case 8: + if (32 < c2) + return 0; + break; + case 47: + if (51 < c2) + return 0; + break; + case 84: + if (6 < c2) + return 0; + break; + } + return 1; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.h new file mode 100644 index 00000000000..823f6c76c0d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.h @@ -0,0 +1,87 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTMIME.html + MIME PARSER + + The MIME parser stream presents a MIME document. It recursively invokes the format + manager to handle embedded formats. + + As well as stripping off and parsing the headers, the MIME parser has to parse any + weirld MIME encodings it may meet within the body parts of messages, and must deal with + multipart messages. + + This module is implemented to the level necessary for operation with WWW, but is not + currently complete for any arbitrary MIME message. + + Check the source for latest additions to functionality. + + The MIME parser is complicated by the fact that WWW allows real binary to be sent, not + ASCII encoded. Therefore the netascii decoding is included in this module. One cannot + layer it by converting first from Net to local text, then decoding it. Of course, for + local files, the net ascii decoding is not needed. There are therefore two creation + routines. + + */ +#ifndef HTMIME_H +#define HTMIME_H + +#include "HTStream.h" +#include "HTAnchor.h" + +/* +** This function is for trimming off any paired +** open- and close-double quotes from header values. +** It does not parse the string for embedded quotes, +** and will not modify the string unless both the +** first and last characters are double-quotes. - FM +*/ +extern void HTMIME_TrimDoubleQuotes PARAMS(( + char * value)); + +/* + + INPUT: LOCAL TEXT + + */ +extern HTStream * HTMIMEConvert PARAMS((HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); +/* + + INPUT: NET ASCII + + */ +extern HTStream * HTNetMIME PARAMS((HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + + +/* + + For handling Japanese headers. + +*/ +extern void HTmmdec_base64 PARAMS(( + char * t, + char * s)); + +extern void HTmmdec_quote PARAMS(( + char * t, + char * s)); + +extern void HTmmdecode PARAMS(( + char * trg, + char * str)); + +extern int HTrjis PARAMS(( + char * t, + char * s)); + +PUBLIC int HTmaybekanji PARAMS(( + int c1, + int c2)); + + +#endif /* !HTMIME_H */ + +/* + + end of HTMIME */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.c new file mode 100644 index 00000000000..0d616bf1d2e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.c @@ -0,0 +1,1674 @@ +/* Our Static DTD for HTML +** ----------------------- +*/ + +/* Implements: +*/ + +#include "HTUtils.h" +#include "HTMLDTD.h" +#include "LYLeaks.h" + +/* Entity Names +** ------------ +** +** This table must be matched exactly with ALL the translation tables +** (this is an obsolete translation mechanism, +** currently replaced with unicode chartrans in most cases...) +*/ +static CONST char* entities[] = { + "AElig", /* capital AE diphthong (ligature) */ + "Aacute", /* capital A, acute accent */ + "Acirc", /* capital A, circumflex accent */ + "Agrave", /* capital A, grave accent */ + "Aring", /* capital A, ring */ + "Atilde", /* capital A, tilde */ + "Auml", /* capital A, dieresis or umlaut mark */ + "Ccedil", /* capital C, cedilla */ + "Dstrok", /* capital Eth, Icelandic */ + "ETH", /* capital Eth, Icelandic */ + "Eacute", /* capital E, acute accent */ + "Ecirc", /* capital E, circumflex accent */ + "Egrave", /* capital E, grave accent */ + "Euml", /* capital E, dieresis or umlaut mark */ + "Iacute", /* capital I, acute accent */ + "Icirc", /* capital I, circumflex accent */ + "Igrave", /* capital I, grave accent */ + "Iuml", /* capital I, dieresis or umlaut mark */ + "Ntilde", /* capital N, tilde */ + "Oacute", /* capital O, acute accent */ + "Ocirc", /* capital O, circumflex accent */ + "Ograve", /* capital O, grave accent */ + "Oslash", /* capital O, slash */ + "Otilde", /* capital O, tilde */ + "Ouml", /* capital O, dieresis or umlaut mark */ + "THORN", /* capital THORN, Icelandic */ + "Uacute", /* capital U, acute accent */ + "Ucirc", /* capital U, circumflex accent */ + "Ugrave", /* capital U, grave accent */ + "Uuml", /* capital U, dieresis or umlaut mark */ + "Yacute", /* capital Y, acute accent */ + "aacute", /* small a, acute accent */ + "acirc", /* small a, circumflex accent */ + "acute", /* spacing acute */ + "aelig", /* small ae diphthong (ligature) */ + "agrave", /* small a, grave accent */ + "amp", /* ampersand */ + "aring", /* small a, ring */ + "atilde", /* small a, tilde */ + "auml", /* small a, dieresis or umlaut mark */ + "brkbar", /* broken vertical bar */ + "brvbar", /* broken vertical bar */ + "ccedil", /* small c, cedilla */ + "cedil", /* spacing cedilla */ + "cent", /* cent sign */ + "copy", /* copyright sign */ + "curren", /* currency sign */ + "deg", /* degree sign */ + "die", /* spacing dieresis */ + "divide", /* division sign */ + "eacute", /* small e, acute accent */ + "ecirc", /* small e, circumflex accent */ + "egrave", /* small e, grave accent */ + "emdash", /* dash the width of emsp */ + "emsp", /* em space - not collapsed */ + "endash", /* dash the width of ensp */ + "ensp", /* en space - not collapsed */ + "eth", /* small eth, Icelandic */ + "euml", /* small e, dieresis or umlaut mark */ + "frac12", /* fraction 1/2 */ + "frac14", /* fraction 1/4 */ + "frac34", /* fraction 3/4 */ + "gt", /* greater than */ + "hibar", /* spacing macron */ + "iacute", /* small i, acute accent */ + "icirc", /* small i, circumflex accent */ + "iexcl", /* inverted exclamation mark */ + "igrave", /* small i, grave accent */ + "iquest", /* inverted question mark */ + "iuml", /* small i, dieresis or umlaut mark */ + "laquo", /* angle quotation mark, left */ + "lt", /* less than */ + "macr", /* spacing macron */ + "mdash", /* dash the width of emsp */ + "micro", /* micro sign */ + "middot", /* middle dot */ + "nbsp", /* non breaking space */ + "ndash", /* dash the width of ensp */ + "not", /* negation sign */ + "ntilde", /* small n, tilde */ + "oacute", /* small o, acute accent */ + "ocirc", /* small o, circumflex accent */ + "ograve", /* small o, grave accent */ + "ordf", /* feminine ordinal indicator */ + "ordm", /* masculine ordinal indicator */ + "oslash", /* small o, slash */ + "otilde", /* small o, tilde */ + "ouml", /* small o, dieresis or umlaut mark */ + "para", /* paragraph sign */ + "plusmn", /* plus-or-minus sign */ + "pound", /* pound sign */ + "quot", /* quote '"' */ + "raquo", /* angle quotation mark, right */ + "reg", /* circled R registered sign */ + "sect", /* section sign */ + "shy", /* soft hyphen */ + "sup1", /* superscript 1 */ + "sup2", /* superscript 2 */ + "sup3", /* superscript 3 */ + "szlig", /* small sharp s, German (sz ligature) */ + "thinsp", /* thin space (not collapsed) */ + "thorn", /* small thorn, Icelandic */ + "times", /* multiplication sign */ + "trade", /* trade mark sign (U+2122) */ + "uacute", /* small u, acute accent */ + "ucirc", /* small u, circumflex accent */ + "ugrave", /* small u, grave accent */ + "uml", /* spacing dieresis */ + "uuml", /* small u, dieresis or umlaut mark */ + "yacute", /* small y, acute accent */ + "yen", /* yen sign */ + "yuml", /* small y, dieresis or umlaut mark */ +}; + +#define HTML_ENTITIES 112 + +#include <entities.h> + +/* Attribute Lists +** --------------- +** +** Lists must be in alphabetical order by attribute name +** The tag elements contain the number of attributes +*/ +static attr a_attr[] = { /* Anchor attributes */ + { "ACCESSKEY" }, + { "CHARSET" }, + { "CLASS" }, + { "CLEAR" }, + { "COORDS" }, + { "DIR" }, + { "HREF" }, + { "ID" }, + { "ISMAP" }, + { "LANG" }, + { "MD" }, + { "NAME" }, + { "NOTAB" }, + { "ONCLICK" }, + { "ONMOUSEOUT" }, + { "ONMOUSEOVER" }, + { "REL" }, + { "REV" }, + { "SHAPE" }, + { "STYLE" }, + { "TABINDEX" }, + { "TARGET" }, + { "TITLE" }, + { "TYPE" }, + { "URN" }, + { 0 } /* Terminate list */ +}; + +static attr address_attr[] = { /* ADDRESS attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NOWRAP" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr applet_attr[] = { /* APPLET attributes */ + { "ALIGN" }, + { "ALT" }, + { "CLASS" }, + { "CLEAR" }, + { "CODE" }, + { "CODEBASE" }, + { "DIR" }, + { "DOWNLOAD" }, + { "HEIGHT" }, + { "HSPACE" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "STYLE" }, + { "TITLE" }, + { "VSPACE" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr area_attr[] = { /* AREA attributes */ + { "ALT" }, + { "CLASS" }, + { "CLEAR" }, + { "COORDS" }, + { "DIR" }, + { "HREF" }, + { "ID" }, + { "LANG" }, + { "NOHREF" }, + { "NOTAB" }, + { "ONCLICK" }, + { "ONMOUSEOUT" }, + { "ONMOUSEOVER" }, + { "SHAPE" }, + { "STYLE" }, + { "TABINDEX" }, + { "TARGET" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr base_attr[] = { /* BASE attributes */ + { "HREF" }, + { "TARGET" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr bgsound_attr[] = { /* BGSOUND attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "LOOP" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr body_attr[] = { /* BODY attributes */ + { "ALINK" }, + { "BACKGROUND" }, + { "BGCOLOR" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "LINK" }, + { "ONLOAD" }, + { "ONUNLOAD" }, + { "STYLE" }, + { "TITLE" }, + { "TEXT" }, + { "VLINK" }, + { 0 } /* Terminate list */ +}; + +static attr bodytext_attr[] = { /* BODYTEXT attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DATA" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "OBJECT" }, + { "REF" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { "VALUE" }, + { "VALUETYPE" }, + { 0 } /* Terminate list */ +}; + +static attr bq_attr[] = { /* BQ (BLOCKQUOTE) attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NOWRAP" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr button_attr[] = { /* BUTTON attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DISABLED" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "ONFOCUS" }, + { "ONBLUR" }, + { "STYLE" }, + { "TABINDEX" }, + { "TITLE" }, + { "TYPE" }, + { "VALUE" }, + { 0 } /* Terminate list */ +}; + +static attr caption_attr[] = { /* CAPTION attributes */ + { "ACCESSKEY" }, + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr col_attr[] = { /* COL and COLGROUP attributes */ + { "ALIGN" }, + { "CHAR" }, + { "CHAROFF" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "SPAN" }, + { "STYLE" }, + { "TITLE" }, + { "VALIGN" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr credit_attr[] = { /* CREDIT attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr div_attr[] = { /* DIV attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr embed_attr[] = { /* EMBED attributes */ + { "ALIGN" }, /* (including, for now, those from FIG and IMG) */ + { "ALT" }, + { "BORDER" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "HEIGHT" }, + { "ID" }, + { "IMAGEMAP" }, + { "ISMAP" }, + { "LANG" }, + { "MD" }, + { "NAME" }, + { "NOFLOW" }, + { "PARAMS" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "UNITS" }, + { "USEMAP" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr fig_attr[] = { /* FIG attributes */ + { "ALIGN" }, + { "BORDER" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "HEIGHT" }, + { "ID" }, + { "IMAGEMAP" }, + { "ISOBJECT" }, + { "LANG" }, + { "MD" }, + { "NOFLOW" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "UNITS" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr fieldset_attr[] = { /* FIELDSET attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr fn_attr[] = { /* FN attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr font_attr[] = { /* FONT attributes */ + { "CLASS" }, + { "CLEAR" }, + { "COLOR" }, + { "DIR" }, + { "END" }, + { "FACE" }, + { "ID" }, + { "LANG" }, + { "SIZE" }, + { "STYLE" }, + { 0 } /* Terminate list */ +}; + +static attr form_attr[] = { /* FORM attributes */ + { "ACCEPT-CHARSET"}, /* HTML 4.0 draft - kw */ + { "ACTION"}, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ENCTYPE" }, + { "ID" }, + { "LANG" }, + { "METHOD" }, + { "ONSUBMIT" }, + { "SCRIPT" }, + { "STYLE" }, + { "SUBJECT" }, + { "TARGET" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr frame_attr[] = { /* FRAME attributes */ + { "ID" }, + { "MARGINHEIGHT"}, + { "MARGINWIDTH" }, + { "NAME" }, + { "NORESIZE" }, + { "SCROLLING" }, + { "SRC" }, + { 0 } /* Terminate list */ +}; + +static attr frameset_attr[] = { /* FRAMESET attributes */ + { "COLS"}, + { "ROWS" }, + { 0 } /* Terminate list */ +}; + +static attr gen_attr[] = { /* Minimum HTML 3.0 */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr glossary_attr[] = { /* DL (and DLC) attributes */ + { "CLASS" }, + { "CLEAR" }, + { "COMPACT" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr h_attr[] = { /* H1 - H6 attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DINGBAT" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "MD" }, + { "NOWRAP" }, + { "SEQNUM" }, + { "SKIP" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr hr_attr[] = { /* HR attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "MD" }, + { "NOSHADE" }, + { "SIZE" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr iframe_attr[] = { /* IFRAME attributes */ + { "ALIGN" }, + { "FRAMEBORDER" }, + { "HEIGHT" }, + { "ID" }, + { "MARGINHEIGHT"}, + { "MARGINWIDTH" }, + { "NAME" }, + { "SCROLLING" }, + { "SRC" }, + { "STYLE" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr img_attr[] = { /* IMG attributes */ + { "ALIGN" }, + { "ALT" }, + { "BORDER" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "HEIGHT" }, + { "ID" }, + { "ISMAP" }, + { "ISOBJECT" }, + { "LANG" }, + { "MD" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "UNITS" }, + { "USEMAP" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr input_attr[] = { /* INPUT attributes */ + { "ACCEPT" }, + { "ACCEPT-CHARSET" }, /* RFC 2070 HTML i18n - kw */ + { "ALIGN" }, + { "ALT" }, + { "CHECKED" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DISABLED" }, + { "ERROR" }, + { "HEIGHT" }, + { "ID" }, + { "LANG" }, + { "MAX" }, + { "MAXLENGTH" }, + { "MD" }, + { "MIN" }, + { "NAME" }, + { "NOTAB" }, + { "ONBLUR" }, + { "ONCHANGE" }, + { "ONCLICK" }, + { "ONFOCUS" }, + { "ONSELECT" }, + { "SIZE" }, + { "SRC" }, + { "STYLE" }, + { "TABINDEX" }, + { "TITLE" }, + { "TYPE" }, + { "VALUE" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr isindex_attr[] = { /* ISINDEX attributes */ + { "ACTION" }, /* Not in spec. Lynx treats it as HREF. - FM */ + { "DIR" }, + { "HREF" }, /* HTML 3.0 attribute for search action. - FM */ + { "ID" }, + { "LANG" }, + { "PROMPT" }, /* HTML 3.0 attribute for prompt string. - FM */ + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr keygen_attr[] = { /* KEYGEN attributes */ + { "CHALLENGE" }, + { "CLASS" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr label_attr[] = { /* LABEL attributes */ + { "ACCESSKEY" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "FOR" }, + { "ID" }, + { "LANG" }, + { "ONCLICK" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr legend_attr[] = { /* LEGEND attributes */ + { "ACCESSKEY" }, + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr link_attr[] = { /* LINK attributes */ + { "CHARSET" }, /* RFC 2070 HTML i18n -- hint for UA -- - kw */ + { "CLASS" }, + { "HREF" }, + { "ID" }, + { "MEDIA" }, + { "REL" }, + { "REV" }, + { "STYLE" }, + { "TARGET" }, + { "TITLE" }, + { "TYPE" }, + { 0 } /* Terminate list */ +}; + +static attr list_attr[] = { /* LI attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DINGBAT" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "MD" }, + { "SKIP" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { "VALUE" }, + { 0 } /* Terminate list */ +}; + +static attr map_attr[] = { /* MAP attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr math_attr[] = { /* MATH attributes */ + { "BOX" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr meta_attr[] = { /* META attributes */ + { "CONTENT" }, + { "HTTP-EQUIV" }, + { "NAME" }, + { 0 } /* Terminate list */ +}; + +static attr nextid_attr[] = { /* NEXTID attributes */ + { "N" } +}; + +static attr note_attr[] = { /* NOTE attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "MD" }, + { "ROLE" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr object_attr[] = { /* OBJECT attributes */ + { "ALIGN" }, + { "BORDER" }, + { "CLASS" }, + { "CLASSID" }, + { "CODEBASE" }, + { "CODETYPE" }, + { "DATA" }, + { "DECLARE" }, + { "DIR" }, + { "HEIGHT" }, + { "HSPACE" }, + { "ID" }, + { "ISMAP" }, + { "LANG" }, + { "NAME" }, + { "NOTAB" }, + { "SHAPES" }, + { "STANDBY" }, + { "STYLE" }, + { "TABINDEX" }, + { "TITLE" }, + { "TYPE" }, + { "USEMAP" }, + { "VSPACE" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr olist_attr[] = { /* OL attributes */ + { "CLASS" }, + { "CLEAR" }, + { "COMPACT" }, + { "CONTINUE" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "SEQNUM" }, + { "START" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { 0 } /* Terminate list */ +}; + +static attr option_attr[] = { /* OPTION attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DISABLED" }, + { "ERROR" }, + { "ID" }, + { "LANG" }, + { "SELECTED" }, + { "SHAPE" }, + { "STYLE" }, + { "TITLE" }, + { "VALUE" }, + { 0 } /* Terminate list */ +}; + +static attr overlay_attr[] = { /* OVERLAY attributes */ + { "CLASS" }, + { "HEIGHT" }, + { "ID" }, + { "IMAGEMAP" }, + { "MD" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "UNITS" }, + { "WIDTH" }, + { "X" }, + { "Y" }, + { 0 } /* Terminate list */ +}; + +static attr p_attr[] = { /* P attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NOWRAP" }, + { "STYLE" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr param_attr[] = { /* PARAM attributes */ + { "ACCEPT" }, + { "ACCEPT-CHARSET" }, + { "ACCEPT-ENCODING" }, + { "CLASS" }, + { "CLEAR" }, + { "DATA" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "OBJECT" }, + { "REF" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { "VALUE" }, + { "VALUEREF" }, + { "VALUETYPE" }, + { 0 } /* Terminate list */ +}; + +static attr script_attr[] = { /* SCRIPT attributes */ + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "EVENT" }, + { "FOR" }, + { "ID" }, + { "LANG" }, + { "LANGUAGE" }, + { "NAME" }, + { "SCRIPTENGINE" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { 0 } /* Terminate list */ +}; + +static attr select_attr[] = { /* SELECT attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DISABLED" }, + { "ERROR" }, + { "HEIGHT" }, + { "ID" }, + { "LANG" }, + { "MD" }, + { "MULTIPLE" }, + { "NAME" }, + { "NOTAB" }, + { "ONBLUR" }, + { "ONCHANGE" }, + { "ONFOCUS" }, + { "SIZE" }, + { "STYLE" }, + { "TABINDEX" }, + { "TITLE" }, + { "UNITS" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr style_attr[] = { /* STYLE attributes */ + { "DIR" }, + { "LANG" }, + { "NOTATION" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr tab_attr[] = { /* TAB attributes */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DP" }, + { "ID" }, + { "INDENT" }, + { "LANG" }, + { "STYLE" }, + { "TITLE" }, + { "TO" }, + { 0 } /* Terminate list */ +}; + +static attr table_attr[] = { /* TABLE attributes */ + { "ALIGN" }, + { "BORDER" }, + { "CELLPADDING" }, + { "CELLSPACING" }, + { "CLASS" }, + { "CLEAR" }, + { "COLS" }, + { "COLSPEC" }, + { "DIR" }, + { "DP" }, + { "FRAME" }, + { "ID" }, + { "LANG" }, + { "NOFLOW" }, + { "NOWRAP" }, + { "RULES" }, + { "STYLE" }, + { "TITLE" }, + { "UNITS" }, + { "WIDTH" }, + { 0 } /* Terminate list */ +}; + +static attr td_attr[] = { /* TD and TH attributes */ + { "ALIGN" }, + { "AXES" }, + { "AXIS" }, + { "CHAR" }, + { "CHAROFF" }, + { "CLASS" }, + { "CLEAR" }, + { "COLSPAN" }, + { "DIR" }, + { "DP" }, + { "ID" }, + { "LANG" }, + { "NOWRAP" }, + { "ROWSPAN" }, + { "STYLE" }, + { "TITLE" }, + { "VALIGN" }, + { 0 } /* Terminate list */ +}; + +static attr textarea_attr[] = { /* TEXTAREA attributes */ + { "ACCEPT-CHARSET" }, /* RFC 2070 HTML i18n - kw */ + { "ALIGN" }, + { "CLASS" }, + { "CLEAR" }, + { "COLS" }, + { "DIR" }, + { "DISABLED" }, + { "ERROR" }, + { "ID" }, + { "LANG" }, + { "NAME" }, + { "NOTAB" }, + { "ONBLUR" }, + { "ONCHANGE" }, + { "ONFOCUS" }, + { "ONSELECT" }, + { "ROWS" }, + { "STYLE" }, + { "TABINDEX" }, + { "TITLE" }, + { 0 } /* Terminate list */ +}; + +static attr tr_attr[] = { /* TR, THEAD, TFOOT, and TBODY attributes */ + { "ALIGN" }, + { "CHAR" }, + { "CHAROFF" }, + { "CLASS" }, + { "CLEAR" }, + { "DIR" }, + { "DP" }, + { "ID" }, + { "LANG" }, + { "NOWRAP" }, + { "STYLE" }, + { "TITLE" }, + { "VALIGN" }, + { 0 } /* Terminate list */ +}; + +static attr ulist_attr[] = { /* UL attributes */ + { "CLASS" }, + { "CLEAR" }, + { "COMPACT" }, + { "DINGBAT" }, + { "DIR" }, + { "ID" }, + { "LANG" }, + { "MD" }, + { "PLAIN" }, + { "SRC" }, + { "STYLE" }, + { "TITLE" }, + { "TYPE" }, + { "WRAP" }, + { 0 } /* Terminate list */ +}; + +/* From Peter Flynn's intro to the HTML Pro DTD: + + %structure; + + DIV, CENTER, H1 to H6, P, UL, OL, DL, DIR, MENU, PRE, XMP, LISTING, BLOCKQUOTE, BQ, + 2 1 2 2 1 8 8 8 8 8 8 8 8 4 4 + MULTICOL,?NOBR, FORM, TABLE, ADDRESS, FIG, BDO, NOTE, and FN; plus?WBR, LI, and LH + 8 n ?1 n 8 8 2 2 2 2 2 ?1 nE 4 4 + + %insertions; + + Elements which usually contain special-purpose material, or no text material at all. + + BASEFONT, APPLET, OBJECT, EMBED, SCRIPT, MAP, MARQUEE, HR, ISINDEX, BGSOUND, TAB,?IMG, + 1 e? 2 2 l 1 e 2 l 8 4 4 E 1? E 1 E ! E ?1 E + IMAGE, BR, plus NOEMBED, SERVER, SPACER, AUDIOSCOPE, and SIDEBAR; ?area + 1 n 1 E n n n n n 8 E + + %text; + + Elements within the %structure; which directly contain running text. + + Descriptive or analytic markup: EM, STRONG, DFN, CODE, SAMP, KBD, VAR, CITE, Q, LANG, AU, + 2 2 2 2 2 2 2 2 2 2 n 2 + AUTHOR, PERSON, ACRONYM, ABBREV, INS, DEL, and SPAN + 2 2 n 2 2 2 2 2 + Visual markup:S, STRIKE, I, B, TT, U,?NOBR,?WBR, BR, BIG, SMALL, FONT, STYLE, BLINK, TAB, + 1 1 1 1 1 1 ?1 n ?1nE? 1 E 1 1 1 1 l 1 1 E? + BLACKFACE, LIMITTEXT, NOSMARTQUOTES, and SHADOW + 1 n 1 n 1 n 1 n + Hypertext and graphics: A and?IMG + 8 ?8 E + Mathematical: SUB, SUP, and MATH + 4 4 4 l + Documentary: COMMENT, ENTITY, ELEMENT, and ATTRIB + 4 4 n 4 n 4 n + %formula; + */ + +/* Extra element info +** ------------------ +** +** Order and number of tags should match the tags_* tables +** further below and definitions in HTMLDTD.html. +** +** The interspersed comments give the original Lynx tags[] entries +** for orientation, so they do not necessarily reflect what will +** be used with the T_* info (which is in tags_new[]). +** +** An important design goal was that info for each tag should fit on +** one 80 character screen line :). The price to pay is that it's +** a bit cryptic, to say the least... - kw +*/ +/* 1 2 3 4 5 6 7 8 */ +/*345678901234567890123456789012345678901234567890123456789012345678901234567890 */ + +/* self contain icont'n contn'd icont'd canclos omit */ + /* { "A" , a_attr, HTML_A_ATTRIBUTES, SGML_MIXED }, */ +#define T_A 0x0008, 0x0B007,0x0FF17,0x37787,0x77BA7,0x8604F,0x00004 + /* { "ABBREV" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_ABBREV 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "ACRONYM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_ACRONYM 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "ADDRESS" , address_attr, HTML_ADDRESS_ATTRIBUTES, SGML_MIXED }, */ +#define T_ADDRESS 0x0200, 0x0F14F,0x8FFFF,0x36680,0xB6FAF,0x80317,0x00000 + /* { "APPLET" , applet_attr, HTML_APPLET_ATTRIBUTES, SGML_MIXED }, */ +#define T_APPLET 0x2000, 0x0B0CF,0x8FFFF,0x37F9F,0xB7FBF,0x8300F,0x00000 + /* { "AREA" , area_attr, HTML_AREA_ATTRIBUTES, SGML_EMPTY }, */ +#define T_AREA 0x8000, 0x00000,0x00000,0x08000,0x3FFFF,0x00F1F,0x00001 + /* { "AU" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_AU 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "AUTHOR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_AUTHOR 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "B" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_B 0x0001, 0x8B04F,0xAFFFF,0xA778F,0xF7FBF,0x00001,0x00004 + /* { "BANNER" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_BANNER 0x0200, 0x0FB8F,0x0FFFF,0x30000,0x30000,0x8031F,0x00000 + /* { "BASE" , base_attr, HTML_BASE_ATTRIBUTES, SGML_EMPTY }, */ +#define T_BASE 0x40000,0x00000,0x00000,0x50000,0x50000,0x8000F,0x00001 + /* { "BASEFONT", font_attr, HTML_FONT_ATTRIBUTES, SGML_EMPTY }, */ +#define T_BASEFONT 0x1000, 0x00000,0x00000,0x377AF,0x37FAF,0x8F000,0x00001 + /* { "BDO" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_BDO 0x0100, 0x0B04F,0x8FFFF,0x36680,0xB6FAF,0x0033F,0x00000 + /* { "BGSOUND" , bgsound_attr, HTML_BGSOUND_ATTRIBUTES, SGML_EMPTY }, */ +#define T_BGSOUND 0x1000, 0x00000,0x00000,0x777AF,0x77FAF,0x8730F,0x00001 + /* { "BIG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_BIG 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00004 + /* { "BLINK" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_BLINK 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FAF,0x00001,0x00004 + /* { "BLOCKQUOTE", bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED }, */ +#define T_BLOCKQUOTE 0x0200, 0xAFBCF,0xAFFFF,0xB6680,0xB6FAF,0x8031F,0x00000 + /* { "BODY" , body_attr, HTML_BODY_ATTRIBUTES, SGML_MIXED }, */ +#define T_BODY 0x20000,0x2FB8F,0x2FFFF,0x30000,0x30000,0xDFF7F,0x00003 + /* { "BODYTEXT", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED }, */ +#define T_BODYTEXT 0x20000,0x0FB8F,0xAFFFF,0x30200,0xB7FAF,0x8F17F,0x00003 + /* { "BQ" , bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED }, */ +#define T_BQ 0x0200, 0xAFBCF,0xAFFFF,0xB6680,0xB6FAF,0x8031F,0x00000 + /* { "BR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_BR 0x1000, 0x00000,0x00000,0x377BF,0x77FBF,0x8101F,0x00001 +#define T_BUTTON 0x0200, 0x0BB0B,0x0FF3B,0x0378F,0x37FAF,0x8035F,0x00000 + /* { "CAPTION" , caption_attr, HTML_CAPTION_ATTRIBUTES, SGML_MIXED }, */ +#define T_CAPTION 0x0100, 0x0B04F,0x8FFFF,0x06A00,0xB6FA7,0x8035F,0x00000 + /* { "CENTER" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED }, */ +#define T_CENTER 0x0200, 0x8FBCF,0x8FFFF,0xB6680,0xB6FA7,0x8071F,0x00000 + /* { "CITE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_CITE 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00002,0x00000 + /* { "CODE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_CODE 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00002,0x00000 + /* { "COL" , col_attr, HTML_COL_ATTRIBUTES, SGML_EMPTY }, */ +#define T_COL 0x4000, 0x00000,0x00000,0x00820,0x36FA7,0x88F5F,0x00001 + /* { "COLGROUP", col_attr, HTML_COL_ATTRIBUTES, SGML_EMPTY }, */ +#define T_COLGROUP 0x0020, 0x04000,0x04000,0x00800,0x36FA7,0x8875F,0x00001 + /* { "COMMENT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_COMMENT 0x0004, 0x00000,0x00000,0xA77AF,0x7FFFF,0x00003,0x00000 + /* { "CREDIT" , credit_attr, HTML_CREDIT_ATTRIBUTES, SGML_MIXED }, */ +#define T_CREDIT 0x0100, 0x0B04F,0x8FFFF,0x06A00,0xB7FBF,0x8030F,0x00000 + /* { "DD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_DD 0x0400, 0x0FBCF,0x8FFFF,0x00800,0xB6FFF,0x8071F,0x00001 + /* { "DEL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_DEL 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "DFN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_DFN 0x0002, 0x8B0CF,0x8FFFF,0x8778F,0xF7FBF,0x00003,0x00000 + /* { "DIR" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED }, */ +#define T_DIR 0x0800, 0x0B400,0x0F75F,0x37680,0x36FB7,0x84F7F,0x00000 + /* { "DIV" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED }, */ +#define T_DIV 0x0200, 0x8FB8F,0x8FFFF,0xB66A0,0xB7FFF,0x8031F,0x00004 + /* { "DL" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED }, */ +#define T_DL 0x0800, 0x0C480,0x8FFFF,0x36680,0xB7FB7,0x0075F,0x00000 + /* { "DLC" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED }, */ +#define T_DLC 0x0800, 0x0C480,0x8FFFF,0x36680,0xB7FB7,0x0075F,0x00000 + /* { "DT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_DT 0x0400, 0x0B04F,0x0B1FF,0x00800,0x17FFF,0x8071F,0x00001 + /* { "EM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_EM 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FAF,0x00003,0x00000 + /* { "EMBED" , embed_attr, HTML_EMBED_ATTRIBUTES, SGML_EMPTY }, */ +#define T_EMBED 0x2000, 0x8F107,0x8FFF7,0xB6FBF,0xB7FBF,0x1FF7F,0x00001 + /* { "FIELDSET", fieldset_attr,HTML_FIELDSET_ATTRIBUTES, SGML_MIXED }, */ +#define T_FIELDSET 0x0200, 0x0FB42,0x0FF5F,0x07787,0x37FF7,0x8805F,0x00000 + /* { "FIG" , fig_attr, HTML_FIG_ATTRIBUTES, SGML_MIXED }, */ +#define T_FIG 0x0200, 0x0FB00,0x8FFFF,0x36680,0xB6FBF,0x8834F,0x00000 + /* { "FN" , fn_attr, HTML_FN_ATTRIBUTES, SGML_MIXED }, */ +#define T_FN 0x0200, 0x8FBCF,0x8FFFF,0xB6680,0xB7EBF,0x8114F,0x00000 + /* { "FONT" , font_attr, HTML_FONT_ATTRIBUTES, SGML_EMPTY }, */ +#define T_FONT 0x0001, 0x8B04F,0x8FFFF,0xB778F,0xF7FBF,0x00001,0x00004 + /* { "FORM" , form_attr, HTML_FORM_ATTRIBUTES, SGML_EMPTY }, */ +#define T_FORM 0x0080, 0x0FF6F,0x0FF7F,0x36E07,0x33F07,0x88DFF,0x00000 + /* { "FRAME" , frame_attr, HTML_FRAME_ATTRIBUTES, SGML_EMPTY }, */ +#define T_FRAME 0x10000,0x00000,0x00000,0x10000,0x10000,0x9FFFF,0x00001 + /* { "FRAMESET", frameset_attr,HTML_FRAMESET_ATTRIBUTES, SGML_MIXED }, */ +#define T_FRAMESET 0x10000,0x90000,0x90000,0x90000,0x93000,0x9FFFF,0x00000 + /* { "H1" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H1 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "H2" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H2 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "H3" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H3 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "H4" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H4 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "H5" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H5 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "H6" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED }, */ +#define T_H6 0x0100, 0x0B04F,0x0B05F,0x36680,0x37FAF,0x80317,0x00000 + /* { "HEAD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_HEAD 0x40000,0x4F000,0x47000,0x10000,0x10000,0x9FF7F,0x00006 + /* { "HR" , hr_attr, HTML_HR_ATTRIBUTES, SGML_EMPTY }, */ +#define T_HR 0x4000, 0x00000,0x00000,0x3FE80,0x3FFBF,0x87F37,0x00001 + /* { "HTML" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_HTML 0x10000,0x7FB8F,0x7FFFF,0x00000,0x00000,0x1FFFF,0x00003 +#define T_HY 0x1000, 0x00000,0x00000,0x3779F,0x77FBF,0x8101F,0x00001 + /* { "I" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_I 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00004 +#define T_IFRAME 0x2000, 0x8FBCF,0x8FFFF,0xB679F,0xB6FBF,0xD335F,0x00000 + /* { "IMG" , img_attr, HTML_IMG_ATTRIBUTES, SGML_EMPTY }, */ +#define T_IMG 0x1000, 0x00000,0x00000,0x3779F,0x37FBF,0x80000,0x00001 + /* { "INPUT" , input_attr, HTML_INPUT_ATTRIBUTES, SGML_EMPTY }, */ +#define T_INPUT 0x0040, 0x00000,0x00000,0x03F87,0x37F87,0x8904F,0x00001 + /* { "INS" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_INS 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00003,0x00000 + /* { "ISINDEX" , isindex_attr, HTML_ISINDEX_ATTRIBUTES,SGML_EMPTY }, */ +#define T_ISINDEX 0x8000, 0x00000,0x00000,0x7778F,0x7FFAF,0x80007,0x00001 + /* { "KBD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_KBD 0x0002, 0x00000,0x00000,0x2778F,0x77FBF,0x00003,0x00000 + /* { "KEYGEN" , keygen_attr, HTML_KEYGEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_KEYGEN 0x0040, 0x00000,0x00000,0x07FB7,0x37FB7,0x80070,0x00001 + /* { "LABEL" , label_attr, HTML_LABEL_ATTRIBUTES, SGML_MIXED }, */ +#define T_LABEL 0x0020, 0x9FFFF,0x9FFFF,0x9FFFF,0x9FFFF,0x00007,0x00000 +#define T_LEGEND 0x0002, 0x0B04F,0x0FF7F,0x00200,0x37FA7,0x00003,0x00000 + /* { "LH" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_LH 0x0400, 0x0BB7F,0x8FFFF,0x00800,0x97FFF,0x8071F,0x00001 + /* { "LI" , list_attr, HTML_LI_ATTRIBUTES, SGML_EMPTY }, */ +#define T_LI 0x0400, 0x0BBFF,0x8FFFF,0x00800,0x97FFF,0x8071F,0x00001 + /* { "LINK" , link_attr, HTML_LINK_ATTRIBUTES, SGML_EMPTY }, */ +#define T_LINK 0x8000, 0x00000,0x00000,0x50000,0x50000,0x0FF7F,0x00001 + /* { "LISTING" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_LISTING 0x0800, 0x00000,0x00000,0x36600,0x36F00,0x80F1F,0x00000 + /* { "MAP" , map_attr, HTML_MAP_ATTRIBUTES, SGML_MIXED }, */ +#define T_MAP 0x8000, 0x08000,0x08000,0x37FCF,0x37FBF,0x0071F,0x00000 + /* { "MARQUEE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_MARQUEE 0x4000, 0x0000F,0x8F01F,0x37787,0xB7FA7,0x8301C,0x00000 + /* { "MATH" , math_attr, HTML_MATH_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_MATH 0x0004, 0x0B05F,0x8FFFF,0x2778F,0xF7FBF,0x0001F,0x00000 + /* { "MENU" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED }, */ +#define T_MENU 0x0800, 0x0B400,0x0F75F,0x17680,0x36FB7,0x88F7F,0x00000 + /* { "META" , meta_attr, HTML_META_ATTRIBUTES, SGML_EMPTY }, */ +#define T_META 0x8000, 0x00000,0x00000,0x50000,0x50000,0x0FF7F,0x00001 + /* { "NEXTID" , nextid_attr, 1, SGML_EMPTY }, */ +#define T_NEXTID 0x1000, 0x00000,0x00000,0x50000,0x1FFF7,0x00001,0x00001 + /* { "NOFRAMES", gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_NOFRAMES 0x20000,0x2FB8F,0x0FFFF,0x17000,0x17000,0x0CF5F,0x00000 + /* { "NOTE" , note_attr, HTML_NOTE_ATTRIBUTES, SGML_MIXED }, */ +#define T_NOTE 0x0200, 0x0BBAF,0x8FFFF,0x376B0,0xB7FFF,0x8031F,0x00000 + /* { "OBJECT" , object_attr, HTML_OBJECT_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_OBJECT 0x2000, 0x8FBCF,0x8FFFF,0xB679F,0xB6FBF,0x83F5F,0x00000 + /* { "OL" , olist_attr, HTML_OL_ATTRIBUTES, SGML_MIXED }, */ +#define T_OL 0x0800, 0x0C400,0x8FFFF,0x37680,0xB7FB7,0x88F7F,0x00000 + /* { "OPTION" , option_attr, HTML_OPTION_ATTRIBUTES, SGML_EMPTY }, */ +#define T_OPTION 0x8000, 0x00000,0x00000,0x00040,0x37FFF,0x8031F,0x00001 + /* { "OVERLAY" , overlay_attr, HTML_OVERLAY_ATTRIBUTES, SGML_EMPTY }, */ +#define T_OVERLAY 0x4000, 0x00000,0x00000,0x00200,0x37FBF,0x83F7F,0x00001 + /* { "P" , p_attr, HTML_P_ATTRIBUTES, SGML_EMPTY }, */ +#define T_P 0x0100, 0x0B04F,0x8FFFF,0x36680,0xB6FA7,0x80117,0x00001 + /* { "PARAM" , param_attr, HTML_PARAM_ATTRIBUTES, SGML_EMPTY }, */ +#define T_PARAM 0x1000, 0x00000,0x00000,0x03000,0x17FFF,0x81777,0x00001 + /* { "PLAINTEXT", gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_PLAINTEXT 0x10000,0xFFFFF,0xFFFFF,0x90000,0x90000,0x3FFFF,0x00001 + /* { "PRE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_PRE 0x0200, 0x0F04F,0x0F05E,0x36680,0x36FF0,0x8071E,0x00000 + /* { "Q" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_Q 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FAF,0x00003,0x00000 + /* { "S" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_S 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00000 + /* { "SAMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_SAMP 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00002,0x00000 + /* { "SCRIPT" , script_attr, HTML_SCRIPT_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_SCRIPT 0x2000, 0x00000,0x00000,0x77F9F,0x77FFF,0x87F5F,0x00000 + /* { "SELECT" , select_attr, HTML_SELECT_ATTRIBUTES, SGML_MIXED }, */ +#define T_SELECT 0x0040, 0x08000,0x08000,0x03FAF,0x13FBF,0x80F5F,0x00008 +#define T_SHY 0x1000, 0x00000,0x00000,0x3779F,0x77FBF,0x8101F,0x00001 + /* { "SMALL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_SMALL 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00004 + /* { "SPAN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_SPAN 0x0002, 0x0B04F,0x0FFFF,0x2778F,0x77FBF,0x80003,0x00000 + /* { "SPOT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY }, */ +#define T_SPOT 0x0008, 0x00000,0x00000,0x3FFF7,0x3FFF7,0x00008,0x00001 + /* { "STRIKE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_STRIKE 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00000 + /* { "STRONG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_STRONG 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FAF,0x00003,0x00000 + /* { "STYLE" , style_attr, HTML_STYLE_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_STYLE 0x40000,0x00000,0x00000,0x7638F,0x76FAF,0x8001F,0x00000 + /* { "SUB" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_SUB 0x0004, 0x8B05F,0x8FFFF,0x8779F,0xF7FBF,0x00007,0x00000 + /* { "SUP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_SUP 0x0004, 0x8B05F,0x8FFFF,0x8779F,0xF7FBF,0x00007,0x00000 + /* { "TAB" , tab_attr, HTML_TAB_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TAB 0x1000, 0x00000,0x00000,0x3778F,0x57FAF,0x00001,0x00001 + /* { "TABLE" , table_attr, HTML_TABLE_ATTRIBUTES, SGML_MIXED }, */ +#define T_TABLE 0x0800, 0x0F1E0,0x8FFFF,0x36680,0xB6FA7,0x8C57F,0x00000 + /* { "TBODY" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TBODY 0x0020, 0x00020,0x8FFFF,0x00880,0xB7FB7,0x8C75F,0x00003 + /* { "TD" , td_attr, HTML_TD_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TD 0x0400, 0x0FBCF,0x8FFFF,0x00020,0xB7FB7,0x8C75F,0x00001 + /* { "TEXTAREA", textarea_attr,HTML_TEXTAREA_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_TEXTAREA 0x0040, 0x00000,0x00000,0x07F8F,0x33FBF,0x80F5F,0x00000 + /* { "TEXTFLOW", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED }, */ +#define T_TEXTFLOW 0x20000,0x8FBFF,0x9FFFF,0x977B0,0xB7FB7,0x9B00F,0x00003 + /* { "TFOOT" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TFOOT 0x0020, 0x00020,0x8FFFF,0x00800,0xB7FB7,0x8CF5F,0x00001 + /* { "TH" , td_attr, HTML_TD_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TH 0x0400, 0x0FBCF,0x0FFFF,0x00020,0xB7FB7,0x8CF5F,0x00001 + /* { "THEAD" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY }, */ +#define T_THEAD 0x0020, 0x00020,0x8FFFF,0x00880,0xB7FB7,0x8CF5F,0x00001 + /* { "TITLE", gen_attr, HTML_GEN_ATTRIBUTES, SGML_RCDATA }, */ +#define T_TITLE 0x40000,0x00000,0x00000,0x50000,0x50000,0x0031F,0x00004 + /* { "TR" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY }, */ +#define T_TR 0x0020, 0x00400,0x8FFFF,0x00820,0xB7FB7,0x8C75F,0x00001 + /* { "TT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_TT 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00000 + /* { "U" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_U 0x0001, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00004 + /* { "UL" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED }, */ +#define T_UL 0x0800, 0x0C480,0x8FFFF,0x36680,0xB7FFF,0x8075F,0x00000 + /* { "VAR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED }, */ +#define T_VAR 0x0002, 0x8B04F,0x8FFFF,0xA778F,0xF7FBF,0x00001,0x00000 +#define T_WBR 0x0001, 0x00000,0x00000,0x3778F,0x77FBF,0x8101F,0x00001 + /* { "XMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL }, */ +#define T_XMP 0x0800, 0x00000,0x00000,0x367E0,0x36FFF,0x0875F,0x00001 + +#define T__UNREC_ 0x0000, 0x00000,0x00000,0x00000,0x00000,0x00000,0x00000 + +/* Elements +** -------- +** +** Must match definitions in HTMLDTD.html! +** Must be in alphabetical order. +** +** The T_* extra info is listed here, but it won't matter (is not used +** in SGML.c if New_DTD is not set). This mainly simplifies comparison +** of the tags_old[] table (otherwise unchanged from original Lynx treatment) +** with the tags_new[] table below. - kw +** +** Name, Attributes, No. of attributes, content, extra info... +*/ +static HTTag tags_old[HTML_ELEMENTS] = { + { "A" , a_attr, HTML_A_ATTRIBUTES, SGML_EMPTY,T_A}, + { "ABBREV" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_ABBREV}, + { "ACRONYM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_ACRONYM}, + { "ADDRESS" , address_attr, HTML_ADDRESS_ATTRIBUTES, SGML_MIXED,T_ADDRESS}, + { "APPLET" , applet_attr, HTML_APPLET_ATTRIBUTES, SGML_MIXED,T_APPLET}, + { "AREA" , area_attr, HTML_AREA_ATTRIBUTES, SGML_EMPTY,T_AREA}, + { "AU" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_AU}, + { "AUTHOR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_AUTHOR}, + { "B" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_B}, + { "BANNER" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BANNER}, + { "BASE" , base_attr, HTML_BASE_ATTRIBUTES, SGML_EMPTY,T_BASE}, + { "BASEFONT", font_attr, HTML_FONT_ATTRIBUTES, SGML_EMPTY,T_BASEFONT}, + { "BDO" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BDO}, + { "BGSOUND" , bgsound_attr, HTML_BGSOUND_ATTRIBUTES, SGML_EMPTY,T_BGSOUND}, + { "BIG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BIG}, + { "BLINK" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_BLINK}, + { "BLOCKQUOTE", bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED,T_BLOCKQUOTE}, + { "BODY" , body_attr, HTML_BODY_ATTRIBUTES, SGML_MIXED,T_BODY}, + { "BODYTEXT", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED,T_BODYTEXT}, + { "BQ" , bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED,T_BQ}, + { "BR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_BR}, + { "BUTTON" , button_attr, HTML_BUTTON_ATTRIBUTES, SGML_MIXED,T_BUTTON}, + { "CAPTION" , caption_attr, HTML_CAPTION_ATTRIBUTES, SGML_MIXED,T_CAPTION}, + { "CENTER" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED,T_CENTER}, + { "CITE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_CITE}, + { "CODE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_CODE}, + { "COL" , col_attr, HTML_COL_ATTRIBUTES, SGML_EMPTY,T_COL}, + { "COLGROUP", col_attr, HTML_COL_ATTRIBUTES, SGML_EMPTY,T_COLGROUP}, + { "COMMENT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_COMMENT}, + { "CREDIT" , credit_attr, HTML_CREDIT_ATTRIBUTES, SGML_MIXED,T_CREDIT}, + { "DD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_DD}, + { "DEL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DEL}, + { "DFN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DFN}, + { "DIR" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_DIR}, + { "DIV" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED,T_DIV}, + { "DL" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED,T_DL}, + { "DLC" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED,T_DLC}, + { "DT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_DT}, + { "EM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_EM}, + { "EMBED" , embed_attr, HTML_EMBED_ATTRIBUTES, SGML_EMPTY,T_EMBED}, + { "FIELDSET", fieldset_attr,HTML_FIELDSET_ATTRIBUTES, SGML_MIXED,T_FIELDSET}, + { "FIG" , fig_attr, HTML_FIG_ATTRIBUTES, SGML_MIXED,T_FIG}, + { "FN" , fn_attr, HTML_FN_ATTRIBUTES, SGML_MIXED,T_FN}, + { "FONT" , font_attr, HTML_FONT_ATTRIBUTES, SGML_EMPTY,T_FONT}, + { "FORM" , form_attr, HTML_FORM_ATTRIBUTES, SGML_EMPTY,T_FORM}, + { "FRAME" , frame_attr, HTML_FRAME_ATTRIBUTES, SGML_EMPTY,T_FRAME}, + { "FRAMESET", frameset_attr,HTML_FRAMESET_ATTRIBUTES, SGML_MIXED,T_FRAMESET}, + { "H1" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H1}, + { "H2" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H2}, + { "H3" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H3}, + { "H4" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H4}, + { "H5" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H5}, + { "H6" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H6}, + { "HEAD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_HEAD}, + { "HR" , hr_attr, HTML_HR_ATTRIBUTES, SGML_EMPTY,T_HR}, + { "HTML" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_HTML}, + { "HY" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_HY}, + { "I" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_I}, + { "IFRAME" , iframe_attr, HTML_IFRAME_ATTRIBUTES, SGML_MIXED,T_IFRAME}, + { "IMG" , img_attr, HTML_IMG_ATTRIBUTES, SGML_EMPTY,T_IMG}, + { "INPUT" , input_attr, HTML_INPUT_ATTRIBUTES, SGML_EMPTY,T_INPUT}, + { "INS" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_INS}, + { "ISINDEX" , isindex_attr, HTML_ISINDEX_ATTRIBUTES,SGML_EMPTY,T_ISINDEX}, + { "KBD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_KBD}, + { "KEYGEN" , keygen_attr, HTML_KEYGEN_ATTRIBUTES, SGML_EMPTY,T_KEYGEN}, + { "LABEL" , label_attr, HTML_LABEL_ATTRIBUTES, SGML_MIXED,T_LABEL}, + { "LEGEND" , legend_attr, HTML_LEGEND_ATTRIBUTES, SGML_MIXED,T_LEGEND}, + { "LH" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_LH}, + { "LI" , list_attr, HTML_LI_ATTRIBUTES, SGML_EMPTY,T_LI}, + { "LINK" , link_attr, HTML_LINK_ATTRIBUTES, SGML_EMPTY,T_LINK}, + { "LISTING" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_LISTING}, + { "MAP" , map_attr, HTML_MAP_ATTRIBUTES, SGML_MIXED,T_MAP}, + { "MARQUEE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_MARQUEE}, + { "MATH" , math_attr, HTML_MATH_ATTRIBUTES, SGML_LITTERAL,T_MATH}, + { "MENU" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_MENU}, + { "META" , meta_attr, HTML_META_ATTRIBUTES, SGML_EMPTY,T_META}, + { "NEXTID" , nextid_attr, 1, SGML_EMPTY,T_NEXTID}, + { "NOFRAMES", gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_NOFRAMES}, + { "NOTE" , note_attr, HTML_NOTE_ATTRIBUTES, SGML_MIXED,T_NOTE}, + { "OBJECT" , object_attr, HTML_OBJECT_ATTRIBUTES, SGML_LITTERAL,T_OBJECT}, + { "OL" , olist_attr, HTML_OL_ATTRIBUTES, SGML_MIXED,T_OL}, + { "OPTION" , option_attr, HTML_OPTION_ATTRIBUTES, SGML_EMPTY,T_OPTION}, + { "OVERLAY" , overlay_attr, HTML_OVERLAY_ATTRIBUTES, SGML_EMPTY,T_OVERLAY}, + { "P" , p_attr, HTML_P_ATTRIBUTES, SGML_EMPTY,T_P}, + { "PARAM" , param_attr, HTML_PARAM_ATTRIBUTES, SGML_EMPTY,T_PARAM}, + { "PLAINTEXT", gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_PLAINTEXT}, + { "PRE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_PRE}, + { "Q" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_Q}, + { "S" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_S}, + { "SAMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SAMP}, + { "SCRIPT" , script_attr, HTML_SCRIPT_ATTRIBUTES, SGML_LITTERAL,T_SCRIPT}, + { "SELECT" , select_attr, HTML_SELECT_ATTRIBUTES, SGML_MIXED,T_SELECT}, + { "SHY" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_SHY}, + { "SMALL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SMALL}, + { "SPAN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SPAN}, + { "SPOT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_SPOT}, + { "STRIKE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_STRIKE}, + { "STRONG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_STRONG}, + { "STYLE" , style_attr, HTML_STYLE_ATTRIBUTES, SGML_LITTERAL,T_STYLE}, + { "SUB" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SUB}, + { "SUP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SUP}, + { "TAB" , tab_attr, HTML_TAB_ATTRIBUTES, SGML_EMPTY,T_TAB}, + { "TABLE" , table_attr, HTML_TABLE_ATTRIBUTES, SGML_MIXED,T_TABLE}, + { "TBODY" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY,T_TBODY}, + { "TD" , td_attr, HTML_TD_ATTRIBUTES, SGML_EMPTY,T_TD}, + { "TEXTAREA", textarea_attr,HTML_TEXTAREA_ATTRIBUTES, SGML_LITTERAL,T_TEXTAREA}, + { "TEXTFLOW", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED,T_TEXTFLOW}, + { "TFOOT" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY,T_TFOOT}, + { "TH" , td_attr, HTML_TD_ATTRIBUTES, SGML_EMPTY,T_TH}, + { "THEAD" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY,T_THEAD}, + { "TITLE", gen_attr, HTML_GEN_ATTRIBUTES, SGML_RCDATA,T_TITLE}, + { "TR" , tr_attr, HTML_TR_ATTRIBUTES, SGML_EMPTY,T_TR}, + { "TT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_TT}, + { "U" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_U}, + { "UL" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_UL}, + { "VAR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_VAR}, + { "WBR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_WBR}, + { "XMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_XMP}, +}; + +static HTTag tags_new[HTML_ELEMENTS] = { + { "A" , a_attr, HTML_A_ATTRIBUTES, SGML_MIXED,T_A}, + { "ABBREV" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_ABBREV}, + { "ACRONYM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_ACRONYM}, + { "ADDRESS" , address_attr, HTML_ADDRESS_ATTRIBUTES, SGML_MIXED,T_ADDRESS}, + { "APPLET" , applet_attr, HTML_APPLET_ATTRIBUTES, SGML_MIXED,T_APPLET}, + { "AREA" , area_attr, HTML_AREA_ATTRIBUTES, SGML_EMPTY,T_AREA}, + { "AU" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_AU}, + { "AUTHOR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_AUTHOR}, + { "B" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_B}, + { "BANNER" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BANNER}, + { "BASE" , base_attr, HTML_BASE_ATTRIBUTES, SGML_EMPTY,T_BASE}, + { "BASEFONT", font_attr, HTML_FONT_ATTRIBUTES, SGML_EMPTY,T_BASEFONT}, + { "BDO" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BDO}, + { "BGSOUND" , bgsound_attr, HTML_BGSOUND_ATTRIBUTES, SGML_EMPTY,T_BGSOUND}, + { "BIG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BIG}, + { "BLINK" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_BLINK}, + { "BLOCKQUOTE", bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED,T_BLOCKQUOTE}, + { "BODY" , body_attr, HTML_BODY_ATTRIBUTES, SGML_MIXED,T_BODY}, + { "BODYTEXT", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED,T_BODYTEXT}, + { "BQ" , bq_attr, HTML_BQ_ATTRIBUTES, SGML_MIXED,T_BQ}, + { "BR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_BR}, + { "BUTTON" , button_attr, HTML_BUTTON_ATTRIBUTES, SGML_MIXED,T_BUTTON}, + { "CAPTION" , caption_attr, HTML_CAPTION_ATTRIBUTES, SGML_MIXED,T_CAPTION}, + { "CENTER" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED,T_CENTER}, + { "CITE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_CITE}, + { "CODE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_CODE}, + { "COL" , col_attr, HTML_COL_ATTRIBUTES, SGML_EMPTY,T_COL}, + { "COLGROUP", col_attr, HTML_COL_ATTRIBUTES, SGML_ELEMENT,T_COLGROUP}, + { "COMMENT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_PCDATA,T_COMMENT}, + { "CREDIT" , credit_attr, HTML_CREDIT_ATTRIBUTES, SGML_MIXED,T_CREDIT}, + { "DD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DD}, + { "DEL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DEL}, + { "DFN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DFN}, + { "DIR" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_DIR}, + { "DIV" , div_attr, HTML_DIV_ATTRIBUTES, SGML_MIXED,T_DIV}, + { "DL" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED,T_DL}, + { "DLC" , glossary_attr, HTML_DL_ATTRIBUTES, SGML_MIXED,T_DLC}, + { "DT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_DT}, + { "EM" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_EM}, + { "EMBED" , embed_attr, HTML_EMBED_ATTRIBUTES, SGML_EMPTY,T_EMBED}, + { "FIELDSET", fieldset_attr,HTML_FIELDSET_ATTRIBUTES, SGML_MIXED,T_FIELDSET}, + { "FIG" , fig_attr, HTML_FIG_ATTRIBUTES, SGML_MIXED,T_FIG}, + { "FN" , fn_attr, HTML_FN_ATTRIBUTES, SGML_MIXED,T_FN}, + { "FONT" , font_attr, HTML_FONT_ATTRIBUTES, SGML_MIXED,T_FONT}, + { "FORM" , form_attr, HTML_FORM_ATTRIBUTES, SGML_MIXED,T_FORM}, + { "FRAME" , frame_attr, HTML_FRAME_ATTRIBUTES, SGML_EMPTY,T_FRAME}, + { "FRAMESET", frameset_attr,HTML_FRAMESET_ATTRIBUTES, SGML_ELEMENT,T_FRAMESET}, + { "H1" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H1}, + { "H2" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H2}, + { "H3" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H3}, + { "H4" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H4}, + { "H5" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H5}, + { "H6" , h_attr, HTML_H_ATTRIBUTES, SGML_MIXED,T_H6}, + { "HEAD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_ELEMENT,T_HEAD}, + { "HR" , hr_attr, HTML_HR_ATTRIBUTES, SGML_EMPTY,T_HR}, + { "HTML" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_HTML}, + { "HY" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_HY}, + { "I" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_I}, + { "IFRAME" , iframe_attr, HTML_IFRAME_ATTRIBUTES, SGML_MIXED,T_IFRAME}, + { "IMG" , img_attr, HTML_IMG_ATTRIBUTES, SGML_EMPTY,T_IMG}, + { "INPUT" , input_attr, HTML_INPUT_ATTRIBUTES, SGML_EMPTY,T_INPUT}, + { "INS" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_INS}, + { "ISINDEX" , isindex_attr, HTML_ISINDEX_ATTRIBUTES,SGML_EMPTY,T_ISINDEX}, + { "KBD" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_KBD}, + { "KEYGEN" , keygen_attr, HTML_KEYGEN_ATTRIBUTES, SGML_EMPTY,T_KEYGEN}, + { "LABEL" , label_attr, HTML_LABEL_ATTRIBUTES, SGML_MIXED,T_LABEL}, + { "LEGEND" , legend_attr, HTML_LEGEND_ATTRIBUTES, SGML_MIXED,T_LEGEND}, + { "LH" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_LH}, + { "LI" , list_attr, HTML_LI_ATTRIBUTES, SGML_MIXED,T_LI}, + { "LINK" , link_attr, HTML_LINK_ATTRIBUTES, SGML_EMPTY,T_LINK}, + { "LISTING" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_LISTING}, + { "MAP" , map_attr, HTML_MAP_ATTRIBUTES, SGML_ELEMENT,T_MAP}, + { "MARQUEE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_MARQUEE}, + { "MATH" , math_attr, HTML_MATH_ATTRIBUTES, SGML_LITTERAL,T_MATH}, + { "MENU" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_MENU}, + { "META" , meta_attr, HTML_META_ATTRIBUTES, SGML_EMPTY,T_META}, + { "NEXTID" , nextid_attr, 1, SGML_EMPTY,T_NEXTID}, + { "NOFRAMES", gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_NOFRAMES}, + { "NOTE" , note_attr, HTML_NOTE_ATTRIBUTES, SGML_MIXED,T_NOTE}, + { "OBJECT" , object_attr, HTML_OBJECT_ATTRIBUTES, SGML_LITTERAL,T_OBJECT}, + { "OL" , olist_attr, HTML_OL_ATTRIBUTES, SGML_MIXED,T_OL}, + { "OPTION" , option_attr, HTML_OPTION_ATTRIBUTES, SGML_PCDATA,T_OPTION}, + { "OVERLAY" , overlay_attr, HTML_OVERLAY_ATTRIBUTES, SGML_PCDATA,T_OVERLAY}, + { "P" , p_attr, HTML_P_ATTRIBUTES, SGML_MIXED,T_P}, + { "PARAM" , param_attr, HTML_PARAM_ATTRIBUTES, SGML_EMPTY,T_PARAM}, + { "PLAINTEXT", gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_PLAINTEXT}, + { "PRE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_PRE}, + { "Q" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_Q}, + { "S" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_S}, + { "SAMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SAMP}, + { "SCRIPT" , script_attr, HTML_SCRIPT_ATTRIBUTES, SGML_LITTERAL,T_SCRIPT}, + { "SELECT" , select_attr, HTML_SELECT_ATTRIBUTES, SGML_ELEMENT,T_SELECT}, + { "SHY" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_SHY}, + { "SMALL" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SMALL}, + { "SPAN" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SPAN}, + { "SPOT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_SPOT}, + { "STRIKE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_STRIKE}, + { "STRONG" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_STRONG}, + { "STYLE" , style_attr, HTML_STYLE_ATTRIBUTES, SGML_LITTERAL,T_STYLE}, + { "SUB" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SUB}, + { "SUP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_SUP}, + { "TAB" , tab_attr, HTML_TAB_ATTRIBUTES, SGML_EMPTY,T_TAB}, + { "TABLE" , table_attr, HTML_TABLE_ATTRIBUTES, SGML_ELEMENT,T_TABLE}, + { "TBODY" , tr_attr, HTML_TR_ATTRIBUTES, SGML_ELEMENT,T_TBODY}, + { "TD" , td_attr, HTML_TD_ATTRIBUTES, SGML_MIXED,T_TD}, + { "TEXTAREA", textarea_attr,HTML_TEXTAREA_ATTRIBUTES, SGML_LITTERAL,T_TEXTAREA}, + { "TEXTFLOW", bodytext_attr,HTML_BODYTEXT_ATTRIBUTES, SGML_MIXED,T_TEXTFLOW}, + { "TFOOT" , tr_attr, HTML_TR_ATTRIBUTES, SGML_ELEMENT,T_TFOOT}, + { "TH" , td_attr, HTML_TD_ATTRIBUTES, SGML_MIXED,T_TH}, + { "THEAD" , tr_attr, HTML_TR_ATTRIBUTES, SGML_ELEMENT,T_THEAD}, + { "TITLE" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_PCDATA,T_TITLE}, + { "TR" , tr_attr, HTML_TR_ATTRIBUTES, SGML_MIXED,T_TR}, + { "TT" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_TT}, + { "U" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_U}, + { "UL" , ulist_attr, HTML_UL_ATTRIBUTES, SGML_MIXED,T_UL}, + { "VAR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_MIXED,T_VAR}, + { "WBR" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_EMPTY,T_WBR}, + { "XMP" , gen_attr, HTML_GEN_ATTRIBUTES, SGML_LITTERAL,T_XMP}, +}; + +/* Dummy space, will be filled with the contents of either tags_new + or tags_old on calling HTSwitchDTD - kw */ + +static HTTag tags[HTML_ELEMENTS]; + +PUBLIC CONST SGML_dtd HTML_dtd = { + tags, + HTML_ELEMENTS, + entities, + sizeof(entities)/sizeof(entities[0]), + unicode_entities, + sizeof(unicode_entities)/sizeof(unicode_entities[0]) +}; + +/* This function fills the "tags" part of the HTML_dtd structure with + what we want to use, either tags_old or tags_new. Note that it + has to be called at least once before HTML_dtd is used, otherwise + the HTML_dtd contents will be invalid! This could be coded in a way + that would make an initialisation call unnecessary, but my C knowledge + is limited and I didn't want to list the whole tags_new table + twice... - kw */ +PUBLIC void HTSwitchDTD ARGS1( + BOOL, new) +{ + if (TRACE) + fprintf(stderr,"HTMLDTD: Copying DTD element info of size %d, %d * %d\n", + new ? sizeof(tags_new) : sizeof(tags_old), + HTML_ELEMENTS, sizeof(HTTag)); + if (new) + memcpy(tags, tags_new, HTML_ELEMENTS * sizeof(HTTag)); + else + memcpy(tags, tags_old, HTML_ELEMENTS * sizeof(HTTag)); +} + +PUBLIC CONST HTTag HTTag_unrecognized = + { NULL, NULL, 0, SGML_EMPTY,T__UNREC_}; + +/* +** Utility Routine: Useful for people building HTML objects. +*/ + +/* Start anchor element +** -------------------- +** +** It is kinda convenient to have a particulr routine for +** starting an anchor element, as everything else for HTML is +** simple anyway. +*/ +struct _HTStructured { + HTStructuredClass * isa; + /* ... */ +}; + +PUBLIC void HTStartAnchor ARGS3( + HTStructured *, obj, + CONST char *, name, + CONST char *, href) +{ + BOOL present[HTML_A_ATTRIBUTES]; + CONST char * value[HTML_A_ATTRIBUTES]; + int i; + + for (i = 0; i < HTML_A_ATTRIBUTES; i++) + present[i] = NO; + + if (name && *name) { + present[HTML_A_NAME] = YES; + value[HTML_A_NAME] = (CONST char *)name; + } + if (href) { + present[HTML_A_HREF] = YES; + value[HTML_A_HREF] = (CONST char *)href; + } + + (*obj->isa->start_element)(obj, HTML_A, present, value, -1, 0); +} + +PUBLIC void HTStartIsIndex ARGS3( + HTStructured *, obj, + CONST char *, prompt, + CONST char *, href) +{ + BOOL present[HTML_ISINDEX_ATTRIBUTES]; + CONST char * value[HTML_ISINDEX_ATTRIBUTES]; + int i; + + for (i = 0; i < HTML_ISINDEX_ATTRIBUTES; i++) + present[i] = NO; + + if (prompt && *prompt) { + present[HTML_ISINDEX_PROMPT] = YES; + value[HTML_ISINDEX_PROMPT] = (CONST char *)prompt; + } + if (href) { + present[HTML_ISINDEX_HREF] = YES; + value[HTML_ISINDEX_HREF] = (CONST char *)href; + } + + (*obj->isa->start_element)(obj, HTML_ISINDEX , present, value, -1, 0); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.h new file mode 100644 index 00000000000..15004a1d7da --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.h @@ -0,0 +1,1006 @@ +/* The HTML DTD -- software interface in libwww + HTML DTD - SOFTWARE INTERFACE + + SGML purists should excuse the use of the term "DTD" in this file to + represent DTD-related information which is not exactly a DTD itself. + + The C modular structure doesn't work very well here, as the dtd is + partly in the .h and partly in the .c which are not very independent. + Tant pis. + + */ +#ifndef HTMLDTD_H +#define HTMLDTD_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "SGML.h" + +/* +** Lynx internal character representations. +*/ +#ifndef HT_NON_BREAK_SPACE +#define HT_NON_BREAK_SPACE ((char)1) /* For now */ +#endif /* !HT_NON_BREAK_SPACE */ +#ifndef HT_EM_SPACE +#define HT_EM_SPACE ((char)2) /* For now */ +#endif /* !HT_EM_SPACE */ +#ifndef LY_SOFT_HYPHEN +#define LY_SOFT_HYPHEN ((char)7) +#endif /* !LY_SOFT_HYPHEN */ + +/* + +Element Numbers + + */ + +/* + + Must Match all tables by element! + These include tables in HTMLDTD.c and code in HTML.c. + + */ +typedef enum _HTMLElement { + HTML_A, + HTML_ABBREV, + HTML_ACRONYM, + HTML_ADDRESS, + HTML_APPLET, + HTML_AREA, + HTML_AU, + HTML_AUTHOR, + HTML_B, + HTML_BANNER, + HTML_BASE, + HTML_BASEFONT, + HTML_BDO, + HTML_BGSOUND, + HTML_BIG, + HTML_BLINK, + HTML_BLOCKQUOTE, + HTML_BODY, + HTML_BODYTEXT, + HTML_BQ, + HTML_BR, + HTML_BUTTON, + HTML_CAPTION, + HTML_CENTER, + HTML_CITE, + HTML_CODE, + HTML_COL, + HTML_COLGROUP, + HTML_COMMENT, + HTML_CREDIT, + HTML_DD, + HTML_DEL, + HTML_DFN, + HTML_DIR, + HTML_DIV, + HTML_DL, + HTML_DLC, + HTML_DT, + HTML_EM, + HTML_EMBED, + HTML_FIELDSET, + HTML_FIG, + HTML_FN, + HTML_FONT, + HTML_FORM, + HTML_FRAME, + HTML_FRAMESET, + HTML_H1, + HTML_H2, + HTML_H3, + HTML_H4, + HTML_H5, + HTML_H6, + HTML_HEAD, + HTML_HR, + HTML_HTML, + HTML_HY, + HTML_I, + HTML_IFRAME, + HTML_IMG, + HTML_INPUT, + HTML_INS, + HTML_ISINDEX, + HTML_KBD, + HTML_KEYGEN, + HTML_LABEL, + HTML_LEGEND, + HTML_LH, + HTML_LI, + HTML_LINK, + HTML_LISTING, + HTML_MAP, + HTML_MARQUEE, + HTML_MATH, + HTML_MENU, + HTML_META, + HTML_NEXTID, + HTML_NOFRAMES, + HTML_NOTE, + HTML_OBJECT, + HTML_OL, + HTML_OPTION, + HTML_OVERLAY, + HTML_P, + HTML_PARAM, + HTML_PLAINTEXT, + HTML_PRE, + HTML_Q, + HTML_S, + HTML_SAMP, + HTML_SCRIPT, + HTML_SELECT, + HTML_SHY, + HTML_SMALL, + HTML_SPAN, + HTML_SPOT, + HTML_STRIKE, + HTML_STRONG, + HTML_STYLE, + HTML_SUB, + HTML_SUP, + HTML_TAB, + HTML_TABLE, + HTML_TBODY, + HTML_TD, + HTML_TEXTAREA, + HTML_TEXTFLOW, + HTML_TFOOT, + HTML_TH, + HTML_THEAD, + HTML_TITLE, + HTML_TR, + HTML_TT, + HTML_U, + HTML_UL, + HTML_VAR, + HTML_WBR, + HTML_XMP } HTMLElement; + +#define HTML_ELEMENTS 118 + +/* + +Attribute numbers + + */ + +/* + + Identifier is HTML_<element>_<attribute>. + These must match the tables in HTML.c! + + */ +#define HTML_A_ACCESSKEY 0 +#define HTML_A_CHARSET 1 /* i18n draft, added tentatively - KW */ +#define HTML_A_CLASS 2 +#define HTML_A_CLEAR 3 +#define HTML_A_COORDS 4 +#define HTML_A_DIR 5 +#define HTML_A_HREF 6 +#define HTML_A_ID 7 +#define HTML_A_ISMAP 8 +#define HTML_A_LANG 9 +#define HTML_A_MD 10 +#define HTML_A_NAME 11 +#define HTML_A_NOTAB 12 +#define HTML_A_ONCLICK 13 +#define HTML_A_ONMOUSEOUT 14 +#define HTML_A_ONMOUSEOVER 15 +#define HTML_A_REL 16 +#define HTML_A_REV 17 +#define HTML_A_SHAPE 18 +#define HTML_A_STYLE 19 +#define HTML_A_TABINDEX 20 +#define HTML_A_TARGET 21 +#define HTML_A_TITLE 22 +#define HTML_A_TYPE 23 +#define HTML_A_URN 24 +#define HTML_A_ATTRIBUTES 25 + +#define HTML_ADDRESS_CLASS 0 +#define HTML_ADDRESS_CLEAR 1 +#define HTML_ADDRESS_DIR 2 +#define HTML_ADDRESS_ID 3 +#define HTML_ADDRESS_LANG 4 +#define HTML_ADDRESS_NOWRAP 5 +#define HTML_ADDRESS_STYLE 6 +#define HTML_ADDRESS_TITLE 7 +#define HTML_ADDRESS_ATTRIBUTES 8 + +#define HTML_APPLET_ALIGN 0 +#define HTML_APPLET_ALT 1 +#define HTML_APPLET_CLASS 2 +#define HTML_APPLET_CLEAR 3 +#define HTML_APPLET_CODE 4 +#define HTML_APPLET_CODEBASE 5 +#define HTML_APPLET_DIR 6 +#define HTML_APPLET_DOWNLOAD 7 +#define HTML_APPLET_HEIGHT 8 +#define HTML_APPLET_HSPACE 9 +#define HTML_APPLET_ID 10 +#define HTML_APPLET_LANG 11 +#define HTML_APPLET_NAME 12 +#define HTML_APPLET_STYLE 13 +#define HTML_APPLET_TITLE 14 +#define HTML_APPLET_VSPACE 15 +#define HTML_APPLET_WIDTH 16 +#define HTML_APPLET_ATTRIBUTES 17 + +#define HTML_AREA_ALT 0 +#define HTML_AREA_CLASS 1 +#define HTML_AREA_CLEAR 2 +#define HTML_AREA_COORDS 3 +#define HTML_AREA_DIR 4 +#define HTML_AREA_HREF 5 +#define HTML_AREA_ID 6 +#define HTML_AREA_LANG 7 +#define HTML_AREA_NOHREF 8 +#define HTML_AREA_NONOTAB 9 +#define HTML_AREA_ONCLICK 10 +#define HTML_AREA_ONMOUSEOUT 11 +#define HTML_AREA_ONMOUSEOVER 12 +#define HTML_AREA_SHAPE 13 +#define HTML_AREA_STYLE 14 +#define HTML_AREA_TABINDEX 15 +#define HTML_AREA_TARGET 16 +#define HTML_AREA_TITLE 17 +#define HTML_AREA_ATTRIBUTES 18 + +#define HTML_BASE_HREF 0 +#define HTML_BASE_TARGET 1 +#define HTML_BASE_TITLE 2 +#define HTML_BASE_ATTRIBUTES 3 + +#define HTML_BGSOUND_CLASS 0 +#define HTML_BGSOUND_CLEAR 1 +#define HTML_BGSOUND_DIR 2 +#define HTML_BGSOUND_ID 3 +#define HTML_BGSOUND_LANG 4 +#define HTML_BGSOUND_LOOP 5 +#define HTML_BGSOUND_SRC 6 +#define HTML_BGSOUND_STYLE 7 +#define HTML_BGSOUND_TITLE 8 +#define HTML_BGSOUND_ATTRIBUTES 9 + +#define HTML_BODY_ALINK 0 +#define HTML_BODY_BACKGROUND 1 +#define HTML_BODY_BGCOLOR 2 +#define HTML_BODY_CLASS 3 +#define HTML_BODY_CLEAR 4 +#define HTML_BODY_DIR 5 +#define HTML_BODY_ID 6 +#define HTML_BODY_LANG 7 +#define HTML_BODY_LINK 8 +#define HTML_BODY_ONLOAD 9 +#define HTML_BODY_ONUNLOAD 10 +#define HTML_BODY_STYLE 11 +#define HTML_BODY_TEXT 12 +#define HTML_BODY_TITLE 13 +#define HTML_BODY_VLINK 14 +#define HTML_BODY_ATTRIBUTES 15 + +#define HTML_BODYTEXT_CLASS 0 +#define HTML_BODYTEXT_CLEAR 1 +#define HTML_BODYTEXT_DATA 2 +#define HTML_BODYTEXT_DIR 3 +#define HTML_BODYTEXT_ID 4 +#define HTML_BODYTEXT_LANG 5 +#define HTML_BODYTEXT_NAME 6 +#define HTML_BODYTEXT_OBJECT 7 +#define HTML_BODYTEXT_REF 8 +#define HTML_BODYTEXT_STYLE 9 +#define HTML_BODYTEXT_TITLE 10 +#define HTML_BODYTEXT_TYPE 11 +#define HTML_BODYTEXT_VALUE 12 +#define HTML_BODYTEXT_VALUETYPE 13 +#define HTML_BODYTEXT_ATTRIBUTES 14 + +#define HTML_BQ_CLASS 0 +#define HTML_BQ_CLEAR 1 +#define HTML_BQ_DIR 2 +#define HTML_BQ_ID 3 +#define HTML_BQ_LANG 4 +#define HTML_BQ_NOWRAP 5 +#define HTML_BQ_STYLE 6 +#define HTML_BQ_TITLE 7 +#define HTML_BQ_ATTRIBUTES 8 + +#define HTML_BUTTON_CLASS 0 +#define HTML_BUTTON_CLEAR 1 +#define HTML_BUTTON_DIR 2 +#define HTML_BUTTON_DISABLED 3 +#define HTML_BUTTON_ID 4 +#define HTML_BUTTON_LANG 5 +#define HTML_BUTTON_NAME 6 +#define HTML_BUTTON_ONFOCUS 7 +#define HTML_BUTTON_ONBLUR 8 +#define HTML_BUTTON_STYLE 9 +#define HTML_BUTTON_TABINDEX 10 +#define HTML_BUTTON_TITLE 11 +#define HTML_BUTTON_TYPE 12 +#define HTML_BUTTON_VALUE 13 +#define HTML_BUTTON_ATTRIBUTES 14 + +#define HTML_CAPTION_ACCESSKEY 0 +#define HTML_CAPTION_ALIGN 1 +#define HTML_CAPTION_CLASS 2 +#define HTML_CAPTION_CLEAR 3 +#define HTML_CAPTION_DIR 4 +#define HTML_CAPTION_ID 5 +#define HTML_CAPTION_LANG 6 +#define HTML_CAPTION_STYLE 7 +#define HTML_CAPTION_TITLE 8 +#define HTML_CAPTION_ATTRIBUTES 9 + +#define HTML_COL_ALIGN 0 +#define HTML_COL_CHAR 1 +#define HTML_COL_CHAROFF 2 +#define HTML_COL_CLASS 3 +#define HTML_COL_CLEAR 4 +#define HTML_COL_DIR 5 +#define HTML_COL_ID 6 +#define HTML_COL_LANG 7 +#define HTML_COL_SPAN 8 +#define HTML_COL_STYLE 9 +#define HTML_COL_TITLE 10 +#define HTML_COL_VALIGN 11 +#define HTML_COL_WIDTH 12 +#define HTML_COL_ATTRIBUTES 13 + +#define HTML_CREDIT_CLASS 0 +#define HTML_CREDIT_CLEAR 1 +#define HTML_CREDIT_DIR 2 +#define HTML_CREDIT_ID 3 +#define HTML_CREDIT_LANG 4 +#define HTML_CREDIT_STYLE 5 +#define HTML_CREDIT_TITLE 6 +#define HTML_CREDIT_ATTRIBUTES 7 + +#define HTML_DIV_ALIGN 0 +#define HTML_DIV_CLASS 1 +#define HTML_DIV_CLEAR 2 +#define HTML_DIV_DIR 3 +#define HTML_DIV_ID 4 +#define HTML_DIV_LANG 5 +#define HTML_DIV_STYLE 6 +#define HTML_DIV_TITLE 7 +#define HTML_DIV_ATTRIBUTES 8 + +#define HTML_DL_CLASS 0 +#define HTML_DL_CLEAR 1 +#define HTML_DL_COMPACT 2 +#define HTML_DL_DIR 3 +#define HTML_DL_ID 4 +#define HTML_DL_LANG 5 +#define HTML_DL_STYLE 6 +#define HTML_DL_TITLE 7 +#define HTML_DL_ATTRIBUTES 8 + +#define HTML_EMBED_ALIGN 0 +#define HTML_EMBED_ALT 1 +#define HTML_EMBED_BORDER 2 +#define HTML_EMBED_CLASS 3 +#define HTML_EMBED_CLEAR 4 +#define HTML_EMBED_DIR 5 +#define HTML_EMBED_HEIGHT 6 +#define HTML_EMBED_ID 7 +#define HTML_EMBED_IMAGEMAP 8 +#define HTML_EMBED_ISMAP 9 +#define HTML_EMBED_LANG 10 +#define HTML_EMBED_MD 11 +#define HTML_EMBED_NAME 12 +#define HTML_EMBED_NOFLOW 13 +#define HTML_EMBED_PARAMS 14 +#define HTML_EMBED_SRC 15 +#define HTML_EMBED_STYLE 16 +#define HTML_EMBED_TITLE 17 +#define HTML_EMBED_UNITS 18 +#define HTML_EMBED_USEMAP 19 +#define HTML_EMBED_WIDTH 20 +#define HTML_EMBED_ATTRIBUTES 21 + +#define HTML_FIELDSET_CLASS 0 +#define HTML_FIELDSET_CLEAR 1 +#define HTML_FIELDSET_DIR 2 +#define HTML_FIELDSET_ID 3 +#define HTML_FIELDSET_LANG 4 +#define HTML_FIELDSET_STYLE 5 +#define HTML_FIELDSET_TITLE 6 +#define HTML_FIELDSET_ATTRIBUTES 7 + +#define HTML_FIG_ALIGN 0 +#define HTML_FIG_BORDER 1 +#define HTML_FIG_CLASS 2 +#define HTML_FIG_CLEAR 3 +#define HTML_FIG_DIR 4 +#define HTML_FIG_HEIGHT 5 +#define HTML_FIG_ID 6 +#define HTML_FIG_IMAGEMAP 7 +#define HTML_FIG_ISOBJECT 8 +#define HTML_FIG_LANG 9 +#define HTML_FIG_MD 10 +#define HTML_FIG_NOFLOW 11 +#define HTML_FIG_SRC 12 +#define HTML_FIG_STYLE 13 +#define HTML_FIG_TITLE 14 +#define HTML_FIG_UNITS 15 +#define HTML_FIG_WIDTH 16 +#define HTML_FIG_ATTRIBUTES 17 + +#define HTML_FN_CLASS 0 +#define HTML_FN_CLEAR 1 +#define HTML_FN_DIR 2 +#define HTML_FN_ID 3 +#define HTML_FN_LANG 4 +#define HTML_FN_STYLE 5 +#define HTML_FN_TITLE 6 +#define HTML_FN_ATTRIBUTES 7 + +#define HTML_FONT_CLASS 0 +#define HTML_FONT_CLEAR 1 +#define HTML_FONT_COLOR 2 +#define HTML_FONT_DIR 3 +#define HTML_FONT_FACE 4 +#define HTML_FONT_ID 5 +#define HTML_FONT_LANG 6 +#define HTML_FONT_SIZE 7 +#define HTML_FONT_STYLE 8 +#define HTML_FONT_ATTRIBUTES 9 + +#define HTML_FORM_ACCEPT_CHARSET 0 /* HTML 4.0 draft - kw */ +#define HTML_FORM_ACTION 1 +#define HTML_FORM_CLASS 2 +#define HTML_FORM_CLEAR 3 +#define HTML_FORM_DIR 4 +#define HTML_FORM_ENCTYPE 5 +#define HTML_FORM_ID 6 +#define HTML_FORM_LANG 7 +#define HTML_FORM_METHOD 8 +#define HTML_FORM_ONSUBMIT 9 +#define HTML_FORM_SCRIPT 10 +#define HTML_FORM_STYLE 11 +#define HTML_FORM_SUBJECT 12 +#define HTML_FORM_TARGET 13 +#define HTML_FORM_TITLE 14 +#define HTML_FORM_ATTRIBUTES 15 + +#define HTML_FRAME_ID 0 +#define HTML_FRAME_MARGINHEIGHT 1 +#define HTML_FRAME_MARGINWIDTH 2 +#define HTML_FRAME_NAME 3 +#define HTML_FRAME_NORESIZE 4 +#define HTML_FRAME_SCROLLING 5 +#define HTML_FRAME_SRC 6 +#define HTML_FRAME_ATTRIBUTES 7 + +#define HTML_FRAMESET_COLS 0 +#define HTML_FRAMESET_ROWS 1 +#define HTML_FRAMESET_ATTRIBUTES 2 + +#define HTML_GEN_CLASS 0 +#define HTML_GEN_CLEAR 1 +#define HTML_GEN_DIR 2 +#define HTML_GEN_ID 3 +#define HTML_GEN_LANG 4 +#define HTML_GEN_STYLE 5 +#define HTML_GEN_TITLE 6 +#define HTML_GEN_ATTRIBUTES 7 + +#define HTML_H_ALIGN 0 +#define HTML_H_CLASS 1 +#define HTML_H_CLEAR 2 +#define HTML_H_DINGBAT 3 +#define HTML_H_DIR 4 +#define HTML_H_ID 5 +#define HTML_H_LANG 6 +#define HTML_H_MD 7 +#define HTML_H_NOWRAP 8 +#define HTML_H_SEQNUM 9 +#define HTML_H_SKIP 10 +#define HTML_H_SRC 11 +#define HTML_H_STYLE 12 +#define HTML_H_TITLE 13 +#define HTML_H_ATTRIBUTES 14 + +#define HTML_HR_ALIGN 0 +#define HTML_HR_CLASS 1 +#define HTML_HR_CLEAR 2 +#define HTML_HR_DIR 3 +#define HTML_HR_ID 4 +#define HTML_HR_MD 5 +#define HTML_HR_NOSHADE 6 +#define HTML_HR_SIZE 7 +#define HTML_HR_SRC 8 +#define HTML_HR_STYLE 9 +#define HTML_HR_TITLE 10 +#define HTML_HR_WIDTH 11 +#define HTML_HR_ATTRIBUTES 12 + +#define HTML_IFRAME_ALIGN 0 +#define HTML_IFRAME_FRAMEBORDER 1 +#define HTML_IFRAME_HEIGHT 2 +#define HTML_IFRAME_ID 3 +#define HTML_IFRAME_MARGINHEIGHT 4 +#define HTML_IFRAME_MARGINWIDTH 5 +#define HTML_IFRAME_NAME 6 +#define HTML_IFRAME_SCROLLING 7 +#define HTML_IFRAME_SRC 8 +#define HTML_IFRAME_STYLE 9 +#define HTML_IFRAME_WIDTH 10 +#define HTML_IFRAME_ATTRIBUTES 11 + +#define HTML_IMG_ALIGN 0 +#define HTML_IMG_ALT 1 +#define HTML_IMG_BORDER 2 +#define HTML_IMG_CLASS 3 +#define HTML_IMG_CLEAR 4 +#define HTML_IMG_DIR 5 +#define HTML_IMG_HEIGHT 6 +#define HTML_IMG_ID 7 +#define HTML_IMG_ISMAP 8 +#define HTML_IMG_ISOBJECT 9 +#define HTML_IMG_LANG 10 +#define HTML_IMG_MD 11 +#define HTML_IMG_SRC 12 +#define HTML_IMG_STYLE 13 +#define HTML_IMG_TITLE 14 +#define HTML_IMG_UNITS 15 +#define HTML_IMG_USEMAP 16 +#define HTML_IMG_WIDTH 17 +#define HTML_IMG_ATTRIBUTES 18 + +#define HTML_INPUT_ACCEPT 0 +#define HTML_INPUT_ACCEPT_CHARSET 1 /* RFC 2070 HTML i18n - kw */ +#define HTML_INPUT_ALIGN 2 +#define HTML_INPUT_ALT 3 +#define HTML_INPUT_CHECKED 4 +#define HTML_INPUT_CLASS 5 +#define HTML_INPUT_CLEAR 6 +#define HTML_INPUT_DIR 7 +#define HTML_INPUT_DISABLED 8 +#define HTML_INPUT_ERROR 9 +#define HTML_INPUT_HEIGHT 10 +#define HTML_INPUT_ID 11 +#define HTML_INPUT_LANG 12 +#define HTML_INPUT_MAX 13 +#define HTML_INPUT_MAXLENGTH 14 +#define HTML_INPUT_MD 15 +#define HTML_INPUT_MIN 16 +#define HTML_INPUT_NAME 17 +#define HTML_INPUT_NOTAB 18 +#define HTML_INPUT_ONBLUR 19 +#define HTML_INPUT_ONCHANGE 20 +#define HTML_INPUT_ONCLICK 21 +#define HTML_INPUT_ONFOCUS 22 +#define HTML_INPUT_ONSELECT 23 +#define HTML_INPUT_SIZE 24 +#define HTML_INPUT_SRC 25 +#define HTML_INPUT_STYLE 26 +#define HTML_INPUT_TABINDEX 27 +#define HTML_INPUT_TITLE 28 +#define HTML_INPUT_TYPE 29 +#define HTML_INPUT_VALUE 30 +#define HTML_INPUT_WIDTH 31 +#define HTML_INPUT_ATTRIBUTES 32 + +#define HTML_ISINDEX_ACTION 0 /* Treat as synonym for HREF. - FM */ +#define HTML_ISINDEX_DIR 1 +#define HTML_ISINDEX_HREF 2 /* HTML 3.0 "action". - FM */ +#define HTML_ISINDEX_ID 3 +#define HTML_ISINDEX_LANG 4 +#define HTML_ISINDEX_PROMPT 5 /* HTML 3.0 "prompt". - FM */ +#define HTML_ISINDEX_TITLE 6 +#define HTML_ISINDEX_ATTRIBUTES 7 + +#define HTML_KEYGEN_CHALLENGE 0 +#define HTML_KEYGEN_CLASS 1 +#define HTML_KEYGEN_DIR 2 +#define HTML_KEYGEN_ID 3 +#define HTML_KEYGEN_LANG 4 +#define HTML_KEYGEN_NAME 5 +#define HTML_KEYGEN_STYLE 6 +#define HTML_KEYGEN_TITLE 7 +#define HTML_KEYGEN_ATTRIBUTES 8 + +#define HTML_LABEL_ACCESSKEY 0 +#define HTML_LABEL_CLASS 1 +#define HTML_LABEL_CLEAR 2 +#define HTML_LABEL_DIR 3 +#define HTML_LABEL_FOR 4 +#define HTML_LABEL_ID 5 +#define HTML_LABEL_LANG 6 +#define HTML_LABEL_ONCLICK 7 +#define HTML_LABEL_STYLE 8 +#define HTML_LABEL_TITLE 9 +#define HTML_LABEL_ATTRIBUTES 10 + +#define HTML_LEGEND_ACCESSKEY 0 +#define HTML_LEGEND_ALIGN 1 +#define HTML_LEGEND_CLASS 2 +#define HTML_LEGEND_CLEAR 3 +#define HTML_LEGEND_DIR 4 +#define HTML_LEGEND_ID 5 +#define HTML_LEGEND_LANG 6 +#define HTML_LEGEND_STYLE 7 +#define HTML_LEGEND_TITLE 8 +#define HTML_LEGEND_ATTRIBUTES 9 + +#define HTML_LI_CLASS 0 +#define HTML_LI_CLEAR 1 +#define HTML_LI_DINGBAT 2 +#define HTML_LI_DIR 3 +#define HTML_LI_ID 4 +#define HTML_LI_LANG 5 +#define HTML_LI_MD 6 +#define HTML_LI_SKIP 7 +#define HTML_LI_SRC 8 +#define HTML_LI_STYLE 9 +#define HTML_LI_TITLE 10 +#define HTML_LI_TYPE 11 +#define HTML_LI_VALUE 12 +#define HTML_LI_ATTRIBUTES 13 + +#define HTML_LINK_CHARSET 0 /* RFC 2070 HTML i18n - kw */ +#define HTML_LINK_CLASS 1 +#define HTML_LINK_HREF 2 +#define HTML_LINK_ID 3 +#define HTML_LINK_MEDIA 4 +#define HTML_LINK_REL 5 +#define HTML_LINK_REV 6 +#define HTML_LINK_STYLE 7 +#define HTML_LINK_TARGET 8 +#define HTML_LINK_TITLE 9 +#define HTML_LINK_TYPE 10 +#define HTML_LINK_ATTRIBUTES 11 + +#define HTML_MAP_CLASS 0 +#define HTML_MAP_CLEAR 1 +#define HTML_MAP_DIR 2 +#define HTML_MAP_ID 3 +#define HTML_MAP_LANG 4 +#define HTML_MAP_NAME 5 +#define HTML_MAP_STYLE 6 +#define HTML_MAP_TITLE 7 +#define HTML_MAP_ATTRIBUTES 8 + +#define HTML_MATH_BOX 0 +#define HTML_MATH_CLASS 1 +#define HTML_MATH_CLEAR 2 +#define HTML_MATH_DIR 3 +#define HTML_MATH_ID 4 +#define HTML_MATH_LANG 5 +#define HTML_MATH_STYLE 6 +#define HTML_MATH_TITLE 7 +#define HTML_MATH_ATTRIBUTES 8 + +#define HTML_META_CONTENT 0 +#define HTML_META_HTTP_EQUIV 1 /* For parsing in HTML.c - FM */ +#define HTML_META_NAME 2 +#define HTML_META_ATTRIBUTES 3 + +#define NEXTID_N 0 + +#define HTML_NOTE_CLASS 0 +#define HTML_NOTE_CLEAR 1 +#define HTML_NOTE_DIR 2 +#define HTML_NOTE_ID 3 +#define HTML_NOTE_LANG 4 +#define HTML_NOTE_MD 5 +#define HTML_NOTE_ROLE 6 /* Old name for CLASS - FM */ +#define HTML_NOTE_SRC 7 +#define HTML_NOTE_STYLE 8 +#define HTML_NOTE_TITLE 9 +#define HTML_NOTE_ATTRIBUTES 10 + +#define HTML_OBJECT_ALIGN 0 +#define HTML_OBJECT_BORDER 1 +#define HTML_OBJECT_CLASS 2 +#define HTML_OBJECT_CLASSID 3 +#define HTML_OBJECT_CODEBASE 4 +#define HTML_OBJECT_CODETYPE 5 +#define HTML_OBJECT_DATA 6 +#define HTML_OBJECT_DECLARE 7 +#define HTML_OBJECT_DIR 8 +#define HTML_OBJECT_HEIGHT 9 +#define HTML_OBJECT_HSPACE 10 +#define HTML_OBJECT_ID 11 +#define HTML_OBJECT_ISMAP 12 +#define HTML_OBJECT_LANG 13 +#define HTML_OBJECT_NAME 14 +#define HTML_OBJECT_NOTAB 15 +#define HTML_OBJECT_SHAPES 16 +#define HTML_OBJECT_STANDBY 17 +#define HTML_OBJECT_STYLE 18 +#define HTML_OBJECT_TABINDEX 19 +#define HTML_OBJECT_TITLE 20 +#define HTML_OBJECT_TYPE 21 +#define HTML_OBJECT_USEMAP 22 +#define HTML_OBJECT_VSPACE 23 +#define HTML_OBJECT_WIDTH 24 +#define HTML_OBJECT_ATTRIBUTES 25 + +#define HTML_OL_CLASS 0 +#define HTML_OL_CLEAR 1 +#define HTML_OL_COMPACT 2 +#define HTML_OL_CONTINUE 3 +#define HTML_OL_DIR 4 +#define HTML_OL_ID 5 +#define HTML_OL_LANG 6 +#define HTML_OL_SEQNUM 7 +#define HTML_OL_START 8 +#define HTML_OL_STYLE 9 +#define HTML_OL_TITLE 10 +#define HTML_OL_TYPE 11 +#define HTML_OL_ATTRIBUTES 12 + +#define HTML_OPTION_CLASS 0 +#define HTML_OPTION_CLEAR 1 +#define HTML_OPTION_DIR 2 +#define HTML_OPTION_DISABLED 3 +#define HTML_OPTION_ERROR 4 +#define HTML_OPTION_ID 5 +#define HTML_OPTION_LANG 6 +#define HTML_OPTION_SELECTED 7 +#define HTML_OPTION_SHAPE 8 +#define HTML_OPTION_STYLE 9 +#define HTML_OPTION_TITLE 10 +#define HTML_OPTION_VALUE 11 +#define HTML_OPTION_ATTRIBUTES 12 + +#define HTML_OVERLAY_CLASS 0 +#define HTML_OVERLAY_HEIGHT 1 +#define HTML_OVERLAY_ID 2 +#define HTML_OVERLAY_IMAGEMAP 3 +#define HTML_OVERLAY_MD 4 +#define HTML_OVERLAY_SRC 5 +#define HTML_OVERLAY_STYLE 6 +#define HTML_OVERLAY_TITLE 7 +#define HTML_OVERLAY_UNITS 8 +#define HTML_OVERLAY_WIDTH 9 +#define HTML_OVERLAY_X 10 +#define HTML_OVERLAY_Y 11 +#define HTML_OVERLAY_ATTRIBUTES 12 + +#define HTML_P_ALIGN 0 +#define HTML_P_CLASS 1 +#define HTML_P_CLEAR 2 +#define HTML_P_DIR 3 +#define HTML_P_ID 4 +#define HTML_P_LANG 5 +#define HTML_P_NOWRAP 6 +#define HTML_P_STYLE 7 +#define HTML_P_TITLE 8 +#define HTML_P_ATTRIBUTES 9 + +#define HTML_PARAM_ACCEPT 0 +#define HTML_PARAM_ACCEPT_CHARSET 1 +#define HTML_PARAM_ACCEPT_ENCODING 2 +#define HTML_PARAM_CLASS 3 +#define HTML_PARAM_CLEAR 4 +#define HTML_PARAM_DATA 5 +#define HTML_PARAM_DIR 6 +#define HTML_PARAM_ID 7 +#define HTML_PARAM_LANG 8 +#define HTML_PARAM_NAME 9 +#define HTML_PARAM_OBJECT 10 +#define HTML_PARAM_REF 11 +#define HTML_PARAM_STYLE 12 +#define HTML_PARAM_TITLE 13 +#define HTML_PARAM_TYPE 14 +#define HTML_PARAM_VALUE 15 +#define HTML_PARAM_VALUEREF 16 /* Use VALUETYPE (DATA|REF|OBJECT). - FM */ +#define HTML_PARAM_VALUETYPE 17 +#define HTML_PARAM_ATTRIBUTES 18 + +#define HTML_SCRIPT_CLASS 0 +#define HTML_SCRIPT_CLEAR 1 +#define HTML_SCRIPT_DIR 2 +#define HTML_SCRIPT_EVENT 3 +#define HTML_SCRIPT_FOR 4 +#define HTML_SCRIPT_ID 5 +#define HTML_SCRIPT_LANG 6 +#define HTML_SCRIPT_LANGUAGE 7 +#define HTML_SCRIPT_NAME 8 +#define HTML_SCRIPT_SCRIPTENGINE 9 +#define HTML_SCRIPT_SRC 10 +#define HTML_SCRIPT_STYLE 11 +#define HTML_SCRIPT_TITLE 12 +#define HTML_SCRIPT_TYPE 13 +#define HTML_SCRIPT_ATTRIBUTES 14 + +#define HTML_SELECT_ALIGN 0 +#define HTML_SELECT_CLASS 1 +#define HTML_SELECT_CLEAR 2 +#define HTML_SELECT_DIR 3 +#define HTML_SELECT_DISABLED 4 +#define HTML_SELECT_ERROR 5 +#define HTML_SELECT_HEIGHT 6 +#define HTML_SELECT_ID 7 +#define HTML_SELECT_LANG 8 +#define HTML_SELECT_MD 9 +#define HTML_SELECT_MULTIPLE 10 +#define HTML_SELECT_NAME 11 +#define HTML_SELECT_NOTAB 12 +#define HTML_SELECT_ONBLUR 13 +#define HTML_SELECT_ONCHANGE 14 +#define HTML_SELECT_ONFOCUS 15 +#define HTML_SELECT_SIZE 16 +#define HTML_SELECT_STYLE 17 +#define HTML_SELECT_TABINDEX 18 +#define HTML_SELECT_TITLE 19 +#define HTML_SELECT_UNITS 20 +#define HTML_SELECT_WIDTH 21 +#define HTML_SELECT_ATTRIBUTES 22 + +#define HTML_STYLE_DIR 0 +#define HTML_STYLE_LANG 1 +#define HTML_STYLE_NOTATION 2 +#define HTML_STYLE_TITLE 3 +#define HTML_STYLE_ATTRIBUTES 4 + +#define HTML_TAB_ALIGN 0 +#define HTML_TAB_CLASS 1 +#define HTML_TAB_CLEAR 2 +#define HTML_TAB_DIR 3 +#define HTML_TAB_DP 4 +#define HTML_TAB_ID 5 +#define HTML_TAB_INDENT 6 +#define HTML_TAB_LANG 7 +#define HTML_TAB_STYLE 8 +#define HTML_TAB_TITLE 9 +#define HTML_TAB_TO 10 +#define HTML_TAB_ATTRIBUTES 11 + +#define HTML_TABLE_ALIGN 0 +#define HTML_TABLE_BORDER 1 +#define HTML_TABLE_CELLPADDING 2 +#define HTML_TABLE_CELLSPACING 3 +#define HTML_TABLE_CLASS 4 +#define HTML_TABLE_CLEAR 5 +#define HTML_TABLE_COLS 6 +#define HTML_TABLE_COLSPEC 7 +#define HTML_TABLE_DIR 8 +#define HTML_TABLE_DP 9 +#define HTML_TABLE_FRAME 10 +#define HTML_TABLE_ID 11 +#define HTML_TABLE_LANG 12 +#define HTML_TABLE_NOFLOW 13 +#define HTML_TABLE_NOWRAP 14 +#define HTML_TABLE_RULES 15 +#define HTML_TABLE_STYLE 16 +#define HTML_TABLE_TITLE 17 +#define HTML_TABLE_UNITS 18 +#define HTML_TABLE_WIDTH 19 +#define HTML_TABLE_ATTRIBUTES 20 + +#define HTML_TD_ALIGN 0 +#define HTML_TD_AXES 1 +#define HTML_TD_AXIS 2 +#define HTML_TD_CHAR 3 +#define HTML_TD_CHAROFF 4 +#define HTML_TD_CLASS 5 +#define HTML_TD_CLEAR 6 +#define HTML_TD_COLSPAN 7 +#define HTML_TD_DIR 8 +#define HTML_TD_DP 9 +#define HTML_TD_ID 10 +#define HTML_TD_LANG 11 +#define HTML_TD_NOWRAP 12 +#define HTML_TD_ROWSPAN 13 +#define HTML_TD_STYLE 14 +#define HTML_TD_TITLE 15 +#define HTML_TD_VALIGN 16 +#define HTML_TD_ATTRIBUTES 17 + +#define HTML_TEXTAREA_ACCEPT_CHARSET 0 /* RFC 2070 HTML i18n - kw */ +#define HTML_TEXTAREA_ALIGN 1 +#define HTML_TEXTAREA_CLASS 2 +#define HTML_TEXTAREA_CLEAR 3 +#define HTML_TEXTAREA_COLS 4 +#define HTML_TEXTAREA_DIR 5 +#define HTML_TEXTAREA_DISABLED 6 +#define HTML_TEXTAREA_ERROR 7 +#define HTML_TEXTAREA_ID 8 +#define HTML_TEXTAREA_LANG 9 +#define HTML_TEXTAREA_NAME 10 +#define HTML_TEXTAREA_NOTAB 11 +#define HTML_TEXTAREA_ONBLUR 12 +#define HTML_TEXTAREA_ONCHANGE 13 +#define HTML_TEXTAREA_ONFOCUS 14 +#define HTML_TEXTAREA_ONSELECT 15 +#define HTML_TEXTAREA_ROWS 16 +#define HTML_TEXTAREA_STYLE 17 +#define HTML_TEXTAREA_TABINDEX 18 +#define HTML_TEXTAREA_TITLE 19 +#define HTML_TEXTAREA_ATTRIBUTES 20 + +#define HTML_TR_ALIGN 0 +#define HTML_TR_CHAR 1 +#define HTML_TR_CHAROFF 2 +#define HTML_TR_CLASS 3 +#define HTML_TR_CLEAR 4 +#define HTML_TR_DIR 5 +#define HTML_TR_DP 6 +#define HTML_TR_ID 7 +#define HTML_TR_LANG 8 +#define HTML_TR_NOWRAP 9 +#define HTML_TR_STYLE 10 +#define HTML_TR_TITLE 11 +#define HTML_TR_VALIGN 12 +#define HTML_TR_ATTRIBUTES 13 + +#define HTML_UL_CLASS 0 +#define HTML_UL_CLEAR 1 +#define HTML_UL_COMPACT 2 +#define HTML_UL_DINGBAT 3 +#define HTML_UL_DIR 4 +#define HTML_UL_ID 5 +#define HTML_UL_LANG 6 +#define HTML_UL_MD 7 +#define HTML_UL_PLAIN 8 +#define HTML_UL_SRC 9 +#define HTML_UL_STYLE 10 +#define HTML_UL_TITLE 11 +#define HTML_UL_TYPE 12 +#define HTML_UL_WRAP 13 +#define HTML_UL_ATTRIBUTES 14 + +extern CONST SGML_dtd HTML_dtd; + +extern void HTSwitchDTD PARAMS(( + BOOL new)); + +extern CONST HTTag HTTag_unrecognized; + +/* + +Start anchor element + + It is kinda convenient to have a particular routine for starting an anchor + element, as everything else for HTML is simple anyway. + + ON ENTRY + + targetstream points to a structured stream object. + + name and href point to attribute strings or are NULL if the attribute is + to be omitted. + + */ +extern void HTStartAnchor PARAMS(( + HTStructured * targetstream, + CONST char * name, + CONST char * href)); + +/* + +Start IsIndex element - FM + + It is kinda convenient to have a particular routine for starting an IsIndex + element with the prompt and/or href (action) attributes specified. + + ON ENTRY + + targetstream points to a structured stream object. + + prompt and href point to attribute strings or are NULL if the attribute is + to be omitted. + + */ +extern void HTStartIsIndex PARAMS(( + HTStructured * targetstream, + CONST char * prompt, + CONST char * href)); + + +#endif /* HTMLDTD_H */ + +/* + + End of module definition */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.c new file mode 100644 index 00000000000..1839f3c41a1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.c @@ -0,0 +1,544 @@ +/* HTML Generator +** ============== +** +** This version of the HTML object sends HTML markup to the output stream. +** +** Bugs: Line wrapping is not done at all. +** All data handled as PCDATA. +** Should convert old XMP, LISTING and PLAINTEXT to PRE. +** +** It is not obvious to me right now whether the HEAD should be generated +** from the incomming data or the anchor. Currently it is from the former +** which is cleanest. +*/ + +#include "HTUtils.h" +#include "tcp.h" + +#define BUFFER_SIZE 200 /* Line buffer attempts to make neat breaks */ +#define MAX_CLEANNESS 20 + +/* Implements: +*/ +#include "HTMLGen.h" + +#include <stdio.h> +#include "HTMLDTD.h" +#include "HTStream.h" +#include "SGML.h" +#include "HTFormat.h" + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define PUTC(c) (*me->targetClass.put_character)(me->target, c) +/* #define PUTS(s) (*me->targetClass.put_string)(me->target, s) */ +#define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l) + +/* HTML Object +** ----------- +*/ +struct _HTStream { + CONST HTStreamClass * isa; + HTStream * target; + HTStreamClass targetClass; /* COPY for speed */ +}; + +struct _HTStructured { + CONST HTStructuredClass * isa; + HTStream * target; + HTStreamClass targetClass; /* COPY for speed */ + + char buffer[BUFFER_SIZE+1]; /* 1for NL */ + int buffer_maxchars; + char * write_pointer; + char * line_break [MAX_CLEANNESS+1]; + int cleanness; + BOOL overflowed; + BOOL delete_line_break_char[MAX_CLEANNESS+1]; + BOOL preformatted; + BOOL escape_specials; + BOOL in_attrval; +}; + +/* Flush Buffer +** ------------ +*/ + +PRIVATE void flush_breaks ARGS1( + HTStructured *, me) +{ + int i; + for (i=0; i<= MAX_CLEANNESS; i++) { + me->line_break[i] = NULL; + } +} + +PRIVATE void HTMLGen_flush ARGS1( + HTStructured *, me) +{ + (*me->targetClass.put_block)(me->target, + me->buffer, + me->write_pointer - me->buffer); + me->write_pointer = me->buffer; + flush_breaks(me); + me->cleanness = 0; + me->delete_line_break_char[0] = NO; +} + +/* Weighted optional line break +** +** We keep track of all the breaks for when we chop the line +*/ + +PRIVATE void allow_break ARGS3( + HTStructured *, me, + int, new_cleanness, + BOOL, dlbc) +{ + if (dlbc && me->write_pointer == me->buffer) dlbc = NO; + me->line_break[new_cleanness] = + dlbc ? me->write_pointer - 1 /* Point to space */ + : me->write_pointer ; /* point to gap */ + me->delete_line_break_char[new_cleanness] = dlbc; + if (new_cleanness >= me->cleanness && + (me->overflowed || me->line_break[new_cleanness] > me->buffer)) + me->cleanness = new_cleanness; +} + +/* Character handling +** ------------------ +** +** The tricky bits are the line break handling. This attempts +** to synchrononise line breaks on sentence or phrase ends. This +** is important if one stores SGML files in a line-oriented code +** repository, so that if a small change is made, line ends don't +** shift in a ripple-through to apparently change a large part of the +** file. We give extra "cleanness" to spaces appearing directly +** after periods (full stops), [semi]colons and commas. +** This should make the source files easier to read and modify +** by hand, too, though this is not a primary design consideration. TBL +*/ +PRIVATE void HTMLGen_put_character ARGS2( + HTStructured *, me, + char, c) +{ + if (me->escape_specials && (unsigned char)c < 32) { + if (c == HT_NON_BREAK_SPACE || c == HT_EM_SPACE || + c == LY_SOFT_HYPHEN) { /* recursion... */ + HTMLGen_put_character(me, '&'); + HTMLGen_put_character(me, '#'); + HTMLGen_put_character(me, 'x'); + switch(c) { + case HT_NON_BREAK_SPACE: /*   */ + HTMLGen_put_character(me, 'A'); + HTMLGen_put_character(me, '0'); + break; + case HT_EM_SPACE: /*   */ + HTMLGen_put_character(me, '2'); + HTMLGen_put_character(me, '0'); + HTMLGen_put_character(me, '0'); + HTMLGen_put_character(me, '3'); + break; + case LY_SOFT_HYPHEN: /* ­ */ + HTMLGen_put_character(me, 'A'); + HTMLGen_put_character(me, 'D'); + break; + } + c = ';'; + } + } + + *me->write_pointer++ = c; + + if (c == '\n') { + HTMLGen_flush(me); + return; + } + + /* Figure our whether we can break at this point + */ + if ((!me->preformatted && (c == ' ' || c == '\t'))) { + int new_cleanness = 3; + if (me->write_pointer > (me->buffer + 1)) { + char delims[5]; + char * p; + strcpy(delims, ",;:."); /* @@ english bias */ + p = strchr(delims, me->write_pointer[-2]); + if (p) new_cleanness = p - delims + 6; + if (!me->in_attrval) new_cleanness += 10; + } + allow_break(me, new_cleanness, YES); + } + + /* + * Flush buffer out when full, or whenever the line is over + * the nominal maximum and we can break at all + */ + if (me->write_pointer >= me->buffer + me->buffer_maxchars || + (me->overflowed && me->cleanness)) { + if (me->cleanness) { + char line_break_char = me->line_break[me->cleanness][0]; + char * saved = me->line_break[me->cleanness]; + + if (me->delete_line_break_char[me->cleanness]) saved++; + me->line_break[me->cleanness][0] = '\n'; + (*me->targetClass.put_block)(me->target, + me->buffer, + me->line_break[me->cleanness] - me->buffer + 1); + me->line_break[me->cleanness][0] = line_break_char; + { /* move next line in */ + char * p = saved; + char *q; + for (q = me->buffer; p < me->write_pointer; ) + *q++ = *p++; + } + me->cleanness = 0; + /* Now we have to check whether ther are any perfectly good breaks + ** which weren't good enough for the last line but may be + ** good enough for the next + */ + { + int i; + for(i=0; i <= MAX_CLEANNESS; i++) { + if (me->line_break[i] != NULL && + me->line_break[i] > saved) { + me->line_break[i] = me->line_break[i] - + (saved-me->buffer); + me->cleanness = i; + } else { + me->line_break[i] = NULL; + } + } + } + + me->delete_line_break_char[0] = 0; + me->write_pointer = me->write_pointer - (saved-me->buffer); + me->overflowed = NO; + + } else { + (*me->targetClass.put_block)(me->target, + me->buffer, + me->buffer_maxchars); + me->write_pointer = me->buffer; + flush_breaks(me); + me->overflowed = YES; + } + } +} + +/* String handling +** --------------- +*/ +PRIVATE void HTMLGen_put_string ARGS2( + HTStructured *, me, + CONST char *, s) +{ + CONST char * p; + + for (p = s; *p; p++) + HTMLGen_put_character(me, *p); +} + +PRIVATE void HTMLGen_write ARGS3( + HTStructured *, me, + CONST char *, s, + int, l) +{ + CONST char * p; + + for (p = s; p < (s + l); p++) + HTMLGen_put_character(me, *p); +} + +/* Start Element +** ------------- +** +** Within the opening tag, there may be spaces +** and the line may be broken at these spaces. +*/ +PRIVATE void HTMLGen_start_element ARGS6( + HTStructured *, me, + int, element_number, + CONST BOOL*, present, + CONST char **, value, + int, charset GCC_UNUSED, + char **, insert GCC_UNUSED) +{ + int i; + BOOL was_preformatted = me->preformatted; + HTTag * tag = &HTML_dtd.tags[element_number]; + + me->preformatted = YES; /* free text within tags */ + HTMLGen_put_character(me, '<'); + HTMLGen_put_string(me, tag->name); + if (present) { + BOOL had_attr = NO; + for (i = 0; i < tag->number_of_attributes; i++) { + if (present[i]) { + had_attr = YES; + HTMLGen_put_character(me, ' '); + allow_break(me, 11, YES); + HTMLGen_put_string(me, tag->attributes[i].name); + if (value[i]) { + me->preformatted = was_preformatted; + me->in_attrval = YES; + if (strchr(value[i], '"') == NULL) { + HTMLGen_put_string(me, "=\""); + HTMLGen_put_string(me, value[i]); + HTMLGen_put_character(me, '"'); + } else if (strchr(value[i], '\'') == NULL) { + HTMLGen_put_string(me, "='"); + HTMLGen_put_string(me, value[i]); + HTMLGen_put_character(me, '\''); + } else { /* attribute value has both kinds of quotes */ + CONST char *p; + HTMLGen_put_string(me, "=\""); + for (p = value[i]; *p; p++) { + if (*p != '"') { + HTMLGen_put_character(me, *p); + } else { + HTMLGen_put_string(me, """); + } + } + HTMLGen_put_character(me, '"'); + } + me->preformatted = YES; + me->in_attrval = NO; + } + } + } + if (had_attr) + allow_break(me, 12, NO); + } + HTMLGen_put_string(me, ">"); /* got rid of \n LJM */ + + /* + * Make very specific HTML assumption that PRE can't be nested! + */ + me->preformatted = (element_number == HTML_PRE) ? YES : was_preformatted; + + /* + * Can break after element start. + */ + if (!me->preformatted && tag->contents != SGML_EMPTY) { + if (HTML_dtd.tags[element_number].contents == SGML_ELEMENT) + allow_break(me, 15, NO); + else + allow_break(me, 2, NO); + } +} + +/* End Element +** ----------- +** +*/ +/* When we end an element, the style must be returned to that +** in effect before that element. Note that anchors (etc?) +** don't have an associated style, so that we must scan down the +** stack for an element with a defined style. (In fact, the styles +** should be linked to the whole stack not just the top one.) +** TBL 921119 +*/ +PRIVATE void HTMLGen_end_element ARGS3( + HTStructured *, me, + int, element_number, + char **, insert GCC_UNUSED) +{ + if (!me->preformatted && + HTML_dtd.tags[element_number].contents != SGML_EMPTY) { + /* + * Can break before element end. + */ + if (HTML_dtd.tags[element_number].contents == SGML_ELEMENT) + allow_break(me, 14, NO); + else + allow_break(me, 1, NO); + } + HTMLGen_put_string(me, "</"); + HTMLGen_put_string(me, HTML_dtd.tags[element_number].name); + HTMLGen_put_character(me, '>'); + if (element_number == HTML_PRE) { + me->preformatted = NO; + } +} + +/* Expanding entities +** ------------------ +** +*/ +PRIVATE int HTMLGen_put_entity ARGS2( + HTStructured *, me, + int, entity_number) +{ + int nent = HTML_dtd.number_of_entities; + + HTMLGen_put_character(me, '&'); + if (entity_number < nent) { + HTMLGen_put_string(me, HTML_dtd.entity_names[entity_number]); + } + HTMLGen_put_character(me, ';'); + return HT_OK; +} + +/* Free an HTML object +** ------------------- +** +*/ +PRIVATE void HTMLGen_free ARGS1( + HTStructured *, me) +{ + (*me->targetClass.put_character)(me->target, '\n'); + HTMLGen_flush(me); + (*me->targetClass._free)(me->target); /* ripple through */ + FREE(me); +} + +PRIVATE void PlainToHTML_free ARGS1( + HTStructured *, me) +{ + HTMLGen_end_element(me, HTML_PRE, 0); + HTMLGen_free(me); +} + +PRIVATE void HTMLGen_abort ARGS2( + HTStructured *, me, + HTError, e GCC_UNUSED) +{ + HTMLGen_free(me); +} + +PRIVATE void PlainToHTML_abort ARGS2( + HTStructured *, me, + HTError, e GCC_UNUSED) +{ + PlainToHTML_free(me); +} + +/* Structured Object Class +** ----------------------- +*/ +PRIVATE CONST HTStructuredClass HTMLGeneration = /* As opposed to print etc */ +{ + "HTMLGen", + HTMLGen_free, + HTMLGen_abort, + HTMLGen_put_character, HTMLGen_put_string, HTMLGen_write, + HTMLGen_start_element, HTMLGen_end_element, + HTMLGen_put_entity +}; + +/* Subclass-specific Methods +** ------------------------- +*/ +extern int LYcols; /* LYCurses.h, set in LYMain.c */ +extern BOOL dump_output_immediately; /* TRUE if no interactive user */ +extern int dump_output_width; /* -width instead of 80 */ +extern BOOLEAN LYPreparsedSource; /* Show source as preparsed? */ + +PUBLIC HTStructured * HTMLGenerator ARGS1( + HTStream *, output) +{ + HTStructured* me = (HTStructured*)malloc(sizeof(*me)); + if (me == NULL) + outofmem(__FILE__, "HTMLGenerator"); + me->isa = &HTMLGeneration; + + me->target = output; + me->targetClass = *me->target->isa; /* Copy pointers to routines for speed*/ + + me->write_pointer = me->buffer; + flush_breaks(me); + me->line_break[0] = me->buffer; + me->cleanness = 0; + me->overflowed = NO; + me->delete_line_break_char[0] = NO; + me->preformatted = NO; + me->in_attrval = NO; + + /* + * For what line length should we attempt to wrap ? - kw + */ + if (!LYPreparsedSource) { + me->buffer_maxchars = 80; /* work as before - kw */ + } else if (dump_output_width > 1) { + me->buffer_maxchars = dump_output_width; /* try to honor -width - kw */ + } else if (dump_output_immediately) { + me->buffer_maxchars = 80; /* try to honor -width - kw */ + } else { + me->buffer_maxchars = LYcols - 2; + if (me->buffer_maxchars < 38) /* too narrow, let GridText deal */ + me->buffer_maxchars = 40; + } + if (me->buffer_maxchars > 900) /* likely not true - kw */ + me->buffer_maxchars = 78; + if (me->buffer_maxchars > BUFFER_SIZE) /* must not be larger! */ + me->buffer_maxchars = BUFFER_SIZE - 2; + + /* + * If dump_output_immediately is set, there likely isn't anything + * after this stream to interpret the Lynx special chars. Also + * if they get displayed via HTPlain, that will probably make + * non-breaking space chars etc. invisible. So let's translate + * them to numerical character references. For debugging + * purposes we'll use the new hex format. + */ + me->escape_specials = LYPreparsedSource; + + return me; +} + +/* Stream Object Class +** ------------------- +** +** This object just converts a plain text stream into HTML +** It is officially a structured strem but only the stream bits exist. +** This is just the easiest way of typecasting all the routines. +*/ +PRIVATE CONST HTStructuredClass PlainToHTMLConversion = +{ + "plaintexttoHTML", + HTMLGen_free, + PlainToHTML_abort, + HTMLGen_put_character, + HTMLGen_put_string, + HTMLGen_write, + NULL, /* Structured stuff */ + NULL, + NULL +}; + +/* HTConverter from plain text to HTML Stream +** ------------------------------------------ +*/ +PUBLIC HTStream* HTPlainToHTML ARGS3( + HTPresentation *, pres GCC_UNUSED, + HTParentAnchor *, anchor GCC_UNUSED, + HTStream *, sink) +{ + HTStructured *me = (HTStructured *)malloc(sizeof(*me)); + if (me == NULL) + outofmem(__FILE__, "PlainToHTML"); + me->isa = (CONST HTStructuredClass *)&PlainToHTMLConversion; + + /* + * Copy pointers to routines for speed. + */ + me->target = sink; + me->targetClass = *me->target->isa; + me->write_pointer = me->buffer; + flush_breaks(me); + me->cleanness = 0; + me->overflowed = NO; + me->delete_line_break_char[0] = NO; + /* try to honor -width - kw */ + me->buffer_maxchars = (dump_output_width > 1 ? + dump_output_width : 80); + + HTMLGen_put_string(me, "<HTML>\n<BODY>\n<PRE>\n"); + me->preformatted = YES; + me->escape_specials = NO; + me->in_attrval = NO; + return (HTStream*) me; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.h new file mode 100644 index 00000000000..ac814ad882a --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.h @@ -0,0 +1,32 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTMLGen.html + HTML GENERATOR + + This module converts structed stream into stream. That is, given a stream to write to, + it will give you a structured stream to + + */ +#ifndef HTMLGEN_H +#define HTMLGEN_H + +#include "HTML.h" +#include "HTStream.h" + +/* Subclass: +*/ +/* extern CONST HTStructuredClass HTMLGeneration; */ + +/* Special Creation: +*/ +extern HTStructured * HTMLGenerator PARAMS((HTStream * output)); + +extern HTStream * HTPlainToHTML PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + + +#endif + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.c new file mode 100644 index 00000000000..2094df68eec --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.c @@ -0,0 +1,2824 @@ +/* NEWS ACCESS HTNews.c +** =========== +** +** History: +** 26 Sep 90 Written TBL +** 29 Nov 91 Downgraded to C, for portable implementation. +*/ + +#include "HTUtils.h" /* Coding convention macros */ +#include "tcp.h" + +/* Implements: +*/ +#include "HTNews.h" + +#include "HTCJK.h" +#include "HTMIME.h" +#include "HTTCP.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* this define should be in HTFont.h :( */ +#define HT_NON_BREAK_SPACE ((char)1) /* For now */ + +#define NEWS_PORT 119 /* See rfc977 */ +#define SNEWS_PORT 563 /* See Lou Montulli */ +#define APPEND /* Use append methods */ +PUBLIC int HTNewsChunkSize = 30;/* Number of articles for quick display */ +PUBLIC int HTNewsMaxChunk = 40; /* Largest number of articles in one window */ + +#ifndef DEFAULT_NEWS_HOST +#define DEFAULT_NEWS_HOST "news" +#endif /* DEFAULT_NEWS_HOST */ +#ifndef SERVER_FILE +#define SERVER_FILE "/usr/local/lib/rn/server" +#endif /* SERVER_FILE */ + +#define NEWS_NETWRITE NETWRITE +#define NEWS_NETCLOSE NETCLOSE +#define NEXT_CHAR HTGetCharacter() + +#include <ctype.h> + +#include "HTML.h" +#include "HTParse.h" +#include "HTFormat.h" +#include "HTAlert.h" + +#include "LYNews.h" +#include "LYGlobalDefs.h" +#include "LYLeaks.h" + +#define BIG 1024 /* @@@ */ + +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; +struct _HTStream +{ + HTStreamClass * isa; +}; + +#define LINE_LENGTH 512 /* Maximum length of line of ARTICLE etc */ +#define GROUP_NAME_LENGTH 256 /* Maximum length of group name */ +extern BOOLEAN scan_for_buried_news_references; +extern BOOLEAN LYListNewsNumbers; +extern BOOLEAN LYListNewsDates; +extern HTCJKlang HTCJK; +extern int interrupted_in_htgetcharacter; +extern BOOL keep_mime_headers; /* Include mime headers and force raw text */ +extern BOOL using_proxy; /* Are we using an NNTP proxy? */ + +/* +** Module-wide variables. +*/ +PUBLIC char * HTNewsHost = NULL; /* Default host */ +PRIVATE char * NewsHost = NULL; /* Current host */ +PRIVATE char * NewsHREF = NULL; /* Current HREF prefix */ +PRIVATE int s; /* Socket for NewsHost */ +PRIVATE int HTCanPost = FALSE; /* Current POST permission */ +PRIVATE char response_text[LINE_LENGTH+1]; /* Last response */ +/* PRIVATE HText * HT; */ /* the new hypertext */ +PRIVATE HTStructured * target; /* The output sink */ +PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */ +PRIVATE HTStream * rawtarget = NULL; /* The output sink for rawtext */ +PRIVATE HTStreamClass rawtargetClass; /* Copy of fn addresses */ +PRIVATE HTParentAnchor *node_anchor; /* Its anchor */ +PRIVATE int diagnostic; /* level: 0=none 2=source */ +PRIVATE BOOL rawtext = NO; /* Flag: HEAD or -mime_headers */ +PRIVATE HTList *NNTP_AuthInfo = NULL; /* AUTHINFO database */ + +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define RAW_PUTS(s) (*rawtargetClass.put_string)(rawtarget, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ + (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET if (rawtext) (*rawtargetClass._free)(rawtarget); \ + else (*targetClass._free)(target) +#define ABORT_TARGET if (rawtext) (*rawtargetClass._abort)(rawtarget, NULL); \ + else (*targetClass._abort)(target, NULL) + +typedef struct _NNTPAuth { + char * host; + char * user; + char * pass; +} NNTPAuth; + +PRIVATE void free_news_globals NOARGS +{ + if (s >= 0) { + NEWS_NETCLOSE(s); + s = -1; + } + FREE(HTNewsHost); + FREE(NewsHost); + FREE(NewsHREF); +} + +PRIVATE void free_NNTP_AuthInfo NOARGS +{ + HTList *cur = NNTP_AuthInfo; + NNTPAuth *auth = NULL; + + if (!cur) + return; + + while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { + FREE(auth->host); + FREE(auth->user); + FREE(auth->pass); + FREE(auth); + } + HTList_delete(NNTP_AuthInfo); + NNTP_AuthInfo = NULL; + return; +} + +PUBLIC CONST char * HTGetNewsHost NOARGS +{ + return HTNewsHost; +} + +PUBLIC void HTSetNewsHost ARGS1(CONST char *, value) +{ + StrAllocCopy(HTNewsHost, value); +} + +/* Initialisation for this module +** ------------------------------ +** +** Except on the NeXT, we pick up the NewsHost name from +** +** 1. Environment variable NNTPSERVER +** 2. File SERVER_FILE +** 3. Compilation time macro DEFAULT_NEWS_HOST +** 4. Default to "news" +** +** On the NeXT, we pick up the NewsHost name from, in order: +** +** 1. WorldWideWeb default "NewsHost" +** 2. Global default "NewsHost" +** 3. News default "NewsHost" +** 4. Compilation time macro DEFAULT_NEWS_HOST +** 5. Default to "news" +*/ +PRIVATE BOOL initialized = NO; +PRIVATE BOOL initialize NOARGS +{ +#ifdef NeXTStep + char *cp = NULL; +#endif + + /* + ** Get name of Host. + */ +#ifdef NeXTStep + if ((cp = NXGetDefaultValue("WorldWideWeb","NewsHost"))==0) { + if ((cp = NXGetDefaultValue("News","NewsHost")) == 0) { + StrAllocCopy(HTNewsHost, DEFAULT_NEWS_HOST); + } + } + if (cp) { + StrAllocCopy(HTNewsHost, cp); + cp = NULL; + } +#else + if (getenv("NNTPSERVER")) { + StrAllocCopy(HTNewsHost, (char *)getenv("NNTPSERVER")); + if (TRACE) fprintf(stderr, "HTNews: NNTPSERVER defined as `%s'\n", + HTNewsHost); + } else { + char server_name[256]; + FILE* fp = fopen(SERVER_FILE, "r"); + if (fp) { + if (fscanf(fp, "%s", server_name)==1) { + StrAllocCopy(HTNewsHost, server_name); + if (TRACE) fprintf(stderr, + "HTNews: File %s defines news host as `%s'\n", + SERVER_FILE, HTNewsHost); + } + fclose(fp); + } + } + if (!HTNewsHost) + StrAllocCopy(HTNewsHost, DEFAULT_NEWS_HOST); +#endif /* NeXTStep */ + + s = -1; /* Disconnected */ + atexit(free_news_globals); + return YES; +} + +/* Send NNTP Command line to remote host & Check Response +** ------------------------------------------------------ +** +** On entry, +** command points to the command to be sent, including CRLF, or is null +** pointer if no command to be sent. +** On exit, +** Negative status indicates transmission error, socket closed. +** Positive status is an NNTP status. +*/ +PRIVATE int response ARGS1(CONST char *,command) +{ + int result; + char * p = response_text; + char ch; + + if (command) { + int status; + int length = strlen(command); + if (TRACE) fprintf(stderr, "NNTP command to be sent: %s", command); +#ifdef NOT_ASCII + { + CONST char * p; + char * q; + char ascii[LINE_LENGTH+1]; + for(p = command, q=ascii; *p; p++, q++) { + *q = TOASCII(*p); + } + status = NEWS_NETWRITE(s, ascii, length); + } +#else + status = NEWS_NETWRITE(s, (char *)command, length); +#endif /* NOT_ASCII */ + if (status < 0){ + if (TRACE) fprintf(stderr, + "HTNews: Unable to send command. Disconnecting.\n"); + NEWS_NETCLOSE(s); + s = -1; + return status; + } /* if bad status */ + } /* if command to be sent */ + + for (;;) { + if (((*p++ = NEXT_CHAR) == LF) || + (p == &response_text[LINE_LENGTH])) { + *--p = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, "NNTP Response: %s\n", response_text); + sscanf(response_text, "%d", &result); + return result; + } /* if end of line */ + + if ((ch = *(p-1)) == (char)EOF) { + *(p-1) = '\0'; + if (TRACE) { + if (interrupted_in_htgetcharacter) { + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + } else { + fprintf(stderr, + "HTNews: EOF on read, closing socket %d\n", + s); + } + } + NEWS_NETCLOSE(s); /* End of file, close socket */ + s = -1; + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + return(HT_INTERRUPTED); + } + return((int)EOF); /* End of file on response */ + } + } /* Loop over characters */ +} + +/* Case insensitive string comparisons +** ----------------------------------- +** +** On entry, +** template must be already un upper case. +** unknown may be in upper or lower or mixed case to match. +*/ +PRIVATE BOOL match ARGS2 (CONST char *,unknown, CONST char *,template) +{ + CONST char * u = unknown; + CONST char * t = template; + for (; *u && *t && (TOUPPER(*u) == *t); u++, t++) + ; /* Find mismatch or end */ + return (BOOL)(*t == 0); /* OK if end of template */ +} + +typedef enum { + NNTPAUTH_ERROR = 0, /* general failure */ + NNTPAUTH_OK = 281, /* authenticated successfully */ + NNTPAUTH_CLOSE = 502 /* server probably closed connection */ +} NNTPAuthResult; +/* +** This function handles nntp authentication. - FM +*/ +PRIVATE NNTPAuthResult HTHandleAuthInfo ARGS1( + char *, host) +{ + HTList *cur = NULL; + NNTPAuth *auth = NULL; + char *UserName = NULL; + char *PassWord = NULL; + char *msg = NULL; + char buffer[512]; + int status, tries; + + /* + ** Make sure we have an interactive user and a host. - FM + */ + if (dump_output_immediately || !(host && *host)) + return NNTPAUTH_ERROR; + + /* + ** Check for an existing authorization entry. - FM + */ + if (NNTP_AuthInfo != NULL) { + cur = NNTP_AuthInfo; + while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { + if (!strcmp(auth->host, host)) { + UserName = auth->user; + PassWord = auth->pass; + break; + } + } + } else { + NNTP_AuthInfo = HTList_new(); + atexit(free_NNTP_AuthInfo); + } + + /* + ** Handle the username. - FM + */ + buffer[511] = '\0'; + tries = 3; + + while (tries) { + if (UserName == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "Username for news host '%s':", host); + UserName = HTPrompt(msg, NULL); + FREE(msg); + if (!(UserName && *UserName)) { + FREE(UserName); + return NNTPAUTH_ERROR; + } + } + sprintf(buffer, "AUTHINFO USER %.*s%c%c", 495, UserName, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) + _HTProgress("Connection interrupted."); + else + HTAlert("Connection closed ???"); + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + } else { + FREE(UserName); + } + return NNTPAUTH_CLOSE; + } + if (status == 281) { + /* + ** Username is accepted and no password is required. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + } else { + /* + ** Store the accepted username and no password. - FM + */ + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + if (status != 381) { + /* + ** Not success, nor a request for the password, + ** so it must be an error. - FM + */ + HTAlert(response_text); + tries--; + if ((tries > 0) && HTConfirm("Change username?")) { + if (!auth || auth->user != UserName) { + FREE(UserName); + } + if ((UserName = HTPrompt("Username:", UserName)) != NULL && + *UserName) { + continue; + } + } + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + } + FREE(auth->pass); + } + FREE(UserName); + return NNTPAUTH_ERROR; + } + break; + } + + if (status == 381) { + /* + ** Handle the password. - FM + */ + tries = 3; + while (tries) { + if (PassWord == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "Password for news host '%s':", host); + PassWord = HTPromptPassword(msg); + FREE(msg); + if (!(PassWord && *PassWord)) { + FREE(PassWord); + return NNTPAUTH_ERROR; + } + } + sprintf(buffer, "AUTHINFO PASS %.*s%c%c", 495, PassWord, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + } else { + HTAlert("Connection closed ???"); + } + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + if (auth->pass != PassWord) { + FREE(auth->pass); + auth->pass = PassWord; + } + } else { + FREE(UserName); + FREE(PassWord); + } + return NNTPAUTH_CLOSE; + } + if (status == 502) { + /* + * That's what INN's nnrpd returns. + * It closes the connection after this. - kw + */ + HTAlert(response_text); + if (auth) { + if (auth->user == UserName) + UserName = NULL; + FREE(auth->user); + if (auth->pass == PassWord) + PassWord = NULL; + FREE(auth->pass); + } + FREE(UserName); + FREE(PassWord); + return NNTPAUTH_CLOSE; + } + if (status == 281) { + /* + ** Password also is accepted, and everything + ** has been stored. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + if (auth->pass != PassWord) { + FREE(auth->pass); + auth->pass = PassWord; + } + } else { + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + auth->pass = PassWord; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + /* + ** Not success, so it must be an error. - FM + */ + HTAlert(response_text); + if (!auth || auth->pass != PassWord) { + FREE(PassWord); + } else { + PassWord = NULL; + } + tries--; + if ((tries > 0) && HTConfirm("Change password?")) { + continue; + } + if (auth) { + if (auth->user == UserName) + UserName = NULL; + FREE(auth->user); + FREE(auth->pass); + } + FREE(UserName); + break; + } + } + + return NNTPAUTH_ERROR; +} + +/* Find Author's name in mail address +** ---------------------------------- +** +** On exit, +** Returns allocated string which cannot be freed by the +** calling function, and is reallocated on subsequent calls +** to this function. +** +** For example, returns "Tim Berners-Lee" if given any of +** " Tim Berners-Lee <tim@online.cern.ch> " +** or " tim@online.cern.ch ( Tim Berners-Lee ) " +*/ +PRIVATE char * author_name ARGS1 (char *,email) +{ + static char *name = NULL; + char *p, *e; + + StrAllocCopy(name, email); + if (TRACE) + fprintf(stderr,"Trying to find name in: %s\n",name); + + if ((p = strchr(name, '(')) && (e = strchr(name, ')'))) { + if (e > p) { + *e = '\0'; /* Chop off everything after the ')' */ + return HTStrip(p+1); /* Remove leading and trailing spaces */ + } + } + + if ((p = strchr(name, '<')) && (e = strchr(name, '>'))) { + if (e > p) { + strcpy(p, e+1); /* Remove <...> */ + return HTStrip(name); /* Remove leading and trailing spaces */ + } + } + + return HTStrip(name); /* Default to the whole thing */ +} + +/* Find Author's mail address +** -------------------------- +** +** On exit, +** Returns allocated string which cannot be freed by the +** calling function, and is reallocated on subsequent calls +** to this function. +** +** For example, returns "montulli@spaced.out.galaxy.net" if given any of +** " Lou Montulli <montulli@spaced.out.galaxy.net> " +** or " montulli@spaced.out.galaxy.net ( Lou "The Stud" Montulli ) " +*/ +PRIVATE char * author_address ARGS1(char *,email) +{ + static char *address = NULL; + char *p, *at, *e; + + StrAllocCopy(address, email); + if (TRACE) + fprintf(stderr,"Trying to find address in: %s\n",address); + + if ((p = strchr(address, '<'))) { + if ((e = strchr(p, '>')) && (at = strchr(p, '@'))) { + if (at < e) { + *e = '\0'; /* Remove > */ + return HTStrip(p+1); /* Remove leading and trailing spaces */ + } + } + } + + if ((p = strchr(address, '(')) && + (e = strchr(address, ')')) && (at = strchr(address, '@'))) { + if (e > p && at < e) { + *p = '\0'; /* Chop off everything after the ')' */ + return HTStrip(address); /* Remove leading and trailing spaces */ + } + } + + if ((at = strchr(address, '@')) && at > address) { + p = (at - 1); + e = (at + 1); + while (p > address && !isspace((unsigned char)*p)) + p--; + while (*e && !isspace((unsigned char)*e)) + e++; + *e = 0; + return HTStrip(p); + } + + /* + ** Default to the first word. + */ + p = address; + while (isspace((unsigned char)*p)) + p++; /* find first non-space */ + e = p; + while (!isspace((unsigned char)*e) && *e != '\0') + e++; /* find next space or end */ + *e = '\0'; /* terminate space */ + + return(p); +} + +/* Start anchor element +** -------------------- +*/ +PRIVATE void start_anchor ARGS1(CONST char *, href) +{ + BOOL present[HTML_A_ATTRIBUTES]; + CONST char* value[HTML_A_ATTRIBUTES]; + + { + int i; + for(i=0; i < HTML_A_ATTRIBUTES; i++) + present[i] = (i == HTML_A_HREF); + } + ((CONST char **)value)[HTML_A_HREF] = href; + (*targetClass.start_element)(target, HTML_A , present, + (CONST char **)value, -1, 0); +} + +/* Start link element +** ------------------ +*/ +PRIVATE void start_link ARGS2(CONST char *, href, CONST char *, rev) +{ + BOOL present[HTML_LINK_ATTRIBUTES]; + CONST char* value[HTML_LINK_ATTRIBUTES]; + + { + int i; + for(i=0; i < HTML_LINK_ATTRIBUTES; i++) + present[i] = (i == HTML_LINK_HREF || i == HTML_LINK_REV); + } + ((CONST char **)value)[HTML_LINK_HREF] = href; + ((CONST char **)value)[HTML_LINK_REV] = rev; + (*targetClass.start_element)(target, HTML_LINK, present, + (CONST char **)value, -1, 0); +} + +/* Start list element +** ------------------ +*/ +PRIVATE void start_list ARGS1(int, seqnum) +{ + BOOL present[HTML_OL_ATTRIBUTES]; + CONST char* value[HTML_OL_ATTRIBUTES]; + char SeqNum[20]; + int i; + + for (i = 0; i < HTML_OL_ATTRIBUTES; i++) + present[i] = (i == HTML_OL_SEQNUM || i == HTML_OL_START); + sprintf(SeqNum, "%d", seqnum); + ((CONST char **)value)[HTML_OL_SEQNUM] = SeqNum; + ((CONST char **)value)[HTML_OL_START] = SeqNum; + (*targetClass.start_element)(target, HTML_OL , present, + (CONST char **)value, -1, 0); +} + +/* Paste in an Anchor +** ------------------ +** +** +** On entry, +** HT has a selection of zero length at the end. +** text points to the text to be put into the file, 0 terminated. +** addr points to the hypertext reference address, +** terminated by white space, comma, NULL or '>' +*/ +PRIVATE void write_anchor ARGS2(CONST char *,text, CONST char *,addr) +{ + char href[LINE_LENGTH+1]; + + { + CONST char * p; + strcpy(href, NewsHREF); + for (p = addr; *p && (*p != '>') && !WHITE(*p) && (*p!=','); p++) + ; + strncat(href, addr, p-addr); /* Make complete hypertext reference */ + } + + start_anchor(href); + PUTS(text); + END(HTML_A); +} + +/* Write list of anchors +** --------------------- +** +** We take a pointer to a list of objects, and write out each, +** generating an anchor for each. +** +** On entry, +** HT has a selection of zero length at the end. +** text points to a comma or space separated list of addresses. +** On exit, +** *text is NOT any more chopped up into substrings. +*/ +PRIVATE void write_anchors ARGS1 (char *,text) +{ + char * start = text; + char * end; + char c; + for (;;) { + for (; *start && (WHITE(*start)); start++) + ; /* Find start */ + if (!*start) + return; /* (Done) */ + for (end = start; + *end && (*end != ' ') && (*end != ','); end++) + ;/* Find end */ + if (*end) + end++; /* Include comma or space but not NULL */ + c = *end; + *end = '\0'; + if (*start == '<') + write_anchor(start, start+1); + else + write_anchor(start, start); + START(HTML_BR); + *end = c; + start = end; /* Point to next one */ + } +} + +/* Abort the connection abort_socket +** -------------------- +*/ +PRIVATE void abort_socket NOARGS +{ + if (TRACE) + fprintf(stderr, + "HTNews: EOF on read, closing socket %d\n", s); + NEWS_NETCLOSE(s); /* End of file, close socket */ + PUTS("Network Error: connection lost"); + PUTC('\n'); + s = -1; /* End of file on response */ +} + +/* +** Determine if a line is a valid header line. valid_header +** ------------------------------------------- +*/ +PRIVATE BOOLEAN valid_header ARGS1( + char *, line) +{ + char *colon, *space; + + /* + ** Blank or tab in first position implies + ** this is a continuation header. + */ + if (line[0] == ' ' || line[0] == '\t') + return(TRUE); + + /* + ** Just check for initial letter, colon, and space to make + ** sure we discard only invalid headers. + */ + colon = strchr(line, ':'); + space = strchr(line, ' '); + if (isalpha(line[0]) && colon && space == colon + 1) + return(TRUE); + + /* + ** Anything else is a bad header -- it should be ignored. + */ + return(FALSE); +} + +/* post in an Article post_article +** ------------------ +** (added by FM, modeled on Lynx's previous mini inews) +** +** Note the termination condition of a single dot on a line by itself. +** +** On entry, +** s Global socket number is OK +** postfile file with header and article to post. +*/ +PRIVATE void post_article ARGS1( + char *, postfile) +{ + char line[512]; + char buf[512]; + char crlf[3]; + char *cp; + int status; + FILE *fd; + int in_header = 1, seen_header = 0, seen_fromline = 0; + int blen = 0, llen = 0; + + + /* + ** Open the temporary file with the + ** nntp headers and message body. - FM + */ + if ((fd = fopen((postfile ? postfile : ""), "r")) == NULL) { + HTAlert("Cannot open temporary file for news POST."); + return; + } + + /* + ** Read the temporary file and post + ** in maximum 512 byte chunks. - FM + */ + buf[0] = '\0'; + sprintf(crlf, "%c%c", CR, LF); + while (fgets(line, sizeof(line), fd) != NULL) { + if ((cp = strchr(line, '\n')) != NULL) + *cp = '\0'; + if (line[0] == '.') { + /* + ** A single '.' means end of transmission + ** for nntp. Lead dots on lines normally + ** are trimmed and the EOF is not registered + ** if the dot was not followed by CRLF. + ** We prepend an extra dot for any line + ** beginning with one, to retain the one + ** intended, as well as avoid a false EOF + ** signal. We know we have room for it in + ** the buffer, because we normally send when + ** it would exceed 510. - FM + */ + strcat(buf, "."); + blen++; + } + llen = strlen(line); + if (in_header && !strncasecomp(line, "From:", 5)) { + seen_header = 1; + seen_fromline = 1; + } + if (in_header && line[0] == '\0') { + if (seen_header) { + in_header = 0; + if (!seen_fromline) { + if (blen < 475) { + strcat(buf, "From: anonymous@nowhere.you.know"); + strcat(buf, crlf); + blen += 34; + } else { + NEWS_NETWRITE(s, buf, blen); + sprintf(buf, + "From: anonymous@nowhere.you.know%s", crlf); + blen = 34; + } + } + } else { + continue; + } + } else if (in_header) { + if (valid_header(line)) { + seen_header = 1; + } else { + continue; + } + } + strcat(line, crlf); + llen += 2; + if ((blen + llen) < 511) { + strcat(buf, line); + blen += llen; + } else { + NEWS_NETWRITE(s, buf, blen); + strcpy(buf, line); + blen = llen; + } + } + fclose(fd); +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + + /* + ** Send the nntp EOF and get the server's response. - FM + */ + if (blen < 508) { + strcat(buf, "."); + strcat(buf, crlf); + blen += 3; + NEWS_NETWRITE(s, buf, blen); + } else { + NEWS_NETWRITE(s, buf, blen); + sprintf(buf, ".%s", crlf); + blen = 3; + NEWS_NETWRITE(s, buf, blen); + } + status = response(NULL); + if (status == 240) { + /* + ** Successful post. - FM + */ + HTProgress(response_text); + } else { + /* + ** Shucks, something went wrong. - FM + */ + HTAlert(response_text); + } +} + +/* Read in an Article read_article +** ------------------ +** +** Note the termination condition of a single dot on a line by itself. +** RFC 977 specifies that the line "folding" of RFC850 is not used, so we +** do not handle it here. +** +** On entry, +** s Global socket number is OK +** HT Global hypertext object is ready for appending text +*/ +PRIVATE int read_article NOARGS +{ + char line[LINE_LENGTH+1]; + char *full_line = NULL; + char *subject = NULL; /* Subject string */ + char *from = NULL; /* From string */ + char *replyto = NULL; /* Reply-to string */ + char *date = NULL; /* Date string */ + char *organization = NULL; /* Organization string */ + char *references = NULL; /* Hrefs for other articles */ + char *newsgroups = NULL; /* Newsgroups list */ + char *followupto = NULL; /* Followup list */ + char *href = NULL; + char *p = line; + BOOL done = NO; + + /* + ** Read in the HEADer of the article. + ** + ** The header fields are either ignored, + ** or formatted and put into the text. + */ + if (!diagnostic && !rawtext) { + while (!done) { + char ch = *p++ = NEXT_CHAR; + if (ch == (char)EOF) { + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } + abort_socket(); /* End of file, close socket */ + return(HT_LOADED); /* End of file on response */ + } + if ((ch == LF) || (p == &line[LINE_LENGTH])) { + *--p = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, "H %s\n", line); + + if (line[0] == '\t' || line[0] == ' ') { + int i = 0; + while (line[i]) { + if (line[i] == '\t') + line[i] = ' '; + i++; + } + if (full_line == NULL) { + StrAllocCopy(full_line, line); + } else { + StrAllocCat(full_line, line); + } + } else { + StrAllocCopy(full_line, line); + } + + if (full_line[0] == '.') { + /* + ** End of article? + */ + if ((unsigned char)full_line[1] < ' ') { + done = YES; + break; + } + } else if ((unsigned char)full_line[0] < ' ') { + break; /* End of Header? */ + + } else if (match(full_line, "SUBJECT:")) { + StrAllocCopy(subject, HTStrip(strchr(full_line,':')+1)); + if (HTCJK == JAPANESE) { + HTmmdecode(subject, subject); + HTrjis(subject, subject); + } + + } else if (match(full_line, "DATE:")) { + StrAllocCopy(date, HTStrip(strchr(full_line,':')+1)); + + } else if (match(full_line, "ORGANIZATION:")) { + StrAllocCopy(organization, + HTStrip(strchr(full_line,':')+1)); + if (HTCJK == JAPANESE) { + HTmmdecode(organization, organization); + HTrjis(organization, organization); + } + + } else if (match(full_line, "FROM:")) { + StrAllocCopy(from, HTStrip(strchr(full_line,':')+1)); + if (HTCJK == JAPANESE) { + HTmmdecode(from, from); + HTrjis(from, from); + } + + } else if (match(full_line, "REPLY-TO:")) { + StrAllocCopy(replyto, HTStrip(strchr(full_line,':')+1)); + if (HTCJK == JAPANESE) { + HTmmdecode(replyto, replyto); + HTrjis(replyto, replyto); + } + + } else if (match(full_line, "NEWSGROUPS:")) { + StrAllocCopy(newsgroups, HTStrip(strchr(full_line,':')+1)); + + } else if (match(full_line, "REFERENCES:")) { + StrAllocCopy(references, HTStrip(strchr(full_line,':')+1)); + + } else if (match(full_line, "FOLLOWUP-TO:")) { + StrAllocCopy(followupto, HTStrip(strchr(full_line,':')+1)); + + } /* end if match */ + p = line; /* Restart at beginning */ + } /* if end of line */ + } /* Loop over characters */ + FREE(full_line); + + START(HTML_HEAD); + PUTC('\n'); + START(HTML_TITLE); + if (subject && *subject != '\0') + PUTS(subject); + else + PUTS("No Subject"); + END(HTML_TITLE); + PUTC('\n'); + /* + ** Put in the owner as a link rel. + */ + if (from || replyto) { + char *temp=NULL; + StrAllocCopy(temp, replyto ? replyto : from); + StrAllocCopy(href,"mailto:"); + StrAllocCat(href, author_address(temp)); + start_link(href, "made"); + PUTC('\n'); + FREE(temp); + } + END(HTML_HEAD); + PUTC('\n'); + + START(HTML_H1); + if (subject && *subject != '\0') + PUTS(subject); + else + PUTS("No Subject"); + END(HTML_H1); + PUTC('\n'); + + if (subject) + FREE(subject); + + START(HTML_DLC); + PUTC('\n'); + + if (from || replyto) { + START(HTML_DT); + START(HTML_B); + PUTS("From:"); + END(HTML_B); + PUTC(' '); + if (from) + PUTS(from); + else + PUTS(from); + MAYBE_END(HTML_DT); + PUTC('\n'); + + if (!replyto) + StrAllocCopy(replyto, from); + START(HTML_DT); + START(HTML_B); + PUTS("Reply to:"); + END(HTML_B); + PUTC(' '); + start_anchor(href); + if (*replyto != '<') + PUTS(author_name(replyto)); + else + PUTS(author_address(replyto)); + END(HTML_A); + START(HTML_BR); + MAYBE_END(HTML_DT); + PUTC('\n'); + + FREE(from); + FREE(replyto); + } + + if (date) { + START(HTML_DT); + START(HTML_B); + PUTS("Date:"); + END(HTML_B); + PUTC(' '); + PUTS(date); + MAYBE_END(HTML_DT); + PUTC('\n'); + FREE(date); + } + + if (organization) { + START(HTML_DT); + START(HTML_B); + PUTS("Organization:"); + END(HTML_B); + PUTC(' '); + PUTS(organization); + MAYBE_END(HTML_DT); + PUTC('\n'); + FREE(organization); + } + + if (newsgroups && HTCanPost) { + /* + ** We have permission to POST to this host, + ** so add a link for posting followups for + ** this article. - FM + */ + if (!strncasecomp(NewsHREF, "snews:", 6)) + StrAllocCopy(href,"snewsreply://"); + else + StrAllocCopy(href,"newsreply://"); + StrAllocCat(href, NewsHost); + StrAllocCat(href, "/"); + StrAllocCat(href, (followupto ? followupto : newsgroups)); + + START(HTML_DT); + START(HTML_B); + PUTS("Newsgroups:"); + END(HTML_B); + PUTC('\n'); + MAYBE_END(HTML_DT); + START(HTML_DD); + write_anchors(newsgroups); + MAYBE_END(HTML_DD); + PUTC('\n'); + + START(HTML_DT); + START(HTML_B); + PUTS("Followup to:"); + END(HTML_B); + PUTC(' '); + start_anchor(href); + PUTS("newsgroup(s)"); + END(HTML_A); + MAYBE_END(HTML_DT); + PUTC('\n'); + } + FREE(newsgroups); + FREE(followupto); + + if (references) { + START(HTML_DT); + START(HTML_B); + PUTS("References:"); + END(HTML_B); + MAYBE_END(HTML_DT); + PUTC('\n'); + START(HTML_DD); + write_anchors(references); + MAYBE_END(HTML_DD); + PUTC('\n'); + FREE(references); + } + + END(HTML_DLC); + PUTC('\n'); + FREE(href); + } + + if (rawtext) { + /* + * No tags - kw + */ + ; + } else if (diagnostic) { + /* + ** Read in the HEAD and BODY of the Article + ** as XMP formatted text. - FM + */ + START(HTML_XMP); + } else { + /* + ** Read in the BODY of the Article + ** as PRE formatted text. - FM + */ + START(HTML_PRE); + } + PUTC('\n'); + + p = line; + while (!done) { + char ch = *p++ = NEXT_CHAR; + if (ch == (char)EOF) { + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } + abort_socket(); /* End of file, close socket */ + return(HT_LOADED); /* End of file on response */ + } + if ((ch == LF) || (p == &line[LINE_LENGTH])) { + *p++ = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, "B %s", line); + if (line[0] == '.') { + /* + ** End of article? + */ + if ((unsigned char)line[1] < ' ') { + done = YES; + break; + } else { /* Line starts with dot */ + if (rawtext) + RAW_PUTS(&line[1]); + else + PUTS(&line[1]); /* Ignore first dot */ + } + } else { + if (rawtext) { + RAW_PUTS(line); + } else if (diagnostic || !scan_for_buried_news_references) { + /* + ** All lines are passed as unmodified source. - FM + */ + PUTS(line); + } else { + /* + ** Normal lines are scanned for buried references + ** to other articles. Unfortunately, it could pick + ** up mail addresses as well! It also can corrupt + ** uuencoded messages! So we don't do this when + ** fetching articles as WWW_SOURCE or when downloading + ** (diagnostic is TRUE) or if the client has set + ** scan_for_buried_news_references to FALSE. + ** Otherwise, we convert all "<...@...>" strings + ** preceded by "rticle " to "news:...@..." links, + ** and any strings that look like URLs to links. - FM + */ + char *l = line; + char *p2; + + while ((p2 = strstr(l, "rticle <")) != NULL) { + char *q = strchr(p2,'>'); + char *at = strchr(p2, '@'); + if (q && at && at<q) { + char c = q[1]; + q[1] = 0; /* chop up */ + p2 += 7; + *p2 = 0; + while (*l) { + if (strncmp(l, "news:", 5) && + strncmp(l, "snews://", 8) && + strncmp(l, "nntp://", 7) && + strncmp(l, "snewspost:", 10) && + strncmp(l, "snewsreply:", 11) && + strncmp(l, "newspost:", 9) && + strncmp(l, "newsreply:", 10) && + strncmp(l, "ftp://", 6) && + strncmp(l, "file:/", 6) && + strncmp(l, "finger://", 9) && + strncmp(l, "http://", 7) && + strncmp(l, "https://", 8) && + strncmp(l, "wais://", 7) && + strncmp(l, "mailto:", 7) && + strncmp(l, "cso://", 6) && + strncmp(l, "gopher://", 9)) + PUTC (*l++); + else { + StrAllocCopy(href, l); + start_anchor(strtok(href, " \r\n\t,>)\"")); + while (*l && !strchr(" \r\n\t,>)\"", *l)) + PUTC(*l++); + END(HTML_A); + FREE(href); + } + } + *p2 = '<'; /* again */ + *q = 0; + start_anchor(p2+1); + *q = '>'; /* again */ + PUTS(p2); + END(HTML_A); + q[1] = c; /* again */ + l=q+1; + } else { + break; /* line has unmatched <> */ + } + } + while (*l) { /* Last bit of the line */ + if (strncmp(l, "news:", 5) && + strncmp(l, "snews://", 8) && + strncmp(l, "nntp://", 7) && + strncmp(l, "snewspost:", 10) && + strncmp(l, "snewsreply:", 11) && + strncmp(l, "newspost:", 9) && + strncmp(l, "newsreply:", 10) && + strncmp(l, "ftp://", 6) && + strncmp(l, "file:/", 6) && + strncmp(l, "finger://", 9) && + strncmp(l, "http://", 7) && + strncmp(l, "https://", 8) && + strncmp(l, "wais://", 7) && + strncmp(l, "mailto:", 7) && + strncmp(l, "cso://", 6) && + strncmp(l, "gopher://", 9)) + PUTC (*l++); + else { + StrAllocCopy(href, l); + start_anchor(strtok(href, " \r\n\t,>)\"")); + while (*l && !strchr(" \r\n\t,>)\"", *l)) + PUTC(*l++); + END(HTML_A); + FREE(href); + } + } + } /* if diagnostic or not scan_for_buried_news_references */ + } /* if not dot */ + p = line; /* Restart at beginning */ + } /* if end of line */ + } /* Loop over characters */ + + if (rawtext) + return(HT_LOADED); + + if (diagnostic) + END(HTML_XMP); + else + END(HTML_PRE); + PUTC('\n'); + return(HT_LOADED); +} + +/* Read in a List of Newsgroups +** ---------------------------- +** +** Note the termination condition of a single dot on a line by itself. +** RFC 977 specifies that the line "folding" of RFC850 is not used, +** so we do not handle it here. +*/ +PRIVATE int read_list ARGS1(char *, arg) +{ + char line[LINE_LENGTH+1]; + char *p; + BOOL done = NO; + BOOL head = NO; + BOOL tail = NO; + BOOL skip_this_line = NO; + BOOL skip_rest_of_line = NO; + int listing = 0; + char *pattern = NULL; + int len = 0; + + /* + ** Support head or tail matches for groups to list. - FM + */ + if (arg && strlen(arg) > 1) { + if (*arg == '*') { + tail = YES; + StrAllocCopy(pattern, (arg+1)); + } else if (arg[strlen(arg)-1] == '*') { + head = YES; + StrAllocCopy(pattern, arg); + pattern[strlen(pattern)-1] = '\0'; + } + if (tail || head) { + len = strlen(pattern); + } + + } + + /* + ** Read the server's reply. + ** + ** The lines are scanned for newsgroup + ** names and descriptions. + */ + START(HTML_HEAD); + PUTC('\n'); + START(HTML_TITLE); + PUTS("Newsgroups"); + END(HTML_TITLE); + PUTC('\n'); + END(HTML_HEAD); + PUTC('\n'); + START(HTML_H1); + PUTS( "Newsgroups"); + END(HTML_H1); + PUTC('\n'); + p = line; + START(HTML_DLC); + PUTC('\n'); + while (!done) { + char ch = NEXT_CHAR; + if (ch == (char)EOF) { + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } + abort_socket(); /* End of file, close socket */ + FREE(pattern); + return(HT_LOADED); /* End of file on response */ + } else if (skip_this_line) { + if (ch == LF) { + skip_this_line = skip_rest_of_line = NO; + p = line; + } + continue; + } else if (skip_rest_of_line) { + if (ch != LF) { + continue; + } + } else if (p == &line[LINE_LENGTH]) { + if (TRACE) { + fprintf(stderr, "b %.*s%c[...]\n", (LINE_LENGTH), line, ch); + } + *p = '\0'; + if (ch == LF) { + ; /* Will be dealt with below */ + } else if (WHITE(ch)) { + ch = LF; /* May treat as line without description */ + skip_this_line = YES; /* ...and ignore until LF */ + } else if (strchr(line, ' ') == NULL && + strchr(line, '\t') == NULL) { + /* No separator found */ + if (TRACE) + fprintf(stderr, + "HTNews..... group name too long, discarding.\n"); + skip_this_line = YES; /* ignore whole line */ + continue; + } else { + skip_rest_of_line = YES; /* skip until ch == LF found */ + } + } else { + *p++ = ch; + } + if (ch == LF) { + skip_rest_of_line = NO; /* done, reset flag */ + *p = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, "B %s", line); + if (line[0] == '.') { + /* + ** End of article? + */ + if ((unsigned char)line[1] < ' ') { + done = YES; + break; + } else { /* Line starts with dot */ + START(HTML_DT); + PUTS(&line[1]); + MAYBE_END(HTML_DT); + } + } else if (line[0] == '#') { /* Comment? */ + p = line; /* Restart at beginning */ + continue; + } else { + /* + ** Normal lines are scanned for references to newsgroups. + */ + int i = 0; + + /* find whitespace if it exits */ + for (; line[i] != '\0' && !WHITE(line[i]); i++) + ; /* null body */ + + if (line[i] != '\0') { + line[i] = '\0'; + if ((head && strncasecomp(line, pattern, len)) || + (tail && (i < len || + strcasecomp((line + (i - len)), pattern)))) { + p = line; /* Restart at beginning */ + continue; + } + START(HTML_DT); + write_anchor(line, line); + listing++; + MAYBE_END(HTML_DT); + PUTC('\n'); + START(HTML_DD); + PUTS(&line[i+1]); /* put description */ + MAYBE_END(HTML_DD); + } else { + if ((head && strncasecomp(line, pattern, len)) || + (tail && (i < len || + strcasecomp((line + (i - len)), pattern)))) { + p = line; /* Restart at beginning */ + continue; + } + START(HTML_DT); + write_anchor(line, line); + MAYBE_END(HTML_DT); + listing++; + } + } /* if not dot */ + p = line; /* Restart at beginning */ + } /* if end of line */ + } /* Loop over characters */ + if (!listing) { + START(HTML_DT); + sprintf(line, "No matches for: %s", arg); + PUTS(line); + MAYBE_END(HTML_DT); + } + END(HTML_DLC); + PUTC('\n'); + FREE(pattern); + return(HT_LOADED); +} + +/* Read in a Newsgroup +** ------------------- +** +** Unfortunately, we have to ask for each article one by one if we +** want more than one field. +** +*/ +PRIVATE int read_group ARGS3( + CONST char *,groupName, + int,first_required, + int,last_required) +{ + char line[LINE_LENGTH+1]; + char author[LINE_LENGTH+1]; + char subject[LINE_LENGTH+1]; + char *date = NULL; + int i; + char *p; + BOOL done; + + char buffer[LINE_LENGTH]; + char *reference = NULL; /* Href for article */ + int art; /* Article number WITHIN GROUP */ + int status, count, first, last; /* Response fields */ + /* count is only an upper limit */ + + author[0] = '\0'; + START(HTML_HEAD); + PUTC('\n'); + START(HTML_TITLE); + PUTS("Newsgroup "); + PUTS(groupName); + END(HTML_TITLE); + PUTC('\n'); + END(HTML_HEAD); + PUTC('\n'); + + sscanf(response_text, " %d %d %d %d", &status, &count, &first, &last); + if (TRACE) + fprintf(stderr, + "Newsgroup status=%d, count=%d, (%d-%d) required:(%d-%d)\n", + status, count, first, last, first_required, last_required); + if (last == 0) { + PUTS("\nNo articles in this group.\n"); + goto add_post; + } + +#define FAST_THRESHOLD 100 /* Above this, read IDs fast */ +#define CHOP_THRESHOLD 50 /* Above this, chop off the rest */ + + if (first_required < first) + first_required = first; /* clip */ + if ((last_required == 0) || (last_required > last)) + last_required = last; + + if (last_required < first_required) { + PUTS("\nNo articles in this range.\n"); + goto add_post; + } + + if (last_required-first_required+1 > HTNewsMaxChunk) { /* Trim this block */ + first_required = last_required-HTNewsChunkSize+1; + } + if (TRACE) + fprintf(stderr, " Chunk will be (%d-%d)\n", + first_required, last_required); + + /* + ** Set window title. + */ + sprintf(buffer, "%s, Articles %d-%d", + groupName, first_required, last_required); + START(HTML_H1); + PUTS(buffer); + END(HTML_H1); + PUTC('\n'); + + /* + ** Link to earlier articles. + */ + if (first_required > first) { + int before; /* Start of one before */ + if (first_required-HTNewsMaxChunk <= first) + before = first; + else + before = first_required-HTNewsChunkSize; + sprintf(buffer, "%s%s/%d-%d", NewsHREF, groupName, + before, first_required-1); + if (TRACE) + fprintf(stderr, " Block before is %s\n", buffer); + PUTC('('); + start_anchor(buffer); + PUTS("Earlier articles"); + END(HTML_A); + PUTS("...)\n"); + START(HTML_P); + PUTC('\n'); + } + + done = NO; + +/*#define USE_XHDR*/ +#ifdef USE_XHDR + if (count > FAST_THRESHOLD) { + sprintf(buffer, + "\nThere are about %d articles currently available in %s, IDs as follows:\n\n", + count, groupName); + PUTS(buffer); + sprintf(buffer, "XHDR Message-ID %d-%d%c%c", first, last, CR, LF); + status = response(buffer); + if (status == 221) { + p = line; + while (!done) { + char ch = *p++ = NEXT_CHAR; + if (ch == (char)EOF) { + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } + abort_socket(); /* End of file, close socket */ + return(HT_LOADED); /* End of file on response */ + } + if ((ch == '\n') || (p == &line[LINE_LENGTH])) { + *p = '\0'; /* Terminate the string */ + if (TRACE) + fprintf(stderr, "X %s", line); + if (line[0] == '.') { + /* + ** End of article? + */ + if ((unsigned char)line[1] < ' ') { + done = YES; + break; + } else { /* Line starts with dot */ + /* Ignore strange line */ + } + } else { + /* + ** Normal lines are scanned for + ** references to articles. + */ + char * space = strchr(line, ' '); + if (space++) + write_anchor(space, space); + } /* if not dot */ + p = line; /* Restart at beginning */ + } /* if end of line */ + } /* Loop over characters */ + + /* leaving loop with "done" set */ + } /* Good status */ + } +#endif /* USE_XHDR */ + + /* + ** Read newsgroup using individual fields. + */ + if (!done) { + START(HTML_B); + if (first == first_required && last == last_required) + PUTS("All available articles in "); + else + PUTS("Articles in "); + PUTS(groupName); + END(HTML_B); + PUTC('\n'); + if (LYListNewsNumbers) + start_list(first_required); + else + START(HTML_UL); + for (art = first_required; art <= last_required; art++) { +/*#define OVERLAP*/ +#ifdef OVERLAP + /* + ** With this code we try to keep the server running flat out + ** by queuing just one extra command ahead of time. + ** We assume (1) that the server won't abort if it gets input + ** during output, and (2) that TCP buffering is enough for the + ** two commands. Both these assumptions seem very reasonable. + ** However, we HAVE had a hangup with a loaded server. + */ + if (art == first_required) { + if (art == last_required) { /* Only one */ + sprintf(buffer, "HEAD %d%c%c", + art, CR, LF); + status = response(buffer); + } else { /* First of many */ + sprintf(buffer, "HEAD %d%c%cHEAD %d%c%c", + art, CR, LF, art+1, CR, LF); + status = response(buffer); + } + } else if (art == last_required) { /* Last of many */ + status = response(NULL); + } else { /* Middle of many */ + sprintf(buffer, "HEAD %d%c%c", art+1, CR, LF); + status = response(buffer); + } +#else /* Not OVERLAP: */ + sprintf(buffer, "HEAD %d%c%c", art, CR, LF); + status = response(buffer); +#endif /* OVERLAP */ + /* + ** Check for a good response (221) for the HEAD request, + ** and if so, parse it. Otherwise, indicate the error + ** so that the number of listings corresponds to what's + ** claimed for the range, and if we are listing numbers + ** via an ordered list, they stay in synchrony with the + ** article numbers. - FM + */ + if (status == 221) { /* Head follows - parse it:*/ + p = line; /* Write pointer */ + done = NO; + while( !done ) { + char ch = *p++ = NEXT_CHAR; + if (ch == (char)EOF) { + if (interrupted_in_htgetcharacter) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } + abort_socket(); /* End of file, close socket */ + return(HT_LOADED); /* End of file on response */ + } + if ((ch == LF) || + (p == &line[LINE_LENGTH])) { + + *--p = '\0'; /* Terminate & chop LF*/ + p = line; /* Restart at beginning */ + if (TRACE) + fprintf(stderr, "G %s\n", line); + switch(line[0]) { + + case '.': + /* + ** End of article? + */ + done = ((unsigned char)line[1] < ' '); + break; + + case 'S': + case 's': + if (match(line, "SUBJECT:")) { + strcpy(subject, line+9);/* Save subject */ + if (HTCJK == JAPANESE) { + HTmmdecode(subject, subject); + HTrjis(subject, subject); + } + } + break; + + case 'M': + case 'm': + if (match(line, "MESSAGE-ID:")) { + char * addr = HTStrip(line+11) +1; /* Chop < */ + addr[strlen(addr)-1] = '\0'; /* Chop > */ + StrAllocCopy(reference, addr); + } + break; + + case 'f': + case 'F': + if (match(line, "FROM:")) { + char * p2; + strcpy(author, + author_name(strchr(line,':')+1)); + if (HTCJK == JAPANESE) { + HTmmdecode(author, author); + HTrjis(author, author); + } + p2 = author + strlen(author) - 1; + if (*p2==LF) + *p2 = '\0'; /* Chop off newline */ + } + break; + + case 'd': + case 'D': + if (LYListNewsDates && match(line, "DATE:")) { + StrAllocCopy(date, + HTStrip(strchr(line,':')+1)); + } + break; + + } /* end switch on first character */ + } /* if end of line */ + } /* Loop over characters */ + + PUTC('\n'); + START(HTML_LI); + sprintf(buffer, "\"%s\"", subject); + if (reference) { + write_anchor(buffer, reference); + FREE(reference); + } else { + PUTS(buffer); + } + if (author[0] != '\0') { + PUTS(" - "); + if (LYListNewsDates) + START(HTML_I); + PUTS(author); + if (LYListNewsDates) + END(HTML_I); + author[0] = '\0'; + } + if (date) { + if (!diagnostic) { + for (i = 0; date[i]; i++) { + if (date[i] == ' ') { + date[i] = HT_NON_BREAK_SPACE; + } + } + } + sprintf(buffer, " [%s]", date); + PUTS(buffer); + FREE(date); + } + MAYBE_END(HTML_LI); + /* + ** Indicate progress! @@@@@@ + */ + } else if (status == HT_INTERRUPTED) { + interrupted_in_htgetcharacter = 0; + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on read, closing socket %d\n", + s); + NEWS_NETCLOSE(s); + s = -1; + return(HT_INTERRUPTED); + } else { + /* + ** Use the response text on error. - FM + */ + PUTC('\n'); + START(HTML_LI); + START(HTML_I); + if (LYListNewsNumbers) + strcpy(buffer, "Status:"); + else + sprintf(buffer, "Status (ARTICLE %d):", art); + PUTS(buffer); + END(HTML_I); + PUTC(' '); + PUTS(response_text); + MAYBE_END(HTML_LI); + } /* Handle response to HEAD request */ + } /* Loop over article */ + } /* If read headers */ + PUTC('\n'); + if (LYListNewsNumbers) + END(HTML_OL); + else + END(HTML_UL); + PUTC('\n'); + + /* + ** Link to later articles. + */ + if (last_required < last) { + int after; /* End of article after */ + after = last_required+HTNewsChunkSize; + if (after == last) + sprintf(buffer, "%s%s", NewsHREF, groupName); /* original group */ + else + sprintf(buffer, "%s%s/%d-%d", NewsHREF, groupName, + last_required+1, after); + if (TRACE) + fprintf(stderr, " Block after is %s\n", buffer); + PUTC('('); + start_anchor(buffer); + PUTS("Later articles"); + END(HTML_A); + PUTS("...)\n"); + } + +add_post: + if (HTCanPost) { + /* + ** We have permission to POST to this host, + ** so add a link for posting messages to + ** this newsgroup. - FM + */ + char *href = NULL; + + START(HTML_HR); + PUTC('\n'); + if (!strncasecomp(NewsHREF, "snews:", 6)) + StrAllocCopy(href,"snewspost://"); + else + StrAllocCopy(href,"newspost://"); + StrAllocCat(href, NewsHost); + StrAllocCat(href, "/"); + StrAllocCat(href,groupName); + start_anchor(href); + PUTS("Post to "); + PUTS(groupName); + END(HTML_A); + FREE(href); + } else { + START(HTML_HR); + } + PUTC('\n'); + return(HT_LOADED); +} + +/* Load by name. HTLoadNews +** ============= +*/ +PRIVATE int HTLoadNews ARGS4( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, stream) +{ + char command[260]; /* The whole command */ + char proxycmd[260]; /* The proxy command */ + char groupName[GROUP_NAME_LENGTH]; /* Just the group name */ + int status; /* tcp return */ + int retries; /* A count of how hard we have tried */ + BOOL group_wanted; /* Flag: group was asked for, not article */ + BOOL list_wanted; /* Flag: list was asked for, not article */ + BOOL post_wanted; /* Flag: new post to group was asked for */ + BOOL reply_wanted; /* Flag: followup post was asked for */ + BOOL spost_wanted; /* Flag: new SSL post to group was asked for */ + BOOL sreply_wanted; /* Flag: followup SSL post was asked for */ + BOOL head_wanted = NO; /* Flag: want HEAD of single article */ + int first, last; /* First and last articles asked for */ + char *cp = 0; + char *ListArg = NULL; + char *ProxyHost = NULL; + char *ProxyHREF = NULL; + char *postfile = NULL; + + diagnostic = (format_out == WWW_SOURCE || /* set global flag */ + format_out == HTAtom_for("www/download") || + format_out == HTAtom_for("www/dump")); + rawtext = NO; + + if (TRACE) fprintf(stderr, "HTNews: Looking for %s\n", arg); + + if (!initialized) + initialized = initialize(); + if (!initialized) + return -1; /* FAIL */ + + FREE(NewsHREF); + command[0] = '\0'; + command[259] = '\0'; + proxycmd[0] = '\0'; + proxycmd[259] = '\0'; + + { + CONST char * p1 = arg; + + /* + ** We will ask for the document, omitting the host name & anchor. + ** + ** Syntax of address is + ** xxx@yyy Article + ** <xxx@yyy> Same article + ** xxxxx News group (no "@") + ** group/n1-n2 Articles n1 to n2 in group + */ + spost_wanted = (strstr(arg, "snewspost:") != NULL); + sreply_wanted = (!(spost_wanted) && + strstr(arg, "snewsreply:") != NULL); + post_wanted = (!(spost_wanted || sreply_wanted) && + strstr(arg, "newspost:") != NULL); + reply_wanted = (!(spost_wanted || sreply_wanted || + post_wanted) && + strstr(arg, "newsreply:") != NULL); + group_wanted = (!(spost_wanted || sreply_wanted || + post_wanted || reply_wanted) && + strchr(arg, '@') == NULL) && (strchr(arg, '*') == NULL); + list_wanted = (!(spost_wanted || sreply_wanted || + post_wanted || reply_wanted || + group_wanted) && + strchr(arg, '@') == NULL) && (strchr(arg, '*') != NULL); + + if (!strncasecomp(arg, "snewspost:", 10) || + !strncasecomp(arg, "snewsreply:", 11)) { + HTAlert( + "This client does not contain support for posting to news with SSL."); + return HT_NOT_LOADED; + } + if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { + /* + ** Make sure we have a non-zero path for the newsgroup(s). - FM + */ + if ((p1 = strrchr(arg, '/')) != NULL) { + p1++; + } else if ((p1 = strrchr(arg, ':')) != NULL) { + p1++; + } + if (!(p1 && *p1)) { + HTAlert("Invalid URL!"); + return(HT_NO_DATA); + } + if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, HTNewsHost); + } else { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, cp); + } + FREE(cp); + sprintf(command, "%s://%.245s/", + (post_wanted ? + "newspost" : + (reply_wanted ? + "newreply" : + (spost_wanted ? + "snewspost" : "snewsreply"))), NewsHost); + StrAllocCopy(NewsHREF, command); + + /* + ** If the SSL daemon is being used as a proxy, + ** reset p1 to the start of the proxied URL + ** rather than to the start of the newsgroup(s). - FM + */ + if (spost_wanted && strncasecomp(arg, "snewspost:", 10)) + p1 = strstr(arg, "snewspost:"); + if (sreply_wanted && strncasecomp(arg, "snewsreply:", 11)) + p1 = strstr(arg, "snewsreply:"); + + /* p1 = HTParse(arg, "", PARSE_PATH | PARSE_PUNCTUATION); */ + /* + ** Don't use HTParse because news: access doesn't follow traditional + ** rules. For instance, if the article reference contains a '#', + ** the rest of it is lost -- JFG 10/7/92, from a bug report + */ + } else if (!strncasecomp (arg, "nntp:", 5)) { + if (((*(arg + 5) == '\0') || + (!strcmp((arg + 5), "/") || + !strcmp((arg + 5), "//") || + !strcmp((arg + 5), "///"))) || + ((!strncmp((arg + 5), "//", 2)) && + (!(cp = strchr((arg + 7), '/')) || *(cp + 1) == '\0'))) { + p1 = "*"; + group_wanted = FALSE; + list_wanted = TRUE; + } else if (*(arg + 5) != '/') { + p1 = (arg + 5); + } else if (*(arg + 5) == '/' && *(arg + 6) != '/') { + p1 = (arg + 6); + } else { + p1 = (cp + 1); + } + if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, HTNewsHost); + } else { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, cp); + } + FREE(cp); + sprintf(command, "nntp://%.251s/", NewsHost); + StrAllocCopy(NewsHREF, command); + } + else if (!strncasecomp(arg, "snews:", 6)) { + HTAlert("This client does not contain support for SNEWS URLs."); + return HT_NOT_LOADED; + } + else if (!strncasecomp (arg, "news:/", 6)) { + if (((*(arg + 6) == '\0') || + !strcmp((arg + 6), "/") || + !strcmp((arg + 6), "//")) || + ((*(arg + 6) == '/') && + (!(cp = strchr((arg + 7), '/')) || *(cp + 1) == '\0'))) { + p1 = "*"; + group_wanted = FALSE; + list_wanted = TRUE; + } else if (*(arg + 6) != '/') { + p1 = (arg + 6); + } else { + p1 = (cp + 1); + } + if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, HTNewsHost); + } else { + if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, cp); + } + FREE(cp); + sprintf(command, "news://%.251s/", NewsHost); + StrAllocCopy(NewsHREF, command); + } else { + p1 = (arg + 5); /* Skip "news:" prefix */ + if (*p1 == '\0') { + p1 = "*"; + group_wanted = FALSE; + list_wanted = TRUE; + } + if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) { + NEWS_NETCLOSE(s); + s = -1; + } + StrAllocCopy(NewsHost, HTNewsHost); + StrAllocCopy(NewsHREF, "news:"); + } + + /* + ** Set up any proxy for snews URLs that returns NNTP + ** responses for Lynx to convert to HTML, instead of + ** doing the conversion itself, and for handling posts + ** or followups. - TZ & FM + */ + if (!strncasecomp(p1, "snews:", 6) || + !strncasecomp(p1, "snewspost:", 10) || + !strncasecomp(p1, "snewsreply:", 11)) { + StrAllocCopy(ProxyHost, NewsHost); + if ((cp = HTParse(p1, "", PARSE_HOST)) != NULL && *cp != '\0') { + sprintf(command, "snews://%.250s", cp); + StrAllocCopy(NewsHost, cp); + } else { + sprintf(command, "snews://%.250s", NewsHost); + } + command[258] = '\0'; + FREE(cp); + sprintf(proxycmd, "GET %.251s%c%c%c%c", command, CR, LF, CR, LF); + if (TRACE) + fprintf(stderr, + "HTNews: Proxy command is '%.*s'\n", + (int)(strlen(proxycmd) - 4), proxycmd); + strcat(command, "/"); + StrAllocCopy(ProxyHREF, NewsHREF); + StrAllocCopy(NewsHREF, command); + if (spost_wanted || sreply_wanted) { + /* + ** Reset p1 so that it points to the newsgroup(s). + */ + if ((p1 = strrchr(arg, '/')) != NULL) { + p1++; + } else { + p1 = (strrchr(arg, ':') + 1); + } + } else { + /* + ** Reset p1 so that it points to the newgroup + ** (or a wildcard), or the article. + */ + if (!(cp = strrchr((p1 + 6), '/')) || *(cp + 1) == '\0') { + p1 = "*"; + group_wanted = FALSE; + list_wanted = TRUE; + } else { + p1 = (cp + 1); + } + } + } + + /* + ** Set up command for a post, listing, or article request. - FM + */ + if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { + strcpy(command, "POST"); + } else if (list_wanted) { + sprintf(command, "XGTITLE %.*s", 249, p1); + } else if (group_wanted) { + char * slash = strchr(p1, '/'); + strcpy(command, "GROUP "); + first = 0; + last = 0; + if (slash) { + *slash = '\0'; + strcpy(groupName, p1); + *slash = '/'; + (void)sscanf(slash+1, "%d-%d", &first, &last); + if ((first > 0) && (isdigit(*(slash+1))) && + (strchr(slash+1, '-') == NULL || first == last)) { + /* + ** We got a number greater than 0, which will be + ** loaded as first, and either no range or the + ** range computes to zero, so make last negative, + ** as a flag to select the group and then fetch + ** an article by number (first) instead of by + ** messageID. - FM + */ + last = -1; + } + } else { + strcpy(groupName, p1); + } + strcat(command, groupName); + } else { + strcpy(command, "ARTICLE "); + if (strchr(p1, '<') == 0) + strcat(command,"<"); + strcat(command, p1); + if (strchr(p1, '>') == 0) + strcat(command,">"); + } + + { + char * p = command + strlen(command); + /* + ** Terminate command with CRLF, as in RFC 977. + */ + *p++ = CR; /* Macros to be correct on Mac */ + *p++ = LF; + *p++ = 0; + } + StrAllocCopy(ListArg, p1); + } /* scope of p1 */ + + if (!*arg) { + FREE(NewsHREF); + FREE(ProxyHost); + FREE(ProxyHREF); + FREE(ListArg); + return NO; /* Ignore if no name */ + } + + if (!(post_wanted || reply_wanted || spost_wanted || sreply_wanted || + (group_wanted && last != -1) || list_wanted)) { + head_wanted = anAnchor->isHEAD; + if (head_wanted && !strncmp(command, "ARTICLE_", 8)) { + /* overwrite "ARTICLE" - hack... */ + strcpy(command, "HEAD "); + for (cp = command + 5; ; cp++) + if ((*cp = *(cp + 3)) == '\0') + break; + } + rawtext = (head_wanted || keep_mime_headers); + } + if (rawtext) { + node_anchor = anAnchor; + rawtarget = HTStreamStack(WWW_PLAINTEXT, + format_out, + stream, anAnchor); + if (!rawtarget) { + FREE(NewsHost); + FREE(NewsHREF); + FREE(ProxyHost); + FREE(ProxyHREF); + FREE(ListArg); + HTAlert("No target for raw text!"); + return(HT_NOT_LOADED); + } /* Copy routine entry points */ + rawtargetClass = *rawtarget->isa; + } else + /* + ** Make a hypertext object with an anchor list. + */ + if (!(post_wanted || reply_wanted || spost_wanted || sreply_wanted)) { + node_anchor = anAnchor; + target = HTML_new(anAnchor, format_out, stream); + targetClass = *target->isa; /* Copy routine entry points */ + } + + /* + ** Now, let's get a stream setup up from the NewsHost. + */ + for (retries = 0; retries < 2; retries++) { + if (s < 0) { + /* CONNECTING to news host */ + char url[260]; + if (!strcmp(NewsHREF, "news:")) { + sprintf (url, "lose://%.251s/", NewsHost); + } else if (ProxyHREF) { + sprintf (url, "%.259s", ProxyHREF); + } else { + sprintf (url, "%.259s", NewsHREF); + } + if (TRACE) + fprintf (stderr, "News: doing HTDoConnect on '%s'\n", url); + + _HTProgress("Connecting to NewsHost ..."); + + status = HTDoConnect (url, "NNTP", NEWS_PORT, &s); + if (status == HT_INTERRUPTED) { + /* + ** Interrupt cleanly. + */ + if (TRACE) + fprintf(stderr, + "HTNews: Interrupted on connect; recovering cleanly.\n"); + _HTProgress("Connection interrupted."); + if (!(post_wanted || reply_wanted || + spost_wanted || sreply_wanted)) { + ABORT_TARGET; + } + FREE(NewsHost); + FREE(NewsHREF); + FREE(ProxyHost); + FREE(ProxyHREF); + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return HT_NOT_LOADED; + } + if (status < 0) { + char message[256]; + NEWS_NETCLOSE(s); + s = -1; + if (TRACE) + fprintf(stderr, + "HTNews: Unable to connect to news host.\n"); + if (retries < 1) + continue; + sprintf(message, "Could not access %s.", NewsHost); + FREE(NewsHost); + FREE(NewsHREF); + FREE(ProxyHost); + FREE(ProxyHREF); + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return HTLoadError(stream, 500, message); + } else { + if (TRACE) + fprintf(stderr, "HTNews: Connected to news host %s.\n", + NewsHost); + HTInitInput(s); /* set up buffering */ + if (proxycmd[0]) { + status = NEWS_NETWRITE(s, proxycmd, strlen(proxycmd)); + if (TRACE) + fprintf(stderr, + "HTNews: Proxy command returned status '%d'.\n", + status); + } + if (((status = response(NULL)) / 100) != 2) { + char message[BIG]; + NEWS_NETCLOSE(s); + s = -1; + if (status == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + if (!(post_wanted || reply_wanted || + spost_wanted || sreply_wanted)) { + ABORT_TARGET; + } + FREE(NewsHost); + FREE(NewsHREF); + FREE(ProxyHost); + FREE(ProxyHREF); + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return(HT_NOT_LOADED); + } + if (retries < 1) + continue; + sprintf(message, + "Can't read news info. News host %.20s responded: %.200s", + NewsHost, response_text); + return HTLoadError(stream, 500, message); + } + if (status == 200) { + HTCanPost = TRUE; + } else { + HTCanPost = FALSE; + if (post_wanted || reply_wanted || + spost_wanted || sreply_wanted) { + HTAlert("Cannot POST to this host."); + FREE(NewsHREF); + if (ProxyHREF) { + StrAllocCopy(NewsHost, ProxyHost); + FREE(ProxyHost); + FREE(ProxyHREF); + } + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return(HT_NOT_LOADED); + } + } + } + } /* If needed opening */ + + if (post_wanted || reply_wanted || + spost_wanted || sreply_wanted) { + if (!HTCanPost) { + HTAlert("Cannot POST to this host."); + FREE(NewsHREF); + if (ProxyHREF) { + StrAllocCopy(NewsHost, ProxyHost); + FREE(ProxyHost); + FREE(ProxyHREF); + } + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return(HT_NOT_LOADED); + } + if (postfile == NULL) { + postfile = LYNewsPost(ListArg, (reply_wanted || sreply_wanted)); + } + if (postfile == NULL) { + HTProgress("Cancelled!"); + FREE(NewsHREF); + if (ProxyHREF) { + StrAllocCopy(NewsHost, ProxyHost); + FREE(ProxyHost); + FREE(ProxyHREF); + } + FREE(ListArg); + return(HT_NOT_LOADED); + } + } else { + /* + ** Ensure reader mode, but don't bother checking the + ** status for anything but HT_INTERRUPTED or a 480 + ** Authorization request, because if the reader mode + ** command is not needed, the server probably returned + ** a 500, which is irrelevant at this point. - FM + */ + char buffer[20]; + + sprintf(buffer, "mode reader%c%c", CR, LF); + if ((status = response(buffer)) == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + break; + } + if (status == 480) { + NNTPAuthResult auth_result = HTHandleAuthInfo(NewsHost); + if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + } + if (auth_result != NNTPAUTH_OK) { + break; + } + if ((status = response(buffer)) == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + break; + } + } + } + +Send_NNTP_command: + if ((status = response(command)) == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + break; + } + if (status < 0) { + if (retries < 1) { + continue; + } else { + break; + } + } + /* + * For some well known error responses which are expected + * to occur in normal use, break from the loop without retrying + * and without closing the connection. It is unlikely that + * these are leftovers from a timed-out connection (but we do + * some checks to see whether the response rorresponds to the + * last command), or that they will give anything else when + * automatically retried. - kw + */ + if (status == 411 && group_wanted && + !strncmp(command, "GROUP ", 6) && + !strncasecomp(response_text + 3, " No such group ", 15) && + !strcmp(response_text + 18, groupName)) { + + HTAlert(response_text); + break; + } else if (status == 430 && !group_wanted && !list_wanted && + !strncmp(command, "ARTICLE <", 9) && + !strcasecomp(response_text + 3, " No such article")) { + + HTAlert(response_text); + break; + } + if ((status/100) != 2 && + status != 340 && + status != 480) { + if (retries) { + if (list_wanted && !strncmp(command, "XGTITLE", 7)) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } + HTAlert(response_text); + } else { + _HTProgress(response_text); + } + NEWS_NETCLOSE(s); + s = -1; + /* + ** Message might be a leftover "Timeout-disconnected", + ** so try again if the retries maximum has not been + ** reached. + */ + continue; + } + + /* + ** Post or load a group, article, etc + */ + if (status == 480) { + NNTPAuthResult auth_result; + /* + * Some servers return 480 for a failed XGTITLE. - FM + */ + if (list_wanted && !strncmp(command, "XGTITLE", 7) && + strstr(response_text, "uthenticat") == NULL && + strstr(response_text, "uthor") == NULL) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } + /* + ** Handle Authorization. - FM + */ + if ((auth_result = HTHandleAuthInfo(NewsHost)) == NNTPAUTH_OK) { + goto Send_NNTP_command; + } else if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + if (retries < 1) + continue; + } + status = HT_NOT_LOADED; + } else if (post_wanted || reply_wanted || + spost_wanted || sreply_wanted) { + /* + ** Handle posting of an article. - FM + */ + if (status != 340) { + HTAlert("Cannot POST to this host."); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + } + } else { + post_article(postfile); + } + FREE(postfile); + status = HT_NOT_LOADED; + } else if (list_wanted) { + /* + ** List available newsgroups. - FM + */ + _HTProgress("Reading list of available newsgroups."); + status = read_list(ListArg); + } else if (group_wanted) { + /* + ** List articles in a news group. - FM + */ + if (last < 0) { + /* + ** We got one article number rather than a range + ** following the slash which followed the group + ** name, or the range was zero, so now that we + ** have selected that group, load ARTICLE and the + ** the number (first) as the command and go back + ** to send it and check the response. - FM + */ + sprintf(command, "%s %d%c%c", + head_wanted ? "HEAD" : "ARTICLE", + first, CR, LF); + group_wanted = FALSE; + retries = 2; + goto Send_NNTP_command; + } + _HTProgress("Reading list of articles in newsgroup."); + status = read_group(groupName, first, last); + } else { + /* + ** Get an article from a news group. - FM + */ + _HTProgress("Reading news article."); + status = read_article(); + } + if (status == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + status = HT_LOADED; + } + if (!(post_wanted || reply_wanted || + spost_wanted || sreply_wanted)) { + if (status == HT_NOT_LOADED) { + ABORT_TARGET; + } else { + FREE_TARGET; + } + } + FREE(NewsHREF); + if (ProxyHREF) { + StrAllocCopy(NewsHost, ProxyHost); + FREE(ProxyHost); + FREE(ProxyHREF); + } + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return status; + } /* Retry loop */ + + /* HTAlert("Sorry, could not load requested news."); */ + +/* NXRunAlertPanel(NULL, "Sorry, could not load `%s'.", + NULL,NULL,NULL, arg);No -- message earlier wil have covered it */ + + if (!(post_wanted || reply_wanted || + spost_wanted || sreply_wanted)) { + ABORT_TARGET; + } + FREE(NewsHREF); + if (ProxyHREF) { + StrAllocCopy(NewsHost, ProxyHost); + FREE(ProxyHost); + FREE(ProxyHREF); + } + FREE(ListArg); + if (postfile) { +#ifdef VMS + while (remove(postfile) == 0) + ; /* loop through all versions */ +#else + remove(postfile); +#endif /* VMS */ + FREE(postfile); + } + return HT_NOT_LOADED; +} + +/* +** This function clears all authorization information by +** invoking the free_HTAAGlobals() function, which normally +** is invoked at exit. It allows a browser command to do +** this at any time, for example, if the user is leaving +** the terminal for a period of time, but does not want +** to end the current session. - FM +*/ +PUBLIC void HTClearNNTPAuthInfo NOARGS +{ + /* + ** Need code to check cached documents and do + ** something to ensure that any protected + ** documents no longer can be accessed without + ** a new retrieval. - FM + */ + + /* + ** Now free all of the authorization info. - FM + */ + free_NNTP_AuthInfo(); +} + +#ifdef GLOBALDEF_IS_MACRO +#define _HTNEWS_C_1_INIT { "news", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTNews,_HTNEWS_C_1_INIT); +#define _HTNEWS_C_2_INIT { "nntp", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTNNTP,_HTNEWS_C_2_INIT); +#define _HTNEWS_C_3_INIT { "newspost", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTNewsPost,_HTNEWS_C_3_INIT); +#define _HTNEWS_C_4_INIT { "newsreply", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTNewsReply,_HTNEWS_C_4_INIT); +#define _HTNEWS_C_5_INIT { "snews", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTSNews,_HTNEWS_C_5_INIT); +#define _HTNEWS_C_6_INIT { "snewspost", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTSNewsPost,_HTNEWS_C_6_INIT); +#define _HTNEWS_C_7_INIT { "snewsreply", HTLoadNews, NULL } +GLOBALDEF (HTProtocol,HTSNewsReply,_HTNEWS_C_7_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTNews = { "news", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTNNTP = { "nntp", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTNewsPost = { "newspost", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTNewsReply = { "newsreply", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTSNews = { "snews", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTSNewsPost = { "snewspost", HTLoadNews, NULL }; +GLOBALDEF PUBLIC HTProtocol HTSNewsReply = { "snewsreply", HTLoadNews, NULL }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.h new file mode 100644 index 00000000000..bc25fc87a1b --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.h @@ -0,0 +1,46 @@ +/* Network News Transfer protocol module for the WWW library + HTNEWS + + */ +/* History: +** 26 Sep 90 Written TBL in Objective-C +** 29 Nov 91 Downgraded to C, for portable implementation. +*/ + +#ifndef HTNEWS_H +#define HTNEWS_H + +#include "HTAccess.h" +#include "HTAnchor.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF(HTProtocol, HTNews); +extern GLOBALREF(HTProtocol, HTNNTP); +extern GLOBALREF(HTProtocol, HTNewsPost); +extern GLOBALREF(HTProtocol, HTNewsReply); +extern GLOBALREF(HTProtocol, HTSNews); +extern GLOBALREF(HTProtocol, HTSNewsPost); +extern GLOBALREF(HTProtocol, HTSNewsReply); +#else +GLOBALREF HTProtocol HTNews; +GLOBALREF HTProtocol HTNNTP; +GLOBALREF HTProtocol HTNewsPost; +GLOBALREF HTProtocol HTNewsReply; +GLOBALREF HTProtocol HTSNews; +GLOBALREF HTProtocol HTSNewsPost; +GLOBALREF HTProtocol HTSNewsReply; +#endif /* GLOBALREF_IS_MACRO */ + +extern void HTSetNewsHost PARAMS(( + CONST char * value)); +extern CONST char * HTGetNewsHost NOPARAMS; +extern char * HTNewsHost; + +extern void HTClearNNTPAuthInfo NOPARAMS; + +#endif /* HTNEWS_H */ + + +/* + + tbl */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.c new file mode 100644 index 00000000000..655801fa9e3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.c @@ -0,0 +1,901 @@ +/* Parse HyperText Document Address HTParse.c +** ================================ +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTParse.h" + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define HEX_ESCAPE '%' + +struct struct_parts { + char * access; + char * host; + char * absolute; + char * relative; +/* char * search; no - treated as part of path */ + char * anchor; +}; + + +/* Strip white space off a string. HTStrip() +** ------------------------------- +** +** On exit, +** Return value points to first non-white character, or to 0 if none. +** All trailing white space is OVERWRITTEN with zero. +*/ +PUBLIC char * HTStrip ARGS1( + char *, s) +{ +#define SPACE(c) ((c == ' ') || (c == '\t') || (c == '\n')) + char * p = s; + for (p = s; *p; p++) + ; /* Find end of string */ + for (p--; p >= s; p--) { + if (SPACE(*p)) + *p = '\0'; /* Zap trailing blanks */ + else + break; + } + while (SPACE(*s)) + s++; /* Strip leading blanks */ + return s; +} + +/* Scan a filename for its consituents. scan() +** ------------------------------------ +** +** On entry, +** name points to a document name which may be incomplete. +** On exit, +** absolute or relative may be nonzero (but not both). +** host, anchor and access may be nonzero if they were specified. +** Any which are nonzero point to zero terminated strings. +*/ +PRIVATE void scan ARGS2( + char *, name, + struct struct_parts *, parts) +{ + char * after_access; + char * p; +#ifdef NOTDEFINED + int length = strlen(name); +#endif /* NOTDEFINED */ + + parts->access = NULL; + parts->host = NULL; + parts->absolute = NULL; + parts->relative = NULL; + parts->anchor = NULL; + + /* + ** Scan left-to-right for a scheme (access). + */ + after_access = name; + for (p = name; *p; p++) { + if (*p==':') { + *p = '\0'; + parts->access = name; /* Access name has been specified */ + after_access = (p + 1); + break; + } + if (*p == '/' || *p == '#' || *p == ';' || *p == '?') + break; + } + +#ifdef NOTDEFINED + for (p = (name + length-1); p >= name; p--) {} +#endif /* NOTDEFINED */ + /* + ** Scan left-to-right for a fragment (anchor). + */ + for (p = after_access; *p; p++) { + if (*p =='#') { + parts->anchor = (p + 1); + *p = '\0'; /* terminate the rest */ + break; /* leave things after first # alone - kw */ + } + } + + /* + ** Scan left-to-right for a host or absolute path. + */ + p = after_access; + if (*p == '/') { + if (p[1] == '/') { + parts->host = (p + 2); /* host has been specified */ + *p = '\0'; /* Terminate access */ + p = strchr(parts->host, '/'); /* look for end of host name if any */ + if (p != NULL) { + *p = '\0'; /* Terminate host */ + parts->absolute = (p + 1); /* Root has been found */ + } + } else { + parts->absolute = (p + 1); /* Root found but no host */ + } + } else { + parts->relative = (*after_access) ? + after_access : NULL; /* NULL for "" */ + } + + /* + ** Check schemes that commonly have unescaped hashes. + */ + if (parts->access && parts->anchor) { + if ((!parts->host && strcasecomp(parts->access, "lynxcgi")) || + !strcasecomp(parts->access, "nntp") || + !strcasecomp(parts->access, "snews") || + !strcasecomp(parts->access, "news") || + !strcasecomp(parts->access, "data")) { + /* + * Access specified but no host and not a lynxcgi URL, so the + * anchor may not really be one, e.g., news:j462#36487@foo.bar, + * or it's an nntp or snews URL, or news URL with a host. + * Restore the '#' in the address. + */ + /* but only if we have found a path component of which this will + * become part. - kw */ + if (parts->relative || parts->absolute) { + *(parts->anchor - 1) = '#'; + parts->anchor = NULL; + } + } + } + +#ifdef NOT_DEFINED /* search is just treated as part of path */ + { + char *p = (relative ? relative : absolute); + if (p != NULL) { + char *q = strchr(p, '?'); /* Any search string? */ + if (q != NULL) { + *q = '\0'; /* If so, chop that off. */ + parts->search = (q + 1); + } + } + } +#endif /* NOT_DEFINED */ +} /*scan */ + + +/* Parse a Name relative to another name. HTParse() +** -------------------------------------- +** +** This returns those parts of a name which are given (and requested) +** substituting bits from the related name where necessary. +** +** On entry, +** aName A filename given +** relatedName A name relative to which aName is to be parsed +** wanted A mask for the bits which are wanted. +** +** On exit, +** returns A pointer to a calloc'd string which MUST BE FREED +*/ +PUBLIC char * HTParse ARGS3( + CONST char *, aName, + CONST char *, relatedName, + int, wanted) +{ + char * result = NULL; + char * return_value = NULL; + int len; + char * name = NULL; + char * rel = NULL; + char * p; + char * acc_method; + struct struct_parts given, related; + + if (TRACE) + fprintf(stderr, + "HTParse: aName:%s relatedName:%s\n", aName, relatedName); + + /* + ** Allocate the output string. + */ + len = strlen(aName) + strlen(relatedName) + 10; + result = (char *)calloc(1, len); /* Lots of space: more than enough */ + if (result == NULL) { + outofmem(__FILE__, "HTParse"); + } + + /* + ** Make working copies of the input strings to cut up. + */ + StrAllocCopy(name, aName); + StrAllocCopy(rel, relatedName); + + /* + ** Cut up the strings into URL fields. + */ + scan(name, &given); + scan(rel, &related); + + /* + ** Handle the scheme (access) field. + */ + if (given.access && given.host && !given.relative && !given.absolute) { + if (!strcmp(given.access, "http") || + !strcmp(given.access, "https") || + !strcmp(given.access, "ftp")) + /* + ** Assume root. + */ + given.absolute = ""; + } + acc_method = given.access ? given.access : related.access; + if (wanted & PARSE_ACCESS) { + if (acc_method) { + strcat(result, acc_method); + if (wanted & PARSE_PUNCTUATION) + strcat(result, ":"); + } + } + + /* + ** If different schemes, inherit nothing. + ** + ** We'll try complying with RFC 1808 and + ** the Fielding draft, and inherit nothing + ** if both schemes are given, rather than + ** only when they differ, except for + ** file URLs - FM + ** + ** After trying it for a while, it's still + ** premature, IHMO, to go along with it, so + ** this is back to inheriting for identical + ** schemes whether or not they are "file". + ** If you want to try it again yourself, + ** uncomment the strncasecomp() below. - FM + */ + if ((given.access && related.access) && + (/* strcasecomp(given.access, "file") || */ + strcmp(given.access, related.access))) { + related.host = NULL; + related.absolute = NULL; + related.relative = NULL; + related.anchor = NULL; + } + + /* + ** Handle the host field. + */ + if (wanted & PARSE_HOST) + if (given.host || related.host) { + char *tail = result + strlen(result); + if (wanted & PARSE_PUNCTUATION) + strcat(result, "//"); + strcat(result, given.host ? given.host : related.host); +#define CLEAN_URLS +#ifdef CLEAN_URLS + /* + ** Ignore default port numbers, and trailing dots on FQDNs, + ** which will only cause identical addresses to look different. + */ + { + char *p2, *h; + if ((p2 = strchr(result, '@')) != NULL) + tail = (p2 + 1); + p2 = strchr(tail, ':'); + if (p2 != NULL && !isdigit((unsigned char)p2[1])) + /* + ** Colon not followed by a port number. + */ + *p2 = '\0'; + if (p2 != NULL && *p2 != '\0' && acc_method != NULL) { + /* + ** Port specified. + */ + if ((!strcmp(acc_method, "http" ) && !strcmp(p2, ":80" )) || + (!strcmp(acc_method, "https" ) && !strcmp(p2, ":443")) || + (!strcmp(acc_method, "gopher" ) && !strcmp(p2, ":70" )) || + (!strcmp(acc_method, "ftp" ) && !strcmp(p2, ":21" )) || + (!strcmp(acc_method, "wais" ) && !strcmp(p2, ":210")) || + (!strcmp(acc_method, "nntp" ) && !strcmp(p2, ":119")) || + (!strcmp(acc_method, "news" ) && !strcmp(p2, ":119")) || + (!strcmp(acc_method, "newspost" ) && !strcmp(p2, ":119")) || + (!strcmp(acc_method, "newsreply" ) && !strcmp(p2, ":119")) || + (!strcmp(acc_method, "snews" ) && !strcmp(p2, ":563")) || + (!strcmp(acc_method, "snewspost" ) && !strcmp(p2, ":563")) || + (!strcmp(acc_method, "snewsreply") && !strcmp(p2, ":563")) || + (!strcmp(acc_method, "finger" ) && !strcmp(p2, ":79" )) || + (!strcmp(acc_method, "telnet" ) && !strcmp(p2, ":23" )) || + (!strcmp(acc_method, "tn3270" ) && !strcmp(p2, ":23" )) || + (!strcmp(acc_method, "rlogin" ) && !strcmp(p2, ":513")) || + (!strcmp(acc_method, "cso" ) && !strcmp(p2, ":105"))) + *p2 = '\0'; /* It is the default: ignore it */ + } + if (p2 == NULL) { + int len2 = strlen(tail); + + if (len2 > 0) { + h = tail + len2 - 1; /* last char of hostname */ + if (*h == '.') + *h = '\0'; /* chop final . */ + } + } else { + h = p2; + h--; /* End of hostname */ + if (*h == '.') { + /* + ** Slide p2 over h. + */ + while (*p2 != '\0') + *h++ = *p2++; + *h = '\0'; /* terminate */ + } + } + } +#endif /* CLEAN_URLS */ + } + + /* + ** If different hosts, inherit no path. + */ + if (given.host && related.host) + if (strcmp(given.host, related.host) != 0) { + related.absolute = NULL; + related.relative = NULL; + related.anchor = NULL; + } + + /* + ** Handle the path. + */ + if (wanted & PARSE_PATH) { + if (acc_method && !given.absolute && given.relative) { + if (!strcasecomp(acc_method, "nntp") || + !strcasecomp(acc_method, "snews") || + (!strcasecomp(acc_method, "news") && + !strncasecomp(result, "news://", 7))) { + /* + * Treat all given nntp or snews paths, + * or given paths for news URLs with a host, + * as absolute. + */ + given.absolute = given.relative; + given.relative = NULL; + } + } + if (given.absolute) { /* All is given */ + if (wanted & PARSE_PUNCTUATION) + strcat(result, "/"); + strcat(result, given.absolute); + if (TRACE) + fprintf(stderr, "1\n"); + } else if (related.absolute) { /* Adopt path not name */ + strcat(result, "/"); + strcat(result, related.absolute); + if (given.relative) { + p = strchr(result, '?'); /* Search part? */ + if (p == NULL) + p = (result + strlen(result) - 1); + for (; *p != '/'; p--) + ; /* last / */ + p[1] = '\0'; /* Remove filename */ + strcat(result, given.relative); /* Add given one */ + HTSimplify (result); + } + if (TRACE) + fprintf(stderr, "2\n"); + } else if (given.relative) { + strcat(result, given.relative); /* what we've got */ + if (TRACE) + fprintf(stderr, "3\n"); + } else if (related.relative) { + strcat(result, related.relative); + if (TRACE) + fprintf(stderr, "4\n"); + } else { /* No inheritance */ + if (strncasecomp(aName, "lynxcgi:", 8) && + strncasecomp(aName, "lynxexec:", 9) && + strncasecomp(aName, "lynxprog:", 9)) { + strcat(result, "/"); + } + if (!strcmp(result, "news:/")) + result[5] = '*'; + if (TRACE) + fprintf(stderr, "5\n"); + } + } + + /* + ** Handle the fragment (anchor). + */ + if (wanted & PARSE_ANCHOR) + if ((given.anchor && *given.anchor) || + (!given.anchor && related.anchor)) { + if (wanted & PARSE_PUNCTUATION) + strcat(result, "#"); + strcat(result, (given.anchor) ? + given.anchor : related.anchor); + } + if (TRACE) + fprintf(stderr, "HTParse: result:%s\n", result); + FREE(rel); + FREE(name); + + StrAllocCopy(return_value, result); + FREE(result); + + return return_value; /* exactly the right length */ +} + +/* Simplify a filename. HTSimplify() +** -------------------- +** +** A unix-style file is allowed to contain the seqeunce xxx/../ which may +** be replaced by "" , and the seqeunce "/./" which may be replaced by "/". +** Simplification helps us recognize duplicate filenames. +** +** Thus, /etc/junk/../fred becomes /etc/fred +** /etc/junk/./fred becomes /etc/junk/fred +** +** but we should NOT change +** http://fred.xxx.edu/../.. +** +** or ../../albert.html +*/ +PUBLIC void HTSimplify ARGS1( + char *, filename) +{ + char *p; + char *q, *q1; + + if (filename == NULL) + return; + + if (!(filename[0] && filename[1]) || + filename[0] == '?' || filename[1] == '?' || filename[2] == '?') + return; + + if (strchr(filename, '/') != NULL) { + for (p = (filename + 2); *p; p++) { + if (*p == '?') { + /* + ** We're still treating a ?searchpart as part of + ** the path in HTParse() and scan(), but if we + ** encounter a '?' here, assume it's the delimiter + ** and break. We also could check for a parameter + ** delimiter (';') here, but the current Fielding + ** draft (wisely or ill-advisedly :) says that it + ** should be ignored and collapsing be allowed in + ** it's value). The only defined parameter at + ** present is ;type=[A, I, or D] for ftp URLs, so + ** if there's a "/..", "/../", "/./", or terminal + ** '.' following the ';', it must be due to the + ** ';' being an unescaped path character and not + ** actually a parameter delimiter. - FM + */ + break; + } + if (*p == '/') { + if ((p[1] == '.') && (p[2] == '.') && + (p[3] == '/' || p[3] == '?' || p[3] == '\0')) { + /* + ** Handle "../", "..?" or "..". + */ + for (q = (p - 1); (q >= filename) && (*q != '/'); q--) + /* + ** Back up to previous slash or beginning of string. + */ + ; + if ((q[0] == '/') && + (strncmp(q, "/../", 4) && + strncmp(q, "/..?", 4)) && + !((q - 1) > filename && q[-1] == '/')) { + /* + ** Not at beginning of string or in a + ** host field, so remove the "/xxx/..". + */ + q1 = (p + 3); + p = q; + while (*q1 != '\0') + *p++ = *q1++; + *p = '\0'; /* terminate */ +#ifdef NOTDEFINED + /* + ** Make sure filename has at least one slash. + */ + if (*filename == '\0') { + *filename = '/'; + *(filename + 1) = '\0'; + } +#endif /* NOTDEFINED */ + /* + ** Start again with previous slash. + */ + p = (q - 1); + } + } else if (p[1] == '.' && p[2] == '/') { + /* + ** Handle "./" by removing both characters. + */ + q = p; + q1 = (p + 2); + while (*q1 != '\0') + *q++ = *q1++; + *q = '\0'; /* terminate */ + p--; + } else if (p[1] == '.' && p[2] == '?') { + /* + ** Handle ".?" by removing the dot. + */ + q = (p + 1); + q1 = (p + 2); + while (*q1 != '\0') + *q++ = *q1++; + *q = '\0'; /* terminate */ + p--; + } else if (p[1] == '.' && p[2] == '\0') { + /* + ** Handle terminal "." by removing the character. + */ + p[1] = '\0'; + } + } + } + if (p >= filename + 2 && *p == '?' && *(p-1) == '.') { + if (*(p-2) == '/') { + /* + ** Handle "/.?" by removing the dot. + */ + q = p - 1; + q1 = p; + while (*q1 != '\0') + *q++ = *q1++; + *q = '\0'; + } else if (*(p-2) == '.' && + p >= filename + 4 && *(p-3) == '/' && + (*(p-4) != '/' || + (p > filename + 4 && *(p-5) != ':'))) { + /* + ** Handle "xxx/..?" + */ + for (q = (p - 4); (q > filename) && (*q != '/'); q--) + /* + ** Back up to previous slash or beginning of string. + */ + ; + if (*q == '/') { + if (q > filename && *(q-1) == '/' && + !(q > filename + 1 && *(q-1) != ':')) + return; + q++; + } + if (strncmp(q, "../", 3) && strncmp(q, "./", 2)) { + /* + ** Not after "//" at beginning of string or + ** after "://", and xxx is not ".." or ".", + ** so remove the "xxx/..". + */ + q1 = p; + p = q; + while (*q1 != '\0') + *p++ = *q1++; + *p = '\0'; /* terminate */ + } + } + } + } +} + +/* Make Relative Name. HTRelative() +** ------------------- +** +** This function creates and returns a string which gives an expression of +** one address as related to another. Where there is no relation, an absolute +** address is retured. +** +** On entry, +** Both names must be absolute, fully qualified names of nodes +** (no anchor bits) +** +** On exit, +** The return result points to a newly allocated name which, if +** parsed by HTParse relative to relatedName, will yield aName. +** The caller is responsible for freeing the resulting name later. +** +*/ +PUBLIC char * HTRelative ARGS2( + CONST char *, aName, + CONST char *, relatedName) +{ + char * result = NULL; + CONST char *p = aName; + CONST char *q = relatedName; + CONST char * after_access = NULL; + CONST char * path = NULL; + CONST char * last_slash = NULL; + int slashes = 0; + + for (; *p; p++, q++) { /* Find extent of match */ + if (*p != *q) + break; + if (*p == ':') + after_access = p+1; + if (*p == '/') { + last_slash = p; + slashes++; + if (slashes == 3) + path=p; + } + } + + /* q, p point to the first non-matching character or zero */ + + if (!after_access) { /* Different access */ + StrAllocCopy(result, aName); + } else if (slashes < 3){ /* Different nodes */ + StrAllocCopy(result, after_access); + } else if (slashes == 3){ /* Same node, different path */ + StrAllocCopy(result, path); + } else { /* Some path in common */ + int levels = 0; + for (; *q && (*q != '#'); q++) + if (*q == '/') + levels++; + result = (char *)calloc(1, (3*levels + strlen(last_slash) + 1)); + if (result == NULL) + outofmem(__FILE__, "HTRelative"); + result[0] = '\0'; + for (; levels; levels--) + strcat(result, "../"); + strcat(result, last_slash+1); + } + if (TRACE) + fprintf(stderr, "HT: `%s' expressed relative to\n `%s' is\n `%s'.", + aName, relatedName, result); + return result; +} + +/* Escape undesirable characters using % HTEscape() +** ------------------------------------- +** +** This function takes a pointer to a string in which +** some characters may be unacceptable unescaped. +** It returns a string which has these characters +** represented by a '%' character followed by two hex digits. +** +** Unlike HTUnEscape(), this routine returns a calloced string. +*/ +PRIVATE CONST unsigned char isAcceptable[96] = + +/* Bit 0 xalpha -- see HTFile.h +** Bit 1 xpalpha -- as xalpha but with plus. +** Bit 3 ... path -- as xpalphas but with / +*/ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,7,6,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ + 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 }; /* 7X pqrstuvwxyz{|}~ DEL */ + +PRIVATE char *hex = "0123456789ABCDEF"; +#define ACCEPTABLE(a) ( a>=32 && a<128 && ((isAcceptable[a-32]) & mask)) + +PUBLIC char * HTEscape ARGS2( + CONST char *, str, + unsigned char, mask) +{ + CONST char * p; + char * q; + char * result; + int unacceptable = 0; + for (p = str; *p; p++) + if (!ACCEPTABLE((unsigned char)TOASCII(*p))) + unacceptable++; + result = (char *)calloc(1, (p-str + unacceptable + unacceptable + 1)); + if (result == NULL) + outofmem(__FILE__, "HTEscape"); + for (q = result, p = str; *p; p++) { + unsigned char a = TOASCII(*p); + if (!ACCEPTABLE(a)) { + *q++ = HEX_ESCAPE; /* Means hex commming */ + *q++ = hex[a >> 4]; + *q++ = hex[a & 15]; + } + else *q++ = *p; + } + *q++ = '\0'; /* Terminate */ + return result; +} + +/* Escape undesirable characters using % but space to +. HTEscapeSP() +** ----------------------------------------------------- +** +** This function takes a pointer to a string in which +** some characters may be unacceptable unescaped. +** It returns a string which has these characters +** represented by a '%' character followed by two hex digits, +** except that spaces are converted to '+' instead of %2B. +** +** Unlike HTUnEscape(), this routine returns a calloced string. +*/ +PUBLIC char * HTEscapeSP ARGS2( + CONST char *, str, + unsigned char, mask) +{ + CONST char * p; + char * q; + char * result; + int unacceptable = 0; + for (p = str; *p; p++) + if (!(*p == ' ' || ACCEPTABLE((unsigned char)TOASCII(*p)))) + unacceptable++; + result = (char *)calloc(1, (p-str + unacceptable + unacceptable + 1)); + if (result == NULL) + outofmem(__FILE__, "HTEscape"); + for (q = result, p = str; *p; p++) { + unsigned char a = TOASCII(*p); + if (a == 32) { + *q++ = '+'; + } else if (!ACCEPTABLE(a)) { + *q++ = HEX_ESCAPE; /* Means hex commming */ + *q++ = hex[a >> 4]; + *q++ = hex[a & 15]; + } else { + *q++ = *p; + } + } + *q++ = '\0'; /* Terminate */ + return result; +} + +/* Decode %xx escaped characters. HTUnEscape() +** ------------------------------ +** +** This function takes a pointer to a string in which some +** characters may have been encoded in %xy form, where xy is +** the acsii hex code for character 16x+y. +** The string is converted in place, as it will never grow. +*/ +PRIVATE char from_hex ARGS1( + char, c) +{ + return c >= '0' && c <= '9' ? c - '0' + : c >= 'A' && c <= 'F'? c - 'A' + 10 + : c - 'a' + 10; /* accept small letters just in case */ +} + +PUBLIC char * HTUnEscape ARGS1( + char *, str) +{ + char * p = str; + char * q = str; + + if (!(p && *p)) + return str; + + while (*p != '\0') { + if (*p == HEX_ESCAPE && + /* + * Tests shouldn't be needed, but better safe than sorry. + */ + p[1] && p[2] && + isxdigit((unsigned char)p[1]) && + isxdigit((unsigned char)p[2])) { + p++; + if (*p) + *q = from_hex(*p++) * 16; + if (*p) + *q = FROMASCII(*q + from_hex(*p++)); + q++; + } else { + *q++ = *p++; + } + } + + *q++ = '\0'; + return str; + +} /* HTUnEscape */ + +/* Decode some %xx escaped characters. HTUnEscapeSome() +** ----------------------------------- Klaus Weide +** (kweide@tezcat.com) +** This function takes a pointer to a string in which some +** characters may have been encoded in %xy form, where xy is +** the acsii hex code for character 16x+y, and a pointer to +** a second string containing one or more characters which +** should be unescaped if escaped in the first string. +** The first string is converted in place, as it will never grow. +*/ +PUBLIC char * HTUnEscapeSome ARGS2( + char *, str, + CONST char *, do_trans) +{ + char * p = str; + char * q = str; + char testcode; + + if (p == NULL || *p == '\0' || do_trans == NULL || *do_trans == '\0') + return str; + + while (*p != '\0') { + if (*p == HEX_ESCAPE && + p[1] && p[2] && /* tests shouldn't be needed, but.. */ + isxdigit((unsigned char)p[1]) && + isxdigit((unsigned char)p[2]) && + (testcode = from_hex(p[1])*16 + from_hex(p[2])) && /* %00 no good*/ + strchr(do_trans, testcode)) { /* it's one of the ones we want */ + *q++ = FROMASCII(testcode); + p += 3; + } else { + *q++ = *p++; + } + } + + *q++ = '\0'; + return str; + +} /* HTUnEscapeSome */ + +PRIVATE CONST unsigned char crfc[96] = + +/* Bit 0 xalpha -- need "quoting" +** Bit 1 xpalpha -- need \escape if quoted +*/ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 1,0,3,0,0,0,0,0,1,1,0,0,1,0,1,0, /* 2x !"#$%&'()*+,-./ */ + 0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0, /* 3x 0123456789:;<=>? */ + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */ + 0,0,0,0,0,0,0,0,0,0,0,1,2,1,0,0, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3 }; /* 7X pqrstuvwxyz{|}~ DEL */ + +/* +** Turn a string which is not a RFC 822 token into a quoted-string. - KW +*/ +PUBLIC void HTMake822Word ARGS1( + char **, str) +{ + CONST char * p; + char * q; + char * result; + unsigned char a; + int added = 0; + if (!(*str) || !(**str)) { + StrAllocCopy(*str, "\"\""); + return; + } + for (p = *str; *p; p++) { + a = *p; + if (a < 32 || a >= 128 || + ((crfc[a-32]) & 1)) { + if (!added) + added = 2; + if (a >= 160 || a == '\t') + continue; + if (a == '\r' || a == '\n') + added += 2; + else if ((a & 127) < 32 || ((crfc[a-32]) & 2)) + added++; + } + } + if (!added) + return; + result = (char *)calloc(1, (p-(*str) + added + 1)); + if (result == NULL) + outofmem(__FILE__, "HTMake822Word"); + result[0] = '"'; + for (q = result + 1, p = *str; *p; p++) { + a = TOASCII(*p); + if ((a != '\t') && ((a & 127) < 32 || + ( a < 128 && ((crfc[a-32]) & 2)))) + *q++ = '\\'; + *q++ = *p; + if (a == '\n' || (a == '\r' && (TOASCII(*(p+1)) != '\n'))) + *q++ = ' '; + } + *q++ = '"'; + *q++ = '\0'; /* Terminate */ + FREE(*str); + *str = result; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.h new file mode 100644 index 00000000000..2f77f0796cf --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.h @@ -0,0 +1,167 @@ +/* HTParse: URL parsing in the WWW Library +** HTPARSE +** +** This module of the WWW library contains code to parse URLs and various +** related things. +** Implemented by HTParse.c . +*/ +#ifndef HTPARSE_H +#define HTPARSE_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +/* +** The following are flag bits which may be ORed together to form +** a number to give the 'wanted' argument to HTParse. +*/ +#define PARSE_ACCESS 16 +#define PARSE_HOST 8 +#define PARSE_PATH 4 +#define PARSE_ANCHOR 2 +#define PARSE_PUNCTUATION 1 +#define PARSE_ALL 31 + +/* +** The following are valid mask values. The terms are the BNF names +** in the URL document. +*/ +#define URL_XALPHAS (unsigned char) 1 +#define URL_XPALPHAS (unsigned char) 2 +#define URL_PATH (unsigned char) 4 + + +/* Strip white space off a string. HTStrip() +** ------------------------------- +** +** On exit, +** Return value points to first non-white character, or to 0 if none. +** All trailing white space is OVERWRITTEN with zero. +*/ +extern char * HTStrip PARAMS(( + char * s)); + +/* Parse a Name relative to another name. HTParse() +** -------------------------------------- +** +** This returns those parts of a name which are given (and requested) +** substituting bits from the related name where necessary. +** +** On entry, +** aName A filename given +** relatedName A name relative to which aName is to be parsed +** wanted A mask for the bits which are wanted. +** +** On exit, +** returns A pointer to a malloc'd string which MUST BE FREED +*/ +extern char * HTParse PARAMS(( + CONST char * aName, + CONST char * relatedName, + int wanted)); + +/* Simplify a filename. HTSimplify() +** -------------------- +** +** A unix-style file is allowed to contain the seqeunce xxx/../ which may +** be replaced by "" , and the seqeunce "/./" which may be replaced by "/". +** Simplification helps us recognize duplicate filenames. +** +** Thus, /etc/junk/../fred becomes /etc/fred +** /etc/junk/./fred becomes /etc/junk/fred +** +** but we should NOT change +** http://fred.xxx.edu/../.. +** +** or ../../albert.html +*/ +extern void HTSimplify PARAMS(( + char * filename)); + +/* Make Relative Name. HTRelative() +** ------------------- +** +** This function creates and returns a string which gives an expression of +** one address as related to another. Where there is no relation, an absolute +** address is retured. +** +** On entry, +** Both names must be absolute, fully qualified names of nodes +** (no anchor bits) +** +** On exit, +** The return result points to a newly allocated name which, if +** parsed by HTParse relative to relatedName, will yield aName. +** The caller is responsible for freeing the resulting name later. +** +*/ +extern char * HTRelative PARAMS(( + CONST char * aName, + CONST char * relatedName)); + +/* Escape undesirable characters using % HTEscape() +** ------------------------------------- +** +** This function takes a pointer to a string in which +** some characters may be unacceptable unescaped. +** It returns a string which has these characters +** represented by a '%' character followed by two hex digits. +** +** Unlike HTUnEscape(), this routine returns a malloced string. +*/ +extern char * HTEscape PARAMS(( + CONST char * str, + unsigned char mask)); + +/* Escape undesirable characters using % but space to +. HTEscapeSP() +** ----------------------------------------------------- +** +** This function takes a pointer to a string in which +** some characters may be unacceptable unescaped. +** It returns a string which has these characters +** represented by a '%' character followed by two hex digits, +** except that spaces are converted to '+' instead of %2B. +** +** Unlike HTUnEscape(), this routine returns a malloced string. +*/ +extern char * HTEscapeSP PARAMS(( + CONST char * str, + unsigned char mask)); + +/* Decode %xx escaped characters. HTUnEscape() +** ------------------------------ +** +** This function takes a pointer to a string in which some +** characters may have been encoded in %xy form, where xy is +** the acsii hex code for character 16x+y. +** The string is converted in place, as it will never grow. +*/ +extern char * HTUnEscape PARAMS(( + char * str)); + +/* Decode some %xx escaped characters. HTUnEscapeSome() +** ----------------------------------- Klaus Weide +** (kweide@tezcat.com) +** This function takes a pointer to a string in which some +** characters may have been encoded in %xy form, where xy is +** the acsii hex code for character 16x+y, and a pointer to +** a second string containing one or more characters which +** should be unescaped if escaped in the first string. +** The first string is converted in place, as it will never grow. +*/ +extern char * HTUnEscapeSome PARAMS(( + char * str, + CONST char * do_trans)); + +/* +** Turn a string which is not a RFC 822 token into a quoted-string. - KW +*/ +extern void HTMake822Word PARAMS(( + char ** str)); + +#endif /* HTPARSE_H */ + +/* + end of HTParse + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.c new file mode 100644 index 00000000000..ada39ee5005 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.c @@ -0,0 +1,301 @@ + +/* MODULE HTPasswd.c +** PASSWORD FILE ROUTINES +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 7 Nov 93 MD free for crypt taken out (static data returned) +** +** +** BUGS: +** +** +*/ + + +#include "HTUtils.h" +#include "tcp.h" /* FROMASCII() */ +#include <string.h> +#include "HTAAUtil.h" /* Common parts of AA */ +#include "HTAAFile.h" /* File routines */ +#include "HTAAServ.h" /* Server routines */ +#include "HTPasswd.h" /* Implemented here */ + +#include "LYLeaks.h" + +extern char *crypt(); + + +PRIVATE char salt_chars [65] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; + + +/* PRIVATE next_rec() +** GO TO THE BEGINNING OF THE NEXT RECORD +** Otherwise like HTAAFile_nextRec() but +** does not handle continuation lines +** (because password file has none). +** ON ENTRY: +** fp is the password file from which records are read from. +** +** ON EXIT: +** returns nothing. File read pointer is located at the beginning +** of the next record. +*/ +PRIVATE void next_rec ARGS1(FILE *, fp) +{ + int ch = getc(fp); + + while (ch != EOF && ch != CR && ch != LF) + ch = getc(fp); /* Skip until end-of-line */ + + while (ch != EOF && + (ch == CR || ch == LF)) /*Skip carriage returns and linefeeds*/ + ch = getc(fp); + + if (ch != EOF) + ungetc(ch, fp); +} + + +/* PUBLIC HTAA_encryptPasswd() +** ENCRYPT PASSWORD TO THE FORM THAT IT IS SAVED +** IN THE PASSWORD FILE. +** ON ENTRY: +** password is a string of arbitrary lenght. +** +** ON EXIT: +** returns password in one-way encrypted form. +** +** NOTE: +** Uses currently the C library function crypt(), which +** only accepts at most 8 characters long strings and produces +** always 13 characters long strings. This function is +** called repeatedly so that longer strings can be encrypted. +** This is of course not as safe as encrypting the entire +** string at once, but then again, we are not that paranoid +** about the security inside the machine. +** +*/ +PUBLIC char *HTAA_encryptPasswd ARGS1(CONST char *, password) +{ + char salt[3]; + char chunk[9]; + char *result; + char *tmp; + CONST char *cur = password; + int len = strlen(password); + int randum = (int)theTime; /* This is random enough */ + + if (!(result = (char*)malloc(13*((strlen(password)+7)/8) + 1))) + outofmem(__FILE__, "HTAA_encryptPasswd"); + + *result = (char)0; + while (len > 0) { + salt[0] = salt_chars[randum%64]; + salt[1] = salt_chars[(randum/64)%64]; + salt[2] = (char)0; + + strncpy(chunk, cur, 8); + chunk[8] = (char)0; + + tmp = crypt((char*)password, salt); /*crypt() doesn't change its args*/ + strcat(result, tmp); + + cur += 8; + len -= 8; + } /* while */ + + return result; +} + + + +/* PUBLIC HTAA_passwdMatch() +** VERIFY THE CORRECTNESS OF A GIVEN PASSWORD +** AGAINST A ONE-WAY ENCRYPTED FORM OF PASSWORD. +** ON ENTRY: +** password is cleartext password. +** encrypted is one-way encrypted password, as returned +** by function HTAA_encryptPasswd(). +** This is typically read from the password +** file. +** +** ON EXIT: +** returns YES, if password matches the encrypted one. +** NO, if not, or if either parameter is NULL. +** FIX: +** Only the length of original encrypted password is +** checked -- longer given passwords are accepted if +** common length is correct (but not shorter). +** This is to allow interoperation of servers and clients +** who have a hard-coded limit of 8 to password. +*/ +PUBLIC BOOL HTAA_passwdMatch ARGS2(CONST char *, password, + CONST char *, encrypted) +{ + char *result; + int len; + int status; + + if (!password || !encrypted) + return NO; + + len = 13*((strlen(password)+7)/8); + if (len < strlen(encrypted)) + return NO; + + if (!(result = (char*)malloc(len + 1))) + outofmem(__FILE__, "HTAA_encryptPasswd"); + + *result = (char)0; + while (len > 0) { + char salt[3]; + char chunk[9]; + CONST char *cur1 = password; + CONST char *cur2 = encrypted; + char *tmp; + + salt[0] = *cur2; + salt[1] = *(cur2+1); + salt[2] = (char)0; + + strncpy(chunk, cur1, 8); + chunk[8] = (char)0; + + tmp = crypt((char*)password, salt); + strcat(result, tmp); + + cur1 += 8; + cur2 += 13; + len -= 13; + } /* while */ + + status = strncmp(result, encrypted, strlen(encrypted)); + + if (TRACE) + fprintf(stderr, + "%s `%s' (encrypted: `%s') with: `%s' => %s\n", + "HTAA_passwdMatch: Matching password:", + password, result, encrypted, + (status==0 ? "OK" : "INCORRECT")); + + FREE(result); + + if (status==0) + return YES; + else + return NO; +} + + +/* PUBLIC HTAAFile_readPasswdRec() +** READ A RECORD FROM THE PASSWORD FILE +** ON ENTRY: +** fp open password file +** out_username buffer to put the read username, must be at +** least MAX_USERNAME_LEN+1 characters long. +** out_passwd buffer to put the read password, must be at +** least MAX_PASSWORD_LEN+1 characters long. +** ON EXIT: +** returns EOF on end of file, +** otherwise the number of read fields +** (i.e. in a correct case returns 2). +** out_username contains the null-terminated read username. +** out_password contains the null-terminated read password. +** +** FORMAT OF PASSWORD FILE: +** username:password:maybe real name or other stuff +** (may include even colons) +** +** There may be whitespace (blanks or tabs) in the beginning and +** the end of each field. They are ignored. +*/ +PUBLIC int HTAAFile_readPasswdRec ARGS3(FILE *, fp, + char *, out_username, + char *, out_password) +{ + int terminator; + + terminator = HTAAFile_readField(fp, out_username, MAX_USERNAME_LEN); + + if (terminator == EOF) { /* End of file */ + return EOF; + } + else if (terminator == CR || terminator == LF) { /* End of line */ + next_rec(fp); + return 1; + } + else { + HTAAFile_readField(fp, out_password, MAX_PASSWORD_LEN); + next_rec(fp); + return 2; + } +} + + + +/* PUBLIC HTAA_checkPassword() +** CHECK A USERNAME-PASSWORD PAIR +** ON ENTRY: +** username is a null-terminated string containing +** the client's username. +** password is a null-terminated string containing +** the client's corresponding password. +** filename is a null-terminated absolute filename +** for password file. +** If NULL or empty, the value of +** PASSWD_FILE is used. +** ON EXIT: +** returns YES, if the username-password pair was correct. +** NO, otherwise; also, if open fails. +*/ +PUBLIC BOOL HTAA_checkPassword ARGS3(CONST char *, username, + CONST char *, password, + CONST char *, filename) +{ + FILE *fp = NULL; + char user[MAX_USERNAME_LEN+1]; + char pw[MAX_PASSWORD_LEN+1]; + int status; + + if (filename && *filename) fp = fopen(filename,"r"); + else fp = fopen(PASSWD_FILE,"r"); + + if (!fp) { + if (TRACE) fprintf(stderr, "%s `%s'\n", + "HTAA_checkPassword: Unable to open password file", + (filename && *filename ? filename : PASSWD_FILE)); + return NO; + } + do { + if (2 == (status = HTAAFile_readPasswdRec(fp,user,pw))) { + if (TRACE) + fprintf(stderr, + "HTAAFile_validateUser: %s \"%s\" %s \"%s:%s\"\n", + "Matching username:", username, + "against passwd record:", user, pw); + if (username && user && !strcmp(username,user)) { + /* User's record found */ + if (*pw != '\0') { /* So password is required for this user */ + if (!password || + !HTAA_passwdMatch(password,pw)) /* Check the password */ + status = EOF; /* If wrong, indicate it with EOF */ + } + break; /* exit loop */ + } /* if username found */ + } /* if record is ok */ + } while (status != EOF); + + fclose(fp); + + if (TRACE) fprintf(stderr, "HTAAFile_checkPassword: (%s,%s) %scorrect\n", + username, password, ((status != EOF) ? "" : "in")); + + if (status == EOF) return NO; /* We traversed to the end without luck */ + else return YES; /* The user was found */ +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.h new file mode 100644 index 00000000000..0c3b3eb680f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.h @@ -0,0 +1,129 @@ +/* PASSWORD FILE ROUTINES + + */ + +#ifndef HTPASSWD_H +#define HTPASSWD_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTList.h" + +#ifdef SHORT_NAMES +#define HTAAenPw HTAA_encryptPasswd +#define HTAApwMa HTAA_passwdMatch +#define HTAAFrPR HTAAFile_readPasswdRec +#define HTAAchPw HTAA_checkPasswd +#endif /* SHORT_NAMES */ + +/* + +User Authentication + + HTAA_checkPassword(username,password,passwdfile)opens the password file, and checks if + the username-password pair is correct. Return value is YES, if and only if they are + correct. Otherwise, and also if the open fails, returns NO. + + If the given password file name is NULL or an empty string, the default password file + name is used (macro PASSWD_FILE). + + */ + +/* PUBLIC HTAA_checkPassword() +** VALIDATE A USERNAME-PASSWORD PAIR +** ON ENTRY: +** username is a null-terminated string containing +** the client's username. +** password is a null-terminated string containing +** the client's corresponding password. +** filename is a null-terminated absolute filename +** for password file. +** If NULL or empty, the value of +** PASSWD_FILE is used. +** ON EXIT: +** returns YES, if the username-password pair was correct. +** NO, otherwise; also, if open fails. +*/ +PUBLIC BOOL HTAA_checkPassword PARAMS((CONST char * username, + CONST char * password, + CONST char * filename)); +/* + +Password File Maintenance Routines + + */ + +/* PUBLIC HTAA_encryptPasswd() +** ENCRYPT PASSWORD TO THE FORM THAT IT IS SAVED +** IN THE PASSWORD FILE. +** ON ENTRY: +** password is a string of arbitrary lenght. +** +** ON EXIT: +** returns password in one-way encrypted form. +** +** NOTE: +** Uses currently the C library function crypt(), which +** only accepts at most 8 characters long strings and produces +** always 13 characters long strings. This function is +** called repeatedly so that longer strings can be encrypted. +** This is of course not as safe as encrypting the entire +** string at once, but then again, we are not that paranoid +** about the security inside the machine. +** +*/ +PUBLIC char *HTAA_encryptPasswd PARAMS((CONST char * password)); + + +/* PUBLIC HTAA_passwdMatch() +** VERIFY THE CORRECTNESS OF A GIVEN PASSWORD +** AGAINST A ONE-WAY ENCRYPTED FORM OF PASSWORD. +** ON ENTRY: +** password is cleartext password. +** encrypted is one-way encrypted password, as returned +** by function HTAA_encryptPasswd(). +** This is typically read from the password +** file. +** +** ON EXIT: +** returns YES, if password matches the encrypted one. +** NO, if not, or if either parameter is NULL. +*/ +PUBLIC BOOL HTAA_passwdMatch PARAMS((CONST char * password, + CONST char * encrypted)); + + +/* PUBLIC HTAAFile_readPasswdRec() +** READ A RECORD FROM THE PASSWORD FILE +** ON ENTRY: +** fp open password file +** out_username buffer to put the read username, must be at +** least MAX_USERNAME_LEN+1 characters long. +** out_passwd buffer to put the read password, must be at +** least MAX_PASSWORD_LEN+1 characters long. +** ON EXIT: +** returns EOF on end of file, +** otherwise the number of read fields +** (i.e. in a correct case returns 2). +** out_username contains the null-terminated read username. +** out_password contains the null-terminated read password. +** +** FORMAT OF PASSWORD FILE: +** username:password:maybe real name or other stuff +** (may include even colons) +** +** There may be whitespace (blanks or tabs) in the beginning and +** the end of each field. They are ignored. +*/ +PUBLIC int HTAAFile_readPasswdRec PARAMS((FILE * fp, + char * out_username, + char * out_password)); +/* + + */ + +#endif /* not HTPASSWD_H */ +/* + + End of file HTPasswd.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.c new file mode 100644 index 00000000000..dda98d5fe82 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.c @@ -0,0 +1,665 @@ +/* Plain text object HTWrite.c +** ================= +** +** This version of the stream object just writes to a socket. +** The socket is assumed open and left open. +** +** Bugs: +** strings written must be less than buffer size. +*/ +#include "HTUtils.h" +#include "tcp.h" + +#include "HTPlain.h" + +#include "HTChunk.h" +#include "HText.h" +#include "HTStyle.h" +#define Lynx_HTML_Handler +#include "HTML.h" /* styles[] */ + +#define BUFFER_SIZE 4096; /* Tradeoff */ + +#include "HText.h" +#include "HTStyle.h" +#include "HTMLDTD.h" +#include "HTCJK.h" +#include "UCMap.h" +#include "UCDefs.h" +#include "UCAux.h" + +#include "LYCharSets.h" +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern BOOLEAN LYRawMode; +extern BOOL HTPassEightBitRaw; +extern BOOL HTPassHighCtrlRaw; +extern HTCJKlang HTCJK; + +PUBLIC int HTPlain_lastraw = -1; + +/* HTML Object +** ----------- +*/ +struct _HTStream { + CONST HTStreamClass * isa; + HText * text; + /* + ** The node_anchor UCInfo and handle for the input (PARSER) stage. - FM + */ + LYUCcharset * inUCI; + int inUCLYhndl; + /* + ** The node_anchor UCInfo and handle for the output (HTEXT) stage. - FM + */ + int outUCLYhndl; + /* + ** Counter, value, buffer and pointer for UTF-8 handling. - FM + */ + char utf_count; + UCode_t utf_char; + char utf_buf[8]; + char * utf_buf_p; + /* + ** The charset transformation structure. - FM + */ + UCTransParams T; +}; + +PRIVATE char replace_buf [64]; /* buffer for replacement strings */ + +PRIVATE void HTPlain_getChartransInfo ARGS2( + HTStream *, me, + HTParentAnchor *, anchor) +{ + if (me->inUCLYhndl < 0) { + HTAnchor_copyUCInfoStage(anchor, UCT_STAGE_PARSER, UCT_STAGE_MIME, + UCT_SETBY_PARSER); + me->inUCLYhndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_PARSER); + } + if (me->outUCLYhndl < 0) { + int chndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_HTEXT); + if (chndl < 0) { + chndl = current_char_set; + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT); + } + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT); + me->outUCLYhndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_HTEXT); + } + me->inUCI = HTAnchor_getUCInfoStage(anchor, UCT_STAGE_PARSER); +} + +/* Write the buffer out to the socket +** ---------------------------------- +*/ + +/*_________________________________________________________________________ +** +** A C T I O N R O U T I N E S +*/ + +PRIVATE void HTPlain_write PARAMS(( + HTStream * me, + CONST char * s, + int l)); + +/* Character handling +** ------------------ +*/ +PRIVATE void HTPlain_put_character ARGS2( + HTStream *, me, + char, c) +{ +#ifdef REMOVE_CR_ONLY + /* + ** Throw away \r's. + */ + if (c != '\r') { + HText_appendCharacter(me->text, c); + } +#else + /* + ** See HTPlain_write() for explanations of the following code + ** (we've been called via HTPlain_put_string() to do for each + ** character of a terminated string what HTPlain_write() does + ** via a while loop for each character in a stream of given + ** length). - FM + */ + if ((HTPlain_lastraw == '\r') && c == '\n') { + HTPlain_lastraw = -1; + return; + } + HTPlain_lastraw = c; + if (c == '\r') { + HText_appendCharacter(me->text, '\n'); + } else if (HTCJK != NOCJK) { + HText_appendCharacter(me->text, c); + } else if ((unsigned char)c >= 127) { + /* + ** For now, don't repeat everything here + ** that has been done below - KW + */ + HTPlain_write(me, &c, 1); + } else if ((unsigned char)c >= 127 && (unsigned char)c < 161 && + HTPassHighCtrlRaw) { + HText_appendCharacter(me->text, c); + } else if ((unsigned char)c == 160) { + HText_appendCharacter(me->text, ' '); + } else if ((unsigned char)c == 173) { + return; + } else if (((unsigned char)c >= 32 && (unsigned char)c < 127) || + c == '\n' || c == '\t') { + HText_appendCharacter(me->text, c); + } else if ((unsigned char)c > 160) { + if (!HTPassEightBitRaw && + current_char_set != 0) { + size_t len, high, low, i; + int diff = 1; + CONST char * name; + UCode_t value = (UCode_t)((unsigned char)c - 160); + + name = HTMLGetEntityName(value); + len = strlen(name); + for (low = 0, high = HTML_dtd.number_of_entities; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { + /* Binary search */ + i = (low + (high-low)/2); + diff = strncmp(HTML_dtd.entity_names[i], name, len); + if (diff == 0) { + HText_appendText(me->text, + LYCharSets[current_char_set][i]); + break; + } + } + if (diff) { + HText_appendCharacter(me->text, c); + } + } else { + HText_appendCharacter(me->text, c); + } + } +#endif /* REMOVE_CR_ONLY */ +} + + +/* String handling +** --------------- +** +*/ +PRIVATE void HTPlain_put_string ARGS2(HTStream *, me, CONST char*, s) +{ +#ifdef REMOVE_CR_ONLY + HText_appendText(me->text, s); +#else + CONST char * p; + + if (s == NULL) + return; + for (p = s; *p; p++) { + HTPlain_put_character(me, *p); + } +#endif /* REMOVE_CR_ONLY */ +} + + +/* +** Entry function for displayed text/plain and WWW_SOURCE strings. - FM +** --------------------------------------------------------------- +*/ +PRIVATE void HTPlain_write ARGS3(HTStream *, me, CONST char*, s, int, l) +{ + CONST char * p; + CONST char * e = s+l; + char c; + unsigned char c_unsign; + BOOL chk; + UCode_t code; + long uck = 0; + + for (p = s; p < e; p++) { +#ifdef REMOVE_CR_ONLY + /* + ** Append the whole string, but remove any \r's. - FM + */ + if (*p != '\r') { + HText_appendCharacter(me->text, *p); + } +#else + /* + ** Try to handle lone LFs, CRLFs and lone CRs + ** as newline, and to deal with control, ASCII, + ** and 8-bit characters based on best guesses + ** of what's appropriate. - FM + */ + if ((HTPlain_lastraw == '\r') && *p == '\n') { + HTPlain_lastraw = -1; + continue; + } + HTPlain_lastraw = *p; + if (*p == '\r') { + HText_appendCharacter(me->text, '\n'); + continue; + } + /* + ** Make sure the character is handled as Unicode + ** whenever that's appropriate. - FM + */ + c = *p; + c_unsign = (unsigned char)c; + code = (UCode_t)c_unsign; + /* + ** Combine any UTF-8 multibytes into Unicode + ** to check for special characters. - FM + */ + if (me->T.decode_utf8) { + /* + ** Combine UTF-8 into Unicode. + ** Incomplete characters silently ignored. + ** from Linux kernel's console.c - KW + */ + if (c_unsign > 127) { + /* + ** We have an octet from a multibyte character. - FM + */ + if (me->utf_count > 0 && (c & 0xc0) == 0x80) { + /* + ** Adjust the UCode_t value, add the octet + ** to the buffer, and decrement the byte + ** count. - FM + */ + me->utf_char = (me->utf_char << 6) | (c & 0x3f); + me->utf_count--; + *(me->utf_buf_p) = c; + (me->utf_buf_p)++; + if (me->utf_count == 0) { + /* + ** Got a complete multibyte character. + */ + *(me->utf_buf_p) = '\0'; + code = me->utf_char; + if (code < 256) { + c = FROMASCII((char)code); + } + } else { + /* + ** Get the next byte. - FM + */ + continue; + } + } else { + /* + ** Start handling a new multibyte character. - FM + */ + me->utf_buf_p = me->utf_buf; + me->utf_buf_p[0] = c; + (me->utf_buf_p)++; + if ((*p & 0xe0) == 0xc0) { + me->utf_count = 1; + me->utf_char = (c & 0x1f); + } else if ((*p & 0xf0) == 0xe0) { + me->utf_count = 2; + me->utf_char = (c & 0x0f); + } else if ((*p & 0xf8) == 0xf0) { + me->utf_count = 3; + me->utf_char = (c & 0x07); + } else if ((*p & 0xfc) == 0xf8) { + me->utf_count = 4; + me->utf_char = (c & 0x03); + } else if ((*p & 0xfe) == 0xfc) { + me->utf_count = 5; + me->utf_char = (c & 0x01); + } else { + /* + * We got garbage, so ignore it. - FM + */ + me->utf_count = 0; + me->utf_buf_p = me->utf_buf; + me->utf_buf_p[0] = '\0'; + } + /* + ** Get the next byte. - FM + */ + continue; + } + } else { + /* + ** Got an ASCII character. + */ + me->utf_count = 0; + me->utf_buf[0] = '\0'; + me->utf_buf_p = me->utf_buf; + } + } + + if (me->T.trans_to_uni && + (code >= 127 || + (code < 32 && code != 0 && + me->T.trans_C0_to_uni))) { + /* + ** Convert the octet to Unicode. - FM + */ + code = (UCode_t)UCTransToUni(c, me->inUCLYhndl); + if (code > 0) { + if (code < 256) { + c = FROMASCII((char)code); + } + } + } + /* + ** At this point we have either code in Unicode + ** (and c in latin1 if code is in the latin1 range), + ** or code and c will have to be passed raw. + */ + + /* + ** If CJK mode is on, we'll assume the document matches + ** the user's selected character set, and if not, the + ** user should toggle off raw/CJK mode to reload. - FM + */ + if (HTCJK != NOCJK) { + HText_appendCharacter(me->text, c); + +#define PASSHICTRL (me->T.transp || \ + code >= LYlowest_eightbit[me->inUCLYhndl]) +#define PASS8859SPECL me->T.pass_160_173_raw +#define PASSHI8BIT (HTPassEightBitRaw || \ + (me->T.do_8bitraw && !me->T.trans_from_uni)) + /* + ** If HTPassHighCtrlRaw is set (e.g., for KOI8-R) assume the + ** document matches and pass 127-160 8-bit characters. If it + ** doesn't match, the user should toggle raw/CJK mode off. - FM + */ + } else if (code >= 127 && code < 161 && + PASSHICTRL && PASS8859SPECL) { + HText_appendCharacter(me->text, c); + } else if (code == 173 && PASS8859SPECL) { + HText_appendCharacter(me->text, c); + /* + ** If neither HTPassHighCtrlRaw nor CJK is set, play it safe + ** and treat 160 (nbsp) as an ASCII space (32). - FM + */ + } else if (code == 160) { + HText_appendCharacter(me->text, ' '); + /* + ** If neither HTPassHighCtrlRaw nor CJK is set, play it safe + ** and ignore 173 (shy). - FM + */ + } else if (code == 173) { + continue; + /* + ** If we get to here, pass the displayable ASCII characters. - FM + */ + } else if ((code >= 32 && code < 127) || + (PASSHI8BIT && + c >= LYlowest_eightbit[me->outUCLYhndl]) || + *p == '\n' || *p == '\t') { + HText_appendCharacter(me->text, c); + + } else if (me->T.use_raw_char_in) { + HText_appendCharacter(me->text, *p); +#ifdef NOTDEFINED + /* + ** Use an ASCII space (32) for ensp, emsp or thinsp. - FM + */ + } else if (code == 8194 || code == 8195 || code == 8201) { + HText_appendCharacter(me->text, ' '); +#endif /* NOTDEFINED */ + +/****************************************************************** + * I. LATIN-1 OR UCS2 TO DISPLAY CHARSET + ******************************************************************/ + } else if ((chk = (me->T.trans_from_uni && code >= 160)) && + (uck = UCTransUniChar(code, + me->outUCLYhndl)) >= 32 && + uck < 256) { + if (TRACE) { + fprintf(stderr, + "UCTransUniChar returned 0x%.2lX:'%c'.\n", + uck, FROMASCII((char)uck)); + } + HText_appendCharacter(me->text, ((char)(uck & 0xff))); + } else if (chk && + (uck == -4 || + (me->T.repl_translated_C0 && uck > 0 && uck < 32)) && + /* + ** Not found; look for replacement string. + */ + (uck = UCTransUniCharStr(replace_buf, 60, code, + me->outUCLYhndl, 0) >= 0)) { + /* + ** No further tests for valididy - assume that whoever + ** defined replacement strings knew what she was doing. + */ + HText_appendText(me->text, replace_buf); + /* + ** If we get to here, and should have translated, + ** translation has failed so far. + */ + } else if (chk && code > 127 && me->T.output_utf8) { + /* + ** We want UTF-8 output, so do it now. - FM + */ + if (*me->utf_buf) { + HText_appendText(me->text, me->utf_buf); + me->utf_buf[0] = '\0'; + me->utf_buf_p = me->utf_buf; + } else if (UCConvertUniToUtf8(code, replace_buf)) { + HText_appendText(me->text, replace_buf); + } else { + sprintf(replace_buf, "U%.2lX", code); + HText_appendText(me->text, replace_buf); + } +#ifdef NOTDEFINED + } else if (me->T.strip_raw_char_in && + (unsigned char)*p >= 192 && + (unsigned char)*p < 255) { + /* + ** KOI special: strip high bit, gives + ** (somewhat) readable ASCII. + */ + HText_appendCharacter(me->text, (char)(*p & 0x7f)); + /* + ** If we do not have the "7-bit approximations" as our + ** output character set (in which case we did it already) + ** seek a translation for that. Otherwise, or if the + ** translation fails, use UHHH notation. - FM + */ + } else if (chk && + (chk = (!HTPassEightBitRaw && + (me->outUCLYhndl != + UCGetLYhndl_byMIME("us-ascii")))) && + (uck = UCTransUniChar(code, + UCGetLYhndl_byMIME("us-ascii"))) + >= 32 && uck < 127) { + /* + ** Got an ASCII character (yippey). - FM + */ + c = ((char)(uck & 0xff)); + HText_appendCharacter(me->text, c); + } else if ((chk && uck == -4) && + (uck = UCTransUniCharStr(replace_buf, + 60, code, + UCGetLYhndl_byMIME("us-ascii"), + 0) >= 0)) { + /* + ** Got a repacement string (yippey). - FM + */ + HText_appendText(me->text, replace_buf); + } else if (code == 8204 || code == 8205) { + /* + ** Ignore 8204 (zwnj) or 8205 (zwj), if we get to here. - FM + */ + if (TRACE) { + fprintf(stderr, + "HTPlain_write: Ignoring '%ld'.\n", code); + } + } else if (code == 8206 || code == 8207) { + /* + ** Ignore 8206 (lrm) or 8207 (rlm), if we get to here. - FM + */ + if (TRACE) { + fprintf(stderr, + "HTPlain_write: Ignoring '%ld'.\n", code); + } +#endif /* NOTDEFINED */ + } else if (me->T.trans_from_uni && code > 255) { + if (PASSHI8BIT && PASSHICTRL && LYRawMode && + (unsigned char)*p >= LYlowest_eightbit[me->outUCLYhndl]) { + HText_appendCharacter(me->text, *p); + } else { + sprintf(replace_buf, "U%.2lX", code); + HText_appendText(me->text, replace_buf); + } + /* + ** If we get to here and HTPassEightBitRaw or the + ** selected character set is not "ISO Latin 1", + ** use the translation tables for 161-255 8-bit + ** characters (173 was handled above). - FM + */ + } else if (code > 160) { + if (!HTPassEightBitRaw && code <= 255 && + me->outUCLYhndl != 0) { + /* + ** Out of luck, so use the UHHH notation (ugh). - FM + */ + size_t len, high, low, i; + int diff = 1; + CONST char * name; + int value = (int)(code - 160); + + name = HTMLGetEntityName(value); + len = strlen(name); + for(low = 0, high = HTML_dtd.number_of_entities; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { + /* Binary search */ + i = (low + (high-low)/2); + diff = strncmp(HTML_dtd.entity_names[i], name, len); + if (diff == 0) { + HText_appendText(me->text, + LYCharSets[me->outUCLYhndl][i]); + break; + } + } + if (diff) { + /* + ** Something went wrong in the translation, so + ** either output as UTF8 or a hex representation or + ** pass the raw character and hope it's OK. + */ + if (!PASSHI8BIT) + c = FROMASCII((char)code); + if (me->T.output_utf8 && + *me->utf_buf) { + HText_appendText(me->text, me->utf_buf); + me->utf_buf_p = me->utf_buf; + *(me->utf_buf_p) = '\0'; + + } else if (me->T.trans_from_uni) { + sprintf(replace_buf, "U%.2lX", code); + HText_appendText(me->text, replace_buf); + } else + HText_appendCharacter(me->text, c); + } + } else { + /* + ** Didn't attempt a translation. - FM + */ + /* Either output as UTF8 or a hex representation or + ** pass the raw character and hope it's OK. + */ + if (code <= 255 && !PASSHI8BIT) + c = FROMASCII((char)code); + if (code > 127 && me->T.output_utf8 && *me->utf_buf) { + HText_appendText(me->text, me->utf_buf); + me->utf_buf_p = me->utf_buf; + *(me->utf_buf_p) = '\0'; + + } else if (LYRawMode && + me->inUCLYhndl != me->outUCLYhndl && + (PASSHI8BIT || PASSHICTRL) && + (unsigned char)c >= + LYlowest_eightbit[me->outUCLYhndl]) { + HText_appendCharacter(me->text, c); + } else if (me->T.trans_from_uni && code >= 127) { + sprintf(replace_buf, "U%.2lX", code); + HText_appendText(me->text, replace_buf); + } else + HText_appendCharacter(me->text, c); + } + } +#endif /* REMOVE_CR_ONLY */ + } +} + +/* Free an HTML object +** ------------------- +** +** Note that the SGML parsing context is freed, but the created object is +** not, as it takes on an existence of its own unless explicitly freed. +*/ +PRIVATE void HTPlain_free ARGS1( + HTStream *, me) +{ + FREE(me); +} + +/* End writing +*/ +PRIVATE void HTPlain_abort ARGS2( + HTStream *, me, + HTError, e GCC_UNUSED) +{ + HTPlain_free(me); +} + +/* Structured Object Class +** ----------------------- +*/ +PUBLIC CONST HTStreamClass HTPlain = +{ + "PlainPresenter", + HTPlain_free, + HTPlain_abort, + HTPlain_put_character, HTPlain_put_string, HTPlain_write, +}; + +/* New object +** ---------- +*/ +PUBLIC HTStream* HTPlainPresent ARGS3( + HTPresentation *, pres GCC_UNUSED, + HTParentAnchor *, anchor, + HTStream *, sink GCC_UNUSED) +{ + + HTStream* me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) + outofmem(__FILE__, "HTPlain_new"); + me->isa = &HTPlain; + + HTPlain_lastraw = -1; + + me->utf_count = 0; + me->utf_char = 0; + me->utf_buf[0] = me->utf_buf[6] =me->utf_buf[7] = '\0'; + me->utf_buf_p = me->utf_buf; + me->outUCLYhndl = HTAnchor_getUCLYhndl(anchor,UCT_STAGE_HTEXT); + me->inUCLYhndl = HTAnchor_getUCLYhndl(anchor,UCT_STAGE_PARSER); + HTPlain_getChartransInfo(me, anchor); + UCSetTransParams(&me->T, + me->inUCLYhndl, me->inUCI, + me->outUCLYhndl, + HTAnchor_getUCInfoStage(anchor,UCT_STAGE_HTEXT)); + + me->text = HText_new(anchor); + HText_setStyle(me->text, styles[HTML_XMP] ); + HText_beginAppend(me->text); + + return (HTStream*) me; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.h new file mode 100644 index 00000000000..f4ce3e14696 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.h @@ -0,0 +1,21 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTPlain.html + PLAIN TEXT OBJECT + + */ +#ifndef HTPLAIN_H +#define HTPLAIN_H + +#include "HTStream.h" +#include "HTAnchor.h" + +extern HTStream* HTPlainPresent PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + + +#endif + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.c new file mode 100644 index 00000000000..93a9eb255ee --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.c @@ -0,0 +1,418 @@ +/* Configuration manager for Hypertext Daemon HTRules.c +** ========================================== +** +** +** History: +** 3 Jun 91 Written TBL +** 10 Aug 91 Authorisation added after Daniel Martin (pass, fail) +** Rule order in file changed +** Comments allowed with # on 1st char of rule line +** 17 Jun 92 Bug fix: pass and fail failed if didn't contain '*' TBL +** 1 Sep 93 Bug fix: no memory check - Nathan Torkington +** BYTE_ADDRESSING removed - Arthur Secret +** 11 Sep 93 MD Changed %i into %d in debug printf. +** VMS does not recognize %i. +** Bug Fix: in case of PASS, only one parameter to printf. +** 19 Sep 93 AL Added Access Authorization stuff. +** 1 Nov 93 AL Added htbin. +** +*/ + +/* (c) CERN WorldWideWeb project 1990,91. See Copyright.html for details */ +#include "HTRules.h" + +#include "HTUtils.h" +#include "tcp.h" +/*#include <stdio.h> included by HTUtils.h -- FM */ +#include "HTFile.h" +#include "HTAAServ.h" /* Access Authorization */ + +#include "LYLeaks.h" + +#define LINE_LENGTH 256 + + +typedef struct _rule { + struct _rule * next; + HTRuleOp op; + char * pattern; + char * equiv; +} rule; + +/* Global variables +** ---------------- +*/ +PUBLIC char *HTBinDir = NULL; /* Physical /htbin directory path. */ + /* In future this should not be global. */ +PUBLIC char *HTSearchScript = NULL; /* Search script name. */ + + +/* Module-wide variables +** --------------------- +*/ + +PRIVATE rule * rules = 0; /* Pointer to first on list */ +#ifndef PUT_ON_HEAD +PRIVATE rule * rule_tail = 0; /* Pointer to last on list */ +#endif + + +/* Add rule to the list HTAddRule() +** -------------------- +** +** On entry, +** pattern points to 0-terminated string containing a single "*" +** equiv points to the equivalent string with * for the +** place where the text matched by * goes. +** On exit, +** returns 0 if success, -1 if error. +*/ + +#ifdef __STDC__ +PUBLIC int HTAddRule (HTRuleOp op, const char * pattern, const char * equiv) +#else +int HTAddRule(op, pattern, equiv) + HTRuleOp op; + char * pattern; + char * equiv; +#endif +{ /* BYTE_ADDRESSING removed and memory check - AS - 1 Sep 93 */ + rule * temp; + char * pPattern; + + temp = (rule *)malloc(sizeof(*temp)); + if (temp==NULL) + outofmem(__FILE__, "HTAddRule"); + pPattern = (char *)malloc(strlen(pattern)+1); + if (pPattern==NULL) + outofmem(__FILE__, "HTAddRule"); + if (equiv) { /* Two operands */ + char * pEquiv = (char *)malloc(strlen(equiv)+1); + if (pEquiv==NULL) + outofmem(__FILE__, "HTAddRule"); + temp->equiv = pEquiv; + strcpy(pEquiv, equiv); + } else { + temp->equiv = 0; + } + temp->pattern = pPattern; + temp->op = op; + + strcpy(pPattern, pattern); + if (TRACE) { + if (equiv) + fprintf(stderr, "Rule: For `%s' op %d `%s'\n", pattern, op, equiv); + else + fprintf(stderr, "Rule: For `%s' op %d\n", pattern, op); + } + +#ifdef PUT_ON_HEAD + temp->next = rules; + rules = temp; +#else + temp->next = 0; + if (rule_tail) rule_tail->next = temp; + else rules = temp; + rule_tail = temp; +#endif + + + return 0; +} + + +/* Clear all rules HTClearRules() +** --------------- +** +** On exit, +** There are no rules +** returns 0 if success, -1 if error. +** +** See also +** HTAddRule() +*/ +#ifdef __STDC__ +int HTClearRules(void) +#else +int HTClearRules() +#endif +{ + while (rules) { + rule * temp = rules; + rules = temp->next; + FREE(temp->pattern); + FREE(temp->equiv); + FREE(temp); + } +#ifndef PUT_ON_HEAD + rule_tail = 0; +#endif + + return 0; +} + + +/* Translate by rules HTTranslate() +** ------------------ +** +** The most recently defined rules are applied first. +** +** On entry, +** required points to a string whose equivalent value is neeed +** On exit, +** returns the address of the equivalent string allocated from +** the heap which the CALLER MUST FREE. If no translation +** occured, then it is a copy of te original. +** NEW FEATURES: +** When a "protect" or "defprot" rule is mathed, +** a call to HTAA_setCurrentProtection() or +** HTAA_setDefaultProtection() is made to notify +** the Access Authorization module that the file is +** protected, and so it knows how to handle it. +** -- AL +*/ +#ifdef __STDC__ +char * HTTranslate(const char * required) +#else +char * HTTranslate(required) + char * required; +#endif +{ + rule * r; + char *current = NULL; + StrAllocCopy(current, required); + + HTAA_clearProtections(); /* Reset from previous call -- AL */ + + for(r = rules; r; r = r->next) { + char * p = r->pattern; + int m=0; /* Number of characters matched against wildcard */ + CONST char * q = current; + for(;*p && *q; p++, q++) { /* Find first mismatch */ + if (*p!=*q) break; + } + + if (*p == '*') { /* Match up to wildcard */ + m = strlen(q) - strlen(p+1); /* Amount to match to wildcard */ + if(m<0) continue; /* tail is too short to match */ + if (0!=strcmp(q+m, p+1)) continue; /* Tail mismatch */ + } else /* Not wildcard */ + if (*p != *q) continue; /* plain mismatch: go to next rule */ + + switch (r->op) { /* Perform operation */ + +#ifdef ACCESS_AUTH + case HT_DefProt: + case HT_Protect: + { + char *local_copy = NULL; + char *p2; + char *eff_ids = NULL; + char *prot_file = NULL; + + if (TRACE) fprintf(stderr, + "HTRule: `%s' matched %s %s: `%s'\n", + current, + (r->op==HT_Protect ? "Protect" : "DefProt"), + "rule, setup", + (r->equiv ? r->equiv : + (r->op==HT_Protect ?"DEFAULT" :"NULL!!"))); + + if (r->equiv) { + StrAllocCopy(local_copy, r->equiv); + p2 = local_copy; + prot_file = HTNextField(&p2); + eff_ids = HTNextField(&p2); + } + + if (r->op == HT_Protect) + HTAA_setCurrentProtection(current, prot_file, eff_ids); + else + HTAA_setDefaultProtection(current, prot_file, eff_ids); + + FREE(local_copy); + + /* continue translating rules */ + } + break; +#endif /* ACCESS_AUTH */ + + case HT_Pass: /* Authorised */ + if (!r->equiv) { + if (TRACE) fprintf(stderr, "HTRule: Pass `%s'\n", current); + return current; + } + /* Else fall through ...to map and pass */ + + case HT_Map: + if (*p == *q) { /* End of both strings, no wildcard */ + if (TRACE) fprintf(stderr, + "For `%s' using `%s'\n", current, r->equiv); + StrAllocCopy(current, r->equiv); /* use entire translation */ + } else { + char * ins = strchr(r->equiv, '*'); /* Insertion point */ + if (ins) { /* Consistent rule!!! */ + char * temp = (char *)malloc( + strlen(r->equiv)-1 + m + 1); + if (temp==NULL) + outofmem(__FILE__, "HTTranslate"); /* NT & AS */ + strncpy(temp, r->equiv, ins-r->equiv); + /* Note: temp may be unterminated now! */ + strncpy(temp+(ins-r->equiv), q, m); /* Matched bit */ + strcpy (temp+(ins-r->equiv)+m, ins+1); /* Last bit */ + if (TRACE) fprintf(stderr, "For `%s' using `%s'\n", + current, temp); + FREE(current); + current = temp; /* Use this */ + + } else { /* No insertion point */ + char * temp = (char *)malloc(strlen(r->equiv)+1); + if (temp==NULL) + outofmem(__FILE__, "HTTranslate"); /* NT & AS */ + strcpy(temp, r->equiv); + if (TRACE) fprintf(stderr, "For `%s' using `%s'\n", + current, temp); + FREE(current); + current = temp; /* Use this */ + } /* If no insertion point exists */ + } + if (r->op == HT_Pass) { + if (TRACE) fprintf(stderr, "HTRule: ...and pass `%s'\n", + current); + return current; + } + break; + + case HT_Invalid: + case HT_Fail: /* Unauthorised */ + if (TRACE) fprintf(stderr, "HTRule: *** FAIL `%s'\n", + current); + return (char *)0; + + } /* if tail matches ... switch operation */ + + } /* loop over rules */ + + + return current; +} + +/* Load one line of configuration +** ------------------------------ +** +** Call this, for example, to load a X resource with config info. +** +** returns 0 OK, < 0 syntax error. +*/ +PUBLIC int HTSetConfiguration ARGS1(CONST char *, config) +{ + HTRuleOp op; + char * line = NULL; + char * pointer = line; + char *word1, *word2, *word3; + float quality, secs, secs_per_byte; + int maxbytes; + int status; + + StrAllocCopy(line, config); + { + char * p = strchr(line, '#'); /* Chop off comments */ + if (p) *p = 0; + } + pointer = line; + word1 = HTNextField(&pointer); + if (!word1) { + FREE(line); + return 0; + } ; /* Comment only or blank */ + + word2 = HTNextField(&pointer); + + if (0==strcasecomp(word1, "defprot") || + 0==strcasecomp(word1, "protect")) + word3 = pointer; /* The rest of the line to be parsed by AA module */ + else + word3 = HTNextField(&pointer); /* Just the next word */ + + if (!word2) { + fprintf(stderr, "HTRule: Insufficient operands: %s\n", line); + FREE(line); + return -2; /*syntax error */ + } + + if (0==strcasecomp(word1, "suffix")) { + char * encoding = HTNextField(&pointer); + if (pointer) status = sscanf(pointer, "%f", &quality); + else status = 0; + HTSetSuffix(word2, word3, + encoding ? encoding : "binary", + status >= 1? quality : 1.0); + + } else if (0==strcasecomp(word1, "presentation")) { + if (pointer) status = sscanf(pointer, "%f%f%f%d", + &quality, &secs, &secs_per_byte, &maxbytes); + else status = 0; + HTSetPresentation(word2, word3, + status >= 1? quality : 1.0, + status >= 2 ? secs : 0.0, + status >= 3 ? secs_per_byte : 0.0, + status >= 4 ? maxbytes : 0 ); + + } else if (0==strncasecomp(word1, "htbin", 5) || + 0==strncasecomp(word1, "bindir", 6)) { + StrAllocCopy(HTBinDir, word2); /* Physical /htbin location */ + + } else if (0==strncasecomp(word1, "search", 6)) { + StrAllocCopy(HTSearchScript, word2); /* Search script name */ + + } else { + op = 0==strcasecomp(word1, "map") ? HT_Map + : 0==strcasecomp(word1, "pass") ? HT_Pass + : 0==strcasecomp(word1, "fail") ? HT_Fail + : 0==strcasecomp(word1, "defprot") ? HT_DefProt + : 0==strcasecomp(word1, "protect") ? HT_Protect + : HT_Invalid; + if (op==HT_Invalid) { + fprintf(stderr, "HTRule: Bad rule `%s'\n", config); + } else { + HTAddRule(op, word2, word3); + } + } + FREE(line); + return 0; +} + + +/* Load the rules from a file HTLoadRules() +** -------------------------- +** +** On entry, +** Rules can be in any state +** On exit, +** Any existing rules will have been kept. +** Any new rules will have been loaded. +** Returns 0 if no error, 0 if error! +** +** Bugs: +** The strings may not contain spaces. +*/ + +int HTLoadRules ARGS1(CONST char *, filename) +{ + FILE * fp = fopen(filename, "r"); + char line[LINE_LENGTH+1]; + + if (!fp) { + if (TRACE) fprintf(stderr, + "HTRules: Can't open rules file %s\n", filename); + return -1; /* File open error */ + } + for(;;) { + if (!fgets(line, LINE_LENGTH+1, fp)) break; /* EOF or error */ + (void) HTSetConfiguration(line); + } + fclose(fp); + return 0; /* No error or syntax errors ignored */ +} + + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.h new file mode 100644 index 00000000000..8407524467f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.h @@ -0,0 +1,165 @@ +/* Configuration Manager for libwww + CONFIGURATION MANAGER + + Author Tim Berners-Lee/CERN. Public domain. Please mail changes to timbl@info.cern.ch. + + The configuration information loaded includes tables (file suffixes, presentation + methods) in other modules. The most likely routines needed by developers will be: + + HTSetConfiguration to load configuration information. + + HTLoadRules to load a whole file of configuration information + + HTTranslate to translate a URL using the rule table. + + */ +#ifndef HTRULE_H +#define HTRULE_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +typedef enum _HTRuleOp { + HT_Invalid, + HT_Map, + HT_Pass, + HT_Fail, + HT_DefProt, + HT_Protect +} HTRuleOp; + +#ifdef SHORT_NAMES +#define HTSearSc HTSearchScript +#endif /*SHORT_NAMES*/ + +/* + +Server Side Script Execution + + If a URL starts with /htbin/ it is understood to mean a script execution request on + server. This feature needs to be turned on by setting HTBinDir by the htbin rule. + Index searching is enabled by setting HTSearchScript into the name of script in BinDir + doing the actual search by search rule (BinDir must also be set in this case, of + course). + + */ + +extern char * HTBinDir; /* Physical /htbin location */ +extern char * HTSearchScript; /* Search script name */ + +/* + +HTAddRule: Add rule to the list + + ON ENTRY, + + pattern points to 0-terminated string containing a single "*" + + equiv points to the equivalent string with * for the place where the + text matched by * goes. + + ON EXIT, + + returns 0 if success, -1 if error. + + Note that if BYTE_ADDRESSING is set, the three blocks required are allocated and + deallocated as one. This will save time and storage, when malloc's allocation units are + large. + + */ +extern int HTAddRule PARAMS((HTRuleOp op, const char * pattern, const char * equiv)); + + +/* + +HTClearRules: Clear all rules + + ON EXIT, + + Rule file There are no rules + + returns + 0 if success, -1 if error. + + */ + +#ifdef __STDC__ +extern int HTClearRules(void); +#else +extern int HTClearRules(); +#endif + + +/* + +HTTranslate: Translate by rules + + */ + +/* + + ON ENTRY, + + required points to a string whose equivalent value is neeed + + ON EXIT, + + returns the address of the equivalent string allocated from the heap + which the CALLER MUST FREE. If no translation occured, then it is + a copy of the original. + + */ +#ifdef __STDC__ +extern char * HTTranslate(const char * required); +#else +extern char * HTTranslate(); +#endif + + +/* + +HTSetConfiguration: Load one line of configuration information + + ON ENTRY, + + config is a string in the syntax of a rule file line. + + This routine may be used for loading configuration information from sources other than + the rule file, for example INI files for X resources. + + */ +extern int HTSetConfiguration PARAMS((CONST char * config)); + + +/* + +HtLoadRules: Load the rules from a file + + ON ENTRY, + + Rule table Rules can be in any state + + ON EXIT, + + Rule table Any existing rules will have been kept. Any new rules will have + been loaded on top, so as to be tried first. + + Returns 0 if no error. + + */ + +#ifdef __STDC__ +extern int HTLoadRules(const char * filename); +#else +extern int HTLoadRules(); +#endif +/* + + */ + + +#endif /* HTUtils.h */ +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStream.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStream.h new file mode 100644 index 00000000000..72344cd367e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStream.h @@ -0,0 +1,61 @@ +/* The Stream class definition -- libwww + STREAM OBJECT DEFINITION + + A Stream object is something which accepts a stream of text. + + The creation methods will vary on the type of Stream Object. All creation methods + return a pointer to the stream type below. + + As you can see, but the methods used to write to the stream and close it are pointed to + be the object itself. + + */ +#ifndef HTSTREAM_H +#define HTSTREAM_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +typedef struct _HTStream HTStream; + +/* + + These are the common methods of all streams. They should be self-explanatory, except + for end_document which must be called before free. It should be merged with free in + fact: it should be dummy for new streams. + + The put_block method was write, but this upset systems whiuch had macros for write(). + + */ +typedef struct _HTStreamClass { + + char* name; /* Just for diagnostics */ + + void (*_free) PARAMS(( + HTStream* me)); + + void (*_abort) PARAMS(( + HTStream* me, + HTError e)); + + void (*put_character) PARAMS(( + HTStream* me, + char ch)); + + void (*put_string) PARAMS(( + HTStream* me, + CONST char * str)); + + void (*put_block) PARAMS(( + HTStream* me, + CONST char * str, + int len)); + +}HTStreamClass; + +#endif /* HTSTREAM_H */ + +/* + + end of HTStream.h */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.c new file mode 100644 index 00000000000..5f358b9775f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.c @@ -0,0 +1,344 @@ +/* Case-independent string comparison HTString.c +** +** Original version came with listserv implementation. +** Version TBL Oct 91 replaces one which modified the strings. +** 02-Dec-91 (JFG) Added stralloccopy and stralloccat +** 23 Jan 92 (TBL) Changed strallocc* to 8 char HTSAC* for VM and suchlike +** 6 Oct 92 (TBL) Moved WWW_TraceFlag in here to be in library +*/ +#include <ctype.h> +#include "HTUtils.h" +#include "tcp.h" + +#include "LYLeaks.h" +#include "LYStrings.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +PUBLIC int WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */ + +#ifndef VC +#define VC "unknown" +#endif /* !VC */ + +PUBLIC CONST char * HTLibraryVersion = VC; /* String for help screen etc */ + +/* +** strcasecomp8 is a variant of strcasecomp (below) +** ------------ ----------- +** but uses 8bit upper/lower case information +** from the current display charset. +** It returns 0 if exact match. +*/ +PUBLIC int strcasecomp8 ARGS2( + CONST char*, a, + CONST char *, b) +{ + CONST char *p = a; + CONST char *q = b; + + for ( ; *p && *q; p++, q++) { + int diff = UPPER8(*p, *q); + if (diff) return diff; + } + if (*p) + return 1; /* p was longer than q */ + if (*q) + return -1; /* p was shorter than q */ + return 0; /* Exact match */ +} + +/* +** strncasecomp8 is a variant of strncasecomp (below) +** ------------- ------------ +** but uses 8bit upper/lower case information +** from the current display charset. +** It returns 0 if exact match. +*/ +PUBLIC int strncasecomp8 ARGS3( + CONST char*, a, + CONST char *, b, + int, n) +{ + CONST char *p = a; + CONST char *q = b; + + for ( ; ; p++, q++) { + int diff; + if (p == (a+n)) + return 0; /* Match up to n characters */ + if (!(*p && *q)) + return (*p - *q); + diff = UPPER8(*p, *q); + if (diff) + return diff; + } + /*NOTREACHED*/ +} +#ifndef VM /* VM has these already it seems */ + +/* Strings of any length +** --------------------- +*/ +PUBLIC int strcasecomp ARGS2( + CONST char*, a, + CONST char *, b) +{ + CONST char *p = a; + CONST char *q = b; + + for ( ; *p && *q; p++, q++) { + int diff = TOLOWER(*p) - TOLOWER(*q); + if (diff) return diff; + } + if (*p) + return 1; /* p was longer than q */ + if (*q) + return -1; /* p was shorter than q */ + return 0; /* Exact match */ +} + + +/* With count limit +** ---------------- +*/ +PUBLIC int strncasecomp ARGS3( + CONST char*, a, + CONST char *, b, + int, n) +{ + CONST char *p = a; + CONST char *q = b; + + for ( ; ; p++, q++) { + int diff; + if (p == (a+n)) + return 0; /* Match up to n characters */ + if (!(*p && *q)) + return (*p - *q); + diff = TOLOWER(*p) - TOLOWER(*q); + if (diff) + return diff; + } + /*NOTREACHED*/ +} +#endif /* VM */ + +/* Allocate a new copy of a string, and returns it +*/ +PUBLIC char * HTSACopy ARGS2( + char **, dest, + CONST char *, src) +{ + FREE(*dest); + if (src) { + *dest = (char *) malloc (strlen(src) + 1); + if (*dest == NULL) + outofmem(__FILE__, "HTSACopy"); + strcpy (*dest, src); + } + return *dest; +} + +/* String Allocate and Concatenate +*/ +PUBLIC char * HTSACat ARGS2( + char **, dest, + CONST char *, src) +{ + if (src && *src) { + if (*dest) { + int length = strlen(*dest); + *dest = (char *)realloc(*dest, length + strlen(src) + 1); + if (*dest == NULL) + outofmem(__FILE__, "HTSACat"); + strcpy (*dest + length, src); + } else { + *dest = (char *)malloc(strlen(src) + 1); + if (*dest == NULL) + outofmem(__FILE__, "HTSACat"); + strcpy (*dest, src); + } + } + return *dest; +} + + +/* Find next Field +** --------------- +** +** On entry, +** *pstr points to a string containig white space separated +** field, optionlly quoted. +** +** On exit, +** *pstr has been moved to the first delimiter past the +** field +** THE STRING HAS BEEN MUTILATED by a 0 terminator +** +** returns a pointer to the first field +*/ +PUBLIC char * HTNextField ARGS1( + char **, pstr) +{ + char * p = *pstr; + char * start; /* start of field */ + + while (*p && WHITE(*p)) + p++; /* Strip white space */ + if (!*p) { + *pstr = p; + return NULL; /* No first field */ + } + if (*p == '"') { /* quoted field */ + p++; + start = p; + for (; *p && *p!='"'; p++) { + if (*p == '\\' && p[1]) + p++; /* Skip escaped chars */ + } + } else { + start = p; + while (*p && !WHITE(*p)) + p++; /* Skip first field */ + } + if (*p) + *p++ = '\0'; + *pstr = p; + return start; +} + +/* Find next Token +** --------------- +** Finds the next token in a string +** On entry, +** *pstr points to a string to be parsed. +** delims lists characters to be recognized as delimiters. +** If NULL default is white white space "," ";" or "=". +** The word can optionally be quoted or enclosed with +** chars from bracks. +** Comments surrrounded by '(' ')' are filtered out +** unless they are specifically reqested by including +** ' ' or '(' in delims or bracks. +** bracks lists bracketing chars. Some are recognized as +** special, for those give the opening char. +** If NULL defaults to <"> and "<" ">". +** found points to location to fill with the ending delimiter +** found, or is NULL. +** +** On exit, +** *pstr has been moved to the first delimiter past the +** field +** THE STRING HAS BEEN MUTILATED by a 0 terminator +** found points to the delimiter found unless it was NULL. +** Returns a pointer to the first word or NULL on error +*/ +PUBLIC char * HTNextTok ARGS4( + char **, pstr, + const char *, delims, + const char *, bracks, + char *, found) +{ + char * p = *pstr; + char * start = NULL; + BOOL get_blanks, skip_comments; + BOOL get_comments; + BOOL get_closing_char_too = FALSE; + char closer; + if (!pstr || !*pstr) return NULL; + if (!delims) delims = " ;,=" ; + if (!bracks) bracks = "<\"" ; + + get_blanks = (!strchr(delims,' ') && !strchr(bracks,' ')); + get_comments = (strchr(bracks,'(') != NULL); + skip_comments = (!get_comments && !strchr(delims,'(') && !get_blanks); +#define skipWHITE(c) (!get_blanks && WHITE(c)) + + while (*p && skipWHITE(*p)) + p++; /* Strip white space */ + if (!*p) { + *pstr = p; + if (found) *found = '\0'; + return NULL; /* No first field */ + } + while (1) { + /* Strip white space and other delimiters */ + while (*p && (skipWHITE(*p) || strchr(delims,*p))) p++; + if (!*p) { + *pstr = p; + if (found) *found = *(p-1); + return NULL; /* No field */ + } + + if (*p == '(' && (skip_comments || get_comments)) { /* Comment */ + int comment_level = 0; + if (get_comments && !start) start = p+1; + for(;*p && (*p!=')' || --comment_level>0); p++) { + if (*p == '(') comment_level++; + else if (*p == '"') { /* quoted field within Comment */ + for(p++; *p && *p!='"'; p++) + if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ + if (!*p) break; /* (invalid) end of string found, leave */ + } + if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ + } + if (get_comments) + break; + if (*p) p++; + if (get_closing_char_too) { + if (!*p || (!strchr(bracks,*p) && strchr(delims,*p))) { + break; + } else + get_closing_char_too = (strchr(bracks,*p) != NULL); + } + } else if (strchr(bracks,*p)) { /* quoted or bracketted field */ + switch (*p) { + case '<': closer = '>'; break; + case '[': closer = ']'; break; + case '{': closer = '}'; break; + case ':': closer = ';'; break; + default: closer = *p; + } + if (!start) start = ++p; + for(;*p && *p!=closer; p++) + if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ + if (get_closing_char_too) { + p++; + if (!*p || (!strchr(bracks,*p) && strchr(delims,*p))) { + break; + } else + get_closing_char_too = (strchr(bracks,*p) != NULL); + } else + break; /* kr95-10-9: needs to stop here */ +#if 0 + } else if (*p == '<') { /* quoted field */ + if (!start) start = ++p; + for(;*p && *p!='>'; p++) + if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ + break; /* kr95-10-9: needs to stop here */ +#endif + } else { /* Spool field */ + if (!start) start = p; + while(*p && !skipWHITE(*p) && !strchr(bracks,*p) && + !strchr(delims,*p)) + p++; + if (*p && strchr(bracks,*p)) { + get_closing_char_too = TRUE; + } else { + if (*p=='(' && skip_comments) { + *pstr = p; + HTNextTok(pstr, NULL, "(", found); /* Advance pstr */ + *p = '\0'; + if (*pstr && **pstr) (*pstr)++; + return start; + } + break; /* Got it */ + } + } + } + if (found) *found = *p; + + if (*p) *p++ = '\0'; + *pstr = p; + return start; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.h new file mode 100644 index 00000000000..0b2c23dcca6 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.h @@ -0,0 +1,63 @@ +/* String handling for libwww + STRINGS + + Case-independent string comparison and allocations with copies etc + + */ +#ifndef HTSTRING_H +#define HTSTRING_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +extern int WWW_TraceFlag; /* Global flag for all W3 trace */ + +extern CONST char * HTLibraryVersion; /* String for help screen etc */ + +/* + +Case-insensitive string comparison + + The usual routines (comp instead of cmp) had some problem. + + */ +extern int strcasecomp PARAMS((CONST char *a, CONST char *b)); +extern int strncasecomp PARAMS((CONST char *a, CONST char *b, int n)); + +extern int strcasecomp8 PARAMS((CONST char *a, CONST char *b)); +extern int strncasecomp8 PARAMS((CONST char *a, CONST char *b, int n)); + /* + ** strcasecomp8 and strncasecomp8 are variants of strcasecomp + ** and strncasecomp, but use 8bit upper/lower case information + ** from the current display charset + */ + + +/* + +Malloced string manipulation + + */ +#define StrAllocCopy(dest, src) HTSACopy (&(dest), src) +#define StrAllocCat(dest, src) HTSACat (&(dest), src) +extern char * HTSACopy PARAMS ((char **dest, CONST char *src)); +extern char * HTSACat PARAMS ((char **dest, CONST char *src)); + +/* + +Next word or quoted string + + */ +extern char * HTNextField PARAMS ((char** pstr)); + +/* A more general parser - kw */ +extern char * HTNextTok PARAMS((char ** pstr, + const char * delims, const char * bracks, char * found)); + +#endif +/* + + end + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.c new file mode 100644 index 00000000000..a5e242056b6 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.c @@ -0,0 +1,363 @@ +/* Style Implementation for Hypertext HTStyle.c +** ================================== +** +** Styles allow the translation between a logical property +** of a piece of text and its physical representation. +** +** A StyleSheet is a collection of styles, defining the +** translation necessary to +** represent a document. It is a linked list of styles. +*/ +#include "HTUtils.h" +#include "HTStyle.h" + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* Create a new style +*/ +PUBLIC HTStyle* HTStyleNew NOARGS +{ + HTStyle * self = (HTStyle *)malloc(sizeof(*self)); + memset((void *)self, 0, sizeof(*self)); + self->font = (HTFont) 0; + self->color = 0; + return self; +} + +/* Create a new style with a name +*/ +PUBLIC HTStyle* HTStyleNewNamed ARGS1 (CONST char *,name) +{ + HTStyle * self = HTStyleNew(); + StrAllocCopy(self->name, name); + return self; +} + + +/* Free a style +*/ +PUBLIC HTStyle * HTStyleFree ARGS1 (HTStyle *,self) +{ + FREE(self->name); + FREE(self->SGMLTag); + FREE(self); + return NULL; +} + + +#ifdef SUPPRESS /* Only on the NeXT */ +/* Read a style from a stream (without its name) +** -------------------------- +** +** Reads a style with paragraph information from a stream. +** The style name is not read or written by these routines. +*/ +#define NONE_STRING "(None)" +#define HTStream NXStream + +HTStyle * HTStyleRead (HTStyle * style, HTStream * stream) +{ + char myTag[STYLE_NAME_LENGTH]; + char fontName[STYLE_NAME_LENGTH]; + NXTextStyle *p; + int tab; + int gotpara; /* flag: have we got a paragraph definition? */ + + NXScanf(stream, "%s%s%f%d", + myTag, + fontName, + &style->fontSize, + &gotpara); + if (gotpara) { + if (!style->paragraph) { + style->paragraph = malloc(sizeof(*(style->paragraph))); + style->paragraph->tabs = 0; + } + p = style->paragraph; + NXScanf(stream, "%f%f%f%f%hd%f%f%hd", + &p->indent1st, + &p->indent2nd, + &p->lineHt, + &p->descentLine, + &p->alignment, + &style->spaceBefore, + &style->spaceAfter, + &p->numTabs); + FREE(p->tabs); + p->tabs = malloc(p->numTabs * sizeof(p->tabs[0])); + for (tab=0; tab < p->numTabs; tab++) { + NXScanf(stream, "%hd%f", + &p->tabs[tab].kind, + &p->tabs[tab].x); + } + } else { /* No paragraph */ + FREE(style->paragraph); + } /* if no paragraph */ + StrAllocCopy(style->SGMLTag, myTag); + if (strcmp(fontName, NONE_STRING)==0) + style->font = 0; + else + style->font = [Font newFont:fontName size:style->fontSize]; + return NULL; +} + + +/* Write a style to a stream in a compatible way +*/ +HTStyle * HTStyleWrite (HTStyle * style, NXStream * stream) +{ + int tab; + NXTextStyle *p = style->paragraph; + NXPrintf(stream, "%s %s %f %d\n", + style->SGMLTag, + style->font ? [style->font name] : NONE_STRING, + style->fontSize, + p!=0); + + if (p) { + NXPrintf(stream, "\t%f %f %f %f %d %f %f\t%d\n", + p->indent1st, + p->indent2nd, + p->lineHt, + p->descentLine, + p->alignment, + style->spaceBefore, + style->spaceAfter, + p->numTabs); + + for (tab=0; tab < p->numTabs; tab++) + NXPrintf(stream, "\t%d %f\n", + p->tabs[tab].kind, + p->tabs[tab].x); + } + return style; +} + + +/* Write a style to stdout for diagnostics +*/ +HTStyle * HTStyleDump (HTStyle * style) +{ + int tab; + NXTextStyle *p = style->paragraph; + printf("Style %d `%s' SGML:%s. Font %s %.1f point.\n", + style, + style->name, + style->SGMLTag, + [style->font name], + style->fontSize); + if (p) { + printf( + "\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n" + "\tAlign=%d, %d tabs. (%.0f before, %.0f after)\n", + p->indent1st, + p->indent2nd, + p->lineHt, + p->descentLine, + p->alignment, + p->numTabs, + style->spaceBefore, + style->spaceAfter); + + for (tab=0; tab < p->numTabs; tab++) { + printf("\t\tTab kind=%d at %.0f\n", + p->tabs[tab].kind, + p->tabs[tab].x); + } + printf("\n"); + } /* if paragraph */ + return style; +} +#endif /* SUPPRESS */ + + +/* StyleSheet Functions +** ==================== +*/ + +/* Searching for styles: +*/ +HTStyle * HTStyleNamed ARGS2 (HTStyleSheet *,self, CONST char *,name) +{ + HTStyle * scan; + for (scan=self->styles; scan; scan=scan->next) + if (0==strcmp(scan->name, name)) return scan; + if (TRACE) fprintf(stderr, "StyleSheet: No style named `%s'\n", name); + return NULL; +} + +#ifdef NEXT_SUPRESS /* Not in general common code */ + +HTStyle * HTStyleMatching (HTStyleSheet * self, HTStyle *style) +{ + HTStyle * scan; + for (scan=self->styles; scan; scan=scan->next) + if (scan->paragraph == para) return scan; + return NULL; +} + +/* Find the style which best fits a given run +** ------------------------------------------ +** +** This heuristic is used for guessing the style for a run of +** text which has been pasted in. In order, we try: +** +** A style whose paragraph structure is actually used by the run. +** A style matching in font +** A style matching in paragraph style exactly +** A style matching in paragraph to a degree +*/ + +HTStyle * HTStyleForRun (HTStyleSheet *self, NXRun *run) +{ + HTStyle * scan; + HTStyle * best = 0; + int bestMatch = 0; + NXTextStyle * rp = run->paraStyle; + for (scan=self->styles; scan; scan=scan->next) + if (scan->paragraph == run->paraStyle) return scan; /* Exact */ + + for (scan=self->styles; scan; scan=scan->next){ + NXTextStyle * sp = scan->paragraph; + if (sp) { + int match = 0; + if (sp->indent1st == rp->indent1st) match = match+1; + if (sp->indent2nd == rp->indent2nd) match = match+2; + if (sp->lineHt == rp->lineHt) match = match+1; + if (sp->numTabs == rp->numTabs) match = match+1; + if (sp->alignment == rp->alignment) match = match+3; + if (scan->font == run->font) match = match+10; + if (match>bestMatch) { + best=scan; + bestMatch=match; + } + } + } + if (TRACE) fprintf(stderr, "HTStyleForRun: Best match for style is %d out of 18\n", + bestMatch); + return best; +} +#endif /* NEXT_SUPRESS */ + + +/* Add a style to a sheet +** ---------------------- +*/ +HTStyleSheet * HTStyleSheetAddStyle ARGS2 + (HTStyleSheet *,self, HTStyle *,style) +{ + style->next = 0; /* The style will go on the end */ + if (!self->styles) { + self->styles = style; + } else { + HTStyle * scan; + for(scan=self->styles; scan->next; scan=scan->next); /* Find end */ + scan->next=style; + } + return self; +} + + +/* Remove the given object from a style sheet if it exists +*/ +HTStyleSheet * HTStyleSheetRemoveStyle ARGS2 + (HTStyleSheet *,self, HTStyle *,style) +{ + if (self->styles == style) { + self->styles = style->next; + return self; + } else { + HTStyle * scan; + for(scan = self->styles; scan; scan = scan->next) { + if (scan->next == style) { + scan->next = style->next; + return self; + } + } + } + return NULL; +} + +/* Create new style sheet +*/ + +HTStyleSheet * HTStyleSheetNew NOARGS +{ + HTStyleSheet * self = (HTStyleSheet *)malloc(sizeof(*self)); + + memset((void*)self, 0, sizeof(*self)); /* ANSI */ +/* Harbison c ref man says (char*)self + but k&r ansii and abc books and Think_C say (void*) */ + +/* bzero(self, sizeof(*self)); */ /* BSD */ + return self; +} + + +/* Free off a style sheet pointer +*/ +HTStyleSheet * HTStyleSheetFree ARGS1 (HTStyleSheet *,self) +{ + HTStyle * style; + while((style=self->styles)!=0) { + self->styles = style->next; + HTStyleFree(style); + } + FREE(self); + return NULL; +} + + +/* Read a stylesheet from a typed stream +** ------------------------------------- +** +** Reads a style sheet from a stream. If new styles have the same names +** as existing styles, they replace the old ones without changing the ids. +*/ + +#ifdef NEXT_SUPRESS /* Only on the NeXT */ +HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream) +{ + int numStyles; + int i; + HTStyle * style; + char styleName[80]; + NXScanf(stream, " %d ", &numStyles); + if (TRACE) fprintf(stderr, "Stylesheet: Reading %d styles\n", numStyles); + for (i=0; i<numStyles; i++) { + NXScanf(stream, "%s", styleName); + style = HTStyleNamed(self, styleName); + if (!style) { + style = HTStyleNewNamed(styleName); + (void) HTStyleSheetAddStyle(self, style); + } + (void) HTStyleRead(style, stream); + if (TRACE) HTStyleDump(style); + } + return self; +} + +/* Write a stylesheet to a typed stream +** ------------------------------------ +** +** Writes a style sheet to a stream. +*/ + +HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream) +{ + int numStyles = 0; + HTStyle * style; + + for(style=self->styles; style; style=style->next) numStyles++; + NXPrintf(stream, "%d\n", numStyles); + + if (TRACE) fprintf(stderr, "StyleSheet: Writing %d styles\n", numStyles); + for (style=self->styles; style; style=style->next) { + NXPrintf(stream, "%s ", style->name); + (void) HTStyleWrite(style, stream); + } + return self; +} +#endif /* NEXT_SUPRESS */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.h new file mode 100644 index 00000000000..bbab0ea662c --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.h @@ -0,0 +1,182 @@ +/* HTStyle: Style management for libwww + STYLE DEFINITION FOR HYPERTEXT + + Styles allow the translation between a logical property of a piece of text and its + physical representation. + + A StyleSheet is a collection of styles, defining the translation necessary to represent + a document. It is a linked list of styles. + +Overriding this module + + Why is the style structure declared in the HTStyle.h module, instead of having the user + browser define the structure, and the HTStyle routines just use sizeof() for copying? + + It's not obvious whether HTStyle.c should be common code. It's useful to have common + code for loading style sheets, especially if the movement toward standard style sheets + gets going. + + If it IS common code, then both the hypertext object and HTStyle.c must know the + structure of a style, so HTStyle.h is a suitable place to put that. HTStyle.c has to + be compiled with a knowledge of the + + It we take it out of the library, then of course HTStyle could be declared as an + undefined structure. The only references to it are in the structure-flattening code + HTML.c and HTPlain.c, which only use HTStypeNamed(). + + You can in any case override this function in your own code, which will prevent the + HTStyle from being loaded. You will be able to redefine your style structure in this + case without problems, as no other moule needs to know it. + + */ +#ifndef HTStyle_H +#define HTStyle_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTAnchor.h" + +typedef long int HTFont; /* Dummy definition instead */ + +#ifdef SHORT_NAMES +#define HTStyleNew HTStNew +#define HTStyleFree HTStFree +#define HTStyleRead HTStRead +#define HTStyleWrite HTStWrite +#define HTStyleSheetNew HTStShNe +#define HTStyleSheetFree HTStShFr +#define HTStyleNamed HTStName +#define HTStyleForParagraph HTStFoPa +#define HTStyleMatching HTStMatc +#define HTStyleForRun HTStFoRu +#define HTStyleSheetAddStyle HTStShAd +#define HTStyleSheetRemoveStyle HTStShRm +#define HTStyleSheetRead HTStShRe +#define HTStyleSheetWrite HTStShWr +#endif + +#ifdef NeXT_suppressed +#include <appkit/appkit.h> +typedef NXCoord HTCoord; +#define HTParagraphStyle NXTextStyle +#define HTCoord NXCoord +typedef struct _color { + float grey; + int RGBColor; +} HTColor; +#else + +typedef int HTCoord; /* changed from float to int - kw */ + +typedef struct _HTParagraphStyle { + HTCoord left_indent; /* @@@@ junk! etc etc*/ +} HTParagraphStyle; + +typedef int HTColor; /* Sorry about the US spelling! */ + +#endif + + + +#define STYLE_NAME_LENGTH 80 /* @@@@@@@@@@@ */ + +typedef struct { + short kind; /* only NX_LEFTTAB implemented*/ + HTCoord position; /* x coordinate for stop */ +} HTTabStop; + + +/* The Style Structure +** ------------------- +*/ + +typedef struct _HTStyle { + +/* Style management information +*/ + struct _HTStyle *next; /* Link for putting into stylesheet */ + char * name; /* Style name */ + char * SGMLTag; /* Tag name to start */ + + +/* Character attributes (a la NXRun) +*/ + HTFont font; /* Font id */ + HTCoord fontSize; /* The size of font, not independent */ + HTColor color; /* text gray of current run */ + int superscript; /* superscript (-sub) in points */ + + HTAnchor *anchor; /* Anchor id if any, else zero */ + +/* Paragraph Attribtes (a la NXTextStyle) +*/ + HTCoord indent1st; /* how far first line in paragraph is + * indented */ + HTCoord leftIndent; /* how far second line is indented */ + HTCoord rightIndent; /* (Missing from NeXT version */ + short alignment; /* quad justification */ + HTCoord lineHt; /* line height */ + HTCoord descentLine; /* descender bottom from baseline */ + CONST HTTabStop *tabs; /* array of tab stops, 0 terminated */ + + BOOL wordWrap; /* Yes means wrap at space not char */ + BOOL freeFormat; /* Yes means \n is just white space */ + HTCoord spaceBefore; /* Omissions from NXTextStyle */ + HTCoord spaceAfter; + int paraFlags; /* Paragraph flags, bits as follows: */ + +#define PARA_KEEP 1 /* Do not break page within this paragraph */ +#define PARA_WITH_NEXT 2 /* Do not break page after this paragraph */ + +#define HT_JUSTIFY 0 /* For alignment */ +#define HT_LEFT 1 +#define HT_RIGHT 2 +#define HT_CENTER 3 + +} HTStyle; + + +/* Style functions: +*/ +extern HTStyle * HTStyleNew NOPARAMS; +extern HTStyle * HTStyleNewNamed PARAMS ((CONST char * name)); +extern HTStyle * HTStyleFree PARAMS((HTStyle * self)); +#ifdef SUPRESS +extern HTStyle * HTStyleRead PARAMS((HTStyle * self, HTStream * stream)); +extern HTStyle * HTStyleWrite PARAMS((HTStyle * self, HTStream * stream)); +#endif +/* Style Sheet +** ----------- +*/ +typedef struct _HTStyleSheet { + char * name; + HTStyle * styles; +} HTStyleSheet; + + +/* Stylesheet functions: +*/ +extern HTStyleSheet * HTStyleSheetNew NOPARAMS; +extern HTStyleSheet * HTStyleSheetFree PARAMS((HTStyleSheet * self)); +extern HTStyle * HTStyleNamed PARAMS((HTStyleSheet * self, CONST char * name)); +extern HTStyle * HTStyleForParagraph PARAMS((HTStyleSheet * self, + HTParagraphStyle * paraStyle)); +extern HTStyle * HTStyleMatching PARAMS((HTStyleSheet *self, HTStyle * style)); +/* extern HTStyle * HTStyleForRun PARAMS((HTStyleSheet *self, NXRun * run)); */ +extern HTStyleSheet * HTStyleSheetAddStyle PARAMS((HTStyleSheet * self, + HTStyle * style)); +extern HTStyleSheet * HTStyleSheetRemoveStyle PARAMS((HTStyleSheet * self, + HTStyle * style)); +#ifdef SUPPRESS +extern HTStyleSheet * HTStyleSheetRead PARAMS((HTStyleSheet * self, + HTStream * stream)); +extern HTStyleSheet * HTStyleSheetWrite PARAMS((HTStyleSheet * self, + HTStream * stream)); +#endif +#define CLEAR_POINTER ((void *)-1) /* Pointer value means "clear me" */ + +/* DefaultStyle.c */ +extern HTStyleSheet * DefaultStyle NOPARAMS; + +#endif /* HTStyle_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.c new file mode 100644 index 00000000000..dab7ab7373e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.c @@ -0,0 +1,1142 @@ +/* Generic Communication Code HTTCP.c +** ========================== +** +** This code is in common between client and server sides. +** +** 16 Jan 92 TBL Fix strtol() undefined on CMU Mach. +** 25 Jun 92 JFG Added DECNET option through TCP socket emulation. +** 13 Sep 93 MD Added correct return of vmserrorno for HTInetStatus. +** Added decoding of vms error message for MULTINET. +** 7-DEC-1993 Bjorn S. Nilsson, ALEPH, CERN, VMS UCX ioctl() changes +** (done of Mosaic) +** 19 Feb 94 Danny Mayer Added Bjorn Fixes to Lynx version +** 7 Mar 94 Danny Mayer Added Fix UCX version for full domain name +** 20 May 94 Andy Harper Added support for CMU TCP/IP transport +** 17 Nov 94 Andy Harper Added support for SOCKETSHR transport +** 16 Jul 95 S. Bjorndahl added kluge to deal with LIBCMU bug +*/ + +#include "HTUtils.h" +#include "tcp.h" /* Defines SHORT_NAMES if necessary */ +#include "HTAccess.h" +#include "HTParse.h" +#include "HTAlert.h" +#include "HTTCP.h" + +#ifdef NSL_FORK +#include <signal.h> +#include <sys/wait.h> +#endif /* NSL_FORK */ + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern int HTCheckForInterrupt NOPARAMS; + +#ifdef SVR4_BSDSELECT +PUBLIC int BSDselect PARAMS(( + int nfds, + fd_set * readfds, + fd_set * writefds, + fd_set * exceptfds, + struct timeval * timeout)); +#ifdef select +#undef select +#endif /* select */ +#define select BSDselect +#ifdef SOCKS +#ifdef Rselect +#undef Rselect +#endif /* Rselect */ +#define Rselect BSDselect +#endif /* SOCKS */ +#endif /* SVR4_BSDSELECT */ + +#include "LYLeaks.h" + +#ifdef SHORT_NAMES +#define HTInetStatus HTInStat +#define HTInetString HTInStri +#define HTParseInet HTPaInet +#endif /* SHORT_NAMES */ + +#ifndef FD_SETSIZE +#if defined(UCX) || defined(SOCKETSHR_TCP) || defined(CMU_TCP) +#define FD_SETSIZE 32 +#else +#define FD_SETSIZE 256 +#endif /* Limit # sockets to 32 for UCX, BSN - also SOCKETSHR and CMU, AH */ +#endif /* FD_SETSIZE */ + +/* +** Module-Wide variables +*/ +PRIVATE char *hostname = NULL; /* The name of this host */ + +/* +** PUBLIC VARIABLES +*/ +#ifdef SOCKS +extern BOOLEAN socks_flag; +PUBLIC unsigned long socks_bind_remoteAddr; /* for long Rbind */ +#endif /* SOCKS */ + +/* PUBLIC SockA HTHostAddress; */ /* The internet address of the host */ + /* Valid after call to HTHostName() */ + +/* Encode INET status (as in sys/errno.h) inet_status() +** ------------------ +** +** On entry, +** where gives a description of what caused the error +** global errno gives the error number in the Unix way. +** +** On return, +** returns a negative status in the Unix way. +*/ +#ifndef PCNFS + +#ifdef VMS +#include <perror.h> +#ifndef errno +extern int errno; +#endif /* !errno */ +#endif /* VMS */ + +#ifndef VM +#ifndef VMS +#ifndef THINK_C + +#ifdef DECL_SYS_ERRLIST +extern char *sys_errlist[]; /* see man perror on cernvax */ +extern int sys_nerr; +#endif /* DECL_SYS_ERRLIST */ + +#endif /* !THINK_C */ +#endif /* !VMS */ +#endif /* !VM */ + +#endif /* !PCNFS */ + +#if defined(VMS) && defined(UCX) +/* +** A routine to mimic the ioctl function for UCX. +** Bjorn S. Nilsson, 25-Nov-1993. Based on an example in the UCX manual. +*/ +#include <iodef.h> +#define IOC_OUT (int)0x40000000 +extern int vaxc$get_sdc(), sys$qiow(); + +PUBLIC int HTioctl ARGS3( + int, d, + int, request, + int *, argp) +{ + int sdc, status; + unsigned short fun, iosb[4]; + char *p5, *p6; + struct comm { + int command; + char *addr; + } ioctl_comm; + struct it2 { + unsigned short len; + unsigned short opt; + struct comm *addr; + } ioctl_desc; + + if ((sdc = vaxc$get_sdc (d)) == 0) { + errno = EBADF; + return -1; + } + ioctl_desc.opt = UCX$C_IOCTL; + ioctl_desc.len = sizeof(struct comm); + ioctl_desc.addr = &ioctl_comm; + if (request & IOC_OUT) { + fun = IO$_SENSEMODE; + p5 = 0; + p6 = (char *)&ioctl_desc; + } else { + fun = IO$_SETMODE; + p5 = (char *)&ioctl_desc; + p6 = 0; + } + ioctl_comm.command = request; + ioctl_comm.addr = (char *)argp; + status = sys$qiow (0, sdc, fun, iosb, 0, 0, 0, 0, 0, 0, p5, p6); + if (!(status & 01)) { + errno = status; + return -1; + } + if (!(iosb[0] & 01)) { + errno = iosb[0]; + return -1; + } + return 0; +} +#endif /* VMS && UCX */ + +/* Report Internet Error +** --------------------- +*/ +PUBLIC int HTInetStatus ARGS1( + char *, where) +{ +#ifdef VMS +#ifdef MULTINET + SOCKET_ERRNO = vmserrno; +#endif /* MULTINET */ +#endif /* VMS */ + + CTRACE(tfp, + "TCP: Error %d in `SOCKET_ERRNO' after call to %s() failed.\n\t%s\n", + SOCKET_ERRNO, where, + /* third arg is transport/platform specific */ +#ifdef VM + "(Error number not translated)"); /* What Is the VM equiv? */ +#define ER_NO_TRANS_DONE +#endif /* VM */ + +#ifdef VMS +#ifdef MULTINET + vms_errno_string()); +#else + ((SOCKET_ERRNO > 0 && SOCKET_ERRNO <= 65) ? + strerror(SOCKET_ERRNO) : "(Error number not translated)")); +#endif /* MULTINET */ +#define ER_NO_TRANS_DONE +#endif /* VMS */ + +#ifdef HAVE_STRERROR + strerror(SOCKET_ERRNO)); +#define ER_NO_TRANS_DONE +#endif /* HAVE_STRERROR */ + +#ifndef ER_NO_TRANS_DONE + (SOCKET_ERRNO < sys_nerr ? + sys_errlist[SOCKET_ERRNO] : "Unknown error" )); +#endif /* !ER_NO_TRANS_DONE */ + +#ifdef VMS +#ifndef MULTINET + CTRACE(tfp, + " Unix error number (SOCKET_ERRNO) = %ld dec\n", + SOCKET_ERRNO); + CTRACE(tfp, + " VMS error (vaxc$errno) = %lx hex\n", + vaxc$errno); +#endif /* MULTINET */ +#endif /* VMS */ + +#ifdef VMS + /* + ** uerrno and errno happen to be zero if vmserrno <> 0 + */ +#ifdef MULTINET + return -vmserrno; +#else + return -vaxc$errno; +#endif /* MULTINET */ +#else + return -SOCKET_ERRNO; +#endif /* VMS */ +} + +/* Parse a cardinal value parse_cardinal() +** ---------------------- +** +** On entry, +** *pp points to first character to be interpreted, terminated by +** non 0:9 character. +** *pstatus points to status already valid +** maxvalue gives the largest allowable value. +** +** On exit, +** *pp points to first unread character +** *pstatus points to status updated iff bad +*/ +PUBLIC unsigned int HTCardinal ARGS3( + int *, pstatus, + char **, pp, + unsigned int, max_value) +{ + unsigned int n; + if ((**pp<'0') || (**pp>'9')) { /* Null string is error */ + *pstatus = -3; /* No number where one expected */ + return 0; + } + + n = 0; + while ((**pp >= '0') && (**pp <= '9')) + n = n*10 + *((*pp)++) - '0'; + + if (n > max_value) { + *pstatus = -4; /* Cardinal outside range */ + return 0; + } + + return n; +} + +#ifndef DECNET /* Function only used below for a trace message */ +/* Produce a string for an Internet address +** ---------------------------------------- +** +** On exit, +** returns a pointer to a static string which must be copied if +** it is to be kept. +*/ +PUBLIC CONST char * HTInetString ARGS1( + SockA*, soc_in) +{ + static char string[16]; + sprintf(string, "%d.%d.%d.%d", + (int)*((unsigned char *)(&soc_in->sin_addr)+0), + (int)*((unsigned char *)(&soc_in->sin_addr)+1), + (int)*((unsigned char *)(&soc_in->sin_addr)+2), + (int)*((unsigned char *)(&soc_in->sin_addr)+3)); + return string; +} +#endif /* !DECNET */ + +/* Parse a network node address and port +** ------------------------------------- +** +** On entry, +** str points to a string with a node name or number, +** with optional trailing colon and port number. +** soc_in points to the binary internet or decnet address field. +** +** On exit, +** *soc_in is filled in. If no port is specified in str, that +** field is left unchanged in *soc_in. +*/ +PUBLIC int HTParseInet ARGS2( + SockA *, soc_in, + CONST char *, str) +{ + char *port; + char *host = NULL; + int dotcount_ip = 0; /* for dotted decimal IP addr */ + struct hostent *phost; /* Pointer to host - See netdb.h */ + + if (!str) { + if (TRACE) { + fprintf(stderr, "HTParseInet: Can't parse `NULL'.\n"); + } + return -1; + } + if (HTCheckForInterrupt()) { + if (TRACE) { + fprintf (stderr, "HTParseInet: INTERRUPTED for '%s'.\n", str); + } + return -1; + } + StrAllocCopy(host, str); /* Make a copy we can mutilate */ + + /* + ** Parse port number if present. + */ + if ((port = strchr(host, ':')) != NULL) { + *port++ = 0; /* Chop off port */ + if (port[0] >= '0' && port[0] <= '9') { +#ifdef unix + soc_in->sin_port = htons(atol(port)); +#else /* VMS: */ +#ifdef DECNET + soc_in->sdn_objnum = (unsigned char)(strtol(port, (char**)0, 10)); +#else + soc_in->sin_port = htons((unsigned short)strtol(port,(char**)0,10)); +#endif /* Decnet */ +#endif /* Unix vs. VMS */ +#ifdef SUPPRESS /* 1. crashes!?!. 2. Not recommended */ + } else { + struct servent * serv = getservbyname(port, (char*)0); + if (serv) { + soc_in->sin_port = serv->s_port; + } else if (TRACE) { + fprintf(stderr, "TCP: Unknown service %s\n", port); + } +#endif /* SUPPRESS */ + } + } + +#ifdef DECNET + /* + ** Read Decnet node name. @@ Should know about DECnet addresses, but + ** it's probably worth waiting until the Phase transition from IV to V. + */ + soc_in->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */ + strncpy(soc_in->sdn_nam.n_name, host, soc_in->sdn_nam.n_len + 1); + if (TRACE) { + fprintf(stderr, + "DECnet: Parsed address as object number %d on host %.6s...\n", + soc_in->sdn_objnum, host); + } +#else /* parse Internet host: */ + + if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */ + char *strptr = host; + while (*strptr) { + if (*strptr == '.') { + dotcount_ip++; + } else if (!isdigit(*strptr)) { + break; + } + strptr++; + } + if (*strptr) { /* found non-numeric, assume domain name */ + dotcount_ip = 0; + } + } + + /* + ** Parse host number if present. + */ + if (dotcount_ip == 3) { /* Numeric node address: */ + +#ifdef DJGPP + soc_in->sin_addr.s_addr = htonl(aton(host)); +#else +#ifdef DGUX_OLD + soc_in->sin_addr.s_addr = inet_addr(host).s_addr; /* See arpa/inet.h */ +#else +#ifdef GUSI + soc_in->sin_addr = inet_addr(host); /* See netinet/in.h */ +#else + soc_in->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */ +#endif /* GUSI */ +#endif /* DGUX_OLD */ +#endif /* DJGPP */ + FREE(host); + } else { /* Alphanumeric node name: */ +#ifdef MVS /* Outstanding problem with crash in MVS gethostbyname */ + if (TRACE) { + fprintf(stderr, + "HTParseInet: Calling gethostbyname(%s)\n", host); + } +#endif /* MVS */ + +#ifdef NSL_FORK + /* + ** Start block for fork-based gethostbyname() with + ** checks for interrupts. - Tom Zerucha (tz@execpc.com) & FM + */ + { + /* + ** Pipe, child pid, and status buffers. + */ + pid_t fpid, waitret = (pid_t)0; + int pfd[2], cstat, cst1 = 0; + + pipe(pfd); + + if ((fpid = fork()) == 0 ) { + /* + ** Child - for the long call. + */ + phost = gethostbyname(host); + cst1 = 0; + /* + ** Return value (or nulls). + */ + if (phost != NULL) + write(pfd[1], phost->h_addr, phost->h_length); + else + write(pfd[1], &cst1, 4); + /* + ** Return an error code. + */ + _exit(phost == NULL); + } + + /* + ** (parent) Wait until lookup finishes, or interrupt. + */ + cstat = 0; + while (cstat <= 0) { + /* + ** Exit when data sent. + */ + IOCTL(pfd[0], FIONREAD, &cstat); + if (cstat > 0) + break; + /* + ** Exit if child exited. + */ + if ((waitret = waitpid(fpid, &cst1, WNOHANG)) > 0) { + break; + } + /* + ** Abort if interrupt key pressed. + */ + if (HTCheckForInterrupt()) { + if (TRACE) { + fprintf(stderr, + "HTParseInet: INTERRUPTED gethostbyname.\n"); + } + kill(fpid , SIGKILL); + waitpid(fpid, NULL, 0); + FREE(host); + close(pfd[0]); + close(pfd[1]); + return HT_INTERRUPTED; + } + /* + ** Be nice to the system. + */ + sleep(1); + } + if (waitret <= 0) { + waitret = waitpid(fpid, &cst1, WNOHANG); + } + if (TRACE) { + if (WIFEXITED(cst1)) { + fprintf(stderr, + "HTParseInet: NSL_FORK child %d exited, status 0x%x.\n", + (int)waitret, cst1); + } else if (WIFSIGNALED(cst1)) { + fprintf(stderr, + "HTParseInet: NSL_FORK child %d got signal, status 0x%x!\n", + (int)waitret, cst1); +#ifdef WCOREDUMP + if (WCOREDUMP(cst1)) { + fprintf(stderr, + "HTParseInet: NSL_FORK child %d dumped core!\n", + (int)waitret); + } +#endif /* WCOREDUMP */ + } else if (WIFSTOPPED(cst1)) { + fprintf(stderr, + "HTParseInet: NSL_FORK child %d is stopped, status 0x%x!\n", + (int)waitret, cst1); + } + } + /* + ** Read as much as we can - should be the address. + */ + IOCTL(pfd[0], FIONREAD, &cstat); + if (cstat < 4) { + if (TRACE) { + fprintf(stderr, + "HTParseInet: NSL_FORK child returns only %d bytes.\n", + cstat); + fprintf(stderr, + " Trying again without forking.\n"); + } + phost = gethostbyname(host); /* See netdb.h */ + if (!phost) { + if (TRACE) { + fprintf(stderr, + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } + memset((void *)&soc_in->sin_addr, 0, sizeof(soc_in->sin_addr)); + } else { + memcpy((void *)&soc_in->sin_addr, + phost->h_addr, phost->h_length); + } +#ifdef NOTDEFINED + cstat = read(pfd[0], (void *)&soc_in->sin_addr , 4); +#endif /* NOTDEFINED */ + } else { + cstat = read(pfd[0], (void *)&soc_in->sin_addr , cstat); + } + close(pfd[0]); + close(pfd[1]); + } + if (soc_in->sin_addr.s_addr == 0) { + if (TRACE) { + fprintf(stderr, + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } + FREE(host); + return -1; + } + FREE(host); +#ifdef MVS + if (TRACE) { + fprintf(stderr, + "HTParseInet: gethostbyname() returned %d\n", phost); + } +#endif /* MVS */ + +#else /* Not NSL_FORK: */ +#ifdef DJGPP + soc_in->sin_addr.s_addr = htonl(resolve(host)); + FREE(host); + if (soc_in->sin_addr.s_addr == 0) { + if (TRACE) + fprintf(stderr, + "HTTPAccess: Can't find internet node name `%s'.\n",host); + return -1; /* Fail? */ + } +#else + phost = gethostbyname(host); /* See netdb.h */ +#ifdef MVS + if (TRACE) { + fprintf(stderr, + "HTParseInet: gethostbyname() returned %d\n", phost); + } +#endif /* MVS */ + if (!phost) { + if (TRACE) { + fprintf(stderr, + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } + FREE(host); + return -1; /* Fail? */ + } + FREE(host); +#if defined(VMS) && defined(CMU_TCP) + /* + ** In LIBCMU, phost->h_length contains not the length of one address + ** (four bytes) but the number of bytes in *h_addr, i.e. some multiple + ** of four. Thus we need to hard code the value here, and remember to + ** change it if/when IP addresses change in size. :-( LIBCMU is no + ** longer supported, and CMU users are encouraged to obtain and use + ** SOCKETSHR/NETLIB instead. - S. Bjorndahl + */ + memcpy((void *)&soc_in->sin_addr, phost->h_addr, 4); +#else + memcpy((void *)&soc_in->sin_addr, phost->h_addr, phost->h_length); +#endif /* VMS && CMU_TCP */ +#endif /* DJGPP */ +#endif /* NSL_FORK */ + } + + if (TRACE) { + fprintf(stderr, + "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n", + (int)ntohs(soc_in->sin_port), + (int)*((unsigned char *)(&soc_in->sin_addr)+0), + (int)*((unsigned char *)(&soc_in->sin_addr)+1), + (int)*((unsigned char *)(&soc_in->sin_addr)+2), + (int)*((unsigned char *)(&soc_in->sin_addr)+3)); + } +#endif /* Internet vs. Decnet */ + + return 0; /* OK */ +} + +/* Free our name for the host on which we are - FM +** ------------------------------------------- +** +*/ +PRIVATE void free_HTTCP_hostname NOARGS +{ + FREE(hostname); +} + +/* Derive the name of the host on which we are +** ------------------------------------------- +** +*/ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 /* Arbitrary limit */ +#endif /* MAXHOSTNAMELEN */ + +PRIVATE void get_host_details NOARGS +{ + char name[MAXHOSTNAMELEN+1]; /* The name of this host */ +#ifdef UCX + char *domain_name; /* The name of this host domain */ +#endif /* UCX */ +#ifdef NEED_HOST_ADDRESS /* no -- needs name server! */ + struct hostent * phost; /* Pointer to host -- See netdb.h */ +#endif /* NEED_HOST_ADDRESS */ + int namelength = sizeof(name); + + if (hostname) + return; /* Already done */ + gethostname(name, namelength); /* Without domain */ + StrAllocCopy(hostname, name); + atexit(free_HTTCP_hostname); +#ifdef UCX + /* + ** UCX doesn't give the complete domain name. + ** Get rest from UCX$BIND_DOM logical. + */ + if (strchr(hostname,'.') == NULL) { /* Not full address */ + domain_name = getenv("UCX$BIND_DOMAIN"); + if (domain_name != NULL) { + StrAllocCat(hostname, "."); + StrAllocCat(hostname, domain_name); + } + } +#endif /* UCX */ + CTRACE(tfp, "TCP: Local host name is %s\n", hostname); + +#ifndef DECNET /* Decnet ain't got no damn name server 8#OO */ +#ifdef NEED_HOST_ADDRESS /* no -- needs name server! */ + phost = gethostbyname(name); /* See netdb.h */ + if (!phost) { + if (TRACE) fprintf(stderr, + "TCP: Can't find my own internet node address for `%s'!!\n", + name); + return; /* Fail! */ + } + StrAllocCopy(hostname, phost->h_name); + memcpy(&HTHostAddress, &phost->h_addr, phost->h_length); + if (TRACE) fprintf(stderr, " Name server says that I am `%s' = %s\n", + hostname, HTInetString(&HTHostAddress)); +#endif /* NEED_HOST_ADDRESS */ + +#endif /* !DECNET */ +} + +PUBLIC CONST char * HTHostName NOARGS +{ + get_host_details(); + return hostname; +} + +/* +** Interruptable connect as implemented for Mosaic by Marc Andreesen +** and hacked in for Lynx years ago by Lou Montulli, and further +** modified over the years by numerous Lynx lovers. - FM +*/ +PUBLIC int HTDoConnect ARGS4( + CONST char *, url, + char *, protocol, + int, default_port, + int *, s) +{ + struct sockaddr_in soc_address; + struct sockaddr_in *soc_in = &soc_address; + int status; + char *line = NULL; + char *p1 = NULL; + char *at_sign = NULL; + char *host = NULL; + + /* + ** Set up defaults. + */ + soc_in->sin_family = AF_INET; + soc_in->sin_port = htons(default_port); + + /* + ** Get node name and optional port number. + */ + p1 = HTParse(url, "", PARSE_HOST); + if ((at_sign = strchr(p1, '@')) != NULL) { + /* + ** If there's an @ then use the stuff after it as a hostname. + */ + StrAllocCopy(host, (at_sign + 1)); + } else { + StrAllocCopy(host, p1); + } + FREE(p1); + + line = (char *)calloc(1, (strlen(host) + strlen(protocol) + 128)); + if (line == NULL) + outofmem(__FILE__, "HTDoConnect"); + sprintf (line, "Looking up %s.", host); + _HTProgress (line); + status = HTParseInet(soc_in, host); + if (status) { + if (status != HT_INTERRUPTED) { + sprintf (line, "Unable to locate remote host %s.", host); + _HTProgress(line); + status = HT_NO_DATA; + } + FREE(host); + FREE(line); + return status; + } + + sprintf (line, "Making %s connection to %s.", protocol, host); + _HTProgress (line); + FREE(host); + + /* + ** Now, let's get a socket set up from the server for the data. + */ + *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (*s == -1) { + HTAlert("socket failed."); + FREE(line); + return HT_NO_DATA; + } + +#ifndef DOSPATH +#if !defined(NO_IOCTL) || defined(USE_FCNTL) + /* + ** Make the socket non-blocking, so the connect can be canceled. + ** This means that when we issue the connect we should NOT + ** have to wait for the accept on the other end. + */ + { +#ifdef USE_FCNTL + int ret = fcntl(*s, F_SETFL, O_NONBLOCK); +#else + int val = 1; + int ret = IOCTL(*s, FIONBIO, &val); +#endif /* USE_FCNTL */ + if (ret == -1) + _HTProgress("Could not make connection non-blocking."); + } +#endif /* !NO_IOCTL || USE_FCNTL */ +#endif /* !DOSPATH */ + + /* + ** Issue the connect. Since the server can't do an instantaneous + ** accept and we are non-blocking, this will almost certainly return + ** a negative status. + */ +#ifdef SOCKS + if (socks_flag) { + status = Rconnect(*s, (struct sockaddr*)&soc_address, + sizeof(soc_address)); + /* + ** For long Rbind. + */ + socks_bind_remoteAddr = soc_address.sin_addr.s_addr; + } else +#endif /* SOCKS */ + status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address)); +#ifndef DJGPP + /* + ** According to the Sun man page for connect: + ** EINPROGRESS The socket is non-blocking and the con- + ** nection cannot be completed immediately. + ** It is possible to select(2) for comple- + ** tion by selecting the socket for writ- + ** ing. + ** According to the Motorola SVR4 man page for connect: + ** EAGAIN The socket is non-blocking and the con- + ** nection cannot be completed immediately. + ** It is possible to select for completion + ** by selecting the socket for writing. + ** However, this is only possible if the + ** socket STREAMS module is the topmost + ** module on the protocol stack with a + ** write service procedure. This will be + ** the normal case. + */ + if ((status < 0) && + (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EAGAIN)) { + struct timeval timeout; + int ret; + int tries=0; + + ret = 0; + while (ret <= 0) { + fd_set writefds; + + /* + ** Protect against an infinite loop. + */ + if (tries++ >= 180000) { + HTAlert("Connection failed for 180,000 tries."); + FREE(line); + return HT_NO_DATA; + } + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + FD_ZERO(&writefds); + FD_SET(*s, &writefds); +#ifdef SOCKS + if (socks_flag) + ret = Rselect(FD_SETSIZE, NULL, + (void *)&writefds, NULL, &timeout); + else +#endif /* SOCKS */ + ret = select(FD_SETSIZE, NULL, (void *)&writefds, NULL, &timeout); + + /* + ** If we suspend, then it is possible that select will be + ** interrupted. Allow for this possibility. - JED + */ + if ((ret == -1) && (errno == EINTR)) + continue; + + /* + ** Again according to the Sun and Motorola man pages for connect: + ** EALREADY The socket is non-blocking and a previ- + ** ous connection attempt has not yet been + ** completed. + ** Thus if the SOCKET_ERRNO is NOT EALREADY we have a real error, + ** and should break out here and return that error. + ** Otherwise if it is EALREADY keep on trying to complete the + ** connection. + */ + if ((ret < 0) && (SOCKET_ERRNO != EALREADY)) { + status = ret; + break; + } else if (ret > 0) { + /* + ** Extra check here for connection success, if we try to + ** connect again, and get EISCONN, it means we have a + ** successful connection. But don't check with SOCKS. + */ +#ifdef SOCKS + if (socks_flag) { + status = 0; + } else { +#endif /* SOCKS */ + status = connect(*s, (struct sockaddr*)&soc_address, + sizeof(soc_address)); +#ifdef UCX + /* + ** A UCX feature: Instead of returning EISCONN + ** UCX returns EADDRINUSE. + ** Test for this status also. + */ + if ((status < 0) && ((SOCKET_ERRNO == EISCONN) || + (SOCKET_ERRNO == EADDRINUSE))) +#else + if ((status < 0) && (SOCKET_ERRNO == EISCONN)) +#endif /* UCX */ + { + status = 0; + } + + if (status && (SOCKET_ERRNO == EALREADY)) /* new stuff LJM */ + ret = 0; /* keep going */ + else + break; +#ifdef SOCKS + } +#endif /* SOCKS */ + } +#ifdef SOCKS + else if (!socks_flag) +#else + else +#endif /* SOCKS */ + { + /* + ** The select says we aren't ready yet. Try to connect + ** again to make sure. If we don't get EALREADY or EISCONN, + ** something has gone wrong. Break out and report it. + ** + ** For some reason, SVR4 returns EAGAIN here instead of + ** EALREADY, even though the man page says it should be + ** EALREADY. + ** + ** For some reason, UCX pre 3 apparently returns + ** errno = 18242 instead the EALREADY or EISCONN. + */ + status = connect(*s, (struct sockaddr*)&soc_address, + sizeof(soc_address)); + if ((status < 0) && + (SOCKET_ERRNO != EALREADY && SOCKET_ERRNO != EAGAIN) && +#ifdef UCX + (SOCKET_ERRNO != 18242) && +#endif /* UCX */ + (SOCKET_ERRNO != EISCONN)) { + break; + } + } + if (HTCheckForInterrupt()) { + if (TRACE) + fprintf(stderr, "*** INTERRUPTED in middle of connect.\n"); + status = HT_INTERRUPTED; + SOCKET_ERRNO = EINTR; + break; + } + } + } +#endif /* !DJGPP */ + if (status < 0) { + /* + ** The connect attempt failed or was interrupted, + ** so close up the socket. + */ + NETCLOSE(*s); + } +#ifndef DOSPATH +#if !defined(NO_IOCTL) || defined(USE_FCNTL) + else { + /* + ** Make the socket blocking again on good connect. + */ +#ifdef USE_FCNTL + int ret = fcntl(*s, F_SETFL, 0); +#else + int val = 0; + int ret = IOCTL(*s, FIONBIO, &val); +#endif /* USE_FCNTL */ + if (ret == -1) + _HTProgress("Could not restore socket to blocking."); + } +#endif /* !NO_IOCTL || USE_FCNTL */ +#endif /* !DOSPATH */ + + FREE(line); + return status; +} + +/* +** This is so interruptible reads can be implemented cleanly. +*/ +PUBLIC int HTDoRead ARGS3( + int, fildes, + void *, buf, + unsigned, nbyte) +{ + int ready, ret; + fd_set readfds; + struct timeval timeout; + int tries=0; +#ifdef UCX + int nb; +#endif /* UCX, BSN */ + + if (fildes <= 0) + return -1; + + if (HTCheckForInterrupt()) { + SOCKET_ERRNO = EINTR; + return (HT_INTERRUPTED); + } + +#if !defined(NO_IOCTL) + ready = 0; +#else + ready = 1; +#endif /* bypass for NO_IOCTL */ + while (!ready) { + /* + ** Protect against an infinite loop. + */ + if (tries++ >= 180000) { + HTAlert("Socket read failed for 180,000 tries."); + SOCKET_ERRNO = EINTR; + return HT_INTERRUPTED; + } + + /* + ** If we suspend, then it is possible that select will be + ** interrupted. Allow for this possibility. - JED + */ + do { + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + FD_ZERO(&readfds); + FD_SET(fildes, &readfds); +#ifdef SOCKS + if (socks_flag) + ret = Rselect(FD_SETSIZE, + (void *)&readfds, NULL, NULL, &timeout); + else +#endif /* SOCKS */ + ret = select(FD_SETSIZE, + (void *)&readfds, NULL, NULL, &timeout); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + return -1; + } else if (ret > 0) { + ready = 1; + } else if (HTCheckForInterrupt()) { + SOCKET_ERRNO = EINTR; + return HT_INTERRUPTED; + } + } + +#if !defined(UCX) || !defined(VAXC) + return SOCKET_READ (fildes, buf, nbyte); +#else + /* + ** VAXC and UCX problem only. + */ + errno = vaxc$errno = 0; + nb = SOCKET_READ (fildes, buf, nbyte); + CTRACE(tfp, + "Read - nb,errno,vaxc$errno: %d %d %d\n", nb,errno,vaxc$errno); + if ((nb <= 0) && TRACE) + perror ("HTTCP.C:HTDoRead:read"); /* RJF */ + /* + ** An errno value of EPIPE and nb < 0 indicates end-of-file on VAXC. + */ + if ((nb <= 0) && (errno == EPIPE)) { + nb = 0; + errno = 0; + } + return nb; +#endif /* UCX, BSN */ +} + +#ifdef SVR4_BSDSELECT +/* +** This is a fix for the difference between BSD's select() and +** SVR4's select(). SVR4's select() can never return a value larger +** than the total number of file descriptors being checked. So, if +** you select for read and write on one file descriptor, and both +** are true, SVR4 select() will only return 1. BSD select in the +** same situation will return 2. +** +** Additionally, BSD select() on timing out, will zero the masks, +** while SVR4 does not. This is fixed here as well. +** +** Set your tabstops to 4 characters to have this code nicely formatted. +** +** Jerry Whelan, guru@bradley.edu, June 12th, 1993 +*/ +#ifdef select +#undef select +#endif /* select */ + +#ifdef SOCKS +#ifdef Rselect +#undef Rselect +#endif /* Rselect */ +#endif /* SOCKS */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/select.h> + +PUBLIC int BSDselect ARGS5( + int, nfds, + fd_set *, readfds, + fd_set *, writefds, + fd_set *, exceptfds, + struct timeval *, timeout) +{ + int rval, + i; + +#ifdef SOCKS + if (socks_flag) + rval = Rselect(nfds, readfds, writefds, exceptfds, timeout); + else +#endif /* SOCKS */ + rval = select(nfds, readfds, writefds, exceptfds, timeout); + + switch (rval) { + case -1: + return(rval); + break; + + case 0: + if (readfds != NULL) + FD_ZERO(readfds); + if (writefds != NULL) + FD_ZERO(writefds); + if (exceptfds != NULL) + FD_ZERO(exceptfds); + return(rval); + break; + + default: + for (i = 0, rval = 0; i < nfds; i++) { + if ((readfds != NULL) && FD_ISSET(i, readfds)) + rval++; + if ((writefds != NULL) && FD_ISSET(i, writefds)) + rval++; + if ((exceptfds != NULL) && FD_ISSET(i, exceptfds)) + rval++; + + } + return(rval); + } +/* Should never get here */ +} +#endif /* SVR4_BSDSELECT */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.h new file mode 100644 index 00000000000..b4dab1d6d88 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.h @@ -0,0 +1,120 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/src/HTTCP.html + GENERIC TCP/IP COMMUNICATION + + This module has the common code for handling TCP/IP connections etc. + + */ +#ifndef HTTCP_H +#define HTTCP_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "tcp.h" + +#ifdef SHORT_NAMES +#define HTInetStatus HTInStat +#define HTInetString HTInStri +#define HTParseInet HTPaInet +#endif + + +/* Produce a string for an internet address +** --------------------------------------- +** +** On exit: +** returns a pointer to a static string which must be copied if +** it is to be kept. +*/ +#ifndef _WINDOWS +#ifdef __STDC__ + extern const char * HTInetString(struct sockaddr_in* mysin); +#else + extern char * HTInetString(); +#endif +#endif + + +/* Encode INET status (as in sys/errno.h) inet_status() +** ------------------ +** +** On entry: +** where gives a description of what caused the error +** global errno gives the error number in the unix way. +** +** On return: +** returns a negative status in the unix way. +*/ +#ifdef __STDC__ + extern int HTInetStatus(char *where); +#else + extern int HTInetStatus(); +#endif + +/* Publicly accessible variables +*/ +/* extern struct sockaddr_in HTHostAddress; */ + /* The internet address of the host */ + /* Valid after call to HTHostName() */ + + +/* Parse a cardinal value parse_cardinal() +** ---------------------- +** +** On entry: +** *pp points to first character to be interpreted, terminated by +** non 0..9 character. +** *pstatus points to status already valid, +** maxvalue gives the largest allowable value. +** +** On exit: +** *pp points to first unread character, +** *pstatus points to status updated iff bad +*/ + +extern unsigned int HTCardinal PARAMS((int *pstatus, + char **pp, + unsigned int max_value)); + + +/* Parse an internet node address and port +** --------------------------------------- +** +** On entry: +** str points to a string with a node name or number, +** with optional trailing colon and port number. +** sin points to the binary internet or decnet address field. +** +** On exit: +** *sin is filled in. If no port is specified in str, that +** field is left unchanged in *sin. +*/ +#ifdef __STDC__ + extern int HTParseInet(struct sockaddr_in * mysin, CONST char * str); + /*!! had to change this to get it to compile. CTB */ +#else + extern int HTParseInet(); +#endif + +/* Get Name of This Machine +** ------------------------ +** +*/ + +extern CONST char * HTHostName NOPARAMS; + +extern int HTDoConnect PARAMS(( + CONST char * url, + char * protocol, + int default_port, + int * s)); + +extern int HTDoRead PARAMS(( + int fildes, + void * buf, + unsigned nbyte)); + +#endif /* HTTCP_H */ +/* + + End. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c new file mode 100644 index 00000000000..d13549110d0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c @@ -0,0 +1,1854 @@ +/* HyperText Tranfer Protocol - Client implementation HTTP.c +** ========================== +** Modified: +** 27 Jan 1994 PDM Added Ari Luotonen's Fix for Reload when using proxy +** servers. +** 28 Apr 1997 AJL,FM Do Proxy Authorisation. +*/ + +#include "HTUtils.h" +#include "tcp.h" + +#include "HTTP.h" + +#define HTTP_VERSION "HTTP/1.0" + +#define HTTP_PORT 80 +#define HTTPS_PORT 443 +#define SNEWS_PORT 563 + +#define INIT_LINE_SIZE 1024 /* Start with line buffer this big */ +#define LINE_EXTEND_THRESH 256 /* Minimum read size */ +#define VERSION_LENGTH 20 /* for returned protocol version */ + +#include "HTParse.h" +#include "HTTCP.h" +#include "HTFormat.h" +#include "HTFile.h" +#include <ctype.h> +#include "HTAlert.h" +#include "HTMIME.h" +#include "HTML.h" +#include "HTInit.h" +#include "HTAABrow.h" + +#include "LYGlobalDefs.h" +#include "LYLeaks.h" + +/* #define TRACE 1 */ + +struct _HTStream +{ + HTStreamClass * isa; +}; + +extern char * HTAppName; /* Application name: please supply */ +extern char * HTAppVersion; /* Application version: please supply */ +extern char * personal_mail_address; /* User's name/email address */ +extern char * LYUserAgent; /* Lynx User-Agent string */ +extern BOOL LYNoRefererHeader; /* Never send Referer header? */ +extern BOOL LYNoRefererForThis; /* No Referer header for this URL? */ +extern BOOL LYNoFromHeader; /* Never send From header? */ +extern BOOL LYSetCookies; /* Act on Set-Cookie headers? */ + +extern BOOL using_proxy; /* Are we using an HTTP gateway? */ +PUBLIC BOOL reloading = FALSE; /* Reloading => send no-cache pragma to proxy */ +PUBLIC char * redirecting_url = NULL; /* Location: value. */ +PUBLIC BOOL permanent_redirection = FALSE; /* Got 301 status? */ +PUBLIC BOOL redirect_post_content = FALSE; /* Don't convert to GET? */ + +extern char LYUserSpecifiedURL; /* Is the URL a goto? */ + +extern BOOL keep_mime_headers; /* Include mime headers and force source dump */ +extern BOOL no_url_redirection; /* Don't follow Location: URL for */ +extern char *http_error_file; /* Store HTTP status code in this file */ +extern BOOL traversal; /* TRUE if we are doing a traversal */ +extern BOOL dump_output_immediately; /* TRUE if no interactive user */ + +extern char * HTLoadedDocumentURL NOPARAMS; +extern int HTCheckForInterrupt NOPARAMS; +extern void LYSetCookie PARAMS(( + CONST char * SetCookie, + CONST char * SetCookie2, + CONST char * address)); +extern char * LYCookie PARAMS(( + CONST char * hostname, + CONST char * path, + int port, + BOOL secure)); + +#define HTTP_NETREAD(a, b, c, d) NETREAD(a, b, c) +#define HTTP_NETWRITE(a, b, c, d) NETWRITE(a, b, c) +#define HTTP_NETCLOSE(a, b) (void)NETCLOSE(a) + + +/* Load Document from HTTP Server HTLoadHTTP() +** ============================== +** +** Given a hypertext address, this routine loads a document. +** +** +** On entry, +** arg is the hypertext reference of the article to be loaded. +** +** On exit, +** returns >=0 If no error, a good socket number +** <0 Error. +** +** The socket must be closed by the caller after the document has been +** read. +** +*/ +PRIVATE int HTLoadHTTP ARGS4 ( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) +{ + int s; /* Socket number for returned data */ + CONST char *url = arg; /* The URL which get_physical() returned */ + char *command = NULL; /* The whole command */ + char *eol; /* End of line if found */ + char *start_of_data; /* Start of body of reply */ + int status; /* tcp return */ + int bytes_already_read; + char crlf[3]; /* A CR LF equivalent string */ + HTStream *target; /* Unconverted data */ + HTFormat format_in; /* Format arriving in the message */ + BOOL do_head = FALSE; /* Whether or not we should do a head */ + BOOL do_post = FALSE; /* ARE WE posting ? */ + char *METHOD; + + BOOL had_header; /* Have we had at least one header? */ + char *line_buffer; + char *line_kept_clean; + BOOL extensions; /* Assume good HTTP server */ + char line[INIT_LINE_SIZE]; + char temp[80]; + BOOL first_Accept = TRUE; + BOOL show_401 = FALSE; + BOOL show_407 = FALSE; + BOOL auth_proxy = NO; /* Generate a proxy authorization. - AJL */ + + int length, rv; + BOOL doing_redirect, already_retrying = FALSE, bad_location = FALSE; + int len = 0; + + void * handle = NULL; + + if (anAnchor->isHEAD) + do_head = TRUE; + else if (anAnchor->post_data) + do_post = TRUE; + + if (!url) { + status = -3; + _HTProgress ("Bad request."); + goto done; + } + if (!*url) { + status = -2; + _HTProgress ("Bad request."); + goto done; + } + + sprintf(crlf, "%c%c", CR, LF); + + /* + ** At this point, we're talking HTTP/1.0. + */ + extensions = YES; + +try_again: + /* + ** All initializations are moved down here from up above, + ** so we can start over here... + */ + eol = 0; + bytes_already_read = 0; + had_header = NO; + length = 0; + doing_redirect = FALSE; + permanent_redirection = FALSE; + redirect_post_content = FALSE; + target = NULL; + line_buffer = NULL; + line_kept_clean = NULL; + + if (!strncmp(url, "https", 5)) + { + HTAlert("This client does not contain support for HTTPS URLs."); + status = HT_NOT_LOADED; + goto done; + } + status = HTDoConnect (arg, "HTTP", HTTP_PORT, &s); + if (status == HT_INTERRUPTED) { + /* + ** Interrupt cleanly. + */ + if (TRACE) + fprintf (stderr, + "HTTP: Interrupted on connect; recovering cleanly.\n"); + _HTProgress ("Connection interrupted."); + status = HT_NOT_LOADED; + goto done; + } + if (status < 0) { + if (TRACE) + fprintf(stderr, + "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n", + url, SOCKET_ERRNO); + HTAlert("Unable to connect to remote host."); + status = HT_NOT_LOADED; + goto done; + } + + /* Ask that node for the document, + ** omitting the host name & anchor + */ + { + char * p1 = (HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION)); + + if (do_post) { + METHOD = "POST"; + StrAllocCopy(command, "POST "); + } else if (do_head) { + METHOD = "HEAD"; + StrAllocCopy(command, "HEAD "); + } else { + METHOD = "GET"; + StrAllocCopy(command, "GET "); + } + + /* + ** If we are using a proxy gateway don't copy in the first slash + ** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj + ** so that just gopher://.... is sent. + */ + if (using_proxy) + StrAllocCat(command, p1+1); + else + StrAllocCat(command, p1); + FREE(p1); + } + if (extensions) { + StrAllocCat(command, " "); + StrAllocCat(command, HTTP_VERSION); + } + + StrAllocCat(command, crlf); /* CR LF, as in rfc 977 */ + + if (extensions) { + int n, i; + char * host = NULL; + + if ((host = HTParse(anAnchor->address, "", PARSE_HOST)) != NULL) { + sprintf(line, "Host: %s%c%c", host, CR,LF); + StrAllocCat(command, line); + FREE(host); + } + + if (!HTPresentations) + HTFormatInit(); + n = HTList_count(HTPresentations); + + first_Accept = TRUE; + len = 0; + for (i = 0; i < n; i++) { + HTPresentation *pres = + (HTPresentation *)HTList_objectAt(HTPresentations, i); + if (pres->rep_out == WWW_PRESENT) { + if (pres->rep != WWW_SOURCE && + strcasecomp(HTAtom_name(pres->rep), "www/mime") && + strcasecomp(HTAtom_name(pres->rep), "www/compressed") && + pres->quality <= 1.0 && pres->quality >= 0.0) { + if (pres->quality < 1.0) { + if (pres->maxbytes > 0) { + sprintf(temp, ";q=%4.3f;mxb=%ld", + pres->quality, pres->maxbytes); + } else { + sprintf(temp, ";q=%4.3f", pres->quality); + } + } else if (pres->maxbytes > 0) { + sprintf(temp, ";mxb=%ld", pres->maxbytes); + } else { + temp[0] = '\0'; + } + sprintf(line, "%s%s%s", + (first_Accept ? + "Accept: " : ", "), + HTAtom_name(pres->rep), + temp); + len += strlen(line); + if (len > 252 && !first_Accept) { + StrAllocCat(command, crlf); + sprintf(line, "Accept: %s%s", + HTAtom_name(pres->rep), + temp); + len = strlen(line); + } + StrAllocCat(command, line); + first_Accept = FALSE; + } + } + } + sprintf(line, "%s*/*;q=0.01%c%c", + (first_Accept ? + "Accept: " : ", "), CR, LF); + StrAllocCat(command, line); + first_Accept = FALSE; + len = 0; + + sprintf(line, "Accept-Encoding: %s, %s%c%c", + "gzip", "compress", CR, LF); + StrAllocCat(command, line); + + if (language && *language) { + sprintf(line, "Accept-Language: %s%c%c", language, CR, LF); + StrAllocCat(command, line); + } + + if (pref_charset && *pref_charset) { + StrAllocCat(command, "Accept-Charset: "); + strcpy(line, pref_charset); + if (line[strlen(line)-1] == ',') + line[strlen(line)-1] = '\0'; + for (i = 0; line[i]; i++) + line[i] = TOLOWER(line[i]); + if (strstr(line, "iso-8859-1") == NULL) + strcat(line, ", iso-8859-1;q=0.01"); + if (strstr(line, "us-ascii") == NULL) + strcat(line, ", us-ascii;q=0.01"); + StrAllocCat(command, line); + sprintf(line, "%c%c", CR, LF); + StrAllocCat(command, line); + } + + /* + ** Promote 300 (Multiple Choices) replies, if supported, + ** over 406 (Not Acceptable) replies. - FM + */ + if (!do_post) { + sprintf(line, "Negotiate: trans%c%c", CR, LF); + StrAllocCat(command, line); + } + + /* + ** When reloading give no-cache pragma to proxy server to make + ** it refresh its cache. -- Ari L. <luotonen@dxcern.cern.ch> + ** + ** Also send it as a Cache-Control header for HTTP/1.1. - FM + */ + if (reloading) { + sprintf(line, "Pragma: no-cache%c%c", CR, LF); + StrAllocCat(command, line); + sprintf(line, "Cache-Control: no-cache%c%c", CR, LF); + StrAllocCat(command, line); + } + + if (LYUserAgent && *LYUserAgent) { + sprintf(line, "User-Agent: %s%c%c", LYUserAgent, CR, LF); + } else { + sprintf(line, "User-Agent: %s/%s libwww-FM/%s%c%c", + HTAppName ? HTAppName : "unknown", + HTAppVersion ? HTAppVersion : "0.0", + HTLibraryVersion, CR, LF); + } + StrAllocCat(command, line); + + if (personal_mail_address && !LYNoFromHeader) { + sprintf(line, "From: %s%c%c", personal_mail_address, CR,LF); + StrAllocCat(command, line); + } + + if (!(LYUserSpecifiedURL || + LYNoRefererHeader || LYNoRefererForThis) && + strcmp(HTLoadedDocumentURL(), "")) { + char *cp = HTLoadedDocumentURL(); + StrAllocCat(command, "Referer: "); + if (!strncasecomp(cp, "LYNXIMGMAP:", 11)) { + char *cp1 = strchr(cp, '#'); + if (cp1) + *cp1 = '\0'; + StrAllocCat(command, cp + 11); + if (cp1) + *cp1 = '#'; + } else { + StrAllocCat(command, cp); + } + sprintf(line, "%c%c", CR, LF); + StrAllocCat(command, line); + } + + { + char *abspath; + char *docname; + char *hostname; + char *colon; + int portnumber; + char *auth, *cookie = NULL; + BOOL secure = (strncmp(anAnchor->address, "https", 5) ? + FALSE : TRUE); + + abspath = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION); + docname = HTParse(arg, "", PARSE_PATH); + hostname = HTParse(arg, "", PARSE_HOST); + if (hostname && + NULL != (colon = strchr(hostname, ':'))) { + *(colon++) = '\0'; /* Chop off port number */ + portnumber = atoi(colon); + } else if (!strncmp(arg, "https", 5)) { + portnumber = HTTPS_PORT; + } else { + portnumber = HTTP_PORT; + } + + /* + ** Add Authorization, Proxy-Authorization, + ** and/or Cookie headers, if applicable. + */ + if (using_proxy) { + /* + ** If we are using a proxy, first determine if + ** we should include an Authorization header + ** and/or Cookie header for the ultimate target + ** of this request. - FM & AJL + */ + char *host2 = NULL, *path2 = NULL; + int port2 = (strncmp(docname, "https", 5) ? + HTTP_PORT : HTTPS_PORT); + host2 = HTParse(docname, "", PARSE_HOST); + path2 = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION); + if (host2) { + if ((colon = strchr(host2, ':')) != NULL) { + /* Use non-default port number */ + *colon = '\0'; + colon++; + port2 = atoi(colon); + } + } + /* + ** This composeAuth() does file access, i.e., for + ** the ultimate target of the request. - AJL + */ + auth_proxy = NO; + if ((auth = HTAA_composeAuth(host2, port2, path2, + auth_proxy)) != NULL && + *auth != '\0') { + /* + ** If auth is not NULL nor zero-length, it's + ** an Authorization header to be included. - FM + */ + sprintf(line, "%s%c%c", auth, CR, LF); + StrAllocCat(command, line); + if (TRACE) + fprintf(stderr, "HTTP: Sending authorization: %s\n", auth); + } else if (auth && *auth == '\0') { + /* + ** If auth is a zero-length string, the user either + ** cancelled or goofed at the username and password + ** prompt. - FM + */ + if (!(traversal || dump_output_immediately) && + HTConfirm( + "Proceed without a username and password?")) { + show_401 = TRUE; + } else { + if (traversal || dump_output_immediately) + HTAlert( + "Can't proceed without a username and password."); + FREE(command); + FREE(hostname); + FREE(docname); + FREE(host2); + FREE(path2); + status = HT_NOT_LOADED; + goto done; + } + } else { + if (TRACE) + fprintf(stderr, + "HTTP: Not sending authorization (yet).\n"); + } + /* + ** Add 'Cookie:' header, if it's HTTP or HTTPS + ** document being proxied. + */ + if (!strncmp(docname, "http", 4)) { + cookie = LYCookie(host2, path2, port2, secure); + } + FREE(host2); + FREE(path2); + /* + ** The next composeAuth() will be for the proxy. - AJL + */ + auth_proxy = YES; + } else { + /* + ** Add cookie for a non-proxied request. - FM + */ + cookie = LYCookie(hostname, abspath, portnumber, secure); + auth_proxy = NO; + } + /* + ** If we do have a cookie set, add it to the request buffer. - FM + */ + if (cookie != NULL) { + if (*cookie != '$') { + /* + ** It's a historical cookie, so signal to the + ** server that we support modern cookies. - FM + */ + StrAllocCat(command, "Cookie2: $Version=\"1\""); + StrAllocCat(command, crlf); + if (TRACE) + fprintf(stderr, + "HTTP: Sending Cookie2: $Version =\"1\"\n"); + } + if (*cookie != '\0') { + /* + ** It's not a zero-length string, so add the header. + ** Note that any folding of long strings has been + ** done already in LYCookie.c. - FM + */ + StrAllocCat(command, "Cookie: "); + StrAllocCat(command, cookie); + StrAllocCat(command, crlf); + if (TRACE) + fprintf(stderr, "HTTP: Sending Cookie: %s\n", cookie); + } + FREE(cookie); + } + FREE(abspath); + + /* + ** If we are using a proxy, auth_proxy should be YES, and + ** we check here whether we want a Proxy-Authorization header + ** for it. If we are not using a proxy, auth_proxy should + ** still be NO, and we check here for whether we want an + ** Authorization header. - FM & AJL + */ + if ((auth = HTAA_composeAuth(hostname, + portnumber, + docname, + auth_proxy)) != NULL && + *auth != '\0') { + /* + ** If auth is not NULL nor zero-length, it's + ** an Authorization or Proxy-Authorization + ** header to be included. - FM + */ + sprintf(line, "%s%c%c", auth, CR, LF); + StrAllocCat(command, line); + if (TRACE) + fprintf(stderr, + (auth_proxy ? + "HTTP: Sending proxy authorization: %s\n" : + "HTTP: Sending authorization: %s\n"), + auth); + } else if (auth && *auth == '\0') { + /* + ** If auth is a zero-length string, the user either + ** cancelled or goofed at the username and password + ** prompt. - FM + */ + if (!(traversal || dump_output_immediately) && + HTConfirm("Proceed without a username and password?")) { + if (auth_proxy == TRUE) { + show_407 = TRUE; + } else { + show_401 = TRUE; + } + } else { + if (traversal || dump_output_immediately) + HTAlert("Can't proceed without a username and password."); + FREE(command); + FREE(hostname); + FREE(docname); + status = HT_NOT_LOADED; + goto done; + } + } else { + if (TRACE) + fprintf(stderr, + (auth_proxy ? + "HTTP: Not sending proxy authorization (yet).\n" : + "HTTP: Not sending authorization (yet).\n")); + } + FREE(hostname); + FREE(docname); + } + auth_proxy = NO; + } + + if (do_post) + { + if (TRACE) + fprintf (stderr, "HTTP: Doing post, content-type '%s'\n", + anAnchor->post_content_type ? anAnchor->post_content_type + : "lose"); + sprintf (line, "Content-type: %s%c%c", + anAnchor->post_content_type ? anAnchor->post_content_type + : "lose", CR, LF); + StrAllocCat(command, line); + { + int content_length; + if (!anAnchor->post_data) + content_length = 0; + else + content_length = strlen (anAnchor->post_data); + sprintf (line, "Content-length: %d%c%c", + content_length, CR, LF); + StrAllocCat(command, line); + } + + StrAllocCat(command, crlf); /* Blank line means "end" of headers */ + + StrAllocCat(command, anAnchor->post_data); + } + else + StrAllocCat(command, crlf); /* Blank line means "end" of headers */ + + if (TRACE) { + fprintf (stderr, + "Writing:\n%s%s----------------------------------\n", + command, + (anAnchor->post_data ? crlf : "")); + } + + _HTProgress ("Sending HTTP request."); + + status = HTTP_NETWRITE(s, command, (int)strlen(command), handle); + FREE(command); + if (status <= 0) { + if (status == 0) { + if (TRACE) + fprintf (stderr, "HTTP: Got status 0 in initial write\n"); + /* Do nothing. */ + } else if ((SOCKET_ERRNO == ENOTCONN || + SOCKET_ERRNO == ECONNRESET || + SOCKET_ERRNO == EPIPE) && + !already_retrying && + /* Don't retry if we're posting. */ !do_post) { + /* + ** Arrrrgh, HTTP 0/1 compability problem, maybe. + */ + if (TRACE) + fprintf (stderr, + "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n"); + _HTProgress ("Retrying as HTTP0 request."); + HTTP_NETCLOSE(s, handle); + extensions = NO; + already_retrying = TRUE; + goto try_again; + } else { + if (TRACE) + fprintf (stderr, + "HTTP: Hit unexpected network WRITE error; aborting connection.\n"); + HTTP_NETCLOSE(s, handle); + status = -1; + HTAlert("Unexpected network write error; connection aborted."); + goto done; + } + } + + if (TRACE) + fprintf (stderr, "HTTP: WRITE delivered OK\n"); + _HTProgress ("HTTP request sent; waiting for response."); + + /* Read the first line of the response + ** ----------------------------------- + */ + { + /* Get numeric status etc */ + BOOL end_of_file = NO; + int buffer_length = INIT_LINE_SIZE; + + line_buffer = (char *)calloc(1, (buffer_length * sizeof(char))); + + do {/* Loop to read in the first line */ + /* + ** Extend line buffer if necessary for those crazy WAIS URLs ;-) + */ + if (buffer_length - length < LINE_EXTEND_THRESH) { + buffer_length = buffer_length + buffer_length; + line_buffer = + (char *)realloc(line_buffer, (buffer_length * sizeof(char))); + } + if (TRACE) + fprintf (stderr, "HTTP: Trying to read %d\n", + buffer_length - length - 1); + status = HTTP_NETREAD(s, line_buffer + length, + buffer_length - length - 1, handle); + if (TRACE) + fprintf (stderr, "HTTP: Read %d\n", status); + if (status <= 0) { + /* + * Retry if we get nothing back too. + * Bomb out if we get nothing twice. + */ + if (status == HT_INTERRUPTED) { + if (TRACE) + fprintf (stderr, "HTTP: Interrupted initial read.\n"); + _HTProgress ("Connection interrupted."); + HTTP_NETCLOSE(s, handle); + status = HT_NO_DATA; + goto clean_up; + } else if (status < 0 && + (SOCKET_ERRNO == ENOTCONN || + SOCKET_ERRNO == ECONNRESET || + SOCKET_ERRNO == EPIPE) && + !already_retrying && !do_post) { + /* + ** Arrrrgh, HTTP 0/1 compability problem, maybe. + */ + if (TRACE) + fprintf (stderr, + "HTTP: BONZO Trying again with HTTP0 request.\n"); + HTTP_NETCLOSE(s, handle); + FREE(line_buffer); + FREE(line_kept_clean); + + extensions = NO; + already_retrying = TRUE; + _HTProgress ("Retrying as HTTP0 request."); + goto try_again; + } else { + if (TRACE) + fprintf (stderr, + "HTTP: Hit unexpected network read error; aborting connection; status %d.\n", + status); + HTAlert("Unexpected network read error; connection aborted."); + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + } + + bytes_already_read += status; + sprintf (line, "Read %d bytes of data.", bytes_already_read); + HTProgress (line); + +#ifdef UCX /* UCX returns -1 on EOF */ + if (status == 0 || status == -1) +#else + if (status == 0) +#endif + { + end_of_file = YES; + break; + } + line_buffer[length+status] = 0; + + if (line_buffer) { + FREE(line_kept_clean); + line_kept_clean = (char *)malloc(buffer_length * sizeof(char)); + memcpy(line_kept_clean, line_buffer, buffer_length); + } + + eol = strchr(line_buffer + length, LF); + /* Do we *really* want to do this? */ + if (eol && eol != line_buffer && *(eol-1) == CR) + *(eol-1) = ' '; + + length = length + status; + + /* Do we really want to do *this*? */ + if (eol) + *eol = 0; /* Terminate the line */ + } + /* All we need is the first line of the response. If it's a HTTP/1.0 + ** response, then the first line will be absurdly short and therefore + ** we can safely gate the number of bytes read through this code + ** (as opposed to below) to ~1000. + ** + ** Well, let's try 100. + */ + while (!eol && !end_of_file && bytes_already_read < 100); + } /* Scope of loop variables */ + + + /* We now have a terminated unfolded line. Parse it. + ** ------------------------------------------------- + */ + if (TRACE) + fprintf(stderr, "HTTP: Rx: %s\n", line_buffer); + + /* + ** Kludge to work with old buggy servers and the VMS Help gateway. + ** They can't handle the third word, so we try again without it. + */ + if (extensions && /* Old buggy server or Help gateway? */ + (0==strncmp(line_buffer,"<TITLE>Bad File Request</TITLE>",31) || + 0==strncmp(line_buffer,"Address should begin with",25) || + 0==strncmp(line_buffer,"<TITLE>Help ",12) || + 0==strcmp(line_buffer, + "Document address invalid or access not authorised"))) { + FREE(line_buffer); + FREE(line_kept_clean); + extensions = NO; + already_retrying = TRUE; + if (TRACE) + fprintf(stderr, "HTTP: close socket %d to retry with HTTP0\n", s); + HTTP_NETCLOSE(s, handle); + /* print a progress message */ + _HTProgress ("Retrying as HTTP0 request."); + goto try_again; + } + + + { + int fields; + char server_version[VERSION_LENGTH+1]; + int server_status; + + server_version[0] = 0; + + fields = sscanf(line_buffer, "%20s %d", + server_version, + &server_status); + + if (TRACE) + fprintf (stderr, "HTTP: Scanned %d fields from line_buffer\n", fields); + + if (http_error_file) { /* Make the status code externally available */ + FILE *error_file; +#ifdef SERVER_STATUS_ONLY + error_file = fopen(http_error_file, "w"); + if (error_file) { /* Managed to open the file */ + fprintf(error_file, "error=%d\n", server_status); + fclose(error_file); + } +#else + error_file = fopen(http_error_file, "a"); + if (error_file) { /* Managed to open the file */ + fprintf(error_file, " URL=%s (%s)\n", url, METHOD); + fprintf(error_file, "STATUS=%s\n", line_buffer); + fclose(error_file); + } +#endif /* SERVER_STATUS_ONLY */ + } + + /* + ** Rule out a non-HTTP/1.n reply as best we can. + */ + if (fields < 2 || !server_version[0] || server_version[0] != 'H' || + server_version[1] != 'T' || server_version[2] != 'T' || + server_version[3] != 'P' || server_version[4] != '/' || + server_version[6] != '.') { + /* + * Ugh! An HTTP0 reply, + */ + HTAtom * encoding; + + if (TRACE) + fprintf (stderr, "--- Talking HTTP0.\n"); + + format_in = HTFileFormat(url, &encoding, NULL); + /* + ** Treat all plain text as HTML. + ** This sucks but its the only solution without + ** without looking at content. + */ + if (!strncmp(HTAtom_name(format_in), "text/plain",10)) { + if (TRACE) + fprintf(stderr, + "HTTP: format_in being changed to text/HTML\n"); + format_in = WWW_HTML; + } + if (!IsUnityEnc(encoding)) { + /* + ** Change the format to that for "www/compressed". + */ + if (TRACE) { + fprintf(stderr, + "HTTP: format_in is '%s',\n", HTAtom_name(format_in)); + } + StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in)); + StrAllocCopy(anAnchor->content_encoding, HTAtom_name(encoding)); + format_in = HTAtom_for("www/compressed"); + if (TRACE) { + fprintf(stderr, + " Treating as '%s' with encoding '%s'\n", + "www/compressed", HTAtom_name(encoding)); + } + } + + start_of_data = line_kept_clean; + } else { + /* + ** Set up to decode full HTTP/1.n response. - FM + */ + format_in = HTAtom_for("www/mime"); + if (TRACE) + fprintf (stderr, "--- Talking HTTP1.\n"); + + /* + ** We set start_of_data to "" when !eol here because there + ** will be a put_block done below; we do *not* use the value + ** of start_of_data (as a pointer) in the computation of + ** length (or anything else) when !eol. Otherwise, set the + ** value of length to what we have beyond eol (i.e., beyond + ** the status line). - FM + */ + start_of_data = eol ? eol + 1 : ""; + length = eol ? length - (start_of_data - line_buffer) : 0; + + /* + ** Trim trailing spaces in line_buffer so that we can use + ** it in messages which include the status line. - FM + */ + while (line_buffer[strlen(line_buffer)-1] == ' ') + line_buffer[strlen(line_buffer)-1] = '\0'; + + /* + ** Take appropriate actions based on the status. - FM + */ + switch (server_status/100) { + case 1: + /* + ** HTTP/1.1 Informational statuses. + ** 100 Continue. + ** 101 Switching Protocols. + ** > 101 is unknown. + ** We should never get these, and they have only + ** the status line and possibly other headers, + ** so we'll deal with them by showing the full + ** header to the user as text/plain. - FM + */ + HTAlert("Got unexpected Informational Status."); + do_head = TRUE; + break; + + case 2: + /* + ** Good: Got MIME object! (Successful) - FM + */ + if (do_head) { + /* + * If HEAD was requested, show headers (and possibly + * bogus body) for all 2xx status codes as text/plain - KW + */ + HTProgress(line_buffer); + break; + } + switch (server_status) { + case 204: + /* + * No Content. + */ + HTAlert(line_buffer); + HTTP_NETCLOSE(s, handle); + status = HT_NO_DATA; + goto clean_up; + break; + + case 205: + /* + * Reset Content. The server has fulfilled the + * request but nothing is returned and we should + * reset any form content. We'll instruct the + * user to do that, and restore the current + * document. - FM + */ + HTAlert("Request fulfilled. Reset Content."); + HTTP_NETCLOSE(s, handle); + status = HT_NO_DATA; + goto clean_up; + break; + + case 206: + /* + * Partial Content. We didn't send a Range + * so something went wrong somewhere. Show + * the status message and restore the current + * document. - FM + */ + HTAlert(line_buffer); + HTTP_NETCLOSE(s, handle); + status = HT_NO_DATA; + goto clean_up; + break; + + default: + /* + * 200 OK. + * 201 Created. + * 202 Accepted. + * 203 Non-Authoritative Information. + * > 206 is unknown. + * All should return something to display. + */ + HTProgress(line_buffer); + } /* case 2 switch */ + break; + + case 3: + /* + ** Various forms of Redirection. - FM + ** 300 Multiple Choices. + ** 301 Moved Permanently. + ** 302 Found (temporary; we can, and do, use GET). + ** 303 See Other (temporary; always use GET). + ** 304 Not Modified. + ** 305 Use Proxy. + ** 306 Set Proxy. + ** 307 Temporary Redirect with method retained. + ** > 308 is unknown. + */ + if (no_url_redirection || do_head || keep_mime_headers) { + /* + * If any of these flags are set, we do not redirect, + * but instead show what was returned to the user as + * text/plain. - FM + */ + HTProgress(line_buffer); + break; + } + + if (server_status == 300) { /* Multiple Choices */ + /* + * For client driven content negotiation. The server + * should be sending some way for the user-agent to + * make a selection, so we'll show the user whatever + * the server returns. There might be a Location: + * header with the server's preference present, but + * the choice should be up to the user, someday based + * on an Alternates: header, and a body always should + * be present with descriptions and links for the + * choices (i.e., we use the latter, for now). - FM + */ + HTAlert(line_buffer); + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } + + if (server_status == 304) { /* Not Modified */ + /* + * We didn't send an "If-Modified-Since" header, + * so this status is inappropriate. We'll deal + * with it by showing the full header to the user + * as text/plain. - FM + */ + HTAlert("Got unexpected 304 Not Modified status."); + do_head = TRUE; + break; + } + + if (server_status == 305 || + server_status == 306 || + server_status > 307) { + /* + * Show user the content, if any, for 305, 306, + * or unknown status. - FM + */ + HTAlert(line_buffer); + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } + + /* + * We do not load the file, but read the headers for + * the "Location:", check out that redirecting_url + * and if it's acceptible (e.g., not a telnet URL + * when we have that disabled), initiate a new fetch. + * If that's another redirecting_url, we'll repeat the + * checks, and fetch initiations if acceptible, until + * we reach the actual URL, or the redirection limit + * set in HTAccess.c is exceeded. If the status was 301 + * indicating that the relocation is permanent, we set + * the permanent_redirection flag to make it permanent + * for the current anchor tree (i.e., will persist until + * the tree is freed or the client exits). If the + * redirection would include POST content, we seek + * confirmation from an interactive user, with option to + * use 303 for 301 (but not for 307), and otherwise refuse + * the redirection. We also don't allow permanent + * redirection if we keep POST content. If we don't find + * the Location header or it's value is zero-length, we + * display whatever the server returned, and the user + * should RELOAD that to try again, or make a selection + * from it if it contains links, or Left-Arrow to the + * previous document. - FM + */ + { + char *cp; + + if ((dump_output_immediately || traversal) && + do_post && + server_status != 303 && + server_status != 302 && + server_status != 301) { + /* + * Don't redirect POST content without approval + * from an interactive user. - FM + */ + HTTP_NETCLOSE(s, handle); + status = -1; + HTAlert( + "Redirection of POST content requires user approval."); + if (traversal) + HTProgress(line_buffer); + goto clean_up; + } + + /* + * Get the rest of the headers and data, if + * any, and then close the connection. - FM + */ + while ((status = HTTP_NETREAD(s, line_buffer, + (INIT_LINE_SIZE - 1), + handle)) > 0) { + line_buffer[status] = '\0'; + StrAllocCat(line_kept_clean, line_buffer); + } + HTTP_NETCLOSE(s, handle); + if (status == HT_INTERRUPTED) { + /* + * Impatient user. - FM + */ + if (TRACE) + fprintf (stderr, "HTTP: Interrupted followup read.\n"); + _HTProgress ("Connection interrupted."); + status = HT_INTERRUPTED; + goto clean_up; + } + doing_redirect = TRUE; + if (server_status == 301) { /* Moved Permanently */ + HTProgress(line_buffer); + if (do_post) { + /* + * Don't make the redirection permanent + * if we have POST content. - FM + */ + if (TRACE) + fprintf(stderr, + "HTTP: Have POST content. Treating 301 (Permanent) as Temporary.\n"); + HTAlert( + "Have POST content. Treating Permanent Redirection as Temporary.\n"); + } else { + permanent_redirection = TRUE; + } + } + + /* + ** Look for "Set-Cookie:" and "Set-Cookie2:" headers. - FM + */ + if (LYSetCookies == TRUE) { + char *value = NULL; + char *SetCookie = NULL; + char *SetCookie2 = NULL; + cp = line_kept_clean; + while (*cp) { + /* + ** Assume a CRLF pair terminates + ** the header section. - FM + */ + if (*cp == CR) { + if (*(cp+1) == LF && + *(cp+2) == CR && *(cp+3) == LF) { + break; + } + } + if (TOUPPER(*cp) != 'S') { + cp++; + } else if (!strncasecomp(cp, "Set-Cookie:", 11)) { + char *cp1 = NULL, *cp2 = NULL; + cp += 11; +Cookie_continuation: + /* + * Trim leading spaces. - FM + */ + while (isspace((unsigned char)*cp)) + cp++; + /* + ** Accept CRLF, LF, or CR as end of line. - FM + */ + if (((cp1 = strchr(cp, LF)) != NULL) || + (cp2 = strchr(cp, CR)) != NULL) { + if (*cp1) { + *cp1 = '\0'; + if ((cp2 = strchr(cp, CR)) != NULL) + *cp2 = '\0'; + } else { + *cp2 = '\0'; + } + } + if (*cp == '\0') { + if (cp1) + *cp1 = LF; + if (cp2) + *cp2 = CR; + if (value != NULL) { + HTMIME_TrimDoubleQuotes(value); + if (SetCookie == NULL) { + StrAllocCopy(SetCookie, value); + } else { + StrAllocCat(SetCookie, ", "); + StrAllocCat(SetCookie, value); + } + FREE(value); + } + break; + } + StrAllocCat(value, cp); + cp += strlen(cp); + if (cp1) { + *cp1 = LF; + cp1 = NULL; + } + if (cp2) { + *cp2 = CR; + cp2 = NULL; + } + cp1 = cp; + if (*cp1 == CR) + cp1++; + if (*cp1 == LF) + cp1++; + if (*cp1 == ' ' || *cp1 == '\t') { + StrAllocCat(value, " "); + cp = cp1; + cp++; + cp1 = NULL; + goto Cookie_continuation; + } + HTMIME_TrimDoubleQuotes(value); + if (SetCookie == NULL) { + StrAllocCopy(SetCookie, value); + } else { + StrAllocCat(SetCookie, ", "); + StrAllocCat(SetCookie, value); + } + FREE(value); + } else if (!strncasecomp(cp, "Set-Cookie2:", 12)) { + char *cp1 = NULL, *cp2 = NULL; + cp += 12; +Cookie2_continuation: + /* + * Trim leading spaces. - FM + */ + while (isspace((unsigned char)*cp)) + cp++; + /* + ** Accept CRLF, LF, or CR as end of line. - FM + */ + if (((cp1 = strchr(cp, LF)) != NULL) || + (cp2 = strchr(cp, CR)) != NULL) { + if (*cp1) { + *cp1 = '\0'; + if ((cp2 = strchr(cp, CR)) != NULL) + *cp2 = '\0'; + } else { + *cp2 = '\0'; + } + } + if (*cp == '\0') { + if (cp1) + *cp1 = LF; + if (cp2) + *cp2 = CR; + if (value != NULL) { + HTMIME_TrimDoubleQuotes(value); + if (SetCookie2 == NULL) { + StrAllocCopy(SetCookie2, value); + } else { + StrAllocCat(SetCookie2, ", "); + StrAllocCat(SetCookie2, value); + } + FREE(value); + } + break; + } + StrAllocCat(value, cp); + cp += strlen(cp); + if (cp1) { + *cp1 = LF; + cp1 = NULL; + } + if (cp2) { + *cp2 = CR; + cp2 = NULL; + } + cp1 = cp; + if (*cp1 == CR) + cp1++; + if (*cp1 == LF) + cp1++; + if (*cp1 == ' ' || *cp1 == '\t') { + StrAllocCat(value, " "); + cp = cp1; + cp++; + cp1 = NULL; + goto Cookie2_continuation; + } + HTMIME_TrimDoubleQuotes(value); + if (SetCookie2 == NULL) { + StrAllocCopy(SetCookie2, value); + } else { + StrAllocCat(SetCookie2, ", "); + StrAllocCat(SetCookie2, value); + } + FREE(value); + } else { + cp++; + } + } + FREE(value); + if (SetCookie != NULL || SetCookie2 != NULL) { + LYSetCookie(SetCookie, SetCookie2, anAnchor->address); + FREE(SetCookie); + FREE(SetCookie2); + } + } + + /* + * Look for the "Location:" in the headers. - FM + */ + cp = line_kept_clean; + while (*cp) { + if (TOUPPER(*cp) != 'L') { + cp++; + } else if (!strncasecomp(cp, "Location:", 9)) { + char *cp1 = NULL, *cp2 = NULL; + cp += 9; + /* + * Trim leading spaces. - FM + */ + while (isspace((unsigned char)*cp)) + cp++; + /* + * Accept CRLF, LF, or CR as end of header. - FM + */ + if (((cp1 = strchr(cp, LF)) != NULL) || + (cp2 = strchr(cp, CR)) != NULL) { + if (*cp1) { + *cp1 = '\0'; + if ((cp2 = strchr(cp, CR)) != NULL) + *cp2 = '\0'; + } else { + *cp2 = '\0'; + } + /* + * Load the new URL into redirecting_url, + * and make sure it's not zero-length. - FM + */ + StrAllocCopy(redirecting_url, cp); + HTMIME_TrimDoubleQuotes(redirecting_url); + if (*redirecting_url == '\0') { + /* + * The "Location:" value is zero-length, and + * thus is probably something in the body, so + * we'll show the user what was returned. - FM + */ + if (TRACE) + fprintf(stderr, + "HTTP: 'Location:' is zero-length!\n"); + if (cp1) + *cp1 = LF; + if (cp2) + *cp2 = CR; + bad_location = TRUE; + FREE(redirecting_url); + HTAlert( + "Got redirection with a bad Location header."); + HTProgress(line_buffer); + break; + } + + /* + * Set up for checking redirecting_url in + * LYGetFile.c for restrictions before we + * seek the document at that Location. - FM + */ + HTProgress(line_buffer); + if (TRACE) + fprintf(stderr, + "HTTP: Picked up location '%s'\n", + redirecting_url); + if (cp1) + *cp1 = LF; + if (cp2) + *cp2 = CR; + if (server_status == 305) { /* Use Proxy */ + /* + * Make sure the proxy field ends with + * a slash. - FM + */ + if (redirecting_url[strlen(redirecting_url)-1] + != '/') + StrAllocCat(redirecting_url, "/"); + /* + * Append our URL. - FM + */ + StrAllocCat(redirecting_url, anAnchor->address); + if (TRACE) + fprintf(stderr, + "HTTP: Proxy URL is '%s'\n", + redirecting_url); + } + if (!do_post || + server_status == 303 || + server_status == 302) { + /* + * We don't have POST content (nor support PUT + * or DELETE), or the status is "See Other" or + * "General Redirection" and we can convert to + * GET, so go back and check out the new URL. - FM + */ + status = HT_REDIRECTING; + goto clean_up; + } + /* + * Make sure the user wants to redirect + * the POST content, or treat as GET - FM & DK + */ + switch (HTConfirmPostRedirect(redirecting_url, + server_status)) { + /* + * User failed to confirm. + * Abort the fetch. + */ + case 0: + doing_redirect = FALSE; + FREE(redirecting_url); + status = HT_NO_DATA; + goto clean_up; + + /* + * User wants to treat as GET with no content. + * Go back to check out the URL. + */ + case 303: + status = HT_REDIRECTING; + goto clean_up; + + /* + * Set the flag to retain the POST + * content and go back to check out + * the URL. - FM + */ + default: + status = HT_REDIRECTING; + redirect_post_content = TRUE; + goto clean_up; + } + } + break; + } else { + /* + * Keep looking for the Location header. - FM + */ + cp++; + } + } + + /* + * If we get to here, we didn't find the Location + * header, so we'll show the user what we got, if + * anything. - FM + */ + if (TRACE) + fprintf (stderr, "HTTP: Failed to pick up location.\n"); + doing_redirect = FALSE; + permanent_redirection = FALSE; + start_of_data = line_kept_clean; + length = strlen(start_of_data); + if (!bad_location) { + HTAlert("Got redirection with no Location header."); + HTProgress(line_buffer); + } + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } + + case 4: + /* + ** "I think I goofed!" (Client Error) - FM + */ + switch (server_status) { + case 401: /* Unauthorized */ + /* + * Authorization for orgin server required. + * If show_401 is set, proceed to showing the + * 401 body. Otherwise, if we can set up + * authorization based on the WWW-Authenticate + * header, and the user provides a username and + * password, try again. Otherwise, check whether + * to show the 401 body or restore the current + * document. - FM + */ + if (show_401) + break; + if (HTAA_shouldRetryWithAuth(start_of_data, length, + (void *)handle, s, NO)) { + + HTTP_NETCLOSE(s, handle); + if (dump_output_immediately && !authentication_info[0]) { + fprintf(stderr, + "HTTP: Access authorization required.\n"); + fprintf(stderr, + " Use the -auth=id:pw parameter.\n"); + status = HT_NO_DATA; + goto clean_up; + } + + if (TRACE) + fprintf(stderr, "%s %d %s\n", + "HTTP: close socket", s, + "to retry with Access Authorization"); + + _HTProgress ( + "Retrying with access authorization information."); + FREE(line_buffer); + FREE(line_kept_clean); + goto try_again; + break; + } else if (!(traversal || dump_output_immediately) && + HTConfirm("Show the 401 message body?")) { + break; + } else { + if (traversal || dump_output_immediately) + HTAlert( + "Can't retry with authorization! Contact the server's WebMaster."); + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + break; + + case 407: + /* + * Authorization for proxy server required. + * If we are not in fact using a proxy, or + * show_407 is set, proceed to showing the + * 407 body. Otherwise, if we can set up + * authorization based on the Proxy-Authenticate + * header, and the user provides a username and + * password, try again. Otherwise, check whether + * to show the 401 body or restore the current + * document. - FM & AJL + */ + if (!using_proxy || show_407) + break; + if (HTAA_shouldRetryWithAuth(start_of_data, length, + (void *)handle, s, YES)) { + + HTTP_NETCLOSE(s, handle); + if (dump_output_immediately && !proxyauth_info[0]) { + fprintf(stderr, + "HTTP: Proxy authorization required.\n"); + fprintf(stderr, + " Use the -pauth=id:pw parameter.\n"); + status = HT_NO_DATA; + goto clean_up; + } + + if (TRACE) + fprintf(stderr, "%s %d %s\n", + "HTTP: close socket", s, + "to retry with Proxy Authorization"); + + _HTProgress ( + "Retrying with proxy authorization information."); + FREE(line_buffer); + FREE(line_kept_clean); + goto try_again; + break; + } else if (!(traversal || dump_output_immediately) && + HTConfirm("Show the 407 message body?")) { + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } else { + if (traversal || dump_output_immediately) + HTAlert( + "Can't retry with proxy authorization! Contact the server's WebMaster."); + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + break; + + case 408: + /* + * Request Timeout. Show the status message + * and restore the current document. - FM + */ + HTAlert(line_buffer); + HTTP_NETCLOSE(s, handle); + status = HT_NO_DATA; + goto done; + break; + + default: + /* + * 400 Bad Request. + * 402 Payment Required. + * 403 Forbidden. + * 404 Not Found. + * 405 Method Not Allowed. + * 406 Not Acceptable. + * 409 Conflict. + * 410 Gone. + * 411 Length Required. + * 412 Precondition Failed. + * 413 Request Entity Too Large. + * 414 Request-URI Too Long. + * 415 Unsupported Media Type. + * 416 List Response (for content negotiation). + * > 416 is unknown. + * Show the status message, and display + * the returned text if we are not doing + * a traversal. - FM + */ + HTAlert(line_buffer); + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } /* case 4 switch */ + break; + + case 5: + /* + ** "I think YOU goofed!" (server error) + ** 500 Internal Server Error + ** 501 Not Implemented + ** 502 Bad Gateway + ** 503 Service Unavailable + ** 504 Gateway Timeout + ** 505 HTTP Version Not Supported + ** > 505 is unknown. + ** Should always include a message, which + ** we always should display. - FM + */ + HTAlert(line_buffer); + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + + default: + /* + ** Bad or unknown server_status number. + ** Take a chance and hope there is + ** something to display. - FM + */ + HTAlert("Unknown status reply from server!"); + HTAlert(line_buffer); + if (traversal) { + HTTP_NETCLOSE(s, handle); + status = -1; + goto clean_up; + } + if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } + break; + } /* Switch on server_status/100 */ + + } /* Full HTTP reply */ + } /* scope of fields */ + + /* + ** Set up the stream stack to handle the body of the message. + */ + if (do_head || keep_mime_headers) { + /* + ** It was a HEAD request, or we want the headers and source. + */ + start_of_data = line_kept_clean; + length = strlen(start_of_data); + format_in = HTAtom_for("text/plain"); + } + + target = HTStreamStack(format_in, + format_out, + sink, anAnchor); + + if (!target || target == NULL) { + char buffer[1024]; /* @@@@@@@@ */ + + HTTP_NETCLOSE(s, handle); + sprintf(buffer, "Sorry, no known way of converting %s to %s.", + HTAtom_name(format_in), HTAtom_name(format_out)); + _HTProgress (buffer); + status = -1; + goto clean_up; + } + + /* + ** Recycle the first chunk of data, in all cases. + */ + (*target->isa->put_block)(target, start_of_data, length); + + /* + ** Go pull the bulk of the data down. + */ + rv = HTCopy(anAnchor, s, (void *)handle, target); + + if (rv == -1) { + /* + ** Intentional interrupt before data were received, not an error + */ + /* (*target->isa->_abort)(target, NULL); */ /* already done in HTCopy */ + status = HT_INTERRUPTED; + HTTP_NETCLOSE(s, handle); + goto clean_up; + } + + if (rv == -2) { + /* + ** Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server + */ + (*target->isa->_abort)(target, NULL); + HTTP_NETCLOSE(s, handle); + if (!already_retrying && !do_post) { + if (TRACE) + fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n"); + /* + ** May as well consider it an interrupt -- right? + */ + FREE(line_buffer); + FREE(line_kept_clean); + extensions = NO; + already_retrying = TRUE; + _HTProgress ("Retrying as HTTP0 request."); + goto try_again; + } else { + status = HT_NOT_LOADED; + goto clean_up; + } + } + + /* + ** Free if complete transmission (socket was closed before return). + ** Close socket if partial transmission (was freed on abort). + */ + if (rv != HT_INTERRUPTED) { + (*target->isa->_free)(target); + } else { + HTTP_NETCLOSE(s, handle); + } + + if (doing_redirect) { + /* + ** We already jumped over all this if the "case 3:" code worked + ** above, but we'll check here as a backup in case it fails. - FM + */ + /* Lou's old comment: - FM */ + /* OK, now we've got the redirection URL temporarily stored + in external variable redirecting_url, exported from HTMIME.c, + since there's no straightforward way to do this in the library + currently. Do the right thing. */ + status = HT_REDIRECTING; + } else { + /* + ** If any data were received, treat as a complete transmission + */ + status = HT_LOADED; + } + + /* + ** Clean up + */ +clean_up: + FREE(line_buffer); + FREE(line_kept_clean); + +done: + /* + ** Clear out on exit, just in case. + */ + do_head = FALSE; + do_post = FALSE; + reloading = FALSE; + return status; +} + +/* Protocol descriptor +*/ +#ifdef GLOBALDEF_IS_MACRO +#define _HTTP_C_GLOBALDEF_1_INIT { "http", HTLoadHTTP, 0} +GLOBALDEF (HTProtocol,HTTP,_HTTP_C_GLOBALDEF_1_INIT); +#define _HTTP_C_GLOBALDEF_2_INIT { "https", HTLoadHTTP, 0} +GLOBALDEF (HTProtocol,HTTPS,_HTTP_C_GLOBALDEF_2_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0 }; +GLOBALDEF PUBLIC HTProtocol HTTPS = { "https", HTLoadHTTP, 0 }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.h new file mode 100644 index 00000000000..92f1951c63b --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.h @@ -0,0 +1,33 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTTP.html + HYPERTEXT TRANFER PROTOCOL + + */ +#ifndef HTTP_H +#define HTTP_H + +#include "HTAccess.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF (HTProtocol,HTTP); +extern GLOBALREF (HTProtocol,HTTPS); +#else +GLOBALREF HTProtocol HTTP; +GLOBALREF HTProtocol HTTPS; +#endif /* GLOBALREF_IS_MACRO */ + +#define URL_GET_METHOD 1 +#define URL_POST_METHOD 2 +#define URL_MAIL_METHOD 3 + +extern BOOL reloading; +extern char * redirecting_url; +extern BOOL permanent_redirection; +extern BOOL redirect_post_content; + +#endif /* HTTP_H */ + +/* + + end of HTTP module definition + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.c new file mode 100644 index 00000000000..140630e1cb3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.c @@ -0,0 +1,590 @@ +/* Telnet Acees, Roligin, etc HTTelnet.c +** ========================== +** +** Authors +** TBL Tim Berners-Lee timbl@info.cern.ch +** JFG Jean-Francois Groff jgh@next.com +** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu> +** History +** 8 Jun 92 Telnet hopping prohibited as telnet is not secure (TBL) +** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. (JFG) +** 6 Oct 92 Moved HTClientHost and logfile into here. (TBL) +** 17 Dec 92 Tn3270 added, bug fix. (DD) +** 2 Feb 93 Split from HTAccess.c. Registration.(TBL) +*/ + +#include "HTUtils.h" +#include "tcp.h" + +/* Implements: +*/ +#include "HTTelnet.h" + +#include "HTParse.h" +#include "HTAnchor.h" +#include "HTTP.h" +#include "HTFile.h" +/*#include <errno.h> included by tcp.h -- FM */ +/*#include <stdio.h> included by HTUtils.h -- FM */ + +#include "HText.h" + +#include "HTAccess.h" +#include "HTAlert.h" +#if !defined (VMS) && !defined (_WINDOWS) +#include "../../../userdefs.h" /* for TELNET_COMMAND and RLOGIN_COMMAND */ +#endif /* not VMS */ + +#ifdef _WINDOWS /* ../../.. doesn't work for me */ +#include "userdefs.h" /* for TELNET_COMMAND and RLOGIN_COMMAND */ +#endif + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define HT_NO_DATA -9999 + + +/* Telnet or "rlogin" access +** ------------------------- +*/ +PRIVATE int remote_session ARGS2(char *, acc_method, char *, host) +{ + char * user = host; + char * password = NULL; + char * cp; + char * hostname; + char * port; + char command[256]; + enum _login_protocol { telnet, rlogin, tn3270 } login_protocol = + strcmp(acc_method, "rlogin") == 0 ? rlogin : + strcmp(acc_method, "tn3270") == 0 ? tn3270 : telnet; +#ifdef VMS + extern int DCLsystem PARAMS((char *command)); +#define system(a) DCLsystem(a) /* use LYCurses.c routines for spawns */ +#endif /* VMS */ + + /* + * Modified to allow for odd chars in a username only if exists. + * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe + */ + /* prevent telnet://hostname;rm -rf * URL's (VERY BAD) + * *cp=0; / * terminate at any ;,<,>,`,|,",' or space or return + * or tab to prevent security whole + */ + for(cp = (strchr(host, '@') ? strchr(host, '@') : host); *cp != '\0'; + cp++) { + if(!isalnum(*cp) && *cp != '_' && *cp != '-' && + *cp != ':' && *cp != '.' && *cp != '@') { + *cp = '\0'; + break; + } + } + + hostname = strchr(host, '@'); + + if (hostname) { + *hostname++ = '\0'; /* Split */ + } else { + hostname = host; + user = NULL; /* No user specified */ + } + + port = strchr(hostname, ':'); + if (port) + *port++ = '\0'; /* Split */ + + if (!hostname || *hostname == '\0') { + if (TRACE) + fprintf(stderr, "HTTelnet: No host specified!\n"); + return HT_NO_DATA; + } + + if (user) { + password = strchr(user, ':'); + if (password) { + *password++ = '\0'; + } + } + +/* If the person is already telnetting etc, forbid hopping */ +/* This is a security precaution, for us and remote site */ + + if (HTSecure) { + +#ifdef TELNETHOPPER_MAIL + sprintf(command, + "finger @%s | mail -s \"**telnethopper %s\" tbl@dxcern.cern.ch", + HTClientHost, HTClientHost); + system(command); +#endif + printf("\n\nSorry, but the service you have selected is one\n"); + printf("to which you have to log in. If you were running www\n"); + printf("on your own computer, you would be automatically connected.\n"); + printf("For security reasons, this is not allowed when\n"); + printf("you log in to this information service remotely.\n\n"); + + printf("You can manually connect to this service using %s\n", + acc_method); + printf("to host %s", hostname); + if (user) printf(", user name %s", user); + if (password) printf(", password %s", password); + if (port) printf(", port %s", port); + printf(".\n\n"); + return HT_NO_DATA; + } + +/* Not all telnet servers get it even if user name is specified +** so we always tell the guy what to log in as +*/ + if (user && login_protocol != rlogin) + printf("When you are connected, log in as: %s\n", user); + if (password && login_protocol != rlogin) + printf(" The password is: %s\n", password); + +/* + * NeXTSTEP is the implied version of the NeXT operating system. + * You may need to define this yourself. + */ +#if defined(NeXT) && defined(NeXTSTEP) && NeXTSTEP<=20100 + sprintf(command, "%s%s%s %s %s", TELNET_COMMAND, + user ? " -l " : "", + user ? user : "", + hostname, + port ? port : ""); + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ +#define TELNET_DONE +#endif + +/* Most unix machines suppport username only with rlogin */ +#if defined(unix) || defined(DOSPATH) +#ifndef TELNET_DONE + if (login_protocol == rlogin) { + sprintf(command, "%s %s%s%s", RLOGIN_COMMAND, + hostname, + user ? " -l " : "", + user ? user : ""); + + } else if (login_protocol == tn3270) { + sprintf(command, "%s %s %s", TN3270_COMMAND, + hostname, + port ? port : ""); + + } else { /* TELNET */ + sprintf(command, "%s %s %s", TELNET_COMMAND, + hostname, + port ? port : ""); + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Normal: Command is: %s\n\n", command); +#ifdef __DJGPP__ + __djgpp_set_ctrl_c(0); + _go32_want_ctrl_break(1); +#endif /* __DJGPP__ */ + system(command); +#ifdef __DJGPP__ + __djgpp_set_ctrl_c(1); + _go32_want_ctrl_break(0); +#endif /* __DJGPP__ */ + return HT_NO_DATA; /* Ok - it was done but no data */ +#define TELNET_DONE +#endif /* !TELNET_DONE */ +#endif /* unix */ + +/* VMS varieties */ +#if defined(MULTINET) + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN%s%s%s%s%s %s", /*lm 930713 */ + user ? "/USERNAME=\"" : "", + user ? user : "", + user ? "\"" : "", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else if (login_protocol == tn3270) { + sprintf(command, "TELNET/TN3270 %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else { /* TELNET */ + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ +#define TELNET_DONE +#endif /* MULTINET */ + +#if defined(WIN_TCP) + { + char *cp; + + if ((cp=getenv("WINTCP_COMMAND_STYLE")) != NULL && + 0==strncasecomp(cp, "VMS", 3)) { /* VMS command syntax */ + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN%s%s%s%s%s %s", /*lm 930713 */ + user ? "/USERNAME=\"" : "", + user ? user : "", + user ? "\"" : "", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else if (login_protocol == tn3270) { + sprintf(command, "TELNET/TN3270 %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else { /* TELNET */ + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } + + } else { /* UNIX command syntax */ + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN %s%s%s%s%s", + hostname, + user ? " -l " : "", + user ? "\"" : "", + user ? user : "", + user ? "\"" : ""); + + } else if (login_protocol == tn3270) { + sprintf(command, "TN3270 %s %s", + hostname, + port ? port : ""); + + } else { /* TELNET */ + sprintf(command, "TELNET %s %s", + hostname, + port ? port : ""); + } + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ + } +#define TELNET_DONE +#endif /* WIN_TCP */ + +#ifdef UCX + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN%s%s%s %s %s", + user ? "/USERNAME=\"" : "", + user ? user : "", + user ? "\"" : "", + hostname, + port ? port : ""); + + } else if (login_protocol == tn3270) { + sprintf(command, "TN3270 %s %s", + hostname, + port ? port : ""); + + } else { /* TELNET */ + sprintf(command, "TELNET %s %s", + hostname, + port ? port : ""); + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ +#define TELNET_DONE +#endif /* UCX */ + +#ifdef CMU_TCP + if (login_protocol == telnet) { + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + } + else { + extern int LYgetch NOPARAMS; + extern BOOLEAN HadVMSInterrupt; + + printf( + "\nSorry, this browser was compiled without the %s access option.\n", + acc_method); + printf("\nPress <return> to return to Lynx."); + LYgetch(); + HadVMSInterrupt = FALSE; + } + return HT_NO_DATA; /* Ok - it was done but no data */ +#define TELNET_DONE +#endif /* CMU_TCP */ + +#ifdef SOCKETSHR_TCP + { + char *cp; + + if (getenv("MULTINET_SOCKET_LIBRARY") != NULL) { + if (login_protocol == rlogin) { + sprintf(command, "MULTINET RLOGIN%s%s%s%s %s", /*lm 930713 */ + user ? "/USERNAME=" : "", + user ? user : "", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else if (login_protocol == tn3270) { + sprintf(command, "MULTINET TELNET/TN3270 %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + + } else { /* TELNET */ + sprintf(command, "MULTINET TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ + } + else if ((cp=getenv("WINTCP_COMMAND_STYLE")) != NULL) { + if (0==strncasecomp(cp, "VMS", 3)) { /* VMS command syntax */ + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN%s%s%s%s %s", /*lm 930713 */ + user ? "/USERNAME=" : "", + user ? user : "", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } else if (login_protocol == tn3270) { + sprintf(command, "TELNET/TN3270 %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } else { /* TELNET */ + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + } + } else { /* UNIX command syntax */ + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN %s%s%s", + hostname, + user ? " -l " : "", + user ? user : ""); + } else if (login_protocol == tn3270) { + sprintf(command, "TN3270 %s %s", + hostname, + port ? port : ""); + } else { /* TELNET */ + sprintf(command, "TELNET %s %s", + hostname, + port ? port : ""); + } + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ + } + else if (getenv("UCX$DEVICE") != NULL) { + if (login_protocol == rlogin) { + sprintf(command, "RLOGIN%s%s %s %s", + user ? "/USERNAME=" : "", + user ? user : "", + hostname, + port ? port : ""); + + } else if (login_protocol == tn3270) { + sprintf(command, "TN3270 %s %s", + hostname, + port ? port : ""); + + } else { /* TELNET */ + sprintf(command, "TELNET %s %s", + hostname, + port ? port : ""); + } + + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ + } + else if (getenv("CMUTEK_ROOT") != NULL) { + if (login_protocol == telnet) { + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + } + else { + extern int LYgetch NOPARAMS; + extern BOOLEAN HadVMSInterrupt; + + printf( + "\nSorry, this browser was compiled without the %s access option.\n", + acc_method); + printf("\nPress <return> to return to Lynx."); + LYgetch(); + HadVMSInterrupt = FALSE; + } + return HT_NO_DATA; /* Ok - it was done but no data */ + } + else { + if (login_protocol == telnet) { + sprintf(command, "TELNET %s%s %s", + port ? "/PORT=" : "", + port ? port : "", + hostname); + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + } + else { + extern int LYgetch NOPARAMS; + extern BOOLEAN HadVMSInterrupt; + + printf( + "\nSorry, this browser was compiled without the %s access option.\n", + acc_method); + printf("\nPress <return> to return to Lynx."); + LYgetch(); + HadVMSInterrupt = FALSE; + } + return HT_NO_DATA; /* Ok - it was done but no data */ + } + } +#define TELNET_DONE +#endif /* SOCKETSHR_TCP */ + +#ifdef VM +#define SIMPLE_TELNET +#endif +#ifdef SIMPLE_TELNET + if (login_protocol == telnet) { /* telnet only */ + sprintf(command, "TELNET %s", /* @@ Bug: port ignored */ + hostname); + if (TRACE) + fprintf(stderr, "HTTelnet: Command is: %s\n\n", command); + system(command); + return HT_NO_DATA; /* Ok - it was done but no data */ + } +#endif + +#ifndef TELNET_DONE + printf( + "\nSorry, this browser was compiled without the %s access option.\n", + acc_method); + printf( + "\nTo access the information you must %s to %s", acc_method, hostname); + if (port) + printf(" (port %s)", port); + if (user) + printf("\nlogging in with username %s", user); + printf(".\n"); + { + extern int LYgetch NOPARAMS; + + printf("\nPress <return> to return to Lynx."); + fflush(stdout); + LYgetch(); +#ifdef VMS + { + extern BOOLEAN HadVMSInterrupt; + HadVMSInterrupt = FALSE; + } +#endif /* VMS */ + } + return HT_NO_DATA; +#endif /* !TELNET_DONE */ +} + +/* "Load a document" -- establishes a session +** ------------------------------------------ +** +** On entry, +** addr must point to the fully qualified hypertext reference. +** +** On exit, +** returns <0 Error has occured. +** >=0 Value of file descriptor or socket to be used +** to read data. +** *pFormat Set to the format of the file, if known. +** (See WWW.h) +** +*/ +PRIVATE int HTLoadTelnet +ARGS4 +( + CONST char *, addr, + HTParentAnchor *, anchor GCC_UNUSED, + HTFormat, format_out GCC_UNUSED, + HTStream *, sink /* Ignored */ +) +{ + char * acc_method; + char * host; + int status; + + if (sink) { + if (TRACE) + fprintf(stderr, + "HTTelnet: Can't output a live session -- must be interactive!\n"); + return HT_NO_DATA; + } + acc_method = HTParse(addr, "file:", PARSE_ACCESS); + + host = HTParse(addr, "", PARSE_HOST); + if (!host || *host == '\0') { + status = HT_NO_DATA; + if (TRACE) + fprintf(stderr, "HTTelnet: No host specified!\n"); + } else { + status = remote_session(acc_method, host); + } + + FREE(host); + FREE(acc_method); + return status; +} + + +#ifdef GLOBALDEF_IS_MACRO +#define _HTTELNET_C_1_INIT { "telnet", HTLoadTelnet, NULL } +#define _HTTELNET_C_2_INIT { "rlogin", HTLoadTelnet, NULL } +#define _HTTELNET_C_3_INIT { "tn3270", HTLoadTelnet, NULL } +GLOBALDEF (HTProtocol, HTTelnet, _HTTELNET_C_1_INIT ); +GLOBALDEF (HTProtocol, HTRlogin, _HTTELNET_C_2_INIT ); +GLOBALDEF (HTProtocol, HTTn3270, _HTTELNET_C_3_INIT ); +#else +GLOBALDEF PUBLIC HTProtocol HTTelnet = { "telnet", HTLoadTelnet, NULL }; +GLOBALDEF PUBLIC HTProtocol HTRlogin = { "rlogin", HTLoadTelnet, NULL }; +GLOBALDEF PUBLIC HTProtocol HTTn3270 = { "tn3270", HTLoadTelnet, NULL }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.h new file mode 100644 index 00000000000..4c5de744fc1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.h @@ -0,0 +1,24 @@ +/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTTelnet.html + TELNET AND SIMILAR ACCESS METHODS + + */ + +#ifndef HTTELNET_H +#define HTTELNET_H + +#include "HTAccess.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF(HTProtocol,HTTelnet); +extern GLOBALREF(HTProtocol,HTRlogin); +extern GLOBALREF(HTProtocol,HTTn3270); +#else +GLOBALREF HTProtocol HTTelnet; +GLOBALREF HTProtocol HTRlogin; +GLOBALREF HTProtocol HTTn3270; +#endif /* GLOBALREF_IS_MACRO */ +#endif /* HTTELNET_H */ + +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.c new file mode 100644 index 00000000000..865315cc0aa --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.c @@ -0,0 +1,207 @@ + +/* MODULE HTUU.c +** UUENCODE AND UUDECODE +** +** ACKNOWLEDGEMENT: +** This code is taken from rpem distribution, and was originally +** written by Mark Riordan. +** +** AUTHORS: +** MR Mark Riordan riordanmr@clvax1.cl.msu.edu +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** Added as part of the WWW library and edited to conform +** with the WWW project coding standards by: AL 5 Aug 1993 +** Originally written by: MR 12 Aug 1990 +** Original header text: +** ------------------------------------------------------------- +** File containing routines to convert a buffer +** of bytes to/from RFC 1113 printable encoding format. +** +** This technique is similar to the familiar Unix uuencode +** format in that it maps 6 binary bits to one ASCII +** character (or more aptly, 3 binary bytes to 4 ASCII +** characters). However, RFC 1113 does not use the same +** mapping to printable characters as uuencode. +** +** Mark Riordan 12 August 1990 and 17 Feb 1991. +** This code is hereby placed in the public domain. +** ------------------------------------------------------------- +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include "HTUU.h" + +#include "LYLeaks.h" + +PRIVATE char six2pr[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/' +}; + +PRIVATE unsigned char pr2six[256]; + + +/*--- function HTUU_encode ----------------------------------------------- + * + * Encode a single line of binary data to a standard format that + * uses only printing ASCII characters (but takes up 33% more bytes). + * + * Entry bufin points to a buffer of bytes. If nbytes is not + * a multiple of three, then the byte just beyond + * the last byte in the buffer must be 0. + * nbytes is the number of bytes in that buffer. + * This cannot be more than 48. + * bufcoded points to an output buffer. Be sure that this + * can hold at least 1 + (4*nbytes)/3 characters. + * + * Exit bufcoded contains the coded line. The first 4*nbytes/3 bytes + * contain printing ASCII characters representing + * those binary bytes. This may include one or + * two '=' characters used as padding at the end. + * The last byte is a zero byte. + * Returns the number of ASCII characters in "bufcoded". + */ +PUBLIC int HTUU_encode ARGS3(unsigned char *, bufin, + unsigned int, nbytes, + char *, bufcoded) +{ +/* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) six2pr[c] + + register char *outptr = bufcoded; + unsigned int i; + /* This doesn't seem to be needed (AL): register unsigned char *inptr = bufin; */ + + for (i=0; i<nbytes; i += 3) { + *(outptr++) = ENC(*bufin >> 2); /* c1 */ + *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/ + *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/ + *(outptr++) = ENC(bufin[2] & 077); /* c4 */ + + bufin += 3; + } + + /* If nbytes was not a multiple of 3, then we have encoded too + * many characters. Adjust appropriately. + */ + if(i == nbytes+1) { + /* There were only 2 bytes in that last group */ + outptr[-1] = '='; + } else if(i == nbytes+2) { + /* There was only 1 byte in that last group */ + outptr[-1] = '='; + outptr[-2] = '='; + } + *outptr = '\0'; + return(outptr - bufcoded); +} + + +/*--- function HTUU_decode ------------------------------------------------ + * + * Decode an ASCII-encoded buffer back to its original binary form. + * + * Entry bufcoded points to a uuencoded string. It is + * terminated by any character not in + * the printable character table six2pr, but + * leading whitespace is stripped. + * bufplain points to the output buffer; must be big + * enough to hold the decoded string (generally + * shorter than the encoded string) plus + * as many as two extra bytes used during + * the decoding process. + * outbufsize is the maximum number of bytes that + * can fit in bufplain. + * + * Exit Returns the number of binary bytes decoded. + * bufplain contains these bytes. + */ +PUBLIC int HTUU_decode ARGS3(char *, bufcoded, + unsigned char *, bufplain, + int, outbufsize) +{ +/* single character decode */ +#define DEC(c) pr2six[(int)c] +#define MAXVAL 63 + + static int first = 1; + + int nbytesdecoded, j; + register char *bufin = bufcoded; + register unsigned char *bufout = bufplain; + register int nprbytes; + + /* If this is the first call, initialize the mapping table. + * This code should work even on non-ASCII machines. + */ + if(first) { + first = 0; + for(j=0; j<256; j++) pr2six[j] = MAXVAL+1; + + for(j=0; j<64; j++) pr2six[(unsigned char)six2pr[j]] = (unsigned char)j; +#if 0 + pr2six['A']= 0; pr2six['B']= 1; pr2six['C']= 2; pr2six['D']= 3; + pr2six['E']= 4; pr2six['F']= 5; pr2six['G']= 6; pr2six['H']= 7; + pr2six['I']= 8; pr2six['J']= 9; pr2six['K']=10; pr2six['L']=11; + pr2six['M']=12; pr2six['N']=13; pr2six['O']=14; pr2six['P']=15; + pr2six['Q']=16; pr2six['R']=17; pr2six['S']=18; pr2six['T']=19; + pr2six['U']=20; pr2six['V']=21; pr2six['W']=22; pr2six['X']=23; + pr2six['Y']=24; pr2six['Z']=25; pr2six['a']=26; pr2six['b']=27; + pr2six['c']=28; pr2six['d']=29; pr2six['e']=30; pr2six['f']=31; + pr2six['g']=32; pr2six['h']=33; pr2six['i']=34; pr2six['j']=35; + pr2six['k']=36; pr2six['l']=37; pr2six['m']=38; pr2six['n']=39; + pr2six['o']=40; pr2six['p']=41; pr2six['q']=42; pr2six['r']=43; + pr2six['s']=44; pr2six['t']=45; pr2six['u']=46; pr2six['v']=47; + pr2six['w']=48; pr2six['x']=49; pr2six['y']=50; pr2six['z']=51; + pr2six['0']=52; pr2six['1']=53; pr2six['2']=54; pr2six['3']=55; + pr2six['4']=56; pr2six['5']=57; pr2six['6']=58; pr2six['7']=59; + pr2six['8']=60; pr2six['9']=61; pr2six['+']=62; pr2six['/']=63; +#endif + } + + /* Strip leading whitespace. */ + + while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++; + + /* Figure out how many characters are in the input buffer. + * If this would decode into more bytes than would fit into + * the output buffer, adjust the number of input bytes downwards. + */ + bufin = bufcoded; + while(pr2six[(unsigned char)*(bufin++)] <= MAXVAL); + nprbytes = bufin - bufcoded - 1; + nbytesdecoded = ((nprbytes+3)/4) * 3; + if(nbytesdecoded > outbufsize) { + nprbytes = (outbufsize*4)/3; + } + + bufin = bufcoded; + + while (nprbytes > 0) { + *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); + *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); + *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); + bufin += 4; + nprbytes -= 4; + } + + if(nprbytes & 03) { + if(pr2six[(int)bufin[-2]] > MAXVAL) { + nbytesdecoded -= 2; + } else { + nbytesdecoded -= 1; + } + } + + return(nbytesdecoded); +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.h new file mode 100644 index 00000000000..05874e240a5 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.h @@ -0,0 +1,29 @@ +/* ENCODING TO PRINTABLE CHARACTERS + + File module provides functions HTUU_encode() and HTUU_decode() which convert a buffer + of bytes to/from RFC 1113 printable encoding format. This technique is similar to the + familiar Unix uuencode format in that it maps 6 binary bits to one ASCII character (or + more aptly, 3 binary bytes to 4 ASCII characters). However, RFC 1113 does not use the + same mapping to printable characters as uuencode. + + */ + +#ifndef HTUU_H +#define HTUU_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +PUBLIC int HTUU_encode PARAMS((unsigned char *bufin, + unsigned int nbytes, + char *bufcoded)); + +PUBLIC int HTUU_decode PARAMS((char *bufcoded, + unsigned char *bufplain, + int outbufsize)); + +#endif +/* + + End of file. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUtils.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUtils.h new file mode 100644 index 00000000000..21128bb99f4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTUtils.h @@ -0,0 +1,447 @@ +/* Utitlity macros for the W3 code library + MACROS FOR GENERAL USE + + Generates: HTUtils.h + + See also: the system dependent file "tcp.h" + + */ + +#ifndef DEBUG +#define DEBUG /* Noone ever turns this off as trace is too important */ +#endif /* Keep option for really small memory applications tho */ + +#ifndef HTUTILS_H +#define HTUTILS_H + +#ifdef HAVE_CONFIG_H +#include <lynx_cfg.h> /* generated by autoconf 'configure' script */ +#include <sys/types.h> +#else + +#define DONT_TRACK_INTERNAL_LINKS 1 + +/* Explicit system-configure */ +#ifdef VMS +#define NO_SIZECHANGE +#define NO_UNISTD_H +#define NO_KEYPAD +#define NO_UTMP +#endif + +/* FIXME: these will be removed after completing auto-configure script */ + +#ifdef _IBMR2 +#define USE_DIRENT /* sys V style directory open */ +#endif /* _IBMR2 */ + +#ifdef _SYSV3 +#include <fcntl.h> +#define USE_DIRENT /* sys V style directory open */ +#endif /* _SYSV3 */ + +/* Solaris. */ +#if defined(sun) && defined(__svr4__) && !defined(USE_DIRENT) +#define USE_DIRENT /* sys V style directory open */ +#endif /* sun && __svr4__ && !USE_DIRENT */ + +#ifdef __alpha +#define USE_DIRENT +#endif /* __alpha */ + +#ifndef USE_DIRENT +#ifdef SVR4 +#define USE_DIRENT +#endif /* SVR4 */ +#endif /* !USE_DIRENT */ + +#ifndef SOLARIS2 +#include <string.h> /* For bzero etc */ +#endif /* !SOLARIS2 */ + +#ifdef SCO +#define sco +#endif /* SCO */ +#ifdef sco +#include <sys/fcntl.h> +#define USE_DIRENT +#endif /* sco */ + +/* +Intergraph CLIX + */ +#ifdef CLIX +#include <sys/fcntl.h> +#define USE_DIRENT +#endif /* CLIX */ + +#ifdef ISC +#ifndef NO_UNISTD_H +#include <sys/unistd.h> +#endif /* !NO_UNISTD_H */ +#else +#if !defined(NO_UNISTD_H) && !defined(VMS) +#include <unistd.h> +#endif /* !NO_UNISTD_H && !VMS */ +#endif /* ISC */ + +#if defined(SVR4) || defined(UNIXWARE) +#include <sys/fcntl.h> +#ifndef NO_FILIO_H /* BSD Interactive doesn't have filio.h. */ +#include <sys/filio.h> +#endif /* !NO_FILIO_H */ +#endif /* SVR4 || UNIXWARE */ + +/* +SOLARIS 2 + */ +#ifdef SOLARIS2 +#include <sys/filio.h> +#endif /* SOLARIS2 */ + +#ifndef NO_FILIO_H +#define NO_FILIO_H /* prevent conflict between autoconf & BSDI make */ +#endif + +/* Accommodate pre-autoconf Makefile */ + +#ifndef NO_CBREAK +#define HAVE_CBREAK 1 +#endif + +#ifndef NO_CUSERID +#define HAVE_CUSERID 1 +#endif + +#ifndef NO_FILIO_H +#define HAVE_SYS_FILIO_H 1 +#endif + +#ifndef NO_GETCWD +#define HAVE_GETCWD 1 +#endif + +#ifndef USE_SLANG +#ifndef NO_KEYPAD +#define HAVE_KEYPAD 1 +#endif +#ifndef NO_TTYTYPE +#define HAVE_TTYTYPE 1 +#endif +#endif /* USE_SLANG */ + +#ifndef NO_PUTENV +#define HAVE_PUTENV 1 +#endif + +#ifndef NO_SIZECHANGE +#define HAVE_SIZECHANGE 1 +#endif + +#ifndef NO_UNISTD_H +#define HAVE_UNISTD_H 1 +#endif + +#ifndef NO_UTMP +#define HAVE_UTMP 1 +#endif + +#endif + +#ifndef GCC_UNUSED +#define GCC_UNUSED /* nothing */ +#endif + +#ifdef _WINDOWS /* SCW */ +#include "windef.h" +#define BOOLEAN_DEFINED +#define va_arg +#include <dos.h> +#define popen _popen +#define pclose _pclose +#endif /* _WINDOWS */ + +#ifdef SHORT_NAMES +#define WWW_TraceFlag HTTrFlag +#endif + +/* + +Debug message control. + + */ +#ifndef STDIO_H +#include <stdio.h> +#define STDIO_H +#endif + +#ifdef DEBUG +#define TRACE (WWW_TraceFlag) +#define PROGRESS(str) printf(str) + extern int WWW_TraceFlag; +#else +#define TRACE 0 +#define PROGRESS(str) /* nothing for now */ +#endif + +#define CTRACE if(TRACE)fprintf +#define tfp stderr + +/* + + ERROR TYPE + + This is passed back when streams are aborted. It might be nice to have some structure + of error messages, numbers, and recursive pointers to reasons. Curently this is a + placeholder for something more sophisticated. + + */ +typedef void * HTError; /* Unused at present -- best definition? */ + +/* + +Standard C library for malloc() etc + + */ +#ifdef DGUX +#include <stdlib.h> +#endif /* DGUX */ + +#ifdef vax +#ifdef unix +#define ultrix /* Assume vax+unix=ultrix */ +#endif /* unix */ +#endif /* vax */ + +#ifndef VMS +#ifndef ultrix + +#ifdef NeXT +#include <libc.h> /* NeXT */ +#endif /* NeXT */ +#ifndef MACH /* Vincent.Cate@furmint.nectar.cs.cmu.edu */ +#ifndef __STRICT_BSD__ +#include <stdlib.h> +#endif /* !__STRICT_BSD__ */ +#endif /* !MACH */ + +#else /* ultrix: */ + +#include <malloc.h> +#include <memory.h> +#include <stdio.h> +#include <stdlib.h> /* ANSI */ /* BSN */ + +#endif /* !ultrix */ +#else /* VMS: */ + +#include <stdlib.h> +#include <unixlib.h> +#include <ctype.h> +#if defined(VAXC) && !defined(__DECC) +#define malloc VAXC$MALLOC_OPT +#define calloc VAXC$CALLOC_OPT +#define free VAXC$FREE_OPT +#define cfree VAXC$CFREE_OPT +#define realloc VAXC$REALLOC_OPT +#endif /* VAXC && !__DECC */ + +#endif /* !VMS */ + +/* + +Macros for declarations + + */ +#define PUBLIC /* Accessible outside this module */ +#define PRIVATE static /* Accessible only within this module */ + +#ifdef __STDC__ +#define CONST const /* "const" only exists in STDC */ +#define NOPARAMS (void) +#define PARAMS(parameter_list) parameter_list +#define NOARGS (void) +#define ARGS1(t,a) \ + (t a) +#define ARGS2(t,a,u,b) \ + (t a, u b) +#define ARGS3(t,a,u,b,v,c) \ + (t a, u b, v c) +#define ARGS4(t,a,u,b,v,c,w,d) \ + (t a, u b, v c, w d) +#define ARGS5(t,a,u,b,v,c,w,d,x,e) \ + (t a, u b, v c, w d, x e) +#define ARGS6(t,a,u,b,v,c,w,d,x,e,y,f) \ + (t a, u b, v c, w d, x e, y f) +#define ARGS7(t,a,u,b,v,c,w,d,x,e,y,f,z,g) \ + (t a, u b, v c, w d, x e, y f, z g) +#define ARGS8(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h) \ + (t a, u b, v c, w d, x e, y f, z g, s h) +#define ARGS9(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i) \ + (t a, u b, v c, w d, x e, y f, z g, s h, r i) +#define ARGS10(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i,q,j) \ + (t a, u b, v c, w d, x e, y f, z g, s h, r i, q j) + +#else /* not ANSI */ + +#ifndef _WINDOWS +#define CONST +#endif +#define NOPARAMS () +#define PARAMS(parameter_list) () +#define NOARGS () +#define ARGS1(t,a) (a) \ + t a; +#define ARGS2(t,a,u,b) (a,b) \ + t a; u b; +#define ARGS3(t,a,u,b,v,c) (a,b,c) \ + t a; u b; v c; +#define ARGS4(t,a,u,b,v,c,w,d) (a,b,c,d) \ + t a; u b; v c; w d; +#define ARGS5(t,a,u,b,v,c,w,d,x,e) (a,b,c,d,e) \ + t a; u b; v c; w d; x e; +#define ARGS6(t,a,u,b,v,c,w,d,x,e,y,f) (a,b,c,d,e,f) \ + t a; u b; v c; w d; x e; y f; +#define ARGS7(t,a,u,b,v,c,w,d,x,e,y,f,z,g) (a,b,c,d,e,f,g) \ + t a; u b; v c; w d; x e; y f; z g; +#define ARGS8(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h) (a,b,c,d,e,f,g,h) \ + t a; u b; v c; w d; x e; y f; z g; s h; +#define ARGS9(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i) (a,b,c,d,e,f,g,h,i) \ + t a; u b; v c; w d; x e; y f; z g; s h; r i; +#define ARGS10(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i,q,j) (a,b,c,d,e,f,g,h,i,j) \ + t a; u b; v c; w d; x e; y f; z g; s h; r i; q j; + + +#endif /* __STDC__ (ANSI) */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* + +Booleans + + */ +/* Note: GOOD and BAD are already defined (differently) on RS6000 aix */ +/* #define GOOD(status) ((status)38;1) VMS style status: test bit 0 */ +/* #define BAD(status) (!GOOD(status)) Bit 0 set if OK, otherwise clear */ + +#ifndef _WINDOWS +#ifndef BOOLEAN_DEFINED + typedef char BOOLEAN; /* Logical value */ +#ifndef CURSES +#ifndef TRUE +#define TRUE (BOOLEAN)1 +#define FALSE (BOOLEAN)0 +#endif +#endif /* CURSES */ +#endif /* _WINDOWS */ +#define BOOLEAN_DEFINED +#endif + +#ifndef BOOL +#define BOOL BOOLEAN +#endif +#ifndef YES +#define YES (BOOLEAN)1 +#define NO (BOOLEAN)0 +#endif + +extern BOOL LYOutOfMemory; /* Declared in LYexit.c - FM */ + +#define TCP_PORT 80 /* Allocated to http by Jon Postel/ISI 24-Jan-92 */ +#define OLD_TCP_PORT 2784 /* Try the old one if no answer on 80 */ +#define DNP_OBJ 80 /* This one doesn't look busy, but we must check */ + /* That one was for decnet */ + +/* Inline Function WHITE: Is character c white space? */ +/* For speed, include all control characters */ + +#define WHITE(c) (((unsigned char)(TOASCII(c))) <= 32) + + +/* + +Sucess (>=0) and failure (<0) codes + + */ + +#define HT_REDIRECTING 29996 +#define HT_LOADED 29997 /* Instead of a socket */ +#define HT_PARTIAL_CONTENT 206 /* Partial Content */ +#define HT_INTERRUPTED -29998 +#define HT_NOT_LOADED -29999 +#define HT_OK 0 /* Generic success*/ + +#define HT_ERROR -1 /* Generic failure */ + +#define HT_NO_ACCESS -10 /* Access not available */ +#define HT_FORBIDDEN -11 /* Access forbidden */ +#define HT_INTERNAL -12 /* Weird -- should never happen. */ +#define HT_BAD_EOF -12 /* Premature EOF */ + + +#include "HTString.h" /* String utilities */ + +#ifndef va_arg +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#endif + +/* + +Out Of Memory checking for malloc() return: + + */ +#ifndef __FILE__ +#define __FILE__ "" +#define __LINE__ "" +#endif + +#include "LYexit.h" + +#define outofmem(file, func)\ + { fprintf(stderr,\ + "\r\n\r\n\r\n%s %s: out of memory. Aborting...\r\n", file, func);\ + LYOutOfMemory = TRUE; exit(-1);} +/* extern void outofmem PARAMS((const char *fname, const char *func)); */ + +/* + +Upper- and Lowercase macros + + The problem here is that toupper(x) is not defined officially unless isupper(x) is. + These macros are CERTAINLY needed on #if defined(pyr) || define(mips) or BDSI + platforms. For safefy, we make them mandatory. + + */ +#include <ctype.h> +#include <string.h> + +#ifndef TOLOWER + /* Pyramid and Mips can't uppercase non-alpha */ +#define TOLOWER(c) (isupper((unsigned char)c) ? tolower((unsigned char)c) : ((unsigned char)c)) +#define TOUPPER(c) (islower((unsigned char)c) ? toupper((unsigned char)c) : ((unsigned char)c)) +#endif /* TOLOWER */ + +/* + +The local equivalents of CR and LF + + We can check for these after net ascii text has been converted to the local + representation. Similarly, we include them in strings to be sent as net ascii after + translation. + + */ +#define LF FROMASCII('\012') /* ASCII line feed LOCAL EQUIVALENT */ +#define CR FROMASCII('\015') /* Will be converted to ^M for transmission */ + +#endif /* HTUTILS_H */ + +/* + + end of utilities */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.c new file mode 100644 index 00000000000..118f95178b2 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.c @@ -0,0 +1,1264 @@ + +/* MODULE HTVMSUtil.c +** VMS Utility Routines +** +** AUTHORS: +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 14 Nov 93 MD Written +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTFormat.h" +#include "HTStream.h" +#include "UCDefs.h" +#include "UCMap.h" +#include "UCAux.h" +#include "HTVMSUtils.h" +/*#include <stdio.h> included by HTUtils.h -- FM */ +/*#include <unixlib.h> included by HTUtils.h -- FM */ +#include <ssdef.h> +#include <jpidef.h> +#include <prvdef.h> +#include <acldef.h> +#include <chpdef.h> +#include <descrip.h> +#include <lib$routines.h> +#include <starlet.h> +#include <rmsdef.h> + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define INFINITY 512 /* File name length @@ FIXME */ + +PUBLIC BOOL HTVMSFileVersions=FALSE; /* Include version numbers in listing? */ + +typedef struct { + unsigned long BufferLength : 16; + unsigned long ItemCode : 16; + unsigned long BufferAddress : 32; + unsigned long ReturnLengthAddress : 32; +} ItemStruct; + +extern CONST char * HTHostName NOPARAMS; + +/* PUBLIC HTVMS_authSysPrv() +** CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns YES if SYSPRV is authorized +*/ +PUBLIC BOOL HTVMS_authSysPrv NOARGS +{ +unsigned long Result; +ItemStruct ItemList[2]; +unsigned long Length; +unsigned long Buffer[2]; + + /* fill Item */ + ItemList[0].BufferLength = sizeof(Buffer); + ItemList[0].BufferAddress = (unsigned long)Buffer; + ItemList[0].ReturnLengthAddress = (unsigned long)&Length; + ItemList[0].ItemCode = JPI$_AUTHPRIV; + + /* terminate list */ + ItemList[1].ItemCode = 0; + ItemList[1].BufferLength = 0; + + /* call system */ + Result = sys$getjpiw(0, 0, 0, ItemList, 0, 0, 0); + + if (Result != SS$_NORMAL) + return(NO); + + if (Buffer[0] & PRV$M_SYSPRV) + return(YES); + + return(NO); +} + + + +/* PUBLIC HTVMS_enableSysPrv() +** ENABLES SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** +*/ +PUBLIC void HTVMS_enableSysPrv NOARGS +{ +unsigned long Result; +unsigned long Prv[2], PreviousPrv[2]; + + Prv[0] = PRV$M_SYSPRV; + Prv[1] = 0; + Result = sys$setprv(1,&Prv,0,&PreviousPrv); + + if (TRACE) { + if (Result == SS$_NORMAL) { + if (!(PreviousPrv[0] & PRV$M_SYSPRV)) { + fprintf(stderr, "HTVMS_enableSysPrv: Enabled SYSPRV\n"); + } + } + } +} + + + +/* PUBLIC HTVMS_disableSysPrv() +** DISABLES SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** +*/ +PUBLIC void HTVMS_disableSysPrv NOARGS +{ +unsigned long Result; +unsigned long Prv[2], PreviousPrv[2]; + + Prv[0] = PRV$M_SYSPRV; + Prv[1] = 0; + Result = sys$setprv(0,&Prv,0,&PreviousPrv); + + if (TRACE) { + if (Result == SS$_NORMAL) { + if (PreviousPrv[0] & PRV$M_SYSPRV) { + fprintf(stderr, "HTVMS_disableSysPrv: Disabled SYSPRV\n"); + } + } + } +} + + + +/* PUBLIC HTVMS_checkAccess() +** CHECKS ACCESS TO FILE FOR CERTAIN USER +** ON ENTRY: +** FileName The file to be accessed +** UserName Name of the user to check access for. +** User nobody, represented by "" is given NO for an answer +** Method Name of the method to be chceked +** +** ON EXIT: +** returns YES if access is allowed +** +*/ +PUBLIC BOOL HTVMS_checkAccess ARGS3( + CONST char *, FileName, + CONST char *, UserName, + CONST char *, Method) +{ +unsigned long Result; +ItemStruct ItemList[2]; +unsigned long Length; +unsigned long Buffer; +unsigned long ObjType; + +char *VmsName; + +struct dsc$descriptor_s FileNameDesc; +struct dsc$descriptor_s UserNameDesc; + +char *colon; + + /* user nobody should access as from account under which server is running */ + if (0 == strcmp(UserName,"")) + return(NO); + + /* check Filename and convert */ + colon = strchr(FileName,':'); + if (colon) + VmsName = HTVMS_name("",colon+1); + else + VmsName = HTVMS_name("",FileName); + + /* check for GET */ + if (0 == strcmp(Method,"GET")) + { + /* fill Item */ + ItemList[0].BufferLength = sizeof(Buffer); + ItemList[0].BufferAddress = (unsigned long)&Buffer; + ItemList[0].ReturnLengthAddress = (unsigned long)&Length; + ItemList[0].ItemCode = CHP$_FLAGS; + + /* terminate list */ + ItemList[1].ItemCode = 0; + ItemList[1].BufferLength = 0; + + /* fill input */ + ObjType = ACL$C_FILE; + Buffer = CHP$M_READ; + UserNameDesc.dsc$w_length = strlen(UserName); + UserNameDesc.dsc$b_dtype = DSC$K_DTYPE_T; + UserNameDesc.dsc$b_class = DSC$K_CLASS_S; + UserNameDesc.dsc$a_pointer = (char *)UserName; + FileNameDesc.dsc$w_length = strlen(VmsName); + FileNameDesc.dsc$b_dtype = DSC$K_DTYPE_T; + FileNameDesc.dsc$b_class = DSC$K_CLASS_S; + FileNameDesc.dsc$a_pointer = VmsName; + + /* call system */ + Result = sys$check_access(&ObjType,&FileNameDesc,&UserNameDesc,ItemList); + + if (Result == SS$_NORMAL) + return(YES); + else + return(NO); + } + + return(NO); +} + + + +/* PUBLIC HTVMS_wwwName() +** CONVERTS VMS Name into WWW Name +** ON ENTRY: +** vmsname VMS file specification (NO NODE) +** +** ON EXIT: +** returns www file specification +** +** EXAMPLES: +** vmsname wwwname +** DISK$USER disk$user +** DISK$USER: /disk$user/ +** DISK$USER:[DUNS] /disk$user/duns +** DISK$USER:[DUNS.ECHO] /disk$user/duns/echo +** [DUNS] duns +** [DUNS.ECHO] duns/echo +** [DUNS.ECHO.-.TRANS] duns/echo/../trans +** [DUNS.ECHO.--.TRANS] duns/echo/../../trans +** [.DUNS] duns +** [.DUNS.ECHO] duns/echo +** [.DUNS.ECHO]TEST.COM duns/echo/test.com +** TEST.COM test.com +** +** +*/ +PUBLIC char * HTVMS_wwwName ARGS1( + char *, vmsname) +{ +static char wwwname[256]; +char *src, *dst; +int dir; + dst = wwwname; + src = vmsname; + dir = 0; + if (strchr(src,':')) *(dst++) = '/'; + for ( ; *src != '\0' ; src++) + { + switch(*src) + { + case ':': *(dst++) = '/'; break; + case '-': if (dir) + { + if ((*(src-1)=='[' || *(src-1)=='.' || *(src-1)=='-') && + (*(src+1)=='.' || *(src+1)=='-')) + { + *(dst++) = '/'; + *(dst++) = '.'; + *(dst++) = '.'; + } + else + *(dst++) = '-'; + } + else + { + if (*(src-1) == ']') *(dst++) = '/'; + *(dst++) = '-'; + } + break; + case '.': if (dir) + { + if (*(src-1) != '[') *(dst++) = '/'; + } + else + { + if (*(src-1) == ']') *(dst++) = '/'; + *(dst++) = '.'; + } + break; + case '[': dir = 1; break; + case ']': dir = 0; break; + default: if (*(src-1) == ']') *(dst++) = '/'; + *(dst++) = *src; + break; + } + } + *(dst++) = '\0'; + return(wwwname); +} + + +/* PUBLIC HTVMS_name() +** CONVERTS WWW name into a VMS name +** ON ENTRY: +** nn Node Name (optional) +** fn WWW file name +** +** ON EXIT: +** returns vms file specification +** +** Bug: Returns pointer to static -- non-reentrant +*/ +PUBLIC char * HTVMS_name ARGS2( + CONST char *, nn, + CONST char *, fn) +{ + +/* We try converting the filename into Files-11 syntax. That is, we assume +** first that the file is, like us, on a VMS node. We try remote +** (or local) DECnet access. Files-11, VMS, VAX and DECnet +** are trademarks of Digital Equipment Corporation. +** The node is assumed to be local if the hostname WITHOUT DOMAIN +** matches the local one. @@@ +*/ + static char vmsname[INFINITY]; /* returned */ + char * filename = (char*)malloc(strlen(fn)+1); + char * nodename = (char*)malloc(strlen(nn)+2+1); /* Copies to hack */ + char *second; /* 2nd slash */ + char *last; /* last slash */ + + char * hostname = (char *)HTHostName(); + + if (!filename || !nodename) outofmem(__FILE__, "HTVMSname"); + strcpy(filename, fn); + strcpy(nodename, ""); /* On same node? Yes if node names match */ + if (strncmp(nn,"localhost",9)) { + char *p, *q; + for (p=hostname, q=(char *)nn; + *p && *p!='.' && *q && *q!='.'; p++, q++){ + if (TOUPPER(*p)!=TOUPPER(*q)) { + strcpy(nodename, nn); + q = strchr(nodename, '.'); /* Mismatch */ + if (q) *q=0; /* Chop domain */ + strcat(nodename, "::"); /* Try decnet anyway */ + break; + } + } + } + + second = strchr(filename+1, '/'); /* 2nd slash */ + last = strrchr(filename, '/'); /* last slash */ + + if (!second) { /* Only one slash */ + sprintf(vmsname, "%s%s", nodename, filename + 1); + } else if(second==last) { /* Exactly two slashes */ + *second = 0; /* Split filename from disk */ + sprintf(vmsname, "%s%s:%s", nodename, filename+1, second+1); + *second = '/'; /* restore */ + } else { /* More than two slashes */ + char * p; + *second = 0; /* Split disk from directories */ + *last = 0; /* Split dir from filename */ + sprintf(vmsname, "%s%s:[%s]%s", + nodename, filename+1, second+1, last+1); + *second = *last = '/'; /* restore filename */ + for (p=strchr(vmsname, '['); *p!=']'; p++) + if (*p=='/') *p='.'; /* Convert dir sep. to dots */ + } + FREE(nodename); + FREE(filename); + return vmsname; +} + +/* +** The code below is for directory browsing by VMS Curses clients. +** It is based on the newer WWWLib's HTDirBrw.c. - Foteos Macrides +*/ +PUBLIC int HTStat ARGS2( + CONST char *, filename, + stat_t *, info) +{ + /* + the following stuff does not work in VMS with a normal stat... + --> /disk$user/duns/www if www is a directory + is statted like: /disk$user/duns/www.dir + after a normal stat has failed + --> /disk$user/duns if duns is a toplevel directory + is statted like: /disk$user/000000/duns.dir + --> /disk$user since disk$user is a device + is statted like: /disk$user/000000/000000.dir + --> / + searches all devices, no solution yet... + --> /vxcern!/disk$cr/wwwteam/login.com + is not statted but granted with fake information... + */ +int Result; +int Len; +char *Ptr, *Ptr2; +char Name[256]; + + /* try normal stat... */ + Result = stat((char *)filename,info); + if (Result == 0) + return(Result); + + /* make local copy */ + strcpy(Name,filename); + +#ifdef NOT_USED + /* if filename contains a node specification (! or ::), we will try to access + the file via DECNET, but we do not stat it..., just return success + with some fake information... */ + if (HTVMS_checkDecnet(Name)) + { + /* set up fake info, only the one we use... */ + info->st_dev = NULL; + info->st_ino[0] = 0; + info->st_ino[1] = 0; + info->st_ino[2] = 0; + info->st_mode = S_IFREG | S_IREAD; /* assume it is a regular Readable file */ + info->st_nlink = NULL; + info->st_uid = 0; + info->st_gid = 0; + info->st_rdev = 0; + info->st_size = 0; + info->st_atime = time(NULL); + info->st_mtime = time(NULL); + info->st_ctime = time(NULL); + + return(0); + } +#endif /* NOT_USED */ + + /* failed,so do device search in case root is requested */ + if (!strcmp(Name,"/")) + { /* root requested */ + return(-1); + } + + /* failed so this might be a directory, add '.dir' */ + Len = strlen(Name); + if (Name[Len-1] == '/') + Name[Len-1] = '\0'; + + /* fail in case of device */ + Ptr = strchr(Name+1,'/'); + if ((Ptr == NULL) && (Name[0] == '/')) + { /* device only... */ + strcat(Name,"/000000/000000"); + } + + if (Ptr != NULL) + { /* correct filename in case of toplevel dir */ + Ptr2 = strchr(Ptr+1,'/'); + if ((Ptr2 == NULL) && (Name[0] == '/')) + { + char End[256]; + strcpy(End,Ptr); + *(Ptr+1) = '\0'; + strcat(Name,"000000"); + strcat(Name,End); + } + } + + /* try in case a file on toplevel directory or .DIR was alreadyt specified */ + Result = stat(Name,info); + if (Result == 0) + return(Result); + + /* add .DIR and try again */ + strcat(Name,".dir"); + Result = stat(Name,info); + return(Result); +} + +/*** "dirent.h" ***/ +/* #include <types.h> already in tcp.h */ + +#ifndef _POSIX_SOURCE +#define d_ino d_fileno /* compatability */ +#ifndef NULL +#define NULL 0 +#endif +#endif /* !_POSIX_SOURCE */ + +typedef struct __dirdesc { +#if 0 + int dd_fd; /* file descriptor */ + long dd_loc; /* buf offset of entry from last readddir() */ + long dd_size; /* amount of valid data in buffer */ + long dd_bsize; /* amount of entries read at a time */ + long dd_off; /* Current offset in dir (for telldir) */ + char *dd_buf; /* directory data buffer */ +#endif + long context; /* context descriptor for LIB$FIND_FILE calls */ + char dirname[255+1]; /* keeps the directory name, including *.* */ + struct dsc$descriptor_s dirname_desc; /* descriptor of dirname */ +} DIR; + +PRIVATE DIR *HTVMSopendir(char *dirname); +PRIVATE struct dirent *HTVMSreaddir(DIR *dirp); +PRIVATE int HTVMSclosedir(DIR *dirp); +#if 0 +#ifndef _POSIX_SOURCE +extern void seekdir(/* DIR *dirp, int loc */); +extern long telldir(/* DIR *dirp */); +#endif /* POSIX_SOURCE */ +extern void rewinddir(/* DIR *dirp */); + +#ifndef lint +#define rewinddir(dirp) seekdir((dirp), (long)0) +#endif +#endif /* not defined for VMS */ + +/*** #include "sys_dirent.h" ***/ +/*** "sys_dirent.h" ***/ +struct dirent { +#if 0 + off_t d_off; /* offset of next disk dir entry */ +#endif + unsigned long d_fileno; /* file number of entry */ +#if 0 + unsigned short d_reclen; /* length of this record */ +#endif + unsigned short d_namlen; /* length of string in d_name */ + char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */ +}; + +#ifndef _POSIX_SOURCE +/* + * It's unlikely to change, but make sure that sizeof d_name above is + * at least MAXNAMLEN + 1 (more may be added for padding). + */ +#define MAXNAMLEN 255 +/* + * The macro DIRSIZ(dp) gives the minimum amount of space required to represent + * a directory entry. For any directory entry dp->d_reclen >= DIRSIZ(dp). + * Specific filesystem types may use this macro to construct the value + * for d_reclen. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ + (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3) + +#endif /* !_POSIX_SOURCE */ + + +PRIVATE DIR *HTVMSopendir(char *dirname) +{ +static DIR dir; +char *closebracket; +long status; +struct dsc$descriptor_s entryname_desc; +struct dsc$descriptor_s dirname_desc; +char DirEntry[256]; +char VMSentry[256]; +char UnixEntry[256]; +int index; +char *dot; + + /* check if directory exists */ + /* dirname can look like /disk$user/duns/www/test/multi */ + /* or like /disk$user/duns/www/test/multi/ */ + /* DirEntry should look like disk$user:[duns.www.test]multi in both cases */ + /* dir.dirname should look like disk$user:[duns.www.test.multi] */ + strcpy(UnixEntry,dirname); + if (UnixEntry[strlen(UnixEntry)-1] != '/') + strcat(UnixEntry,"/"); + + strcpy(DirEntry, HTVMS_name("",UnixEntry)); + strcpy(dir.dirname, DirEntry); + index = strlen(DirEntry) - 1; + + if (DirEntry[index] == ']') + DirEntry[index] = '\0'; + + if ((dot = strrchr(DirEntry,'.')) == NULL) + { /* convert disk$user:[duns] into disk$user:[000000]duns.dir */ + char *openbr = strrchr(DirEntry,'['); + if (!openbr) + { /* convert disk$user: into disk$user:[000000]000000.dir */ + strcpy(dir.dirname, DirEntry); + strcat(dir.dirname, "[000000]"); + strcat(DirEntry,"[000000]000000.dir"); + } + else + { + char End[256]; + strcpy(End,openbr+1); + *(openbr+1) = '\0'; + strcat(DirEntry,"000000]"); + strcat(DirEntry,End); + strcat(DirEntry,".dir"); + } + } + else + { + *dot = ']'; + strcat(DirEntry,".dir"); + } + + dir.context = 0; + dirname_desc.dsc$w_length = strlen(DirEntry); + dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + dirname_desc.dsc$b_class = DSC$K_CLASS_S; + dirname_desc.dsc$a_pointer = (char *)&(DirEntry); + + /* look for the directory */ + entryname_desc.dsc$w_length = 255; + entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + entryname_desc.dsc$b_class = DSC$K_CLASS_S; + entryname_desc.dsc$a_pointer = VMSentry; + + status = lib$find_file(&(dirname_desc), + &entryname_desc, + &(dir.context), + 0,0,0,0); + if (!(status & 0x01)) + { /* directory not found */ + return(NULL); + } + +#if 0 + /* now correct dirname, which looks like disk$user:[duns.www.test]multi */ + /* and should look like disk$user:[duns.www.test.multi] */ + closebracket = strchr(dir.dirname,']'); + *closebracket = '.'; + closebracket = strstr(dir.dirname,".dir"); + *closebracket = '\0'; + strcat(dir.dirname,"]"); +#endif + + if (HTVMSFileVersions) + strcat(dir.dirname,"*.*;*"); + else + strcat(dir.dirname,"*.*"); + dir.context = 0; + dir.dirname_desc.dsc$w_length = strlen(dir.dirname); + dir.dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + dir.dirname_desc.dsc$b_class = DSC$K_CLASS_S; + dir.dirname_desc.dsc$a_pointer = (char *)&(dir.dirname); + return(&dir); +} + +PRIVATE struct dirent *HTVMSreaddir(DIR *dirp) +{ +static struct dirent entry; +long status; +struct dsc$descriptor_s entryname_desc; +char *space, *slash; +char VMSentry[256]; +char *UnixEntry; + + entryname_desc.dsc$w_length = 255; + entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + entryname_desc.dsc$b_class = DSC$K_CLASS_S; + entryname_desc.dsc$a_pointer = VMSentry; + + status = lib$find_file(&(dirp->dirname_desc), + &entryname_desc, + &(dirp->context), + 0,0,0,0); + if (status == RMS$_NMF) + { /* no more files */ + return(NULL); + } + else + { /* ok */ + if (!(status & 0x01)) return(0); + if (HTVMSFileVersions) + space = strchr(VMSentry,' '); + else + space = strchr(VMSentry,';'); + if (space) + *space = '\0'; + + /* convert to unix style... */ + UnixEntry = HTVMS_wwwName(VMSentry); + slash = strrchr(UnixEntry,'/') + 1; + strcpy(entry.d_name,slash); + entry.d_namlen = strlen(entry.d_name); + entry.d_fileno = 1; + return(&entry); + } +} + +PRIVATE int HTVMSclosedir(DIR *dirp) +{ +long status; + + status = lib$find_file_end(&(dirp->context)); + if (!(status & 0x01)) exit(status); + dirp->context = 0; + return(0); +} + +#include "HTAnchor.h" +#include "HTParse.h" +#include "HTBTree.h" +#include "HTFile.h" /* For HTFileFormat() */ +#include "HTAlert.h" +/* +** Hypertext object building machinery. +*/ +#include "HTML.h" +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET (*targetClass._free)(target) +#define ABORT_TARGET (*targetClass._free)(target) +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; + +#define STRUCT_DIRENT struct dirent + +PRIVATE char * months[12] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +typedef struct _VMSEntryInfo { + char * filename; + char * type; + char * date; + unsigned int size; + BOOLEAN display; /* show this entry? */ +} VMSEntryInfo; + +PRIVATE void free_VMSEntryInfo_struct_contents ARGS1(VMSEntryInfo *,entry_info) +{ + if (entry_info) { + FREE(entry_info->filename); + FREE(entry_info->type); + FREE(entry_info->date); + } + /* dont free the struct */ +} + +#define FILE_BY_NAME 0 +#define FILE_BY_TYPE 1 +#define FILE_BY_SIZE 2 +#define FILE_BY_DATE 3 +extern BOOLEAN HTfileSortMethod; /* specifies the method of sorting */ + +PUBLIC int compare_VMSEntryInfo_structs ARGS2(VMSEntryInfo *,entry1, + VMSEntryInfo *,entry2) +{ + int i, status; + char date1[16], date2[16], time1[8], time2[8], month[4]; + + switch(HTfileSortMethod) + { + case FILE_BY_SIZE: + /* both equal or both 0 */ + if(entry1->size == entry2->size) + return(strcasecomp(entry1->filename, + entry2->filename)); + else + if(entry1->size > entry2->size) + return(1); + else + return(-1); + break; + case FILE_BY_TYPE: + if(entry1->type && entry2->type) { + status = strcasecomp(entry1->type, entry2->type); + if(status) + return(status); + /* else fall to filename comparison */ + } + return (strcasecomp(entry1->filename, + entry2->filename)); + break; + case FILE_BY_DATE: + if(entry1->date && entry2->date) { + /* + ** Make sure we have the correct length. - FM + */ + if (strlen(entry1->date) != 12 || + strlen(entry2->date) != 12) { + return (strcasecomp(entry1->filename, + entry2->filename)); + } + /* + ** Set up for sorting in reverse + ** chronological order. - FM + */ + if (entry1->date[7] != ' ') { + strcpy(date1, "9999"); + strcpy(time1, (char *)&entry1->date[7]); + } else { + strcpy(date1, (char *)&entry1->date[8]); + strcpy(time1, "00:00"); + } + strncpy(month, entry1->date, 3); + month[3] = '\0'; + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%s%d", (i < 10 ? "0" : ""), i); + strcat(date1, month); + strncat(date1, (char *)&entry1->date[4], 2); + date1[8] = '\0'; + if (date1[6] == ' ') { + date1[6] = '0'; + } + strcat(date1, time1); + if (entry2->date[7] != ' ') { + strcpy(date2, "9999"); + strcpy(time2, (char *)&entry2->date[7]); + } else { + strcpy(date2, (char *)&entry2->date[8]); + strcpy(time2, "00:00"); + } + strncpy(month, entry2->date, 3); + month[3] = '\0'; + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%s%d", (i < 10 ? "0" : ""), i); + strcat(date2, month); + strncat(date2, (char *)&entry2->date[4], 2); + date2[8] = '\0'; + if (date2[6] == ' ') { + date2[6] = '0'; + } + strcat(date2, time2); + /* + ** Do the comparison. - FM + */ + status = strcasecomp(date2, date1); + if(status) + return(status); + /* else fall to filename comparison */ + } + return (strcasecomp(entry1->filename, + entry2->filename)); + break; + case FILE_BY_NAME: + default: + return (strcmp(entry1->filename, + entry2->filename)); + } +} + + +/* HTVMSBrowseDir() +** +** This function generates a directory listing as an HTML-object +** for local file URL's. It assumes the first two elements of +** of the path are a device followed by a directory: +** +** file://localhost/device/directory[/[foo]] +** +** Will not accept 000000 as a directory name. +** Will offer links to parent through the top directory, unless +** a terminal slash was included in the calling URL. +** +** Returns HT_LOADED on success, HTLoadError() messages on error. +** +** Developed for Lynx by Foteos Macrides (macrides@sci.wfeb.edu). +*/ +PUBLIC int HTVMSBrowseDir ARGS4( + CONST char *, address, + HTParentAnchor *, anchor, + HTFormat, format_out, + HTStream *, sink +) +{ + HTStructured* target; + HTStructuredClass targetClass; + char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION); + char *tail = NULL; + char *title = NULL; + char *header = NULL; + char *parent = NULL; + char *relative = NULL; + char *cp, *cp1; + int pathend, len; + DIR *dp; + struct stat file_info; + time_t NowTime; + static char ThisYear[8]; + VMSEntryInfo *entry_info=0; + char string_buffer[64]; + extern BOOLEAN no_dotfiles, show_dotfiles; + + HTUnEscape(pathname); + CTRACE(stderr,"HTVMSBrowseDir: Browsing `%s\'\n", pathname); + + /* + * Require at least two elements (presumably a device and directory) + * and disallow the device root (000000 directory). Symbolic paths + * (e.g., sys$help) should have been translated and expanded (e.g., + * to /sys$sysroot/syshlp) before calling this routine. + */ + if (((*pathname != '/') || + (cp=strchr(pathname+1, '/')) == NULL || + *(cp+1) == '\0' || + 0==strncmp((cp+1), "000000", 6)) || + (dp=HTVMSopendir(pathname)) == NULL) { + FREE(pathname); + return HTLoadError(sink, 403, "Could not access directory."); + } + + /* + * Set up the output stream. + */ + _HTProgress ("Building directory listing..."); + if (UCLYhndl_HTFile_for_unspec >= 0) { + HTAnchor_setUCInfoStage(anchor, + UCLYhndl_HTFile_for_unspec, + UCT_STAGE_PARSER, + UCT_SETBY_DEFAULT); + } + target = HTML_new(anchor, format_out, sink); + targetClass = *(target->isa); + + /* + * Set up the offset string of the anchor reference, + * and strings for the title and header. + */ + cp = strrchr(pathname, '/'); /* find lastslash */ + StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */ + if (*tail != '\0') { + StrAllocCopy(title, tail); + *cp = '\0'; + if ((cp1=strrchr(pathname, '/')) != NULL && + cp1 != pathname && + strncmp((cp1+1), "000000", 6)) + StrAllocCopy(parent, (cp1+1)); + *cp = '/'; + } else { + pathname[strlen(pathname)-1] = '\0'; + cp = strrchr(pathname, '/'); + StrAllocCopy(title, (cp+1)); + pathname[strlen(pathname)] = '/'; + } + StrAllocCopy(header, pathname); + + /* + * Initialize path name for HTStat(). + */ + pathend = strlen(pathname); + if (*(pathname+pathend-1) != '/') { + StrAllocCat(pathname, "/"); + pathend++; + } + + /* + * Output the title and header. + */ + START(HTML_HTML); + PUTS("\n"); + START(HTML_HEAD); + PUTS("\n"); + HTUnEscape(title); + START(HTML_TITLE); + PUTS(title); + PUTS(" directory"); + END(HTML_TITLE); + PUTS("\n"); + FREE(title); + END(HTML_HEAD); + PUTS("\n"); + START(HTML_BODY); + PUTS("\n"); + HTUnEscape(header); + START(HTML_H1); + PUTS(header); + END(HTML_H1); + PUTS("\n"); + if (HTDirReadme == HT_DIR_README_TOP) { + FILE * fp; + if (header[strlen(header)-1] != '/') + StrAllocCat(header, "/"); + StrAllocCat(header, HT_DIR_README_FILE); + if ((fp = fopen(header, "r")) != NULL) { + START(HTML_PRE); + for(;;) { + char c = fgetc(fp); + if (c == (char)EOF) + break; +#ifdef NOTDEFINED + switch (c) { + case '&': + case '<': + case '>': + PUTC('&'); + PUTC('#'); + PUTC((char)(c / 10)); + PUTC((char) (c % 10)); + PUTC(';'); + break; + default: + PUTC(c); + } +#else + PUTC(c); +#endif /* NOTDEFINED */ + } + END(HTML_PRE); + fclose(fp); + } + } + FREE(header); + if (parent) { + relative = (char*) malloc(strlen(tail) + 4); + if (relative == NULL) + outofmem(__FILE__, "HTVMSBrowseDir"); + sprintf(relative, "%s/..", tail); + HTStartAnchor(target, "", relative); + PUTS("Up to "); + HTUnEscape(parent); + PUTS(parent); + END(HTML_A); + START(HTML_P); + PUTS("\n"); + FREE(relative); + FREE(parent); + } + + /* + * Set up the date comparison. + */ + NowTime = time(NULL); + strcpy(ThisYear, (char *)ctime(&NowTime)+20); + ThisYear[4] = '\0'; + + /* + * Now, generate the Btree and put it out to the output stream. + */ + { + char dottest = 2; /* To avoid two strcmp() each time */ + STRUCT_DIRENT *dirbuf; + HTBTree *bt; + + /* Set up sort key and initialize BTree */ + bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs); + + /* Build tree */ + while ((dirbuf = HTVMSreaddir(dp))) { + HTAtom *encoding = NULL; + HTFormat format; + + /* Skip if not used */ + if (!dirbuf->d_ino) { + continue; + } + + /* Current and parent directories are never shown in list */ + if (dottest && (!strcmp(dirbuf->d_name, ".") || + !strcmp(dirbuf->d_name, ".."))) { + dottest--; + continue; + } + + /* Don't show the selective enabling file + * unless version numbers are included */ + if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) { + continue; + } + + /* Skip files beginning with a dot? */ + if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') { + continue; + } + + /* OK, make an lstat() and get a key ready. */ + *(pathname+pathend) = '\0'; + StrAllocCat(pathname, dirbuf->d_name); + if (HTStat(pathname, &file_info)) { + /* for VMS the failure here means the file is not readable... + we however continue to browse through the directory... */ + continue; + } + entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo)); + if (entry_info == NULL) + outofmem(__FILE__, "HTVMSBrowseDir"); + entry_info->type = 0; + entry_info->size = 0; + entry_info->date = 0; + entry_info->filename = 0; + entry_info->display = TRUE; + + /* Get the type */ + format = HTFileFormat(dirbuf->d_name, &encoding, + (CONST char **)&cp); + if (!cp) { + if(!strncmp(HTAtom_name(format), "application",11)) + { + cp = HTAtom_name(format) + 12; + if(!strncmp(cp,"x-", 2)) + cp += 2; + } + else + cp = HTAtom_name(format); + } + StrAllocCopy(entry_info->type, cp); + + StrAllocCopy(entry_info->filename, dirbuf->d_name); + if ((file_info.st_mode & S_IFMT) == S_IFDIR) { + /* strip .DIR part... */ + char *dot; + dot = strstr(entry_info->filename, ".DIR"); + if (dot) + *dot = '\0'; + cp = entry_info->filename; + while (cp && *cp) { + *cp = TOLOWER(*cp); + cp++; + } + StrAllocCopy(entry_info->type, "Directory"); + } else { + if ((cp = strstr(entry_info->filename, "READ")) == NULL) { + cp = entry_info->filename; + } else { + cp += 4; + if (!strncmp(cp, "ME", 2)) { + cp += 2; + while (cp && *cp && *cp != '.') { + cp++; + } + } else if (!strncmp(cp, ".ME", 3)) { + cp = (entry_info->filename + + strlen(entry_info->filename)); + } else { + cp = entry_info->filename; + } + } + while (cp && *cp) { + *cp = TOLOWER(*cp); + cp++; + } + if (((len = strlen(entry_info->filename)) > 2) && + entry_info->filename[len-1] == 'z') { + if (entry_info->filename[len-2] == '.' || + entry_info->filename[len-2] == '_') + entry_info->filename[len-1] = 'Z'; + } + } + + /* Get the date */ + { + char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime); + *(t+24) = '\0'; + + StrAllocCopy(entry_info->date, (t+4)); + *((entry_info->date)+7) = '\0'; + if ((atoi((t+19))) < atoi(ThisYear)) + StrAllocCat(entry_info->date, (t+19)); + else { + StrAllocCat(entry_info->date, (t+11)); + *((entry_info->date)+12) = '\0'; + } + } + + /* Get the size */ + if ((file_info.st_mode & S_IFMT) != S_IFDIR) + entry_info->size = (unsigned int)file_info.st_size; + else + entry_info->size = 0; + + /* Now, update the BTree etc. */ + if(entry_info->display) + { + CTRACE(stderr,"Adding file to BTree: %s\n", + entry_info->filename); + HTBTree_add(bt, (VMSEntryInfo *)entry_info); + } + + } /* End while HTVMSreaddir() */ + + FREE(pathname); + HTVMSclosedir(dp); + + START(HTML_PRE); + /* + * Run through the BTree printing out in order + */ + { + HTBTElement * ele; + int i; + for (ele = HTBTree_next(bt, NULL); + ele != NULL; + ele = HTBTree_next(bt, ele)) + { + entry_info = (VMSEntryInfo *)HTBTree_object(ele); + + /* Output the date */ + if(entry_info->date) + { + PUTS(entry_info->date); + PUTS(" "); + } + else + PUTS(" * "); + + /* Output the type */ + if(entry_info->type) + { + for(i = 0; entry_info->type[i] != '\0' && i < 15; i++) + PUTC(entry_info->type[i]); + for(; i < 17; i++) + PUTC(' '); + + } + + /* Output the link for the name */ + HTDirEntry(target, tail, entry_info->filename); + PUTS(entry_info->filename); + END(HTML_A); + + /* Output the size */ + if(entry_info->size) + { + if(entry_info->size < 1024) + sprintf(string_buffer," %d bytes", + entry_info->size); + else + sprintf(string_buffer," %dKb", + entry_info->size/1024); + PUTS(string_buffer); + } + + PUTC('\n'); /* end of this entry */ + + free_VMSEntryInfo_struct_contents(entry_info); + } + } + + HTBTreeAndObject_free(bt); + + } /* End of both BTree loops */ + + /* + * Complete the output stream. + */ + END(HTML_PRE); + PUTS("\n"); + END(HTML_BODY); + PUTS("\n"); + END(HTML_HTML); + PUTS("\n"); + FREE(tail); + FREE_TARGET; + + return HT_LOADED; + +} /* End of directory reading section */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.h new file mode 100644 index 00000000000..e055d6724c6 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.h @@ -0,0 +1,116 @@ +/* VMS specific routines + + */ + +#ifndef HTVMSUTIL_H +#define HTVMSUTIL_H + +#include <stat.h> + +extern BOOL HTVMSFileVersions; /* Include version numbers in listing? */ + +/* PUBLIC HTVMS_authSysPrv() +** CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns YES if SYSPRV is authorized +*/ +PUBLIC BOOL HTVMS_authSysPrv NOPARAMS; + + +/* PUBLIC HTVMS_enableSysPrv() +** ENABLES SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** +*/ +PUBLIC void HTVMS_enableSysPrv NOPARAMS; + + +/* PUBLIC HTVMS_disableSysPrv() +** DISABLES SYSPRV +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** +*/ +PUBLIC void HTVMS_disableSysPrv NOPARAMS; + +/* PUBLIC HTVMS_checkAccess() +** CHECKS ACCESS TO FILE FOR CERTAIN USER +** ON ENTRY: +** FileName The file to be accessed +** UserName Name of the user to check access for +** +** ON EXIT: +** returns YES if access is allowed +** +*/ +PUBLIC BOOL HTVMS_checkAccess PARAMS(( + CONST char * FileName, + CONST char * UserName, + CONST char * Method)); + + +/* PUBLIC HTVMS_wwwName() +** CONVERTS VMS Name into WWW Name +** ON ENTRY: +** vmsname VMS file specification (NO NODE) +** +** ON EXIT: +** returns www file specification +** +** EXAMPLES: +** vmsname wwwname +** DISK$USER disk$user +** DISK$USER: /disk$user/ +** DISK$USER:[DUNS] /disk$user/duns +** DISK$USER:[DUNS.ECHO] /disk$user/duns/echo +** [DUNS] duns +** [DUNS.ECHO] duns/echo +** [DUNS.ECHO.-.TRANS] duns/echo/../trans +** [DUNS.ECHO.--.TRANS] duns/echo/../../trans +** [.DUNS] duns +** [.DUNS.ECHO] duns/echo +** [.DUNS.ECHO]TEST.COM duns/echo/test.com +** TEST.COM test.com +** +** +*/ +PUBLIC char * HTVMS_wwwName PARAMS(( + char * vmsname)); + +/* PUBLIC HTVMS_name() +** CONVERTS WWW name into a VMS name +** ON ENTRY: +** nn Node Name (optional) +** fn WWW file name +** +** ON EXIT: +** returns vms file specification +** +** Bug: Returns pointer to static -- non-reentrant +*/ +PUBLIC char * HTVMS_name PARAMS(( + CONST char * nn, + CONST char * fn)); + +PUBLIC int HTStat PARAMS(( + CONST char * filename, + stat_t * info)); + +PUBLIC int HTVMSBrowseDir PARAMS(( + CONST char * address, + HTParentAnchor * anchor, + HTFormat format_out, + HTStream * sink)); + +#endif /* not HTVMSUTIL_H */ +/* + + End of file HTVMSUtil.h. */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.c new file mode 100644 index 00000000000..ee3a51c0e14 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.c @@ -0,0 +1,2501 @@ +/* HTVMS_WAISProt.c +** +** Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu) +** +** 31-May-1994 FM Initial version. +** +**----------------------------------------------------------------------*/ + +/* +** Routines originally from WProt.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 3.30.90 Harry Morris + - removed chunk code from WAISSearchAPDU, + - added makeWAISQueryType1Query() and readWAISType1Query() which replace + makeWAISQueryTerms() and makeWAISQueryDocs(). + 4.11.90 HWM - generalized conditional includes (see c-dialect.h) + - renamed makeWAISType1Query() to makeWAISTextQuery() + renamed readWAISType1Query() to readWAISTextQuery() + 5.29.90 TS - fixed bug in makeWAISQueryDocs + added CSTFreeWAISFoo functions +*/ + +#define _C_WAIS_protocol_ + +/* This file implements the Z39.50 extensions required for WAIS +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTVMS_WaisUI.h" +#include "HTVMS_WaisProt.h" + +#include "LYLeaks.h" + + +/* very rough estimates of the size of an object */ +#define DefWAISInitResponseSize (size_t)200 +#define DefWAISSearchSize (size_t)3000 +#define DefWAISSearchResponseSize (size_t)6000 +#define DefWAISPresentSize (size_t)1000 +#define DefWAISPresentResponseSize (size_t)6000 +#define DefWAISDocHeaderSize (size_t)500 +#define DefWAISShortHeaderSize (size_t)200 +#define DefWAISLongHeaderSize (size_t)800 +#define DefWAISDocTextSize (size_t)6000 +#define DefWAISDocHeadlineSize (size_t)500 +#define DefWAISDocCodeSize (size_t)500 + +#define RESERVE_SPACE_FOR_WAIS_HEADER(len) \ + if (*len > 0) \ + *len -= header_len; + +/*----------------------------------------------------------------------*/ + +static unsigned long userInfoTagSize _AP((data_tag tag, + unsigned long length)); + +static unsigned long +userInfoTagSize(tag,length) +data_tag tag; +unsigned long length; +/* return the number of bytes required to write the user info tag and + length + */ +{ + unsigned long size; + + /* calculate bytes required to represent tag. max tag is 16K */ + size = writtenCompressedIntSize(tag); + size += writtenCompressedIntSize(length); + + return(size); +} + +/*----------------------------------------------------------------------*/ + +static char* writeUserInfoHeader _AP((data_tag tag,long infoSize, + long estHeaderSize,char* buffer, + long* len)); + +static char* +writeUserInfoHeader(tag,infoSize,estHeaderSize,buffer,len) +data_tag tag; +long infoSize; +long estHeaderSize; +char* buffer; +long* len; +/* write the tag and size, making sure the info fits. return the true end + of the info (after adjustment) note that the argument infoSize includes + estHeaderSize. Note that the argument len is the number of bytes remaining + in the buffer. Since we write the tag and size at the begining of the + buffer (in space that we reserved) we don't want to pass len the calls which + do that writing. + */ +{ + long dummyLen = 100; /* plenty of space for a tag and size */ + char* buf = buffer; + long realSize = infoSize - estHeaderSize; + long realHeaderSize = userInfoTagSize(tag,realSize); + + if (buffer == NULL || *len == 0) + return(NULL); + + /* write the tag */ + buf = writeTag(tag,buf,&dummyLen); + + /* see if the if the header size was correct. if not, + we have to shift the info to fit the real header size */ + if (estHeaderSize != realHeaderSize) + { /* make sure there is enough space */ + CHECK_FOR_SPACE_LEFT(realHeaderSize - estHeaderSize,len); + memmove(buffer + realHeaderSize,buffer + estHeaderSize,(size_t)(realSize)); + } + + /* write the size */ + writeCompressedInteger(realSize,buf,&dummyLen); + + /* return the true end of buffer */ + return(buffer + realHeaderSize + realSize); +} + +/*----------------------------------------------------------------------*/ + +static char* readUserInfoHeader _AP((data_tag* tag,unsigned long* num, + char* buffer)); + +static char* +readUserInfoHeader(tag,num,buffer) +data_tag* tag; +unsigned long* num; +char* buffer; +/* read the tag and size */ +{ + char* buf = buffer; + buf = readTag(tag,buf); + buf = readCompressedInteger(num,buf); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISInitResponse* +makeWAISInitResponse(chunkCode, + chunkIDLen, + chunkMarker, + highlightMarker, + deHighlightMarker, + newLineChars) +long chunkCode; +long chunkIDLen; +char* chunkMarker; +char* highlightMarker; +char* deHighlightMarker; +char* newLineChars; +/* create a WAIS init response object */ +{ + WAISInitResponse* init = (WAISInitResponse*)s_malloc((size_t)sizeof(WAISInitResponse)); + + init->ChunkCode = chunkCode; /* note: none are copied! */ + init->ChunkIDLength = chunkIDLen; + init->ChunkMarker = chunkMarker; + init->HighlightMarker = highlightMarker; + init->DeHighlightMarker = deHighlightMarker; + init->NewlineCharacters = newLineChars; + + return(init); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISInitResponse(init) +WAISInitResponse* init; +/* free an object made with makeWAISInitResponse */ +{ + s_free(init->ChunkMarker); + s_free(init->HighlightMarker); + s_free(init->DeHighlightMarker); + s_free(init->NewlineCharacters); + s_free(init); +} + +/*----------------------------------------------------------------------*/ + +char* +writeInitResponseInfo(init,buffer,len) +InitResponseAPDU* init; +char* buffer; +long* len; +/* write an init response object */ +{ + unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISInitResponseSize); + char* buf = buffer + header_len; + WAISInitResponse* info = (WAISInitResponse*)init->UserInformationField; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeNum(info->ChunkCode,DT_ChunkCode,buf,len); + buf = writeNum(info->ChunkIDLength,DT_ChunkIDLength,buf,len); + buf = writeString(info->ChunkMarker,DT_ChunkMarker,buf,len); + buf = writeString(info->HighlightMarker,DT_HighlightMarker,buf,len); + buf = writeString(info->DeHighlightMarker,DT_DeHighlightMarker,buf,len); + buf = writeString(info->NewlineCharacters,DT_NewlineCharacters,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readInitResponseInfo(info,buffer) +void** info; +char* buffer; +/* read an init response object */ +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + long chunkCode,chunkIDLen; + char* chunkMarker = NULL; + char* highlightMarker = NULL; + char* deHighlightMarker = NULL; + char* newLineChars = NULL; + + chunkCode = chunkIDLen = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_ChunkCode: + buf = readNum(&chunkCode,buf); + break; + case DT_ChunkIDLength: + buf = readNum(&chunkIDLen,buf); + break; + case DT_ChunkMarker: + buf = readString(&chunkMarker,buf); + break; + case DT_HighlightMarker: + buf = readString(&highlightMarker,buf); + break; + case DT_DeHighlightMarker: + buf = readString(&deHighlightMarker,buf); + break; + case DT_NewlineCharacters: + buf = readString(&newLineChars,buf); + break; + default: + s_free(highlightMarker); + s_free(deHighlightMarker); + s_free(newLineChars); + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISInitResponse(chunkCode,chunkIDLen,chunkMarker, + highlightMarker,deHighlightMarker, + newLineChars); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISSearch* +makeWAISSearch(seedWords, + docs, + textList, + dateFactor, + beginDateRange, + endDateRange, + maxDocsRetrieved) +char* seedWords; +DocObj** docs; +char** textList; +long dateFactor; +char* beginDateRange; +char* endDateRange; +long maxDocsRetrieved; + +/* create a type 3 query object */ +{ + WAISSearch* query = (WAISSearch*)s_malloc((size_t)sizeof(WAISSearch)); + + query->SeedWords = seedWords; /* not copied! */ + query->Docs = docs; /* not copied! */ + query->TextList = textList; /* not copied! */ + query->DateFactor = dateFactor; + query->BeginDateRange = beginDateRange; + query->EndDateRange = endDateRange; + query->MaxDocumentsRetrieved = maxDocsRetrieved; + + return(query); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISSearch(query) +WAISSearch* query; + +/* destroy an object made with makeWAISSearch() */ +{ + void* ptr = NULL; + long i; + + s_free(query->SeedWords); + + if (query->Docs != NULL) + for (i = 0,ptr = (void *)query->Docs[i]; ptr != NULL; ptr = (void *)query->Docs[++i]) + freeDocObj((DocObj*)ptr); + s_free(query->Docs); + + if (query->TextList != NULL) /* XXX revisit when textlist is fully defined */ + for (i = 0,ptr = (void *)query->TextList[i]; ptr != NULL; ptr = (void *)query->TextList[++i]) + s_free(ptr); + s_free(query->TextList); + + s_free(query->BeginDateRange); + s_free(query->EndDateRange); + s_free(query); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingWholeDocument(docID,type) +any* docID; +char* type; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->DocumentID = docID; /* not copied! */ + doc->Type = type; /* not copied! */ + doc->ChunkCode = CT_document; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingLines(docID,type,start,end) +any* docID; +char* type; +long start; +long end; + +/* construct a document object using line chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_line; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; /* not copied! */ + doc->ChunkStart.Pos = start; + doc->ChunkEnd.Pos = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingBytes(docID,type,start,end) +any* docID; +char* type; +long start; +long end; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_byte; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; /* not copied! */ + doc->ChunkStart.Pos = start; + doc->ChunkEnd.Pos = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingParagraphs(docID,type,start,end) +any* docID; +char* type; +any* start; +any* end; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_paragraph; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; + doc->ChunkStart.ID = start; + doc->ChunkEnd.ID = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +void +freeDocObj(doc) +DocObj* doc; + +/* free a docObj */ +{ + freeAny(doc->DocumentID); + s_free(doc->Type); + if (doc->ChunkCode == CT_paragraph) + { freeAny(doc->ChunkStart.ID); + freeAny(doc->ChunkEnd.ID); + } + s_free(doc); +} + +/*----------------------------------------------------------------------*/ + +static char* writeDocObj _AP((DocObj* doc,char* buffer,long* len)); + +static char* +writeDocObj(doc,buffer,len) +DocObj* doc; +char* buffer; +long* len; + +/* write as little as we can about the doc obj */ +{ + char* buf = buffer; + + /* we alwasy have to write the id, but its tag depends on if its a chunk */ + if (doc->ChunkCode == CT_document) + buf = writeAny(doc->DocumentID,DT_DocumentID,buf,len); + else + buf = writeAny(doc->DocumentID,DT_DocumentIDChunk,buf,len); + + if (doc->Type != NULL) + buf = writeString(doc->Type,DT_TYPE,buf,len); + + switch (doc->ChunkCode) + { case CT_document: + /* do nothing - there is no chunk data */ + break; + case CT_byte: + case CT_line: + buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len); + buf = writeNum(doc->ChunkStart.Pos,DT_ChunkStartID,buf,len); + buf = writeNum(doc->ChunkEnd.Pos,DT_ChunkEndID,buf,len); + break; + case CT_paragraph: + buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len); + buf = writeAny(doc->ChunkStart.ID,DT_ChunkStartID,buf,len); + buf = writeAny(doc->ChunkEnd.ID,DT_ChunkEndID,buf,len); + break; + default: + panic("Implementation error: unknown chuck type %ld", + doc->ChunkCode); + break; + } + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +static char* readDocObj _AP((DocObj** doc,char* buffer)); + +static char* +readDocObj(doc,buffer) +DocObj** doc; +char* buffer; + +/* read whatever we have about the new document */ +{ + char* buf = buffer; + data_tag tag; + + *doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + + tag = peekTag(buf); + buf = readAny(&((*doc)->DocumentID),buf); + + if (tag == DT_DocumentID) + { (*doc)->ChunkCode = CT_document; + tag = peekTag(buf); + if (tag == DT_TYPE) /* XXX depends on DT_TYPE != what comes next */ + buf = readString(&((*doc)->Type),buf); + /* ChunkStart and ChunkEnd are undefined */ + } + else if (tag == DT_DocumentIDChunk) + { boolean readParagraphs = false; /* for cleanup */ + tag = peekTag(buf); + if (tag == DT_TYPE) /* XXX depends on DT_TYPE != CT_FOO */ + buf = readString(&((*doc)->Type),buf); + buf = readNum(&((*doc)->ChunkCode),buf); + switch ((*doc)->ChunkCode) + { case CT_byte: + case CT_line: + buf = readNum(&((*doc)->ChunkStart.Pos),buf); + buf = readNum(&((*doc)->ChunkEnd.Pos),buf); + break; + case CT_paragraph: + readParagraphs = true; + buf = readAny(&((*doc)->ChunkStart.ID),buf); + buf = readAny(&((*doc)->ChunkEnd.ID),buf); + break; + default: + freeAny((*doc)->DocumentID); + if (readParagraphs) + { freeAny((*doc)->ChunkStart.ID); + freeAny((*doc)->ChunkEnd.ID); + } + s_free(doc); + REPORT_READ_ERROR(buf); + break; + } + } + else + { freeAny((*doc)->DocumentID); + s_free(*doc); + REPORT_READ_ERROR(buf); + } + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +writeSearchInfo(query,buffer,len) +SearchAPDU* query; +char* buffer; +long* len; + +/* write out a WAIS query (type 1 or 3) */ +{ + if (strcmp(query->QueryType,QT_TextRetrievalQuery) == 0) + { return(writeAny((any*)query->Query,DT_Query,buffer,len)); + } + else + { unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISSearchSize); + char* buf = buffer + header_len; + WAISSearch* info = (WAISSearch*)query->Query; + unsigned long size; + long i; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeString(info->SeedWords,DT_SeedWords,buf,len); + + if (info->Docs != NULL) + { for (i = 0; info->Docs[i] != NULL; i++) + { buf = writeDocObj(info->Docs[i],buf,len); + } + } + + /* XXX text list */ + + buf = writeNum(info->DateFactor,DT_DateFactor,buf,len); + buf = writeString(info->BeginDateRange,DT_BeginDateRange,buf,len); + buf = writeString(info->EndDateRange,DT_EndDateRange,buf,len); + buf = writeNum(info->MaxDocumentsRetrieved,DT_MaxDocumentsRetrieved,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); + } +} + +/*----------------------------------------------------------------------*/ + +char* +readSearchInfo(info,buffer) +void** info; +char* buffer; + +/* read a WAIS query (type 1 or 3) */ +{ + data_tag type = peekTag(buffer); + if (type == DT_Query) /* this is a type 1 query */ + { char* buf = buffer; + any* query = NULL; + buf = readAny(&query,buf); + *info = (void *)query; + return(buf); + } + else /* a type 3 query */ + { char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + char* seedWords = NULL; + char* beginDateRange = NULL; + char* endDateRange = NULL; + long dateFactor,maxDocsRetrieved; + char** textList = NULL; + DocObj** docIDs = NULL; + DocObj* doc = NULL; + long docs = 0; + long i; + void* ptr = NULL; + + dateFactor = maxDocsRetrieved = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_SeedWords: + buf = readString(&seedWords,buf); + break; + case DT_DocumentID: + case DT_DocumentIDChunk: + if (docIDs == NULL) /* create a new doc list */ + { docIDs = (DocObj**)s_malloc((size_t)sizeof(DocObj*) * 2); + } + else /* grow the doc list */ + { docIDs = (DocObj**)s_realloc((char*)docIDs,(size_t)(sizeof(DocObj*) * (docs + 2))); + } + buf = readDocObj(&doc,buf); + if (buf == NULL) + { s_free(seedWords); + s_free(beginDateRange); + s_free(endDateRange); + if (docIDs != NULL) + for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i]) + freeDocObj((DocObj*)ptr); + s_free(docIDs); + /* XXX should also free textlist when it is fully defined */ + } + RETURN_ON_NULL(buf); + docIDs[docs++] = doc; /* put it in the list */ + docIDs[docs] = NULL; + break; + case DT_TextList: + /* XXX */ + break; + case DT_DateFactor: + buf = readNum(&dateFactor,buf); + break; + case DT_BeginDateRange: + buf = readString(&beginDateRange,buf); + break; + case DT_EndDateRange: + buf = readString(&endDateRange,buf); + break; + case DT_MaxDocumentsRetrieved: + buf = readNum(&maxDocsRetrieved,buf); + break; + default: + s_free(seedWords); + s_free(beginDateRange); + s_free(endDateRange); + if (docIDs != NULL) + for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i]) + freeDocObj((DocObj*)ptr); + s_free(docIDs); + /* XXX should also free textlist when it is fully defined */ + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISSearch(seedWords,docIDs,textList, + dateFactor,beginDateRange,endDateRange, + maxDocsRetrieved); + return(buf); + } +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentHeader* +makeWAISDocumentHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines, + types, + source, + date, + headline, + originCity) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +char** types; +char* source; +char* date; +char* headline; +char* originCity; + +/* construct a standard document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentHeader* header = + (WAISDocumentHeader*)s_malloc((size_t)sizeof(WAISDocumentHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + header->Types = types; + header->Source = source; + header->Date = date; + header->Headline = headline; + header->OriginCity = originCity; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentHeader(header) +WAISDocumentHeader* header; + +{ + freeAny(header->DocumentID); + doList((void**)header->Types,fs_free); /* can't use the macro here ! */ + s_free(header->Types); + s_free(header->Source); + s_free(header->Date); + s_free(header->Headline); + s_free(header->OriginCity); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentHeader(header,buffer,len) +WAISDocumentHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentHeaderGroup , + DefWAISDocHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + if (header->Types != NULL) + { long size; + char* ptr = NULL; + long i; + buf = writeTag(DT_TYPE_BLOCK,buf,len); + for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + { long typeSize = strlen(ptr); + size += writtenTagSize(DT_TYPE); + size += writtenCompressedIntSize(typeSize); + size += typeSize; + } + buf = writeCompressedInteger((unsigned long)size,buf,len); + for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + buf = writeString(ptr,DT_TYPE,buf,len); + } + buf = writeString(header->Source,DT_Source,buf,len); + buf = writeString(header->Date,DT_Date,buf,len); + buf = writeString(header->Headline,DT_Headline,buf,len); + buf = writeString(header->OriginCity,DT_OriginCity,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentHeader(header,buffer) +WAISDocumentHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID = NULL; + long versionNumber,score,bestMatch,docLength,lines; + char** types = NULL; + char *source = NULL; + char *date = NULL; + char *headline = NULL; + char *originCity = NULL; + + versionNumber = score = bestMatch = docLength = lines = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + case DT_TYPE_BLOCK: + { unsigned long size = -1; + long numTypes = 0; + buf = readTag(&tag,buf); + buf = readCompressedInteger(&size,buf); + while (size > 0) + { char* type = NULL; + char* originalBuf = buf; + buf = readString(&type,buf); + types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2))); + types[numTypes++] = type; + types[numTypes] = NULL; + size -= (buf - originalBuf); + } + } + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentHeader(docID,versionNumber,score,bestMatch, + docLength,lines,types,source,date,headline, + originCity); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentShortHeader* +makeWAISDocumentShortHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +/* construct a short document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentShortHeader* header = + (WAISDocumentShortHeader*)s_malloc((size_t)sizeof(WAISDocumentShortHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentShortHeader(header) +WAISDocumentShortHeader* header; +{ + freeAny(header->DocumentID); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentShortHeader(header,buffer,len) +WAISDocumentShortHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentShortHeaderGroup , + DefWAISShortHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentShortHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentShortHeader(header,buffer) +WAISDocumentShortHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID = NULL; + long versionNumber,score,bestMatch,docLength,lines; + + versionNumber = score = bestMatch = docLength = lines = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + default: + freeAny(docID); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentShortHeader(docID,versionNumber,score,bestMatch, + docLength,lines); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentLongHeader* +makeWAISDocumentLongHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines, + types, + source, + date, + headline, + originCity, + stockCodes, + companyCodes, + industryCodes) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +char** types; +char* source; +char* date; +char* headline; +char* originCity; +char* stockCodes; +char* companyCodes; +char* industryCodes; +/* construct a long document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentLongHeader* header = + (WAISDocumentLongHeader*)s_malloc((size_t)sizeof(WAISDocumentLongHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + header->Types = types; + header->Source = source; + header->Date = date; + header->Headline = headline; + header->OriginCity = originCity; + header->StockCodes = stockCodes; + header->CompanyCodes = companyCodes; + header->IndustryCodes = industryCodes; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentLongHeader(header) +WAISDocumentLongHeader* header; +{ + freeAny(header->DocumentID); + doList((void**)header->Types,fs_free); /* can't use the macro here! */ + s_free(header->Source); + s_free(header->Date); + s_free(header->Headline); + s_free(header->OriginCity); + s_free(header->StockCodes); + s_free(header->CompanyCodes); + s_free(header->IndustryCodes); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentLongHeader(header,buffer,len) +WAISDocumentLongHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentLongHeaderGroup , + DefWAISLongHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + if (header->Types != NULL) + { long size; + char* ptr = NULL; + long i; + buf = writeTag(DT_TYPE_BLOCK,buf,len); + for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + { long typeSize = strlen(ptr); + size += writtenTagSize(DT_TYPE); + size += writtenCompressedIntSize(typeSize); + size += typeSize; + } + buf = writeCompressedInteger((unsigned long)size,buf,len); + for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + buf = writeString(ptr,DT_TYPE,buf,len); + } + buf = writeString(header->Source,DT_Source,buf,len); + buf = writeString(header->Date,DT_Date,buf,len); + buf = writeString(header->Headline,DT_Headline,buf,len); + buf = writeString(header->OriginCity,DT_OriginCity,buf,len); + buf = writeString(header->StockCodes,DT_StockCodes,buf,len); + buf = writeString(header->CompanyCodes,DT_CompanyCodes,buf,len); + buf = writeString(header->IndustryCodes,DT_IndustryCodes,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentLongHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentLongHeader(header,buffer) +WAISDocumentLongHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber,score,bestMatch,docLength,lines; + char **types; + char *source,*date,*headline,*originCity,*stockCodes,*companyCodes,*industryCodes; + + docID = NULL; + versionNumber = score = bestMatch = docLength = lines = UNUSED; + types = NULL; + source = date = headline = originCity = stockCodes = companyCodes = industryCodes = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + case DT_TYPE_BLOCK: + { unsigned long size = -1; + long numTypes = 0; + buf = readTag(&tag,buf); + readCompressedInteger(&size,buf); + while (size > 0) + { char* type = NULL; + char* originalBuf = buf; + buf = readString(&type,buf); + types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2))); + types[numTypes++] = type; + types[numTypes] = NULL; + size -= (buf - originalBuf); + } + } + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + case DT_StockCodes: + buf = readString(&stockCodes,buf); + break; + case DT_CompanyCodes: + buf = readString(&companyCodes,buf); + break; + case DT_IndustryCodes: + buf = readString(&industryCodes,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + s_free(stockCodes); + s_free(companyCodes); + s_free(industryCodes); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentLongHeader(docID,versionNumber,score,bestMatch, + docLength,lines,types,source,date,headline, + originCity,stockCodes,companyCodes, + industryCodes); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISSearchResponse* +makeWAISSearchResponse(seedWordsUsed, + docHeaders, + shortHeaders, + longHeaders, + text, + headlines, + codes, + diagnostics) +char* seedWordsUsed; +WAISDocumentHeader** docHeaders; +WAISDocumentShortHeader** shortHeaders; +WAISDocumentLongHeader** longHeaders; +WAISDocumentText** text; +WAISDocumentHeadlines** headlines; +WAISDocumentCodes** codes; +diagnosticRecord** diagnostics; +{ + WAISSearchResponse* response = (WAISSearchResponse*)s_malloc((size_t)sizeof(WAISSearchResponse)); + + response->SeedWordsUsed = seedWordsUsed; + response->DocHeaders = docHeaders; + response->ShortHeaders = shortHeaders; + response->LongHeaders = longHeaders; + response->Text = text; + response->Headlines = headlines; + response->Codes = codes; + response->Diagnostics = diagnostics; + + return(response); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISSearchResponse(response) +WAISSearchResponse* response; +{ + void* ptr = NULL; + long i; + + s_free(response->SeedWordsUsed); + + if (response->DocHeaders != NULL) + for (i = 0,ptr = (void *)response->DocHeaders[i]; ptr != NULL; ptr = (void *)response->DocHeaders[++i]) + freeWAISDocumentHeader((WAISDocumentHeader*)ptr); + s_free(response->DocHeaders); + + if (response->ShortHeaders != NULL) + for (i = 0,ptr = (void *)response->ShortHeaders[i]; ptr != NULL; ptr = (void *)response->ShortHeaders[++i]) + freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr); + s_free(response->ShortHeaders); + + if (response->LongHeaders != NULL) + for (i = 0,ptr = (void *)response->LongHeaders[i]; ptr != NULL; ptr = (void *)response->LongHeaders[++i]) + freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr); + s_free(response->LongHeaders); + + if (response->Text != NULL) + for (i = 0,ptr = (void *)response->Text[i]; ptr != NULL; ptr = (void *)response->Text[++i]) + freeWAISDocumentText((WAISDocumentText*)ptr); + s_free(response->Text); + + if (response->Headlines != NULL) + for (i = 0,ptr = (void *)response->Headlines[i]; ptr != NULL; ptr = (void *)response->Headlines[++i]) + freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr); + s_free(response->Headlines); + + if (response->Codes != NULL) + for (i = 0,ptr = (void *)response->Codes[i]; ptr != NULL; ptr = (void *)response->Codes[++i]) + freeWAISDocumentCodes((WAISDocumentCodes*)ptr); + s_free(response->Codes); + + if (response->Diagnostics != NULL) + for (i = 0,ptr = (void *)response->Diagnostics[i]; ptr != NULL; ptr = (void *)response->Diagnostics[++i]) + freeDiag((diagnosticRecord*)ptr); + s_free(response->Diagnostics); + + s_free(response); +} + +/*----------------------------------------------------------------------*/ + +char* +writeSearchResponseInfo(query,buffer,len) +SearchResponseAPDU* query; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISSearchResponseSize); + char* buf = buffer + header_len; + WAISSearchResponse* info = (WAISSearchResponse*)query->DatabaseDiagnosticRecords; + unsigned long size; + void* header = NULL; + long i; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeString(info->SeedWordsUsed,DT_SeedWordsUsed,buf,len); + + /* write out all the headers */ + if (info->DocHeaders != NULL) + { for (i = 0,header = (void *)info->DocHeaders[i]; header != NULL; header = (void *)info->DocHeaders[++i]) + buf = writeWAISDocumentHeader((WAISDocumentHeader*)header,buf,len); + } + + if (info->ShortHeaders != NULL) + { for (i = 0,header = (void *)info->ShortHeaders[i]; header != NULL; header = (void *)info->ShortHeaders[++i]) + buf = writeWAISDocumentShortHeader((WAISDocumentShortHeader*)header,buf,len); + } + + if (info->LongHeaders != NULL) + { for (i = 0,header = (void *)info->LongHeaders[i]; header != NULL; header = (void *)info->LongHeaders[++i]) + buf = writeWAISDocumentLongHeader((WAISDocumentLongHeader*)header,buf,len); + } + + if (info->Text != NULL) + { for (i = 0,header = (void *)info->Text[i]; header != NULL; header = (void *)info->Text[++i]) + buf = writeWAISDocumentText((WAISDocumentText*)header,buf,len); + } + + if (info->Headlines != NULL) + { for (i = 0,header = (void *)info->Headlines[i]; header != NULL; header = (void *)info->Headlines[++i]) + buf = writeWAISDocumentHeadlines((WAISDocumentHeadlines*)header,buf,len); + } + + if (info->Codes != NULL) + { for (i = 0,header = (void *)info->Codes[i]; header != NULL;header = (void *)info->Codes[++i]) + buf = writeWAISDocumentCodes((WAISDocumentCodes*)header,buf,len); + } + + if (info->Diagnostics != NULL) + { for (i = 0, header = (void *)info->Diagnostics[i]; header != NULL; header = (void *)info->Diagnostics[++i]) + buf = writeDiag((diagnosticRecord*)header,buf,len); + } + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +static void +cleanUpWaisSearchResponse _AP((char* buf,char* seedWordsUsed, + WAISDocumentHeader** docHeaders, + WAISDocumentShortHeader** shortHeaders, + WAISDocumentLongHeader** longHeaders, + WAISDocumentText** text, + WAISDocumentHeadlines** headlines, + WAISDocumentCodes** codes, + diagnosticRecord**diags)); + +static void +cleanUpWaisSearchResponse (buf,seedWordsUsed,docHeaders,shortHeaders, + longHeaders,text,headlines,codes,diags) +char* buf; +char* seedWordsUsed; +WAISDocumentHeader** docHeaders; +WAISDocumentShortHeader** shortHeaders; +WAISDocumentLongHeader** longHeaders; +WAISDocumentText** text; +WAISDocumentHeadlines** headlines; +WAISDocumentCodes** codes; +diagnosticRecord** diags; +/* if buf is NULL, we have just gotten a read error, and need to clean up + any state we have built. If not, then everything is going fine, and + we should just hang loose + */ +{ + void* ptr = NULL; + long i; + + if (buf == NULL) + { s_free(seedWordsUsed); + if (docHeaders != NULL) + for (i = 0,ptr = (void *)docHeaders[i]; ptr != NULL; + ptr = (void *)docHeaders[++i]) + freeWAISDocumentHeader((WAISDocumentHeader*)ptr); + s_free(docHeaders); + if (shortHeaders != NULL) + for (i = 0,ptr = (void *)shortHeaders[i]; ptr != NULL; + ptr = (void *)shortHeaders[++i]) + freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr); + s_free(shortHeaders); + if (longHeaders != NULL) + for (i = 0,ptr = (void *)longHeaders[i]; ptr != NULL; + ptr = (void *)longHeaders[++i]) + freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr); + s_free(longHeaders); + if (text != NULL) + for (i = 0,ptr = (void *)text[i]; ptr != NULL; ptr = (void *)text[++i]) + freeWAISDocumentText((WAISDocumentText*)ptr); + s_free(text); + if (headlines != NULL) + for (i = 0,ptr = (void *)headlines[i]; ptr != NULL; + ptr = (void *)headlines[++i]) + freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr); + s_free(headlines); + if (codes != NULL) + for (i = 0,ptr = (void *)codes[i]; ptr != NULL; + ptr = (void *)codes[++i]) + freeWAISDocumentCodes((WAISDocumentCodes*)ptr); + s_free(codes); + if (diags != NULL) + for (i = 0,ptr = (void *)diags[i]; ptr != NULL; + ptr = (void *)diags[++i]) + freeDiag((diagnosticRecord*)ptr); + s_free(diags); + } +} + +/*----------------------------------------------------------------------*/ + +char* +readSearchResponseInfo(info,buffer) +void** info; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + void* header = NULL; + WAISDocumentHeader** docHeaders = NULL; + WAISDocumentShortHeader** shortHeaders = NULL; + WAISDocumentLongHeader** longHeaders = NULL; + WAISDocumentText** text = NULL; + WAISDocumentHeadlines** headlines = NULL; + WAISDocumentCodes** codes = NULL; + long numDocHeaders,numLongHeaders,numShortHeaders,numText,numHeadlines; + long numCodes; + char* seedWordsUsed = NULL; + diagnosticRecord** diags = NULL; + diagnosticRecord* diag = NULL; + long numDiags = 0; + + numDocHeaders = numLongHeaders = numShortHeaders = numText = numHeadlines = numCodes = 0; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_SeedWordsUsed: + buf = readString(&seedWordsUsed,buf); + break; + case DT_DatabaseDiagnosticRecords: + if (diags == NULL) /* create a new diag list */ + { diags = (diagnosticRecord**)s_malloc((size_t)sizeof(diagnosticRecord*) * 2); + } + else /* grow the diag list */ + { diags = (diagnosticRecord**)s_realloc((char*)diags,(size_t)(sizeof(diagnosticRecord*) * (numDiags + 2))); + } + buf = readDiag(&diag,buf); + diags[numDiags++] = diag; /* put it in the list */ + diags[numDiags] = NULL; + break; + case DT_DocumentHeaderGroup: + if (docHeaders == NULL) /* create a new header list */ + { docHeaders = (WAISDocumentHeader**)s_malloc((size_t)sizeof(WAISDocumentHeader*) * 2); + } + else /* grow the doc list */ + { docHeaders = (WAISDocumentHeader**)s_realloc((char*)docHeaders,(size_t)(sizeof(WAISDocumentHeader*) * (numDocHeaders + 2))); + } + buf = readWAISDocumentHeader((WAISDocumentHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + docHeaders[numDocHeaders++] = + (WAISDocumentHeader*)header; /* put it in the list */ + docHeaders[numDocHeaders] = NULL; + break; + case DT_DocumentShortHeaderGroup: + if (shortHeaders == NULL) /* create a new header list */ + { shortHeaders = (WAISDocumentShortHeader**)s_malloc((size_t)sizeof(WAISDocumentShortHeader*) * 2); + } + else /* grow the doc list */ + { shortHeaders = (WAISDocumentShortHeader**)s_realloc((char*)shortHeaders,(size_t)(sizeof(WAISDocumentShortHeader*) * (numShortHeaders + 2))); + } + buf = readWAISDocumentShortHeader((WAISDocumentShortHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + shortHeaders[numShortHeaders++] = + (WAISDocumentShortHeader*)header; /* put it in the list */ + shortHeaders[numShortHeaders] = NULL; + break; + case DT_DocumentLongHeaderGroup: + if (longHeaders == NULL) /* create a new header list */ + { longHeaders = (WAISDocumentLongHeader**)s_malloc((size_t)sizeof(WAISDocumentLongHeader*) * 2); + } + else /* grow the doc list */ + { longHeaders = (WAISDocumentLongHeader**)s_realloc((char*)longHeaders,(size_t)(sizeof(WAISDocumentLongHeader*) * (numLongHeaders + 2))); + } + buf = readWAISDocumentLongHeader((WAISDocumentLongHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + longHeaders[numLongHeaders++] = + (WAISDocumentLongHeader*)header; /* put it in the list */ + longHeaders[numLongHeaders] = NULL; + break; + case DT_DocumentTextGroup: + if (text == NULL) /* create a new list */ + { text = (WAISDocumentText**)s_malloc((size_t)sizeof(WAISDocumentText*) * 2); + } + else /* grow the list */ + { text = (WAISDocumentText**)s_realloc((char*)text,(size_t)(sizeof(WAISDocumentText*) * (numText + 2))); + } + buf = readWAISDocumentText((WAISDocumentText**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + text[numText++] = + (WAISDocumentText*)header; /* put it in the list */ + text[numText] = NULL; + break; + case DT_DocumentHeadlineGroup: + if (headlines == NULL) /* create a new list */ + { headlines = (WAISDocumentHeadlines**)s_malloc((size_t)sizeof(WAISDocumentHeadlines*) * 2); + } + else /* grow the list */ + { headlines = (WAISDocumentHeadlines**)s_realloc((char*)headlines,(size_t)(sizeof(WAISDocumentHeadlines*) * (numHeadlines + 2))); + } + buf = readWAISDocumentHeadlines((WAISDocumentHeadlines**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + headlines[numHeadlines++] = + (WAISDocumentHeadlines*)header; /* put it in the list */ + headlines[numHeadlines] = NULL; + break; + case DT_DocumentCodeGroup: + if (codes == NULL) /* create a new list */ + { codes = (WAISDocumentCodes**)s_malloc((size_t)sizeof(WAISDocumentCodes*) * 2); + } + else /* grow the list */ + { codes = (WAISDocumentCodes**)s_realloc((char*)codes,(size_t)(sizeof(WAISDocumentCodes*) * (numCodes + 2))); + } + buf = readWAISDocumentCodes((WAISDocumentCodes**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + codes[numCodes++] = + (WAISDocumentCodes*)header; /* put it in the list */ + codes[numCodes] = NULL; + break; + default: + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISSearchResponse(seedWordsUsed,docHeaders,shortHeaders, + longHeaders,text,headlines,codes,diags); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentText* +makeWAISDocumentText(docID,versionNumber,documentText) +any* docID; +long versionNumber; +any* documentText; +{ + WAISDocumentText* docText = (WAISDocumentText*)s_malloc((size_t)sizeof(WAISDocumentText)); + + docText->DocumentID = docID; + docText->VersionNumber = versionNumber; + docText->DocumentText = documentText; + + return(docText); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentText(docText) +WAISDocumentText* docText; +{ + freeAny(docText->DocumentID); + freeAny(docText->DocumentText); + s_free(docText); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentText(docText,buffer,len) +WAISDocumentText* docText; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentTextGroup, + DefWAISDocTextSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docText->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docText->VersionNumber,DT_VersionNumber,buf,len); + buf = writeAny(docText->DocumentText,DT_DocumentText,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentTextGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentText(docText,buffer) +WAISDocumentText** docText; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any *docID,*documentText; + long versionNumber; + + docID = documentText = NULL; + versionNumber = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_DocumentText: + buf = readAny(&documentText,buf); + break; + default: + freeAny(docID); + freeAny(documentText); + REPORT_READ_ERROR(buf); + break; + } + } + + *docText = makeWAISDocumentText(docID,versionNumber,documentText); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentHeadlines* +makeWAISDocumentHeadlines(docID, + versionNumber, + source, + date, + headline, + originCity) +any* docID; +long versionNumber; +char* source; +char* date; +char* headline; +char* originCity; +{ + WAISDocumentHeadlines* docHeadline = + (WAISDocumentHeadlines*)s_malloc((size_t)sizeof(WAISDocumentHeadlines)); + + docHeadline->DocumentID = docID; + docHeadline->VersionNumber = versionNumber; + docHeadline->Source = source; + docHeadline->Date = date; + docHeadline->Headline = headline; + docHeadline->OriginCity = originCity; + + return(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentHeadlines(docHeadline) +WAISDocumentHeadlines* docHeadline; +{ + freeAny(docHeadline->DocumentID); + s_free(docHeadline->Source); + s_free(docHeadline->Date); + s_free(docHeadline->Headline); + s_free(docHeadline->OriginCity); + s_free(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentHeadlines(docHeadline,buffer,len) +WAISDocumentHeadlines* docHeadline; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentHeadlineGroup, + DefWAISDocHeadlineSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docHeadline->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docHeadline->VersionNumber,DT_VersionNumber,buf,len); + buf = writeString(docHeadline->Source,DT_Source,buf,len); + buf = writeString(docHeadline->Date,DT_Date,buf,len); + buf = writeString(docHeadline->Headline,DT_Headline,buf,len); + buf = writeString(docHeadline->OriginCity,DT_OriginCity,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentHeadlineGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentHeadlines(docHeadline,buffer) +WAISDocumentHeadlines** docHeadline; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber; + char *source,*date,*headline,*originCity; + + docID = NULL; + versionNumber = UNUSED; + source = date = headline = originCity = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + REPORT_READ_ERROR(buf); + break; + } + } + + *docHeadline = makeWAISDocumentHeadlines(docID,versionNumber,source,date, + headline,originCity); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentCodes* +makeWAISDocumentCodes(docID, + versionNumber, + stockCodes, + companyCodes, + industryCodes) +any* docID; +long versionNumber; +char* stockCodes; +char* companyCodes; +char* industryCodes; +{ + WAISDocumentCodes* docCodes = (WAISDocumentCodes*)s_malloc((size_t)sizeof(WAISDocumentCodes)); + + docCodes->DocumentID = docID; + docCodes->VersionNumber = versionNumber; + docCodes->StockCodes = stockCodes; + docCodes->CompanyCodes = companyCodes; + docCodes->IndustryCodes = industryCodes; + + return(docCodes); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentCodes(docCodes) +WAISDocumentCodes* docCodes; +{ + freeAny(docCodes->DocumentID); + s_free(docCodes->StockCodes); + s_free(docCodes->CompanyCodes); + s_free(docCodes->IndustryCodes); + s_free(docCodes); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentCodes(docCodes,buffer,len) +WAISDocumentCodes* docCodes; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentCodeGroup , + DefWAISDocCodeSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docCodes->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docCodes->VersionNumber,DT_VersionNumber,buf,len); + buf = writeString(docCodes->StockCodes,DT_StockCodes,buf,len); + buf = writeString(docCodes->CompanyCodes,DT_CompanyCodes,buf,len); + buf = writeString(docCodes->IndustryCodes,DT_IndustryCodes,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentCodeGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentCodes(docCodes,buffer) +WAISDocumentCodes** docCodes; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber; + char *stockCodes,*companyCodes,*industryCodes; + + docID = NULL; + versionNumber = UNUSED; + stockCodes = companyCodes = industryCodes = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_StockCodes: + buf = readString(&stockCodes,buf); + break; + case DT_CompanyCodes: + buf = readString(&companyCodes,buf); + break; + case DT_IndustryCodes: + buf = readString(&industryCodes,buf); + break; + default: + freeAny(docID); + s_free(stockCodes); + s_free(companyCodes); + s_free(industryCodes); + REPORT_READ_ERROR(buf); + break; + } + } + + *docCodes = makeWAISDocumentCodes(docID,versionNumber,stockCodes, + companyCodes,industryCodes); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +writePresentInfo(present,buffer,len) +PresentAPDU* present; +char* buffer; +long* len; +{ + /* The WAIS protocol doesn't use present info */ + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +readPresentInfo(info,buffer) +void** info; +char* buffer; +{ + /* The WAIS protocol doesn't use present info */ + *info = NULL; + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +writePresentResponseInfo(response,buffer,len) +PresentResponseAPDU* response; +char* buffer; +long* len; +{ + /* The WAIS protocol doesn't use presentResponse info */ + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +readPresentResponseInfo(info,buffer) +void** info; +char* buffer; +{ + /* The WAIS protocol doesn't use presentResponse info */ + *info = NULL; + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +/* support for type 1 queries */ + +/* new use values (for the chunk types) */ +#define BYTE "wb" +#define LINE "wl" +#define PARAGRAPH "wp" +#define DATA_TYPE "wt" + +/* WAIS supports the following semantics for type 1 queries: + + 1. retrieve the header/codes from a document: + + System_Control_Number = docID + Data Type = type (optional) + And + + 2. retrieve a fragment of the text of a document: + + System_Control_Number = docID + Data Type = type (optional) + And + Chunk >= start + And + Chunk < end + And + + Information from multiple documents may be requested by using + groups of the above joined by: + + OR + + ( XXX does an OR come after every group but the first, or do they + all come at the end? ) + + ( XXX return type could be in the element set) +*/ + +static query_term** makeWAISQueryTerms _AP((DocObj** docs)); + +static query_term** +makeWAISQueryTerms(docs) +DocObj** docs; +/* given a null terminated list of docObjs, construct the appropriate + query of the form given above + */ +{ + query_term** terms = NULL; + long numTerms = 0; + DocObj* doc = NULL; + long i; + + if (docs == NULL) + return((query_term**)NULL); + + terms = (query_term**)s_malloc((size_t)(sizeof(query_term*) * 1)); + terms[numTerms] = NULL; + + /* loop through the docs making terms for them all */ + for (i = 0,doc = docs[i]; doc != NULL; doc = docs[++i]) + { any* type = NULL; + + if (doc->Type != NULL) + type = stringToAny(doc->Type); + + if (doc->ChunkCode == CT_document) /* a whole document */ + { terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 3 + 1))); + terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER, + EQUAL,IGNORE,IGNORE, + IGNORE,IGNORE,doc->DocumentID); + if (type != NULL) + { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL, + IGNORE,IGNORE,IGNORE, + IGNORE,type); + terms[numTerms++] = makeOperatorTerm(AND); + } + terms[numTerms] = NULL; + } + else /* a document fragment */ + { char chunk_att[ATTRIBUTE_SIZE]; + any* startChunk = NULL; + any* endChunk = NULL; + + terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 7 + 1))); + + switch (doc->ChunkCode) + { case CT_byte: + case CT_line: + { char start[20],end[20]; + (doc->ChunkCode == CT_byte) ? + strncpy(chunk_att,BYTE,ATTRIBUTE_SIZE) : + strncpy(chunk_att,LINE,ATTRIBUTE_SIZE); + sprintf(start,"%ld",doc->ChunkStart.Pos); + startChunk = stringToAny(start); + sprintf(end,"%ld",doc->ChunkEnd.Pos); + endChunk = stringToAny(end); + } + break; + case CT_paragraph: + strncpy(chunk_att,PARAGRAPH,ATTRIBUTE_SIZE); + startChunk = doc->ChunkStart.ID; + endChunk = doc->ChunkEnd.ID; + break; + default: + /* error */ + break; + } + + terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER, + EQUAL,IGNORE,IGNORE, + IGNORE, + IGNORE,doc->DocumentID); + if (type != NULL) + { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL,IGNORE, + IGNORE,IGNORE,IGNORE, + type); + terms[numTerms++] = makeOperatorTerm(AND); + } + terms[numTerms++] = makeAttributeTerm(chunk_att, + GREATER_THAN_OR_EQUAL, + IGNORE,IGNORE,IGNORE, + IGNORE, + startChunk); + terms[numTerms++] = makeOperatorTerm(AND); + terms[numTerms++] = makeAttributeTerm(chunk_att,LESS_THAN, + IGNORE,IGNORE,IGNORE, + IGNORE, + endChunk); + terms[numTerms++] = makeOperatorTerm(AND); + terms[numTerms] = NULL; + + if (doc->ChunkCode == CT_byte || doc->ChunkCode == CT_line) + { freeAny(startChunk); + freeAny(endChunk); + } + } + + freeAny(type); + + if (i != 0) /* multiple independent queries, need a disjunction */ + { terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 1 + 1))); + terms[numTerms++] = makeOperatorTerm(OR); + terms[numTerms] = NULL; + } + } + + return(terms); +} + +/*----------------------------------------------------------------------*/ + +static DocObj** makeWAISQueryDocs _AP((query_term** terms)); + +static DocObj** +makeWAISQueryDocs(terms) +query_term** terms; +/* given a list of terms in the form given above, convert them to + DocObjs. + */ +{ + query_term* docTerm = NULL; + query_term* fragmentTerm = NULL; + DocObj** docs = NULL; + DocObj* doc = NULL; + long docNum,termNum; + + docNum = termNum = 0; + + docs = (DocObj**)s_malloc((size_t)(sizeof(DocObj*) * 1)); + docs[docNum] = NULL; + + /* translate the terms into DocObjs */ + while (true) + { + query_term* typeTerm = NULL; + char* type = NULL; + long startTermOffset; + + docTerm = terms[termNum]; + + if (docTerm == NULL) + break; /* we're done converting */; + + typeTerm = terms[termNum + 1]; /* get the lead Term if it exists */ + + if (strcmp(typeTerm->Use,DATA_TYPE) == 0) /* we do have a type */ + { startTermOffset = 3; + type = anyToString(typeTerm->Term); + } + else /* no type */ + { startTermOffset = 1; + typeTerm = NULL; + type = NULL; + } + + /* grow the doc list */ + docs = (DocObj**)s_realloc((char*)docs,(size_t)(sizeof(DocObj*) * + (docNum + 1 + 1))); + + /* figure out what kind of docObj to build - and build it */ + fragmentTerm = terms[termNum + startTermOffset]; + if (fragmentTerm != NULL && fragmentTerm->TermType == TT_Attribute) + { /* build a document fragment */ + query_term* startTerm = fragmentTerm; + query_term* endTerm = terms[termNum + startTermOffset + 2]; + + if (strcmp(startTerm->Use,BYTE) == 0){ /* a byte chunk */ + doc = makeDocObjUsingBytes(duplicateAny(docTerm->Term), + type, + anyToLong(startTerm->Term), + anyToLong(endTerm->Term)); + log_write("byte"); + }else if (strcmp(startTerm->Use,LINE) == 0){ /* a line chunk */ + doc = makeDocObjUsingLines(duplicateAny(docTerm->Term), + type, + anyToLong(startTerm->Term), + anyToLong(endTerm->Term)); + log_write("line"); + }else{ + log_write("chunk"); /* a paragraph chunk */ + doc = makeDocObjUsingParagraphs(duplicateAny(docTerm->Term), + type, + duplicateAny(startTerm->Term), + duplicateAny(endTerm->Term)); +} + termNum += (startTermOffset + 4); /* point to next term */ + } + else /* build a full document */ + { + doc = makeDocObjUsingWholeDocument(duplicateAny(docTerm->Term), + type); +log_write("whole doc"); + termNum += startTermOffset; /* point to next term */ + } + + docs[docNum++] = doc; /* insert the new document */ + + docs[docNum] = NULL; /* keep the doc list terminated */ + + + if (terms[termNum] != NULL) + termNum++; /* skip the OR operator it necessary */ + else + break; /* we are done */ + } + + return(docs); +} + +/*----------------------------------------------------------------------*/ + +any* +makeWAISTextQuery(docs) +DocObj** docs; +/* given a list of DocObjs, return an any whose contents is the corresponding + type 1 query + */ +{ + any *buf = NULL; + query_term** terms = NULL; + + terms = makeWAISQueryTerms(docs); + buf = writeQuery(terms); + + doList((void**)terms,freeTerm); + s_free(terms); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +DocObj** +readWAISTextQuery(buf) +any* buf; +/* given an any whose contents are type 1 queries of the WAIS sort, + construct a list of the corresponding DocObjs + */ +{ + query_term** terms = NULL; + DocObj** docs = NULL; + + terms = readQuery(buf); + docs = makeWAISQueryDocs(terms); + + doList((void**)terms,freeTerm); + s_free(terms); + + return(docs); +} + +/*----------------------------------------------------------------------*/ +/* Customized free WAIS object routines: */ +/* */ +/* This set of procedures is for applications to free a WAIS object */ +/* which was made with makeWAISFOO. */ +/* Each procedure frees only the memory that was allocated in its */ +/* associated makeWAISFOO routine, thus it's not necessary for the */ +/* caller to assign nulls to the pointer fields of the WAIS object. */ +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISInitResponse(init) +WAISInitResponse* init; +/* free an object made with makeWAISInitResponse */ +{ + s_free(init); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISSearch(query) +WAISSearch* query; +/* destroy an object made with makeWAISSearch() */ +{ + s_free(query); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeDocObj(doc) +DocObj* doc; +/* free a docObj */ +{ + s_free(doc); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentHeader(header) +WAISDocumentHeader* header; +{ + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentShortHeader(header) +WAISDocumentShortHeader* header; +{ + s_free(header); +} +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentLongHeader(header) +WAISDocumentLongHeader* header; +{ + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISSearchResponse(response) +WAISSearchResponse* response; +{ + s_free(response); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentText(docText) +WAISDocumentText* docText; +{ + s_free(docText); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocHeadlines(docHeadline) +WAISDocumentHeadlines* docHeadline; +{ + s_free(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentCodes(docCodes) +WAISDocumentCodes* docCodes; +{ + s_free(docCodes); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISTextQuery(query) +any* query; +{ + freeAny(query); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from WMessage.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + 3.26.90 +*/ + +/* This file is for reading and writing the wais packet header. + * Morris@think.com + */ + +/* to do: + * add check sum + * what do you do when checksum is wrong? + */ + +/*---------------------------------------------------------------------*/ + +void +readWAISPacketHeader(msgBuffer,header_struct) +char* msgBuffer; +WAISMessage *header_struct; +{ + /* msgBuffer is a string containing at least HEADER_LENGTH bytes. */ + + memmove(header_struct->msg_len,msgBuffer,(size_t)10); + header_struct->msg_type = char_downcase((unsigned long)msgBuffer[10]); + header_struct->hdr_vers = char_downcase((unsigned long)msgBuffer[11]); + memmove(header_struct->server,(void*)(msgBuffer + 12),(size_t)10); + header_struct->compression = char_downcase((unsigned long)msgBuffer[22]); + header_struct->encoding = char_downcase((unsigned long)msgBuffer[23]); + header_struct->msg_checksum = char_downcase((unsigned long)msgBuffer[24]); +} + +/*---------------------------------------------------------------------*/ + +/* this modifies the header argument. See wais-message.h for the different + * options for the arguments. + */ + +void +writeWAISPacketHeader(header, + dataLen, + type, + server, + compression, + encoding, + version) +char* header; +long dataLen; +long type; +char* server; +long compression; +long encoding; +long version; +/* Puts together the new wais before-the-z39-packet header. */ +{ + char lengthBuf[11]; + char serverBuf[11]; + + long serverLen = strlen(server); + if (serverLen > 10) + serverLen = 10; + + sprintf(lengthBuf, "%010ld", dataLen); + strncpy(header,lengthBuf,10); + + header[10] = type & 0xFF; + header[11] = version & 0xFF; + + strncpy(serverBuf,server,serverLen); + strncpy((char*)(header + 12),serverBuf,serverLen); + + header[22] = compression & 0xFF; + header[23] = encoding & 0xFF; + header[24] = '0'; /* checkSum(header + HEADER_LENGTH,dataLen); XXX the result must be ascii */ +} + +/*---------------------------------------------------------------------*/ + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.h new file mode 100644 index 00000000000..1a4e83d50f1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.h @@ -0,0 +1,376 @@ +/* HTVMS_WAISProt.h +** +** Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu) +** +** 31-May-1994 FM Initial version. +** +**----------------------------------------------------------------------*/ + +/* +** Routines originally from WProt.h -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 3.30.90 Harry Morris + - removed chunk code from WAISSearchAPDU, + - added makeWAISQueryType1Query() and readWAISType1Query() which + replace makeWAISQueryTerms() and makeWAISQueryDocs(). + 4.11.90 HWM - added definitions of wais element set names + 4.14.90 HWM - changed symbol for relevance feedback query from QT_3 to + QT_RelevanceFeedbackQuery added QT_TextRetrievalQuery as a + synonym for QT_BooleanQuery + - renamed makeWAISType1Query() to makeWAISTextQuery() + renamed readWAISType1Query() to readWAISTextQuery() + 5.29.90 TS - added CSTFreeWAISFoo functions +*/ + +#ifndef _H_WAIS_protocol_ + +#define _H_WAIS_protocol_ + +/*----------------------------------------------------------------------*/ +/* Data types / constants */ + +/* date factor constants */ +#define DF_INDEPENDENT 1 +#define DF_LATER 2 +#define DF_EARLIER 3 +#define DF_SPECIFIED_RANGE 4 + +/* chunk types */ +#define CT_document 0 +#define CT_byte 1 +#define CT_line 2 +#define CT_paragraph 3 + +/* relevance feedback query */ +#define QT_RelevanceFeedbackQuery "3" +#define QT_TextRetrievalQuery QT_BooleanQuery + +/* new data tags */ +#define DT_UserInformationLength (data_tag)99 +#define DT_ChunkCode (data_tag)100 +#define DT_ChunkIDLength (data_tag)101 +#define DT_ChunkMarker (data_tag)102 +#define DT_HighlightMarker (data_tag)103 +#define DT_DeHighlightMarker (data_tag)104 +#define DT_NewlineCharacters (data_tag)105 +#define DT_SeedWords (data_tag)106 +#define DT_DocumentIDChunk (data_tag)107 +#define DT_ChunkStartID (data_tag)108 +#define DT_ChunkEndID (data_tag)109 +#define DT_TextList (data_tag)110 +#define DT_DateFactor (data_tag)111 +#define DT_BeginDateRange (data_tag)112 +#define DT_EndDateRange (data_tag)113 +#define DT_MaxDocumentsRetrieved (data_tag)114 +#define DT_SeedWordsUsed (data_tag)115 +#define DT_DocumentID (data_tag)116 +#define DT_VersionNumber (data_tag)117 +#define DT_Score (data_tag)118 +#define DT_BestMatch (data_tag)119 +#define DT_DocumentLength (data_tag)120 +#define DT_Source (data_tag)121 +#define DT_Date (data_tag)122 +#define DT_Headline (data_tag)123 +#define DT_OriginCity (data_tag)124 +#define DT_PresentStartByte (data_tag)125 +#define DT_TextLength (data_tag)126 +#define DT_DocumentText (data_tag)127 +#define DT_StockCodes (data_tag)128 +#define DT_CompanyCodes (data_tag)129 +#define DT_IndustryCodes (data_tag)130 + +/* added by harry */ +#define DT_DocumentHeaderGroup (data_tag)150 +#define DT_DocumentShortHeaderGroup (data_tag)151 +#define DT_DocumentLongHeaderGroup (data_tag)152 +#define DT_DocumentTextGroup (data_tag)153 +#define DT_DocumentHeadlineGroup (data_tag)154 +#define DT_DocumentCodeGroup (data_tag)155 +#define DT_Lines (data_tag)131 +#define DT_TYPE_BLOCK (data_tag)132 +#define DT_TYPE (data_tag)133 + +/* wais element sets */ +#define ES_DocumentHeader "Document Header" +#define ES_DocumentShortHeader "Document Short Header" +#define ES_DocumentLongHeader "Document Long Header" +#define ES_DocumentText "Document Text" +#define ES_DocumentHeadline "Document Headline" +#define ES_DocumentCodes "Document Codes" + +typedef struct DocObj { /* specifies a section of a document */ + any* DocumentID; + char* Type; + long ChunkCode; + union { + long Pos; + any* ID; + } ChunkStart; + union { + long Pos; + any* ID; + } ChunkEnd; + } DocObj; + +/*----------------------------------------------------------------------*/ +/* WAIS APDU extensions */ + +typedef struct WAISInitResponse { + long ChunkCode; + long ChunkIDLength; + char* ChunkMarker; + char* HighlightMarker; + char* DeHighlightMarker; + char* NewlineCharacters; + /* XXX need to add UpdateFrequency and Update Time */ + } WAISInitResponse; + +typedef struct WAISSearch { + char* SeedWords; + DocObj** Docs; + char** TextList; + long DateFactor; + char* BeginDateRange; + char* EndDateRange; + long MaxDocumentsRetrieved; + } WAISSearch; + +typedef struct WAISDocumentHeader { + any* DocumentID; + long VersionNumber; + long Score; + long BestMatch; + long DocumentLength; + long Lines; + char** Types; + char* Source; + char* Date; + char* Headline; + char* OriginCity; + } WAISDocumentHeader; + +typedef struct WAISDocumentShortHeader { + any* DocumentID; + long VersionNumber; + long Score; + long BestMatch; + long DocumentLength; + long Lines; + } WAISDocumentShortHeader; + +typedef struct WAISDocumentLongHeader { + any* DocumentID; + long VersionNumber; + long Score; + long BestMatch; + long DocumentLength; + long Lines; + char** Types; + char* Source; + char* Date; + char* Headline; + char* OriginCity; + char* StockCodes; + char* CompanyCodes; + char* IndustryCodes; + } WAISDocumentLongHeader; + +typedef struct WAISDocumentText { + any* DocumentID; + long VersionNumber; + any* DocumentText; + } WAISDocumentText; + +typedef struct WAISDocumentHeadlines { + any* DocumentID; + long VersionNumber; + char* Source; + char* Date; + char* Headline; + char* OriginCity; + } WAISDocumentHeadlines; + +typedef struct WAISDocumentCodes { + any* DocumentID; + long VersionNumber; + char* StockCodes; + char* CompanyCodes; + char* IndustryCodes; + } WAISDocumentCodes; + +typedef struct WAISSearchResponse { + char* SeedWordsUsed; + WAISDocumentHeader** DocHeaders; + WAISDocumentShortHeader** ShortHeaders; + WAISDocumentLongHeader** LongHeaders; + WAISDocumentText** Text; + WAISDocumentHeadlines** Headlines; + WAISDocumentCodes** Codes; + diagnosticRecord** Diagnostics; + } WAISSearchResponse; + +/*----------------------------------------------------------------------*/ +/* Functions */ + +DocObj* makeDocObjUsingWholeDocument _AP((any* aDocID,char* type)); +DocObj* makeDocObjUsingBytes _AP((any* aDocID,char* type,long start,long end)); +DocObj* makeDocObjUsingLines _AP((any* aDocID,char* type,long start,long end)); +DocObj* makeDocObjUsingParagraphs _AP((any* aDocID,char* type,any* start,any* end)); +void freeDocObj _AP((DocObj* doc)); + +WAISInitResponse* makeWAISInitResponse _AP((long chunkCode,long chunkIDLen, + char* chunkMarker,char* highlightMarker, + char* deHighlightMarker,char* newLineChars)); +void freeWAISInitResponse _AP((WAISInitResponse* init)); + +WAISSearch* makeWAISSearch _AP(( + char* seedWords,DocObj** docs,char** textList, + long dateFactor,char* beginDateRange,char* endDateRange, + long maxDocsRetrieved)); +void freeWAISSearch _AP((WAISSearch* query)); + +WAISDocumentHeader* makeWAISDocumentHeader _AP(( + any* aDocID,long versionNumber,long score,long bestMatch,long docLen, + long lines,char** types,char* source,char* date,char* headline,char* originCity)); +void freeWAISDocumentHeader _AP((WAISDocumentHeader* header)); +char* writeWAISDocumentHeader _AP((WAISDocumentHeader* header,char* buffer,long* len)); +char* readWAISDocumentHeader _AP((WAISDocumentHeader** header,char* buffer)); + +WAISDocumentShortHeader* makeWAISDocumentShortHeader _AP(( + any* aDocID,long versionNumber,long score,long bestMatch,long docLen,long lines)); +void freeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header)); +char* writeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header, + char* buffer,long* len)); +char* readWAISDocumentShortHeader _AP((WAISDocumentShortHeader** header,char* buffer)); + +WAISDocumentLongHeader* makeWAISDocumentLongHeader _AP(( + any* aDocID,long versionNumber,long score,long bestMatch,long docLen, + long lines,char** types,char* source,char* date, char* headline,char* originCity, + char* stockCodes,char* companyCodes,char* industryCodes)); +void freeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header)); +char* writeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header,char* buffer,long* len)); +char* readWAISDocumentLongHeader _AP((WAISDocumentLongHeader** header,char* buffer)); + +WAISSearchResponse* makeWAISSearchResponse _AP(( + char* seedWordsUsed,WAISDocumentHeader** docHeaders, + WAISDocumentShortHeader** shortHeaders, + WAISDocumentLongHeader** longHeaders, + WAISDocumentText** text,WAISDocumentHeadlines** headlines, + WAISDocumentCodes** codes, + diagnosticRecord** diagnostics)); +void freeWAISSearchResponse _AP((WAISSearchResponse* response)); + +WAISDocumentText* makeWAISDocumentText _AP((any* aDocID,long versionNumber, + any* documentText)); +void freeWAISDocumentText _AP((WAISDocumentText* docText)); +char* writeWAISDocumentText _AP((WAISDocumentText* docText,char* buffer,long* len)); +char* readWAISDocumentText _AP((WAISDocumentText** docText,char* buffer)); + +WAISDocumentHeadlines* makeWAISDocumentHeadlines _AP(( + any* aDocID,long versionNumber,char* source,char* date,char* headline, + char* originCity)); +void freeWAISDocumentHeadlines _AP((WAISDocumentHeadlines* docHeadline)); +char* writeWAISDocumentHeadlines _AP((WAISDocumentHeadlines* docHeadline,char* buffer,long* len)); +char* readWAISDocumentHeadlines _AP((WAISDocumentHeadlines** docHeadline,char* buffer)); + +WAISDocumentCodes* makeWAISDocumentCodes _AP(( + any* aDocID,long versionNumber,char* stockCodes,char* companyCodes, + char* industryCodes)); +void freeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes)); +char* writeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes,char* buffer,long* len)); +char* readWAISDocumentCodes _AP((WAISDocumentCodes** docCodes,char* buffer)); + +any* makeWAISTextQuery _AP((DocObj** docs)); +DocObj** readWAISTextQuery _AP((any* terms)); + +void CSTFreeWAISInitResponse _AP((WAISInitResponse* init)); +void CSTFreeWAISSearch _AP((WAISSearch* query)); +void CSTFreeDocObj _AP((DocObj* doc)); +void CSTFreeWAISDocumentHeader _AP((WAISDocumentHeader* header)); +void CSTFreeWAISDocumentShortHeader _AP((WAISDocumentShortHeader* header)); +void CSTFreeWAISDocumentLongHeader _AP((WAISDocumentLongHeader* header)); +void CSTFreeWAISSearchResponse _AP((WAISSearchResponse* response)); +void CSTFreeWAISDocumentText _AP((WAISDocumentText* docText)); +void CSTFreeWAISDocHeadlines _AP((WAISDocumentHeadlines* docHeadline)); +void CSTFreeWAISDocumentCodes _AP((WAISDocumentCodes* docCodes)); +void CSTFreeWAISTextQuery _AP(( any* query)); + +/*----------------------------------------------------------------------*/ + +#endif /* ndef _H_WAIS_protocol_ */ + + +/* +** Routines originally from WMessage.h -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + 3.26.90 +*/ + +/* wais-message.h + * + * This is the header outside of WAIS Z39.50 messages. The header will be + * printable ascii, so as to be transportable. This header will precede each + * Z39.50 APDU, or zero-length message if it is an ACK or NACK. Be sure to + * change hdr_vers current value if you change the structure of the header. + * + * The characters in the header are case insensitive so that the systems from + * the past that only handle one case can at least read the header. + * + * 7.5.90 HWM - added constants + * 7/5/90 brewster added funtion prototypes and comments + * 11/30/90 HWM - went to version 2 (inits and typed retrieval) + */ + +#ifndef WMESSAGE_H +#define WMESSAGE_H + +typedef struct wais_header { + char msg_len[10]; /* length in bytes of following message */ + char msg_type; /* type of message: 'z'=Z39.50 APDU, + 'a'=ACK, 'n'=NACK */ + char hdr_vers; /* version of this header, currently = '2' */ + char server[10]; /* name or address of server */ + char compression; /* <sp>=no compression, 'u'=unix compress */ + char encoding; /* <sp>=no encoding, 'h'=hexize, + 'u'=uuencode */ + char msg_checksum; /* XOR of every byte of message */ + } WAISMessage; + +#define HEADER_LENGTH 25 /* number of bytes needed to write a + wais-header (not sizeof(wais_header)) */ + +#define HEADER_VERSION (long)'2' + +/* message type */ +#define Z3950 'z' +#define ACK 'a' +#define NAK 'n' + +/* compression */ +#define NO_COMPRESSION ' ' +#define UNIX_COMPRESSION 'u' + +/* encoding */ +#define NO_ENCODING ' ' +#define HEX_ENCODING 'h' /* Swartz 4/3 encoding */ +#define IBM_HEXCODING 'i' /* same as h but uses characters acceptable for IBM mainframes */ +#define UUENCODE 'u' + + +void readWAISPacketHeader _AP((char* msgBuffer,WAISMessage *header_struct)); +long getWAISPacketLength _AP((WAISMessage* header)); +void writeWAISPacketHeader _AP((char* header,long dataLen,long type, + char* server,long compression, + long encoding,long version)); + +#endif /* ndef WMESSAGE_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.c new file mode 100644 index 00000000000..81c097070c9 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.c @@ -0,0 +1,2448 @@ +/* HTVMS_WAISUI.c +** +** Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu) +** +** 30-May-1994 FM Initial version. +** +**----------------------------------------------------------------------*/ + +/* +** Routines originally from UI.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + Brewster@think.com +*/ + +/* + * this is a simple ui toolkit for building other ui's on top. + * -brewster + * + * top level functions: + * generate_search_apdu + * generate_retrieval_apdu + * interpret_message + * + */ + +/* to do: + * generate multiple queries for long documents. + * this will crash if the file being retrieved is larger than 100k. + * do log_write() + * + */ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTVMS_WaisUI.h" +#include "HTVMS_WaisProt.h" +#include "HTTCP.h" +/*#include <stdio> included by HTUtils.h -- FM */ +#include <string.h> +#include <ctype.h> +#include <math.h> +#include <stdarg.h> + +#include "LYexit.h" +#include "LYLeaks.h" + +void +log_write(s) +char *s; +{ + return; +} + +/*----------------------------------------------------------------------*/ + +/* returns a pointer in the buffer of the first free byte. + if it overflows, then NULL is returned + */ +char * +generate_search_apdu(buff, + buff_len, + seed_words, + database_name, + docobjs, + maxDocsRetrieved) +char* buff; /* buffer to hold the apdu */ +long *buff_len; /* length of the buffer changed to reflect new data written */ +char *seed_words; /* string of the seed words */ +char *database_name; +DocObj** docobjs; +long maxDocsRetrieved; +{ + /* local variables */ + + SearchAPDU *search3; + char *end_ptr; + static char *database_names[2] = {"", 0}; + any refID; + WAISSearch *query; + refID.size = 1; + refID.bytes = "3"; + + database_names[0] = database_name; + query = makeWAISSearch(seed_words, + docobjs, /* DocObjsPtr */ + 0, + 1, /* DateFactor */ + 0, /* BeginDateRange */ + 0, /* EndDateRange */ + maxDocsRetrieved + ); + + search3 = makeSearchAPDU(30, + 5000, /* should be large */ + 30, + 1, /* replace indicator */ + "", /* result set name */ + database_names, /* database name */ + QT_RelevanceFeedbackQuery, /* query_type */ + 0, /* element name */ + NULL, /* reference ID */ + query); + + end_ptr = writeSearchAPDU(search3, buff, buff_len); + + CSTFreeWAISSearch(query); + freeSearchAPDU(search3); + return(end_ptr); +} + +/*----------------------------------------------------------------------*/ + +/* returns a pointer into the buffer of the next free byte. + if it overflowed, then NULL is returned + */ + +char * +generate_retrieval_apdu(buff, + buff_len, + docID, + chunk_type, + start, + end, + type, + database_name) +char *buff; +long *buff_len; /* length of the buffer changed to reflect new data written */ +any *docID; +long chunk_type; +long start; +long end; +char *type; +char *database_name; +{ + SearchAPDU *search; + char *end_ptr; + + static char *database_names[2]; + static char *element_names[3]; + any refID; + + DocObj *DocObjs[2]; + any *query; /* changed from char* by brewster */ + + if(NULL == type) + type = s_strdup("TEXT"); + + database_names[0] = database_name; + database_names[1] = NULL; + + element_names[0] = " "; + element_names[1] = ES_DocumentText; + element_names[2] = NULL; + + refID.size = 1; + refID.bytes = "3"; + + switch(chunk_type){ + case CT_line: + DocObjs[0] = makeDocObjUsingLines(docID, type, start, end); + break; + case CT_byte: + DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end); + break; + } + DocObjs[1] = NULL; + + query = makeWAISTextQuery(DocObjs); + search = makeSearchAPDU( 10, 16, 15, + 1, /* replace indicator */ + "FOO", /* result set name */ + database_names, /* database name */ + QT_TextRetrievalQuery, /* query_type */ + element_names, /* element name */ + &refID, /* reference ID */ + query); + end_ptr = writeSearchAPDU(search, buff, buff_len); + CSTFreeWAISTextQuery(query); + freeSearchAPDU(search); + return(end_ptr); +} + +/*----------------------------------------------------------------------*/ + +/* this is a safe version of unix 'read' it does all the checking + * and looping necessary + * to those trying to modify the transport code to use non-UNIX streams: + * This is the function to modify! + */ +long read_from_stream(d,buf,nbytes) +int d; /* this is the stream */ +char *buf; +long nbytes; +{ + long didRead; + long toRead = nbytes; + long totalRead = 0; /* paranoia */ + + while (toRead > 0){ + didRead = NETREAD (d, buf, (int)toRead); + if(didRead == HT_INTERRUPTED) + return(HT_INTERRUPTED); + if(didRead == -1) /* error*/ + return(-1); + if(didRead == 0) /* eof */ + return(-2); /* maybe this should return 0? */ + toRead -= didRead; + buf += didRead; + totalRead += didRead; + } + if(totalRead != nbytes) /* we overread for some reason */ + return(- totalRead); /* bad news */ + return(totalRead); +} + +/*----------------------------------------------------------------------*/ + +/* returns the length of the response, 0 if an error */ + +long +transport_message(connection, + request_message, + request_length, + response_message, + response_buffer_length) +int connection; +char *request_message; +long request_length; +char *response_message; +long response_buffer_length; +{ + WAISMessage header; + long response_length; + int rv; + + + /* Write out message. Read back header. Figure out response length. */ + + if( request_length + HEADER_LENGTH != + NETWRITE(connection,request_message, + (int)( request_length +HEADER_LENGTH)) ) + return 0; + + /* read for the first '0' */ + + while(1){ + rv = read_from_stream(connection, response_message, 1); + if (rv == HT_INTERRUPTED) + return HT_INTERRUPTED; + if (rv < 0) + return 0; + if('0' == response_message[0]) + break; + } + + rv = read_from_stream(connection, response_message + 1, HEADER_LENGTH -1); + if (rv == HT_INTERRUPTED) + return HT_INTERRUPTED; + if (rv < 0) + return 0; + + readWAISPacketHeader(response_message, &header); + { + char length_array[11]; + strncpy(length_array, header.msg_len, 10); + length_array[10] = '\0'; + response_length = atol(length_array); + /* + if(verbose){ + printf("WAIS header: '%s' length_array: '%s'\n", + response_message, length_array); + } + */ + if(response_length > response_buffer_length){ + /* we got a message that is too long, therefore empty the message out, + and return 0 */ + long i; + for(i = 0; i < response_length; i++){ + rv = read_from_stream(connection, + response_message + HEADER_LENGTH, + 1); + if (rv == HT_INTERRUPTED) + return HT_INTERRUPTED; + if (rv < 0) + return 0; + } + return(0); + } + } + rv = read_from_stream(connection, + response_message + HEADER_LENGTH, + response_length); + if (rv == HT_INTERRUPTED) + return HT_INTERRUPTED; + if (rv < 0) + return 0; + return(response_length); +} + +/*----------------------------------------------------------------------*/ + +/* returns the number of bytes writen. 0 if an error */ +long +interpret_message(request_message,request_length, + response_message, + response_buffer_length, + connection, + verbose) +char *request_message; +long request_length; /* length of the buffer */ +char *response_message; +long response_buffer_length; +int connection; +boolean verbose; +{ + long response_length; + + /* ? + if(verbose){ + printf ("sending"); + if(hostname_internal && strlen(hostname_internal) > 0) + printf(" to host %s", hostname_internal); + if(service_name && strlen(service_name) > 0) + printf(" for service %s", service_name); + printf("\n"); + twais_dsply_rsp_apdu(request_message + HEADER_LENGTH, + request_length); + } + + */ + + writeWAISPacketHeader(request_message, + request_length, + (long)'z', /* Z39.50 */ + "wais ", /* server name */ + (long)NO_COMPRESSION, /* no compression */ + (long)NO_ENCODING,(long)HEADER_VERSION); + if(connection != 0) { + response_length = transport_message(connection, request_message, + request_length, + response_message, + response_buffer_length); + if (response_length == HT_INTERRUPTED) + return(HT_INTERRUPTED); + } + else + return(0); + + return(response_length); +} + +/*----------------------------------------------------------------------*/ + +/* modifies the string to exclude all seeker codes. sets length to + the new length. */ +char *delete_seeker_codes(string,length) +char *string; +long *length; +{ + long original_count; /* index into the original string */ + long new_count = 0; /* index into the collapsed string */ + for(original_count = 0; original_count < *length; original_count++){ + if(27 == string[original_count]){ + /* then we have an escape code */ + /* if the next letter is '(' or ')', then ignore two letters */ + if('(' == string[original_count + 1] || + ')' == string[original_count + 1]) + original_count += 1; /* it is a term marker */ + else original_count += 4; /* it is a paragraph marker */ + } + else string[new_count++] = string[original_count]; + } + *length = new_count; + return(string); +} + +/*----------------------------------------------------------------------*/ + +#if defined(VMS) && defined(__GNUC__) /* 10-AUG-1995 [pr] */ +/* + Workaround for an obscure bug in gcc's 2.6.[123] and 2.7.0 vax/vms port; + sometimes global variables will end up not being defined properly, + causing first gas to assume they're routines, then the linker to complain + about unresolved symbols, and finally the program to reference the wrong + objects (provoking ACCVIO). It's triggered by the specific ordering of + variable usage in the source code, hence rarely appears. This bug is + fixed in gcc 2.7.1, and was not present in 2.6.0 and earlier. + + Make a reference to VAXCRTL's _ctype_[], and also one to this dummy + variable itself to prevent any "defined but not used" warning. + */ +static __const void *__const ctype_dummy[] = { &_ctype_, &ctype_dummy }; +#endif /* VMS && __GNUC__ */ + +/* returns a pointer to a string with good stuff */ +char *trim_junk(headline) +char *headline; +{ + long length = strlen(headline) + 1; /* include the trailing null */ + long i; + headline = delete_seeker_codes(headline, &length); + /* delete leading spaces */ + for(i=0; i < strlen(headline); i++){ + if(isprint(headline[i])){ + break; + } + } + headline = headline + i; + /* delete trailing stuff */ + for(i=strlen(headline) - 1 ; i > 0; i--){ + if(isprint(headline[i])){ + break; + } + headline[i] = '\0'; + } + return(headline); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from ZProt.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE:` + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 3.30.90 Harry Morris - Changed any->bits to any->bytes + 4.11.90 HWM - generalized conditional includes (see c-dialect.h) +*/ + +#define RESERVE_SPACE_FOR_HEADER(spaceLeft) \ + *spaceLeft -= HEADER_LEN; + +#define RELEASE_HEADER_SPACE(spaceLeft) \ + if (*spaceLeft > 0) \ + *spaceLeft += HEADER_LEN; + +/*----------------------------------------------------------------------*/ + +InitResponseAPDU* +makeInitResponseAPDU(result, + search, + present, + deleteIt, + accessControl, + resourceControl, + prefSize, + maxMsgSize, + auth, + id, + name, + version, + refID, + userInfo) +boolean result; +boolean search; +boolean present; +boolean deleteIt; +boolean accessControl; +boolean resourceControl; +long prefSize; +long maxMsgSize; +char* auth; +char* id; +char* name; +char* version; +any* refID; +void* userInfo; +/* build an initResponse APDU with user specified information */ +{ + InitResponseAPDU* init = (InitResponseAPDU*)s_malloc((size_t)sizeof(InitResponseAPDU)); + + init->PDUType = initResponseAPDU; + init->Result = result; + init->willSearch = search; + init->willPresent = present; + init->willDelete = deleteIt; + init->supportAccessControl = accessControl; + init->supportResourceControl = resourceControl; + init->PreferredMessageSize = prefSize; + init->MaximumRecordSize = maxMsgSize; + init->IDAuthentication = s_strdup(auth); + init->ImplementationID = s_strdup(id); + init->ImplementationName = s_strdup(name); + init->ImplementationVersion = s_strdup(version); + init->ReferenceID = duplicateAny(refID); + init->UserInformationField = userInfo; /* not copied! */ + + return(init); +} + +/*----------------------------------------------------------------------*/ + +void +freeInitResponseAPDU(init) +InitResponseAPDU* init; +/* free an initAPDU */ +{ + s_free(init->IDAuthentication); + s_free(init->ImplementationID); + s_free(init->ImplementationName); + s_free(init->ImplementationVersion); + freeAny(init->ReferenceID); + s_free(init); +} + +/*----------------------------------------------------------------------*/ + +char* +writeInitResponseAPDU(init,buffer,len) +InitResponseAPDU* init; +char* buffer; +long* len; +/* write the initResponse to a buffer, adding system information */ +{ + char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */ + long size; + bit_map* optionsBM = NULL; + + RESERVE_SPACE_FOR_HEADER(len); + + buf = writePDUType(init->PDUType,buf,len); + buf = writeBoolean(init->Result,buf,len); + buf = writeProtocolVersion(buf,len); + + optionsBM = makeBitMap((unsigned long)5,init->willSearch,init->willPresent, + init->willDelete,init->supportAccessControl, + init->supportResourceControl); + buf = writeBitMap(optionsBM,DT_Options,buf,len); + freeBitMap(optionsBM); + + buf = writeNum(init->PreferredMessageSize,DT_PreferredMessageSize,buf,len); + buf = writeNum(init->MaximumRecordSize,DT_MaximumRecordSize,buf,len); + buf = writeString(init->IDAuthentication,DT_IDAuthentication,buf,len); + buf = writeString(init->ImplementationID,DT_ImplementationID,buf,len); + buf = writeString(init->ImplementationName,DT_ImplementationName,buf,len); + buf = writeString(init->ImplementationVersion,DT_ImplementationVersion,buf,len); + buf = writeAny(init->ReferenceID,DT_ReferenceID,buf,len); + + /* go back and write the header-length-indicator */ + RELEASE_HEADER_SPACE(len); + size = buf - buffer - HEADER_LEN; + writeBinaryInteger(size,HEADER_LEN,buffer,len); + + if (init->UserInformationField != NULL) + buf = writeInitResponseInfo(init,buf,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readInitResponseAPDU(init,buffer) +InitResponseAPDU** init; +char* buffer; +{ + char* buf = buffer; + boolean search,present,delete,accessControl,resourceControl; + long prefSize,maxMsgSize; + char *auth,*id,*name,*version; + long size; + pdu_type pduType; + bit_map* versionBM = NULL; + bit_map* optionsBM = NULL; + boolean result; + any *refID = NULL; + void* userInfo = NULL; + + auth = id = name = version = NULL; + refID = NULL; + + /* read required part */ + buf = readBinaryInteger(&size,HEADER_LEN,buf); + buf = readPDUType(&pduType,buf); + buf = readBoolean(&result,buf); + buf = readBitMap(&versionBM,buf); + buf = readBitMap(&optionsBM,buf); + buf = readNum(&prefSize,buf); + buf = readNum(&maxMsgSize,buf); + + /* decode optionsBM */ + search = bitAtPos(0,optionsBM); + present = bitAtPos(1,optionsBM); + delete = bitAtPos(2,optionsBM); + accessControl = bitAtPos(3,optionsBM); + resourceControl = bitAtPos(4,optionsBM); + + /* read optional part */ + while (buf < (buffer + size + HEADER_LEN)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_IDAuthentication: + buf = readString(&auth,buf); + break; + case DT_ImplementationID: + buf = readString(&id,buf); + break; + case DT_ImplementationName: + buf = readString(&name,buf); + break; + case DT_ImplementationVersion: + buf = readString(&version,buf); + break; + case DT_ReferenceID: + buf = readAny(&refID,buf); + break; + default: + freeBitMap(versionBM); + freeBitMap(optionsBM); + s_free(auth); + s_free(id); + s_free(name); + s_free(version); + freeAny(refID); + REPORT_READ_ERROR(buf); + break; + } + } + + buf = readInitResponseInfo(&userInfo,buf); + if (buf == NULL) + { freeBitMap(versionBM); + freeBitMap(optionsBM); + s_free(auth); + s_free(id); + s_free(name); + s_free(version); + freeAny(refID); + } + RETURN_ON_NULL(buf); + + /* construct the basic init object */ + *init = makeInitResponseAPDU(result, + search,present,delete,accessControl,resourceControl, + prefSize,maxMsgSize,auth,id,name,version,refID,userInfo); + + freeBitMap(versionBM); + freeBitMap(optionsBM); + s_free(auth); + s_free(id); + s_free(name); + s_free(version); + freeAny(refID); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +InitResponseAPDU* +replyToInitAPDU(init,result,userInfo) +InitAPDU* init; +boolean result; +void* userInfo; +/* respond to an init message in the default way - echoing back + the init info + */ +{ + InitResponseAPDU* initResp; + initResp = makeInitResponseAPDU(result, + init->willSearch,init->willPresent,init->willDelete, + init->supportAccessControl,init->supportResourceControl, + init->PreferredMessageSize,init->MaximumRecordSize, + init->IDAuthentication,defaultImplementationID(),defaultImplementationName(), + defaultImplementationVersion(), + init->ReferenceID,userInfo); + return(initResp); +} + +/*----------------------------------------------------------------------*/ + +SearchAPDU* +makeSearchAPDU(small, + large, + medium, + replace, + name, + databases, + type, + elements, + refID, + queryInfo) +long small; +long large; +long medium; +boolean replace; +char* name; +char** databases; +char* type; +char** elements; +any* refID; +void* queryInfo; +{ + char* ptr = NULL; + long i; + SearchAPDU* query = (SearchAPDU*)s_malloc((size_t)sizeof(SearchAPDU)); + query->PDUType = searchAPDU; + query->SmallSetUpperBound = small; + query->LargeSetLowerBound = large; + query->MediumSetPresentNumber = medium; + query->ReplaceIndicator = replace; + query->ResultSetName = s_strdup(name); + query->DatabaseNames = NULL; + if (databases != NULL) + { for (i = 0, ptr = databases[i]; ptr != NULL; ptr = databases[++i]) + { if (query->DatabaseNames == NULL) + query->DatabaseNames = (char**)s_malloc((size_t)(sizeof(char*) * 2)); + else + query->DatabaseNames = (char**)s_realloc((char*)query->DatabaseNames, + (size_t)(sizeof(char*) * (i + 2))); + query->DatabaseNames[i] = s_strdup(ptr); + query->DatabaseNames[i+1] = NULL; + } + } + query->QueryType = s_strdup(type); + query->ElementSetNames = NULL; + if (elements != NULL) + { for (i = 0, ptr = elements[i]; ptr != NULL; ptr = elements[++i]) + { if (query->ElementSetNames == NULL) + query->ElementSetNames = (char**)s_malloc((size_t)(sizeof(char*) * 2)); + else + query->ElementSetNames = (char**)s_realloc((char*)query->ElementSetNames, + (size_t)(sizeof(char*) * (i + 2))); + query->ElementSetNames[i] = s_strdup(ptr); + query->ElementSetNames[i+1] = NULL; + } + } + query->ReferenceID = duplicateAny(refID); + query->Query = queryInfo; /* not copied! */ + return(query); +} + +/*----------------------------------------------------------------------*/ + +void +freeSearchAPDU(query) +SearchAPDU* query; +{ + s_free(query->ResultSetName); + s_free(query->QueryType); + doList((void**)query->DatabaseNames,fs_free); /* can't use the macro here ! */ + s_free(query->DatabaseNames); + doList((void**)query->ElementSetNames,fs_free); /* can't use the macro here ! */ + s_free(query->ElementSetNames); + freeAny(query->ReferenceID); + s_free(query); +} + +/*----------------------------------------------------------------------*/ + +#define DB_DELIMITER "\037" /* hex 1F occurs between each database name */ +#define ES_DELIMITER_1 "\037" /* separates database name from element name */ +#define ES_DELIMITER_2 "\036" /* hex 1E separates <db,es> groups from one another */ + +char* +writeSearchAPDU(query,buffer,len) +SearchAPDU* query; +char* buffer; +long* len; +{ + char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */ + long size,i; + char* ptr = NULL; + char* scratch = NULL; + + RESERVE_SPACE_FOR_HEADER(len); + + buf = writePDUType(query->PDUType,buf,len); + buf = writeBinaryInteger(query->SmallSetUpperBound,(size_t)3,buf,len); + buf = writeBinaryInteger(query->LargeSetLowerBound,(size_t)3,buf,len); + buf = writeBinaryInteger(query->MediumSetPresentNumber,(size_t)3,buf,len); + buf = writeBoolean(query->ReplaceIndicator,buf,len); + buf = writeString(query->ResultSetName,DT_ResultSetName,buf,len); + /* write database names */ + if (query->DatabaseNames != NULL) + { for (i = 0,scratch = NULL, ptr = query->DatabaseNames[i]; ptr != NULL; ptr = query->DatabaseNames[++i]) + { if (scratch == NULL) + scratch = s_strdup(ptr); + else + { size_t newScratchSize = (size_t)(strlen(scratch) + strlen(ptr) + 2); + scratch = (char*)s_realloc(scratch,newScratchSize); + s_strncat(scratch,DB_DELIMITER,2,newScratchSize); + s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize); + } + } + buf = writeString(scratch,DT_DatabaseNames,buf,len); + s_free(scratch); + } + buf = writeString(query->QueryType,DT_QueryType,buf,len); + /* write element set names */ + if (query->ElementSetNames != NULL) + { for (i = 0,scratch = NULL, ptr = query->ElementSetNames[i]; ptr != NULL; ptr = query->ElementSetNames[++i]) + { if (scratch == NULL) + { if (query->ElementSetNames[i+1] == NULL) /* there is a single element set name */ + { scratch = (char*)s_malloc((size_t)strlen(ptr) + 2); + strncpy(scratch,ES_DELIMITER_1,2); + s_strncat(scratch,ptr,strlen(ptr) + 1,strlen(ptr) + 2); + } + else /* this is the first of a series of element set names */ + { size_t newScratchSize = (size_t)(strlen(ptr) + strlen(query->ElementSetNames[i + 1]) + 2); + scratch = s_strdup(ptr); /* the database name */ + ptr = query->ElementSetNames[++i]; /* the element set name */ + scratch = (char*)s_realloc(scratch,newScratchSize); + s_strncat(scratch,ES_DELIMITER_1,2,newScratchSize); + s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize); + } + } + else + { char* esPtr = query->ElementSetNames[++i]; /* the element set name */ + size_t newScratchSize = (size_t)(strlen(scratch) + strlen(ptr) + strlen(esPtr) + 3); + scratch = (char*)s_realloc(scratch,newScratchSize); + s_strncat(scratch,ES_DELIMITER_2,2,newScratchSize); + s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize); + s_strncat(scratch,ES_DELIMITER_1,2,newScratchSize); + s_strncat(scratch,esPtr,strlen(esPtr) + 1,newScratchSize); + } + } + buf = writeString(scratch,DT_ElementSetNames,buf,len); + s_free(scratch); + } + buf = writeAny(query->ReferenceID,DT_ReferenceID,buf,len); + + /* go back and write the header-length-indicator */ + RELEASE_HEADER_SPACE(len); + size = buf - buffer - HEADER_LEN; + writeBinaryInteger(size,HEADER_LEN,buffer,len); + + if (query->Query != NULL) + buf = writeSearchInfo(query,buf,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +SearchResponseAPDU* +makeSearchResponseAPDU(result,count,recordsReturned,nextPos,resultStatus, + presentStatus,refID,records) +long result; +long count; +long recordsReturned; +long nextPos; +long resultStatus; +long presentStatus; +any* refID; +void* records; +{ + SearchResponseAPDU* query = (SearchResponseAPDU*)s_malloc((size_t)sizeof(SearchResponseAPDU)); + query->PDUType = searchResponseAPDU; + query->SearchStatus = result; + query->ResultCount = count; + query->NumberOfRecordsReturned = recordsReturned; + query->NextResultSetPosition = nextPos; + query->ResultSetStatus = resultStatus; + query->PresentStatus = presentStatus; + query->ReferenceID = duplicateAny(refID); + query->DatabaseDiagnosticRecords = records; + return(query); +} + +/*----------------------------------------------------------------------*/ + +void +freeSearchResponseAPDU(queryResponse) +SearchResponseAPDU* queryResponse; +{ + freeAny(queryResponse->ReferenceID); + s_free(queryResponse); +} + +/*----------------------------------------------------------------------*/ + +char* +writeSearchResponseAPDU(queryResponse,buffer,len) +SearchResponseAPDU* queryResponse; +char* buffer; +long* len; +{ + char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */ + long size; + + RESERVE_SPACE_FOR_HEADER(len); + + buf = writePDUType(queryResponse->PDUType,buf,len); + buf = writeBinaryInteger(queryResponse->SearchStatus,(size_t)1,buf,len); + buf = writeBinaryInteger(queryResponse->ResultCount,(size_t)3,buf,len); + buf = writeBinaryInteger(queryResponse->NumberOfRecordsReturned,(size_t)3,buf,len); + buf = writeBinaryInteger(queryResponse->NextResultSetPosition,(size_t)3,buf,len); + buf = writeNum(queryResponse->ResultSetStatus,DT_ResultSetStatus,buf,len); + buf = writeNum(queryResponse->PresentStatus,DT_PresentStatus,buf,len); + buf = writeAny(queryResponse->ReferenceID,DT_ReferenceID,buf,len); + + /* go back and write the header-length-indicator */ + RELEASE_HEADER_SPACE(len); + size = buf - buffer - HEADER_LEN; + writeBinaryInteger(size,HEADER_LEN,buffer,len); + + if (queryResponse->DatabaseDiagnosticRecords != NULL) + buf = writeSearchResponseInfo(queryResponse,buf,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readSearchResponseAPDU(queryResponse,buffer) +SearchResponseAPDU** queryResponse; +char* buffer; +{ + char* buf = buffer; + long size; + pdu_type pduType; + long result,count,recordsReturned,nextPos; + long resultStatus,presentStatus; + any *refID = NULL; + void* userInfo = NULL; + + /* read required part */ + buf = readBinaryInteger(&size,HEADER_LEN,buf); + buf = readPDUType(&pduType,buf); + buf = readBinaryInteger(&result,(size_t)1,buf); + buf = readBinaryInteger(&count,(size_t)3,buf); + buf = readBinaryInteger(&recordsReturned,(size_t)3,buf); + buf = readBinaryInteger(&nextPos,(size_t)3,buf); + + resultStatus = presentStatus = UNUSED; + refID = NULL; + + /* read optional part */ + while (buf < (buffer + size + HEADER_LEN)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_ResultSetStatus: + buf = readNum(&resultStatus,buf); + break; + case DT_PresentStatus: + buf = readNum(&presentStatus,buf); + break; + case DT_ReferenceID: + buf = readAny(&refID,buf); + break; + default: + freeAny(refID); + REPORT_READ_ERROR(buf); + break; + } + } + + buf = readSearchResponseInfo(&userInfo,buf); + if (buf == NULL) + freeAny(refID); + RETURN_ON_NULL(buf); + + /* construct the search object */ + *queryResponse = makeSearchResponseAPDU(result,count,recordsReturned,nextPos, + (long)resultStatus,(long)presentStatus,refID,userInfo); + + freeAny(refID); + + return(buf); +} + + +/* +** Routines originally from ZUtil.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 3.30.90 Harry Morris - Changed any->bits to any->bytes + 4.11.90 HWM - fixed include file names, changed + - writeCompressedIntegerWithPadding() to + writeCompressedIntWithPadding() + - generalized conditional includes (see c-dialect.h) + 3.7.91 Jonny Goldman. Replaced "short" in makeBitMap with "int" line 632. +*/ + +char* readErrorPosition = NULL; /* pos where buf stoped making sense */ + +/*----------------------------------------------------------------------*/ +/* A note on error handling + read - these are low level routines, they do not check the type tags + which (sometimes) preceed the data (this is done by the higher + level functions which call these functions). There is no + attempt made to check that the reading does not exceed the read + buffer. Such cases should be very rare and usually will be + caught by the calling functions. (note - it is unlikely that + a series of low level reads will go far off the edge without + triggering a type error. However, it is possible for a single + bad read in an array function (eg. readAny) to attempt to read a + large ammount, possibly causing a segmentation violation or out + of memory condition. + */ +/*----------------------------------------------------------------------*/ + +diagnosticRecord* +makeDiag(surrogate,code,addInfo) +boolean surrogate; +char* code; +char* addInfo; +{ + diagnosticRecord* diag = + (diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord)); + + diag->SURROGATE = surrogate; + memcpy(diag->DIAG,code,DIAGNOSTIC_CODE_SIZE); + diag->ADDINFO = s_strdup(addInfo); + + return(diag); +} + +/*----------------------------------------------------------------------*/ + +void +freeDiag(diag) +diagnosticRecord* diag; +{ + if (diag != NULL) + { if (diag->ADDINFO != NULL) + s_free(diag->ADDINFO); + s_free(diag); + } +} + +/*----------------------------------------------------------------------*/ + +#define END_OF_RECORD 0x1D + +char* +writeDiag(diag,buffer,len) +diagnosticRecord* diag; +char* buffer; +long* len; +/* diagnostics (as per Appendix D) have a very weird format - this changes + in SR-1 + */ +{ + char* buf = buffer; + long length; + + if (diag == NULL) /* handle unspecified optional args */ + return(buf); + + buf = writeTag(DT_DatabaseDiagnosticRecords,buf,len); + CHECK_FOR_SPACE_LEFT(0,len); + + length = 3; + if (diag->ADDINFO != NULL) + length += strlen(diag->ADDINFO); + + if (length >= 0xFFFF ) /* make sure the length is reasonable */ + { length = 0xFFFF - 1; + diag->ADDINFO[0xFFFF - 3 - 1] = '\0'; + } + + buf = writeBinaryInteger(length,2,buf,len); + + CHECK_FOR_SPACE_LEFT(1,len); + buf[0] = diag->DIAG[0]; + buf++; + + CHECK_FOR_SPACE_LEFT(1,len); + buf[0] = diag->DIAG[1]; + buf++; + + if (length > 3) + { CHECK_FOR_SPACE_LEFT(3,len); + memcpy(buf,diag->ADDINFO,(size_t)length - 3); + buf += length - 3; + } + + CHECK_FOR_SPACE_LEFT(1,len); + buf[0] = diag->SURROGATE; + buf++; + + CHECK_FOR_SPACE_LEFT(1,len); + buf[0] = END_OF_RECORD; + buf++; + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readDiag(diag,buffer) +diagnosticRecord** diag; +char* buffer; +{ + char* buf = buffer; + diagnosticRecord* d + = (diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord)); + data_tag tag; + long len; + + buf = readTag(&tag,buf); + + buf = readBinaryInteger(&len,2,buf); + + d->DIAG[0] = buf[0]; + d->DIAG[1] = buf[1]; + d->DIAG[2] = '\0'; + + if (len > 3) + { d->ADDINFO = (char*)s_malloc((size_t)(len - 3 + 1)); + memcpy(d->ADDINFO,(char*)(buf + 2),(size_t)(len - 3)); + d->ADDINFO[len - 3] = '\0'; + } + else + d->ADDINFO = NULL; + + d->SURROGATE = buf[len - 1]; + + *diag = d; + + return(buf + len + 1); +} + +/*----------------------------------------------------------------------*/ + +#define continueBit 0x80 +#define dataMask 0x7F +#define dataBits 7 + +char* +writeCompressedInteger(num,buf,len) +unsigned long num; +char* buf; +long* len; +/* write a binary integer in the format described on p. 40. + this might be sped up +*/ +{ + char byte; + long i; + unsigned long size; + + size = writtenCompressedIntSize(num); + CHECK_FOR_SPACE_LEFT(size,len); + + for (i = size - 1; i >= 0; i--) + { byte = num & dataMask; + if (i != (size-1)) /* turn on continue bit */ + byte = (char)(byte | continueBit); + buf[i] = byte; + num = num >> dataBits; /* don't and here */ + } + + return(buf + size); +} + +/*----------------------------------------------------------------------*/ + +char* +readCompressedInteger(num,buf) +unsigned long *num; +char* buf; +/* read a binary integer in the format described on p. 40. + this might be sped up +*/ +{ + long i = 0; + unsigned char byte; + + *num = 0; + + do + { byte = buf[i++]; + *num = *num << dataBits; + *num += (byte & dataMask); + } + while (byte & continueBit); + + return(buf + i); +} + +/*----------------------------------------------------------------------*/ + +#define pad 128 /* high bit is set */ + +char* +writeCompressedIntWithPadding(num,size,buffer,len) +unsigned long num; +unsigned long size; +char* buffer; +long* len; +/* Like writeCompressedInteger, except writes padding (128) to make + sure that size bytes are used. This can be read correctly by + readCompressedInteger() +*/ +{ + char* buf = buffer; + unsigned long needed,padding; + long i; + + CHECK_FOR_SPACE_LEFT(size,len); + + needed = writtenCompressedIntSize(num); + padding = size - needed; + i = padding - 1; + + for (i = padding - 1;i >= 0;i--) + { buf[i] = pad; + } + + buf = writeCompressedInteger(num,buf + padding,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenCompressedIntSize(num) +unsigned long num; +/* return the number of bytes needed to represnet the value num in + compressed format. curently limited to 4 bytes + */ +{ + if (num < CompressedInt1Byte) + return(1); + else if (num < CompressedInt2Byte) + return(2); + else if (num < CompressedInt3Byte) + return(3); + else + return(4); +} + +/*----------------------------------------------------------------------*/ + +char* +writeTag(tag,buf,len) +data_tag tag; +char* buf; +long* len; +/* write out a data tag */ +{ + return(writeCompressedInteger(tag,buf,len)); +} + +/*----------------------------------------------------------------------*/ + +char* +readTag(tag,buf) +data_tag* tag; +char* buf; +/* read a data tag */ +{ + return(readCompressedInteger(tag,buf)); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenTagSize(tag) +data_tag tag; +{ + return(writtenCompressedIntSize(tag)); +} + +/*----------------------------------------------------------------------*/ + +data_tag +peekTag(buf) +char* buf; +/* read a data tag without advancing the buffer */ +{ + data_tag tag; + readTag(&tag,buf); + return(tag); +} + +/*----------------------------------------------------------------------*/ + +any* +makeAny(size,data) +unsigned long size; +char* data; +{ + any* a = (any*)s_malloc((size_t)sizeof(any)); + a->size = size; + a->bytes = data; + return(a); +} + +/*----------------------------------------------------------------------*/ + +void +freeAny(a) +any* a; +/* destroy an any and its associated data. Assumes a->bytes was + allocated using the s_malloc family of libraries + */ +{ + if (a != NULL) + { if (a->bytes != NULL) + s_free(a->bytes); + s_free(a); + } +} + +/*----------------------------------------------------------------------*/ + +any* +duplicateAny(a) +any* a; +{ + any* copy = NULL; + + if (a == NULL) + return(NULL); + + copy = (any*)s_malloc((size_t)sizeof(any)); + copy->size = a->size; + if (a->bytes == NULL) + copy->bytes = NULL; + else + { copy->bytes = (char*)s_malloc((size_t)copy->size); + memcpy(copy->bytes,a->bytes,(size_t)copy->size); + } + return(copy); +} + +/*----------------------------------------------------------------------*/ + +char* +writeAny(a,tag,buffer,len) +any* a; +data_tag tag; +char* buffer; +long* len; +/* write an any + tag and size info */ +{ + char* buf = buffer; + + if (a == NULL) /* handle unspecified optional args */ + return(buf); + + /* write the tags */ + buf = writeTag(tag,buf,len); + buf = writeCompressedInteger(a->size,buf,len); + + /* write the bytes */ + CHECK_FOR_SPACE_LEFT(a->size,len); + memcpy(buf,a->bytes,(size_t)a->size); + + return(buf+a->size); +} + +/*----------------------------------------------------------------------*/ + + +char *readAny(anAny,buffer) +any** anAny; +char* buffer; +/* read an any + tag and size info */ +{ + char *buf; + any* a; + data_tag tag; + + + +a=(any*)s_malloc((size_t)sizeof(any)); + + buf=buffer; + + buf = readTag(&tag,buf); + + buf = readCompressedInteger(&a->size,buf); + + /* now simply copy the bytes */ + a->bytes = (char*)s_malloc((size_t)a->size); + memcpy(a->bytes,buf,(size_t)a->size); + *anAny = a; + + return(buf+a->size); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenAnySize(tag,a) +data_tag tag; +any* a; +{ + unsigned long size; + + if (a == NULL) + return(0); + + size = writtenTagSize(tag); + size += writtenCompressedIntSize(a->size); + size += a->size; + return(size); +} + +/*----------------------------------------------------------------------*/ + +any* +stringToAny(s) +char* s; +{ + any* a = NULL; + + if (s == NULL) + return(NULL); + + a = (any*)s_malloc((size_t)sizeof(any)); + a->size = strlen(s); + a->bytes = (char*)s_malloc((size_t)a->size); + memcpy(a->bytes,s,(size_t)a->size); + return(a); +} + +/*----------------------------------------------------------------------*/ + +char* +anyToString(a) +any* a; +{ + char* s = NULL; + + if (a == NULL) + return(NULL); + + s = s_malloc((size_t)(a->size + 1)); + memcpy(s,a->bytes,(size_t)a->size); + s[a->size] = '\0'; + return(s); +} + +/*----------------------------------------------------------------------*/ + +char* +writeString(s,tag,buffer,len) +char* s; +data_tag tag; +char* buffer; +long* len; +/* Write a C style string. The terminating null is not written. + This function is not part of the Z39.50 spec. It is provided + for the convienience of those wishing to pass C strings in + the place of an any. + */ +{ + char* buf = buffer; + any* data = NULL; + if (s == NULL) + return(buffer); /* handle unused optional item before making an any */ + data = (any*)s_malloc((size_t)sizeof(any)); + data->size = strlen(s); + data->bytes = s; /* save a copy here by not using stringToAny() */ + buf = writeAny(data,tag,buf,len); + s_free(data); /* don't use freeAny() since it will free s too */ + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readString(s ,buffer) +char** s ; +char* buffer; +/* Read an any and convert it into a C style string. + This function is not part of the Z39.50 spec. It is provided + for the convienience of those wishing to pass C strings in + the place of an any. + */ +{ + any* data = NULL; + char* buf = readAny(&data,buffer); + *s = anyToString(data); + freeAny(data); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenStringSize(tag,s) +data_tag tag; +char* s; +{ + unsigned long size; + + if (s == NULL) + return(0); + + size = writtenTagSize(tag); + size += writtenCompressedIntSize(size); + size += strlen(s); + return(size); +} + +/*----------------------------------------------------------------------*/ + +any* +longToAny(num) +long num; +/* a convienience function */ +{ + char s[40]; + + sprintf(s,"%ld",num); + + return(stringToAny(s)); +} + +/*----------------------------------------------------------------------*/ + +long +anyToLong(a) +any* a; +/* a convienience function */ +{ + long num; + char* str = NULL; + str = anyToString(a); + sscanf(str,"%ld",&num); /* could check the result and return + an error */ + s_free(str); + return(num); +} + +/*----------------------------------------------------------------------*/ + +#define bitsPerByte 8 + +bit_map* +makeBitMap(unsigned long numBits, ...) +/* construct and return a bitmap with numBits elements */ +{ + va_list ap; + long i,j; + bit_map* bm = NULL; + + va_start(ap,numBits); + + bm = (bit_map*)s_malloc((size_t)sizeof(bit_map)); + bm->size = (unsigned long)ceil((double)numBits / bitsPerByte); + bm->bytes = (char*)s_malloc((size_t)bm->size); + + /* fill up the bits */ + for (i = 0; i < bm->size; i++) /* iterate over bytes */ + { char byte = 0; + for (j = 0; j < bitsPerByte; j++) /* iterate over bits */ + { if ((i * bitsPerByte + j) < numBits) + { boolean bit = false; + bit = (boolean)va_arg(ap,boolean); + if (bit) + { byte = byte | (1 << (bitsPerByte - j - 1)); + } + } + } + bm->bytes[i] = byte; + } + + va_end(ap); + return(bm); +} + + +/*----------------------------------------------------------------------*/ + +void +freeBitMap(bm) +bit_map* bm; +/* destroy a bit map created by makeBitMap() */ +{ + s_free(bm->bytes); + s_free(bm); +} + +/*----------------------------------------------------------------------*/ + +/* use this routine to interpret a bit map. pos specifies the bit + number. bit 0 is the Leftmost bit of the first byte. + Could do bounds checking. + */ + +boolean +bitAtPos(pos,bm) +long pos; +bit_map* bm; +{ + if (pos > bm->size*bitsPerByte) + return false; + else + return((bm->bytes[(pos / bitsPerByte)] & + (0x80>>(pos % bitsPerByte))) ? + true : false); +} + +/*----------------------------------------------------------------------*/ + +char* +writeBitMap(bm,tag,buffer,len) +bit_map* bm; +data_tag tag; +char* buffer; +long* len; +/* write a bitmap + type and size info */ +{ + return(writeAny((any*)bm,tag,buffer,len)); +} + +/*----------------------------------------------------------------------*/ + +char* +readBitMap(bm,buffer) +bit_map** bm; +char* buffer; +/* read a bitmap + type and size info */ +{ + char *c; + + + +c=readAny((any**)bm,buffer); + + return(c); +} + +/*----------------------------------------------------------------------*/ + +char* +writeByte(byte,buf,len) +unsigned long byte; +char* buf; +long* len; +{ + CHECK_FOR_SPACE_LEFT(1,len); + buf[0] = byte & 0xFF; /* we really only want the first byte */ + return(buf + 1); +} + +/*----------------------------------------------------------------------*/ + +char* +readByte(byte,buf) +unsigned char* byte; +char* buf; +{ + *byte = buf[0]; + return(buf + 1); +} + +/*----------------------------------------------------------------------*/ + +char* +writeBoolean(flag,buf,len) +boolean flag; +char* buf; +long* len; +{ + return(writeByte(flag,buf,len)); +} + +/*----------------------------------------------------------------------*/ + +char* +readBoolean(flag,buffer) +boolean* flag; +char* buffer; +{ + unsigned char byte; + char* buf = readByte(&byte,buffer); + *flag = (byte == true) ? true : false; + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +writePDUType(pduType,buf,len) +pdu_type pduType; +char* buf; +long* len; +/* PDUType is a single byte */ +{ + return(writeBinaryInteger((long)pduType,(unsigned long)1,buf,len)); +} + +/*----------------------------------------------------------------------*/ + +char* +readPDUType(pduType,buf) +pdu_type* pduType; +char* buf; +/* PDUType is a single byte */ +{ + return(readBinaryInteger((long*)pduType,(unsigned long)1,buf)); +} + +/*----------------------------------------------------------------------*/ + +pdu_type +peekPDUType(buf) +char* buf; +/* read the next pdu without advancing the buffer, Note that this + function is to be used on a buffer that is known to contain an + APDU. The pdu_type is written HEADER_LEN bytes into the buffer + */ +{ + pdu_type pdu; + readPDUType(&pdu,buf + HEADER_LEN); + return(pdu); +} + +/*----------------------------------------------------------------------*/ + +#define BINARY_INTEGER_BYTES sizeof(long) /* the number of bytes used by + a "binary integer" */ +char* +writeBinaryInteger(num,size,buf,len) +long num; +unsigned long size; +char* buf; +long* len; +/* write out first size bytes of num - no type info + XXX should this take unsigned longs instead ??? */ +{ + long i; + char byte; + + if (size < 1 || size > BINARY_INTEGER_BYTES) + return(NULL); /* error */ + + CHECK_FOR_SPACE_LEFT(size,len); + + for (i = size - 1; i >= 0; i--) + { byte = (char)(num & 255); + buf[i] = byte; + num = num >> bitsPerByte; /* don't and here */ + } + + return(buf + size); +} + +/*----------------------------------------------------------------------*/ + +char* +readBinaryInteger(num,size,buf) +long* num; +unsigned long size; +char* buf; +/* read in first size bytes of num - no type info + XXX this should take unsigned longs instead !!! */ +{ + long i; + unsigned char byte; + + if (size < 1 || size > BINARY_INTEGER_BYTES) + return(buf); /* error */ + *num = 0; + + for (i = 0; i < size; i++) + { byte = buf[i]; + *num = *num << bitsPerByte; + *num += byte; + } + + return(buf + size); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenCompressedBinIntSize(num) +long num; +/* return the number of bytes needed to represent the value num. + currently limited to max of 4 bytes + Only compresses for positive nums - negatives get whole 4 bytes + */ +{ + if (num < 0L) + return(4); + else if (num < 256L) /* 2**8 */ + return(1); + else if (num < 65536L) /* 2**16 */ + return(2); + else if (num < 16777216L) /* 2**24 */ + return(3); + else + return(4); +} + +/*----------------------------------------------------------------------*/ + +char* +writeNum(num,tag,buffer,len) +long num; +data_tag tag; +char* buffer; +long* len; +/* write a binary integer + size and tag info */ +{ + char* buf = buffer; + long size = writtenCompressedBinIntSize(num); + + if (num == UNUSED) + return(buffer); + + buf = writeTag(tag,buf,len); + buf = writeCompressedInteger(size,buf,len); + buf = writeBinaryInteger(num,(unsigned long)size,buf,len); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readNum(num,buffer) +long* num; +char* buffer; +/* read a binary integer + size and tag info */ +{ + char* buf = buffer; + data_tag tag; + unsigned long size; + unsigned long val; + + buf = readTag(&tag,buf); + buf = readCompressedInteger(&val,buf); + size = (unsigned long)val; + buf = readBinaryInteger(num,size,buf); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +unsigned long +writtenNumSize(tag,num) +data_tag tag; +long num; +{ + long dataSize = writtenCompressedBinIntSize(num); + long size; + + size = writtenTagSize(tag); /* space for the tag */ + size += writtenCompressedIntSize(dataSize); /* space for the size */ + size += dataSize; /* space for the data */ + + return(size); +} + +/*----------------------------------------------------------------------*/ + +typedef void (voidfunc)(); + +void +doList(list,func) +void** list; +voidfunc *func; +/* call func on each element of the NULL terminated list of pointers */ +{ + register long i; + register void* ptr = NULL; + if (list == NULL) + return; + for (i = 0,ptr = list[i]; ptr != NULL; ptr = list[++i]) + (*func)(ptr); +} + +/*----------------------------------------------------------------------*/ + +char* +writeProtocolVersion(buf,len) +char* buf; +long* len; +/* write a bitmap describing the protocols available */ +{ + static bit_map* version = NULL; + + if (version == NULL) + { version = makeBitMap((unsigned long)1,true); /* version 1! */ + } + + return(writeBitMap(version,DT_ProtocolVersion,buf,len)); +} + +/*----------------------------------------------------------------------*/ + +char* +defaultImplementationID() +{ + static char ImplementationID[] = "TMC"; + return(ImplementationID); +} + +/*----------------------------------------------------------------------*/ + +char* +defaultImplementationName() +{ + static char ImplementationName[] = "Thinking Machines Corporation Z39.50"; + return(ImplementationName); +} + +/*----------------------------------------------------------------------*/ + +char* +defaultImplementationVersion() +{ + static char ImplementationVersion[] = "2.0A"; + return(ImplementationVersion); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from ZType1.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 4.11.90 HWM - generalized conditional includes (see c-dialect.h) +*/ +/*----------------------------------------------------------------------*/ + +query_term* +makeAttributeTerm(use, + relation, + position, + structure, + truncation, + completeness, + term) +char* use; +char* relation; +char* position; +char* structure; +char* truncation; +char* completeness; +any* term; +{ + query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term)); + + qt->TermType = TT_Attribute; + + /* copy in the attributes */ + strncpy(qt->Use,use,ATTRIBUTE_SIZE); + strncpy(qt->Relation,relation,ATTRIBUTE_SIZE); + strncpy(qt->Position,position,ATTRIBUTE_SIZE); + strncpy(qt->Structure,structure,ATTRIBUTE_SIZE); + strncpy(qt->Truncation,truncation,ATTRIBUTE_SIZE); + strncpy(qt->Completeness,completeness,ATTRIBUTE_SIZE); + + qt->Term = duplicateAny(term); + + qt->ResultSetID = NULL; + + return(qt); +} + +/*----------------------------------------------------------------------*/ + +query_term* +makeResultSetTerm(resultSet) +any* resultSet; +{ + query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term)); + + qt->TermType = TT_ResultSetID; + + qt->ResultSetID = duplicateAny(resultSet); + + qt->Term = NULL; + + return(qt); +} + +/*----------------------------------------------------------------------*/ + +query_term* +makeOperatorTerm(operatorCode) +char* operatorCode; +{ + query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term)); + + qt->TermType = TT_Operator; + + strncpy(qt->Operator,operatorCode,OPERATOR_SIZE); + + qt->Term = NULL; + qt->ResultSetID = NULL; + + return(qt); +} + +/*----------------------------------------------------------------------*/ + +void +freeTerm(qt) +query_term* qt; +{ + switch (qt->TermType) + { case TT_Attribute: + freeAny(qt->Term); + break; + case TT_ResultSetID: + freeAny(qt->ResultSetID); + break; + case TT_Operator: + /* do nothing */ + break; + default: + panic("Implementation error: Unknown term type %ld", + qt->TermType); + break; + } + s_free(qt); +} + +/*----------------------------------------------------------------------*/ + +#define ATTRIBUTE_LIST_SIZE ATTRIBUTE_SIZE * 6 +#define AT_DELIMITER " " + +char* +writeQueryTerm(qt,buffer,len) +query_term* qt; +char* buffer; +long* len; +{ + char* buf = buffer; + char attributes[ATTRIBUTE_LIST_SIZE]; + + switch (qt->TermType) + { case TT_Attribute: + strncpy(attributes,qt->Use,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,qt->Relation,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,qt->Position,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,qt->Structure,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,qt->Truncation,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE); + s_strncat(attributes,qt->Completeness,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); + buf = writeString(attributes,DT_AttributeList,buf,len); + buf = writeAny(qt->Term,DT_Term,buf,len); + break; + case TT_ResultSetID: + buf = writeAny(qt->ResultSetID,DT_ResultSetID,buf,len); + break; + case TT_Operator: + buf = writeString(qt->Operator,DT_Operator,buf,len); + break; + default: + panic("Implementation error: Unknown term type %ld", + qt->TermType); + break; + } + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readQueryTerm(qt,buffer) +query_term** qt; +char* buffer; +{ + char* buf = buffer; + char *attributeList = NULL; + char* operator = NULL; + any* term; + char* use = NULL; + char* relation = NULL; + char* position = NULL; + char* structure = NULL; + char* truncation = NULL; + char* completeness; + any* resultSetID = NULL; + data_tag tag; + + + tag = peekTag(buffer); + + switch(tag) + { case DT_AttributeList: + buf = readString(&attributeList,buf); + buf = readAny(&term,buf); + use = strtok(attributeList,AT_DELIMITER); + relation = strtok(NULL,AT_DELIMITER); + position = strtok(NULL,AT_DELIMITER); + structure = strtok(NULL,AT_DELIMITER); + truncation = strtok(NULL,AT_DELIMITER); + completeness = strtok(NULL,AT_DELIMITER); + *qt = makeAttributeTerm(use,relation,position,structure, + truncation,completeness,term); + s_free(attributeList); + freeAny(term); + break; + case DT_ResultSetID: + buf = readAny(&resultSetID,buf); + *qt = makeResultSetTerm(resultSetID); + freeAny(resultSetID); + break; + case DT_Operator: + buf = readString(&operator,buf); + *qt = makeOperatorTerm(operator); + s_free(operator); + break; + default: + REPORT_READ_ERROR(buf); + break; + } + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +static unsigned long getQueryTermSize _AP((query_term* qt)); + +static unsigned long +getQueryTermSize(qt) +query_term* qt; +/* figure out how many bytes it will take to write this query */ +{ + unsigned long size; + static char attributes[] = "11 22 33 44 55 66"; /* we just need this to + calculate its written + size */ + + switch (qt->TermType) + { case TT_Attribute: + size = writtenStringSize(DT_AttributeList,attributes); + size += writtenAnySize(DT_Term,qt->Term); + break; + case TT_ResultSetID: + size = writtenAnySize(DT_ResultSetID,qt->ResultSetID); + break; + case TT_Operator: + size = writtenStringSize(DT_Operator,qt->Operator); + break; + default: + panic("Implementation error: Unknown term type %ld", + qt->TermType); + break; + } + + return(size); +} + +/*----------------------------------------------------------------------*/ + +/* A query is simply a null terminated list of query terms. For + transmission, a query is written into an any which is sent as + the user information field. */ + +any* +writeQuery(terms) +query_term** terms; +{ + any* info = NULL; + char* writePos = NULL; + char* data = NULL; + unsigned long size = 0; + long remaining = 0; + long i; + query_term* qt = NULL; + + if (terms == NULL) + return(NULL); + + /* calculate the size of write buffer */ + for (i = 0,qt = terms[i]; qt != NULL; qt = terms[++i]) + size += getQueryTermSize(qt); + + data = (char*)s_malloc((size_t)size); + + /* write the terms */ + writePos = data; + remaining = size; + for (i = 0,qt = terms[i]; qt != NULL; qt = terms[++i]) + writePos = writeQueryTerm(qt,writePos,&remaining); + + info = makeAny(size,data); + + return(info); +} + +/*----------------------------------------------------------------------*/ + +query_term** +readQuery(info) +any *info; +{ + char* readPos = info->bytes; + query_term** terms = NULL; + query_term* qt = NULL; + long numTerms = 0L; +char tmp[100]; + +sprintf(tmp,"readquery: bytes: %ld",info->size); +log_write(tmp); + + while (readPos < info->bytes + info->size) + { readPos = readQueryTerm(&qt,readPos); + + if (terms == NULL) + { terms = (query_term**)s_malloc((size_t)(sizeof(query_term*)*2)); + } + else + { terms = + (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*)*(numTerms+2))); + } +if(qt==NULL) + log_write("qt = null"); + terms[numTerms++] = qt; + terms[numTerms] = NULL; + } + + return(terms); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from panic.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + Morris@think.com +*/ + +/* panic is an error system interface. On the Mac, it will pop + * up a little window to explain the problem. + * On a unix box, it will print out the error and call perror() + */ + +/*----------------------------------------------------------------------*/ + +static void exitAction _AP((long error)); + +static void +exitAction(error) +long error; +{ + long i; + for (i = 0; i < 100000; i++) + ; + exit(0); +} + +/*----------------------------------------------------------------------*/ + +#define PANIC_HEADER "Fatal Error: " + +void +panic(char *format, ...) +{ + va_list ap; /* the variable arguments */ + + fprintf(stderr,PANIC_HEADER); + va_start(ap, format); /* init ap */ + vfprintf(stderr,format,ap); /* print the contents */ + va_end(ap); /* free ap */ + fflush(stderr); + + exitAction(0); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from cutil.c -- FM +** +**----------------------------------------------------------------------*/ +/* Wide AREA INFORMATION SERVER SOFTWARE + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 4.11.90 HWM - generalized conditional includes (see c-dialect.h) +*/ + +#include <varargs.h> + + +/*----------------------------------------------------------------------*/ + +void +fs_checkPtr(ptr) +void* ptr; +/* If the ptr is NULL, give an error */ +{ + if (ptr == NULL) + panic("checkPtr found a NULL pointer"); +} + +/*----------------------------------------------------------------------*/ + +void* +fs_malloc(size) +size_t size; +/* does safety checks and optional accounting */ +{ + register void* ptr = NULL; + + ptr = (void*)calloc((size_t)size,(size_t)1); + s_checkPtr(ptr); + + return(ptr); +} + +/*----------------------------------------------------------------------*/ + +void* +fs_realloc(ptr,size) +void* ptr; +size_t size; +/* does safety checks and optional accounting + note - we don't know how big ptr's memory is, so we can't ensure + that any new memory allocated is NULLed! + */ +{ + register void* nptr = NULL; + + if (ptr == NULL) /* this is really a malloc */ + return(s_malloc(size)); + + nptr = (void*)realloc(ptr,size); + s_checkPtr(ptr); + + return(nptr); +} + +/*----------------------------------------------------------------------*/ + +void +fs_free(ptr) +void* ptr; +/* does safety checks and optional accounting */ +{ + if (ptr != NULL) /* some non-ansi compilers/os's cant handle freeing null */ + { /* if we knew the size of this block of memory, we could clear it - oh well */ + free(ptr); + ptr = NULL; + } +} + +/*----------------------------------------------------------------------*/ + +char* +s_strdup(s) +char* s; + +/* return a copy of s. This is identical to the standard library routine + strdup(), except that it is safe. If s == NULL or malloc fails, + appropriate action is taken. + */ +{ + unsigned long len; + char* copy = NULL; + + if (s == NULL) /* saftey check to postpone stupid errors */ + return(NULL); + + len = strlen(s); /* length of string - terminator */ + copy = (char*)s_malloc((size_t)(sizeof(char)*(len + 1))); + strncpy(copy,s,len + 1); + return(copy); +} + +/*----------------------------------------------------------------------*/ + +char* +fs_strncat(dst,src,maxToAdd,maxTotal) +char* dst; + char* src; + size_t maxToAdd; + size_t maxTotal; + +/* like strncat, except the fourth argument limits the maximum total + length of the resulting string + */ +{ + size_t dstSize = strlen(dst); + size_t srcSize = strlen(src); + + if (dstSize + srcSize < maxTotal) /* use regular old strncat */ + return(strncat(dst,src,maxToAdd)); + else + { size_t truncateTo = maxTotal - dstSize - 1; + char saveChar = src[truncateTo]; + char* result = NULL; + src[truncateTo] = '\0'; + result = strncat(dst,src,maxToAdd); + src[truncateTo] = saveChar; + return(result); + } +} + +/*----------------------------------------------------------------------*/ + +char char_downcase(long_ch) +unsigned long long_ch; +{ + unsigned char ch = long_ch & 0xFF; /* just want one byte */ + /* when ansi is the way of the world, this can be tolower */ + return (((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' -'A') : ch); +} + +char *string_downcase(word) +char *word; +{ + long i = 0; + while(word[i] != '\0'){ + word[i] = char_downcase((unsigned long)word[i]); + i++; + } + return(word); +} + +/*----------------------------------------------------------------------*/ + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.h new file mode 100644 index 00000000000..6f492b878e4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.h @@ -0,0 +1,674 @@ +/* HTVMS_WAISUI.h +** +** Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu) +** +** 31-May-1994 FM Initial version. +*/ + +#ifndef HTVMSWAIS_H +#define HTVMSWAIS_H + +#ifndef __STDLIB_LOADED +#include <stdlib.h> +#endif /* __STDLIB_LOADED */ + +#define _AP(args) () + +void log_write _AP((char *)); + +/* +** Routines originally from Panic.h -- FM +** +**----------------------------------------------------------------------*/ + +void panic (char* format,...); + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from CUtil.h -- FM +** +**----------------------------------------------------------------------*/ + +/* types and constants */ + +#ifndef boolean +#define boolean unsigned long +#endif /* boolean */ + +#ifndef true +#define true (boolean)1L +#endif /* true */ + +#ifndef false +#define false (boolean)0L /* used to be (!true), but broke + some compilers */ +#endif /* false */ + +#ifndef TRUE +#define TRUE true +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE false +#endif /* FALSE */ + +/*----------------------------------------------------------------------*/ +/* functions */ + +/* enhanced memory handling functions - don't call them directly, use the + macros below */ +void fs_checkPtr _AP((void* ptr)); +void* fs_malloc _AP((size_t size)); +void* fs_realloc _AP((void* ptr,size_t size)); +void fs_free _AP((void* ptr)); +char* fs_strncat _AP((char* dst,char* src,size_t maxToAdd,size_t maxTotal)); + +/* macros for memory functions. call these in your program. */ +#define s_checkPtr(ptr) fs_checkPtr(ptr) +#define s_malloc(size) fs_malloc(size) +#define s_realloc(ptr,size) fs_realloc((ptr),(size)) +#define s_free(ptr) { fs_free((char*)ptr); ptr = NULL; } +#define s_strncat(dst,src,maxToAdd,maxTotal) fs_strncat((dst),(src),(maxToAdd),(maxTotal)) + +char* s_strdup _AP((char* s)); + +#define IS_DELIMITER 1 +#define NOT_DELIMITER !IS_DELIMITER + +char char_downcase _AP((unsigned long ch)); +char *string_downcase _AP((char* word)); + +/*----------------------------------------------------------------------*/ + + + +/* +** Routines originally from ZUtil.c -- FM +** +**----------------------------------------------------------------------*/ + +/* Data types / constants */ + +/* bytes to leave for the header size info */ +#define HEADER_LEN (size_t)2 + +typedef long pdu_type; + +#define initAPDU (pdu_type)20 +#define initResponseAPDU (pdu_type)21 +#define searchAPDU (pdu_type)22 +#define searchResponseAPDU (pdu_type)23 +#define presentAPDU (pdu_type)24 +#define presentResponseAPDU (pdu_type)25 +#define deteteAPDU (pdu_type)26 +#define deleteResponseAPDU (pdu_type)27 +#define accessControlAPDU (pdu_type)28 +#define accessControlResponseAPDU (pdu_type)29 +#define resourceControlAPDU (pdu_type)30 +#define resourceControlResponseAPDU (pdu_type)31 + +typedef struct any { /* an any is a non-ascii string of characters */ + unsigned long size; + char* bytes; + } any; + +typedef any bit_map; /* a bit_map is a group of packed bits */ + +typedef unsigned long data_tag; + +#define DT_PDUType (data_tag)1 +#define DT_ReferenceID (data_tag)2 +#define DT_ProtocolVersion (data_tag)3 +#define DT_Options (data_tag)4 +#define DT_PreferredMessageSize (data_tag)5 +#define DT_MaximumRecordSize (data_tag)6 +#define DT_IDAuthentication (data_tag)7 +#define DT_ImplementationID (data_tag)8 +#define DT_ImplementationName (data_tag)9 +#define DT_ImplementationVersion (data_tag)10 +#define DT_UserInformationField (data_tag)11 +#define DT_Result (data_tag)12 +#define DT_SmallSetUpperBound (data_tag)13 +#define DT_LargeSetLowerBound (data_tag)14 +#define DT_MediumSetPresentNumber (data_tag)15 +#define DT_ReplaceIndicator (data_tag)16 +#define DT_ResultSetName (data_tag)17 +#define DT_DatabaseNames (data_tag)18 +#define DT_ElementSetNames (data_tag)19 +#define DT_QueryType (data_tag)20 +#define DT_Query (data_tag)21 +#define DT_SearchStatus (data_tag)22 +#define DT_ResultCount (data_tag)23 +#define DT_NumberOfRecordsReturned (data_tag)24 +#define DT_NextResultSetPosition (data_tag)25 +#define DT_ResultSetStatus (data_tag)26 +#define DT_PresentStatus (data_tag)27 +#define DT_DatabaseDiagnosticRecords (data_tag)28 +#define DT_NumberOfRecordsRequested (data_tag)29 +#define DT_ResultSetStartPosition (data_tag)30 +#define DT_ResultSetID (data_tag)31 +#define DT_DeleteOperation (data_tag)32 +#define DT_DeleteStatus (data_tag)33 +#define DT_NumberNotDeleted (data_tag)34 +#define DT_BulkStatuses (data_tag)35 +#define DT_DeleteMSG (data_tag)36 +#define DT_SecurityChallenge (data_tag)37 +#define DT_SecurityChallengeResponse (data_tag)38 +#define DT_SuspendedFlag (data_tag)39 +#define DT_ResourceReport (data_tag)40 +#define DT_PartialResultsAvailable (data_tag)41 +#define DT_ContinueFlag (data_tag)42 +#define DT_ResultSetWanted (data_tag)43 + +#define UNUSED -1 + +/* number of bytes required to represent the following sizes in compressed + integer format + */ +#define CompressedInt1Byte 128 /* 2 ^ 7 */ +#define CompressedInt2Byte 16384 /* 2 ^ 14 */ +#define CompressedInt3Byte 2097152 /* 2 ^ 21 */ +/* others may follow ... */ + +/* types of query */ +#define QT_0 "0" /* query whose non-standard format has been agreed upon + client and server */ +/* values for InitAPDU option element */ +#define WILL_USE TRUE +#define WILL_NOT_USE FALSE +#define WILL_SUPPORT TRUE +#define WILL_NOT_SUPPORT FALSE + +/* values for InitResponseAPDU result element */ +#define ACCEPT TRUE +#define REJECT FALSE + +/* values for SearchAPDU replace indicator element */ +#define ON TRUE +#define OFF FALSE + +/* values for SearchResponseAPDU search status element */ +#define SUCCESS 0 /* intuitive huh? */ +#define FAILURE 1 + +/* values for SearchResponseAPDU result set status element */ +#define SUBSET 1 +#define INTERIM 2 +#define NONE 3 + +/* values for SearchResponseAPDU present status element */ +/* SUCCESS already defined */ +#define PARTIAL_1 1 +#define PARTIAL_2 2 +#define PARTIAL_3 3 +#define PARTIAL_4 4 +#define PS_NONE 5 /* can't use NONE since it was used by result + set status */ + +#define DIAGNOSTIC_CODE_SIZE (size_t)3 + +typedef struct diagnosticRecord + { boolean SURROGATE; + char DIAG[DIAGNOSTIC_CODE_SIZE]; + char* ADDINFO; + } diagnosticRecord; + +#define D_PermanentSystemError "S1" +#define D_TemporarySystemError "S2" +#define D_UnsupportedSearch "S3" +#define D_TermsOnlyStopWords "S5" +#define D_TooManyArgumentWords "S6" +#define D_TooManyBooleanOperators "S7" +#define D_TooManyTruncatedWords "S8" +#define D_TooMany IncompleteSubfields "S9" +#define D_TruncatedWordsTooShort "SA" +#define D_InvalidFormatForRecordNumber "SB" +#define D_TooManyCharactersInSearch "SC" +#define D_TooManyRecordsRetrieved "SD" +#define D_PresentRequestOutOfRange "SF" +#define D_SystemErrorInPresentRecords "SG" +#define D_RecordNotAuthorizedToBeSent "SH" +#define D_RecordExceedsPrefMessageSize "SI" +#define D_RecordExceedsMaxRecordSize "SJ" +#define D_ResultSetNotSuppAsSearchTerm "SK" +#define D_OnlyOneRsltSetAsSrchTermSupp "SL" +#define D_OnlyANDingOfASnglRsltSetSupp "SM" +#define D_RsltSetExistsNoReplace "SN" +#define D_ResultSetNamingNotSupported "SO" +#define D_CombinationDatabasesNotSupp "SP" +#define D_ElementSetNamesNotSupported "SQ" +#define D_ElementSetNameNotValid "SR" +#define D_OnlyASingleElmntSetNameSupp "SS" +#define D_ResultSetDeletedByTarget "ST" +#define D_ResultSetIsInUse "SU" +#define D_DatabasesIsLocked "SV" +#define D_TerminatedByNoContinueResp "SW" +#define D_ResultSetDoesNotExist "SX" +#define D_ResExNoResultsAvailable "SY" +#define D_ResExUnpredictableResults "SZ" +#define D_ResExValidSubsetOfResults "T1" +#define D_AccessControlFailure "T2" +#define D_SecurityNotIssuedReqTerm "T3" +#define D_SecurityNotBeIssuedRecNotInc "T4" + +/*----------------------------------------------------------------------*/ + +/* for internal error handling */ + +extern char* readErrorPosition; /* pos where buf stoped making sense */ + +/* the following are macros so that they can return OUT of the function + which calls them + */ + +#define RETURN_ON_NULL(var) \ + if (var == NULL) \ + return(NULL); /* jump out of caller */ + +#define REPORT_READ_ERROR(pos) \ + { readErrorPosition = (pos); \ + return(NULL); /* jump out of caller */ \ + } + +#define CHECK_FOR_SPACE_LEFT(spaceNeeded,spaceLeft) \ + { if (*spaceLeft >= spaceNeeded) \ + (*spaceLeft) -= spaceNeeded; \ + else \ + { *spaceLeft = 0; \ + return(NULL); /* jump out of the caller */ \ + } \ + } + +/*----------------------------------------------------------------------*/ + +diagnosticRecord* makeDiag _AP((boolean surrogate,char* code,char* addInfo)); +void freeDiag _AP((diagnosticRecord* diag)); +char* writeDiag _AP((diagnosticRecord* diag,char* buffer,long* len)); +char* readDiag _AP((diagnosticRecord** diag,char* buffer)); + +char* writeCompressedInteger _AP((unsigned long num,char* buf,long* len)); +char* readCompressedInteger _AP((unsigned long *num,char* buf)); +char* writeCompressedIntWithPadding _AP((unsigned long num,unsigned long size, + char* buffer,long* len)); +unsigned long writtenCompressedIntSize _AP((unsigned long num)); + +char* writeTag _AP((data_tag tag,char* buf,long* len)); +char* readTag _AP((data_tag* tag,char* buf)); +data_tag peekTag _AP((char* buf)); +unsigned long writtenTagSize _AP((data_tag tag)); + +any* makeAny _AP((unsigned long size,char* data)); +void freeAny _AP((any* a)); +any* duplicateAny _AP((any* a)); +char* writeAny _AP((any* a,data_tag tag,char* buffer,long* len)); +char* readAny _AP((any** anAny,char* buffer)); +unsigned long writtenAnySize _AP((data_tag tag,any* a)); + +any* stringToAny _AP((char* s)); +char* anyToString _AP((any* a)); +unsigned long writtenStringSize _AP((data_tag tag,char* s)); + +any* longToAny _AP((long Num)); +long anyToLong _AP((any* a)); + +char* writeString _AP((char* s,data_tag tag,char* buffer,long* len)); +char* readString _AP((char** s,char* buffer)); + +bit_map* makeBitMap (unsigned long numBits,...); + +void freeBitMap _AP((bit_map* bm)); +boolean bitAtPos _AP((long pos,bit_map* bm)); +char* writeBitMap _AP((bit_map* bm,data_tag tag,char* buffer,long* len)); +char* readBitMap _AP((bit_map** bm,char* buffer)); + +char* writeByte _AP((unsigned long byte,char* buf,long* len)); +char* readByte _AP((unsigned char* byte,char* buf)); + +char* writeBoolean _AP((boolean flag,char* buf,long* len)); +char* readBoolean _AP((boolean* flag,char* buf)); + +char* writePDUType _AP((pdu_type pduType,char* buf,long* len)); +char* readPDUType _AP((pdu_type* pduType,char* buf)); +pdu_type peekPDUType _AP((char* buf)); + +char* writeBinaryInteger _AP((long num,unsigned long size, + char* buf,long* len)); +char* readBinaryInteger _AP((long* num,unsigned long size,char* buf)); +unsigned long writtenCompressedBinIntSize _AP((long num)); + +char* writeNum _AP((long num,data_tag tag,char* buffer,long* len)); +char* readNum _AP((long* num,char* buffer)); +unsigned long writtenNumSize _AP((data_tag tag,long num)); + +void doList _AP((void** list,void (*func)())); + +char* writeProtocolVersion _AP((char* buf,long* len)); +char* defaultImplementationID _AP((void)); +char* defaultImplementationName _AP((void)); +char* defaultImplementationVersion _AP((void)); + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from ZType1.c -- FM +** +**----------------------------------------------------------------------*/ + +/* This file implements the type 1 query defined in appendices B & C + of the SR 1 spec. + */ + +/*----------------------------------------------------------------------*/ +/* types and constants */ + +/* new data tags */ +#define DT_AttributeList (data_tag)44 +#define DT_Term (data_tag)45 +#define DT_Operator (data_tag)46 + +#define QT_BooleanQuery "1" /* standard boolean query */ + +/* general attribute code - use in place of any attribute */ +#define IGNORE "ig" + +/* use value codes */ +#define UV_ISBN "ub" +#define CORPORATE_NAME "uc" +#define ISSN "us" +#define PERSONAL_NAME "up" +#define SUBJECT "uj" +#define TITLE "ut" +#define GEOGRAPHIC_NAME "ug" +#define CODEN "ud" +#define SUBJECT_SUBDIVISION "ue" +#define SERIES_TITLE "uf" +#define MICROFORM_GENERATION "uh" +#define PLACE_OF_PUBLICATION "ui" +#define NUC_CODE "uk" +#define LANGUAGE "ul" +#define COMBINATION_OF_USE_VALUES "um" +#define SYSTEM_CONTROL_NUMBER "un" +#define DATE "uo" +#define LC_CONTROL_NUMBER "ur" +#define MUSIC_PUBLISHERS_NUMBER "uu" +#define GOVERNMENT_DOCUMENTS_NUMBER "uv" +#define SUBJECT_CLASSIFICATION "uw" +#define RECORD_TYPE "uy" + +/* relation value codes */ +#define EQUAL "re" +#define GREATER_THAN "rg" +#define GREATER_THAN_OR_EQUAL "ro" +#define LESS_THAN "rl" +#define LESS_THAN_OR_EQUAL "rp" +#define NOT_EQUAL "rn" + +/* position value codes */ +#define FIRST_IN_FIELD "pf" +#define FIRST_IN_SUBFIELD "ps" +#define FIRST_IN_A_SUBFIELD "pa" +#define FIRST_IN_NOT_A_SUBFIELD "pt" +#define ANY_POSITION_IN_FIELD "py" + +/* structure value codes */ +#define PHRASE "sp" +#define WORD "sw" +#define KEY "sk" +#define WORD_LIST "sl" + +/* truncation value codes */ +#define NO_TRUNCATION "tn" +#define RIGHT_TRUNCATION "tr" +#define PROC_NUM_INCLUDED_IN_SEARCH_ARG "ti" + +/* completeness value codes */ +#define INCOMPLETE_SUBFIELD "ci" +#define COMPLETE_SUBFIELD "cs" +#define COMPLETEFIELD "cf" + +/* operator codes */ +#define AND "a" +#define OR "o" +#define AND_NOT "n" + +/* term types */ +#define TT_Attribute 1 +#define TT_ResultSetID 2 +#define TT_Operator 3 + +#define ATTRIBUTE_SIZE 3 +#define OPERATOR_SIZE 2 + +typedef struct query_term { + /* type */ + long TermType; + /* for term */ + char Use[ATTRIBUTE_SIZE]; + char Relation[ATTRIBUTE_SIZE]; + char Position[ATTRIBUTE_SIZE]; + char Structure[ATTRIBUTE_SIZE]; + char Truncation[ATTRIBUTE_SIZE]; + char Completeness[ATTRIBUTE_SIZE]; + any* Term; + /* for result set */ + any* ResultSetID; + /* for operator */ + char Operator[OPERATOR_SIZE]; +} query_term; + +/*----------------------------------------------------------------------*/ +/* functions */ + +query_term* makeAttributeTerm _AP(( + char* use,char* relation,char* position,char* structure, + char* truncation,char* completeness,any* term)); +query_term* makeResultSetTerm _AP((any* resultSet)); +query_term* makeOperatorTerm _AP((char* operatorCode)); +void freeTerm _AP((query_term* qt)); +char* writeQueryTerm _AP((query_term* qt,char* buffer,long* len)); +char* readQueryTerm _AP((query_term** qt,char* buffer)); +any* writeQuery _AP((query_term** terms)); +query_term** readQuery _AP((any* info)); + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from UI.c -- FM +** +**----------------------------------------------------------------------*/ + +char * +generate_search_apdu _AP((char* buff, /* buffer to hold the apdu */ + long *buff_len, /* number of bytes written to the buffer */ + char *seed_words, /* string of the seed words */ + char *database_name, + DocObj** docobjs, + long maxDocsRetrieved + )); + +char * +generate_retrieval_apdu _AP((char *buff, + long *buff_len, + any *docID, + long chunk_type, + long start_line, long end_line, + char *type, + char *database_name)); + + +long +interpret_message _AP((char *request_message, + long request_length, + char *response_message, + long response_buffer_length, /* length of the buffer (modified)*/ + FILE *connection, + boolean verbose)); + + +void +display_text_record_completely _AP((WAISDocumentText *record, + boolean quote_string_quotes)); + +char *trim_junk _AP((char *headline)); + + + +/* +** Routines originally from ZProt.c -- FM +** +**----------------------------------------------------------------------*/ + +/* APDU types */ + +typedef struct InitAPDU { + pdu_type PDUType; + boolean willSearch,willPresent,willDelete; + boolean supportAccessControl,supportResourceControl; + long PreferredMessageSize; + long MaximumRecordSize; + char* IDAuthentication; + char* ImplementationID; + char* ImplementationName; + char* ImplementationVersion; + any* ReferenceID; + void* UserInformationField; + } InitAPDU; + +typedef struct InitResponseAPDU { + pdu_type PDUType; + boolean Result; + boolean willSearch,willPresent,willDelete; + boolean supportAccessControl,supportResourceControl; + long PreferredMessageSize; + long MaximumRecordSize; + char* IDAuthentication; + char* ImplementationID; + char* ImplementationName; + char* ImplementationVersion; + any* ReferenceID; + void* UserInformationField; + } InitResponseAPDU; + +typedef struct SearchAPDU { + pdu_type PDUType; + long SmallSetUpperBound; + long LargeSetLowerBound; + long MediumSetPresentNumber; + boolean ReplaceIndicator; + char* ResultSetName; + char** DatabaseNames; + char* QueryType; + char** ElementSetNames; + any* ReferenceID; + void* Query; + } SearchAPDU; + +typedef struct SearchResponseAPDU { + pdu_type PDUType; + long SearchStatus; + long ResultCount; + long NumberOfRecordsReturned; + long NextResultSetPosition; + long ResultSetStatus; + long PresentStatus; + any* ReferenceID; + void* DatabaseDiagnosticRecords; + } SearchResponseAPDU; + +typedef struct PresentAPDU { + pdu_type PDUType; + long NumberOfRecordsRequested; + long ResultSetStartPosition; + char* ResultSetID; + char* ElementSetNames; + any* ReferenceID; + void* PresentInfo; + } PresentAPDU; + +typedef struct PresentResponseAPDU { + pdu_type PDUType; + boolean PresentStatus; + long NumberOfRecordsReturned; + long NextResultSetPosition; + any* ReferenceID; + void* DatabaseDiagnosticRecords; + } PresentResponseAPDU; + +/*----------------------------------------------------------------------*/ +/* Functions */ + +InitAPDU* makeInitAPDU _AP((boolean search,boolean present,boolean deleteIt, + boolean accessControl,boolean resourceControl, + long prefMsgSize,long maxMsgSize, + char* auth,char* id,char* name, char* version, + any* refID,void* userInfo)); +void freeInitAPDU _AP((InitAPDU* init)); +char* writeInitAPDU _AP((InitAPDU* init,char* buffer,long* len)); +char* readInitAPDU _AP((InitAPDU** init,char* buffer)); + +InitResponseAPDU* makeInitResponseAPDU _AP((boolean result, + boolean search,boolean present,boolean deleteIt, + boolean accessControl,boolean resourceControl, + long prefMsgSize,long maxMsgSize, + char* auth,char* id,char* name, char* version, + any* refID,void* userInfo)); +void freeInitResponseAPDU _AP((InitResponseAPDU* init)); +char* writeInitResponseAPDU _AP((InitResponseAPDU* init,char* buffer,long* len)); +char* readInitResponseAPDU _AP((InitResponseAPDU** init,char* buffer)); +InitResponseAPDU* replyToInitAPDU _AP((InitAPDU* init,boolean result,void* userInfo)); + +SearchAPDU* makeSearchAPDU _AP((long small,long large, long medium, + boolean replace,char* name,char** databases, + char* type,char** elements,any* refID,void* queryInfo)); +void freeSearchAPDU _AP((SearchAPDU* query)); +char* writeSearchAPDU _AP((SearchAPDU* query,char* buffer,long* len)); +char* readSearchAPDU _AP((SearchAPDU** query,char* buffer)); + +SearchResponseAPDU* makeSearchResponseAPDU _AP((long result,long count, + long recordsReturned,long nextPos, + long resultStatus,long presentStatus, + any* refID,void* records)); +void freeSearchResponseAPDU _AP((SearchResponseAPDU* queryResponse)); +char* writeSearchResponseAPDU _AP((SearchResponseAPDU* queryResponse,char* buffer,long* len)); +char* readSearchResponseAPDU _AP((SearchResponseAPDU** queryResponse,char* buffer)); + +PresentAPDU* makePresentAPDU _AP((long recsReq, long startPos, + char* resultID,any* refID,void* info)); +void freePresentAPDU _AP((PresentAPDU* present)); +char* writePresentAPDU _AP((PresentAPDU* present,char* buffer,long* len)); +char* readPresentAPDU _AP((PresentAPDU** present,char* buffer)); + +PresentResponseAPDU* makePresentResponseAPDU _AP((boolean status,long recsRet, + long nextPos,any* refID, + void* records)); +void freePresentResponseAPDU _AP((PresentResponseAPDU* present)); +char* writePresentResponseAPDU _AP((PresentResponseAPDU* present,char* buffer,long* len)); +char* readPresentResponseAPDU _AP((PresentResponseAPDU** present,char* buffer)); + +/*----------------------------------------------------------------------*/ +/* user extension hooks: */ + +extern char* writeInitInfo _AP((InitAPDU* init,char* buffer,long* len)); +extern char* readInitInfo _AP((void** info,char* buffer)); + +extern char* writeInitResponseInfo _AP((InitResponseAPDU* init,char* buffer,long* len)); +extern char* readInitResponseInfo _AP((void** info,char* buffer)); + +extern char* writeSearchInfo _AP((SearchAPDU* query,char* buffer,long* len)); +extern char* readSearchInfo _AP((void** info,char* buffer)); + +extern char* writeSearchResponseInfo _AP((SearchResponseAPDU* query,char* buffer,long* len)); +extern char* readSearchResponseInfo _AP((void** info,char* buffer)); + +extern char* writePresentInfo _AP((PresentAPDU* present,char* buffer,long* len)); +extern char* readPresentInfo _AP((void** info,char* buffer)); + +extern char* writePresentResponseInfo _AP((PresentResponseAPDU* present,char* buffer,long* len)); +extern char* readPresentResponseInfo _AP((void** info,char* buffer)); + + +#endif /* HTVMSWAIS_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.c new file mode 100644 index 00000000000..b4a668ce775 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.c @@ -0,0 +1,1093 @@ +/* WorldWideWeb - Wide Area Informaion Server Access HTWAIS.c +** ================================================== +** +** This module allows a WWW server or client to read data from a +** remote WAIS +** server, and provide that data to a WWW client in hypertext form. +** Source files, once retrieved, are stored and used to provide +** information about the index when that is acessed. +** +** Authors +** BK Brewster Kahle, Thinking Machines, <Brewster@think.com> +** TBL Tim Berners-Lee, CERN <timbl@info.cern.ch> +** FM Foteos Macrides, WFEB <macrides@sci.wfeb.edu> +** +** History +** Sep 91 TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW. +** Feb 91 TBL Generated HTML cleaned up a bit (quotes, escaping) +** Refers to lists of sources. +** Mar 93 TBL Lib 2.0 compatible module made. +** May 94 FM Added DIRECT_WAIS support for VMS. +** +** Bugs +** Uses C stream i/o to read and write sockets, which won't work +** on VMS TCP systems. +** +** Should cache connections. +** +** ANSI C only as written +** +** Bugs fixed +** NT Nathan Torkington (Nathan.Torkington@vuw.ac.nz) +** +** WAIS comments: +** +** 1. Separate directories for different system's .o would help +** 2. Document ids are rather long! +** +** W WW Address mapping convention: +** +** /servername/database/type/length/document-id +** +** /servername/database?word+word+word +*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + Brewster@think.com +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTParse.h" +#include "HTAccess.h" /* We implement a protocol */ +#include "HTML.h" /* The object we will generate */ +#include "HTWSRC.h" +#include "HTTCP.h" +#include "HTCJK.h" +#include "HTAlert.h" + +/* From WAIS +** --------- +*/ +#ifdef VMS +#include "HTVMS_WaisUI.h" +#include "HTVMS_WaisProt.h" +#else +#include <ui.h> +#endif /* VMS */ + +#define MAX_MESSAGE_LEN 100000 +#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */ + +#define WAISSEARCH_DATE "Fri Jul 19 1991" + +/* FROM WWW +** -------- +*/ +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +extern int HTCheckForInterrupt NOPARAMS; + +#define DIRECTORY "/cnidr.org:210/directory-of-servers" +/* #define DIRECTORY "/quake.think.com:210/directory-of-servers" */ + +#define BIG 1024 /* identifier size limit @@@@@ */ + +#define BUFFER_SIZE 4096 /* Arbitrary size for efficiency */ + +#define HEX_ESCAPE '%' + +extern HTCJKlang HTCJK; + +extern int WWW_TraceFlag; /* Control diagnostic output */ +extern FILE * logfile; /* Log file output */ + +PRIVATE BOOL as_gate; /* Client is using us as gateway */ + +PRIVATE char line[2048]; /* For building strings to display */ + /* Must be able to take id */ + +#define PUTC(c) (*target->isa->put_character)(target, c) +#define PUTS(s) (*target->isa->put_string)(target, s) +#define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*target->isa->end_element)(target, e, 0) +#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ + (*target->isa->end_element)(target, e, 0) +#define FREE_TARGET (*target->isa->_free)(target) + +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; + +struct _HTStream { + CONST HTStreamClass * isa; + /* ... */ +}; + +/* ------------------------------------------------------------------------ */ +/* ---------------- Local copy of connect_to_server calls ----------------- */ +/* ------------------------------------------------------------------------ */ +/* Returns 1 on success, 0 on fail, -1 on interrupt. */ +PRIVATE int fd_mosaic_connect_to_server ARGS3( + char *, host_name, + long, port, + long *, fd) +{ + /* + ** New version. + */ + char dummy[256]; + int status; + + sprintf (dummy, "wais://%s:%d/", host_name, port); + + status = HTDoConnect (dummy, "WAIS", 210, (int *)fd); + if (status == HT_INTERRUPTED) { + return -1; + } + if (status < 0) + return 0; + return 1; +} + +/* Returns 1 on success, 0 on fail, -1 on interrupt. */ +#ifdef VMS +PRIVATE int mosaic_connect_to_server ARGS3( + char *, host_name, + long, port, + long *, fdp) +#else +PRIVATE int mosaic_connect_to_server ARGS3( + char *, host_name, + long, port, + FILE **, fp) +#endif /* VMS */ +{ +#ifndef VMS + FILE* file; +#endif /* VMS */ + long fd; + int rv; + + rv = fd_mosaic_connect_to_server (host_name, port, &fd); + if (rv == 0) { + HTAlert ("Could not connect to WAIS server."); + return 0; + } else if (rv == -1) { + HTAlert ("Connection interrupted."); + return -1; + } + +#ifndef VMS + if ((file = fdopen(fd,"r+")) == NULL) { + HTAlert ("Could not open WAIS connection for reading."); + return 0; + } + + *fp = file; +#else + *fdp = fd; +#endif /* VMS */ + return 1; +} +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +/* showDiags +*/ +/* modified from Jonny G's version in ui/question.c */ +PRIVATE void showDiags ARGS2( + HTStream *, target, + diagnosticRecord **, d) +{ + long i; + + for (i = 0; d[i] != NULL; i++) { + if (d[i]->ADDINFO != NULL) { + PUTS("Diagnostic code is "); + PUTS(d[i]->DIAG); + PUTC(' '); + PUTS(d[i]->ADDINFO); + PUTC('\n'); ; + } + } +} + +/* Matrix of allowed characters in filenames +** ----------------------------------------- +*/ + +PRIVATE BOOL acceptable[256]; +PRIVATE BOOL acceptable_inited = NO; + +PRIVATE void init_acceptable NOARGS +{ + unsigned int i; + char * good = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$"; + for(i=0; i<256; i++) acceptable[i] = NO; + for(;*good; good++) acceptable[(unsigned int)*good] = YES; + acceptable_inited = YES; +} + +/* Transform file identifier into WWW address +** ------------------------------------------ +** +** +** On exit, +** returns nil if error +** pointer to malloced string (must be freed) if ok +*/ +PRIVATE char * WWW_from_archie ARGS1( + char *, file) +{ + char * end; + char * result; + char * colon; + for(end=file; *end > ' '; end++); /* assumes ASCII encoding*/ + result = (char *)malloc(10 + (end-file)); + if (!result) return result; /* Malloc error */ + strcpy(result, "file://"); + strncat(result, file, end-file); + colon = strchr(result+7, ':'); /* Expect colon after host */ + if (colon) { + for(; colon[0]; colon[0]=colon[1], colon++); /* move down */ + } + return result; +} /* WWW_from_archie */ + +/* Transform document identifier into URL +** -------------------------------------- +** +** Bugs: A static buffer of finite size is used! +** The format of the docid MUST be good! +** +** On exit, +** returns nil if error +** pointer to malloced string (must be freed) if ok +*/ +PRIVATE char hex [17] = "0123456789ABCDEF"; + +PRIVATE char * WWW_from_WAIS ARGS1( + any *, docid) +{ + static char buf[BIG]; + char * q = buf; + char * p = (docid->bytes); + int i, l; + if (TRACE) { + char *p; + fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size); + for (p = docid->bytes; p < docid->bytes+docid->size; p++) { + if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */ + fprintf(stderr, "%c", *p); + else + fprintf(stderr, "<%x>", (unsigned)*p); + } + fprintf(stderr, "\n"); + } + for (p = docid->bytes; + (p < docid->bytes+docid->size) && (q < &buf[BIG]);) { + if (TRACE) + fprintf(stderr, " Record type %d, length %d\n", p[0], p[1]); + if (*p > 10) { + if (TRACE) + fprintf(stderr, "Eh? DOCID record type of %d!\n", *p); + return 0; + } + { /* Bug fix -- allow any byte value 15 Apr 93 */ + unsigned int i = (unsigned) *p++; + + if (i > 99) { + *q++ = (i/100) + '0'; + i = i % 100; + } + if (i > 9) { + *q++ = (i/10) + '0'; + i = i % 10; + } + *q++ = i + '0'; /* Record type */ + } + *q++ = '='; /* Separate */ + l = *p++; /* Length */ + for (i = 0; i < l; i++, p++){ + if (!acceptable[*p]) { + *q++ = HEX_ESCAPE; /* Means hex commming */ + *q++ = hex[(*p) >> 4]; + *q++ = hex[(*p) & 15]; + } + else *q++ = *p; + } + *q++= ';'; /* Terminate field */ + } + *q++ = 0; /* Terminate string */ + if (TRACE) + fprintf(stderr, "WWW form of id: %s\n", buf); + { + char * result = (char *)malloc(strlen(buf)+1); + if (!result) + outofmem(__FILE__, "WWW_from_WAIS"); + strcpy(result, buf); + return result; + } +} /* WWW_from_WAIS */ + +/* Transform URL into WAIS document identifier +** ------------------------------------------- +** +** On entry, +** docname points to valid name produced originally by +** WWW_from_WAIS +** On exit, +** docid->size is valid +** docid->bytes is malloced and must later be freed. +*/ +PRIVATE any * WAIS_from_WWW ARGS2( + any *, docid, + char *, docname) +{ + char *z; /* Output pointer */ + char *sor; /* Start of record - points to size field. */ + char *p; /* Input pointer */ + char *q; /* Poisition of "=" */ + char *s; /* Position of semicolon */ + int n; /* size */ + if (TRACE) + fprintf(stderr, "WWW id (to become WAIS id): %s\n", docname); + for (n = 0, p = docname; *p; p++) { /* Count sizes of strings */ + n++; + if (*p == ';') + n--; /* Not converted */ + else if (*p == HEX_ESCAPE) + n = n-2; /* Save two bytes */ + docid->size = n; + } + + if (!(docid->bytes = (char *) malloc(docid->size))) /* result record */ + outofmem(__FILE__, "WAIS_from_WWW"); + z = docid->bytes; + + for (p = docname; *p; ) { /* Convert of strings */ + /* Record type */ + + *z = 0; /* Initialize record type */ + while (*p >= '0' && *p <= '9') { + *z = *z*10 + (*p++ - '0'); /* Decode decimal record type */ + } + z++; + if (*p != '=') + return 0; + q = p; + +/* *z++ = *p++ - '0'; + q = strchr(p , '='); + if (!q) return 0; +*/ + s = strchr(q, ';'); /* (Check only) */ + if (!s) + return 0; /* Bad! No ';'; */ + sor = z; /* Remember where the size field was */ + z++; /* Skip record size for now */ + for (p = q+1; *p != ';';) { + if (*p == HEX_ESCAPE) { + char c; + unsigned int b; + p++; + c = *p++; + b = from_hex(c); + c = *p++; + if (!c) + break; /* Odd number of chars! */ + *z++ = (b<<4) + from_hex(c); + } else { + *z++ = *p++; /* Record */ + } + } + *sor = (z-sor-1); /* Fill in size -- not counting size itself */ + p++; /* After semicolon: start of next record */ + } + + if (TRACE) { + char *p; + fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size); + for (p = docid->bytes; p < docid->bytes+docid->size; p++) { + if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */ + fprintf(stderr, "%c", *p); + else + fprintf(stderr, "<%x>", (unsigned)*p); + } + fprintf(stderr, "\n"); + } + return docid; /* Ok */ + +} /* WAIS_from_WWW */ + +/* Send a plain text record to the client output_text_record() +** -------------------------------------- +*/ +PRIVATE void output_text_record ARGS4( + HTStream *, target, + WAISDocumentText *, record, + boolean, quote_string_quotes, + boolean, binary) +{ + long count; + /* printf(" Text\n"); + print_any(" DocumentID: ", record->DocumentID); + printf(" VersionNumber: %d\n", record->VersionNumber); + */ + + if (binary) { + (*target->isa->put_block)(target, + record->DocumentText->bytes, + record->DocumentText->size); + return; + } + + for (count = 0; count < record->DocumentText->size; count++){ + long ch = (unsigned char)record->DocumentText->bytes[count]; + if (ch == 27) { /* What is this in for? Tim */ + /* then we have an escape code */ + /* if the next letter is '(' or ')', then ignore two letters */ + if ('(' == record->DocumentText->bytes[count + 1] || + ')' == record->DocumentText->bytes[count + 1]) + count += 1; /* it is a term marker */ + else count += 4; /* it is a paragraph marker */ + } else if (ch == '\n' || ch == '\r') { + PUTC('\n'); + } else if (HTCJK != NOCJK || ch == '\t' || isprint(ch)){ + PUTC(ch); + } + } +} /* output text record */ + +/* Format A Search response for the client display_search_response +** --------------------------------------- +*/ +/* modified from tracy shen's version in wutil.c + * displays either a text record or a set of headlines. + */ +PRIVATE void display_search_response ARGS4( + HTStructured *, target, + SearchResponseAPDU *, response, + char *, database, + char *, keywords) +{ + WAISSearchResponse *info; + long i, k; + + BOOL archie = strstr(database, "archie")!=0; /* Specical handling */ + + if (TRACE) + fprintf(stderr, "HTWAIS: Displaying search response\n"); + PUTS("Index "); + START(HTML_EM); + PUTS(database); + END(HTML_EM); + sprintf(line, " contains the following %d item%s relevant to \"", + (int)(response->NumberOfRecordsReturned), + response->NumberOfRecordsReturned ==1 ? "" : "s"); + PUTS(line); + START(HTML_EM); + PUTS(keywords); + END(HTML_EM); + PUTS("\".\n"); + PUTS("The first figure after each entry is its relative score, "); + PUTS("the second is the number of lines in the item."); + START(HTML_BR); + START(HTML_BR); + PUTS("\n"); + START(HTML_OL); + + if (response->DatabaseDiagnosticRecords != 0) { + info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords; + i =0; + + if (info->Diagnostics != NULL) + showDiags((HTStream*)target, info->Diagnostics); + + if (info->DocHeaders != 0) { + for (k = 0; info->DocHeaders[k] != 0; k++ ) { + WAISDocumentHeader* head = info->DocHeaders[k]; + char * headline = trim_junk(head->Headline); + any * docid = head->DocumentID; + char * docname; /* printable version of docid */ + + i++; + /* + ** Make a printable string out of the document id. + */ + if (TRACE) + fprintf(stderr, + "HTWAIS: %2ld: Score: %4ld, lines:%4ld '%s'\n", + i, + (long int)(info->DocHeaders[k]->Score), + (long int)(info->DocHeaders[k]->Lines), + headline); + + START(HTML_LI); + + if (archie) { + char * www_name = WWW_from_archie(headline); + if (www_name) { + HTStartAnchor(target, NULL, www_name); + PUTS(headline); + END(HTML_A); + FREE(www_name); + } else { + PUTS(headline); + PUTS(" (bad file name)"); + } + } else { /* Not archie */ + docname = WWW_from_WAIS(docid); + if (docname) { + char * dbname = HTEscape(database, URL_XPALPHAS); + sprintf(line, + "/%s/%s/%d/%s", /* W3 address */ + dbname, + head->Types ? head->Types[0] : "TEXT", + (int)(head->DocumentLength), + docname); + HTStartAnchor(target, NULL, + ((head->Types) && + (!strcmp(head->Types[0], "URL"))) + ? + headline : line); /* NT, Sep 93 */ + PUTS(headline); + END(HTML_A); + FREE(dbname); + FREE(docname); + } else { + PUTS("(bad doc id)"); + } + } + + sprintf(line, "%5ld %5ld ", + head->Score, + head->Lines); + PUTS( line); + MAYBE_END(HTML_LI); + } /* next document header */ + } /* if there were any document headers */ + + if (info->ShortHeaders != 0) { + k = 0; + while (info->ShortHeaders[k] != 0) { + i++; + PUTS( "(Short Header record, can't display)"); + } + } + if (info->LongHeaders != 0) { + k = 0; + while (info->LongHeaders[k] != 0) { + i++; + PUTS( "\nLong Header record, can't display\n"); + } + } + if (info->Text != 0) { + k = 0; + while (info->Text[k] != 0) { + i++; + PUTS( "\nText record\n"); + output_text_record((HTStream*)target, + info->Text[k++], false, false); + } + } + if (info->Headlines != 0) { + k = 0; + while (info->Headlines[k] != 0) { + i++; + PUTS( "\nHeadline record, can't display\n"); + /* dsply_headline_record( info->Headlines[k++]); */ + } + } + if (info->Codes != 0) { + k = 0; + while (info->Codes[k] != 0) { + i++; + PUTS( "\nCode record, can't display\n"); + /* dsply_code_record( info->Codes[k++]); */ + } + } + } /* Loop: display user info */ + END(HTML_OL); + PUTC('\n'); ; +} + +/* Load by name HTLoadWAIS +** ============ +** +** This renders any object or search as required. +*/ +PUBLIC int HTLoadWAIS ARGS4( + CONST char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) + +#define MAX_KEYWORDS_LENGTH 1000 +#define MAX_SERVER_LENGTH 1000 +#define MAX_DATABASE_LENGTH 1000 +#define MAX_SERVICE_LENGTH 1000 +#define MAXDOCS 200 + +{ + static CONST char * error_header = +"<h1>Access error</h1>\nThe following error occured in accesing a WAIS server:<P>\n"; + char * key; /* pointer to keywords in URL */ + char* request_message = NULL; /* arbitrary message limit */ + char* response_message = NULL; /* arbitrary message limit */ + long request_buffer_length; /* how of the request is left */ + SearchResponseAPDU *retrieval_response = 0; + char keywords[MAX_KEYWORDS_LENGTH + 1]; + char *server_name; + char *wais_database = NULL; /* name of current database */ + char *www_database; /* Same name escaped */ + char *service; + char *doctype; + char *doclength; + long document_length; + char *docname; +#ifdef VMS + long connection = 0; +#else + FILE *connection = NULL; +#endif /* VMS */ + char * names; /* Copy of arg to be hacked up */ + BOOL ok = NO; + int return_status = HT_LOADED; + int rv; + + extern FILE * connect_to_server(); + + if (!acceptable_inited) + init_acceptable(); + + /* Decipher and check syntax of WWW address: + ** ---------------------------------------- + ** + ** First we remove the "wais:" if it was spcified. 920110 + */ + names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION); + key = strchr(names, '?'); + + if (key) { + char * p; + *key++ = 0; /* Split off keywords */ + for (p=key; *p; p++) if (*p == '+') *p = ' '; + HTUnEscape(key); + } + if (names[0] == '/') { + server_name = names+1; + if (as_gate =(*server_name == '/')) + server_name++; /* Accept one or two */ + www_database = strchr(server_name,'/'); + if (www_database) { + *www_database++ = 0; /* Separate database name */ + doctype = strchr(www_database, '/'); + if (key) ok = YES; /* Don't need doc details */ + else if (doctype) { /* If not search parse doc details */ + *doctype++ = 0; /* Separate rest of doc address */ + doclength = strchr(doctype, '/'); + if (doclength) { + *doclength++ = 0; + document_length = atol(doclength); + if (document_length) { + docname = strchr(doclength, '/'); + if (docname) { + *docname++ = 0; + ok = YES; /* To avoid a goto! */ + } /* if docname */ + } /* if document_length valid */ + } /* if doclength */ + } else { /* no doctype? Assume index required */ + if (!key) + key = ""; + ok = YES; + } /* if doctype */ + } /* if database */ + } + + if (!ok) + return HTLoadError(sink, 500, "Syntax error in WAIS URL"); + + if (TRACE) + fprintf(stderr, "HTWAIS: Parsed OK\n"); + + service = strchr(names, ':'); + if (service) + *service++ = 0; + else + service = "210"; + + if (server_name[0] == 0) { +#ifdef VMS + connection = 0; +#else + connection = NULL; +#endif /* VMS */ + + } else if (!(key && !*key)) { + int status; + if (TRACE) + fprintf (stderr, "===WAIS=== calling mosaic_connect_to_server\n"); + status = mosaic_connect_to_server(server_name, + atoi(service), + &connection); + if (status == 0) { + if (TRACE) + fprintf (stderr, "===WAIS=== connection failed\n"); + FREE(names); + return HT_NOT_LOADED; + } else if (status == -1) { + if (TRACE) + fprintf (stderr, "===WAIS=== connection interrupted\n"); + FREE(names); + return HT_NOT_LOADED; + } + } + + StrAllocCopy(wais_database,www_database); + HTUnEscape(wais_database); + + /* + ** This below fixed size stuff is terrible. + */ +#ifdef VMS + if (!(request_message = + (char*)calloc((size_t)MAX_MESSAGE_LEN*sizeof(char),1))) + outofmem(__FILE__, "HTLoadWAIS"); + if (!(response_message = + (char*)calloc((size_t)MAX_MESSAGE_LEN*sizeof(char),1))) + outofmem(__FILE__, "HTLoadWAIS"); +#else + request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char)); + response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char)); +#endif /* VMS */ + + /* + ** If keyword search is performed but there are no keywords, + ** the user has followed a link to the index itself. It would be + ** appropriate at this point to send him the .SRC file - how? + */ + if (key && !*key) { /* I N D E X */ +#ifdef CACHE_FILE_PREFIX + char filename[256]; + FILE * fp; +#endif + HTStructured * target = HTML_new(anAnchor, format_out, sink); + + START(HTML_HEAD); + PUTS("\n"); + HTStartIsIndex(target, "Enter WAIS query: ", NULL); + PUTS("\n"); + + { + START(HTML_TITLE); + PUTS(wais_database); + PUTS(" (WAIS Index)"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + + START(HTML_H1); + PUTS("WAIS Index: "); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + END(HTML_H1); + PUTS("\n"); + PUTS("This is a link for searching the "); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + PUTS(" WAIS Index.\n"); + + } + /* + ** If we have seen a source file for this database, use that. + */ +#ifdef CACHE_FILE_PREFIX + sprintf(filename, "%sWSRC-%s:%s:%.100s.txt", + CACHE_FILE_PREFIX, + server_name, service, www_database); + + fp = fopen(filename, "r"); /* Have we found this already? */ + if (TRACE) fprintf(stderr, + "HTWAIS: Description of server %s %s.\n", + filename, + fp ? "exists already" : "does NOT exist!"); + + if (fp) { + char c; + START(HTML_PRE); /* Preformatted description */ + PUTS("\n"); + while((c=getc(fp))!=EOF) PUTC(c); /* Transfer file */ + END(HTML_PRE); + fclose(fp); +#endif + START(HTML_P); + PUTS("\nEnter the 's'earch command and then specify search words.\n"); + + FREE_TARGET; + } else if (key) { /* S E A R C H */ + char *p; + HTStructured * target; + + strncpy(keywords, key, MAX_KEYWORDS_LENGTH); + while(p=strchr(keywords, '+')) *p = ' '; + + /* + ** Send advance title to get something fast to the other end. + */ + target = HTML_new(anAnchor, format_out, sink); + + START(HTML_HEAD); + PUTS("\n"); + HTStartIsIndex(target, "Enter WAIS query: ", NULL); + PUTS("\n"); + START(HTML_TITLE); + PUTS(keywords); + PUTS(" (in "); + PUTS(wais_database); + PUTS(")"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + PUTS("\n"); + + START(HTML_H1); + PUTS("WAIS Search of \""); + START(HTML_EM); + PUTS(keywords); + END(HTML_EM); + PUTS("\" in: "); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + END(HTML_H1); + PUTS("\n"); + + request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */ + if (TRACE) fprintf(stderr, "HTWAIS: Search for `%s' in `%s'\n", + keywords, wais_database); + if(NULL == + generate_search_apdu(request_message + HEADER_LENGTH, + &request_buffer_length, + keywords, wais_database, NULL, MAXDOCS)) { +#ifdef VMS + HTAlert ("HTWAIS: Request too large."); + return_status = HT_NOT_LOADED; + FREE_TARGET; + goto CleanUp; +#else + panic("request too large"); +#endif /* VMS */ + } + + HTProgress("Searching WAIS database..."); + rv = interpret_message (request_message, + MAX_MESSAGE_LEN - request_buffer_length, + response_message, + MAX_MESSAGE_LEN, + connection, + false /* true verbose */ + ); + + if (rv == HT_INTERRUPTED) { + HTAlert ("Search interrupted."); + return_status = HT_INTERRUPTED; + FREE_TARGET; + goto CleanUp; + } else if (!rv) { +#ifdef VMS + HTAlert ("HTWAIS: Return message too large."); + return_status = HT_NOT_LOADED; + FREE_TARGET; + goto CleanUp; +#else + panic("returned message too large"); +#endif /* VMS */ + } else { /* returned message ok */ + SearchResponseAPDU *query_response = 0; + readSearchResponseAPDU(&query_response, + response_message + HEADER_LENGTH); + display_search_response(target, + query_response, wais_database, keywords); + if (query_response->DatabaseDiagnosticRecords) + freeWAISSearchResponse( + query_response->DatabaseDiagnosticRecords); + freeSearchResponseAPDU( query_response); + } /* returned message not too large */ + FREE_TARGET; + } else { /* D O C U M E N T F E T C H */ + HTFormat format_in; + boolean binary; /* how to transfer stuff coming over */ + HTStream * target; + long count; + any doc_chunk; + any * docid = &doc_chunk; + + if (TRACE) fprintf(stderr, + "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n", + docname, doctype, document_length); + + format_in = + !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") : + !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") : + !strcmp(doctype, "HTML") ? HTAtom_for("text/html") : + !strcmp(doctype, "GIF") ? HTAtom_for("image/gif") : + HTAtom_for("application/octet-stream"); + binary = + 0 != strcmp(doctype, "WSRC") && + 0 != strcmp(doctype, "TEXT") && + 0 != strcmp(doctype, "HTML") ; + + target = HTStreamStack(format_in, format_out, sink, anAnchor); + if (!target) + return HTLoadError(sink, 500, + "Can't convert format of WAIS document"); + /* + ** Decode hex or litteral format for document ID. + */ + WAIS_from_WWW(docid, docname); + + /* + ** Loop over slices of the document. + */ + for (count = 0; + count * CHARS_PER_PAGE < document_length; + count++) { +#ifdef VMS + char *type = NULL; + + StrAllocCopy(type, doctype); +#else + char *type = s_strdup(doctype); /* Gets freed I guess */ +#endif /* VMS */ + request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */ + if (TRACE) + fprintf(stderr, "HTWAIS: Slice number %ld\n", count); + + if (HTCheckForInterrupt()) { + HTAlert ("Data transfer interrupted."); + (*target->isa->_abort)(target, NULL); +#ifdef VMS + FREE(type); +#endif /* VMS */ + return_status = HT_NOT_LOADED; + goto CleanUp; + } + + if (0 == + generate_retrieval_apdu(request_message + HEADER_LENGTH, + &request_buffer_length, + docid, + CT_byte, + count * CHARS_PER_PAGE, + ((count + 1) * CHARS_PER_PAGE <= document_length ? + (count + 1) * CHARS_PER_PAGE : + document_length), + type, + wais_database)) { +#ifdef VMS + HTAlert ("HTWAIS: Request too long."); + return_status = HT_NOT_LOADED; + FREE_TARGET; + FREE(type); + FREE(docid->bytes); + goto CleanUp; +#else + panic("request too long"); +#endif /* VMS */ + } + + /* + ** Actually do the transaction given by request_message. + */ + HTProgress("Fetching WAIS document..."); + rv = interpret_message(request_message, + MAX_MESSAGE_LEN - request_buffer_length, + response_message, + MAX_MESSAGE_LEN, + connection, + false /* true verbose */ + ); + if (rv == HT_INTERRUPTED) { + HTAlert ("Data transfer interrupted."); + return_status = HT_INTERRUPTED; + FREE_TARGET; + FREE(type); + FREE(docid->bytes); + goto CleanUp; + } else if (!rv) { +#ifdef VMS + HTAlert ("HTWAIS: Return message too large."); + return_status = HT_NOT_LOADED; + FREE_TARGET; + FREE(type); + FREE(docid->bytes); + goto CleanUp; +#else + panic("Returned message too large"); +#endif /* VMS */ + } + + /* + ** Parse the result which came back into memory. + */ + readSearchResponseAPDU(&retrieval_response, + response_message + HEADER_LENGTH); + + if (NULL == + ((WAISSearchResponse *) + retrieval_response->DatabaseDiagnosticRecords)->Text) { + /* display_search_response(target, retrieval_response, + wais_database, keywords); */ + PUTS("No text was returned!\n"); + /* panic("No text was returned"); */ + } else { + output_text_record(target, + ((WAISSearchResponse *) + retrieval_response->DatabaseDiagnosticRecords)->Text[0], + false, binary); + } /* If text existed */ + +#ifdef VMS + FREE(type); +#endif /* VMS */ + } /* Loop over slices */ + + FREE_TARGET; + FREE(docid->bytes); + + freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); + freeSearchResponseAPDU( retrieval_response); + + } /* If document rather than search */ + +CleanUp: + /* + ** (This postponed until later, after a timeout:) + */ +#ifdef VMS + if (connection) + NETCLOSE((int)connection); +#else + if (connection) + fclose(connection); +#endif /* VMS */ + FREE(wais_database); +#ifdef VMS + FREE(request_message); + FREE(response_message); +#else + s_free(request_message); + s_free(response_message); +#endif /* VMS */ + FREE(names); + return (return_status); +} + +#ifdef GLOBALDEF_IS_MACRO +#define _HTWAIS_C_1_INIT { "wais", HTLoadWAIS, NULL } +GLOBALDEF(HTProtocol, HTWAIS, _HTWAIS_C_1_INIT); +#else +GLOBALDEF PUBLIC HTProtocol HTWAIS = { "wais", HTLoadWAIS, NULL }; +#endif /* GLOBALDEF_IS_MACRO */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.h new file mode 100644 index 00000000000..4aa885dcbed --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.h @@ -0,0 +1,44 @@ +/* WAIS protocol module for the W3 library + WAIS PROTOCOL INTERFACE + + This module does not actually perform the WAIS protocol directly, but it does using one + or more libraries of the freeWAIS distribution. The ui.a library came with the old free + WAIS from TMC, the client.a and wais.a libraries are needed from the freeWAIS from + CNIDR. + + If you include this module in the library, you must also + + Register the HTWAIS protocol at initialisation (e.g. HTInit or HTSInit) by compiling + it with -DDIRECT_WAIS + + Link with the WAIS libraries + + The wais source files are parsed by a separate and independent module, HTWSRC . You + can include HTWSRC without including direct wais using this module, and your WWW code + will be able to read source files, and access WAIS indexes through a gateway. + + A WAIS-WWW gateway is just a normal W3 server with a libwww compiled with this module. + + Anyways, this interface won't change much: + + */ +#ifndef HTWAIS_H +#define HTWAIS_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTAccess.h" + +#ifdef GLOBALREF_IS_MACRO +extern GLOBALREF(HTProtocol, HTWAIS); +#else +GLOBALREF HTProtocol HTWAIS; +#endif /* GLOBALDEF_IS_MACRO */ + +#endif /* HTWAIS_H */ + +/* + Tim BL + +*/ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.c new file mode 100644 index 00000000000..e7f15dad511 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.c @@ -0,0 +1,473 @@ +/* Parse WAIS Source file HTWSRC.c +** ====================== +** +** This module parses a stream with WAIS source file +** format information on it and creates a structured stream. +** That structured stream is then converted into whatever. +** +** 3 June 93 Bug fix: Won't crash if no description +*/ + +#include "HTUtils.h" +#include "tcp.h" + +#include "HTWSRC.h" + + +#include "HTML.h" +#include "HTParse.h" + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +#define BIG 10000 /* Arbitrary limit to value length */ +#define PARAM_MAX BIG +#define CACHE_PERIOD (7*86400) /* Time to keep .src file in seconds */ + +#define HEX_ESCAPE '%' + +struct _HTStructured { + CONST HTStructuredClass * isa; + /* ... */ +}; + +#define PUTC(c) (*me->target->isa->put_character)(me->target, c) +#define PUTS(s) (*me->target->isa->put_string)(me->target, s) +#define START(e) (*me->target->isa->start_element)(me->target, e, 0, 0, -1, 0) +#define END(e) (*me->target->isa->end_element)(me->target, e, 0) +#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ + (*me->target->isa->end_element)(me->target, e, 0) + + +/* Here are the parameters which can be specified in a source file +*/ +PRIVATE CONST char* par_name[] = { + "version", + "ip-address", +#define PAR_IP_NAME 2 + "ip-name", +#define PAR_TCP_PORT 3 + "tcp-port", +#define PAR_DATABASE_NAME 4 + "database-name", +#define PAR_COST 5 + "cost", +#define PAR_COST_UNIT 6 + "cost-unit", +#define PAR_FREE 7 + "free", +#define PAR_MAINTAINER 8 + "maintainer", +#define PAR_DESCRIPTION 9 + "description", + "keyword-list", + "source", + "window-geometry", + "configuration", + "script", + "update-time", + "contact-at", + "last-contacted", + "confidence", + "num-docs-to-request", + "font", + "font-size", +#define PAR_UNKNOWN 22 + "unknown", + 0, /* Terminate list */ +#define PAR_COUNT 23 +} ; + + +enum tokenstate { beginning, before_tag, colon, before_value, + value, bracketed_value, quoted_value, escape_in_quoted, done }; + + +/* Stream Object +** ------------ +** +** The target is the structured stream down which the +** parsed results will go. +** +** all the static stuff below should go in here to make it reentrant +*/ + +struct _HTStream { + CONST HTStreamClass * isa; + HTStructured * target; + char * par_value[PAR_COUNT]; + enum tokenstate state; + char param[BIG+1]; + int param_number; + int param_count; +}; + + + + +PUBLIC CONST char * hex = "0123456789ABCDEF"; + +/* Decode one hex character +*/ + +PUBLIC char from_hex ARGS1(char, c) +{ + return (c>='0')&&(c<='9') ? c-'0' + : (c>='A')&&(c<='F') ? c-'A'+10 + : (c>='a')&&(c<='f') ? c-'a'+10 + : 0; +} + + +/* State machine +** ------------- +** +** On entry, +** me->state is a valid state (see WSRC_init) +** c is the next character +** On exit, +** returns 1 Done with file +** 0 Continue. me->state is updated if necessary. +** -1 Syntax error error +*/ + + +/* Treat One Character +** ------------------- +*/ +PRIVATE void WSRCParser_put_character ARGS2(HTStream*, me, char, c) +{ + switch (me->state) { + case beginning: + if (c=='(') me->state = before_tag; + break; + + case before_tag: + if (c==')') { + me->state = done; + return; /* Done with input file */ + } else if (c==':') { + me->param_count = 0; + me->state = colon; + } /* Ignore other text */ + break; + + case colon: + if (WHITE(c)) { + me->param[me->param_count++] = 0; /* Terminate */ + for(me->param_number = 0; par_name[me->param_number]; me->param_number++) { + if (0==strcmp(par_name[me->param_number], me->param)) { + break; + } + } + if (!par_name[me->param_number]) { /* Unknown field */ + if (TRACE) fprintf(stderr, + "HTWSRC: Unknown field `%s' in source file\n", + me->param); + me->param_number = PAR_UNKNOWN; + me->state = before_value; /* Could be better ignore */ + return; + } + me->state = before_value; + } else { + if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c; + } + break; + + case before_value: + if (c==')') { + me->state = done; + return; /* Done with input file */ + } + if (WHITE(c)) return; /* Skip white space */ + me->param_count = 0; + if (c=='"') { + me->state = quoted_value; + break; + } + me->state = (c=='"') ? quoted_value : + (c=='(') ? bracketed_value : value; + me->param[me->param_count++] = c; /* Don't miss first character */ + break; + + case value: + if (WHITE(c)) { + me->param[me->param_count] = 0; + StrAllocCopy(me->par_value[me->param_number], me->param); + me->state = before_tag; + } else { + if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c; + } + break; + + case bracketed_value: + if (c==')') { + me->param[me->param_count] = 0; + StrAllocCopy(me->par_value[me->param_number], me->param); + me->state = before_tag; + break; + } + if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c; + break; + + case quoted_value: + if (c=='"') { + me->param[me->param_count] = 0; + StrAllocCopy(me->par_value[me->param_number], me->param); + me->state = before_tag; + break; + } + + if (c=='\\') { /* Ignore escape but switch state */ + me->state = escape_in_quoted; + break; + } + /* Fall through! */ + + case escape_in_quoted: + if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c; + me->state = quoted_value; + break; + + case done: /* Ignore anything after EOF */ + return; + + } /* switch me->state */ +} + + +/* Open Cache file +** =============== +** +** Bugs: Maybe for filesystem-challenged platforms (MSDOS for example) we +** should make a hash code for the filename. +*/ + +#ifdef CACHE_FILE_PREFIX +PRIVATE BOOL write_cache ARGS1(HTStream *, me) +{ + FILE * fp; + char cache_file_name[256]; + char * www_database; + if (!me->par_value[PAR_DATABASE_NAME] + || !me->par_value[PAR_IP_NAME] + ) return NO; + + www_database = HTEscape(me->par_value[PAR_DATABASE_NAME], URL_XALPHAS); + sprintf(cache_file_name, "%sWSRC-%s:%s:%.100s.txt", + CACHE_FILE_PREFIX, + me->par_value[PAR_IP_NAME], + me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] : "210", + www_database); + FREE(www_database); + fp = fopen(cache_file_name, "w"); + if (!fp) return NO; + + if (me->par_value[PAR_DESCRIPTION]) + fputs(me->par_value[PAR_DESCRIPTION], fp); + else + fputs("Description not available\n", fp); + fclose(fp); + return YES; +} +#endif + +/* Output equivalent HTML +** ---------------------- +** +*/ + +PRIVATE void give_parameter ARGS2(HTStream *, me, int, p) +{ + PUTS(par_name[p]); + if (me->par_value[p]) { + PUTS(": "); + PUTS(me->par_value[p]); + PUTS("; "); + } else { + PUTS(" NOT GIVEN in source file; "); + } +} + + +/* Generate Outout +** =============== +*/ +PRIVATE void WSRC_gen_html ARGS2(HTStream *, me, BOOL, source_file) + +{ + if (me->par_value[PAR_DATABASE_NAME]) { + char * shortname = 0; + int l; + StrAllocCopy(shortname, me->par_value[PAR_DATABASE_NAME]); + l = strlen(shortname); + if ( l > 4 && !strcasecomp(shortname + l -4, ".src")) { + shortname[l-4] = 0; /* Chop of .src -- boring! */ + } + + START(HTML_HEAD); + PUTS("\n"); + START(HTML_TITLE); + PUTS(shortname); + PUTS(source_file ? " WAIS source file" : " index"); + END(HTML_TITLE); + PUTS("\n"); + END(HTML_HEAD); + + START(HTML_H1); + PUTS(shortname); + PUTS(source_file ? " description" : " index"); + END(HTML_H1); + PUTS("\n"); + FREE(shortname); + } + + START(HTML_DL); /* Definition list of details */ + + if (source_file) { + START(HTML_DT); + PUTS("Access links"); + MAYBE_END(HTML_DT); + START(HTML_DD); + if (me->par_value[PAR_IP_NAME] && + me->par_value[PAR_DATABASE_NAME]) { + + char WSRC_address[256]; + char * www_database; + www_database = HTEscape(me->par_value[PAR_DATABASE_NAME], + URL_XALPHAS); + sprintf(WSRC_address, "wais://%s%s%s/%s", + me->par_value[PAR_IP_NAME], + me->par_value[PAR_TCP_PORT] ? ":" : "", + me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] :"", + www_database); + + HTStartAnchor(me->target, NULL, WSRC_address); + PUTS("Direct access"); + END(HTML_A); + /** Proxy will be used if defined, so let user know that - FM **/ + PUTS(" (or via proxy server, if defined)"); + + FREE(www_database); + + } else { + give_parameter(me, PAR_IP_NAME); + give_parameter(me, PAR_DATABASE_NAME); + } + MAYBE_END(HTML_DD); + + } /* end if source_file */ + + if (me->par_value[PAR_MAINTAINER]) { + START(HTML_DT); + PUTS("Maintainer"); + MAYBE_END(HTML_DT); + START(HTML_DD); + PUTS(me->par_value[PAR_MAINTAINER]); + MAYBE_END(HTML_DD); + } + if (me->par_value[PAR_IP_NAME]) { + START(HTML_DT); + PUTS("Host"); + MAYBE_END(HTML_DT); + START(HTML_DD); + PUTS(me->par_value[PAR_IP_NAME]); + MAYBE_END(HTML_DD); + } + + END(HTML_DL); + + if (me->par_value[PAR_DESCRIPTION]) { + START(HTML_PRE); /* Preformatted description */ + PUTS(me->par_value[PAR_DESCRIPTION]); + END(HTML_PRE); + } + + (*me->target->isa->_free)(me->target); + + return; +} /* generate html */ + + +PRIVATE void WSRCParser_put_string ARGS2(HTStream *, context, CONST char*, str) +{ + CONST char *p; + for(p=str; *p; p++) + WSRCParser_put_character(context, *p); +} + + +PRIVATE void WSRCParser_write ARGS3( + HTStream *, context, + CONST char*, str, + int, l) +{ + CONST char *p; + CONST char *e = str+l; + for(p=str; p<e; p++) + WSRCParser_put_character(context, *p); +} + + +PRIVATE void WSRCParser_free ARGS1(HTStream *, me) +{ + WSRC_gen_html(me, YES); +#ifdef CACHE_FILE_PREFIX + write_cache(me); +#endif + { + int p; + for (p = 0; par_name[p]; p++) { /* Clear out old values */ + FREE(me->par_value[p]); + } + } + FREE(me); +} + +PRIVATE void WSRCParser_abort ARGS2(HTStream *, me, HTError, e GCC_UNUSED) +{ + WSRCParser_free(me); +} + + +/* Stream subclass -- method routines +** --------------- +*/ + +HTStreamClass WSRCParserClass = { + "WSRCParser", + WSRCParser_free, + WSRCParser_abort, + WSRCParser_put_character, + WSRCParser_put_string, + WSRCParser_write + +}; + + +/* Converter from WAIS Source to whatever +** -------------------------------------- +*/ +PUBLIC HTStream* HTWSRCConvert ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, + HTStream *, sink) +{ + HTStream * me = (HTStream*) malloc(sizeof(*me)); + if (!me) outofmem(__FILE__, "HTWSRCConvert"); + + me->isa = &WSRCParserClass; + me->target = HTML_new(anchor, pres->rep_out, sink); + + { + int p; + for(p=0; p < PAR_COUNT; p++) { /* Clear out parameter values */ + me->par_value[p] = 0; + } + } + me->state = beginning; + + return me; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.h new file mode 100644 index 00000000000..9241b321c0b --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.h @@ -0,0 +1,48 @@ +/* A parser for WAIS source files + WAIS SOURCE FILE PARSER + + This converter returns a stream object into which a WAIS source file can be written. + The result is put via a structured stream into whatever format was required for the + output stream. + + See also: HTWAIS protocol interface module + + */ +#ifndef HTWSRC_H +#define HTWSRC_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ + +#include "HTFormat.h" + +extern char from_hex PARAMS((char c)); + +extern HTStream* HTWSRCConvert PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + +/* + +Escaping Strings + + HTDeSlash takes out the invlaid characters in a URL path ELEMENT by converting them + into hex-escaped characters. HTEnSlash does the reverse. + + Each returns a pointer to a newly allocated string which must eventually be freed by + the caller. + + */ +extern char * HTDeSlash PARAMS((CONST char * str)); + +extern char * HTEnSlash PARAMS((CONST char * str)); + +#endif + +/* + + Tim BL + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.c new file mode 100644 index 00000000000..f803920f808 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.c @@ -0,0 +1,189 @@ +/* FILE WRITER HTWrite.c +** =========== +** +*/ +#include "HTUtils.h" +#include "tcp.h" + +#include "HTWriter.h" + +#define BUFFER_SIZE 4096 /* Tradeoff */ + +/*#include <stdio.h> included by HTUtils.h -- FM */ + +#include "LYLeaks.h" + +#define FREE(x) if (x) {free(x); x = NULL;} + +/* HTML Object +** ----------- +*/ + +struct _HTStream { + CONST HTStreamClass * isa; + + int soc; + char *write_pointer; + char buffer[BUFFER_SIZE]; +#ifdef NOT_ASCII + BOOL make_ascii; /* Are we writing to the net? */ +#endif +}; + + +/* Write the buffer out to the socket +** ---------------------------------- +*/ + +PRIVATE void flush ARGS1(HTStream *, me) +{ + char *read_pointer = me->buffer; + char *write_pointer = me->write_pointer; + +#ifdef NOT_ASCII + if (me->make_ascii) { + char * p; + for(p = me->buffer; p < me->write_pointer; p++) + *p = TOASCII(*p); + } +#endif + while (read_pointer < write_pointer) { + int status; + status = NETWRITE(me->soc, me->buffer, /* Put timeout? @@@ */ + write_pointer - read_pointer); + if (status<0) { + if(TRACE) fprintf(stderr, + "HTWrite: Error: write() on socket returns %d !!!\n", status); + return; + } + read_pointer = read_pointer + status; + } + me->write_pointer = me->buffer; +} + + +/*_________________________________________________________________________ +** +** A C T I O N R O U T I N E S +*/ + +/* Character handling +** ------------------ +*/ + +PRIVATE void HTWriter_put_character ARGS2(HTStream *, me, char, c) +{ + if (me->write_pointer == &me->buffer[BUFFER_SIZE]) flush(me); + *me->write_pointer++ = c; +} + + + +/* String handling +** --------------- +** +** Strings must be smaller than this buffer size. +*/ +PRIVATE void HTWriter_put_string ARGS2(HTStream *, me, CONST char*, s) +{ + int l = strlen(s); + if (me->write_pointer + l > &me->buffer[BUFFER_SIZE]) flush(me); + strcpy(me->write_pointer, s); + me->write_pointer = me->write_pointer + l; +} + + +/* Buffer write. Buffers can (and should!) be big. +** ------------ +*/ +PRIVATE void HTWriter_write ARGS3(HTStream *, me, CONST char*, s, int, l) +{ + + CONST char *read_pointer = s; + CONST char *write_pointer = s+l; + + flush(me); /* First get rid of our buffer */ + + while (read_pointer < write_pointer) { + int status = NETWRITE(me->soc, (char *)read_pointer, + write_pointer - read_pointer); + if (status<0) { + if(TRACE) fprintf(stderr, + "HTWriter_write: Error on socket output stream!!!\n"); + return; + } + read_pointer = read_pointer + status; + } +} + + + + +/* Free an HTML object +** ------------------- +** +** Note that the SGML parsing context is freed, but the created object is not, +** as it takes on an existence of its own unless explicitly freed. +*/ +PRIVATE void HTWriter_free ARGS1(HTStream *, me) +{ + flush(me); + NETCLOSE(me->soc); + FREE(me); +} + +PRIVATE void HTWriter_abort ARGS2(HTStream *, me, HTError, e GCC_UNUSED) +{ + HTWriter_free(me); +} + + +/* Structured Object Class +** ----------------------- +*/ +PRIVATE CONST HTStreamClass HTWriter = /* As opposed to print etc */ +{ + "SocketWriter", + HTWriter_free, + HTWriter_abort, + HTWriter_put_character, HTWriter_put_string, + HTWriter_write +}; + + +/* Subclass-specific Methods +** ------------------------- +*/ + +PUBLIC HTStream* HTWriter_new ARGS1(int, soc) +{ + HTStream* me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) outofmem(__FILE__, "HTML_new"); + me->isa = &HTWriter; + +#ifdef NOT_ASCII + me->make_ascii = NO; +#endif + me->soc = soc; + me->write_pointer = me->buffer; + return me; +} + +/* Subclass-specific Methods +** ------------------------- +*/ + +PUBLIC HTStream* HTASCIIWriter ARGS1(int, soc) +{ + HTStream* me = (HTStream*)malloc(sizeof(*me)); + if (me == NULL) outofmem(__FILE__, "HTML_new"); + me->isa = &HTWriter; + +#ifdef NOT_ASCII + me->make_ascii = YES; +#endif + me->soc = soc; + me->write_pointer = me->buffer; + return me; +} + diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.h new file mode 100644 index 00000000000..9fa5f8c6191 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.h @@ -0,0 +1,28 @@ +/* */ + +/* Unix File or Socket Writer HTWriter.c +** -------------------------- +** +** This version of the stream object just writes to a socket. +** The socket is assumed open and closed afterward. +** +** There are two versions (identical on ASCII machines) +** one of which converts to ASCII on output. +** +** Bugs: +** strings written must be less than buffer size. +*/ + +#ifndef HTWRITE_H +#define HTWRITE_H + +#include "HTStream.h" + +extern HTStream * HTWriter_new PARAMS((int soc)); + +extern HTStream * HTASCIIWriter PARAMS((int soc)); + +#endif +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HText.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/HText.h new file mode 100644 index 00000000000..64000eab7d0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HText.h @@ -0,0 +1,265 @@ +/* Rich Hypertext object for libWWW + RICH HYPERTEXT OBJECT + + */ + +/* + + This is the C interface to the Objective-C (or whatever) Style-oriented HyperText + class. It is used when a style-oriented text object is available or craeted in order to + display hypertext. + + */ +#ifndef HTEXT_H +#define HTEXT_H +#include "HTAnchor.h" +#include "HTStyle.h" +#include "HTStream.h" +#include "SGML.h" + +#ifdef SHORT_NAMES +#define HTMainText HTMaText +#define HTMainAnchor HtMaAnch +#define HText_new HTHTNew +#define HText_new2 HTHTNew2 +#define HText_free HTHTFree +#define HText_beginAppend HTHTBeAp +#define HText_endAppend HTHTEnAp +#define HText_setStyle HTHTSeSt +#define HText_appendCharacter HTHTApCh +#define HText_appendImage HTHTApIm +#define HText_appendText HTHTApTe +#define HText_appendParagraph HTHTApPa +#define HText_beginAnchor HTHTBeAn +#define HText_endAnchor HTHTEnAn +#define HText_dump HTHTDump +#define HText_nodeAnchor HTHTNoAn +#define HText_select HTHTSele +#define HText_selectAnchor HTHTSeAn +#define HText_applyStyle HTHTApSt +#define HText_updateStyle HTHTUpSt +#define HText_selectionStyle HTHTStyl +#define HText_replaceSel HTHTRepl +#define HText_applyToSimilar HTHTApTo +#define HText_selectUnstyled HTHTSeUn +#define HText_unlinkSelection HTHTUnSe +#define HText_linkSelTo HTHTLiSe +#define HText_referenceSelected HTHTRefS +#endif + +#ifndef THINK_C +#ifndef HyperText /* Objective C version defined HyperText */ +typedef struct _HText HText; /* Normal Library */ +#endif +#else +class CHyperText; /* Mac Think-C browser hook */ +typedef CHyperText HText; +#endif + +extern HText * HTMainText; /* Pointer to current main text */ +extern HTParentAnchor * HTMainAnchor; /* Pointer to current text's anchor */ + +/* + +Creation and deletion + + HTEXT_NEW: CREATE HYPERTEXT OBJECT + + There are several methods depending on how much you want to specify. The output stream + is used with objects which need to output the hypertext to a stream. The structure is + for objects which need to refer to the structure which is kep by the creating stream. + + */ + extern HText * HText_new PARAMS((HTParentAnchor * anchor)); + + extern HText * HText_new2 PARAMS((HTParentAnchor * anchor, + HTStream * output_stream)); + + extern HText * HText_new3 PARAMS((HTParentAnchor * anchor, + HTStream * output_stream, + HTStructured * structure)); + +/* + + FREE HYPERTEXT OBJECT + + */ +extern void HText_free PARAMS((HText * me)); + + +/* + +Object Building methods + + These are used by a parser to build the text in an object HText_beginAppend must be + called, then any combination of other append calls, then HText_endAppend. This allows + optimised handling using buffers and caches which are flushed at the end. + + */ +extern void HText_beginAppend PARAMS((HText * text)); + +extern void HText_endAppend PARAMS((HText * text)); + +/* + + SET THE STYLE FOR FUTURE TEXT + + */ + +extern void HText_setStyle PARAMS((HText * text, HTStyle * style)); + +/* + + ADD ONE CHARACTER + + */ +extern void HText_appendCharacter PARAMS((HText * text, char ch)); + +/* + + ADD A ZERO-TERMINATED STRING + + */ + +extern void HText_appendText PARAMS((HText * text, CONST char * str)); + +/* + + NEW PARAGRAPH + + and similar things + + */ +extern void HText_appendParagraph PARAMS((HText * text)); + +extern void HText_appendLineBreak PARAMS((HText * text)); + +extern void HText_appendHorizontalRule PARAMS((HText * text)); + + + +/* + + START/END SENSITIVE TEXT + + */ + +/* + + The anchor object is created and passed to HText_beginAnchor. The senstive text is + added to the text object, and then HText_endAnchor is called. Anchors may not be + nested. + + */ +extern int HText_beginAnchor PARAMS(( + HText * text, + BOOL underline, + HTChildAnchor * anc)); +extern void HText_endAnchor PARAMS((HText * text, int number)); + + +/* + + APPEND AN INLINE IMAGE + + The image is handled by the creation of an anchor whose destination is the image + document to be included. The semantics is the intended inline display of the image. + + An alternative implementation could be, for example, to begin an anchor, append the + alternative text or "IMAGE", then end the anchor. This would simply generate some text + linked to the image itself as a separate document. + + */ +extern void HText_appendImage PARAMS(( + HText * text, + HTChildAnchor * anc, + CONST char * alternative_text, + int alignment, + BOOL isMap)); + +/* + + DUMP DIAGNOSTICS TO STDERR + + */ + +extern void HText_dump PARAMS((HText * me)); + +/* + + RETURN THE ANCHOR ASSOCIATED WITH THIS NODE + + */ +extern HTParentAnchor * HText_nodeAnchor PARAMS((HText * me)); + + +/* + +Browsing functions + + */ + + +/* + + BRING TO FRONT AND HIGHLIGHT IT + + */ + + +extern BOOL HText_select PARAMS((HText * text)); +extern BOOL HText_selectAnchor PARAMS((HText * text, HTChildAnchor* anchor)); + +/* + +Editing functions + + These are called from the application. There are many more functions not included here + from the orginal text object. These functions NEED NOT BE IMPLEMENTED in a browser + which cannot edit. + + */ +/* Style handling: +*/ +/* Apply this style to the selection +*/ +extern void HText_applyStyle PARAMS((HText * me, HTStyle *style)); + +/* Update all text with changed style. +*/ +extern void HText_updateStyle PARAMS((HText * me, HTStyle *style)); + +/* Return style of selection +*/ +extern HTStyle * HText_selectionStyle PARAMS(( + HText * me, + HTStyleSheet* sheet)); + +/* Paste in styled text +*/ +extern void HText_replaceSel PARAMS((HText * me, + CONST char *aString, + HTStyle* aStyle)); + +/* Apply this style to the selection and all similarly formatted text +** (style recovery only) +*/ +extern void HTextApplyToSimilar PARAMS((HText * me, HTStyle *style)); + +/* Select the first unstyled run. +** (style recovery only) +*/ +extern void HTextSelectUnstyled PARAMS((HText * me, HTStyleSheet *sheet)); + + +/* Anchor handling: +*/ +extern void HText_unlinkSelection PARAMS((HText * me)); +extern HTAnchor * HText_referenceSelected PARAMS((HText * me)); +extern HTAnchor * HText_linkSelTo PARAMS((HText * me, HTAnchor* anchor)); + + +#endif /* HTEXT_H */ +/* + + end */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/LYLeaks.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/LYLeaks.h new file mode 100644 index 00000000000..b181cb7fb0c --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/LYLeaks.h @@ -0,0 +1,183 @@ +#ifndef __LYLEAKS_H +/* + * Avoid include redundancy + * Include only if finding memory leaks. + */ +#define __LYLEAKS_H + +/* +** Copyright (c) 1994, University of Kansas, All Rights Reserved +** +** Include File: LYLeaks.h +** Purpose: Header to convert requests for allocation to Lynx +** custom functions to track memory leaks. +** Remarks/Portability/Dependencies/Restrictions: +** For the stdlib.h allocation functions to be overriden by the +** Lynx memory tracking functions all modules allocating, +** freeing, or resizing memory must have LY_FIND_LEAKS +** defined before including this file. +** This header file should be included in every source file which +** does any memory manipulation through use of the +** stdlib.h memory functions. +** For proper reporting of memory leaks, the function LYLeaks +** should be registered for execution by atexit as the +** very first executable statement in main. +** This code is slow and should not be used except in debugging +** circumstances (don't define LY_FIND_LEAKS). +** If you are using LY_FIND_LEAKS and don't want the LYLeak* +** memory functions to be used in a certain file, +** define NO_MEMORY_TRACKING before including this file. +** The only safe way to call the LYLeak* functions is to use +** the below macros because they depend on the static +** string created by __FILE__ to not be dynamic in +** nature (don't free it and assume will exist at all +** times during execution). +** Revision History: +** 05-26-94 created for Lynx 2-3-1, Garrett Arch Blythe +** 10-30-97 modified to handle StrAllocCopy() and +** StrAllocCat(). - KW & FM +*/ + +/* +** Required includes +*/ +#include <stdlib.h> +#include "HTUtils.h" + +/* +** Constant defines +*/ +#define MAX_CONTENT_LENGTH 50 +#ifdef VMS +#define LEAKAGE_SINK "sys$login:Lynx.leaks" +#else +#define LEAKAGE_SINK "Lynx.leaks" +#endif /* VMS */ + +/* +** Data structures +*/ +typedef struct SourceLocation_tag { + /* + * The file name and line number of where an event took place. + */ + CONST char *cp_FileName; + short ssi_LineNumber; +} +SourceLocation; + +typedef struct AllocationList_tag { + /* + * A singly linked list. + */ + struct AllocationList_tag *ALp_Next; + + /* + * The memory pointer allocated. + * If set to NULL, then an invalid request was made. + * The invalid pointer also. + */ + void *vp_Alloced; + void *vp_BadRequest; + + /* + * The size in bytes of the allocated memory. + */ + size_t st_Bytes; + + /* + * The source location of specific event (calloc, malloc, free). + * realloc kept separate since will track last realloc on pointer. + */ + SourceLocation SL_memory; + SourceLocation SL_realloc; +} AllocationList; + +/* +** Global variable declarations +*/ + +/* +** Macros +*/ +#if defined(LY_FIND_LEAKS) && !defined(NO_MEMORY_TRACKING) +/* +** Only use these macros if we are to track memory allocations. +** The reason for using a macro instead of a define is that we want +** to track where the initial allocation took place or where +** the last reallocation took place. +** Track where the allocation took place by the __FILE__ and __LINE__ +** defines which are automatic to the compiler. +*/ +#ifdef malloc +#undef malloc +#endif /* malloc */ +#define malloc(st_bytes) LYLeakMalloc(st_bytes, __FILE__, __LINE__) + +#ifdef calloc +#undef calloc +#endif /* calloc */ +#define calloc(st_number, st_bytes) LYLeakCalloc(st_number, st_bytes, \ + __FILE__, __LINE__) + +#ifdef realloc +#undef realloc +#endif /* realloc */ +#define realloc(vp_alloced, st_newbytes) LYLeakRealloc(vp_alloced, \ + st_newbytes, __FILE__, __LINE__) + +#ifdef free +#undef free +#endif /* free */ +#define free(vp_alloced) LYLeakFree(vp_alloced, __FILE__, __LINE__) + +/* +** Added the following two defines to track Lynx's frequent use +** of those macros. - KW 1997-10-12 +*/ +#ifdef StrAllocCopy +#undef StrAllocCopy +#endif /* StrAllocCopy */ +#define StrAllocCopy(dest, src) LYLeakSACopy(&(dest), src, __FILE__, __LINE__) +#ifdef StrAllocCat +#undef StrAllocCat +#endif /* StrAllocCat */ +#define StrAllocCat(dest, src) LYLeakSACat(&(dest), src, __FILE__, __LINE__) + +#endif /* LY_FIND_LEAKS && !NO_MEMORY_TRACKING */ + +/* +** Function declarations +** See the appropriate source file for usage. +*/ +extern void LYLeaks NOPARAMS; +extern void *LYLeakMalloc PARAMS(( + size_t st_bytes, + CONST char * cp_File, + CONST short ssi_Line)); +extern void *LYLeakCalloc PARAMS(( + size_t st_number, + size_t st_bytes, + CONST char * cp_File, + CONST short ssi_Line)); +extern void *LYLeakRealloc PARAMS(( + void * vp_alloced, + size_t st_newbytes, + CONST char * cp_File, + CONST short ssi_Line)); +extern void LYLeakFree PARAMS(( + void * vp_alloced, + CONST char * cp_File, + CONST short ssi_Line)); +extern char * LYLeakSACopy PARAMS(( + char ** dest, + CONST char * src, + CONST char * cp_File, + CONST short ssi_Line)); +extern char * LYLeakSACat PARAMS(( + char ** dest, + CONST char * src, + CONST char * cp_File, + CONST short ssi_Line)); + +#endif /* __LYLEAKS_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/LYexit.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/LYexit.h new file mode 100644 index 00000000000..7007d615ef6 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/LYexit.h @@ -0,0 +1,58 @@ +#ifndef __LYEXIT_H +/* + * Avoid include redundancy + */ +#define __LYEXIT_H + +/* + * Copyright (c) 1994, University of Kansas, All Rights Reserved + * + * Include File: LYexit.h + * Purpose: Provide an atexit function for libraries without such. + * Remarks/Portability/Dependencies/Restrictions: + * Include this header in every file that you have an exit or + * atexit statment. + * Revision History: + * 06-15-94 created Lynx 2-3-1 Garrett Arch Blythe + */ + +/* + * Required includes + */ +#include <stdlib.h> +#include "HTUtils.h" + +/* + * Constant defines + */ +#ifdef _WINDOWS +#undef exit +#endif /* _WINDOWS */ + +#define exit LYexit +#define atexit LYatexit +#define ATEXITSIZE 32 + +/* + * Data structures + */ + +/* + * Global variable declarations + */ + +/* + * Macros + */ + +/* + * Function declarations + */ +extern void LYexit PARAMS((int status)); +#ifdef __STDC__ +extern int LYatexit(void (*function)(void)); +#else +extern int LYatexit(); +#endif /* __STDC__ */ + +#endif /* __LYEXIT_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.c new file mode 100644 index 00000000000..713bb905811 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.c @@ -0,0 +1,3576 @@ +/* General SGML Parser code SGML.c +** ======================== +** +** This module implements an HTStream object. To parse an +** SGML file, create this object which is a parser. The object +** is (currently) created by being passed a DTD structure, +** and a target HTStructured oject at which to throw the parsed stuff. +** +** 6 Feb 93 Binary seraches used. Intreface modified. +*/ + +#include "HTUtils.h" +#include "tcp.h" /* For FROMASCII */ + +/* Remove the following to disable the experimental HTML DTD parsing. + Currently only used in this source file. - kw */ + +#ifndef NO_EXTENDED_HTMLDTD +#define EXTENDED_HTMLDTD +#endif + +#include "SGML.h" +#include "HTMLDTD.h" +#include "HTCJK.h" +#include "UCMap.h" +#include "UCDefs.h" +#include "UCAux.h" + +#include <ctype.h> +/*#include <stdio.h> included in HTUtils.h -- FM */ +#include "HTChunk.h" + +#include "LYCharSets.h" +#include "LYLeaks.h" + +#define INVALID (-1) + +#define FREE(x) if (x) {free(x); x = NULL;} + +PUBLIC HTCJKlang HTCJK = NOCJK; /* CJK enum value. */ +PUBLIC BOOL HTPassEightBitRaw = FALSE; /* Pass 161-172,174-255 raw. */ +PUBLIC BOOL HTPassEightBitNum = FALSE; /* Pass ^ numeric entities raw. */ +PUBLIC BOOL HTPassHighCtrlRaw = FALSE; /* Pass 127-160,173, raw. */ +PUBLIC BOOL HTPassHighCtrlNum = FALSE; /* Pass €-Ÿ raw. */ + +extern int LYlowest_eightbit[]; + +/* The State (context) of the parser +** +** This is passed with each call to make the parser reentrant +** +*/ + +#define MAX_ATTRIBUTES 36 /* Max number of attributes per element */ + + +/* Element Stack +** ------------- +** This allows us to return down the stack reselcting styles. +** As we return, attribute values will be garbage in general. +*/ +typedef struct _HTElement HTElement; +struct _HTElement { + HTElement * next; /* Previously nested element or 0 */ + HTTag* tag; /* The tag at this level */ +}; + + +/* Internal Context Data Structure +** ------------------------------- +*/ +struct _HTStream { + + CONST HTStreamClass * isa; /* inherited from HTStream */ + + CONST SGML_dtd *dtd; + HTStructuredClass *actions; /* target class */ + HTStructured *target; /* target object */ + + HTTag *current_tag; + CONST HTTag *unknown_tag; + BOOL inSELECT; + int current_attribute_number; + HTChunk *string; + HTElement *element_stack; + enum sgml_state { S_text, S_litteral, + S_tag, S_tag_gap, S_attr, S_attr_gap, S_equals, S_value, + S_ero, S_cro, S_incro, + S_exclamation, S_comment, S_doctype, S_marked, + S_sgmlent, S_sgmlele, S_sgmlatt, + S_squoted, S_dquoted, S_end, S_entity, + S_esc, S_dollar, S_paren, S_nonascii_text, + S_dollar_paren, + S_esc_sq, S_dollar_sq, S_paren_sq, S_nonascii_text_sq, + S_dollar_paren_sq, + S_esc_dq, S_dollar_dq, S_paren_dq, S_nonascii_text_dq, + S_dollar_paren_dq, + S_in_kanji, S_junk_tag} state; +#ifdef CALLERDATA + void * callerData; +#endif /* CALLERDATA */ + BOOL present[MAX_ATTRIBUTES]; /* Flags: attribute is present? */ + char * value[MAX_ATTRIBUTES]; /* malloc'd strings or NULL if none */ + + BOOL lead_exclamation; + BOOL first_dash; + BOOL end_comment; + BOOL doctype_bracket; + BOOL first_bracket; + BOOL second_bracket; + BOOL isHex; + + HTParentAnchor * node_anchor; + LYUCcharset * inUCI; /* pointer to anchor UCInfo */ + int inUCLYhndl; /* charset we are fed */ + LYUCcharset * outUCI; /* anchor UCInfo for target */ + int outUCLYhndl; /* charset for target */ + char utf_count; + UCode_t utf_char; + char utf_buf[8]; + char * utf_buf_p; + UCTransParams T; + int current_tag_charset; /* charset to pass attributes */ + + char * recover; + int recover_index; + char * include; + int include_index; + char * url; + char * csi; + int csi_index; +} ; + +PRIVATE void set_chartrans_handling ARGS3( + HTStream *, context, + HTParentAnchor *, anchor, + int, chndl) +{ + if (chndl < 0) { + /* + ** Nothing was set for the parser in earlier stages, + ** so the HTML parser's UCLYhndl should still be it's + ** default. - FM + */ + chndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_STRUCTURED); + if (chndl < 0) + /* + ** That wasn't set either, so seek the HText default. - FM + */ + chndl = HTAnchor_getUCLYhndl(anchor, UCT_STAGE_HTEXT); + if (chndl < 0) + /* + ** That wasn't set either, so assume the current display + ** character set. - FM + */ + chndl = current_char_set; + /* + ** Try to set the HText and HTML stages' chartrans info + ** with the default lock level (will not be changed if + ** it was set previously with a higher lock level). - FM + */ + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_STRUCTURED, + UCT_SETBY_DEFAULT); + /* + ** Get the chartrans info for output to the HTML parser. - FM + */ + context->outUCI = HTAnchor_getUCInfoStage(anchor, + UCT_STAGE_STRUCTURED); + context->outUCLYhndl = HTAnchor_getUCLYhndl(context->node_anchor, + UCT_STAGE_STRUCTURED); + } + /* + ** Set the in->out transformation parameters. - FM + */ + UCSetTransParams(&context->T, + context->inUCLYhndl, context->inUCI, + context->outUCLYhndl, context->outUCI); + /* + ** This is intended for passing the SGML parser's input + ** charset as an argument in each call to the HTML + ** parser's start tag function, but it would be better + ** to call a Lynx_HTML_parser function to set an element + ** in its HTStructured object, itself, if this were + ** needed. - FM + */ + if (HTCJK != NOCJK) { + context->current_tag_charset = -1; + } else if (context->T.transp) { + context->current_tag_charset = context->inUCLYhndl; + } else if (context->T.decode_utf8) { + context->current_tag_charset = context->inUCLYhndl; + } else if (context->T.do_8bitraw || + context->T.use_raw_char_in) { + context->current_tag_charset = context->inUCLYhndl; + } else if (context->T.output_utf8 || + context->T.trans_from_uni) { + context->current_tag_charset = UCGetLYhndl_byMIME("utf-8"); + } else { + context->current_tag_charset = 0; + } +} + +PRIVATE void change_chartrans_handling ARGS1( + HTStream *, context) +{ + int new_LYhndl = HTAnchor_getUCLYhndl(context->node_anchor, + UCT_STAGE_PARSER); + if (new_LYhndl != context->inUCLYhndl && + new_LYhndl >= 0) { + /* + * Something changed. but ignore if a META wants an unknown charset. + */ + LYUCcharset * new_UCI = HTAnchor_getUCInfoStage(context->node_anchor, + UCT_STAGE_PARSER); + if (new_UCI) { + LYUCcharset * next_UCI = HTAnchor_getUCInfoStage( + context->node_anchor, UCT_STAGE_STRUCTURED + ); + int next_LYhndl = HTAnchor_getUCLYhndl( + context->node_anchor, UCT_STAGE_STRUCTURED + ); + context->inUCI = new_UCI; + context->inUCLYhndl = new_LYhndl; + context->outUCI = next_UCI; + context->outUCLYhndl = next_LYhndl; + set_chartrans_handling(context, + context->node_anchor, next_LYhndl); + } + } +} + +#define PUTC(ch) ((*context->actions->put_character)(context->target, ch)) +#define PUTUTF8(code) (UCPutUtf8_charstring((HTStream *)context->target, \ + (putc_func_t*)(context->actions->put_character), code)) + +extern BOOL historical_comments; +extern BOOL minimal_comments; +extern BOOL soft_dquotes; + +#ifdef USE_COLOR_STYLE +#include "AttrList.h" +extern char class_string[TEMPSTRINGSIZE]; +int current_is_class=0; +#endif + +/* Handle Attribute +** ---------------- +*/ +/* PUBLIC CONST char * SGML_default = ""; ?? */ + +PRIVATE void handle_attribute_name ARGS2( + HTStream *, context, + CONST char *, s) +{ + + HTTag * tag = context->current_tag; + attr * attributes = tag->attributes; + int high, low, i, diff; + + /* + ** Ignore unknown tag. - KW + */ + if (tag == context->unknown_tag) { + return; + } + + /* + ** Binary search for attribute name. + */ + for (low = 0, high = tag->number_of_attributes; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { + i = (low + (high-low)/2); + diff = strcasecomp(attributes[i].name, s); + if (diff == 0) { /* success: found it */ + context->current_attribute_number = i; + context->present[i] = YES; + FREE(context->value[i]); +#ifdef USE_COLOR_STYLE + current_is_class=(!strcasecomp("class", s)); + if (TRACE) + fprintf(stderr, "SGML: found attribute %s, %d\n", s, current_is_class); +#endif + return; + } /* if */ + + } /* for */ + + if (TRACE) + fprintf(stderr, "SGML: Unknown attribute %s for tag %s\n", + s, context->current_tag->name); + context->current_attribute_number = INVALID; /* Invalid */ +} + + +/* Handle attribute value +** ---------------------- +*/ +PRIVATE void handle_attribute_value ARGS2( + HTStream *, context, + CONST char *, s) +{ + if (context->current_attribute_number != INVALID) { + StrAllocCopy(context->value[context->current_attribute_number], s); +#ifdef USE_COLOR_STYLE + if (current_is_class) + { + strncpy (class_string, s, TEMPSTRINGSIZE); + if (TRACE) + fprintf(stderr, "SGML: class is '%s'\n", s); + } + else + { + if (TRACE) + fprintf(stderr, "SGML: attribute value is '%s'\n", s); + } +#endif + } else { + if (TRACE) + fprintf(stderr, "SGML: Attribute value %s ignored\n", s); + } + context->current_attribute_number = INVALID; /* can't have two assignments! */ +} + + +/* +** Translate some Unicodes to Lynx special codes and output them. +** Special codes - ones those output depend on parsing. +** +** Additional issue, like handling bidirectional text if nesseccery +** may be called from here: zwnj (8204), zwj (8205), lrm (8206), rlm (8207) +** - currently they are passed to def7_uni.tbl as regular characters. +** +*/ +PRIVATE BOOL put_special_unicodes ARGS2( + HTStream *, context, + UCode_t, code) +{ + if (code == 160) { + /* + ** Use Lynx special character for nbsp. + */ + PUTC(HT_NON_BREAK_SPACE); + } else if (code == 173) { + /* + ** Use Lynx special character for shy. + */ + PUTC(LY_SOFT_HYPHEN); + } else if (code == 8194 || code == 8195 || code == 8201) { + /* + ** Use Lynx special character for ensp, emsp or thinsp. + ** + ** Originally, Lynx use space '32' as word delimiter and omits this + ** space at end of line if word is wrapped to the next line. There + ** are several other spaces in the Unicode repertoire and we should + ** teach Lynx to understand them, not only as regular characters but + ** in the context of line wrapping. Unfortunately, if we use + ** HT_EM_SPACE we override the chartrans tables for those spaces + ** (e.g., emsp= double space) with a single '32' for all (but do line + ** wrapping more fancy). In the future we need HT_SPACE with a + ** transferred parameter (Unicode number) which falls back to + ** chartrans if line wrapping is not the case. + ** + */ + PUTC(HT_EM_SPACE); +#ifdef NOTUSED_FOTEMODS + } else if (code == 8211 || code == 8212) { + /* + ** Use ASCII hyphen for ndash/endash or mdash/emdash. + */ + PUTC('-'); +#endif + } else { + /* + ** Return NO if nothing done. + */ + return NO; + } + /* + ** We have handled it. + */ + return YES; +} + +/* Handle entity +** ------------- +** +** On entry, +** s contains the entity name zero terminated +** Bugs: +** If the entity name is unknown, the terminator is treated as +** a printable non-special character in all cases, even if it is '<' +** Bug-fix: +** Modified SGML_character() so we only come here with terminator +** as '\0' and check a FoundEntity flag. -- Foteos Macrides +** +** Modified more (for use with Lynx character translation code): +*/ +PRIVATE char replace_buf [64]; /* buffer for replacement strings */ +PRIVATE BOOL FoundEntity = FALSE; + +#define IncludesLatin1Enc \ + (context->outUCLYhndl == 0 || \ + (context->outUCI && \ + (context->outUCI->enc & (UCT_CP_SUPERSETOF_LAT1)))) + +PRIVATE void handle_entity ARGS2( + HTStream *, context, + char, term) +{ + UCode_t code; + long uck; + CONST char *p; + CONST char *s = context->string->data; +#ifdef NOTUSED_FOTEMODS + int high, low, i, diff; +#endif + + + /* + ** Handle all entities normally. - FM + */ + FoundEntity = FALSE; + if ((code = HTMLGetEntityUCValue(s)) != 0) { + /* + ** We got a Unicode value for the entity name. + ** Check for special Unicodes. - FM + */ + if (put_special_unicodes(context, code)) { + FoundEntity = TRUE; + return; + } + /* + ** Seek a translation from the chartrans tables. + */ + if ((uck = UCTransUniChar(code, context->outUCLYhndl)) >= 32 && + uck < 256 && + (uck < 127 || + uck >= LYlowest_eightbit[context->outUCLYhndl])) { + PUTC(FROMASCII((char)uck)); + FoundEntity = TRUE; + return; + } else if ((uck == -4 || + (context->T.repl_translated_C0 && + uck > 0 && uck < 32)) && + /* + ** Not found; look for replacement string. + */ + (uck = UCTransUniCharStr(replace_buf, 60, code, + context->outUCLYhndl, 0) >= 0)) { + for (p = replace_buf; *p; p++) + PUTC(*p); + FoundEntity = TRUE; + return; + } + /* + ** If we're displaying UTF-8, try that now. - FM + */ + if (context->T.output_utf8 && PUTUTF8(code)) { + FoundEntity = TRUE; + return; + } + /* + ** If it's safe ASCII, use it. - FM + */ + if (code >= 32 && code < 127) { + PUTC(FROMASCII((char)code)); + FoundEntity = TRUE; + return; + } +#ifdef NOTUSED_FOTEMODS + /* + ** If the value is greater than 255 and we do not + ** have the "7-bit approximations" as our output + ** character set (in which case we did it already) + ** seek a translation for that. - FM + */ + if ((chk = ((code > 255) && + context->outUCLYhndl != + UCGetLYhndl_byMIME("us-ascii"))) && + (uck = UCTransUniChar(code, + UCGetLYhndl_byMIME("us-ascii")))>= 32 && + uck < 127) { + /* + ** Got an ASCII character (yippey). - FM + */ + PUTC(((char)(uck & 0xff))); + FoundEntity = TRUE; + return; + } else if ((chk && uck == -4) && + (uck = UCTransUniCharStr(replace_buf, + 60, code, + UCGetLYhndl_byMIME("us-ascii"), + 0) >= 0)) { + /* + ** Got a replacement string (yippey). - FM + */ + for (p = replace_buf; *p; p++) + PUTC(*p); + FoundEntity = TRUE; + return; + } + } + /* + ** Ignore zwnj (8204) and zwj (8205), if we get to here. + ** Note that zwnj may have been handled as <WBR> + ** by the calling function. - FM + */ + if (!strcmp(s, "zwnj") || + !strcmp(s, "zwj")) { + if (TRACE) { + fprintf(stderr, "handle_entity: Ignoring '%s'.\n", s); + } + FoundEntity = TRUE; + return; + } + + /* + ** Ignore lrm (8206), and rln (8207), if we get to here. - FM + */ + if (!strcmp(s, "lrm") || + !strcmp(s, "rlm")) { + if (TRACE) { + fprintf(stderr, "handle_entity: Ignoring '%s'.\n", s); + } + FoundEntity = TRUE; + return; + } + + /* + ** We haven't succeeded yet, so try the old LYCharSets + ** arrays for translation strings. - FM + */ + for (low = 0, high = context->dtd->number_of_entities; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { /* Binary search */ + i = (low + (high-low)/2); + diff = strcmp(entities[i], s); /* Case sensitive! */ + if (diff == 0) { /* success: found it */ + for (p = LYCharSets[context->outUCLYhndl][i]; *p; p++) { + PUTC(*p); + } + FoundEntity = TRUE; + return; + } +#endif + } + + /* + ** If entity string not found, display as text. + */ + if (TRACE) + fprintf(stderr, "SGML: Unknown entity '%s'\n", s); + PUTC('&'); + for (p = s; *p; p++) { + PUTC(*p); + } + if (term != '\0') + PUTC(term); +} + + +/* Handle comment +** -------------- +*/ +PRIVATE void handle_comment ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Comment:\n<%s>\n", s); + + if (context->csi == NULL && + strncmp(s, "!--#", 4) == 0 && + LYCheckForCSI(context->node_anchor, (char **)&context->url) == TRUE) { + LYDoCSI(context->url, s, (char **)&context->csi); + } + + return; +} + + +/* Handle identifier +** ----------------- +*/ +PRIVATE void handle_identifier ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Identifier\n<%s>\n", s); + + return; +} + + +/* Handle doctype +** -------------- +*/ +PRIVATE void handle_doctype ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Doctype\n<%s>\n", s); + + return; +} + + +/* Handle marked +** ------------- +*/ +PRIVATE void handle_marked ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Marked Section:\n<%s>\n", s); + + return; +} + + +/* Handle sgmlent +** -------------- +*/ +PRIVATE void handle_sgmlent ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Entity Declaration:\n<%s>\n", s); + + return; +} + + +/* Handle sgmlent +** -------------- +*/ +PRIVATE void handle_sgmlele ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Element Declaration:\n<%s>\n", s); + + return; +} + + +/* Handle sgmlatt +** -------------- +*/ +PRIVATE void handle_sgmlatt ARGS1( + HTStream *, context) +{ + CONST char *s = context->string->data; + + if (TRACE) + fprintf(stderr, "SGML Attribute Declaration:\n<%s>\n", s); + + return; +} + +#ifdef EXTENDED_HTMLDTD + +PRIVATE BOOL element_valid_within ARGS3( + HTTag *, new_tag, + HTTag *, stacked_tag, + BOOL, direct) +{ + TagClass usecontains, usecontained; + if (!stacked_tag || !new_tag) + return YES; + usecontains = (direct ? stacked_tag->contains : stacked_tag->icontains); + usecontained = (direct ? new_tag->contained : new_tag->icontained); + if (new_tag == stacked_tag) + return ((Tgc_same & usecontains) && + (Tgc_same & usecontained)); + else + return ((new_tag->tagclass & usecontains) && + (stacked_tag->tagclass & usecontained)); +} + +extern BOOL New_DTD; + +typedef enum { + close_NO = 0, + close_error = 1, + close_valid = 2 +} canclose_t; + +PRIVATE canclose_t can_close ARGS2( + HTTag *, new_tag, + HTTag *, stacked_tag) +{ + if (!stacked_tag) + return close_NO; + if (stacked_tag->flags & Tgf_endO) + return close_valid; + else if (new_tag == stacked_tag) + return ((Tgc_same & new_tag->canclose) ? close_error : close_NO); + else + return ((stacked_tag->tagclass & new_tag->canclose) ? + close_error : close_NO); +} +PRIVATE void do_close_stacked ARGS1( + HTStream *, context) +{ + HTElement * stacked = context->element_stack; + if (!stacked) + return; /* stack was empty */ + if (context->inSELECT && !strcasecomp(stacked->tag->name, "SELECT")) { + context->inSELECT = FALSE; + } + (*context->actions->end_element)( + context->target, + stacked->tag - context->dtd->tags, + (char **)&context->include); + context->element_stack = stacked->next; + FREE(stacked); +} +PRIVATE int is_on_stack ARGS2( + HTStream *, context, + HTTag *, old_tag) +{ + HTElement * stacked = context->element_stack; + int i = 1; + for (; stacked; stacked = stacked->next, i++) { + if (stacked->tag == old_tag) + return i; + } + return 0; +} +#endif /* EXTENDED_HTMLDTD */ + +/* End element +** ----------- +*/ +PRIVATE void end_element ARGS2( + HTStream *, context, + HTTag *, old_tag) +{ +#ifdef EXTENDED_HTMLDTD + + BOOL extra_action_taken = NO; + canclose_t canclose_check = close_valid; + int stackpos = is_on_stack(context, old_tag); + + if (New_DTD) { + while (canclose_check != close_NO && + context->element_stack && + (stackpos > 1 || (!extra_action_taken && stackpos == 0))) { + canclose_check = can_close(old_tag, context->element_stack->tag); + if (canclose_check != close_NO) { + if (TRACE) + fprintf(stderr, "SGML: End </%s> \t<- %s end </%s>\n", + context->element_stack->tag->name, + canclose_check == close_valid ? "supplied," : "forced by", + old_tag->name); + do_close_stacked(context); + extra_action_taken = YES; + stackpos = is_on_stack(context, old_tag); + } else { + if (TRACE) + fprintf(stderr, "SGML: Still open %s \t<- invalid end </%s>\n", + context->element_stack->tag->name, + old_tag->name); + return; + } + } + + if (stackpos == 0 && old_tag->contents != SGML_EMPTY) { + if (TRACE) + fprintf(stderr, "SGML: Still open %s, no open %s for </%s>\n", + context->element_stack ? + context->element_stack->tag->name : "none", + old_tag->name, + old_tag->name); + return; + } + if (stackpos > 1) { + if (TRACE) + fprintf(stderr, "SGML: Nesting <%s>...<%s> \t<- invalid end </%s>\n", + old_tag->name, + context->element_stack->tag->name, + old_tag->name); + return; + } + } + /* Now let the non-extended code deal with the rest. - kw */ + +#endif /* EXTENDED_HTMLDTD */ + + /* + ** If we are in a SELECT block, ignore anything + ** but a SELECT end tag. - FM + */ + if (context->inSELECT) { + if (!strcasecomp(old_tag->name, "SELECT")) { + /* + ** Turn off the inSELECT flag and fall through. - FM + */ + context->inSELECT = FALSE; + } else { + /* + ** Ignore the end tag. - FM + */ + if (TRACE) { + fprintf(stderr, + "SGML: Ignoring end tag </%s> in SELECT block.\n", + old_tag->name); + } + return; + } + } + /* + ** Handle the end tag. - FM + */ + if (TRACE) + fprintf(stderr, "SGML: End </%s>\n", old_tag->name); + if (old_tag->contents == SGML_EMPTY) { + if (TRACE) + fprintf(stderr, "SGML: Illegal end tag </%s> found.\n", + old_tag->name); + return; + } +#ifdef WIND_DOWN_STACK + while (context->element_stack) { /* Loop is error path only */ +#else + if (context->element_stack) { /* Substitute and remove one stack element */ +#endif /* WIND_DOWN_STACK */ + HTElement * N = context->element_stack; + HTTag * t = N->tag; + + if (old_tag != t) { /* Mismatch: syntax error */ + if (context->element_stack->next) { /* This is not the last level */ + if (TRACE) fprintf(stderr, + "SGML: Found </%s> when expecting </%s>. </%s> assumed.\n", + old_tag->name, t->name, t->name); + } else { /* last level */ + if (TRACE) fprintf(stderr, + "SGML: Found </%s> when expecting </%s>. </%s> Ignored.\n", + old_tag->name, t->name, old_tag->name); + return; /* Ignore */ + } + } + + context->element_stack = N->next; /* Remove from stack */ + FREE(N); + (*context->actions->end_element)(context->target, + t - context->dtd->tags, (char **)&context->include); +#ifdef WIND_DOWN_STACK + if (old_tag == t) + return; /* Correct sequence */ +#else + return; +#endif /* WIND_DOWN_STACK */ + + /* Syntax error path only */ + + } + if (TRACE) + fprintf(stderr, "SGML: Extra end tag </%s> found and ignored.\n", + old_tag->name); +} + + +/* Start a element +*/ +PRIVATE void start_element ARGS1( + HTStream *, context) +{ + HTTag * new_tag = context->current_tag; + +#ifdef EXTENDED_HTMLDTD + + BOOL valid = YES; + BOOL direct_container = YES; + BOOL extra_action_taken = NO; + canclose_t canclose_check = close_valid; + + if (New_DTD) { + while (context->element_stack && + (canclose_check == close_valid || + (canclose_check == close_error && + new_tag == context->element_stack->tag)) && + !(valid = element_valid_within(new_tag, context->element_stack->tag, + direct_container))) { + canclose_check = can_close(new_tag, context->element_stack->tag); + if (canclose_check != close_NO) { + if (TRACE) + fprintf(stderr, "SGML: End </%s> \t<- %s start <%s>\n", + context->element_stack->tag->name, + canclose_check == close_valid ? "supplied," : "forced by", + new_tag->name); + do_close_stacked(context); + extra_action_taken = YES; + if (canclose_check == close_error) + direct_container = NO; + } else { + if (TRACE) + fprintf(stderr, "SGML: Still open %s \t<- invalid start <%s>\n", + context->element_stack->tag->name, + new_tag->name); + } + } + if (context->element_stack && !valid && + (context->element_stack->tag->flags & Tgf_strict) && + !(valid = element_valid_within(new_tag, context->element_stack->tag, + direct_container))) { + if (TRACE) + fprintf(stderr, "SGML: Still open %s \t<- ignoring start <%s>\n", + context->element_stack->tag->name, + new_tag->name); + return; + } + + if (context->element_stack && !extra_action_taken && + canclose_check == close_NO && !valid && (new_tag->flags & Tgf_mafse)) { + BOOL has_attributes = NO; + int i = 0; + for (; i< new_tag->number_of_attributes && !has_attributes; i++) + has_attributes = context->present[i]; + if (!has_attributes) { + if (TRACE) + fprintf(stderr, "SGML: Still open %s, converting invalid <%s> to </%s>\n", + context->element_stack->tag->name, + new_tag->name, + new_tag->name); + end_element(context, new_tag); + return; + } + } + + if (context->element_stack && + canclose_check == close_error && !(valid = + element_valid_within( + new_tag, + context->element_stack->tag, + direct_container))) { + if (TRACE) + fprintf(stderr, "SGML: Still open %s \t<- invalid start <%s>\n", + context->element_stack->tag->name, + new_tag->name); + } + } + /* Fall through to the non-extended code - kw */ + +#endif /* EXTENDED_HTMLDTD */ + + /* + ** If we are not in a SELECT block, check if this is + ** a SELECT start tag. Otherwise (i.e., we are in a + ** SELECT block) accept only OPTION as valid, terminate + ** the SELECT block if it is any other form-related + ** element, and otherwise ignore it. - FM + */ + if (!context->inSELECT) { + /* + ** We are not in a SELECT block, so check if this starts one. - FM + */ + if (!strcasecomp(new_tag->name, "SELECT")) { + /* + ** Set the inSELECT flag and fall through. - FM + */ + context->inSELECT = TRUE; + } + } else { + /* + ** We are in a SELECT block. - FM + */ + if (strcasecomp(new_tag->name, "OPTION")) { + /* + ** Ugh, it is not an OPTION. - FM + */ + if (!strcasecomp(new_tag->name, "INPUT") || + !strcasecomp(new_tag->name, "TEXTAREA") || + !strcasecomp(new_tag->name, "SELECT") || + !strcasecomp(new_tag->name, "BUTTON") || + !strcasecomp(new_tag->name, "FIELDSET") || + !strcasecomp(new_tag->name, "LABEL") || + !strcasecomp(new_tag->name, "LEGEND") || + !strcasecomp(new_tag->name, "FORM")) { + /* + ** It is another form-related start tag, so terminate + ** the current SELECT block and fall through. - FM + */ + if (TRACE) + fprintf(stderr, + "SGML: Faking SELECT end tag before <%s> start tag.\n", + new_tag->name); + end_element(context, SGMLFindTag(context->dtd, "SELECT")); + } else { + /* + ** Ignore the start tag. - FM + */ + if (TRACE) + fprintf(stderr, + "SGML: Ignoring start tag <%s> in SELECT block.\n", + new_tag->name); + return; + } + } + } + /* + ** Handle the start tag. - FM + */ + if (TRACE) + fprintf(stderr, "SGML: Start <%s>\n", new_tag->name); + (*context->actions->start_element)( + context->target, + new_tag - context->dtd->tags, + context->present, + (CONST char**) context->value, /* coerce type for think c */ + context->current_tag_charset, + (char **)&context->include); + if (new_tag->contents != SGML_EMPTY) { /* i.e. tag not empty */ + HTElement * N = (HTElement *)malloc(sizeof(HTElement)); + if (N == NULL) + outofmem(__FILE__, "start_element"); + N->next = context->element_stack; + N->tag = new_tag; + context->element_stack = N; + } else if (!strcasecomp(new_tag->name, "META")) { + /* + ** Check for result of META tag. - KW & FM + */ + change_chartrans_handling(context); + } +} + + +/* Find Tag in DTD tag list +** ------------------------ +** +** On entry, +** dtd points to dtd structire including valid tag list +** string points to name of tag in question +** +** On exit, +** returns: +** NULL tag not found +** else address of tag structure in dtd +*/ +PUBLIC HTTag * SGMLFindTag ARGS2( + CONST SGML_dtd*, dtd, + CONST char *, string) +{ + int high, low, i, diff; + for (low = 0, high=dtd->number_of_tags; + high > low; + diff < 0 ? (low = i+1) : (high = i)) { /* Binary search */ + i = (low + (high-low)/2); + diff = strcasecomp(dtd->tags[i].name, string); /* Case insensitive */ + if (diff == 0) { /* success: found it */ + return &dtd->tags[i]; + } + } + if (isalpha((unsigned char)string[0])) { + /* + ** Unrecognized, but may be valid. - KW + */ + return (HTTag *)&HTTag_unrecognized; + } + return NULL; +} + +/*________________________________________________________________________ +** Public Methods +*/ + + +/* Could check that we are back to bottom of stack! @@ */ +/* Do check! - FM */ +/* */ +PRIVATE void SGML_free ARGS1( + HTStream *, context) +{ + int i; + HTElement * cur; + HTTag * t; + + /* + ** Free the buffers. - FM + */ + FREE(context->recover); + FREE(context->url); + FREE(context->csi); + FREE(context->include); + + /* + ** Wind down stack if any elements are open. - FM + */ + while (context->element_stack) { + cur = context->element_stack; + t = cur->tag; + context->element_stack = cur->next; /* Remove from stack */ + FREE(cur); + (*context->actions->end_element)(context->target, + t - context->dtd->tags, (char **)&context->include); + FREE(context->include); + } + + /* + ** Finish off the target. - FM + */ + (*context->actions->_free)(context->target); + + /* + ** Free the strings and context structure. - FM + */ + HTChunkFree(context->string); + for (i = 0; i < MAX_ATTRIBUTES; i++) + FREE(context->value[i]); + FREE(context); +} + +PRIVATE void SGML_abort ARGS2( + HTStream *, context, + HTError, e) +{ + int i; + HTElement * cur; + + /* + ** Abort the target. - FM + */ + (*context->actions->_abort)(context->target, e); + + /* + ** Free the buffers. - FM + */ + FREE(context->recover); + FREE(context->include); + FREE(context->url); + FREE(context->csi); + + /* + ** Free stack memory if any elements were left open. - KW + */ + while (context->element_stack) { + cur = context->element_stack; + context->element_stack = cur->next; /* Remove from stack */ + FREE(cur); + } + + /* + ** Free the strings and context structure. - FM + */ + HTChunkFree(context->string); + for (i = 0; i < MAX_ATTRIBUTES; i++) + FREE(context->value[i]); + FREE(context); +} + + +/* Read and write user callback handle +** ----------------------------------- +** +** The callbacks from the SGML parser have an SGML context parameter. +** These calls allow the caller to associate his own context with a +** particular SGML context. +*/ + +#ifdef CALLERDATA +PUBLIC void* SGML_callerData ARGS1( + HTStream *, context) +{ + return context->callerData; +} + +PUBLIC void SGML_setCallerData ARGS2( + HTStream *, context, + void*, data) +{ + context->callerData = data; +} +#endif /* CALLERDATA */ + +PRIVATE void SGML_character ARGS2( + HTStream *, context, + char, c_in) +{ + CONST SGML_dtd *dtd = context->dtd; + HTChunk *string = context->string; + CONST char * EntityName; + char * p; + BOOLEAN chk; /* Helps (?) walk through all the else ifs... */ + UCode_t clong, uck; /* Enough bits for UCS4 ... */ + char c; + char saved_char_in = '\0'; + + /* + ** Now some fun with the preprocessor. + ** Use copies for c and unsign_c == clong, so that + ** we can revert back to the unchanged c_in. - KW + */ +#define unsign_c clong + + c = c_in; + clong = (unsigned char)c; /* a.k.a. unsign_c */ + + if (context->T.decode_utf8) { + /* + ** Combine UTF-8 into Unicode. + ** Incomplete characters silently ignored. + ** From Linux kernel's console.c. - KW + */ + if ((unsigned char)c > 127) { + /* + ** We have an octet from a multibyte character. - FM + */ + if (context->utf_count > 0 && (c & 0xc0) == 0x80) { + context->utf_char = (context->utf_char << 6) | (c & 0x3f); + context->utf_count--; + *(context->utf_buf_p) = c; + (context->utf_buf_p)++; + if (context->utf_count == 0) { + /* + ** We have all of the bytes, so terminate + ** the buffer and set 'clong' to the UCode_t + ** value. - FM + */ + *(context->utf_buf_p) = '\0'; + clong = context->utf_char; + if (clong < 256) { + c = ((char)(clong & 0xff)); + } + goto top1; + } else { + /* + ** Wait for more. - KW + */ + return; + } + } else { + /* + ** Start handling a new multibyte character. - FM + */ + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = c; + (context->utf_buf_p)++; + if ((c & 0xe0) == 0xc0) { + context->utf_count = 1; + context->utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + context->utf_count = 2; + context->utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + context->utf_count = 3; + context->utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + context->utf_count = 4; + context->utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + context->utf_count = 5; + context->utf_char = (c & 0x01); + } else { + /* + ** Garbage. - KW + */ + context->utf_count = 0; + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; + } + /* + ** Wait for more. - KW + */ + return; + } + } else { + /* + ** Got an ASCII char. - KW + */ + context->utf_count = 0; + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; + /* goto top; */ + } + } + +#ifdef NOTDEFINED + /* + ** If we have a koi8-r input and do not have + ** koi8-r as the output, save the raw input + ** in saved_char_in before we potentially + ** convert it to Unicode. - FM + */ + if (context->T.strip_raw_char_in) + saved_char_in = c; +#endif /* NOTDEFINED */ + + /* + ** If we want the raw input converted + ** to Unicode, try that now. - FM + */ + if (context->T.trans_to_uni && + ((unsign_c >= 127) || + (unsign_c < 32 && unsign_c != 0 && + context->T.trans_C0_to_uni))) { + /* + ** Convert the octet to Unicode. - FM + */ + clong = UCTransToUni(c, context->inUCLYhndl); + if (clong > 0) { + saved_char_in = c; + if (clong < 256) { + c = FROMASCII((char)clong); + } + } + goto top1; + } else if (unsign_c < 32 && unsign_c != 0 && + context->T.trans_C0_to_uni) { + /* + ** This else if may be too ugly to keep. - KW + */ + if (context->T.trans_from_uni && + (((clong = UCTransToUni(c, context->inUCLYhndl)) >= 32) || + (context->T.transp && + (clong = UCTransToUni(c, context->inUCLYhndl)) > 0))) { + saved_char_in = c; + if (clong < 256) { + c = FROMASCII((char)clong); + } + goto top1; + } else { + uck = -1; + if (context->T.transp) { + uck = UCTransCharStr(replace_buf, 60, c, + context->inUCLYhndl, + context->inUCLYhndl, NO); + } + if (!context->T.transp || uck < 0) { + uck = UCTransCharStr(replace_buf, 60, c, + context->inUCLYhndl, + context->outUCLYhndl, YES); + } + if (uck == 0) { + return; + } else if (uck < 0) { + goto top0a; + } + c = replace_buf[0]; + if (c && replace_buf[1]) { + if (context->state == S_text) { + for (p = replace_buf; *p; p++) + PUTC(*p); + return; + } + StrAllocCat(context->recover, replace_buf + 1); + } + goto top0a; + } /* Next line end of ugly stuff for C0. - KW */ + } else { + goto top0a; + } + + /* + ** At this point we have either unsign_c a.k.a. clong in + ** Unicode (and c in latin1 if clong is in the latin1 range), + ** or unsign_c and c will have to be passed raw. - KW + */ +/* +** We jump up to here from below if we have +** stuff in the recover, insert, or csi buffers +** to process. We zero saved_char_in, in effect +** as a flag that the octet in not that of the +** actual call to this function. This may be OK +** for now, for the stuff this function adds to +** its recover buffer, but it might not be for +** stuff other functions added to the insert or +** csi buffer, so bear that in mind. - FM +*/ +top: + saved_char_in = '\0'; +/* +** We jump to here from above when we don't have +** UTF-8 input, haven't converted to Unicode, and +** want clong set to the input octet (unsigned) +** without zeroing its saved_char_in copy (which +** is signed). - FM +*/ +top0a: + *(context->utf_buf) = '\0'; + clong = (unsigned char)c; +/* +** We jump to here from above if we have converted +** the input, or a multibyte sequence across calls, +** to a Unicode value and loaded it into clong (to +** which unsign_c has been defined), and from below +** when we are recycling a character (e.g., because +** it terminated an entity but is not the standard +** semi-colon). The chararcter will already have +** been put through the Unicode conversions. - FM +*/ +top1: + /* + ** Ignore low ISO 646 7-bit control characters + ** if HTCJK is not set. - FM + */ + if (unsign_c < 32 && + c != 9 && c != 10 && c != 13 && + HTCJK == NOCJK) + return; + + /* + ** Ignore 127 if we don't have HTPassHighCtrlRaw + ** or HTCJK set. - FM + */ +#define PASSHICTRL (context->T.transp || \ + unsign_c >= LYlowest_eightbit[context->inUCLYhndl]) + if (c == 127 && + !(PASSHICTRL || HTCJK != NOCJK)) + return; + + /* + ** Ignore 8-bit control characters 128 - 159 if + ** neither HTPassHighCtrlRaw nor HTCJK is set. - FM + */ + if (unsign_c > 127 && unsign_c < 160 && + !(PASSHICTRL || HTCJK != NOCJK)) + return; + + /* + ** Handle character based on context->state. + */ + switch(context->state) { + + case S_in_kanji: + /* + ** Note that if we don't have a CJK input, then this + ** is not the second byte of a CJK di-byte, and we're + ** trashing the input. That's why 8-bit characters + ** followed by, for example, '<' can cause the tag to + ** be treated as text, not markup. We could try to deal + ** with it by holding each first byte and then checking + ** byte pairs, but that doesn't seem worth the overhead + ** (see below). - FM + */ + context->state = S_text; + PUTC(c); + break; + + case S_text: + if (HTCJK != NOCJK && (c & 0200) != 0) { + /* + ** Setting up for Kanji multibyte handling (based on + ** Takuya ASADA's (asada@three-a.co.jp) CJK Lynx). + ** Note that if the input is not in fact CJK, the + ** next byte also will be mishandled, as explained + ** above. Toggle raw mode off in such cases, or + ** select the "7 bit approximations" display + ** character set, which is largely equivalent + ** to having raw mode off with CJK. - FM + */ + context->state = S_in_kanji; + PUTC(c); + break; + } else if (HTCJK != NOCJK && c == '\033') { + /* + ** Setting up for CJK escape sequence handling (based on + ** Takuya ASADA's (asada@three-a.co.jp) CJK Lynx). - FM + */ + context->state = S_esc; + PUTC(c); + break; + } + if (c == '&' && unsign_c < 127 && + (!context->element_stack || + (context->element_stack->tag && + (context->element_stack->tag->contents == SGML_MIXED || + context->element_stack->tag->contents == SGML_PCDATA || + context->element_stack->tag->contents == SGML_RCDATA)))) { + /* + ** Setting up for possible entity, without the leading '&'. - FM + */ + string->size = 0; + context->state = S_ero; + } else if (c == '<' && unsign_c < 127) { + /* + ** Setting up for possible tag. - FM + */ + string->size = 0; + context->state = (context->element_stack && + context->element_stack->tag && + context->element_stack->tag->contents == SGML_LITTERAL) + ? + S_litteral : S_tag; +#define PASS8859SPECL context->T.pass_160_173_raw + /* + ** Convert 160 (nbsp) to Lynx special character if + ** neither HTPassHighCtrlRaw nor HTCJK is set. - FM + */ + } else if (unsign_c == 160 && + !(PASS8859SPECL || HTCJK != NOCJK)) { + PUTC(HT_NON_BREAK_SPACE); + /* + ** Convert 173 (shy) to Lynx special character if + ** neither HTPassHighCtrlRaw nor HTCJK is set. - FM + */ + } else if (unsign_c == 173 && + !(PASS8859SPECL || HTCJK != NOCJK)) { + PUTC(LY_SOFT_HYPHEN); + /* + ** Handle the case in which we think we have a character + ** which doesn't need further processing (e.g., a koi8-r + ** input for a koi8-r output). - FM + */ + } else if (context->T.use_raw_char_in && saved_char_in) { + /* + ** Only if the original character is still in saved_char_in, + ** otherwise we may be iterating from a goto top. - KW + */ + PUTC(saved_char_in); + saved_char_in = '\0'; +/****************************************************************** + * I. LATIN-1 OR UCS2 TO DISPLAY CHARSET + ******************************************************************/ + } else if ((chk = (context->T.trans_from_uni && unsign_c >= 160)) && + (uck = UCTransUniChar(unsign_c, + context->outUCLYhndl)) >= 32 && + uck < 256) { + if (TRACE) { + fprintf(stderr, + "UCTransUniChar returned 0x%.2lX:'%c'.\n", + uck, FROMASCII((char)uck)); + } + /* + ** We got one octet from the conversions, so use it. - FM + */ + PUTC(FROMASCII((char)uck)); + } else if ((chk && + (uck == -4 || + (context->T.repl_translated_C0 && + uck > 0 && uck < 32))) && + /* + ** Not found; look for replacement string. - KW + */ + (uck = UCTransUniCharStr(replace_buf, 60, clong, + context->outUCLYhndl, + 0) >= 0)) { + /* + ** Got a replacement string. + ** No further tests for valididy - assume that whoever + ** defined replacement strings knew what she was doing. - KW + */ + for (p = replace_buf; *p; p++) + PUTC(*p); + /* + ** If we're displaying UTF-8, try that now. - FM + */ + } else if (context->T.output_utf8 && PUTUTF8(clong)) { + ; /* do nothing more */ + /* + ** If it's any other (> 160) 8-bit chararcter, and + ** we have not set HTPassEightBitRaw nor HTCJK, nor + ** have the "ISO Latin 1" character set selected, + ** back translate for our character set. - FM + */ +#define PASSHI8BIT (HTPassEightBitRaw || \ + (context->T.do_8bitraw && !context->T.trans_from_uni)) + } else if (unsign_c > 160 && unsign_c < 256 && + !(PASSHI8BIT || HTCJK != NOCJK) && + !IncludesLatin1Enc) { + int i; + + string->size = 0; + EntityName = HTMLGetEntityName((int)(unsign_c - 160)); + for (i = 0; EntityName[i]; i++) + HTChunkPutc(string, EntityName[i]); + HTChunkTerminate(string); + handle_entity(context, '\0'); + string->size = 0; + if (!FoundEntity) + PUTC(';'); + /* + ** If we get to here and have an ASCII char, + ** pass the character. - KW + */ + } else if (unsign_c < 127 && unsign_c > 0) { + PUTC(c); + /* + ** If we get to here, and should have translated, + ** translation has failed so far. - KW + ** + ** We should have sent UTF-8 output to the parser + ** already, but what the heck, try again. - FM + */ + } else if (context->T.output_utf8 && *context->utf_buf) { + for (p = context->utf_buf; *p; p++) + PUTC(*p); + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; +#ifdef NOTDEFINED + /* + ** Check for a strippable koi8-r 8-bit character. - FM + */ + } else if (context->T.strip_raw_char_in && saved_char_in && + ((unsigned char)saved_char_in >= 0xc0) && + ((unsigned char)saved_char_in < 255)) { + /* + ** KOI8 special: strip high bit, gives (somewhat) readable + ** ASCII or KOI7 - it was constructed that way! - KW + */ + PUTC(((char)(saved_char_in & 0x7f))); + saved_char_in = '\0'; +#endif /* NOTDEFINED */ + /* + ** If we don't actually want the character, + ** make it safe and output that now. - FM + */ + } else if ((unsigned char)c < + LYlowest_eightbit[context->outUCLYhndl] || + (context->T.trans_from_uni && !HTPassEightBitRaw)) { +#ifdef NOTUSED_FOTEMODS + /* + ** If we do not have the "7-bit approximations" as our + ** output character set (in which case we did it already) + ** seek a translation for that. Otherwise, or if the + ** translation fails, use UHHH notation. - FM + */ + if ((chk = (context->outUCLYhndl != + UCGetLYhndl_byMIME("us-ascii"))) && + (uck = UCTransUniChar(unsign_c, + UCGetLYhndl_byMIME("us-ascii"))) + >= 32 && uck < 127) { + /* + ** Got an ASCII character (yippey). - FM + */ + PUTC(((char)(uck & 0xff))); + } else if ((chk && uck == -4) && + (uck = UCTransUniCharStr(replace_buf, + 60, clong, + UCGetLYhndl_byMIME("us-ascii"), + 0) >= 0)) { + /* + ** Got a replacement string (yippey). - FM + */ + for (p = replace_buf; *p; p++) + PUTC(*p); + } else { + /* + ** Out of luck, so use the UHHH notation (ugh). - FM + */ +#endif /* NOTUSED_FOTEMODS */ + sprintf(replace_buf, "U%.2lX", unsign_c); + for (p = replace_buf; *p; p++) { + PUTC(*p); + } +#ifdef NOTUSED_FOTEMODS + } +#endif /* NOTUSED_FOTEMODS */ + /* + ** If we get to here, pass the character. - FM + */ + } else { + PUTC(c); + } + break; + + /* + ** In litteral mode, waits only for specific end tag (for + ** compatibility with old servers, and for Lynx). - FM + */ + case S_litteral: + HTChunkPutc(string, c); + if (TOUPPER(c) != ((string->size == 1) ? + '/' : + context->element_stack->tag->name[string->size-2])) { + int i; + + /* + ** If complete match, end litteral. + */ + if ((c == '>') && + (!context->element_stack->tag->name[string->size-2])) { + end_element(context, context->element_stack->tag); + string->size = 0; + context->current_attribute_number = INVALID; + context->state = S_text; + break; + } + /* + ** If Mismatch: recover string. + */ + PUTC('<'); + for (i = 0; i < string->size; i++) /* recover */ + PUTC(string->data[i]); + string->size = 0; + context->state = S_text; + } + break; + + /* + ** Character reference (numeric entity) or named entity. + */ + case S_ero: + if (c == '#') { + /* + ** Setting up for possible numeric entity. + */ + context->state = S_cro; /* &# is Char Ref Open */ + break; + } + context->state = S_entity; /* Fall through! */ + + /* + ** Handle possible named entity. + */ + case S_entity: + if (unsign_c < 127 && (string->size ? + isalnum((unsigned char)c) : isalpha((unsigned char)c))) { + /* + ** Accept valid ASCII character. - FM + */ + HTChunkPutc(string, c); + } else if (string->size == 0) { + /* + ** It was an ampersand that's just text, so output + ** the ampersand and recycle this character. - FM + */ + PUTC('&'); + context->state = S_text; + goto top1; + } else { + /* + ** Terminate entity name and try to handle it. - FM + */ + HTChunkTerminate(string); + if (!strcmp(string->data, "zwnj") && + (!context->element_stack || + (context->element_stack->tag && + context->element_stack->tag->contents == SGML_MIXED))) { + /* + ** Handle zwnj (8204) as <WBR>. - FM + */ + char temp[8]; + + if (TRACE) { + fprintf(stderr, + "SGML_character: Handling 'zwnj' entity as 'WBR' element.\n"); + } + if (c != ';') { + sprintf(temp, "<WBR>%c", c); + } else { + sprintf(temp, "<WBR>"); + } + if (context->recover == NULL) { + StrAllocCopy(context->recover, temp); + context->recover_index = 0; + } else { + StrAllocCat(context->recover, temp); + } + string->size = 0; + context->state = S_text; + break; + } else { + handle_entity(context, '\0'); + } + string->size = 0; + context->state = S_text; + /* + ** Don't eat the terminator if we didn't find the + ** entity name and therefore sent the raw string + ** via handle_entity(), or if the terminator is + ** not the "standard" semi-colon for HTML. - FM + */ + if (!FoundEntity || c != ';') + goto top1; + } + break; + + /* + ** Check for a numeric entity. + */ + case S_cro: + if (unsign_c < 127 && TOLOWER((unsigned char)c) == 'x') { + context->isHex = TRUE; + context->state = S_incro; + } else if (unsign_c < 127 && isdigit((unsigned char)c)) { + /* + ** Accept only valid ASCII digits. - FM + */ + HTChunkPutc(string, c); /* accumulate a character NUMBER */ + context->isHex = FALSE; + context->state = S_incro; + } else if (string->size == 0) { + /* + ** No 'x' or digit following the "&#" so recover + ** them and recycle the character. - FM + */ + PUTC('&'); + PUTC('#'); + context->state = S_text; + goto top1; + } + break; + + /* + ** Handle a numeric entity. + */ + case S_incro: + if ((unsign_c < 127) && + (context->isHex ? isxdigit((unsigned char)c) : + isdigit((unsigned char)c))) { + /* + ** Accept only valid hex or ASCII digits. - FM + */ + HTChunkPutc(string, c); /* accumulate a character NUMBER */ + } else if (string->size == 0) { + /* + ** No hex digit following the "&#x" so recover + ** them and recycle the character. - FM + */ + PUTC('&'); + PUTC('#'); + PUTC('x'); + context->isHex = FALSE; + context->state = S_text; + goto top1; + } else { + /* + ** Terminate the numeric entity and try to handle it. - FM + */ + UCode_t code; + int i; + HTChunkTerminate(string); + if ((context->isHex ? sscanf(string->data, "%lx", &code) : + sscanf(string->data, "%ld", &code)) == 1) { + if ((code == 1) || + (code > 129 && code < 156)) { + /* + ** Assume these are Microsoft code points, + ** inflicted on us by FrontPage. - FM + ** + ** MS FrontPage uses syntax like ™ in 128-159 range + ** and doesn't follow Unicode standards for this area. + ** Windows-1252 codepoints are assumed here. + */ + switch (code) { + case 1: + /* + ** WHITE SMILING FACE + */ + code = 0x263a; + break; + case 130: + /* + ** SINGLE LOW-9 QUOTATION MARK (sbquo) + */ + code = 0x201a; + break; + case 132: + /* + ** DOUBLE LOW-9 QUOTATION MARK (bdquo) + */ + code = 0x201e; + break; + case 133: + /* + ** HORIZONTAL ELLIPSIS (hellip) + */ + code = 0x2026; + break; + case 134: + /* + ** DAGGER (dagger) + */ + code = 0x2020; + break; + case 135: + /* + ** DOUBLE DAGGER (Dagger) + */ + code = 0x2021; + break; + case 137: + /* + ** PER MILLE SIGN (permil) + */ + code = 0x2030; + break; + case 139: + /* + ** SINGLE LEFT-POINTING ANGLE QUOTATION MARK + ** (lsaquo) + */ + code = 0x2039; + break; + case 145: + /* + ** LEFT SINGLE QUOTATION MARK (lsquo) + */ + code = 0x2018; + break; + case 146: + /* + ** RIGHT SINGLE QUOTATION MARK (rsquo) + */ + code = 0x2019; + break; + case 147: + /* + ** LEFT DOUBLE QUOTATION MARK (ldquo) + */ + code = 0x201c; + break; + case 148: + /* + ** RIGHT DOUBLE QUOTATION MARK (rdquo) + */ + code = 0x201d; + break; + case 149: + /* + ** BULLET (bull) + */ + code = 0x2022; + break; + case 150: + /* + ** EN DASH (ndash) + */ + code = 0x2013; + break; + case 151: + /* + ** EM DASH (mdash) + */ + code = 0x2014; + break; + case 152: + /* + ** SMALL TILDE (tilde) + */ + code = 0x02dc; + break; + case 153: + /* + ** TRADE MARK SIGN (trade) + */ + code = 0x2122; + break; + case 155: + /* + ** SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + ** (rsaquo) + */ + code = 0x203a; + break; + default: + /* + ** Do not attempt a conversion + ** to valid Unicode values. + */ + break; + } + } + /* + ** Check for special values. - FM + */ + if ((code == 8204) && + (!context->element_stack || + (context->element_stack->tag && + context->element_stack->tag->contents == SGML_MIXED))) { + /* + ** Handle zwnj (8204) as <WBR>. - FM + */ + char temp[8]; + + if (TRACE) { + fprintf(stderr, + "SGML_character: Handling '8204' (zwnj) reference as 'WBR' element.\n"); + } + /* + ** Include the terminator if it is not + ** the standard semi-colon. - FM + */ + if (c != ';') { + sprintf(temp, "<WBR>%c", c); + } else { + sprintf(temp, "<WBR>"); + } + /* + ** Add the replacement string to the + ** recover buffer for processing. - FM + */ + if (context->recover == NULL) { + StrAllocCopy(context->recover, temp); + context->recover_index = 0; + } else { + StrAllocCat(context->recover, temp); + } + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + break; + } else if (put_special_unicodes(context, code)) { + /* + ** We handled the value as a special character, + ** so recycle the terminator or break. - FM + */ + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + if (c != ';') + goto top1; + break; + } + /* + ** Seek a translation from the chartrans tables. + */ + if ((uck = UCTransUniChar(code, + context->outUCLYhndl)) >= 32 && + uck < 256 && + (uck < 127 || + uck >= LYlowest_eightbit[context->outUCLYhndl])) { + PUTC(FROMASCII((char)uck)); + } else if ((uck == -4 || + (context->T.repl_translated_C0 && + uck > 0 && uck < 32)) && + /* + ** Not found; look for replacement string. + */ + (uck = UCTransUniCharStr(replace_buf, 60, code, + context->outUCLYhndl, + 0) >= 0)) { + for (p = replace_buf; *p; p++) { + PUTC(*p); + } + /* + ** If we're displaying UTF-8, try that now. - FM + */ + } else if (context->T.output_utf8 && PUTUTF8(code)) { + ; /* do nothing more */ +#ifdef NOTUSED_FOTEMODS + /* + ** If the value is greater than 255 and we do not + ** have the "7-bit approximations" as our output + ** character set (in which case we did it already) + ** seek a translation for that. - FM + */ + } else if ((chk = ((code > 255) && + context->outUCLYhndl != + UCGetLYhndl_byMIME("us-ascii"))) && + (uck = UCTransUniChar(code, + UCGetLYhndl_byMIME("us-ascii"))) + >= 32 && uck < 127) { + /* + ** Got an ASCII character (yippey). - FM + */ + PUTC(((char)(uck & 0xff))); + } else if ((chk && uck == -4) && + (uck = UCTransUniCharStr(replace_buf, + 60, code, + UCGetLYhndl_byMIME("us-ascii"), + 0) >= 0)) { + /* + ** Got a replacement string (yippey). - FM + */ + for (p = replace_buf; *p; p++) + PUTC(*p); + /* + ** Ignore 8205 (zwj), + ** 8206 (lrm), and 8207 (rln), if we get to here. - FM + */ + } else if (code == 8205 || + code == 8206 || + code == 8207) { + if (TRACE) { + string->size--; + LYstrncpy(replace_buf, + string->data, + (string->size < 64 ? string->size : 63)); + fprintf(stderr, + "SGML_character: Ignoring '%s%s'.\n", + (context->isHex ? "&#x" : "&#"), + replace_buf); + } + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + if (c != ';') + goto top1; + break; +#endif /* NOTUSED_FOTEMODS */ + /* + ** Show the numeric entity if we get to here + ** and the value: + ** (1) Is greater than 255 (but use ASCII characters + ** for spaces or dashes). + ** (2) Is less than 32, and not valid or we don't + ** have HTCJK set. + ** (3) Is 127 and we don't have HTPassHighCtrlRaw or + ** HTCJK set. + ** (4) Is 128 - 159 and we don't have HTPassHighCtrlNum + ** set. + ** - FM + */ + } else if ((code > 255) || + (code < 32 && + code != 9 && code != 10 && code != 13 && + HTCJK == NOCJK) || + (code == 127 && + !(HTPassHighCtrlRaw || HTCJK != NOCJK)) || + (code > 127 && code < 160 && + !HTPassHighCtrlNum)) { + /* + ** Unhandled or illegal value. Recover the + ** "&#" or "&#x" and digit(s), and recycle + ** the terminator. - FM + */ + PUTC('&'); + PUTC('#'); + if (context->isHex) { + PUTC('x'); + context->isHex = FALSE; + } + string->size--; + for (i = 0; i < string->size; i++) /* recover */ + PUTC(string->data[i]); + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + goto top1; + } else if (code < 161 || + HTPassEightBitNum || + IncludesLatin1Enc) { + /* + ** No conversion needed. - FM + */ + PUTC(FROMASCII((char)code)); + } else { + /* + ** Handle as named entity. - FM + */ + code -= 160; + EntityName = HTMLGetEntityName(code); + if (EntityName && EntityName[0] != '\0') { + string->size = 0; + for (i = 0; EntityName[i]; i++) + HTChunkPutc(string, EntityName[i]); + HTChunkTerminate(string); + handle_entity(context, '\0'); + /* + ** Add a semi-colon if something went wrong + ** and handle_entity() sent the string. - FM + */ + if (!FoundEntity) { + PUTC(';'); + } + } else { + /* + ** Our conversion failed, so recover the "&#" + ** and digit(s), and recycle the terminator. - FM + */ + PUTC('&'); + PUTC('#'); + if (context->isHex) { + PUTC('x'); + context->isHex = FALSE; + } + string->size--; + for (i = 0; i < string->size; i++) /* recover */ + PUTC(string->data[i]); + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + goto top1; + } + } + /* + ** If we get to here, we succeeded. Hoorah!!! - FM + */ + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + /* + ** Don't eat the terminator if it's not + ** the "standard" semi-colon for HTML. - FM + */ + if (c != ';') { + goto top1; + } + } else { + /* + ** Not an entity, and don't know why not, so add + ** the terminator to the string, output the "&#" + ** or "&#x", and process the string via the recover + ** element. - FM + */ + string->size--; + HTChunkPutc(string, c); + HTChunkTerminate(string); + PUTC('&'); + PUTC('#'); + if (context->isHex) { + PUTC('x'); + context->isHex = FALSE; + } + if (context->recover == NULL) { + StrAllocCopy(context->recover, string->data); + context->recover_index = 0; + } else { + StrAllocCat(context->recover, string->data); + } + string->size = 0; + context->isHex = FALSE; + context->state = S_text; + break; + } + } + break; + + /* + ** Tag + */ + case S_tag: /* new tag */ + if (unsign_c < 127 && (string->size ? + isalnum((unsigned char)c) : isalpha((unsigned char)c))) { + /* + ** Add valid ASCII character. - FM + */ + HTChunkPutc(string, c); + } else if (c == '!' && !string->size) { /* <! */ + /* + ** Terminate and set up for possible comment, + ** identifier, declaration, or marked section. - FM + */ + context->state = S_exclamation; + context->lead_exclamation = TRUE; + context->doctype_bracket = FALSE; + context->first_bracket = FALSE; + HTChunkPutc(string, c); + break; + } else if (!string->size && + (unsign_c <= 160 && + (c != '/' && c != '?' && c != '_' && c != ':'))) { + /* + ** '<' must be followed by an ASCII letter to be a valid + ** start tag. Here it isn't, nor do we have a '/' for an + ** end tag, nor one of some other characters with a + ** special meaning for SGML or which are likely to be legal + ** Name Start characters in XML or some other extension. + ** So recover the '<' and following character as data. - FM & KW + */ + context->state = S_text; + PUTC('<'); + goto top1; + } else { /* End of tag name */ + /* + ** Try to handle tag. - FM + */ + HTTag * t; + if (c == '/') { + if (TRACE) + if (string->size!=0) + fprintf(stderr,"SGML: `<%s/' found!\n", string->data); + context->state = S_end; + break; + } + HTChunkTerminate(string) ; + + t = SGMLFindTag(dtd, string->data); + if (t == context->unknown_tag && c == ':' && + 0 == strcasecomp(string->data, "URL")) { + /* + ** Treat <URL: as text rather than a junk tag, + ** so we display it and the URL (Lynxism 8-). - FM + */ + int i; + PUTC('<'); + for (i = 0; i < 3; i++) /* recover */ + PUTC(string->data[i]); + PUTC(c); + if (TRACE) + fprintf(stderr, "SGML: Treating <%s%c as text\n", + string->data, c); + string->size = 0; + context->state = S_text; + break; + } else if (!t) { + if (TRACE) + fprintf(stderr, "SGML: *** Invalid element %s\n", + string->data); + context->state = (c == '>') ? S_text : S_junk_tag; + break; + } else if (t == context->unknown_tag) { + if (TRACE) + fprintf(stderr, "SGML: *** Unknown element %s\n", + string->data); + /* + ** Fall through and treat like valid + ** tag for attribute parsing. - KW + */ + } + context->current_tag = t; + + /* + ** Clear out attributes. + */ + { + int i; + for (i = 0; i < context->current_tag->number_of_attributes; i++) + context->present[i] = NO; + } + string->size = 0; + context->current_attribute_number = INVALID; + + if (c == '>') { + if (context->current_tag->name) + start_element(context); + context->state = S_text; + } else { + context->state = S_tag_gap; + } + } + break; + + case S_exclamation: + if (context->lead_exclamation && c == '-') { + /* + ** Set up for possible comment. - FM + */ + context->lead_exclamation = FALSE; + context->first_dash = TRUE; + HTChunkPutc(string, c); + break; + } + if (context->lead_exclamation && c == '[') { + /* + ** Set up for possible marked section. - FM + */ + context->lead_exclamation = FALSE; + context->first_bracket = TRUE; + context->second_bracket = FALSE; + HTChunkPutc(string, c); + context->state = S_marked; + break; + } + if (context->first_dash && c == '-') { + /* + ** Set up to handle comment. - FM + */ + context->lead_exclamation = FALSE; + context->first_dash = FALSE; + context->end_comment = FALSE; + HTChunkPutc(string, c); + context->state = S_comment; + break; + } + context->lead_exclamation = FALSE; + context->first_dash = FALSE; + if (c == '>') { + /* + ** Try to handle identifier. - FM + */ + HTChunkTerminate(string); + handle_identifier(context); + string->size = 0; + context->state = S_text; + break; + } + if (WHITE(c)) { + if (string->size == 8 && + !strncasecomp(string->data, "!DOCTYPE", 8)) { + /* + ** Set up for DOCTYPE declaration. - FM + */ + HTChunkPutc(string, c); + context->doctype_bracket = FALSE; + context->state = S_doctype; + break; + } + if (string->size == 7 && + !strncasecomp(string->data, "!ENTITY", 7)) { + /* + ** Set up for ENTITY declaration. - FM + */ + HTChunkPutc(string, c); + context->first_dash = FALSE; + context->end_comment = TRUE; + context->state = S_sgmlent; + break; + } + if (string->size == 8 && + !strncasecomp(string->data, "!ELEMENT", 8)) { + /* + ** Set up for ELEMENT declaration. - FM + */ + HTChunkPutc(string, c); + context->first_dash = FALSE; + context->end_comment = TRUE; + context->state = S_sgmlele; + break; + } + if (string->size == 8 && + !strncasecomp(string->data, "!ATTLIST", 8)) { + /* + ** Set up for ATTLIST declaration. - FM + */ + HTChunkPutc(string, c); + context->first_dash = FALSE; + context->end_comment = TRUE; + context->state = S_sgmlatt; + break; + } + } + HTChunkPutc(string, c); + break; + + case S_comment: /* Expecting comment. - FM */ + if (historical_comments) { + /* + ** Any '>' terminates. - FM + */ + if (c == '>') { + HTChunkTerminate(string); + handle_comment(context); + string->size = 0; + context->end_comment = FALSE; + context->first_dash = FALSE; + context->state = S_text; + break; + } + HTChunkPutc(string, c); + break; + } + if (!context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = TRUE; + break; + } + if (context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = FALSE; + if (!context->end_comment) + context->end_comment = TRUE; + else if (!minimal_comments) + /* + ** Validly treat '--' pairs as successive comments + ** (for minimal, any "--WHITE>" terminates). - FM + */ + context->end_comment = FALSE; + break; + } + if (context->end_comment && c == '>') { + /* + ** Terminate and handle the comment. - FM + */ + HTChunkTerminate(string); + handle_comment(context); + string->size = 0; + context->end_comment = FALSE; + context->first_dash = FALSE; + context->state = S_text; + break; + } + context->first_dash = FALSE; + if (context->end_comment && !isspace(c)) + context->end_comment = FALSE; + HTChunkPutc(string, c); + break; + + case S_doctype: /* Expecting DOCTYPE. - FM */ + if (context->doctype_bracket) { + HTChunkPutc(string, c); + if (c == ']') + context->doctype_bracket = FALSE; + break; + } + if (c == '[' && WHITE(string->data[string->size - 1])) { + HTChunkPutc(string, c); + context->doctype_bracket = TRUE; + break; + } + if (c == '>') { + HTChunkTerminate(string); + handle_doctype(context); + string->size = 0; + context->state = S_text; + break; + } + HTChunkPutc(string, c); + break; + + case S_marked: /* Expecting marked section. - FM */ + if (context->first_bracket && c == '[') { + HTChunkPutc(string, c); + context->first_bracket = FALSE; + context->second_bracket = TRUE; + break; + } + if (context->second_bracket && c == ']' && + string->data[string->size - 1] == ']') { + HTChunkPutc(string, c); + context->second_bracket = FALSE; + break; + } + if (!context->second_bracket && c == '>') { + HTChunkTerminate(string); + handle_marked(context); + string->size = 0; + context->state = S_text; + break; + } + HTChunkPutc(string, c); + break; + + case S_sgmlent: /* Expecting ENTITY. - FM */ + if (!context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = TRUE; + break; + } + if (context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = FALSE; + if (!context->end_comment) + context->end_comment = TRUE; + else + context->end_comment = FALSE; + break; + } + if (context->end_comment && c == '>') { + HTChunkTerminate(string); + handle_sgmlent(context); + string->size = 0; + context->end_comment = FALSE; + context->first_dash = FALSE; + context->state = S_text; + break; + } + context->first_dash = FALSE; + HTChunkPutc(string, c); + break; + + case S_sgmlele: /* Expecting ELEMENT. - FM */ + if (!context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = TRUE; + break; + } + if (context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = FALSE; + if (!context->end_comment) + context->end_comment = TRUE; + else + context->end_comment = FALSE; + break; + } + if (context->end_comment && c == '>') { + HTChunkTerminate(string); + handle_sgmlele(context); + string->size = 0; + context->end_comment = FALSE; + context->first_dash = FALSE; + context->state = S_text; + break; + } + context->first_dash = FALSE; + HTChunkPutc(string, c); + break; + + case S_sgmlatt: /* Expecting ATTLIST. - FM */ + if (!context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = TRUE; + break; + } + if (context->first_dash && c == '-') { + HTChunkPutc(string, c); + context->first_dash = FALSE; + if (!context->end_comment) + context->end_comment = TRUE; + else + context->end_comment = FALSE; + break; + } + if (context->end_comment && c == '>') { + HTChunkTerminate(string); + handle_sgmlatt(context); + string->size = 0; + context->end_comment = FALSE; + context->first_dash = FALSE; + context->state = S_text; + break; + } + context->first_dash = FALSE; + HTChunkPutc(string, c); + break; + + case S_tag_gap: /* Expecting attribute or '>' */ + if (WHITE(c)) + break; /* Gap between attributes */ + if (c == '>') { /* End of tag */ + if (context->current_tag->name) + start_element(context); + context->state = S_text; + break; + } + HTChunkPutc(string, c); + context->state = S_attr; /* Get attribute */ + break; + + /* accumulating value */ + case S_attr: + if (WHITE(c) || (c == '>') || (c == '=')) { /* End of word */ + HTChunkTerminate(string); + handle_attribute_name(context, string->data); + string->size = 0; + if (c == '>') { /* End of tag */ + if (context->current_tag->name) + start_element(context); + context->state = S_text; + break; + } + context->state = (c == '=' ? S_equals: S_attr_gap); + } else { + HTChunkPutc(string, c); + } + break; + + case S_attr_gap: /* Expecting attribute or '=' or '>' */ + if (WHITE(c)) + break; /* Gap after attribute */ + if (c == '>') { /* End of tag */ + if (context->current_tag->name) + start_element(context); + context->state = S_text; + break; + } else if (c == '=') { + context->state = S_equals; + break; + } + HTChunkPutc(string, c); + context->state = S_attr; /* Get next attribute */ + break; + + case S_equals: /* After attr = */ + if (WHITE(c)) + break; /* Before attribute value */ + if (c == '>') { /* End of tag */ + if (TRACE) + fprintf(stderr, "SGML: found = but no value\n"); + if (context->current_tag->name) + start_element(context); + context->state = S_text; + break; + + } else if (c == '\'') { + context->state = S_squoted; + break; + + } else if (c == '"') { + context->state = S_dquoted; + break; + } + HTChunkPutc(string, c); + context->state = S_value; + break; + + case S_value: + if (WHITE(c) || (c == '>')) { /* End of word */ + HTChunkTerminate(string) ; + handle_attribute_value(context, string->data); + string->size = 0; + if (c == '>') { /* End of tag */ + if (context->current_tag->name) + start_element(context); + context->state = S_text; + break; + } + else context->state = S_tag_gap; + } else if (context->T.decode_utf8 && + *context->utf_buf) { + HTChunkPuts(string, context->utf_buf); + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; + } else if (HTCJK == NOCJK && + (context->T.output_utf8 || + context->T.trans_from_uni)) { + if (clong == 0xfffd && saved_char_in && + HTPassEightBitRaw && + (unsigned char)saved_char_in >= + LYlowest_eightbit[context->outUCLYhndl]) { + HTChunkPutUtf8Char(string, + (0xf000 | (unsigned char)saved_char_in)); + } else { + HTChunkPutUtf8Char(string, clong); + } + } else if (saved_char_in && context->T.use_raw_char_in) { + HTChunkPutc(string, saved_char_in); + } else { + HTChunkPutc(string, c); + } + break; + + case S_squoted: /* Quoted attribute value */ + if (c == '\'') { /* End of attribute value */ + HTChunkTerminate(string) ; + handle_attribute_value(context, string->data); + string->size = 0; + context->state = S_tag_gap; + } else if (c == '\033') { + /* + ** Setting up for possible single quotes in CJK escape + ** sequences. - Takuya ASADA (asada@three-a.co.jp) + */ + context->state = S_esc_sq; + HTChunkPutc(string, c); + } else if (context->T.decode_utf8 && + *context->utf_buf) { + HTChunkPuts(string, context->utf_buf); + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; + } else if (HTCJK == NOCJK && + (context->T.output_utf8 || + context->T.trans_from_uni)) { + if (clong == 0xfffd && saved_char_in && + HTPassEightBitRaw && + (unsigned char)saved_char_in >= + LYlowest_eightbit[context->outUCLYhndl]) { + HTChunkPutUtf8Char(string, + (0xf000 | (unsigned char)saved_char_in)); + } else { + HTChunkPutUtf8Char(string, clong); + } + } else if (saved_char_in && context->T.use_raw_char_in) { + HTChunkPutc(string, saved_char_in); + } else { + HTChunkPutc(string, c); + } + break; + + case S_dquoted: /* Quoted attribute value */ + if (c == '"' || /* Valid end of attribute value */ + (soft_dquotes && /* If emulating old Netscape bug, treat '>' */ + c == '>')) { /* as a co-terminator of dquoted and tag */ + HTChunkTerminate(string) ; + handle_attribute_value(context, string->data); + string->size = 0; + context->state = S_tag_gap; + if (c == '>') /* We emulated the Netscape bug, so we go */ + goto top1; /* back and treat it as the tag terminator */ + } else if (c == '\033') { + /* + ** Setting up for possible double quotes in CJK escape + ** sequences. - Takuya ASADA (asada@three-a.co.jp) + */ + context->state = S_esc_dq; + HTChunkPutc(string, c); + } else if (context->T.decode_utf8 && + *context->utf_buf) { + HTChunkPuts(string, context->utf_buf); + context->utf_buf_p = context->utf_buf; + *(context->utf_buf_p) = '\0'; + } else if (HTCJK == NOCJK && + (context->T.output_utf8 || + context->T.trans_from_uni)) { + if (clong == 0xfffd && saved_char_in && + HTPassEightBitRaw && + (unsigned char)saved_char_in >= + LYlowest_eightbit[context->outUCLYhndl]) { + HTChunkPutUtf8Char(string, + (0xf000 | (unsigned char)saved_char_in)); + } else { + HTChunkPutUtf8Char(string, clong); + } + } else if (saved_char_in && context->T.use_raw_char_in) { + HTChunkPutc(string, saved_char_in); + } else { + HTChunkPutc(string, c); + } + break; + + case S_end: /* </ */ + if (unsign_c < 127 && isalnum((unsigned char)c)) { + HTChunkPutc(string, c); + } else { /* End of end tag name */ + HTTag * t = 0; + + HTChunkTerminate(string); + if (!*string->data) { /* Empty end tag */ + if (context->element_stack) + t = context->element_stack->tag; + } else { + t = SGMLFindTag(dtd, string->data); + } + if (!t || t == context->unknown_tag) { + if (TRACE) + fprintf(stderr, "Unknown end tag </%s>\n", string->data); + } else { + BOOL tag_OK = (c == '>' || WHITE(c)); + context->current_tag = t; +#ifdef EXTENDED_HTMLDTD + /* + ** Just handle ALL end tags normally :-) - kw + */ + if (New_DTD) { + end_element( context, context->current_tag); + } else +#endif /* EXTENDED_HTMLDTD */ + if (tag_OK && + (!strcasecomp(string->data, "DD") || + !strcasecomp(string->data, "DT") || + !strcasecomp(string->data, "LI") || + !strcasecomp(string->data, "LH") || + !strcasecomp(string->data, "TD") || + !strcasecomp(string->data, "TH") || + !strcasecomp(string->data, "TR") || + !strcasecomp(string->data, "THEAD") || + !strcasecomp(string->data, "TFOOT") || + !strcasecomp(string->data, "TBODY") || + !strcasecomp(string->data, "COLGROUP"))) { + /* + ** Don't treat these end tags as invalid, + ** nor act on them. - FM + */ + if (TRACE) + fprintf(stderr, + "SGML: `</%s%c' found! Ignoring it.\n", + string->data, c); + string->size = 0; + context->current_attribute_number = INVALID; + if (c != '>') { + context->state = S_junk_tag; + } else { + context->state = S_text; + } + break; + } else if (tag_OK && + (!strcasecomp(string->data, "A") || + !strcasecomp(string->data, "B") || + !strcasecomp(string->data, "BLINK") || + !strcasecomp(string->data, "CITE") || + !strcasecomp(string->data, "EM") || + !strcasecomp(string->data, "FONT") || + !strcasecomp(string->data, "FORM") || + !strcasecomp(string->data, "I") || + !strcasecomp(string->data, "P") || + !strcasecomp(string->data, "STRONG") || + !strcasecomp(string->data, "TT") || + !strcasecomp(string->data, "U"))) { + /* + ** Handle end tags for container elements declared + ** as SGML_EMPTY to prevent "expected tag substitution" + ** but still processed via HTML_end_element() in HTML.c + ** with checks there to avoid throwing the HTML.c stack + ** out of whack (Ugh, what a hack! 8-). - FM + */ + if (context->inSELECT) { + /* + ** We are in a SELECT block. - FM + */ + if (strcasecomp(string->data, "FORM")) { + /* + ** It is not at FORM end tag, so ignore it. - FM + */ + if (TRACE) { + fprintf(stderr, + "SGML: Ignoring end tag </%s> in SELECT block.\n", + string->data); + } + } else { + /* + ** End the SELECT block and then + ** handle the FORM end tag. - FM + */ + if (TRACE) { + fprintf(stderr, + "SGML: Faking SELECT end tag before </%s> end tag.\n", + string->data); + } + end_element(context, + SGMLFindTag(context->dtd, "SELECT")); + if (TRACE) { + fprintf(stderr, + "SGML: End </%s>\n", string->data); + } + (*context->actions->end_element) + (context->target, + (context->current_tag - context->dtd->tags), + (char **)&context->include); + } + } else if (!strcasecomp(string->data, "P")) { + /* + ** Treat a P end tag like a P start tag (Ugh, + ** what a hack! 8-). - FM + */ + if (TRACE) + fprintf(stderr, + "SGML: `</%s%c' found! Treating as '<%s%c'.\n", + string->data, c, string->data, c); + { + int i; + for (i = 0; + i < context->current_tag->number_of_attributes; + i++) { + context->present[i] = NO; + } + } + if (context->current_tag->name) + start_element(context); + } else { + if (TRACE) { + fprintf(stderr, + "SGML: End </%s>\n", string->data); + } + (*context->actions->end_element) + (context->target, + (context->current_tag - context->dtd->tags), + (char **)&context->include); + } + string->size = 0; + context->current_attribute_number = INVALID; + if (c != '>') { + context->state = S_junk_tag; + } else { + context->state = S_text; + } + break; + } else { + /* + ** Handle all other end tags normally. - FM + */ + end_element( context, context->current_tag); + } + } + + string->size = 0; + context->current_attribute_number = INVALID; + if (c != '>') { + if (TRACE && !WHITE(c)) + fprintf(stderr,"SGML: `</%s%c' found!\n", string->data, c); + context->state = S_junk_tag; + } else { + context->state = S_text; + } + } + break; + + + case S_esc: /* Expecting '$'or '(' following CJK ESC. */ + if (c == '$') { + context->state = S_dollar; + } else if (c == '(') { + context->state = S_paren; + } else { + context->state = S_text; + } + PUTC(c); + break; + + case S_dollar: /* Expecting '@', 'B', 'A' or '(' after CJK "ESC$". */ + if (c == '@' || c == 'B' || c == 'A') { + context->state = S_nonascii_text; + } else if (c == '(') { + context->state = S_dollar_paren; + } + PUTC(c); + break; + + case S_dollar_paren: /* Expecting 'C' after CJK "ESC$(". */ + if (c == 'C') { + context->state = S_nonascii_text; + } else { + context->state = S_text; + } + PUTC(c); + break; + + case S_paren: /* Expecting 'B', 'J', 'T' or 'I' after CJK "ESC(". */ + if (c == 'B' || c == 'J' || c == 'T') { + context->state = S_text; + } else if (c == 'I') { + context->state = S_nonascii_text; + } else { + context->state = S_text; + } + PUTC(c); + break; + + case S_nonascii_text: /* Expecting CJK ESC after non-ASCII text. */ + if (c == '\033') { + context->state = S_esc; + } + PUTC(c); + break; + + case S_esc_sq: /* Expecting '$'or '(' following CJK ESC. */ + if (c == '$') { + context->state = S_dollar_sq; + } else if (c == '(') { + context->state = S_paren_sq; + } else { + context->state = S_squoted; + } + HTChunkPutc(string, c); + break; + + case S_dollar_sq: /* Expecting '@', 'B', 'A' or '(' after CJK "ESC$". */ + if (c == '@' || c == 'B' || c == 'A') { + context->state = S_nonascii_text_sq; + } else if (c == '(') { + context->state = S_dollar_paren_sq; + } + HTChunkPutc(string, c); + break; + + case S_dollar_paren_sq: /* Expecting 'C' after CJK "ESC$(". */ + if (c == 'C') { + context->state = S_nonascii_text_sq; + } else { + context->state = S_squoted; + } + HTChunkPutc(string, c); + break; + + case S_paren_sq: /* Expecting 'B', 'J', 'T' or 'I' after CJK "ESC(". */ + if (c == 'B' || c == 'J' || c == 'T') { + context->state = S_squoted; + } else if (c == 'I') { + context->state = S_nonascii_text_sq; + } else { + context->state = S_squoted; + } + HTChunkPutc(string, c); + break; + + case S_nonascii_text_sq: /* Expecting CJK ESC after non-ASCII text. */ + if (c == '\033') { + context->state = S_esc_sq; + } + HTChunkPutc(string, c); + break; + + case S_esc_dq: /* Expecting '$'or '(' following CJK ESC. */ + if (c == '$') { + context->state = S_dollar_dq; + } else if (c == '(') { + context->state = S_paren_dq; + } else { + context->state = S_dquoted; + } + HTChunkPutc(string, c); + break; + + case S_dollar_dq: /* Expecting '@', 'B', 'A' or '(' after CJK "ESC$". */ + if (c == '@' || c == 'B' || c == 'A') { + context->state = S_nonascii_text_dq; + } else if (c == '(') { + context->state = S_dollar_paren_dq; + } + HTChunkPutc(string, c); + break; + + case S_dollar_paren_dq: /* Expecting 'C' after CJK "ESC$(". */ + if (c == 'C') { + context->state = S_nonascii_text_dq; + } else { + context->state = S_dquoted; + } + HTChunkPutc(string, c); + break; + + case S_paren_dq: /* Expecting 'B', 'J', 'T' or 'I' after CJK "ESC(". */ + if (c == 'B' || c == 'J' || c == 'T') { + context->state = S_dquoted; + } else if (c == 'I') { + context->state = S_nonascii_text_dq; + } else { + context->state = S_dquoted; + } + HTChunkPutc(string, c); + break; + + case S_nonascii_text_dq: /* Expecting CJK ESC after non-ASCII text. */ + if (c == '\033') { + context->state = S_esc_dq; + } + HTChunkPutc(string, c); + break; + + case S_junk_tag: + if (c == '>') { + context->state = S_text; + } + } /* switch on context->state */ + + /* + ** Check whether we've added anything to the recover buffer. - FM + */ + if (context->recover != NULL) { + if (context->recover[context->recover_index] == '\0') { + FREE(context->recover); + context->recover_index = 0; + } else { + c = context->recover[context->recover_index]; + context->recover_index++; + goto top; + } + } + + /* + ** Check whether an external function has added + ** anything to the include buffer. - FM + */ + if (context->include != NULL) { + if (context->include[context->include_index] == '\0') { + FREE(context->include); + context->include_index = 0; + } else { + c = context->include[context->include_index]; + context->include_index++; + goto top; + } + } + + /* + ** Check whether an external function has added + ** anything to the csi buffer. - FM + */ + if (context->csi != NULL) { + if (context->csi[context->csi_index] == '\0') { + FREE(context->csi); + context->csi_index = 0; + } else { + c = context->csi[context->csi_index]; + context->csi_index++; + goto top; + } + } +} /* SGML_character */ + + +PRIVATE void SGML_string ARGS2( + HTStream *, context, + CONST char*, str) +{ + CONST char *p; + for (p = str; *p; p++) + SGML_character(context, *p); +} + + +PRIVATE void SGML_write ARGS3( + HTStream *, context, + CONST char*, str, + int, l) +{ + CONST char *p; + CONST char *e = str+l; + for (p = str; p < e; p++) + SGML_character(context, *p); +} + +/*_______________________________________________________________________ +*/ + +/* Structured Object Class +** ----------------------- +*/ +PUBLIC CONST HTStreamClass SGMLParser = +{ + "SGMLParser", + SGML_free, + SGML_abort, + SGML_character, + SGML_string, + SGML_write, +}; + +/* Create SGML Engine +** ------------------ +** +** On entry, +** dtd represents the DTD, along with +** actions is the sink for the data as a set of routines. +** +*/ + +PUBLIC HTStream* SGML_new ARGS3( + CONST SGML_dtd *, dtd, + HTParentAnchor *, anchor, + HTStructured *, target) +{ + int i; + HTStream* context = (HTStream *) malloc(sizeof(*context)); + if (!context) + outofmem(__FILE__, "SGML_begin"); + + context->isa = &SGMLParser; + context->string = HTChunkCreate(128); /* Grow by this much */ + context->dtd = dtd; + context->target = target; + context->actions = (HTStructuredClass*)(((HTStream*)target)->isa); + /* Ugh: no OO */ + context->unknown_tag = &HTTag_unrecognized; + context->state = S_text; + context->element_stack = 0; /* empty */ + context->inSELECT = FALSE; +#ifdef CALLERDATA + context->callerData = (void*) callerData; +#endif /* CALLERDATA */ + for (i = 0; i < MAX_ATTRIBUTES; i++) + context->value[i] = 0; + + context->lead_exclamation = FALSE; + context->first_dash = FALSE; + context->end_comment = FALSE; + context->doctype_bracket = FALSE; + context->first_bracket = FALSE; + context->second_bracket = FALSE; + context->isHex = FALSE; + + context->node_anchor = anchor; /* Could be NULL? */ + context->utf_count = 0; + context->utf_char = 0; + context->utf_buf[0] = context->utf_buf[6] = '\0'; + context->utf_buf_p = context->utf_buf; + UCTransParams_clear(&context->T); + context->inUCLYhndl = HTAnchor_getUCLYhndl(anchor, + UCT_STAGE_PARSER); + if (context->inUCLYhndl < 0) { + HTAnchor_copyUCInfoStage(anchor, + UCT_STAGE_PARSER, + UCT_STAGE_MIME, + -1); + context->inUCLYhndl = HTAnchor_getUCLYhndl(anchor, + UCT_STAGE_PARSER); + } + context->inUCI = HTAnchor_getUCInfoStage(anchor, + UCT_STAGE_PARSER); + set_chartrans_handling(context, anchor, -1); + + context->recover = NULL; + context->recover_index = 0; + context->include = NULL; + context->include_index = 0; + context->url = NULL; + context->csi = NULL; + context->csi_index = 0; + + return context; +} + +/* Asian character conversion functions +** ==================================== +** +** Added 24-Mar-96 by FM, based on: +** +//////////////////////////////////////////////////////////////////////// +Copyright (c) 1993 Electrotechnical Laboratry (ETL) + +Permission to use, copy, modify, and distribute this material +for any purpose and without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies, and that the name of ETL not be +used in advertising or publicity pertaining to this +material without the specific, prior written permission +of an authorized representative of ETL. +ETL MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY +OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", +WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. +///////////////////////////////////////////////////////////////////////// +Content-Type: program/C; charset=US-ASCII +Program: SJIS.c +Author: Yutaka Sato <ysato@etl.go.jp> +Description: +History: + 930923 extracted from codeconv.c of cosmos +/////////////////////////////////////////////////////////////////////// +*/ + +PUBLIC int TREAT_SJIS = 1; + +PUBLIC void JISx0201TO0208_EUC ARGS4( + register unsigned char, IHI, + register unsigned char, ILO, + register unsigned char *, OHI, + register unsigned char *, OLO) +{ + static char *table[] = { + "\xA1\xA3", "\xA1\xD6", "\xA1\xD7", "\xA1\xA2", "\xA1\xA6", "\xA5\xF2", + "\xA5\xA1", "\xA5\xA3", "\xA5\xA5", "\xA5\xA7", "\xA5\xA9", + "\xA5\xE3", "\xA5\xE5", "\xA5\xE7", "\xA5\xC3", "\xA1\xBC", + "\xA5\xA2", "\xA5\xA4", "\xA5\xA6", "\xA5\xA8", "\xA5\xAA", + "\xA5\xAB", "\xA5\xAD", "\xA5\xAF", "\xA5\xB1", "\xA5\xB3", + "\xA5\xB5", "\xA5\xB7", "\xA5\xB9", "\xA5\xBB", "\xA5\xBD", + "\xA5\xBF", "\xA5\xC1", "\xA5\xC4", "\xA5\xC6", "\xA5\xC8", + "\xA5\xCA", "\xA5\xCB", "\xA5\xCC", "\xA5\xCD", "\xA5\xCE", + "\xA5\xCF", "\xA5\xD2", "\xA5\xD5", "\xA5\xD8", "\xA5\xDB", + "\xA5\xDE", "\xA5\xDF", "\xA5\xE0", "\xA5\xE1", "\xA5\xE2", + "\xA5\xE4", "\xA5\xE6", "\xA5\xE8", "\xA5\xE9", "\xA5\xEA", + "\xA5\xEB", "\xA5\xEC", "\xA5\xED", "\xA5\xEF", "\xA5\xF3", + "\xA1\xAB", "\xA1\xAC" + }; + + if ((IHI == 0x8E) && (ILO >= 0xA1) && (ILO <= 0xDF)) { + *OHI = table[ILO - 0xA1][0]; + *OLO = table[ILO - 0xA1][1]; + } else { + *OHI = IHI; + *OLO = ILO; + } +} + +PUBLIC unsigned char * SJIS_TO_JIS1 ARGS3( + register unsigned char, HI, + register unsigned char, LO, + register unsigned char *, JCODE) +{ + HI -= (HI <= 0x9F) ? 0x71 : 0xB1; + HI = (HI << 1) + 1; + if (0x7F < LO) + LO--; + if (0x9E <= LO) { + LO -= 0x7D; + HI++; + } else { + LO -= 0x1F; + } + JCODE[0] = HI; + JCODE[1] = LO; + return JCODE; +} + +PUBLIC unsigned char * JIS_TO_SJIS1 ARGS3( + register unsigned char, HI, + register unsigned char, LO, + register unsigned char *, SJCODE) +{ + if (HI & 1) + LO += 0x1F; + else + LO += 0x7D; + if (0x7F <= LO) + LO++; + + HI = ((HI - 0x21) >> 1) + 0x81; + if (0x9F < HI) + HI += 0x40; + SJCODE[0] = HI; + SJCODE[1] = LO; + return SJCODE; +} + +PUBLIC unsigned char * EUC_TO_SJIS1 ARGS3( + unsigned char, HI, + unsigned char, LO, + register unsigned char *, SJCODE) +{ + if (HI == 0x8E) JISx0201TO0208_EUC(HI, LO, &HI, &LO); + JIS_TO_SJIS1(HI&0x7F, LO&0x7F, SJCODE); + return SJCODE; +} + +PUBLIC void JISx0201TO0208_SJIS ARGS3( + register unsigned char, I, + register unsigned char *, OHI, + register unsigned char *, OLO) +{ + unsigned char SJCODE[2]; + + JISx0201TO0208_EUC('\x8E', I, OHI, OLO); + JIS_TO_SJIS1(*OHI&0x7F, *OLO&0x7F, SJCODE); + *OHI = SJCODE[0]; + *OLO = SJCODE[1]; +} + +PUBLIC unsigned char * SJIS_TO_EUC1 ARGS3( + unsigned char, HI, + unsigned char, LO, + unsigned char *, data) +{ + SJIS_TO_JIS1(HI, LO, data); + data[0] |= 0x80; + data[1] |= 0x80; + return data; +} + +PUBLIC unsigned char * SJIS_TO_EUC ARGS2( + unsigned char *, src, + unsigned char *, dst) +{ + register unsigned char hi, lo, *sp, *dp; + register int in_sjis = 0; + + for (sp = src, dp = dst; (0 != (hi = sp[0]));) { + lo = sp[1]; + if (TREAT_SJIS && IS_SJIS(hi, lo, in_sjis)) { + SJIS_TO_JIS1(hi,lo,dp); + dp[0] |= 0x80; + dp[1] |= 0x80; + dp += 2; + sp += 2; + } else { + *dp++ = *sp++; + } + } + *dp = 0; + return dst; +} + +PUBLIC unsigned char * EUC_TO_SJIS ARGS2( + unsigned char *, src, + unsigned char *, dst) +{ + register unsigned char *sp, *dp; + + for (sp = src, dp = dst; *sp;) { + if (*sp & 0x80) { + if (sp[1] && (sp[1] & 0x80)) { + JIS_TO_SJIS1(sp[0]&0x7F, sp[1]&0x7F, dp); + dp += 2; + sp += 2; + } else { + sp++; + } + } else { + *dp++ = *sp++; + } + } + *dp = 0; + return dst; +} + +PUBLIC unsigned char * EUC_TO_JIS ARGS4( + unsigned char *, src, + unsigned char *, dst, + CONST char *, toK, + CONST char *, toA) +{ + register unsigned char kana_mode = 0; + register unsigned char cch; + register unsigned char *sp = src; + register unsigned char *dp = dst; + register int i; + + while (0 != (cch = *sp++)) { + if (cch & 0x80) { + if (!kana_mode) { + kana_mode = ~kana_mode; + for (i = 0; toK[i]; i++) { + *dp++ = (unsigned char)toK[i]; + } + } + if (*sp & 0x80) { + *dp++ = cch & ~0x80; + *dp++ = *sp++ & ~0x80; + } + } else { + if (kana_mode) { + kana_mode = ~kana_mode; + for (i = 0; toA[i]; i++) { + *dp++ = (unsigned char)toA[i]; + *dp = '\0'; + } + } + *dp++ = cch; + } + } + if (kana_mode) { + for (i = 0; toA[i]; i++) { + *dp++ = (unsigned char)toA[i]; + } + } + + if (dp) + *dp = 0; + return dst; +} + +PUBLIC unsigned char * TO_EUC ARGS2( + unsigned char *, jis, + unsigned char *, euc) +{ + register unsigned char *s, *d, c, jis_stat; + register int to1B, to2B; + register int in_sjis = 0; + + s = jis; + d = euc; + jis_stat = 0; + to2B = TO_2BCODE; + to1B = TO_1BCODE; + + while (0 != (c = *s++)) { + if (c == ESC) { + if (*s == to2B) { + if ((s[1] == 'B') || (s[1] == '@') || (s[1] == 'A')) { + jis_stat = 0x80; + s += 2; + continue; + } else if ((s[1] == '(') && s[2] && (s[2] == 'C')) { + jis_stat = 0x80; + s += 3; + continue; + } + } else { + if (*s == to1B) { + if ((s[1]=='B') || (s[1]=='J') || + (s[1]=='H') || (s[1]=='T')) { + jis_stat = 0; + s += 2; + continue; + } + } + } + } + if (IS_SJIS(c,*s,in_sjis)) { + SJIS_TO_EUC1(c, *s, d); + d += 2; + s++; + } else { + if (jis_stat && (0x20 < c)) { + *d++ = jis_stat | c; + } else { + *d++ = c; + } + } + } + *d = 0; + return euc; +} + +PUBLIC void TO_SJIS ARGS2( + unsigned char *, any, + unsigned char *, sjis) +{ + unsigned char *euc; + + if (!any || !sjis) + return; + + euc = (unsigned char*)malloc(strlen((CONST char *)any)+1); + if (euc == NULL) + outofmem(__FILE__, "TO_SJIS"); + + TO_EUC(any, euc); + EUC_TO_SJIS(euc, sjis); + FREE(euc); +} + +PUBLIC void TO_JIS ARGS2( + unsigned char *, any, + unsigned char *, jis) +{ + unsigned char *euc; + + if (!any || !jis) + return; + + euc = (unsigned char*)malloc(strlen((CONST char *)any)+1); + if (euc == NULL) + outofmem(__FILE__, "TO_JIS"); + + TO_EUC(any, euc); + EUC_TO_JIS(euc, jis, TO_KANJI, TO_ASCII); + FREE(euc); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.h new file mode 100644 index 00000000000..09ff6fe93a4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.h @@ -0,0 +1,272 @@ +/* SGML parse and stream definition for libwww + SGML AND STRUCTURED STREAMS + + The SGML parser is a state machine. It is called for every character + + of the input stream. The DTD data structure contains pointers + + to functions which are called to implement the actual effect of the + + text read. When these functions are called, the attribute structures pointed to by the + DTD are valid, and the function is passed a pointer to the curent tag structure, and an + "element stack" which represents the state of nesting within SGML elements. + + The following aspects are from Dan Connolly's suggestions: Binary search, Strcutured + object scheme basically, SGML content enum type. + + (c) Copyright CERN 1991 - See Copyright.html + + */ +#ifndef SGML_H +#define SGML_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* HTUTILS_H */ +#include "HTStream.h" +#include "HTAnchor.h" + +/* + +SGML content types + + */ +typedef enum _SGMLContent { + SGML_EMPTY, /* No content. */ + SGML_LITTERAL, /* Literal character data. Recognize exact close tag only. + Old www server compatibility only! Not SGML */ + SGML_CDATA, /* Character data. Recognize </ only. */ + SGML_RCDATA, /* Replaceable character data. Recognize </ and &ref; */ + SGML_MIXED, /* Elements and parsed character data. + Recognize all markup. */ + SGML_ELEMENT, /* Any data found will be returned as an error. */ + SGML_PCDATA /* Added by KW. */ +} SGMLContent; + + +typedef struct { + char * name; /* The (constant) name of the attribute */ + /* Could put type info in here */ +} attr; + +typedef enum _TagClass { + /* textflow */ + Tgc_FONTlike = 0x00001,/* S,STRIKE,I,B,TT,U,BIG,SMALL,STYLE,BLINK;BR,TAB */ + Tgc_EMlike = 0x00002, /* EM,STRONG,DFN,CODE,SAMP,KBD,VAR,CITE,Q,INS,DEL,SPAN,.. */ + Tgc_MATHlike = 0x00004, /* SUB,SUP,MATH,COMMENT */ + Tgc_Alike = 0x00008, /* A */ + Tgc_formula = 0x00010, /* not used until math is supported better... */ + /* used for special structures: forms, tables,... */ + Tgc_TRlike = 0x00020,/* TR and similar */ + Tgc_SELECTlike = 0x00040,/* SELECT,INPUT,TEXTAREA(,...) */ + /* structure */ + Tgc_FORMlike = 0x00080,/* FORM itself */ + Tgc_Plike = 0x00100, /* P,H1..H6,... structures containing text or + insertion but not other structures */ + Tgc_DIVlike = 0x00200, /* ADDRESS,FIG,BDO,NOTE,FN,DIV,CENTER;FIG + structures which can contain other structures */ + Tgc_LIlike = 0x00400, /* LH,LI,DT,DD;TH,TD structure-like, only valid + within certain other structures */ + Tgc_ULlike = 0x00800, /* UL,OL,DL,DIR,MENU;TABLE;XMP,LISTING + special in some way, cannot contain (parsed) + text directly */ + /* insertions */ + Tgc_BRlike = 0x01000,/* BR,IMG,TAB allowed in any text */ + Tgc_APPLETlike = 0x02000, /* APPLET,OBJECT,EMBED,SCRIPT */ + Tgc_HRlike = 0x04000, /* HR,MARQUEE can contain all kinds of things + and/or are not allowed (?) in running text */ + Tgc_MAPlike = 0x08000, /* MAP,AREA some specials that never contain + (directly or indirectly) other things than + special insertions */ + Tgc_outer = 0x10000, /* HTML,FRAMESET,FRAME,PLAINTEXT; */ + Tgc_BODYlike = 0x20000, /* BODY,BODYTEXT,NOFRAMES,TEXTFLOW; */ + Tgc_HEADstuff = 0x40000, /* HEAD,BASE,STYLE,TITLE; */ + /* special relations */ + Tgc_same = 0x80000 +} TagClass; + +/* Some more properties of tags (or rather, elements) and rules how + to deal with them. - kw */ +typedef enum _TagFlags { + Tgf_endO = 0x00001, /* end tag can be Omitted */ + Tgf_startO = 0x00002, /* start tag can be Omitted */ + Tgf_mafse = 0x00004, /* Make Attribute-Free Start-tag End instead + (if found invalid) */ + Tgf_strict = 0x00008 /* Ignore contained invalid elements, + don't pass them on */ +} TagFlags; + +/* A tag structure describes an SGML element. +** ----------------------------------------- +** +** +** name is the string which comes after the tag opener "<". +** +** attributes points to a zero-terminated array +** of attribute names. +** +** litteral determines how the SGML engine parses the charaters +** within the element. If set, tag openers are ignored +** except for that which opens a matching closing tag. +** +*/ +typedef struct _tag HTTag; +struct _tag{ + char * name; /* The name of the tag */ + attr * attributes; /* The list of acceptable attributes */ + int number_of_attributes; /* Number of possible attributes */ + SGMLContent contents; /* End only on end tag @@ */ + TagClass tagclass, + contains, /* which classes of elements this one can contain directly */ + icontains, /* which classes of elements this one can contain indirectly */ + contained, /* in which classes can this tag be contained ? */ + icontained, /* in which classes can this tag be indirectly contained ? */ + canclose; /* which classes of elements can this one close + if something looks wrong ? */ + TagFlags flags; +}; + + +/* DTD Information +** --------------- +** +** Not the whole DTD, but all this parser uses of it. +*/ +typedef struct { + char* name; + long code; +} UC_entity_info; + +typedef struct { + HTTag * tags; /* Must be in strcmp order by name */ + int number_of_tags; + CONST char ** entity_names; /* Must be in strcmp order by name */ + size_t number_of_entities; + CONST UC_entity_info * unicode_entity_info; /* strcmp order by name */ + size_t number_of_unicode_entities; + /* + ** All calls to unicode_entities table should be done + ** through HTMLGetEntityUCValue (LYCharSets.c) only. + ** unicode_entities table now holds *all* + ** old-style entities too. + */ +} SGML_dtd; + + +/* SGML context passed to parsers +*/ +typedef struct _HTSGMLContext *HTSGMLContext; /* Hidden */ + + +/*__________________________________________________________________________ +*/ + +/* + +Structured Object definition + + A structured object is something which can reasonably be represented + in SGML. I'll rephrase that. A structured object is am ordered + tree-structured arrangement of data which is representable as text. + The SGML parer outputs to a Structured object. A Structured object + can output its contents to another Structured Object. It's a kind of + typed stream. The architecure is largely Dan Conolly's. Elements and + entities are passed to the sob by number, implying a knowledge of the + DTD. Knowledge of the SGML syntax is not here, though. + + Superclass: HTStream + + The creation methods will vary on the type of Structured Object. + Maybe the callerData is enough info to pass along. + + */ +typedef struct _HTStructured HTStructured; + +typedef struct _HTStructuredClass{ + + char* name; /* Just for diagnostics */ + + void (*_free) PARAMS(( + HTStructured* me)); + + void (*_abort) PARAMS(( + HTStructured* me, + HTError e)); + + void (*put_character) PARAMS(( + HTStructured* me, + char ch)); + + void (*put_string) PARAMS(( + HTStructured* me, + CONST char * str)); + + void (*_write) PARAMS(( + HTStructured* me, + CONST char * str, + int len)); + + void (*start_element) PARAMS(( + HTStructured* me, + int element_number, + CONST BOOL* attribute_present, + CONST char** attribute_value, + int charset, + char ** include)); + + void (*end_element) PARAMS(( + HTStructured* me, + int element_number, + char ** include)); + + int (*put_entity) PARAMS(( + HTStructured* me, + int entity_number)); + +}HTStructuredClass; + +/* + Equivalents to the following functions possibly could be generalised + into additional HTStructuredClass members. FOr now they don't do + anything target-specific. - kw + */ +extern BOOLEAN LYCheckForCSI PARAMS((HTParentAnchor *anchor, char **url)); +extern void LYDoCSI PARAMS((char *url, CONST char *comment, char **csi)); + +/* + +Find a Tag by Name + + Returns a pointer to the tag within the DTD. + + */ +extern HTTag * SGMLFindTag PARAMS(( + CONST SGML_dtd * dtd, + CONST char * string)); + + +/* + +Create an SGML parser + + */ +/* +** On entry, +** dtd must point to a DTD structure as defined above +** callbacks must point to user routines. +** callData is returned in callbacks transparently. +** On exit, +** The default tag starter has been processed. +*/ +extern HTStream * SGML_new PARAMS(( + CONST SGML_dtd * dtd, + HTParentAnchor * anchor, + HTStructured * target)); + +extern CONST HTStreamClass SGMLParser; + +#endif /* SGML_H */ + +/* + + */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/UCAux.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCAux.h new file mode 100644 index 00000000000..b350e617e81 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCAux.h @@ -0,0 +1,70 @@ +#ifndef UCAUX_H +#define UCAUX_H + +extern BOOL UCCanUniTranslateFrom PARAMS((int from)); +extern BOOL UCCanTranslateUniTo PARAMS((int to)); +extern BOOL UCCanTranslateFromTo PARAMS((int from, int to)); +extern BOOL UCNeedNotTranslate PARAMS(( + int from, + int to)); + +struct _UCTransParams +{ + BOOL transp; + BOOL do_cjk; + BOOL decode_utf8; + BOOL output_utf8; + BOOL use_raw_char_in; + BOOL strip_raw_char_in; + BOOL pass_160_173_raw; + BOOL do_8bitraw; + BOOL trans_to_uni; + BOOL trans_C0_to_uni; + BOOL repl_translated_C0; + BOOL trans_from_uni; +}; +typedef struct _UCTransParams UCTransParams; + +#ifndef UCDEFS_H +#include "UCDefs.h" +#endif /* UCDEFS_H */ + +extern void UCSetTransParams PARAMS(( + UCTransParams * pT, + int cs_in, + CONST LYUCcharset * p_in, + int cs_out, + CONST LYUCcharset * p_out)); + +extern void UCTransParams_clear PARAMS(( + UCTransParams * pT)); + +extern void UCSetBoxChars PARAMS(( + int cset, + int * pvert_out, + int * phori_out, + int vert_in, + int hori_in)); + +#ifndef HTSTREAM_H +#include "HTStream.h" +#endif /* HTSTREAM_H */ + +typedef void putc_func_t PARAMS(( + HTStream * me, + char ch)); + +#ifndef UCMAP_H +#include "UCMap.h" +#endif /* UCMAP_H */ + +extern BOOL UCPutUtf8_charstring PARAMS(( + HTStream * target, + putc_func_t * actions, + UCode_t code)); + +extern BOOL UCConvertUniToUtf8 PARAMS(( + UCode_t code, + char * buffer)); + +#endif /* UCAUX_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/UCDefs.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCDefs.h new file mode 100644 index 00000000000..ac2dc3bc2cb --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCDefs.h @@ -0,0 +1,86 @@ +/* Definitions for Unicode character-translations */ + +#ifndef UCDEFS_H +#define UCDEFS_H + +typedef struct _LYUCcharset { + int UChndl; + CONST char * MIMEname; + int enc; + int repertoire; + int codepoints; + int cpranges; /* which ranges have valid displayable chars + (including nbsp and shy) */ + int like8859; /* for which ranges is it like 8859-1 */ +} LYUCcharset; + +#define UCT_ENC_7BIT 0 +#define UCT_ENC_8BIT 1 +#define UCT_ENC_8859 2 +#define UCT_ENC_8BIT_C0 3 /* 8-bit some chars in C0 control area */ +#define UCT_ENC_MAYBE2022 4 +#define UCT_ENC_CJK 5 +#define UCT_ENC_16BIT 6 +#define UCT_ENC_UTF8 7 + + +#define UCT_REP_SUBSETOF_LAT1 0x01 +#define UCT_REP_SUPERSETOF_LAT1 0x02 +#define UCT_REP_IS_LAT1 UCT_REP_SUBSETOF_LAT1 | UCT_REP_SUPERSETOF_LAT1 +/* + * Assume everything we deal with is included in the UCS2 reperoire, + * so a flag for _REP_SUBSETOF_UCS2 would be redundant. + */ + +/* + * More general description how the code points relate to 8859-1 and UCS: + */ +#define UCT_CP_SUBSETOF_LAT1 0x01 /* implies UCT_CP_SUBSETOF_UCS2 */ +#define UCT_CP_SUPERSETOF_LAT1 0x02 +#define UCT_CP_SUBSETOF_UCS2 0x04 + +#define UCT_CP_IS_LAT1 UCT_CP_SUBSETOF_LAT1 | UCT_CP_SUPERSETOF_LAT1 + +/* + * More specific bitflags for practically important code point ranges: + */ +#define UCT_R_LOWCTRL 0x08 /* 0x00-0x1F, for completeness */ +#define UCT_R_7BITINV 0x10 /* invariant, displayable 7bit chars */ +#define UCT_R_7BITNAT 0x20 /* displayable 7bit, national */ +#define UCT_R_HIGHCTRL 0x40 +#define UCT_R_8859SPECL 0x80 /* special chars in 8859-x sets: nbsp and shy*/ +#define UCT_R_HIGH8BIT 0x100 /* rest of 0xA0-0xFF range */ + +#define UCT_R_ASCII UCT_R_7BITINV | UCT_R_7BITNAT /*displayable US-ASCII*/ +#define UCT_R_LAT1 UCT_R_ASCII | UCT_R_8859SPECL | UCT_R_HIGH8BIT +#define UCT_R_8BIT UCT_R_LAT1 | UCT_R_HIGHCTRL /* full 8bit range */ + +/* + * For the following some comments are in HTAnchor.c. + */ +#define UCT_STAGE_MIME 0 +#define UCT_STAGE_PARSER 1 /* What the parser (SGML.c) gets to see */ +#define UCT_STAGE_STRUCTURED 2 /* What the structured stream (HTML) gets fed*/ +#define UCT_STAGE_HTEXT 3 /* What gets fed to the HText_* functions */ +#define UCT_STAGEMAX 4 + +#define UCT_SETBY_NONE 0 +#define UCT_SETBY_DEFAULT 1 +#define UCT_SETBY_LINK 2 /* set by A or LINK CHARSET= hint */ +#define UCT_SETBY_STRUCTURED 3 /* structured stream stage (HTML.c) */ +#define UCT_SETBY_PARSER 4 /* set by SGML parser or similar */ +#define UCT_SETBY_MIME 5 /* set explicitly by MIME charset parameter */ + +typedef struct _UCStageInfo +{ + int lock; /* by what it has been set */ + int LYhndl; + LYUCcharset C; +} UCStageInfo; + +typedef struct _UCAnchorInfo +{ + struct _UCStageInfo s[UCT_STAGEMAX]; +} UCAnchorInfo; + +#endif /* UCDEFS_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/UCMap.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCMap.h new file mode 100644 index 00000000000..e634f760ee0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/UCMap.h @@ -0,0 +1,48 @@ + +#ifndef UCMAP_H +#define UCMAP_H + +typedef long UCode_t; + +extern int UCTransUniChar PARAMS(( + UCode_t unicode, + int charset_out)); +extern int UCTransUniCharStr PARAMS(( + char * outbuf, + int buflen, + UCode_t unicode, + int charset_out, + int chk_single_flag)); +extern int UCTransChar PARAMS(( + char ch_in, + int charset_in, + int charset_out)); +extern int UCReverseTransChar PARAMS(( + char ch_out, + int charset_in, + int charset_out)); +extern int UCTransCharStr PARAMS(( + char * outbuf, + int buflen, + char ch_in, + int charset_in, + int charset_out, + int chk_single_flag)); +extern UCode_t UCTransToUni PARAMS(( + char ch_in, + int charset_in)); +extern int UCGetLYhndl_byMIME PARAMS(( + CONST char * p)); +extern int UCGetRawUniMode_byLYhndl PARAMS(( + int i)); + +extern int UCLYhndl_for_unspec; +extern int UCLYhndl_for_unrec; +extern int UCLYhndl_HTFile_for_unspec; +extern int UCLYhndl_HTFile_for_unrec; + +#define UCTRANS_NOTFOUND (-4) + +#define HT_CANNOT_TRANSLATE -4 /* could go into HTUtils.h */ + +#endif /* UCMAP_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/Version.make b/gnu/usr.bin/lynx/WWW/Library/Implementation/Version.make new file mode 100644 index 00000000000..4b4b380f32b --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/Version.make @@ -0,0 +1 @@ +VC = 2.14 diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt.c new file mode 100644 index 00000000000..ffc466c7126 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt.c @@ -0,0 +1,129 @@ +/* + * UFC-crypt: ultra fast crypt(3) implementation + * + * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * @(#)crypt.c 2.19 5/28/92 + * + * Semiportable C version + * + */ + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif + +#include "ufc-crypt.h" + +#include "LYLeaks.h" + +#ifdef _UFC_32_ + +/* + * 32 bit version + */ + +extern long32 _ufc_keytab[16][2]; +extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; + +#define SBA(sb, v) (*(long32*)((char*)(sb)+(v))) + +static ufc_long ary[4]; + +ufc_long *_ufc_doit(l1, l2, r1, r2, itr) + ufc_long l1, l2, r1, r2, itr; + { int i; + long32 s, *k; + register long32 *sb0 = _ufc_sb0; + register long32 *sb1 = _ufc_sb1; + register long32 *sb2 = _ufc_sb2; + register long32 *sb3 = _ufc_sb3; + + while(itr--) { + k = &_ufc_keytab[0][0]; + for(i=8; i--; ) { + s = *k++ ^ r1; + l1 ^= SBA(sb1, s & 0xffff); l2 ^= SBA(sb1, (s & 0xffff)+4); + l1 ^= SBA(sb0, s >>= 16); l2 ^= SBA(sb0, (s) +4); + s = *k++ ^ r2; + l1 ^= SBA(sb3, s & 0xffff); l2 ^= SBA(sb3, (s & 0xffff)+4); + l1 ^= SBA(sb2, s >>= 16); l2 ^= SBA(sb2, (s) +4); + + s = *k++ ^ l1; + r1 ^= SBA(sb1, s & 0xffff); r2 ^= SBA(sb1, (s & 0xffff)+4); + r1 ^= SBA(sb0, s >>= 16); r2 ^= SBA(sb0, (s) +4); + s = *k++ ^ l2; + r1 ^= SBA(sb3, s & 0xffff); r2 ^= SBA(sb3, (s & 0xffff)+4); + r1 ^= SBA(sb2, s >>= 16); r2 ^= SBA(sb2, (s) +4); + } + s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s; + } + ary[0] = l1; ary[1] = l2; ary[2] = r1; ary[3] = r2; + return ary; + } + +#endif + +#ifdef _UFC_64_ + +/* + * 64 bit version + */ + +extern long64 _ufc_keytab[16]; +extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; + +#define SBA(sb, v) (*(long64*)((char*)(sb)+(v))) + +static ufc_long ary[4]; + +ufc_long *_ufc_doit(l1, l2, r1, r2, itr) + ufc_long l1, l2, r1, r2, itr; + { int i; + long64 l, r, s, *k; + register long64 *sb0 = _ufc_sb0; + register long64 *sb1 = _ufc_sb1; + register long64 *sb2 = _ufc_sb2; + register long64 *sb3 = _ufc_sb3; + + l = (((long64)l1) << 32) | ((long64)l2); + r = (((long64)r1) << 32) | ((long64)r2); + + while(itr--) { + k = &_ufc_keytab[0]; + for(i=8; i--; ) { + s = *k++ ^ r; + l ^= SBA(sb3, (s >> 0) & 0xffff); + l ^= SBA(sb2, (s >> 16) & 0xffff); + l ^= SBA(sb1, (s >> 32) & 0xffff); + l ^= SBA(sb0, (s >> 48) & 0xffff); + + s = *k++ ^ l; + r ^= SBA(sb3, (s >> 0) & 0xffff); + r ^= SBA(sb2, (s >> 16) & 0xffff); + r ^= SBA(sb1, (s >> 32) & 0xffff); + r ^= SBA(sb0, (s >> 48) & 0xffff); + } + s=l; l=r; r=s; + } + + ary[0] = l >> 32; ary[1] = l & 0xffffffff; + ary[2] = r >> 32; ary[3] = r & 0xffffffff; + return ary; + } + +#endif diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt_util.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt_util.c new file mode 100644 index 00000000000..9ed7e95d4da --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/crypt_util.c @@ -0,0 +1,981 @@ +/* + * UFC-crypt: ultra fast crypt(3) implementation + * + * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * @(#)crypt_util.c 2.40 09/21/92 + * + * Support routines + * + */ + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif + +#ifdef DEBUG +/*#include <stdio.h> included by HTUTils.h - FM */ +#endif + +#ifndef STATIC +#define STATIC static +#endif + +#ifndef DOS +#include "patchlevel.h" +#include "ufc-crypt.h" +#else +/* + * Thanks to greg%wind@plains.NoDak.edu (Greg W. Wettstein) + * for DOS patches + */ +#include "pl.h" +#include "ufc.h" +#endif + +#include "LYLeaks.h" + +static char patchlevel_str[] = PATCHLEVEL; + +/* + * Permutation done once on the 56 bit + * key derived from the original 8 byte ASCII key. + */ +static int pc1[56] = { + 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 +}; + +/* + * How much to rotate each 28 bit half of the pc1 permutated + * 56 bit key before using pc2 to give the i' key + */ +static int rots[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +/* + * Permutation giving the key + * of the i' DES round + */ +static int pc2[48] = { + 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +/* + * The E expansion table which selects + * bits from the 32 bit intermediate result. + */ +static int esel[48] = { + 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 +}; +static int e_inverse[64]; + +/* + * Permutation done on the + * result of sbox lookups + */ +static int perm32[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 +}; + +/* + * The sboxes + */ +static int sbox[8][4][16]= { + { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }, + { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 }, + { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 }, + { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } + }, + + { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, + { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 }, + { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 }, + { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } + }, + + { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, + { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 }, + { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 }, + { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } + }, + + { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, + { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 }, + { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 }, + { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } + }, + + { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, + { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 }, + { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 }, + { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } + }, + + { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, + { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 }, + { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 }, + { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } + }, + + { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, + { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 }, + { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 }, + { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } + }, + + { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, + { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 }, + { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 }, + { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } + } +}; + +/* + * This is the initial + * permutation matrix + */ +static int initial_perm[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 +}; + +/* + * This is the final + * permutation matrix + */ +static int final_perm[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 +}; + +/* + * The 16 DES keys in BITMASK format + */ +#ifdef _UFC_32_ +long32 _ufc_keytab[16][2]; +#endif +#ifdef _UFC_64_ +long64 _ufc_keytab[16]; +#endif + +#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') +#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') + +/* Macro to set a bit (0..23) */ +#define BITMASK(i) ( (1L<<(11L-(i)%12L+3L)) << ((i)<12L?16L:0L) ) + +/* + * sb arrays: + * + * Workhorses of the inner loop of the DES implementation. + * They do sbox lookup, shifting of this value, 32 bit + * permutation and E permutation for the next round. + * + * Kept in 'BITMASK' format. + */ + +#ifdef _UFC_32_ +long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192]; +static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +#endif + +#ifdef _UFC_64_ +long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096]; +static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +#endif + +/* + * eperm32tab: do 32 bit permutation and E selection + * + * The first index is the byte number in the 32 bit value to be permuted + * - second - is the value of this byte + * - third - selects the two 32 bit values + * + * The table is used and generated internally in init_des to speed it up + */ +static ufc_long eperm32tab[4][256][2]; + +/* + * do_pc1: permform pc1 permutation in the key schedule generation. + * + * The first index is the byte number in the 8 byte ASCII key + * - second - - the two 28 bits halfs of the result + * - third - selects the 7 bits actually used of each byte + * + * The result is kept with 28 bit per 32 bit with the 4 most significant + * bits zero. + */ +static ufc_long do_pc1[8][2][128]; + +/* + * do_pc2: permform pc2 permutation in the key schedule generation. + * + * The first index is the septet number in the two 28 bit intermediate values + * - second - - - septet values + * + * Knowledge of the structure of the pc2 permutation is used. + * + * The result is kept with 28 bit per 32 bit with the 4 most significant + * bits zero. + */ +static ufc_long do_pc2[8][128]; + +/* + * efp: undo an extra e selection and do final + * permutation giving the DES result. + * + * Invoked 6 bit a time on two 48 bit values + * giving two 32 bit longs. + */ +static ufc_long efp[16][64][2]; + +/* + * revfinal: undo final permutation and do E expension. + * + * Invoked 6 bit a time on DES output + * giving 4 32 bit longs. + */ +static ufc_long revfinal[11][64][4]; + + +static unsigned char bytemask[8] = { + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + +static ufc_long longmask[32] = { + 0x80000000, 0x40000000, 0x20000000, 0x10000000, + 0x08000000, 0x04000000, 0x02000000, 0x01000000, + 0x00800000, 0x00400000, 0x00200000, 0x00100000, + 0x00080000, 0x00040000, 0x00020000, 0x00010000, + 0x00008000, 0x00004000, 0x00002000, 0x00001000, + 0x00000800, 0x00000400, 0x00000200, 0x00000100, + 0x00000080, 0x00000040, 0x00000020, 0x00000010, + 0x00000008, 0x00000004, 0x00000002, 0x00000001 +}; + +#ifdef DEBUG + +pr_bits(a, n) + ufc_long *a; + int n; + { ufc_long i, j, t, tmp; + n /= 8; + for(i = 0; i < n; i++) { + tmp=0; + for(j = 0; j < 8; j++) { + t=8*i+j; + tmp|=(a[t/24] & BITMASK(t % 24))?bytemask[j]:0; + } + (void)printf("%02x ",tmp); + } + printf(" "); + } + +static set_bits(v, b) + ufc_long v; + ufc_long *b; + { ufc_long i; + *b = 0; + for(i = 0; i < 24; i++) { + if(v & longmask[8 + i]) + *b |= BITMASK(i); + } + } + +#endif + +/* + * Silly rewrite of 'bzero'. I do so + * because some machines don't have + * bzero and some don't have memset. + */ + +STATIC void clearmem(start, cnt) + char *start; + int cnt; + { while(cnt--) + *start++ = '\0'; + } + +static int initialized = 0; + +/* lookup a 6 bit value in sbox */ + +#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf]; + +/* + * Initialize unit - may be invoked directly + * by fcrypt users. + */ + +void init_des() + { int comes_from_bit; + int bit, sg; + ufc_long j; + ufc_long mask1, mask2; + + /* + * Create the do_pc1 table used + * to affect pc1 permutation + * when generating keys + */ + for(bit = 0; bit < 56; bit++) { + comes_from_bit = pc1[bit] - 1; + mask1 = bytemask[comes_from_bit % 8 + 1]; + mask2 = longmask[bit % 28 + 4]; + for(j = 0; j < 128; j++) { + if(j & mask1) + do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2; + } + } + + /* + * Create the do_pc2 table used + * to affect pc2 permutation when + * generating keys + */ + for(bit = 0; bit < 48; bit++) { + comes_from_bit = pc2[bit] - 1; + mask1 = bytemask[comes_from_bit % 7 + 1]; + mask2 = BITMASK(bit % 24); + for(j = 0; j < 128; j++) { + if(j & mask1) + do_pc2[comes_from_bit / 7][j] |= mask2; + } + } + + /* + * Now generate the table used to do combined + * 32 bit permutation and e expansion + * + * We use it because we have to permute 16384 32 bit + * longs into 48 bit in order to initialize sb. + * + * Looping 48 rounds per permutation becomes + * just too slow... + * + */ + + clearmem((char*)eperm32tab, sizeof(eperm32tab)); + + for(bit = 0; bit < 48; bit++) { + ufc_long mask1,comes_from; + + comes_from = perm32[esel[bit]-1]-1; + mask1 = bytemask[comes_from % 8]; + + for(j = 256; j--;) { + if(j & mask1) + eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24); + } + } + + /* + * Create the sb tables: + * + * For each 12 bit segment of an 48 bit intermediate + * result, the sb table precomputes the two 4 bit + * values of the sbox lookups done with the two 6 + * bit halves, shifts them to their proper place, + * sends them through perm32 and finally E expands + * them so that they are ready for the next + * DES round. + * + */ + for(sg = 0; sg < 4; sg++) { + int j1, j2; + int s1, s2; + + for(j1 = 0; j1 < 64; j1++) { + s1 = s_lookup(2 * sg, j1); + for(j2 = 0; j2 < 64; j2++) { + ufc_long to_permute, inx; + + s2 = s_lookup(2 * sg + 1, j2); + to_permute = (((ufc_long)s1 << 4) | + (ufc_long)s2) << (24 - 8 * (ufc_long)sg); + +#ifdef _UFC_32_ + inx = ((j1 << 6) | j2) << 1; + sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0]; + sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1]; + sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0]; + sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1]; +#endif +#ifdef _UFC_64_ + inx = ((j1 << 6) | j2); + sb[sg][inx] = + ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) | + (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) | + (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) | + (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1]; + sb[sg][inx] |= + ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) | + (long64)eperm32tab[3][(to_permute) & 0xff][1]; +#endif + } + } + } + + /* + * Create an inverse matrix for esel telling + * where to plug out bits if undoing it + */ + for(bit=48; bit--;) { + e_inverse[esel[bit] - 1 ] = bit; + e_inverse[esel[bit] - 1 + 32] = bit + 48; + } + + /* + * create efp: the matrix used to + * undo the E expansion and effect final permutation + */ + clearmem((char*)efp, sizeof efp); + for(bit = 0; bit < 64; bit++) { + int o_bit, o_long; + ufc_long word_value, mask1, mask2; + int comes_from_f_bit, comes_from_e_bit; + int comes_from_word, bit_within_word; + + /* See where bit i belongs in the two 32 bit long's */ + o_long = bit / 32; /* 0..1 */ + o_bit = bit % 32; /* 0..31 */ + + /* + * And find a bit in the e permutated value setting this bit. + * + * Note: the e selection may have selected the same bit several + * times. By the initialization of e_inverse, we only look + * for one specific instance. + */ + comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */ + comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */ + comes_from_word = comes_from_e_bit / 6; /* 0..15 */ + bit_within_word = comes_from_e_bit % 6; /* 0..5 */ + + mask1 = longmask[bit_within_word + 26]; + mask2 = longmask[o_bit]; + + for(word_value = 64; word_value--;) { + if(word_value & mask1) + efp[comes_from_word][word_value][o_long] |= mask2; + } + } + + + /* + * Create revfinal: an array to undo final + * the effects of efp + */ + clearmem((char*)revfinal, sizeof(revfinal)); + for(bit = 0; bit < 96; bit++) { + int ibit = initial_perm[esel[bit % 48] - 1 + ((bit >= 48) ? 32 : 0)] - 1; + mask1 = bytemask[ibit % 6 + 2]; + mask2 = BITMASK(bit % 24); + for(j = 64; j--;) { + if(j & mask1) { + revfinal[ibit / 6][j][bit / 24] |= mask2; + } + } + } + + initialized++; + } + +/* + * Process the elements of the sb table permuting the + * bits swapped in the expansion by the current salt. + */ + +#ifdef _UFC_32_ +STATIC void shuffle_sb(k, saltbits) + long32 *k; + ufc_long saltbits; + { ufc_long j; + long32 x; + for(j=4096; j--;) { + x = (k[0] ^ k[1]) & (long32)saltbits; + *k++ ^= x; + *k++ ^= x; + } + } +#endif + +#ifdef _UFC_64_ +STATIC void shuffle_sb(k, saltbits) + long64 *k; + ufc_long saltbits; + { ufc_long j; + long64 x; + for(j=4096; j--;) { + x = ((*k >> 32) ^ *k) & (long64)saltbits; + *k++ ^= (x << 32) | x; + } + } +#endif + +/* + * Setup the unit for a new salt + * Hopefully we'll not see a new salt in each crypt call. + */ + +static unsigned char current_salt[3] = "&&"; /* invalid value */ +static ufc_long current_saltbits = 0; +static int direction = 0; + +STATIC void setup_salt(s) + char *s; + { ufc_long i, j, saltbits; + + if(!initialized) + init_des(); + + if(s[0] == current_salt[0] && s[1] == current_salt[1]) + return; + current_salt[0] = s[0]; current_salt[1] = s[1]; + + /* + * This is the only crypt change to DES: + * entries are swapped in the expansion table + * according to the bits set in the salt. + */ + saltbits = 0; + for(i = 0; i < 2; i++) { + long c=ascii_to_bin(s[i]); +#ifdef notdef + /* + * Some applications do rely on illegal + * salts. It seems that UFC-crypt behaves + * identically to standard crypt + * implementations on illegal salts -- glad + */ + if(c < 0 || c > 63) + c = 0; +#endif + for(j = 0; j < 6; j++) { + if((c >> j) & 0x1) + saltbits |= BITMASK(6 * i + j); + } + } + + /* + * Permute the sb table values + * to reflect the changed e + * selection table + */ + shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits); + + current_saltbits = saltbits; + } + +STATIC void ufc_mk_keytab(key) + char *key; + { ufc_long v1, v2, *k1; + int i; +#ifdef _UFC_32_ + long32 v, *k2 = &_ufc_keytab[0][0]; +#endif +#ifdef _UFC_64_ + long64 v, *k2 = &_ufc_keytab[0]; +#endif + + v1 = v2 = 0; k1 = &do_pc1[0][0][0]; + for(i = 8; i--;) { + v1 |= k1[*key & 0x7f]; k1 += 128; + v2 |= k1[*key++ & 0x7f]; k1 += 128; + } + + for(i = 0; i < 16; i++) { + k1 = &do_pc2[0][0]; + + v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i])); + v = k1[(v1 >> 21) & 0x7f]; k1 += 128; + v |= k1[(v1 >> 14) & 0x7f]; k1 += 128; + v |= k1[(v1 >> 7) & 0x7f]; k1 += 128; + v |= k1[(v1 ) & 0x7f]; k1 += 128; + +#ifdef _UFC_32_ + *k2++ = v; + v = 0; +#endif +#ifdef _UFC_64_ + v <<= 32; +#endif + + v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i])); + v |= k1[(v2 >> 21) & 0x7f]; k1 += 128; + v |= k1[(v2 >> 14) & 0x7f]; k1 += 128; + v |= k1[(v2 >> 7) & 0x7f]; k1 += 128; + v |= k1[(v2 ) & 0x7f]; + + *k2++ = v; + } + + direction = 0; + } + +/* + * Undo an extra E selection and do final permutations + */ + +ufc_long *_ufc_dofinalperm(l1, l2, r1, r2) + ufc_long l1,l2,r1,r2; + { ufc_long v1, v2, x; + static ufc_long ary[2]; + + x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x; + x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x; + + v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3; + + v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1]; + v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1]; + v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1]; + v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1]; + + v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1]; + v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1]; + v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1]; + v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1]; + + v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1]; + v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1]; + v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1]; + v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1]; + + v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1]; + v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1]; + v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1]; + v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1]; + + ary[0] = v1; ary[1] = v2; + return ary; + } + +/* + * crypt only: convert from 64 bit to 11 bit ASCII + * prefixing with the salt + */ + +STATIC char *output_conversion(v1, v2, salt) + ufc_long v1, v2; + char *salt; + { static char outbuf[14]; + int i, s, shf; + + outbuf[0] = salt[0]; + outbuf[1] = salt[1] ? salt[1] : salt[0]; + + for(i = 0; i < 5; i++) { + shf = (26 - 6 * i); /* to cope with MSC compiler bug */ + outbuf[i + 2] = bin_to_ascii((v1 >> shf) & 0x3f); + } + + s = (v2 & 0xf) << 2; + v2 = (v2 >> 2) | ((v1 & 0x3) << 30); + + for(i = 5; i < 10; i++) { + shf = (56 - 6 * i); + outbuf[i + 2] = bin_to_ascii((v2 >> shf) & 0x3f); + } + + outbuf[12] = bin_to_ascii(s); + outbuf[13] = 0; + + return outbuf; + } + +ufc_long *_ufc_doit(); + +/* + * UNIX crypt function + */ + +char *crypt(key, salt) + char *key, *salt; + { ufc_long *s; + char ktab[9]; + + /* + * Hack DES tables according to salt + */ + setup_salt(salt); + + /* + * Setup key schedule + */ + clearmem(ktab, sizeof ktab); + (void)strncpy(ktab, key, 8); + ufc_mk_keytab(ktab); + + /* + * Go for the 25 DES encryptions + */ + s = _ufc_doit((ufc_long)0, (ufc_long)0, + (ufc_long)0, (ufc_long)0, (ufc_long)25); + /* + * Do final permutations + */ + s = _ufc_dofinalperm(s[0], s[1], s[2], s[3]); + + /* + * And convert back to 6 bit ASCII + */ + return output_conversion(s[0], s[1], salt); + } + +/* + * To make fcrypt users happy. + * They don't need to call init_des. + */ + +char *fcrypt(key, salt) + char *key; + char *salt; + { return crypt(key, salt); + } + +/* + * UNIX encrypt function. Takes a bitvector + * represented by one byte per bit and + * encrypt/decrypt according to edflag + */ + +void encrypt(block, edflag) + char *block; + int edflag; + { ufc_long l1, l2, r1, r2, *s; + int i; + + /* + * Undo any salt changes to E expansion + */ + setup_salt(".."); + + /* + * Reverse key table if + * changing operation (encrypt/decrypt) + */ + if((edflag == 0) != (direction == 0)) { + for(i = 0; i < 8; i++) { +#ifdef _UFC_32_ + long32 x; + x = _ufc_keytab[15-i][0]; + _ufc_keytab[15-i][0] = _ufc_keytab[i][0]; + _ufc_keytab[i][0] = x; + + x = _ufc_keytab[15-i][1]; + _ufc_keytab[15-i][1] = _ufc_keytab[i][1]; + _ufc_keytab[i][1] = x; +#endif +#ifdef _UFC_64_ + long64 x; + x = _ufc_keytab[15-i]; + _ufc_keytab[15-i] = _ufc_keytab[i]; + _ufc_keytab[i] = x; +#endif + } + direction = edflag; + } + + /* + * Do initial permutation + E expansion + */ + i = 0; + for(l1 = 0; i < 24; i++) { + if(block[initial_perm[esel[i]-1]-1]) + l1 |= BITMASK(i); + } + for(l2 = 0; i < 48; i++) { + if(block[initial_perm[esel[i]-1]-1]) + l2 |= BITMASK(i-24); + } + + i = 0; + for(r1 = 0; i < 24; i++) { + if(block[initial_perm[esel[i]-1+32]-1]) + r1 |= BITMASK(i); + } + for(r2 = 0; i < 48; i++) { + if(block[initial_perm[esel[i]-1+32]-1]) + r2 |= BITMASK(i-24); + } + + /* + * Do DES inner loops + final conversion + */ + s = _ufc_doit(l1, l2, r1, r2, (ufc_long)1); + /* + * Do final permutations + */ + s = _ufc_dofinalperm(s[0], s[1], s[2], s[3]); + + /* + * And convert to bit array + */ + l1 = s[0]; r1 = s[1]; + for(i = 0; i < 32; i++) { + *block++ = (l1 & longmask[i]) != 0; + } + for(i = 0; i < 32; i++) { + *block++ = (r1 & longmask[i]) != 0; + } + + } + +/* + * UNIX setkey function. Take a 64 bit DES + * key and setup the machinery. + */ + +void setkey(key) + char *key; + { int i,j; + unsigned char c; + unsigned char ktab[8]; + + setup_salt(".."); /* be sure we're initialized */ + + for(i = 0; i < 8; i++) { + for(j = 0, c = 0; j < 8; j++) + c = c << 1 | *key++; + ktab[i] = c >> 1; + } + + ufc_mk_keytab(ktab); + } + +/* + * Ultrix crypt16 function, thanks to pcl@convex.oxford.ac.uk (Paul Leyland) + */ + +char *crypt16(key, salt) + char *key, *salt; + { ufc_long *s, *t; + char ktab[9], ttab[9]; + static char q[14], res[25]; + /* + * Hack DES tables according to salt + */ + setup_salt(salt); + + /* + * Setup key schedule + */ + clearmem(ktab, sizeof ktab); + (void)strncpy(ktab, key, 8); + ufc_mk_keytab(ktab); + + /* + * Go for first 20 DES encryptions + */ + s = _ufc_doit((ufc_long)0, (ufc_long)0, + (ufc_long)0, (ufc_long)0, (ufc_long)20); + + /* + * And convert back to 6 bit ASCII + */ + strcpy (res, output_conversion(s[0], s[1], salt)); + + clearmem(ttab, sizeof ttab); + if (strlen (key) > 8) (void)strncpy(ttab, key+8, 8); + ufc_mk_keytab(ttab); + + /* + * Go for second 5 DES encryptions + */ + t = _ufc_doit((ufc_long)0, (ufc_long)0, + (ufc_long)0, (ufc_long)0, (ufc_long)5); + /* + * And convert back to 6 bit ASCII + */ + strcpy (q, output_conversion(t[0], t[1], salt)); + strcpy (res+13, q+2); + + clearmem(ktab, sizeof ktab); + (void)strncpy(ktab, key, 8); + ufc_mk_keytab(ktab); + + return res; + } + +/* + * Experimental -- not supported -- may choke your dog + */ + +void ufc_setup_password(cookie, s) + long *cookie; + char *s; + { char c; + int i; + ufc_long x; + ufc_long dl1, dl2, dr1, dr2; + + setup_salt(s); + dl1 = dl2 = dr1 = dr2 = 0; + for(i = 0, s += 2; c = *s++; i++) { + int x = ascii_to_bin(c); + dl1 |= revfinal[i][x][0]; + dl2 |= revfinal[i][x][1]; + dr1 |= revfinal[i][x][2]; + dr2 |= revfinal[i][x][3]; + } + x = (dl1 ^ dl2) & current_saltbits; + x = (dr1 ^ dr2) & current_saltbits; + cookie[0] = dl1 ^ x; cookie[1] = dl2 ^ x; + cookie[2] = dr1 ^ x; cookie[3] = dr2 ^ x; + } + +void ufc_do_pw(cookie, guess) + long *cookie; + char *guess; + { char ktab[9]; + ufc_long *s; + clearmem(ktab, sizeof ktab); + (void)strncpy(ktab, guess, 8); + ufc_mk_keytab(ktab); + s = _ufc_doit((ufc_long)0, (ufc_long)0, + (ufc_long)0, (ufc_long)0, (ufc_long)25); + cookie[0] = s[0]; cookie[1] = s[1]; + cookie[2] = s[2]; cookie[3] = s[3]; + } diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/entities.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/entities.h new file mode 100644 index 00000000000..55ce977b665 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/entities.h @@ -0,0 +1,1084 @@ +/* Entity Names to Unicode table +** ----------------------------- +** +* +* Whole entities[] thing (and much more) now present +* in this kind of structure. The structured streams to which +* the SGML modules sends its output could then easily have access +* to both entity names and unicode values for each (special) +* character. Probably the whole translation to display characters +* should be done at that later stage (e.g. in HTML.c). +* What's missing is a way for the later stage to return info +* to SGML whether the entity could be displayed or not. +* (like between SGML_character() and handle_entity() via FoundEntity.) +* Well, trying to do that now. +* Why keep two structures for entities? Backward compatibility.. +*/ + +/* UC_entity_info structure is defined in SGML.h. + This has to be sorted alphabetically (case-sensitive), + bear this in mind when you add some more entities.. */ + +/* + +This table available from ftp://ftp.unicode.org/ +original comment follows: + + +# Author: John Cowan <cowan@ccil.org> +# Date: 25 July 1997 +# +# The following table maps SGML character entities from various +# public sets (namely, ISOamsa, ISOamsb, ISOamsc, ISOamsn, ISOamso, +# ISOamsr, ISObox, ISOcyr1, ISOcyr2, ISOdia, ISOgrk1, ISOgrk2, +# ISOgrk3, ISOgrk4, ISOlat1, ISOlat2, ISOnum, ISOpub, ISOtech, +# HTMLspecial, HTMLsymbol) to corresponding Unicode characters. +# +# The table has four tab-separated columns: +# Column 1: SGML character entity name +# Column 2: SGML public entity set +# Column 3: Unicode 2.0 character code +# Column 4: Unicode 2.0 character name (UPPER CASE) +# Entries which don't have Unicode equivalents have "0x????" +# in Column 3 and a lower case description (from the public entity +# set DTD) in Column 4. The mapping is not reversible, because many +# distinctions are unified away in Unicode, particularly between +# mathematical symbols. +# +# The table is sorted case-blind by SGML character entity name. +# +# The contents of this table are drawn from various sources, and +# are in the public domain. +# +######################## + + We just sort it and move column 2 away (line too long, sorry; + look at sgml.html in test/ directory for details). + Also we add a few (obsolete) synonyms: + "brkbar" for "brvbar" 0x00A6 + "emdash" for "mdash" 0x2014 + "endash" for "ndash" 0x2013 + "hibar" for "macr" 0x00AF + for exact compatibility with entities[] and previous bevavior. + BTW, lots of synonyms found in this table, we shouldn't worry about... +*/ + +static CONST UC_entity_info unicode_entities[] = { + {"AElig", 0x00C6}, /* LATIN CAPITAL LETTER AE */ + {"Aacgr", 0x0386}, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ + {"Aacute", 0x00C1}, /* LATIN CAPITAL LETTER A WITH ACUTE */ + {"Abreve", 0x0102}, /* LATIN CAPITAL LETTER A WITH BREVE */ + {"Acirc", 0x00C2}, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + {"Acy", 0x0410}, /* CYRILLIC CAPITAL LETTER A */ + {"Agr", 0x0391}, /* GREEK CAPITAL LETTER ALPHA */ + {"Agrave", 0x00C0}, /* LATIN CAPITAL LETTER A WITH GRAVE */ + {"Alpha", 0x0391}, /* GREEK CAPITAL LETTER ALPHA */ + {"Amacr", 0x0100}, /* LATIN CAPITAL LETTER A WITH MACRON */ + {"Aogon", 0x0104}, /* LATIN CAPITAL LETTER A WITH OGONEK */ + {"Aring", 0x00C5}, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ + {"Atilde", 0x00C3}, /* LATIN CAPITAL LETTER A WITH TILDE */ + {"Auml", 0x00C4}, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ + {"Barwed", 0x2306}, /* PERSPECTIVE */ + {"Bcy", 0x0411}, /* CYRILLIC CAPITAL LETTER BE */ + {"Beta", 0x0392}, /* GREEK CAPITAL LETTER BETA */ + {"Bgr", 0x0392}, /* GREEK CAPITAL LETTER BETA */ + {"CHcy", 0x0427}, /* CYRILLIC CAPITAL LETTER CHE */ + {"Cacute", 0x0106}, /* LATIN CAPITAL LETTER C WITH ACUTE */ + {"Cap", 0x22D2}, /* DOUBLE INTERSECTION */ + {"Ccaron", 0x010C}, /* LATIN CAPITAL LETTER C WITH CARON */ + {"Ccedil", 0x00C7}, /* LATIN CAPITAL LETTER C WITH CEDILLA */ + {"Ccirc", 0x0108}, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + {"Cdot", 0x010A}, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ + {"Chi", 0x03A7}, /* GREEK CAPITAL LETTER CHI */ + {"Cup", 0x22D3}, /* DOUBLE UNION */ + {"DJcy", 0x0402}, /* CYRILLIC CAPITAL LETTER DJE */ + {"DScy", 0x0405}, /* CYRILLIC CAPITAL LETTER DZE */ + {"DZcy", 0x040F}, /* CYRILLIC CAPITAL LETTER DZHE */ + {"Dagger", 0x2021}, /* DOUBLE DAGGER */ + {"Dcaron", 0x010E}, /* LATIN CAPITAL LETTER D WITH CARON */ + {"Dcy", 0x0414}, /* CYRILLIC CAPITAL LETTER DE */ + {"Delta", 0x0394}, /* GREEK CAPITAL LETTER DELTA */ + {"Dgr", 0x0394}, /* GREEK CAPITAL LETTER DELTA */ + {"Dot", 0x00A8}, /* DIAERESIS */ + {"DotDot", 0x20DC}, /* COMBINING FOUR DOTS ABOVE */ + {"Dstrok", 0x0110}, /* LATIN CAPITAL LETTER D WITH STROKE */ + {"EEacgr", 0x0389}, /* GREEK CAPITAL LETTER ETA WITH TONOS */ + {"EEgr", 0x0397}, /* GREEK CAPITAL LETTER ETA */ + {"ENG", 0x014A}, /* LATIN CAPITAL LETTER ENG */ + {"ETH", 0x00D0}, /* LATIN CAPITAL LETTER ETH */ + {"Eacgr", 0x0388}, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ + {"Eacute", 0x00C9}, /* LATIN CAPITAL LETTER E WITH ACUTE */ + {"Ecaron", 0x011A}, /* LATIN CAPITAL LETTER E WITH CARON */ + {"Ecirc", 0x00CA}, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + {"Ecy", 0x042D}, /* CYRILLIC CAPITAL LETTER E */ + {"Edot", 0x0116}, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ + {"Egr", 0x0395}, /* GREEK CAPITAL LETTER EPSILON */ + {"Egrave", 0x00C8}, /* LATIN CAPITAL LETTER E WITH GRAVE */ + {"Emacr", 0x0112}, /* LATIN CAPITAL LETTER E WITH MACRON */ + {"Eogon", 0x0118}, /* LATIN CAPITAL LETTER E WITH OGONEK */ + {"Epsilon", 0x0395}, /* GREEK CAPITAL LETTER EPSILON */ + {"Eta", 0x0397}, /* GREEK CAPITAL LETTER ETA */ + {"Euml", 0x00CB}, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ + {"Fcy", 0x0424}, /* CYRILLIC CAPITAL LETTER EF */ + {"GJcy", 0x0403}, /* CYRILLIC CAPITAL LETTER GJE */ + {"Gamma", 0x0393}, /* GREEK CAPITAL LETTER GAMMA */ + {"Gbreve", 0x011E}, /* LATIN CAPITAL LETTER G WITH BREVE */ + {"Gcedil", 0x0122}, /* LATIN CAPITAL LETTER G WITH CEDILLA */ + {"Gcirc", 0x011C}, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + {"Gcy", 0x0413}, /* CYRILLIC CAPITAL LETTER GHE */ + {"Gdot", 0x0120}, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ + {"Gg", 0x22D9}, /* VERY MUCH GREATER-THAN */ + {"Ggr", 0x0393}, /* GREEK CAPITAL LETTER GAMMA */ + {"Gt", 0x226B}, /* MUCH GREATER-THAN */ + {"HARDcy", 0x042A}, /* CYRILLIC CAPITAL LETTER HARD SIGN */ + {"Hcirc", 0x0124}, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + {"Hstrok", 0x0126}, /* LATIN CAPITAL LETTER H WITH STROKE */ + {"IEcy", 0x0415}, /* CYRILLIC CAPITAL LETTER IE */ + {"IJlig", 0x0132}, /* LATIN CAPITAL LIGATURE IJ */ + {"IOcy", 0x0401}, /* CYRILLIC CAPITAL LETTER IO */ + {"Iacgr", 0x038A}, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ + {"Iacute", 0x00CD}, /* LATIN CAPITAL LETTER I WITH ACUTE */ + {"Icirc", 0x00CE}, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + {"Icy", 0x0418}, /* CYRILLIC CAPITAL LETTER I */ + {"Idigr", 0x03AA}, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + {"Idot", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {"Igr", 0x0399}, /* GREEK CAPITAL LETTER IOTA */ + {"Igrave", 0x00CC}, /* LATIN CAPITAL LETTER I WITH GRAVE */ + {"Imacr", 0x012A}, /* LATIN CAPITAL LETTER I WITH MACRON */ + {"Iogon", 0x012E}, /* LATIN CAPITAL LETTER I WITH OGONEK */ + {"Iota", 0x0399}, /* GREEK CAPITAL LETTER IOTA */ + {"Itilde", 0x0128}, /* LATIN CAPITAL LETTER I WITH TILDE */ + {"Iukcy", 0x0406}, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN*/ + {"Iuml", 0x00CF}, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ + {"Jcirc", 0x0134}, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + {"Jcy", 0x0419}, /* CYRILLIC CAPITAL LETTER SHORT I */ + {"Jsercy", 0x0408}, /* CYRILLIC CAPITAL LETTER JE */ + {"Jukcy", 0x0404}, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + {"KHcy", 0x0425}, /* CYRILLIC CAPITAL LETTER HA */ + {"KHgr", 0x03A7}, /* GREEK CAPITAL LETTER CHI */ + {"KJcy", 0x040C}, /* CYRILLIC CAPITAL LETTER KJE */ + {"Kappa", 0x039A}, /* GREEK CAPITAL LETTER KAPPA */ + {"Kcedil", 0x0136}, /* LATIN CAPITAL LETTER K WITH CEDILLA */ + {"Kcy", 0x041A}, /* CYRILLIC CAPITAL LETTER KA */ + {"Kgr", 0x039A}, /* GREEK CAPITAL LETTER KAPPA */ + {"LJcy", 0x0409}, /* CYRILLIC CAPITAL LETTER LJE */ + {"Lacute", 0x0139}, /* LATIN CAPITAL LETTER L WITH ACUTE */ + {"Lambda", 0x039B}, /* GREEK CAPITAL LETTER LAMDA */ + {"Larr", 0x219E}, /* LEFTWARDS TWO HEADED ARROW */ + {"Lcaron", 0x013D}, /* LATIN CAPITAL LETTER L WITH CARON */ + {"Lcedil", 0x013B}, /* LATIN CAPITAL LETTER L WITH CEDILLA */ + {"Lcy", 0x041B}, /* CYRILLIC CAPITAL LETTER EL */ + {"Lgr", 0x039B}, /* GREEK CAPITAL LETTER LAMDA */ + {"Ll", 0x22D8}, /* VERY MUCH LESS-THAN */ + {"Lmidot", 0x013F}, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */ + {"Lstrok", 0x0141}, /* LATIN CAPITAL LETTER L WITH STROKE */ + {"Lt", 0x226A}, /* MUCH LESS-THAN */ + {"Mcy", 0x041C}, /* CYRILLIC CAPITAL LETTER EM */ + {"Mgr", 0x039C}, /* GREEK CAPITAL LETTER MU */ + {"Mu", 0x039C}, /* GREEK CAPITAL LETTER MU */ + {"NJcy", 0x040A}, /* CYRILLIC CAPITAL LETTER NJE */ + {"Nacute", 0x0143}, /* LATIN CAPITAL LETTER N WITH ACUTE */ + {"Ncaron", 0x0147}, /* LATIN CAPITAL LETTER N WITH CARON */ + {"Ncedil", 0x0145}, /* LATIN CAPITAL LETTER N WITH CEDILLA */ + {"Ncy", 0x041D}, /* CYRILLIC CAPITAL LETTER EN */ + {"Ngr", 0x039D}, /* GREEK CAPITAL LETTER NU */ + {"Ntilde", 0x00D1}, /* LATIN CAPITAL LETTER N WITH TILDE */ + {"Nu", 0x039D}, /* GREEK CAPITAL LETTER NU */ + {"OElig", 0x0152}, /* LATIN CAPITAL LIGATURE OE */ + {"OHacgr", 0x038F}, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ + {"OHgr", 0x03A9}, /* GREEK CAPITAL LETTER OMEGA */ + {"Oacgr", 0x038C}, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ + {"Oacute", 0x00D3}, /* LATIN CAPITAL LETTER O WITH ACUTE */ + {"Ocirc", 0x00D4}, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + {"Ocy", 0x041E}, /* CYRILLIC CAPITAL LETTER O */ + {"Odblac", 0x0150}, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + {"Ogr", 0x039F}, /* GREEK CAPITAL LETTER OMICRON */ + {"Ograve", 0x00D2}, /* LATIN CAPITAL LETTER O WITH GRAVE */ + {"Omacr", 0x014C}, /* LATIN CAPITAL LETTER O WITH MACRON */ + {"Omega", 0x03A9}, /* GREEK CAPITAL LETTER OMEGA */ + {"Omicron", 0x039F}, /* GREEK CAPITAL LETTER OMICRON */ + {"Oslash", 0x00D8}, /* LATIN CAPITAL LETTER O WITH STROKE */ + {"Otilde", 0x00D5}, /* LATIN CAPITAL LETTER O WITH TILDE */ + {"Ouml", 0x00D6}, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ + {"PHgr", 0x03A6}, /* GREEK CAPITAL LETTER PHI */ + {"PSgr", 0x03A8}, /* GREEK CAPITAL LETTER PSI */ + {"Pcy", 0x041F}, /* CYRILLIC CAPITAL LETTER PE */ + {"Pgr", 0x03A0}, /* GREEK CAPITAL LETTER PI */ + {"Phi", 0x03A6}, /* GREEK CAPITAL LETTER PHI */ + {"Pi", 0x03A0}, /* GREEK CAPITAL LETTER PI */ + {"Prime", 0x2033}, /* DOUBLE PRIME */ + {"Psi", 0x03A8}, /* GREEK CAPITAL LETTER PSI */ + {"Racute", 0x0154}, /* LATIN CAPITAL LETTER R WITH ACUTE */ + {"Rarr", 0x21A0}, /* RIGHTWARDS TWO HEADED ARROW */ + {"Rcaron", 0x0158}, /* LATIN CAPITAL LETTER R WITH CARON */ + {"Rcedil", 0x0156}, /* LATIN CAPITAL LETTER R WITH CEDILLA */ + {"Rcy", 0x0420}, /* CYRILLIC CAPITAL LETTER ER */ + {"Rgr", 0x03A1}, /* GREEK CAPITAL LETTER RHO */ + {"Rho", 0x03A1}, /* GREEK CAPITAL LETTER RHO */ + {"SHCHcy", 0x0429}, /* CYRILLIC CAPITAL LETTER SHCHA */ + {"SHcy", 0x0428}, /* CYRILLIC CAPITAL LETTER SHA */ + {"SOFTcy", 0x042C}, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ + {"Sacute", 0x015A}, /* LATIN CAPITAL LETTER S WITH ACUTE */ + {"Scaron", 0x0160}, /* LATIN CAPITAL LETTER S WITH CARON */ + {"Scedil", 0x015E}, /* LATIN CAPITAL LETTER S WITH CEDILLA */ + {"Scirc", 0x015C}, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + {"Scy", 0x0421}, /* CYRILLIC CAPITAL LETTER ES */ + {"Sgr", 0x03A3}, /* GREEK CAPITAL LETTER SIGMA */ + {"Sigma", 0x03A3}, /* GREEK CAPITAL LETTER SIGMA */ + {"Sub", 0x22D0}, /* DOUBLE SUBSET */ + {"Sup", 0x22D1}, /* DOUBLE SUPERSET */ + {"THORN", 0x00DE}, /* LATIN CAPITAL LETTER THORN */ + {"THgr", 0x0398}, /* GREEK CAPITAL LETTER THETA */ + {"TSHcy", 0x040B}, /* CYRILLIC CAPITAL LETTER TSHE */ + {"TScy", 0x0426}, /* CYRILLIC CAPITAL LETTER TSE */ + {"Tau", 0x03A4}, /* GREEK CAPITAL LETTER TAU */ + {"Tcaron", 0x0164}, /* LATIN CAPITAL LETTER T WITH CARON */ + {"Tcedil", 0x0162}, /* LATIN CAPITAL LETTER T WITH CEDILLA */ + {"Tcy", 0x0422}, /* CYRILLIC CAPITAL LETTER TE */ + {"Tgr", 0x03A4}, /* GREEK CAPITAL LETTER TAU */ + {"Theta", 0x0398}, /* GREEK CAPITAL LETTER THETA */ + {"Tstrok", 0x0166}, /* LATIN CAPITAL LETTER T WITH STROKE */ + {"Uacgr", 0x038E}, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ + {"Uacute", 0x00DA}, /* LATIN CAPITAL LETTER U WITH ACUTE */ + {"Ubrcy", 0x040E}, /* CYRILLIC CAPITAL LETTER SHORT U */ + {"Ubreve", 0x016C}, /* LATIN CAPITAL LETTER U WITH BREVE */ + {"Ucirc", 0x00DB}, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ + {"Ucy", 0x0423}, /* CYRILLIC CAPITAL LETTER U */ + {"Udblac", 0x0170}, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + {"Udigr", 0x03AB}, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + {"Ugr", 0x03A5}, /* GREEK CAPITAL LETTER UPSILON */ + {"Ugrave", 0x00D9}, /* LATIN CAPITAL LETTER U WITH GRAVE */ + {"Umacr", 0x016A}, /* LATIN CAPITAL LETTER U WITH MACRON */ + {"Uogon", 0x0172}, /* LATIN CAPITAL LETTER U WITH OGONEK */ + {"Upsi", 0x03A5}, /* GREEK CAPITAL LETTER UPSILON */ + {"Upsilon", 0x03A5}, /* GREEK CAPITAL LETTER UPSILON */ + {"Uring", 0x016E}, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ + {"Utilde", 0x0168}, /* LATIN CAPITAL LETTER U WITH TILDE */ + {"Uuml", 0x00DC}, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ + {"Vcy", 0x0412}, /* CYRILLIC CAPITAL LETTER VE */ + {"Vdash", 0x22A9}, /* FORCES */ + {"Verbar", 0x2016}, /* DOUBLE VERTICAL LINE */ + {"Vvdash", 0x22AA}, /* TRIPLE VERTICAL BAR RIGHT TURNSTILE */ + {"Wcirc", 0x0174}, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ + {"Xgr", 0x039E}, /* GREEK CAPITAL LETTER XI */ + {"Xi", 0x039E}, /* GREEK CAPITAL LETTER XI */ + {"YAcy", 0x042F}, /* CYRILLIC CAPITAL LETTER YA */ + {"YIcy", 0x0407}, /* CYRILLIC CAPITAL LETTER YI */ + {"YUcy", 0x042E}, /* CYRILLIC CAPITAL LETTER YU */ + {"Yacute", 0x00DD}, /* LATIN CAPITAL LETTER Y WITH ACUTE */ + {"Ycirc", 0x0176}, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ + {"Ycy", 0x042B}, /* CYRILLIC CAPITAL LETTER YERU */ + {"Yuml", 0x0178}, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ + {"ZHcy", 0x0416}, /* CYRILLIC CAPITAL LETTER ZHE */ + {"Zacute", 0x0179}, /* LATIN CAPITAL LETTER Z WITH ACUTE */ + {"Zcaron", 0x017D}, /* LATIN CAPITAL LETTER Z WITH CARON */ + {"Zcy", 0x0417}, /* CYRILLIC CAPITAL LETTER ZE */ + {"Zdot", 0x017B}, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + {"Zeta", 0x0396}, /* GREEK CAPITAL LETTER ZETA */ + {"Zgr", 0x0396}, /* GREEK CAPITAL LETTER ZETA */ + {"aacgr", 0x03AC}, /* GREEK SMALL LETTER ALPHA WITH TONOS */ + {"aacute", 0x00E1}, /* LATIN SMALL LETTER A WITH ACUTE */ + {"abreve", 0x0103}, /* LATIN SMALL LETTER A WITH BREVE */ + {"acirc", 0x00E2}, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ + {"acute", 0x00B4}, /* ACUTE ACCENT */ + {"acy", 0x0430}, /* CYRILLIC SMALL LETTER A */ + {"aelig", 0x00E6}, /* LATIN SMALL LETTER AE */ + {"agr", 0x03B1}, /* GREEK SMALL LETTER ALPHA */ + {"agrave", 0x00E0}, /* LATIN SMALL LETTER A WITH GRAVE */ + {"alefsym", 0x2135}, /* ALEF SYMBOL */ + {"aleph", 0x2135}, /* ALEF SYMBOL */ + {"alpha", 0x03B1}, /* GREEK SMALL LETTER ALPHA */ + {"amacr", 0x0101}, /* LATIN SMALL LETTER A WITH MACRON */ + {"amalg", 0x2210}, /* N-ARY COPRODUCT */ + {"amp", 0x0026}, /* AMPERSAND */ + {"and", 0x2227}, /* LOGICAL AND */ + {"ang", 0x2220}, /* ANGLE */ + {"ang90", 0x221F}, /* RIGHT ANGLE */ + {"angmsd", 0x2221}, /* MEASURED ANGLE */ + {"angsph", 0x2222}, /* SPHERICAL ANGLE */ + {"angst", 0x212B}, /* ANGSTROM SIGN */ + {"aogon", 0x0105}, /* LATIN SMALL LETTER A WITH OGONEK */ + {"ap", 0x2248}, /* ALMOST EQUAL TO */ + {"ape", 0x224A}, /* ALMOST EQUAL OR EQUAL TO */ + {"apos", 0x02BC}, /* MODIFIER LETTER APOSTROPHE */ + {"aring", 0x00E5}, /* LATIN SMALL LETTER A WITH RING ABOVE */ + {"ast", 0x002A}, /* ASTERISK */ + {"asymp", 0x2248}, /* ALMOST EQUAL TO */ + {"atilde", 0x00E3}, /* LATIN SMALL LETTER A WITH TILDE */ + {"auml", 0x00E4}, /* LATIN SMALL LETTER A WITH DIAERESIS */ + {"b.Delta", 0x0394}, /* GREEK CAPITAL LETTER DELTA */ + {"b.Gamma", 0x0393}, /* GREEK CAPITAL LETTER GAMMA */ + {"b.Lambda", 0x039B}, /* GREEK CAPITAL LETTER LAMDA */ + {"b.Omega", 0x03A9}, /* GREEK CAPITAL LETTER OMEGA */ + {"b.Phi", 0x03A6}, /* GREEK CAPITAL LETTER PHI */ + {"b.Pi", 0x03A0}, /* GREEK CAPITAL LETTER PI */ + {"b.Psi", 0x03A8}, /* GREEK CAPITAL LETTER PSI */ + {"b.Sigma", 0x03A3}, /* GREEK CAPITAL LETTER SIGMA */ + {"b.Theta", 0x0398}, /* GREEK CAPITAL LETTER THETA */ + {"b.Upsi", 0x03A5}, /* GREEK CAPITAL LETTER UPSILON */ + {"b.Xi", 0x039E}, /* GREEK CAPITAL LETTER XI */ + {"b.alpha", 0x03B1}, /* GREEK SMALL LETTER ALPHA */ + {"b.beta", 0x03B2}, /* GREEK SMALL LETTER BETA */ + {"b.chi", 0x03C7}, /* GREEK SMALL LETTER CHI */ + {"b.delta", 0x03B3}, /* GREEK SMALL LETTER GAMMA */ + {"b.epsi", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"b.epsis", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"b.epsiv", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"b.eta", 0x03B7}, /* GREEK SMALL LETTER ETA */ + {"b.gamma", 0x03B3}, /* GREEK SMALL LETTER GAMMA */ + {"b.gammad", 0x03DC}, /* GREEK LETTER DIGAMMA */ + {"b.iota", 0x03B9}, /* GREEK SMALL LETTER IOTA */ + {"b.kappa", 0x03BA}, /* GREEK SMALL LETTER KAPPA */ + {"b.kappav", 0x03F0}, /* GREEK KAPPA SYMBOL */ + {"b.lambda", 0x03BB}, /* GREEK SMALL LETTER LAMDA */ + {"b.mu", 0x03BC}, /* GREEK SMALL LETTER MU */ + {"b.nu", 0x03BD}, /* GREEK SMALL LETTER NU */ + {"b.omega", 0x03CE}, /* GREEK SMALL LETTER OMEGA WITH TONOS */ + {"b.phis", 0x03C6}, /* GREEK SMALL LETTER PHI */ + {"b.phiv", 0x03D5}, /* GREEK PHI SYMBOL */ + {"b.pi", 0x03C0}, /* GREEK SMALL LETTER PI */ + {"b.piv", 0x03D6}, /* GREEK PI SYMBOL */ + {"b.psi", 0x03C8}, /* GREEK SMALL LETTER PSI */ + {"b.rho", 0x03C1}, /* GREEK SMALL LETTER RHO */ + {"b.rhov", 0x03F1}, /* GREEK RHO SYMBOL */ + {"b.sigma", 0x03C3}, /* GREEK SMALL LETTER SIGMA */ + {"b.sigmav", 0x03C2}, /* GREEK SMALL LETTER FINAL SIGMA */ + {"b.tau", 0x03C4}, /* GREEK SMALL LETTER TAU */ + {"b.thetas", 0x03B8}, /* GREEK SMALL LETTER THETA */ + {"b.thetav", 0x03D1}, /* GREEK THETA SYMBOL */ + {"b.upsi", 0x03C5}, /* GREEK SMALL LETTER UPSILON */ + {"b.xi", 0x03BE}, /* GREEK SMALL LETTER XI */ + {"b.zeta", 0x03B6}, /* GREEK SMALL LETTER ZETA */ + {"barwed", 0x22BC}, /* NAND */ + {"bcong", 0x224C}, /* ALL EQUAL TO */ + {"bcy", 0x0431}, /* CYRILLIC SMALL LETTER BE */ + {"bdquo", 0x201E}, /* DOUBLE LOW-9 QUOTATION MARK */ + {"becaus", 0x2235}, /* BECAUSE */ + {"bepsi", 0x220D}, /* SMALL CONTAINS AS MEMBER */ + {"bernou", 0x212C}, /* SCRIPT CAPITAL B */ + {"beta", 0x03B2}, /* GREEK SMALL LETTER BETA */ + {"beth", 0x2136}, /* BET SYMBOL */ + {"bgr", 0x03B2}, /* GREEK SMALL LETTER BETA */ + {"blank", 0x2423}, /* OPEN BOX */ + {"blk12", 0x2592}, /* MEDIUM SHADE */ + {"blk14", 0x2591}, /* LIGHT SHADE */ + {"blk34", 0x2593}, /* DARK SHADE */ + {"block", 0x2588}, /* FULL BLOCK */ + {"bottom", 0x22A5}, /* UP TACK */ + {"bowtie", 0x22C8}, /* BOWTIE */ + {"boxDL", 0x2557}, /* BOX DRAWINGS DOUBLE DOWN AND LEFT */ + {"boxDR", 0x2554}, /* BOX DRAWINGS DOUBLE DOWN AND RIGHT */ + {"boxDl", 0x2556}, /* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */ + {"boxDr", 0x2553}, /* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */ + {"boxH", 0x2550}, /* BOX DRAWINGS DOUBLE HORIZONTAL */ + {"boxHD", 0x2566}, /* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */ + {"boxHU", 0x2569}, /* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */ + {"boxHd", 0x2564}, /* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE*/ + {"boxHu", 0x2567}, /* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */ + {"boxUL", 0x255D}, /* BOX DRAWINGS DOUBLE UP AND LEFT */ + {"boxUR", 0x255A}, /* BOX DRAWINGS DOUBLE UP AND RIGHT */ + {"boxUl", 0x255C}, /* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */ + {"boxUr", 0x2559}, /* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */ + {"boxV", 0x2551}, /* BOX DRAWINGS DOUBLE VERTICAL */ + {"boxVH", 0x256C}, /* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */ + {"boxVL", 0x2563}, /* BOX DRAWINGS DOUBLE VERTICAL AND LEFT */ + {"boxVR", 0x2560}, /* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */ + {"boxVh", 0x256B}, /* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SI*/ + {"boxVl", 0x2562}, /* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */ + {"boxVr", 0x255F}, /* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */ + {"boxdL", 0x2555}, /* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */ + {"boxdR", 0x2552}, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */ + {"boxdl", 0x2510}, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ + {"boxdr", 0x250C}, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + {"boxh", 0x2500}, /* BOX DRAWINGS LIGHT HORIZONTAL */ + {"boxhD", 0x2565}, /* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE*/ + {"boxhU", 0x2568}, /* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */ + {"boxhd", 0x252C}, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + {"boxhu", 0x2534}, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + {"boxuL", 0x255B}, /* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */ + {"boxuR", 0x2558}, /* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */ + {"boxul", 0x2518}, /* BOX DRAWINGS LIGHT UP AND LEFT */ + {"boxur", 0x2514}, /* BOX DRAWINGS LIGHT UP AND RIGHT */ + {"boxv", 0x2502}, /* BOX DRAWINGS LIGHT VERTICAL */ + {"boxvH", 0x256A}, /* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DO*/ + {"boxvL", 0x2561}, /* BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE */ + {"boxvR", 0x255E}, /* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */ + {"boxvh", 0x253C}, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + {"boxvl", 0x2524}, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + {"boxvr", 0x251C}, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + {"bprime", 0x2035}, /* REVERSED PRIME */ + {"breve", 0x02D8}, /* BREVE */ + {"brkbar", 0x00A6}, /* obsolete synonym for "brvbar" 0x00A6 */ + {"brvbar", 0x00A6}, /* BROKEN BAR */ + {"bsim", 0x223D}, /* REVERSED TILDE */ + {"bsime", 0x22CD}, /* REVERSED TILDE EQUALS */ + {"bsol", 0x005C}, /* REVERSE SOLIDUS */ + {"bull", 0x2022}, /* BULLET */ + {"bump", 0x224E}, /* GEOMETRICALLY EQUIVALENT TO */ + {"bumpe", 0x224F}, /* DIFFERENCE BETWEEN */ + {"cacute", 0x0107}, /* LATIN SMALL LETTER C WITH ACUTE */ + {"cap", 0x2229}, /* INTERSECTION */ + {"caret", 0x2041}, /* CARET INSERTION POINT */ + {"caron", 0x02C7}, /* CARON */ + {"ccaron", 0x010D}, /* LATIN SMALL LETTER C WITH CARON */ + {"ccedil", 0x00E7}, /* LATIN SMALL LETTER C WITH CEDILLA */ + {"ccirc", 0x0109}, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ + {"cdot", 0x010B}, /* LATIN SMALL LETTER C WITH DOT ABOVE */ + {"cedil", 0x00B8}, /* CEDILLA */ + {"cent", 0x00A2}, /* CENT SIGN */ + {"chcy", 0x0447}, /* CYRILLIC SMALL LETTER CHE */ + {"check", 0x2713}, /* CHECK MARK */ + {"chi", 0x03C7}, /* GREEK SMALL LETTER CHI */ + {"cir", 0x25CB}, /* WHITE CIRCLE */ + {"circ", 0x02C6}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ + {"cire", 0x2257}, /* RING EQUAL TO */ + {"clubs", 0x2663}, /* BLACK CLUB SUIT */ + {"colon", 0x003A}, /* COLON */ + {"colone", 0x2254}, /* COLON EQUALS */ + {"comma", 0x002C}, /* COMMA */ + {"commat", 0x0040}, /* COMMERCIAL AT */ + {"comp", 0x2201}, /* COMPLEMENT */ + {"compfn", 0x2218}, /* RING OPERATOR */ + {"cong", 0x2245}, /* APPROXIMATELY EQUAL TO */ + {"conint", 0x222E}, /* CONTOUR INTEGRAL */ + {"coprod", 0x2210}, /* N-ARY COPRODUCT */ + {"copy", 0x00A9}, /* COPYRIGHT SIGN */ + {"copysr", 0x2117}, /* SOUND RECORDING COPYRIGHT */ + {"crarr", 0x21B5}, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */ + {"cross", 0x2717}, /* BALLOT X */ + {"cuepr", 0x22DE}, /* EQUAL TO OR PRECEDES */ + {"cuesc", 0x22DF}, /* EQUAL TO OR SUCCEEDS */ + {"cularr", 0x21B6}, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW */ + {"cup", 0x222A}, /* UNION */ + {"cupre", 0x227C}, /* PRECEDES OR EQUAL TO */ + {"curarr", 0x21B7}, /* CLOCKWISE TOP SEMICIRCLE ARROW */ + {"curren", 0x00A4}, /* CURRENCY SIGN */ + {"cuvee", 0x22CE}, /* CURLY LOGICAL OR */ + {"cuwed", 0x22CF}, /* CURLY LOGICAL AND */ + {"dArr", 0x21D3}, /* DOWNWARDS DOUBLE ARROW */ + {"dagger", 0x2020}, /* DAGGER */ + {"daleth", 0x2138}, /* DALET SYMBOL */ + {"darr", 0x2193}, /* DOWNWARDS ARROW */ + {"darr2", 0x21CA}, /* DOWNWARDS PAIRED ARROWS */ + {"dash", 0x2010}, /* HYPHEN */ + {"dashv", 0x22A3}, /* LEFT TACK */ + {"dblac", 0x02DD}, /* DOUBLE ACUTE ACCENT */ + {"dcaron", 0x010F}, /* LATIN SMALL LETTER D WITH CARON */ + {"dcy", 0x0434}, /* CYRILLIC SMALL LETTER DE */ + {"deg", 0x00B0}, /* DEGREE SIGN */ + {"delta", 0x03B4}, /* GREEK SMALL LETTER DELTA */ + {"dgr", 0x03B4}, /* GREEK SMALL LETTER DELTA */ + {"dharl", 0x21C3}, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS */ + {"dharr", 0x21C2}, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS */ + {"diam", 0x22C4}, /* DIAMOND OPERATOR */ + {"diams", 0x2666}, /* BLACK DIAMOND SUIT */ + {"die", 0x00A8}, /* DIAERESIS */ + {"divide", 0x00F7}, /* DIVISION SIGN */ + {"divonx", 0x22C7}, /* DIVISION TIMES */ + {"djcy", 0x0452}, /* CYRILLIC SMALL LETTER DJE */ + {"dlarr", 0x2199}, /* SOUTH WEST ARROW */ + {"dlcorn", 0x231E}, /* BOTTOM LEFT CORNER */ + {"dlcrop", 0x230D}, /* BOTTOM LEFT CROP */ + {"dollar", 0x0024}, /* DOLLAR SIGN */ + {"dot", 0x02D9}, /* DOT ABOVE */ + {"drarr", 0x2198}, /* SOUTH EAST ARROW */ + {"drcorn", 0x231F}, /* BOTTOM RIGHT CORNER */ + {"drcrop", 0x230C}, /* BOTTOM RIGHT CROP */ + {"dscy", 0x0455}, /* CYRILLIC SMALL LETTER DZE */ + {"dstrok", 0x0111}, /* LATIN SMALL LETTER D WITH STROKE */ + {"dtri", 0x25BF}, /* WHITE DOWN-POINTING SMALL TRIANGLE */ + {"dtrif", 0x25BE}, /* BLACK DOWN-POINTING SMALL TRIANGLE */ + {"dzcy", 0x045F}, /* CYRILLIC SMALL LETTER DZHE */ + {"eDot", 0x2251}, /* GEOMETRICALLY EQUAL TO */ + {"eacgr", 0x03AD}, /* GREEK SMALL LETTER EPSILON WITH TONOS */ + {"eacute", 0x00E9}, /* LATIN SMALL LETTER E WITH ACUTE */ + {"ecaron", 0x011B}, /* LATIN SMALL LETTER E WITH CARON */ + {"ecir", 0x2256}, /* RING IN EQUAL TO */ + {"ecirc", 0x00EA}, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */ + {"ecolon", 0x2255}, /* EQUALS COLON */ + {"ecy", 0x044D}, /* CYRILLIC SMALL LETTER E */ + {"edot", 0x0117}, /* LATIN SMALL LETTER E WITH DOT ABOVE */ + {"eeacgr", 0x03AE}, /* GREEK SMALL LETTER ETA WITH TONOS */ + {"eegr", 0x03B7}, /* GREEK SMALL LETTER ETA */ + {"efDot", 0x2252}, /* APPROXIMATELY EQUAL TO OR THE IMAGE OF */ + {"egr", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"egrave", 0x00E8}, /* LATIN SMALL LETTER E WITH GRAVE */ + {"egs", 0x22DD}, /* EQUAL TO OR GREATER-THAN */ + {"ell", 0x2113}, /* SCRIPT SMALL L */ + {"els", 0x22DC}, /* EQUAL TO OR LESS-THAN */ + {"emacr", 0x0113}, /* LATIN SMALL LETTER E WITH MACRON */ + {"emdash", 0x2014}, /* obsolete synonym for "mdash" 0x2014 */ + {"empty", 0x2205}, /* EMPTY SET */ + {"emsp", 0x2003}, /* EM SPACE */ + {"emsp13", 0x2004}, /* THREE-PER-EM SPACE */ + {"emsp14", 0x2005}, /* FOUR-PER-EM SPACE */ + {"endash", 0x2013}, /* obsolete synonym for "ndash" 0x2013 */ + {"eng", 0x014B}, /* LATIN SMALL LETTER ENG */ + {"ensp", 0x2002}, /* EN SPACE */ + {"eogon", 0x0119}, /* LATIN SMALL LETTER E WITH OGONEK */ + {"epsi", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"epsilon", 0x03B5}, /* GREEK SMALL LETTER EPSILON */ + {"epsis", 0x220A}, /* SMALL ELEMENT OF */ + {"equals", 0x003D}, /* EQUALS SIGN */ + {"equiv", 0x2261}, /* IDENTICAL TO */ + {"erDot", 0x2253}, /* IMAGE OF OR APPROXIMATELY EQUAL TO */ + {"esdot", 0x2250}, /* APPROACHES THE LIMIT */ + {"eta", 0x03B7}, /* GREEK SMALL LETTER ETA */ + {"eth", 0x00F0}, /* LATIN SMALL LETTER ETH */ + {"euml", 0x00EB}, /* LATIN SMALL LETTER E WITH DIAERESIS */ + {"excl", 0x0021}, /* EXCLAMATION MARK */ + {"exist", 0x2203}, /* THERE EXISTS */ + {"fcy", 0x0444}, /* CYRILLIC SMALL LETTER EF */ + {"female", 0x2640}, /* FEMALE SIGN */ + {"ffilig", 0xFB03}, /* LATIN SMALL LIGATURE FFI */ + {"fflig", 0xFB00}, /* LATIN SMALL LIGATURE FF */ + {"ffllig", 0xFB04}, /* LATIN SMALL LIGATURE FFL */ + {"filig", 0xFB01}, /* LATIN SMALL LIGATURE FI */ + {"flat", 0x266D}, /* MUSIC FLAT SIGN */ + {"fllig", 0xFB02}, /* LATIN SMALL LIGATURE FL */ + {"fnof", 0x0192}, /* LATIN SMALL LETTER F WITH HOOK */ + {"forall", 0x2200}, /* FOR ALL */ + {"fork", 0x22D4}, /* PITCHFORK */ + {"frac12", 0x00BD}, /* VULGAR FRACTION ONE HALF */ + {"frac13", 0x2153}, /* VULGAR FRACTION ONE THIRD */ + {"frac14", 0x00BC}, /* VULGAR FRACTION ONE QUARTER */ + {"frac15", 0x2155}, /* VULGAR FRACTION ONE FIFTH */ + {"frac16", 0x2159}, /* VULGAR FRACTION ONE SIXTH */ + {"frac18", 0x215B}, /* VULGAR FRACTION ONE EIGHTH */ + {"frac23", 0x2154}, /* VULGAR FRACTION TWO THIRDS */ + {"frac25", 0x2156}, /* VULGAR FRACTION TWO FIFTHS */ + {"frac34", 0x00BE}, /* VULGAR FRACTION THREE QUARTERS */ + {"frac35", 0x2157}, /* VULGAR FRACTION THREE FIFTHS */ + {"frac38", 0x215C}, /* VULGAR FRACTION THREE EIGHTHS */ + {"frac45", 0x2158}, /* VULGAR FRACTION FOUR FIFTHS */ + {"frac56", 0x215A}, /* VULGAR FRACTION FIVE SIXTHS */ + {"frac58", 0x215D}, /* VULGAR FRACTION FIVE EIGHTHS */ + {"frac78", 0x215E}, /* VULGAR FRACTION SEVEN EIGHTHS */ + {"frasl", 0x2044}, /* FRACTION SLASH */ + {"frown", 0x2322}, /* FROWN */ + {"gE", 0x2267}, /* GREATER-THAN OVER EQUAL TO */ + {"gacute", 0x01F5}, /* LATIN SMALL LETTER G WITH ACUTE */ + {"gamma", 0x03B3}, /* GREEK SMALL LETTER GAMMA */ + {"gammad", 0x03DC}, /* GREEK LETTER DIGAMMA */ + {"gbreve", 0x011F}, /* LATIN SMALL LETTER G WITH BREVE */ + {"gcedil", 0x0123}, /* LATIN SMALL LETTER G WITH CEDILLA */ + {"gcirc", 0x011D}, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ + {"gcy", 0x0433}, /* CYRILLIC SMALL LETTER GHE */ + {"gdot", 0x0121}, /* LATIN SMALL LETTER G WITH DOT ABOVE */ + {"ge", 0x2265}, /* GREATER-THAN OR EQUAL TO */ + {"gel", 0x22DB}, /* GREATER-THAN EQUAL TO OR LESS-THAN */ + {"ges", 0x2265}, /* GREATER-THAN OR EQUAL TO */ + {"ggr", 0x03B3}, /* GREEK SMALL LETTER GAMMA */ + {"gimel", 0x2137}, /* GIMEL SYMBOL */ + {"gjcy", 0x0453}, /* CYRILLIC SMALL LETTER GJE */ + {"gl", 0x2277}, /* GREATER-THAN OR LESS-THAN */ + {"gnE", 0x2269}, /* GREATER-THAN BUT NOT EQUAL TO */ + {"gne", 0x2269}, /* GREATER-THAN BUT NOT EQUAL TO */ + {"gnsim", 0x22E7}, /* GREATER-THAN BUT NOT EQUIVALENT TO */ + {"grave", 0x0060}, /* GRAVE ACCENT */ + {"gsdot", 0x22D7}, /* GREATER-THAN WITH DOT */ + {"gsim", 0x2273}, /* GREATER-THAN OR EQUIVALENT TO */ + {"gt", 0x003E}, /* GREATER-THAN SIGN */ + {"gvnE", 0x2269}, /* GREATER-THAN BUT NOT EQUAL TO */ + {"hArr", 0x21D4}, /* LEFT RIGHT DOUBLE ARROW */ + {"hairsp", 0x200A}, /* HAIR SPACE */ + {"half", 0x00BD}, /* VULGAR FRACTION ONE HALF */ + {"hamilt", 0x210B}, /* SCRIPT CAPITAL H */ + {"hardcy", 0x044A}, /* CYRILLIC SMALL LETTER HARD SIGN */ + {"harr", 0x2194}, /* LEFT RIGHT ARROW */ + {"harrw", 0x21AD}, /* LEFT RIGHT WAVE ARROW */ + {"hcirc", 0x0125}, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ + {"hearts", 0x2665}, /* BLACK HEART SUIT */ + {"hellip", 0x2026}, /* HORIZONTAL ELLIPSIS */ + {"hibar", 0x00AF}, /* obsolete synonym for "macr" 0x00AF */ + {"horbar", 0x2015}, /* HORIZONTAL BAR */ + {"hstrok", 0x0127}, /* LATIN SMALL LETTER H WITH STROKE */ + {"hybull", 0x2043}, /* HYPHEN BULLET */ + {"hyphen", 0x002D}, /* HYPHEN-MINUS */ + {"iacgr", 0x03AF}, /* GREEK SMALL LETTER IOTA WITH TONOS */ + {"iacute", 0x00ED}, /* LATIN SMALL LETTER I WITH ACUTE */ + {"icirc", 0x00EE}, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ + {"icy", 0x0438}, /* CYRILLIC SMALL LETTER I */ + {"idiagr", 0x0390}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TON*/ + {"idigr", 0x03CA}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + {"iecy", 0x0435}, /* CYRILLIC SMALL LETTER IE */ + {"iexcl", 0x00A1}, /* INVERTED EXCLAMATION MARK */ + {"iff", 0x21D4}, /* LEFT RIGHT DOUBLE ARROW */ + {"igr", 0x03B9}, /* GREEK SMALL LETTER IOTA */ + {"igrave", 0x00EC}, /* LATIN SMALL LETTER I WITH GRAVE */ + {"ijlig", 0x0133}, /* LATIN SMALL LIGATURE IJ */ + {"imacr", 0x012B}, /* LATIN SMALL LETTER I WITH MACRON */ + {"image", 0x2111}, /* BLACK-LETTER CAPITAL I */ + {"incare", 0x2105}, /* CARE OF */ + {"infin", 0x221E}, /* INFINITY */ + {"inodot", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */ + {"int", 0x222B}, /* INTEGRAL */ + {"intcal", 0x22BA}, /* INTERCALATE */ + {"iocy", 0x0451}, /* CYRILLIC SMALL LETTER IO */ + {"iogon", 0x012F}, /* LATIN SMALL LETTER I WITH OGONEK */ + {"iota", 0x03B9}, /* GREEK SMALL LETTER IOTA */ + {"iquest", 0x00BF}, /* INVERTED QUESTION MARK */ + {"isin", 0x2208}, /* ELEMENT OF */ + {"itilde", 0x0129}, /* LATIN SMALL LETTER I WITH TILDE */ + {"iukcy", 0x0456}, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I*/ + {"iuml", 0x00EF}, /* LATIN SMALL LETTER I WITH DIAERESIS */ + {"jcirc", 0x0135}, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ + {"jcy", 0x0439}, /* CYRILLIC SMALL LETTER SHORT I */ + {"jsercy", 0x0458}, /* CYRILLIC SMALL LETTER JE */ + {"jukcy", 0x0454}, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ + {"kappa", 0x03BA}, /* GREEK SMALL LETTER KAPPA */ + {"kappav", 0x03F0}, /* GREEK KAPPA SYMBOL */ + {"kcedil", 0x0137}, /* LATIN SMALL LETTER K WITH CEDILLA */ + {"kcy", 0x043A}, /* CYRILLIC SMALL LETTER KA */ + {"kgr", 0x03BA}, /* GREEK SMALL LETTER KAPPA */ + {"kgreen", 0x0138}, /* LATIN SMALL LETTER KRA */ + {"khcy", 0x0445}, /* CYRILLIC SMALL LETTER HA */ + {"khgr", 0x03C7}, /* GREEK SMALL LETTER CHI */ + {"kjcy", 0x045C}, /* CYRILLIC SMALL LETTER KJE */ + {"lAarr", 0x21DA}, /* LEFTWARDS TRIPLE ARROW */ + {"lArr", 0x21D0}, /* LEFTWARDS DOUBLE ARROW */ + {"lE", 0x2266}, /* LESS-THAN OVER EQUAL TO */ + {"lacute", 0x013A}, /* LATIN SMALL LETTER L WITH ACUTE */ + {"lagran", 0x2112}, /* SCRIPT CAPITAL L */ + {"lambda", 0x03BB}, /* GREEK SMALL LETTER LAMDA */ + {"lang", 0x2329}, /* LEFT-POINTING ANGLE BRACKET */ + {"laquo", 0x00AB}, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ + {"larr", 0x2190}, /* LEFTWARDS ARROW */ + {"larr2", 0x21C7}, /* LEFTWARDS PAIRED ARROWS */ + {"larrhk", 0x21A9}, /* LEFTWARDS ARROW WITH HOOK */ + {"larrlp", 0x21AB}, /* LEFTWARDS ARROW WITH LOOP */ + {"larrtl", 0x21A2}, /* LEFTWARDS ARROW WITH TAIL */ + {"lcaron", 0x013E}, /* LATIN SMALL LETTER L WITH CARON */ + {"lcedil", 0x013C}, /* LATIN SMALL LETTER L WITH CEDILLA */ + {"lceil", 0x2308}, /* LEFT CEILING */ + {"lcub", 0x007B}, /* LEFT CURLY BRACKET */ + {"lcy", 0x043B}, /* CYRILLIC SMALL LETTER EL */ + {"ldot", 0x22D6}, /* LESS-THAN WITH DOT */ + {"ldquo", 0x201C}, /* LEFT DOUBLE QUOTATION MARK */ + {"ldquor", 0x201E}, /* DOUBLE LOW-9 QUOTATION MARK */ + {"le", 0x2264}, /* LESS-THAN OR EQUAL TO */ + {"leg", 0x22DA}, /* LESS-THAN EQUAL TO OR GREATER-THAN */ + {"les", 0x2264}, /* LESS-THAN OR EQUAL TO */ + {"lfloor", 0x230A}, /* LEFT FLOOR */ + {"lg", 0x2276}, /* LESS-THAN OR GREATER-THAN */ + {"lgr", 0x03BB}, /* GREEK SMALL LETTER LAMDA */ + {"lhard", 0x21BD}, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */ + {"lharu", 0x21BC}, /* LEFTWARDS HARPOON WITH BARB UPWARDS */ + {"lhblk", 0x2584}, /* LOWER HALF BLOCK */ + {"ljcy", 0x0459}, /* CYRILLIC SMALL LETTER LJE */ + {"lmidot", 0x0140}, /* LATIN SMALL LETTER L WITH MIDDLE DOT */ + {"lnE", 0x2268}, /* LESS-THAN BUT NOT EQUAL TO */ + {"lne", 0x2268}, /* LESS-THAN BUT NOT EQUAL TO */ + {"lnsim", 0x22E6}, /* LESS-THAN BUT NOT EQUIVALENT TO */ + {"lowast", 0x2217}, /* ASTERISK OPERATOR */ + {"lowbar", 0x005F}, /* LOW LINE */ + {"loz", 0x25CA}, /* LOZENGE */ + {"loz", 0x2727}, /* WHITE FOUR POINTED STAR */ + {"lozf", 0x2726}, /* BLACK FOUR POINTED STAR */ + {"lpar", 0x0028}, /* LEFT PARENTHESIS */ + {"lrarr2", 0x21C6}, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW */ + {"lrhar2", 0x21CB}, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON */ + {"lrm", 0x200E}, /* LEFT-TO-RIGHT MARK */ + {"lsaquo", 0x2039}, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */ + {"lsh", 0x21B0}, /* UPWARDS ARROW WITH TIP LEFTWARDS */ + {"lsim", 0x2272}, /* LESS-THAN OR EQUIVALENT TO */ + {"lsqb", 0x005B}, /* LEFT SQUARE BRACKET */ + {"lsquo", 0x2018}, /* LEFT SINGLE QUOTATION MARK */ + {"lsquor", 0x201A}, /* SINGLE LOW-9 QUOTATION MARK */ + {"lstrok", 0x0142}, /* LATIN SMALL LETTER L WITH STROKE */ + {"lt", 0x003C}, /* LESS-THAN SIGN */ + {"lthree", 0x22CB}, /* LEFT SEMIDIRECT PRODUCT */ + {"ltimes", 0x22C9}, /* LEFT NORMAL FACTOR SEMIDIRECT PRODUCT */ + {"ltri", 0x25C3}, /* WHITE LEFT-POINTING SMALL TRIANGLE */ + {"ltrie", 0x22B4}, /* NORMAL SUBGROUP OF OR EQUAL TO */ + {"ltrif", 0x25C2}, /* BLACK LEFT-POINTING SMALL TRIANGLE */ + {"lvnE", 0x2268}, /* LESS-THAN BUT NOT EQUAL TO */ + {"macr", 0x00AF}, /* MACRON */ + {"male", 0x2642}, /* MALE SIGN */ + {"malt", 0x2720}, /* MALTESE CROSS */ + {"map", 0x21A6}, /* RIGHTWARDS ARROW FROM BAR */ + {"marker", 0x25AE}, /* BLACK VERTICAL RECTANGLE */ + {"mcy", 0x043C}, /* CYRILLIC SMALL LETTER EM */ + {"mdash", 0x2014}, /* EM DASH */ + {"mgr", 0x03BC}, /* GREEK SMALL LETTER MU */ + {"micro", 0x00B5}, /* MICRO SIGN */ + {"mid", 0x2223}, /* DIVIDES */ + {"middot", 0x00B7}, /* MIDDLE DOT */ + {"minus", 0x2212}, /* MINUS SIGN */ + {"minusb", 0x229F}, /* SQUARED MINUS */ + {"mldr", 0x2026}, /* HORIZONTAL ELLIPSIS */ + {"mnplus", 0x2213}, /* MINUS-OR-PLUS SIGN */ + {"models", 0x22A7}, /* MODELS */ + {"mu", 0x03BC}, /* GREEK SMALL LETTER MU */ + {"mumap", 0x22B8}, /* MULTIMAP */ + {"nVDash", 0x22AF}, /* NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNS*/ + {"nVdash", 0x22AE}, /* DOES NOT FORCE */ + {"nabla", 0x2207}, /* NABLA */ + {"nacute", 0x0144}, /* LATIN SMALL LETTER N WITH ACUTE */ + {"nap", 0x2249}, /* NOT ALMOST EQUAL TO */ + {"napos", 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */ + {"natur", 0x266E}, /* MUSIC NATURAL SIGN */ + {"nbsp", 0x00A0}, /* NO-BREAK SPACE */ + {"ncaron", 0x0148}, /* LATIN SMALL LETTER N WITH CARON */ + {"ncedil", 0x0146}, /* LATIN SMALL LETTER N WITH CEDILLA */ + {"ncong", 0x2247}, /* NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO */ + {"ncy", 0x043D}, /* CYRILLIC SMALL LETTER EN */ + {"ndash", 0x2013}, /* EN DASH */ + {"ne", 0x2260}, /* NOT EQUAL TO */ + {"nearr", 0x2197}, /* NORTH EAST ARROW */ + {"nequiv", 0x2262}, /* NOT IDENTICAL TO */ + {"nexist", 0x2204}, /* THERE DOES NOT EXIST */ + {"nge", 0x2271}, /* NEITHER GREATER-THAN NOR EQUAL TO */ + {"nges", 0x2271}, /* NEITHER GREATER-THAN NOR EQUAL TO */ + {"ngr", 0x03BD}, /* GREEK SMALL LETTER NU */ + {"ngt", 0x226F}, /* NOT GREATER-THAN */ + {"nhArr", 0x21CE}, /* LEFT RIGHT DOUBLE ARROW WITH STROKE */ + {"nharr", 0x21AE}, /* LEFT RIGHT ARROW WITH STROKE */ + {"ni", 0x220B}, /* CONTAINS AS MEMBER */ + {"njcy", 0x045A}, /* CYRILLIC SMALL LETTER NJE */ + {"nlArr", 0x21CD}, /* LEFTWARDS DOUBLE ARROW WITH STROKE */ + {"nlarr", 0x219A}, /* LEFTWARDS ARROW WITH STROKE */ + {"nldr", 0x2025}, /* TWO DOT LEADER */ + {"nle", 0x2270}, /* NEITHER LESS-THAN NOR EQUAL TO */ + {"nles", 0x2270}, /* NEITHER LESS-THAN NOR EQUAL TO */ + {"nlt", 0x226E}, /* NOT LESS-THAN */ + {"nltri", 0x22EA}, /* NOT NORMAL SUBGROUP OF */ + {"nltrie", 0x22EC}, /* NOT NORMAL SUBGROUP OF OR EQUAL TO */ + {"nmid", 0x2224}, /* DOES NOT DIVIDE */ + {"not", 0x00AC}, /* NOT SIGN */ + {"notin", 0x2209}, /* NOT AN ELEMENT OF */ + {"npar", 0x2226}, /* NOT PARALLEL TO */ + {"npr", 0x2280}, /* DOES NOT PRECEDE */ + {"npre", 0x22E0}, /* DOES NOT PRECEDE OR EQUAL */ + {"nrArr", 0x21CF}, /* RIGHTWARDS DOUBLE ARROW WITH STROKE */ + {"nrarr", 0x219B}, /* RIGHTWARDS ARROW WITH STROKE */ + {"nrtri", 0x22EB}, /* DOES NOT CONTAIN AS NORMAL SUBGROUP */ + {"nrtrie", 0x22ED}, /* DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL */ + {"nsc", 0x2281}, /* DOES NOT SUCCEED */ + {"nsce", 0x22E1}, /* DOES NOT SUCCEED OR EQUAL */ + {"nsim", 0x2241}, /* NOT TILDE */ + {"nsime", 0x2244}, /* NOT ASYMPTOTICALLY EQUAL TO */ + {"nspar", 0x2226}, /* NOT PARALLEL TO */ + {"nsub", 0x2284}, /* NOT A SUBSET OF */ + {"nsubE", 0x2288}, /* NEITHER A SUBSET OF NOR EQUAL TO */ + {"nsube", 0x2288}, /* NEITHER A SUBSET OF NOR EQUAL TO */ + {"nsup", 0x2285}, /* NOT A SUPERSET OF */ + {"nsupE", 0x2289}, /* NEITHER A SUPERSET OF NOR EQUAL TO */ + {"nsupe", 0x2289}, /* NEITHER A SUPERSET OF NOR EQUAL TO */ + {"ntilde", 0x00F1}, /* LATIN SMALL LETTER N WITH TILDE */ + {"nu", 0x03BD}, /* GREEK SMALL LETTER NU */ + {"num", 0x0023}, /* NUMBER SIGN */ + {"numero", 0x2116}, /* NUMERO SIGN */ + {"numsp", 0x2007}, /* FIGURE SPACE */ + {"nvDash", 0x22AD}, /* NOT TRUE */ + {"nvdash", 0x22AC}, /* DOES NOT PROVE */ + {"nwarr", 0x2196}, /* NORTH WEST ARROW */ + {"oS", 0x24C8}, /* CIRCLED LATIN CAPITAL LETTER S */ + {"oacgr", 0x03CC}, /* GREEK SMALL LETTER OMICRON WITH TONOS */ + {"oacute", 0x00F3}, /* LATIN SMALL LETTER O WITH ACUTE */ + {"oast", 0x229B}, /* CIRCLED ASTERISK OPERATOR */ + {"ocir", 0x229A}, /* CIRCLED RING OPERATOR */ + {"ocirc", 0x00F4}, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ + {"ocy", 0x043E}, /* CYRILLIC SMALL LETTER O */ + {"odash", 0x229D}, /* CIRCLED DASH */ + {"odblac", 0x0151}, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + {"odot", 0x2299}, /* CIRCLED DOT OPERATOR */ + {"oelig", 0x0153}, /* LATIN SMALL LIGATURE OE */ + {"ogon", 0x02DB}, /* OGONEK */ + {"ogr", 0x03BF}, /* GREEK SMALL LETTER OMICRON */ + {"ograve", 0x00F2}, /* LATIN SMALL LETTER O WITH GRAVE */ + {"ohacgr", 0x03CE}, /* GREEK SMALL LETTER OMEGA WITH TONOS */ + {"ohgr", 0x03C9}, /* GREEK SMALL LETTER OMEGA */ + {"ohm", 0x2126}, /* OHM SIGN */ + {"olarr", 0x21BA}, /* ANTICLOCKWISE OPEN CIRCLE ARROW */ + {"oline", 0x203E}, /* OVERLINE */ + {"omacr", 0x014D}, /* LATIN SMALL LETTER O WITH MACRON */ + {"omega", 0x03C9}, /* GREEK SMALL LETTER OMEGA */ + {"omicron", 0x03BF}, /* GREEK SMALL LETTER OMICRON */ + {"ominus", 0x2296}, /* CIRCLED MINUS */ + {"oplus", 0x2295}, /* CIRCLED PLUS */ + {"or", 0x2228}, /* LOGICAL OR */ + {"orarr", 0x21BB}, /* CLOCKWISE OPEN CIRCLE ARROW */ + {"order", 0x2134}, /* SCRIPT SMALL O */ + {"ordf", 0x00AA}, /* FEMININE ORDINAL INDICATOR */ + {"ordm", 0x00BA}, /* MASCULINE ORDINAL INDICATOR */ + {"oslash", 0x00F8}, /* LATIN SMALL LETTER O WITH STROKE */ + {"osol", 0x2298}, /* CIRCLED DIVISION SLASH */ + {"otilde", 0x00F5}, /* LATIN SMALL LETTER O WITH TILDE */ + {"otimes", 0x2297}, /* CIRCLED TIMES */ + {"ouml", 0x00F6}, /* LATIN SMALL LETTER O WITH DIAERESIS */ + {"par", 0x2225}, /* PARALLEL TO */ + {"para", 0x00B6}, /* PILCROW SIGN */ + {"part", 0x2202}, /* PARTIAL DIFFERENTIAL */ + {"pcy", 0x043F}, /* CYRILLIC SMALL LETTER PE */ + {"percnt", 0x0025}, /* PERCENT SIGN */ + {"period", 0x002E}, /* FULL STOP */ + {"permil", 0x2030}, /* PER MILLE SIGN */ + {"perp", 0x22A5}, /* UP TACK */ + {"pgr", 0x03C0}, /* GREEK SMALL LETTER PI */ + {"phgr", 0x03C6}, /* GREEK SMALL LETTER PHI */ + {"phi", 0x03C6}, /* GREEK SMALL LETTER PHI */ + {"phis", 0x03C6}, /* GREEK SMALL LETTER PHI */ + {"phiv", 0x03D5}, /* GREEK PHI SYMBOL */ + {"phmmat", 0x2133}, /* SCRIPT CAPITAL M */ + {"phone", 0x260E}, /* BLACK TELEPHONE */ + {"pi", 0x03C0}, /* GREEK SMALL LETTER PI */ + {"piv", 0x03D6}, /* GREEK PI SYMBOL */ + {"planck", 0x210F}, /* PLANCK CONSTANT OVER TWO PI */ + {"plus", 0x002B}, /* PLUS SIGN */ + {"plusb", 0x229E}, /* SQUARED PLUS */ + {"plusdo", 0x2214}, /* DOT PLUS */ + {"plusmn", 0x00B1}, /* PLUS-MINUS SIGN */ + {"pound", 0x00A3}, /* POUND SIGN */ + {"pr", 0x227A}, /* PRECEDES */ + {"pre", 0x227C}, /* PRECEDES OR EQUAL TO */ + {"prime", 0x2032}, /* PRIME */ + {"prnsim", 0x22E8}, /* PRECEDES BUT NOT EQUIVALENT TO */ + {"prod", 0x220F}, /* N-ARY PRODUCT */ + {"prop", 0x221D}, /* PROPORTIONAL TO */ + {"prsim", 0x227E}, /* PRECEDES OR EQUIVALENT TO */ + {"psgr", 0x03C8}, /* GREEK SMALL LETTER PSI */ + {"psi", 0x03C8}, /* GREEK SMALL LETTER PSI */ + {"puncsp", 0x2008}, /* PUNCTUATION SPACE */ + {"quest", 0x003F}, /* QUESTION MARK */ + {"quot", 0x0022}, /* QUOTATION MARK */ + {"rAarr", 0x21DB}, /* RIGHTWARDS TRIPLE ARROW */ + {"rArr", 0x21D2}, /* RIGHTWARDS DOUBLE ARROW */ + {"racute", 0x0155}, /* LATIN SMALL LETTER R WITH ACUTE */ + {"radic", 0x221A}, /* SQUARE ROOT */ + {"rang", 0x232A}, /* RIGHT-POINTING ANGLE BRACKET */ + {"raquo", 0x00BB}, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ + {"rarr", 0x2192}, /* RIGHTWARDS ARROW */ + {"rarr2", 0x21C9}, /* RIGHTWARDS PAIRED ARROWS */ + {"rarrhk", 0x21AA}, /* RIGHTWARDS ARROW WITH HOOK */ + {"rarrlp", 0x21AC}, /* RIGHTWARDS ARROW WITH LOOP */ + {"rarrtl", 0x21A3}, /* RIGHTWARDS ARROW WITH TAIL */ + {"rarrw", 0x219D}, /* RIGHTWARDS WAVE ARROW */ + {"rcaron", 0x0159}, /* LATIN SMALL LETTER R WITH CARON */ + {"rcedil", 0x0157}, /* LATIN SMALL LETTER R WITH CEDILLA */ + {"rceil", 0x2309}, /* RIGHT CEILING */ + {"rcub", 0x007D}, /* RIGHT CURLY BRACKET */ + {"rcy", 0x0440}, /* CYRILLIC SMALL LETTER ER */ + {"rdquo", 0x201D}, /* RIGHT DOUBLE QUOTATION MARK */ + {"rdquor", 0x201C}, /* LEFT DOUBLE QUOTATION MARK */ + {"real", 0x211C}, /* BLACK-LETTER CAPITAL R */ + {"rect", 0x25AD}, /* WHITE RECTANGLE */ + {"reg", 0x00AE}, /* REGISTERED SIGN */ + {"rfloor", 0x230B}, /* RIGHT FLOOR */ + {"rgr", 0x03C1}, /* GREEK SMALL LETTER RHO */ + {"rhard", 0x21C1}, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */ + {"rharu", 0x21C0}, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */ + {"rho", 0x03C1}, /* GREEK SMALL LETTER RHO */ + {"rhov", 0x03F1}, /* GREEK RHO SYMBOL */ + {"ring", 0x02DA}, /* RING ABOVE */ + {"rlarr2", 0x21C4}, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW */ + {"rlhar2", 0x21CC}, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON */ + {"rlm", 0x200F}, /* RIGHT-TO-LEFT MARK */ + {"rpar", 0x0029}, /* RIGHT PARENTHESIS */ + {"rsaquo", 0x203A}, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */ + {"rsh", 0x21B1}, /* UPWARDS ARROW WITH TIP RIGHTWARDS */ + {"rsqb", 0x005D}, /* RIGHT SQUARE BRACKET */ + {"rsquo", 0x2019}, /* RIGHT SINGLE QUOTATION MARK */ + {"rsquor", 0x2018}, /* LEFT SINGLE QUOTATION MARK */ + {"rthree", 0x22CC}, /* RIGHT SEMIDIRECT PRODUCT */ + {"rtimes", 0x22CA}, /* RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT */ + {"rtri", 0x25B9}, /* WHITE RIGHT-POINTING SMALL TRIANGLE */ + {"rtrie", 0x22B5}, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */ + {"rtrif", 0x25B8}, /* BLACK RIGHT-POINTING SMALL TRIANGLE */ + {"rx", 0x211E}, /* PRESCRIPTION TAKE */ + {"sacute", 0x015B}, /* LATIN SMALL LETTER S WITH ACUTE */ + {"samalg", 0x2210}, /* N-ARY COPRODUCT */ + {"sbquo", 0x201A}, /* SINGLE LOW-9 QUOTATION MARK */ + {"sbsol", 0x005C}, /* REVERSE SOLIDUS */ + {"sc", 0x227B}, /* SUCCEEDS */ + {"scaron", 0x0161}, /* LATIN SMALL LETTER S WITH CARON */ + {"sccue", 0x227D}, /* SUCCEEDS OR EQUAL TO */ + {"sce", 0x227D}, /* SUCCEEDS OR EQUAL TO */ + {"scedil", 0x015F}, /* LATIN SMALL LETTER S WITH CEDILLA */ + {"scirc", 0x015D}, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ + {"scnsim", 0x22E9}, /* SUCCEEDS BUT NOT EQUIVALENT TO */ + {"scsim", 0x227F}, /* SUCCEEDS OR EQUIVALENT TO */ + {"scy", 0x0441}, /* CYRILLIC SMALL LETTER ES */ + {"sdot", 0x22C5}, /* DOT OPERATOR */ + {"sdotb", 0x22A1}, /* SQUARED DOT OPERATOR */ + {"sect", 0x00A7}, /* SECTION SIGN */ + {"semi", 0x003B}, /* SEMICOLON */ + {"setmn", 0x2216}, /* SET MINUS */ + {"sext", 0x2736}, /* SIX POINTED BLACK STAR */ + {"sfgr", 0x03C2}, /* GREEK SMALL LETTER FINAL SIGMA */ + {"sfrown", 0x2322}, /* FROWN */ + {"sgr", 0x03C3}, /* GREEK SMALL LETTER SIGMA */ + {"sharp", 0x266F}, /* MUSIC SHARP SIGN */ + {"shchcy", 0x0449}, /* CYRILLIC SMALL LETTER SHCHA */ + {"shcy", 0x0448}, /* CYRILLIC SMALL LETTER SHA */ + {"shy", 0x00AD}, /* SOFT HYPHEN */ + {"sigma", 0x03C3}, /* GREEK SMALL LETTER SIGMA */ + {"sigmaf", 0x03C2}, /* GREEK SMALL LETTER FINAL SIGMA */ + {"sigmav", 0x03C2}, /* GREEK SMALL LETTER FINAL SIGMA */ + {"sim", 0x223C}, /* TILDE OPERATOR */ + {"sime", 0x2243}, /* ASYMPTOTICALLY EQUAL TO */ + {"smile", 0x2323}, /* SMILE */ + {"softcy", 0x044C}, /* CYRILLIC SMALL LETTER SOFT SIGN */ + {"sol", 0x002F}, /* SOLIDUS */ + {"spades", 0x2660}, /* BLACK SPADE SUIT */ + {"spar", 0x2225}, /* PARALLEL TO */ + {"sqcap", 0x2293}, /* SQUARE CAP */ + {"sqcup", 0x2294}, /* SQUARE CUP */ + {"sqsub", 0x228F}, /* SQUARE IMAGE OF */ + {"sqsube", 0x2291}, /* SQUARE IMAGE OF OR EQUAL TO */ + {"sqsup", 0x2290}, /* SQUARE ORIGINAL OF */ + {"sqsupe", 0x2292}, /* SQUARE ORIGINAL OF OR EQUAL TO */ + {"squ", 0x25A1}, /* WHITE SQUARE */ + {"square", 0x25A1}, /* WHITE SQUARE */ + {"squf", 0x25AA}, /* BLACK SMALL SQUARE */ + {"ssetmn", 0x2216}, /* SET MINUS */ + {"ssmile", 0x2323}, /* SMILE */ + {"sstarf", 0x22C6}, /* STAR OPERATOR */ + {"star", 0x2606}, /* WHITE STAR */ + {"starf", 0x2605}, /* BLACK STAR */ + {"sub", 0x2282}, /* SUBSET OF */ + {"subE", 0x2286}, /* SUBSET OF OR EQUAL TO */ + {"sube", 0x2286}, /* SUBSET OF OR EQUAL TO */ + {"subnE", 0x228A}, /* SUBSET OF WITH NOT EQUAL TO */ + {"subne", 0x228A}, /* SUBSET OF WITH NOT EQUAL TO */ + {"sum", 0x2211}, /* N-ARY SUMMATION */ + {"sung", 0x266A}, /* EIGHTH NOTE */ + {"sup", 0x2283}, /* SUPERSET OF */ + {"sup1", 0x00B9}, /* SUPERSCRIPT ONE */ + {"sup2", 0x00B2}, /* SUPERSCRIPT TWO */ + {"sup3", 0x00B3}, /* SUPERSCRIPT THREE */ + {"supE", 0x2287}, /* SUPERSET OF OR EQUAL TO */ + {"supe", 0x2287}, /* SUPERSET OF OR EQUAL TO */ + {"supnE", 0x228B}, /* SUPERSET OF WITH NOT EQUAL TO */ + {"supne", 0x228B}, /* SUPERSET OF WITH NOT EQUAL TO */ + {"szlig", 0x00DF}, /* LATIN SMALL LETTER SHARP S */ + {"target", 0x2316}, /* POSITION INDICATOR */ + {"tau", 0x03C4}, /* GREEK SMALL LETTER TAU */ + {"tcaron", 0x0165}, /* LATIN SMALL LETTER T WITH CARON */ + {"tcedil", 0x0163}, /* LATIN SMALL LETTER T WITH CEDILLA */ + {"tcy", 0x0442}, /* CYRILLIC SMALL LETTER TE */ + {"tdot", 0x20DB}, /* COMBINING THREE DOTS ABOVE */ + {"telrec", 0x2315}, /* TELEPHONE RECORDER */ + {"tgr", 0x03C4}, /* GREEK SMALL LETTER TAU */ + {"there4", 0x2234}, /* THEREFORE */ + {"theta", 0x03B8}, /* GREEK SMALL LETTER THETA */ + {"thetas", 0x03B8}, /* GREEK SMALL LETTER THETA */ + {"thetasym", 0x03D1}, /* GREEK THETA SYMBOL */ + {"thetav", 0x03D1}, /* GREEK THETA SYMBOL */ + {"thgr", 0x03B8}, /* GREEK SMALL LETTER THETA */ + {"thinsp", 0x2009}, /* THIN SPACE */ + {"thkap", 0x2248}, /* ALMOST EQUAL TO */ + {"thksim", 0x223C}, /* TILDE OPERATOR */ + {"thorn", 0x00FE}, /* LATIN SMALL LETTER THORN */ + {"tilde", 0x02DC}, /* SMALL TILDE */ + {"times", 0x00D7}, /* MULTIPLICATION SIGN */ + {"timesb", 0x22A0}, /* SQUARED TIMES */ + {"top", 0x22A4}, /* DOWN TACK */ + {"tprime", 0x2034}, /* TRIPLE PRIME */ + {"trade", 0x2122}, /* TRADE MARK SIGN */ + {"trie", 0x225C}, /* DELTA EQUAL TO */ + {"tscy", 0x0446}, /* CYRILLIC SMALL LETTER TSE */ + {"tshcy", 0x045B}, /* CYRILLIC SMALL LETTER TSHE */ + {"tstrok", 0x0167}, /* LATIN SMALL LETTER T WITH STROKE */ + {"twixt", 0x226C}, /* BETWEEN */ + {"uArr", 0x21D1}, /* UPWARDS DOUBLE ARROW */ + {"uacgr", 0x03CD}, /* GREEK SMALL LETTER UPSILON WITH TONOS */ + {"uacute", 0x00FA}, /* LATIN SMALL LETTER U WITH ACUTE */ + {"uarr", 0x2191}, /* UPWARDS ARROW */ + {"uarr2", 0x21C8}, /* UPWARDS PAIRED ARROWS */ + {"ubrcy", 0x045E}, /* CYRILLIC SMALL LETTER SHORT U */ + {"ubreve", 0x016D}, /* LATIN SMALL LETTER U WITH BREVE */ + {"ucirc", 0x00FB}, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */ + {"ucy", 0x0443}, /* CYRILLIC SMALL LETTER U */ + {"udblac", 0x0171}, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + {"udiagr", 0x03B0}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND */ + {"udigr", 0x03CB}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + {"ugr", 0x03C5}, /* GREEK SMALL LETTER UPSILON */ + {"ugrave", 0x00F9}, /* LATIN SMALL LETTER U WITH GRAVE */ + {"uharl", 0x21BF}, /* UPWARDS HARPOON WITH BARB LEFTWARDS */ + {"uharr", 0x21BE}, /* UPWARDS HARPOON WITH BARB RIGHTWARDS */ + {"uhblk", 0x2580}, /* UPPER HALF BLOCK */ + {"ulcorn", 0x231C}, /* TOP LEFT CORNER */ + {"ulcrop", 0x230F}, /* TOP LEFT CROP */ + {"umacr", 0x016B}, /* LATIN SMALL LETTER U WITH MACRON */ + {"uml", 0x00A8}, /* DIAERESIS */ + {"uogon", 0x0173}, /* LATIN SMALL LETTER U WITH OGONEK */ + {"uplus", 0x228E}, /* MULTISET UNION */ + {"upsi", 0x03C5}, /* GREEK SMALL LETTER UPSILON */ + {"upsih", 0x03D2}, /* GREEK UPSILON WITH HOOK SYMBOL */ + {"upsilon", 0x03C5}, /* GREEK SMALL LETTER UPSILON */ + {"urcorn", 0x231D}, /* TOP RIGHT CORNER */ + {"urcrop", 0x230E}, /* TOP RIGHT CROP */ + {"uring", 0x016F}, /* LATIN SMALL LETTER U WITH RING ABOVE */ + {"utilde", 0x0169}, /* LATIN SMALL LETTER U WITH TILDE */ + {"utri", 0x25B5}, /* WHITE UP-POINTING SMALL TRIANGLE */ + {"utrif", 0x25B4}, /* BLACK UP-POINTING SMALL TRIANGLE */ + {"uuml", 0x00FC}, /* LATIN SMALL LETTER U WITH DIAERESIS */ + {"vArr", 0x21D5}, /* UP DOWN DOUBLE ARROW */ + {"vDash", 0x22A8}, /* TRUE */ + {"varr", 0x2195}, /* UP DOWN ARROW */ + {"vcy", 0x0432}, /* CYRILLIC SMALL LETTER VE */ + {"vdash", 0x22A2}, /* RIGHT TACK */ + {"veebar", 0x22BB}, /* XOR */ + {"vellip", 0x22EE}, /* VERTICAL ELLIPSIS */ + {"verbar", 0x007C}, /* VERTICAL LINE */ + {"vltri", 0x22B2}, /* NORMAL SUBGROUP OF */ + {"vprime", 0x2032}, /* PRIME */ + {"vprop", 0x221D}, /* PROPORTIONAL TO */ + {"vrtri", 0x22B3}, /* CONTAINS AS NORMAL SUBGROUP */ + {"vsubnE", 0x228A}, /* SUBSET OF WITH NOT EQUAL TO */ + {"vsubne", 0x228A}, /* SUBSET OF WITH NOT EQUAL TO */ + {"vsupnE", 0x228B}, /* SUPERSET OF WITH NOT EQUAL TO */ + {"vsupne", 0x228B}, /* SUPERSET OF WITH NOT EQUAL TO */ + {"wcirc", 0x0175}, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ + {"wedgeq", 0x2259}, /* ESTIMATES */ + {"weierp", 0x2118}, /* SCRIPT CAPITAL P */ + {"wreath", 0x2240}, /* WREATH PRODUCT */ + {"xcirc", 0x25CB}, /* WHITE CIRCLE */ + {"xdtri", 0x25BD}, /* WHITE DOWN-POINTING TRIANGLE */ + {"xgr", 0x03BE}, /* GREEK SMALL LETTER XI */ + {"xhArr", 0x2194}, /* LEFT RIGHT ARROW */ + {"xharr", 0x2194}, /* LEFT RIGHT ARROW */ + {"xi", 0x03BE}, /* GREEK SMALL LETTER XI */ + {"xlArr", 0x21D0}, /* LEFTWARDS DOUBLE ARROW */ + {"xrArr", 0x21D2}, /* RIGHTWARDS DOUBLE ARROW */ + {"xutri", 0x25B3}, /* WHITE UP-POINTING TRIANGLE */ + {"yacute", 0x00FD}, /* LATIN SMALL LETTER Y WITH ACUTE */ + {"yacy", 0x044F}, /* CYRILLIC SMALL LETTER YA */ + {"ycirc", 0x0177}, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ + {"ycy", 0x044B}, /* CYRILLIC SMALL LETTER YERU */ + {"yen", 0x00A5}, /* YEN SIGN */ + {"yicy", 0x0457}, /* CYRILLIC SMALL LETTER YI */ + {"yucy", 0x044E}, /* CYRILLIC SMALL LETTER YU */ + {"yuml", 0x00FF}, /* LATIN SMALL LETTER Y WITH DIAERESIS */ + {"zacute", 0x017A}, /* LATIN SMALL LETTER Z WITH ACUTE */ + {"zcaron", 0x017E}, /* LATIN SMALL LETTER Z WITH CARON */ + {"zcy", 0x0437}, /* CYRILLIC SMALL LETTER ZE */ + {"zdot", 0x017C}, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ + {"zeta", 0x03B6}, /* GREEK SMALL LETTER ZETA */ + {"zgr", 0x03B6}, /* GREEK SMALL LETTER ZETA */ + {"zhcy", 0x0436}, /* CYRILLIC SMALL LETTER ZHE */ + {"zwj", 0x200D}, /* ZERO WIDTH JOINER */ + {"zwnj", 0x200C}, /* ZERO WIDTH NON-JOINER */ +/* {"epsiv", 0x????}, variant epsilon # ISOgrk3 */ +/* {"fjlig", 0x????}, fj ligature # ISOpub */ +/* {"gEl", 0x????}, greater-than, double equals, less-than # ISOamsr */ +/* {"gap", 0x????}, greater-than, approximately equal to # ISOamsr */ +/* {"gnap", 0x????}, greater-than, not approximately equal t# ISOamsn */ +/* {"jnodot", 0x????}, latin small letter dotless j # ISOamso */ +/* {"lEg", 0x????}, less-than, double equals, greater-than # ISOamsr */ +/* {"lap", 0x????}, less-than, approximately equal to # ISOamsr */ +/* {"lnap", 0x????}, less-than, not approximately equal to # ISOamsn */ +/* {"lpargt", 0x????}, left parenthesis, greater-than # ISOamsc */ +/* {"ngE", 0x????}, not greater-than, double equals # ISOamsn */ +/* {"nlE", 0x????}, not less-than, double equals # ISOamsn */ +/* {"nsmid", 0x????}, nshortmid # ISOamsn */ +/* {"prap", 0x????}, precedes, approximately equal to # ISOamsr */ +/* {"prnE", 0x????}, precedes, not double equal # ISOamsn */ +/* {"prnap", 0x????}, precedes, not approximately equal to # ISOamsn */ +/* {"rpargt", 0x????}, right parenthesis, greater-than # ISOamsc */ +/* {"scap", 0x????}, succeeds, approximately equal to # ISOamsr */ +/* {"scnE", 0x????}, succeeds, not double equals # ISOamsn */ +/* {"scnap", 0x????}, succeeds, not approximately equal to # ISOamsn */ +/* {"smid", 0x????}, shortmid # ISOamsr */ +}; diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/getline.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/getline.c new file mode 100644 index 00000000000..7f6ff038ceb --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/getline.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* CHANGED FOR VMS */ + +/* + * <getline.c> + */ + +#include "HTUtils.h" +#include "tcp.h" +#include <stddef.h> + +#include "LYLeaks.h" + +/* Read up to (and including) a newline from STREAM into *LINEPTR + (and null-terminate it). *LINEPTR is a pointer returned from malloc (or + NULL), pointing to *N characters of space. It is realloc'd as + necessary. Returns the number of characters read (not including the + null terminator), or -1 on error or EOF. */ + +int getline(char **lineptr, size_t *n, FILE *stream) +{ +static char line[256]; +char *ptr; +unsigned int len; + + if (lineptr == NULL || n == NULL) + { + SOCKET_ERRNO = EINVAL; + return -1; + } + + if (ferror (stream)) + return -1; + + if (feof(stream)) + return -1; + + fgets(line,256,stream); + + ptr = strchr(line,'\n'); + if (ptr) + *ptr = '\0'; + + len = strlen(line); + + if ((len+1) < 256) + { + ptr = realloc(*lineptr, 256); + if (ptr == NULL) + return(-1); + *lineptr = ptr; + *n = 256; + } + + strcpy(*lineptr,line); + return(len); +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/getpass.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/getpass.c new file mode 100644 index 00000000000..a7f0de7b247 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/getpass.c @@ -0,0 +1,64 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* CHANGED FOR VMS */ + +/* + * <getpass.c> + */ + +#include "HTUtils.h" +/*#include <stdio.h> included by HTUtils.h -- FM */ +#include <descrip.h> +#include <psldef.h> +#include <iodef.h> +#include <starlet.h> + +#include "LYLeaks.h" + +PUBLIC char * getpass ARGS1(CONST char *, prompt) +{ + static char *buf; + + int result; + $DESCRIPTOR(devnam,"SYS$INPUT"); + int chan; + int promptlen; + struct { + short result; + short count; + int info; + } iosb; + + promptlen = strlen(prompt); + + buf = (char *)malloc(256); + if (buf == NULL) + return(NULL); + + result = sys$assign(&devnam, &chan, PSL$C_USER, 0, 0); + + result = sys$qiow(0, chan, IO$_READPROMPT | IO$M_PURGE |IO$M_NOECHO, &iosb, 0, 0, + buf, 255, 0, 0, prompt, promptlen); + + buf[iosb.count] = '\0'; + + result = sys$dassgn(chan); + + return buf; +} diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/patchlevel.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/patchlevel.h new file mode 100644 index 00000000000..c37c8654d32 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/patchlevel.h @@ -0,0 +1,24 @@ +/* + * UFC-crypt: ultra fast crypt(3) implementation + * + * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * @(#)patchlevel.h 1.11 7/15/92 + * + */ + +#define PATCHLEVEL "UFC-crypt, patchlevel 1e, @(#)patchlevel.h 1.11 7/15/92" diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/tcp.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/tcp.h new file mode 100644 index 00000000000..7dde5f34b16 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/tcp.h @@ -0,0 +1,681 @@ +/* System dependencies in the W3 library + SYSTEM DEPENDENCIES + + System-system differences for TCP include files and macros. This + file includes for each system the files necessary for network and + file I/O. It should be used in conjunction with HTUtils.h to help + ensure portability across as many platforms and flavors of platforms + as possible. + + AUTHORS + + TBL Tim Berners-Lee, W3 project, CERN, <timbl@info.cern.ch> + EvA Eelco van Asperen <evas@cs.few.eur.nl> + MA Marc Andreessen NCSA + AT Aleksandar Totic <atotic@ncsa.uiuc.edu> + SCW Susan C. Weber <sweber@kyle.eitech.com> + + HISTORY: + 22 Feb 91 Written (TBL) as part of the WWW library. + 16 Jan 92 PC code from EvA + 22 Apr 93 Merged diffs bits from xmosaic release + 29 Apr 93 Windows/NT code from SCW + 20 May 94 A.Harper Add support for VMS CMU TCP/IP transport + 3 Oct 94 A.Harper Add support for VMS SOCKETSHR/NETLIB + 15 Jul 95 S. Bjorndahl Gnu C for VMS Globaldef/ref support + +*/ + +#ifndef TCP_H +#define TCP_H + +#ifndef HTUTILS_H +#include "HTUtils.h" +#endif /* !HTUTILS_H */ + +/* + +Default values + + These values may be reset and altered by system-specific sections + later on. there are also a bunch of defaults at the end . + + */ +/* Default values of those: */ +#define NETCLOSE close /* Routine to close a TCP-IP socket */ +#define NETREAD HTDoRead /* Routine to read from a TCP-IP socket */ +#define NETWRITE write /* Routine to write to a TCP-IP socket */ +#define SOCKET_READ read /* normal socket read routine */ +#define IOCTL ioctl /* normal ioctl routine for sockets */ +#define SOCKET_ERRNO errno /* normal socket errno */ + +/* Unless stated otherwise, */ +#define SELECT /* Can handle >1 channel. */ +#define GOT_SYSTEM /* Can call shell with string */ + +#ifdef unix +#define GOT_PIPE +#endif /* unix */ + +typedef struct sockaddr_in SockA; /* See netinet/in.h */ + + +#ifndef STDIO_H +#include <stdio.h> +#define STDIO_H +#endif /* !STDIO_H */ + +#ifndef VMS +#include <sys/types.h> + +#if HAVE_DIRENT_H +# include <dirent.h> +# define D_NAMLEN(dirent) strlen((dirent)->d_name) +# define STRUCT_DIRENT struct dirent +#else +# define D_NAMLEN(dirent) (dirent)->d_namlen +# define STRUCT_DIRENT struct direct +# define direct dirent /* FIXME */ +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif /* HAVE_DIRENT_H */ +#endif /* !VMS */ + +#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 + +#ifdef _AIX +#define AIX +#endif /* _AIX */ +#ifdef AIX +#define unix +#endif /* AIX */ + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FCNTL_H +#include <sys/fcntl.h> +#endif +#endif + +#if HAVE_STRING_H +#include <string.h> /* For bzero etc */ +#endif /* HAVE_STRING_H */ + +/* + + M ACROS FOR CONVERTING CHARACTERS + + */ +#ifndef TOASCII +#define TOASCII(c) (c) +#define FROMASCII(c) (c) +#endif /* !TOASCII */ + + +/* +IBM-PC running Windows NT + + These parameters providede by Susan C. Weber <sweber@kyle.eitech.com>. +*/ + +#ifdef _WINDOWS +#include "fcntl.h" /* For HTFile.c */ +#include "sys\types.h" /* For HTFile.c */ +#include "sys\stat.h" /* For HTFile.c */ +#undef NETREAD +#undef NETWRITE +#undef NETCLOSE +#undef IOCTL +#define NETREAD(s,b,l) recv((s),(b),(l),0) +#define NETWRITE(s,b,l) send((s),(b),(l),0) +#define NETCLOSE(s) closesocket(s) +#define IOCTL ioctlsocket +#include <io.h> +#include <string.h> +#include <process.h> +#include <time.h> +#include <errno.h> +#include <direct.h> +#include <stdio.h> +#include <winsock.h> +typedef struct sockaddr_in SockA; /* See netinet/in.h */ +#define EINPROGRESS (WSABASEERR+36) +#define EALREADY (WSABASEERR+37) +#define EISCONN (WSABASEERR+56) +#define EINTR (WSABASEERR+4) +#define EAGAIN (WSABASEERR+1002) +#define ENOTCONN (WSABASEERR+57) +#define ECONNRESET (WSABASEERR+54) +#define EINVAL 22 +#define INCLUDES_DONE +#define TCP_INCLUDES_DONE +#endif /* WINDOWS */ + + + +/* + +VAX/VMS + + Under VMS, there are many versions of TCP-IP. Define one if you do + not use Digital's UCX product: + + UCX DEC's "Ultrix connection" (default) + CMU_TCP Available via FTP from sacusr.mp.usbr.gov + SOCKETSHR Eckhart Meyer's interface to NETLIB + WIN_TCP From Wollongong, now GEC software. + MULTINET From SRI, became TGV, then Cisco. + DECNET Cern's TCP socket emulation over DECnet + + The last three do not interfere with the + unix i/o library, and so they need special calls to read, write and + close sockets. In these cases the socket number is a VMS channel + number, so we make the @@@ HORRIBLE @@@ assumption that a channel + number will be greater than 10 but a unix file descriptor less than + 10. It works. + + */ +#ifdef VMS + +#ifdef UCX +#undef IOCTL +#define IOCTL HTioctl +#endif /* UCX */ + +#ifdef WIN_TCP +#undef SOCKET_READ +#undef NETWRITE +#undef NETCLOSE +#define SOCKET_READ(s,b,l) ((s)>10 ? netread((s),(b),(l)) : read((s),(b),(l))) +#define NETWRITE(s,b,l) ((s)>10 ? netwrite((s),(b),(l)) : write((s),(b),(l))) +#define NETCLOSE(s) ((s)>10 ? netclose(s) : close(s)) +#undef IOCTL +#define IOCTL(a,b,c) -1 /* disables ioctl function */ +#define NO_IOCTL /* flag to check if ioctl is disabled */ +#endif /* WIN_TCP */ + +#ifdef CMU_TCP +#undef SOCKET_READ +#undef NETREAD +#undef NETWRITE +#undef NETCLOSE +#define SOCKET_READ(s,b,l) (cmu_get_sdc((s)) != 0 ? cmu_read((s),(b),(l)) : read((s),(b),(l))) +#define NETREAD(s,b,l) (cmu_get_sdc((s)) != 0 ? HTDoRead((s),(b),(l)) : read((s),(b),(l))) +#define NETWRITE(s,b,l) (cmu_get_sdc((s)) != 0 ? cmu_write((s),(b),(l)) : write((s),(b),(l))) +#define NETCLOSE(s) (cmu_get_sdc((s)) != 0 ? cmu_close((s)) : close((s))) +#endif /* CMU_TCP */ + +#ifdef MULTINET +#undef NETCLOSE +#undef SOCKET_READ +#undef NETWRITE +#undef IOCTL +#undef SOCKET_ERRNO +/* +** Delete these socket_foo() prototypes as MultiNet adds them +** to it's socket library headers. Compiler warnings due to +** the absence of arguments in the generic prototypes here will +** include the names of those which can be deleted. - FM +*/ +extern int socket_read(); +extern int socket_write(); +extern int socket_close(); +extern int socket_ioctl(); + +#define SOCKET_READ(s,b,l) ((s)>10 ? socket_read((s),(b),(l)) : \ + read((s),(b),(l))) +#define NETWRITE(s,b,l) ((s)>10 ? socket_write((s),(b),(l)) : \ + write((s),(b),(l))) +#define NETCLOSE(s) ((s)>10 ? socket_close(s) : close(s)) +#define IOCTL socket_ioctl +#define SOCKET_ERRNO socket_errno +#endif /* MULTINET */ + +#ifdef SOCKETSHR_TCP +#undef SOCKET_READ +#undef NETREAD +#undef NETWRITE +#undef NETCLOSE +#undef IOCTL +#define SOCKET_READ(s,b,l) (si_get_sdc((s)) != 0 ? si_read((s),(b),(l)) : \ + read((s),(b),(l))) +#define NETREAD(s,b,l) (si_get_sdc((s)) != 0 ? HTDoRead((s),(b),(l)) : \ + read((s),(b),(l))) +#define NETWRITE(s,b,l) (si_get_sdc((s)) != 0 ? si_write((s),(b),(l)) : \ + write((s),(b),(l))) +#define NETCLOSE(s) (si_get_sdc((s)) != 0 ? si_close((s)) : close((s))) +#define IOCTL si_ioctl +#endif /* SOCKETSHR_TCP */ + +#include <string.h> + +#ifndef STDIO_H +#include <stdio.h> +#define STDIO_H +#endif /* !STDIO_H */ + +#include <file.h> +#include <stat.h> +#include <unixio.h> +#include <unixlib.h> + +#define INCLUDES_DONE + +#ifdef MULTINET /* Include from standard Multinet directories */ +/* +** Delete any of these multinet_foo() and associated prototypes +** as MultiNet adds them to its socket library headers. You'll +** get compiler warnings about them, due the absence of arguments +** in the generic prototyping here, and the warnings will include +** the names of the functions whose prototype entries can be +** deleted here. - FM +*/ +extern int multinet_accept(); +extern int multinet_bind(); +extern int bzero(); +extern int multinet_connect(); +extern int multinet_gethostname(); +extern int multinet_getsockname(); +extern unsigned short multinet_htons(unsigned short __val); +extern unsigned short multinet_ntohs(unsigned short __val); +extern int multinet_listen(); +extern int multinet_select(); +extern int multinet_socket(); +extern char *vms_errno_string(); + +#ifndef __SOCKET_TYPEDEFS +#define __SOCKET_TYPEDEFS 1 +#endif /* !__SOCKET_TYPEDEFS */ +#include <time.h> +#include <types.h> +#ifdef __TIME_T +#define __TYPES 1 +#define __TYPES_LOADED 1 +#endif /* __TIME_T */ +#ifdef __SOCKET_TYPEDEFS +#undef __SOCKET_TYPEDEFS +#endif /* __SOCKET_TYPEDEFS */ +#include "multinet_root:[multinet.include.sys]types.h" +#ifndef __SOCKET_TYPEDEFS +#define __SOCKET_TYPEDEFS 1 +#endif /* !__SOCKET_TYPEDEFS */ +#include "multinet_root:[multinet.include]errno.h" +#ifdef __TYPES +#define __TIME_T 1 +#endif /* __TYPE */ +#ifdef __TIME_LOADED +#define __TIME 1 /* to avoid double definitions in in.h */ +#endif /* __TIME_LOADED */ +#include "multinet_root:[multinet.include.sys]time.h" +#include "multinet_root:[multinet.include.sys]socket.h" +#include "multinet_root:[multinet.include.netinet]in.h" +#include "multinet_root:[multinet.include.arpa]inet.h" +#include "multinet_root:[multinet.include]netdb.h" +#include "multinet_root:[multinet.include.sys]ioctl.h" +#define TCP_INCLUDES_DONE +/* +** Uncomment this if you get compiler messages +** about struct timeval having no linkage. - FM +*/ +/*#define NO_TIMEVAL*/ +#ifdef NO_TIMEVAL +struct timeval { + long tv_sec; /* seconds since Jan. 1, 1970 */ + long tv_usec; /* microseconds */ +}; +#endif /* NO_TIMEVAL */ +#endif /* MULTINET */ + + +#ifdef DECNET +#include <types.h> +#include <errno.h> +#include <time.h> +#include "types.h" /* for socket.h */ +#include "socket.h" +#include "dn" +#include "dnetdb" +/* #include "vms.h" */ +#define TCP_INCLUDES_DONE +#endif /* DECNET */ + + +#ifdef UCX +#include <types.h> +#include <errno.h> +#include <time.h> +#include <socket.h> +#include <in.h> +#include <inet.h> +#if defined(TCPWARE) && !defined(__DECC) +#include "tcpware_include:netdb.h" +#include "tcpware_include:ucx$inetdef.h" +#else +#include <netdb.h> +#include <ucx$inetdef.h> +#endif /* TCPWARE */ +#define TCP_INCLUDES_DONE +#endif /* UCX */ + + +#ifdef CMU_TCP +#include <types.h> +#include <errno.h> +#include "cmuip_root:[syslib]time.h" +#include "cmuip_root:[syslib]socket.h" +#include <in.h> +#include <inet.h> +#include <netdb.h> +#include "cmuip_root:[syslib]ioctl.h" +#define TCP_INCLUDES_DONE +#endif /* CMU_TCP */ + + +#ifdef SOCKETSHR_TCP +#include <types.h> +#include <errno.h> +#include <time.h> +#include <socket.h> +#include <in.h> +#include <inet.h> +#include <netdb.h> +#include "socketshr_library:socketshr.h" +#include "socketshr_library:ioctl.h" +#define TCP_INCLUDES_DONE +#endif /* SOCKETSHR_TCP */ + +#ifdef WIN_TCP +#include <types.h> +#include <errno.h> +#include <time.h> +#include <socket.h> +#include <in.h> +#include <inet.h> +#include <netdb.h> +#ifndef NO_IOCTL +#include <ioctl.h> +#endif /* !NO_IOCTL */ +#define TCP_INCLUDES_DONE +#endif /* WIN_TCP */ + +#ifndef TCP_INCLUDES_DONE +#include <types.h> +#include <errno.h> +#include <time.h> +#ifdef VMS_SOCKET_HEADERS +/* +** Not all versions of VMS have the full set of headers +** for socket library functions, because the TCP/IP +** packages were layered products. If we want these +** specifically, instead of those for the above packages, +** the module should be compiled with VMS_SOCKET_HEADERS +** defined instead of layered product definitions, above. +** If the module is not using socket library functions, +** none of the definitions need be used, and we include +** only the above three headers. - FM +*/ +#include <socket.h> +#include <in.h> +#include <inet.h> +#include <netdb.h> +#include <ioctl.h> +#endif /* VMS_SOCKET_HEADERS */ +#define TCP_INCLUDES_DONE +#endif /* !TCP_INCLUDES_DONE */ + +/* + + On VMS machines, the linker needs to be told to put global data sections into + a data + segment using these storage classes. (MarkDonszelmann) + + */ +#if defined(VAXC) && !defined(__DECC) +#define GLOBALDEF globaldef +#define GLOBALREF globalref +#else +#ifdef __GNUC__ /* this added by Sterling Bjorndahl */ +#define GLOBALREF_IS_MACRO 1 +#define GLOBALDEF_IS_MACRO 1 +#include <gnu_hacks.h> /* defines GLOBALREF and GLOBALDEF for GNUC on VMS */ +#endif /* __GNUC__ */ +#endif /* VAXC && !DECC */ + +#endif /* VMS */ + +/* + * On non-VMS machines and for DECC on VMS, the GLOBALDEF and GLOBALREF + * storage types default to normal C storage types. + */ +#ifndef GLOBALREF +#define GLOBALDEF +#define GLOBALREF extern +#endif /* !GLOBALREF */ + +#ifdef DJGPP +#undef SELECT +#define TCP_INCLUDES_DONE +#define NO_IOCTL +#include <errno.h> +#include <sys/types.h> +#include <socket.h> + +#undef NETWRITE +#define NETWRITE write_s +#undef NETREAD +#define NETREAD read_s +#undef NETCLOSE +#define NETCLOSE close_s +#endif + +/* +SCO ODT unix version + */ +#if HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif /* HAVE_SYS_FILIO_H */ + +/* +MIPS unix + */ +/* Mips hack (bsd4.3/sysV mixture...) */ +#ifdef mips +extern int errno; +#endif /* mips */ + +/* +Regular BSD unix versions +========================= + These are a default unix where not already defined specifically. + */ +#ifndef INCLUDES_DONE +#include <sys/types.h> +/* #include <streams/streams.h> not ultrix */ +#if HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#include <errno.h> /* independent */ +#ifdef SCO +#include <sys/timeb.h> +#include <time.h> +#endif /* SCO */ +#if defined(AIX) || defined(SVR4) +#include <time.h> +#endif /* AIX || SVR4 */ +#include <sys/time.h> /* independent */ +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/file.h> /* For open() etc */ +#if defined(NeXT) || defined(sony_news) +#ifndef mode_t +typedef unsigned short mode_t; +#endif /* !mode_t */ +#ifndef pid_t +typedef int pid_t; +#endif /* !pid_t */ +#ifndef S_ISREG +#define S_ISREG(m) (((m) & 0170000) == 0100000) +#endif /* S_ISREG */ +#ifndef WEXITSTATUS +#ifdef sony_news +#define WEXITSTATUS(s) WIFEXITED(s) +#else +#define WEXITSTATUS(s) (((s).w_status >> 8) & 0377) +#endif /* sony_news */ +#endif /* !WEXITSTATUS */ +#ifndef WTERMSIG +#ifdef sony_news +#define WTERMSIG(s) (s).w_termsig +#else +#define WTERMSIG(s) (((s).w_status >> 8) & 0177) +#endif /* sony_news */ +#endif /* !WTERMSIG */ +#endif /* NeXT || sony_news */ +#define INCLUDES_DONE +#endif /* Normal includes */ + +/* FIXME: this should be autoconf'd */ +/* Interactive UNIX for i386 and i486 -- Thanks to jeffrey@itm.itm.org */ +#ifdef ISC +#include <net/errno.h> +#include <sys/types.h> +#include <sys/tty.h> +#include <sys/sioctl.h> +#include <sys/bsdtypes.h> +#ifndef MERGE +#define MERGE +#include <sys/pty.h> +#undef MERGE +#else +#include <sys/pty.h> +#endif /* !MERGE */ +#ifndef USE_DIRENT +#define USE_DIRENT /* sys V style directory open */ +#endif /* USE_DIRENT */ +#include <sys/dirent.h> +#endif /* ISC */ + +/* Directory reading stuff - BSD or SYS V +*/ +#if defined(UNIX) && !defined(unix) +#define unix +#endif /* UNIX && !unix */ + +#ifdef HAVE_CONFIG_H + +# ifdef HAVE_LIMITS_H +# include <limits.h> +# endif /* HAVE_LIMITS_H */ +# if !defined(MAXINT) && defined(INT_MAX) +# define MAXINT INT_MAX +# endif /* !MAXINT && INT_MAX */ + +#else + +/* FIXME: remove after completing configure-script */ +#ifdef unix /* if this is to compile on a UNIX machine */ +#define HAVE_READDIR 1 /* if directory reading functions are available */ +#ifdef USE_DIRENT /* sys v version */ +#include <dirent.h> +#define direct dirent +#else +#include <sys/dir.h> +#endif /* USE_DIRENT */ +#if defined(sun) && defined(__svr4__) +#include <sys/fcntl.h> +#include <limits.h> +#else +#if defined(__hpux) || defined(LINUX) || defined (__FreeBSD__) +#include <limits.h> +#endif /* __hpux || LINUX || __FreeBSD__ */ +#endif /* sun && __svr4__ */ +#if !defined(MAXINT) && defined(INT_MAX) +#define MAXINT INT_MAX +#endif /* !MAXINT && INT_MAX */ +#endif /* unix */ + +#ifndef VM +#ifndef VMS +#ifndef THINK_C +#define DECL_SYS_ERRLIST 1 +#endif /* !THINK_C */ +#endif /* !VMS */ +#endif /* !VM */ + +#endif /* !HAVE_CONFIG_H */ + +/* +Defaults +======== + INCLUDE FILES FOR TCP + */ +#ifndef TCP_INCLUDES_DONE +#ifndef NO_IOCTL +#include <sys/ioctl.h> /* EJB */ +#endif /* !NO_IOCTL */ +#include <sys/socket.h> +#include <netinet/in.h> +#ifndef __hpux /* this may or may not be good -marc */ +#include <arpa/inet.h> /* Must be after netinet/in.h */ +#endif /* !__hpux */ +#include <netdb.h> +#endif /* TCP includes */ + +/* + +ROUGH ESTIMATE OF MAX PATH LENGTH + +*/ +#ifndef HT_MAX_PATH +#ifdef MAXPATHLEN +#define HT_MAX_PATH MAXPATHLEN +#else +#ifdef PATH_MAX +#define HT_MAX_PATH PATH_MAX +#else +#define HT_MAX_PATH 1024 /* Any better ideas? */ +#endif +#endif +#endif /* HT_MAX_PATH */ + +#if HT_MAX_PATH < 256 +#undef HT_MAX_PATH +#define HT_MAX_PATH 256 +#endif + +/* + MACROS FOR MANIPULATING MASKS FOR SELECT() + */ +#ifdef SELECT +#ifndef FD_SET +typedef unsigned int fd_set; +#define FD_SET(fd,pmask) (*(pmask)) |= (1<<(fd)) +#define FD_CLR(fd,pmask) (*(pmask)) &= ~(1<<(fd)) +#define FD_ZERO(pmask) (*(pmask))=0 +#define FD_ISSET(fd,pmask) (*(pmask) & (1<<(fd))) +#endif /* !FD_SET */ +#endif /* SELECT */ + + +#endif /* TCP_H */ diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/ufc-crypt.h b/gnu/usr.bin/lynx/WWW/Library/Implementation/ufc-crypt.h new file mode 100644 index 00000000000..13da8b4737d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/ufc-crypt.h @@ -0,0 +1,108 @@ +/* + * UFC-crypt: ultra fast crypt(3) implementation + * + * Copyright (C) 1991, 1992, Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * @(#)ufc-crypt.h 1.16 09/21/92 + * + * Definitions of datatypes + * + */ + +/* + * Requirements for datatypes: + * + * A datatype 'ufc_long' of at least 32 bit + * *and* + * A type 'long32' of exactly 32 bits (_UFC_32_) + * *or* + * A type 'long64' of exactly 64 bits (_UFC_64_) + * + * 'int' is assumed to be at least 8 bit + */ + +/* + * #ifdef's for various architectures + */ + +#ifdef cray +/* thanks to <hutton@opus.sdsc.edu> (Tom Hutton) for testing */ +typedef unsigned long ufc_long; +typedef unsigned long long64; +#define _UFC_64_ +#endif + +#ifdef convex +/* thanks to pcl@convex.oxford.ac.uk (Paul Leyland) for testing */ +typedef unsigned long ufc_long; +typedef long long long64; +#define _UFC_64_ +#endif + +#ifdef ksr +/* + * Note - the KSR machine does not define a unique symbol + * which we can check. So you MUST add '-Dksr' to your Makefile. + * Thanks to lijewski@theory.tc.cornell.edu (Mike Lijewski) for + * the patch. + */ +typedef unsigned long ufc_long; +typedef unsigned long long64; +#define _UFC_64_ +#endif + +/* + * For debugging 64 bit code etc with 'gcc' + */ + +#ifdef GCC3232 +typedef unsigned long ufc_long; +typedef unsigned long long32; +#define _UFC_32_ +#endif + +#ifdef GCC3264 +typedef unsigned long ufc_long; +typedef long long long64; +#define _UFC_64_ +#endif + +#ifdef GCC6432 +typedef long long ufc_long; +typedef unsigned long long32; +#define _UFC_32_ +#endif + +#ifdef GCC6464 +typedef long long ufc_long; +typedef long long long64; +#define _UFC_64_ +#endif + +/* + * Catch all for 99.95% of all UNIX machines + */ + +#ifndef _UFC_64_ +#ifndef _UFC_32_ +#define _UFC_32_ +typedef unsigned long ufc_long; +typedef unsigned long long32; +#endif +#endif + + diff --git a/gnu/usr.bin/lynx/WWW/Library/apollo_m68k/Makefile b/gnu/usr.bin/lynx/WWW/Library/apollo_m68k/Makefile new file mode 100644 index 00000000000..20aa9ac8cd4 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/apollo_m68k/Makefile @@ -0,0 +1,38 @@ +# Make WWW for apollo NOTE WWW macro changed for unwritable source tree ** +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = apollo_m68k + +# For ASIS installation, the ASIS code for the machine/os +ASIS_MACH = apollo-68k/sr-10.3 + + +CFLAGS = -O -DDEBUG +LFLAGS = +CC = cc +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + + + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. +#WWW = /user/timbl/hypertext/WWW + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +# LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) +LIBDIR = /tmp/WWWLibrary_Build + +include $(WWW)/Library/Implementation/CommonMakefile + + + + diff --git a/gnu/usr.bin/lynx/WWW/Library/clix/Makefile b/gnu/usr.bin/lynx/WWW/Library/clix/Makefile new file mode 100644 index 00000000000..e1996d27019 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/clix/Makefile @@ -0,0 +1,30 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = clix + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + + +CFLAGS = -O -DDEBUG -DUSG -DUNIX -DCLIX +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/convex/Makefile b/gnu/usr.bin/lynx/WWW/Library/convex/Makefile new file mode 100644 index 00000000000..fcd28786696 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/convex/Makefile @@ -0,0 +1,32 @@ +# Make WWW under ConvexOS + +# For W3 distribution, machine type for subdirectories +WWW_MACH = convex + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + + +CFLAGS = -O -DDEBUG -Dunix +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + +# HTWAIS = $(LOB)/HTWAIS.o +# WAIS = YES +# WAISINC = -I/tmp/freeWAIS-0.202/ir +# WAISCFLAGS = -DDIRECT_WAIS + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/decstation/Makefile b/gnu/usr.bin/lynx/WWW/Library/decstation/Makefile new file mode 100644 index 00000000000..b35d278cd38 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/decstation/Makefile @@ -0,0 +1,23 @@ +# Platform-specific Makefile for W3 Library (decstation) +# ----------------------------------------- +# + +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +#CFLAGS = +CFLAGS = -O +CC = cc +#LFLAGS = -lresolv +LFLAGS = + +ASIS_MACH = dec-station/ultrix-4.2 +WWW_MACH = decstation + +# Directory for installed binary: +LIBDIR = /usr/local/lib + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/djgpp/CommonMakefile b/gnu/usr.bin/lynx/WWW/Library/djgpp/CommonMakefile new file mode 100644 index 00000000000..1fdaf314799 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/djgpp/CommonMakefile @@ -0,0 +1,371 @@ +# Common Makefile for W3 Library Code +# ----------------------------------- +# +# (c) CERN 1990, 1991 -- see Copyright.html for conditions +# +# This file should be invariant between systems. +# DEPENDENCIES NOT COMPLETE @@ +# +# make Compile and link the software (private version) +# make install Copy it into the system (implies make) +# make update Copy installed version into installed version +# make uninstall Unlink installed version from the system +# make clean Remove intermediate files +# make cleanall Remove intremediate files and products +# +# Macros required to be defined already for make: +# +# CC The C compiler +# CFLAGS Flags for $(CC) -- except the -I which are below +# LFLAGS Flags for ld +# LYFLAGS Flags for Lynx +# +# WWW The WWW source tree directory +# +# Macros needed for make install: +# +# LIBDIR Directory for installed library +#______________________________________________________________________ + +# If this env var is set to something else Some makes will use that instead +SHELL = /bin/sh + +# .h files are distributed but originally are made from the +# self-documenting hypertext files. + +.SUFFIXES: .h .html .htm +.html.h: +# - chmod +w $*.h +# www -w90 -na -to text/x-c $*.html > $*.h +# chmod -w $*.h + +# If this is actually run in a subdirectory, +# +WWW = ../.. +# WWW = ../.. For [cernlib] build in this directory + +WC = $(WWW)/Library +CMN = $(WWW)/Library/Implementation/ +VMS = $(CMN)vms +# Where shall we put the objects and built library? + +LOB = $(WTMP)/Library/$(WWW_MACH) + +# Only needed if HTWAIS.c is to be compiled. Put into your Makefile.include +# uncomment these and fill in WAISINC for adding direct wais access +# to Lynx. +#HTWAIS = $(LOB)/HTWAIS.o +#WAIS = YES +#WAISINC = -I../../../../freeWAIS-0.202/ir +#WAISCFLAGS = -DDIRECT_WAIS +# + +# This path, if relative, is taken relative to the directory +# in which this makefile is, not the pwd. This screws up the +# recursive invocation +# include $(CMN)Version.make +include $(ABS)$(WWW)/Library/Implementation/Version.make + +# XMOsAIC hack is only for server to cope with xmosaic kludge for mmedia +# +# add -DNEW_GATEWAY here for the new gateway config stuff +CFLAGS2 = $(CFLAGS) $(LYFLAGS) $(WAISCFLAGS) -I$(CMN) -DXMOSAIC_HACK -DACCESS_AUTH + +CERNLIBBIN = $(WWW)/bin + +COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ + $(LOB)/HTFile.o $(LOB)/HTBTree.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ + $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ + $(LOB)/HTPlain.o $(LOB)/HTWriter.o \ + $(LOB)/HTMLGen.o \ + $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ + $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTDOS.o \ + $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTMIME.o \ + $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ + $(LOB)/HTTelnet.o $(LOB)/HTFinger.o $(LOB)/HTWSRC.o $(HTWAIS) \ + $(LOB)/HTAAUtil.o $(LOB)/HTAAServ.o $(LOB)/HTAABrow.o \ + $(LOB)/HTAAFile.o $(LOB)/HTPasswd.o $(LOB)/HTGroup.o \ + $(LOB)/HTACL.o $(LOB)/HTAuth.o $(LOB)/HTAAProt.o \ + $(LOB)/HTAssoc.o $(LOB)/HTLex.o $(LOB)/HTUU.o + +CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ + $(CMN)HTBTree.c \ + $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ + $(CMN)HTMLDTD.c \ + $(CMN)HTPlain.c $(CMN)HTWriter.c \ + $(CMN)HTDOS.c $(CMN)HTMLGen.c \ + $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ + $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTRules.c \ + $(CMN)HTFormat.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ + $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ + $(CMN)HTFinger.c $(CMN)HTWAIS.c $(CMN)HTWSRC.c \ + $(CMN)HTAAUtil.c $(CMN)HTAAServ.c $(CMN)HTAABrow.c \ + $(CMN)HTAAFile.c $(CMN)HTPasswd.c $(CMN)HTGroup.c \ + $(CMN)HTACL.c $(CMN)HTAuth.c $(CMN)HTAAProt.c \ + $(CMN)HTAssoc.c $(CMN)HTLex.c $(CMN)HTUU.c + +HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ + $(CMN)HTBTree.h $(CMN)HTFTP.h $(CMN)HTTCP.h \ + $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ + $(CMN)HTPlain.h $(CMN)HTWriter.h \ + $(CMN)HTFWriter.h $(CMN)HTMLGen.h $(CMN)HTDOS.h \ + $(CMN)HTStream.h \ + $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ + $(CMN)HTList.h \ + $(CMN)HTString.h $(CMN)HTAlert.h $(CMN)HTRules.h \ + $(CMN)HTFormat.h $(CMN)HTInit.h \ + $(CMN)HTMIME.h $(CMN)HTHistory.h $(CMN)HTNews.h \ + $(CMN)HTGopher.h \ + $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)HText.h \ + $(CMN)HTTelnet.h $(CMN)HTFinger.h \ + $(CMN)HTWAIS.h $(CMN)HTWSRC.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAServ.h $(CMN)HTAABrow.h \ + $(CMN)HTAAFile.h $(CMN)HTPasswd.h $(CMN)HTGroup.h \ + $(CMN)HTACL.h $(CMN)HTAuth.h $(CMN)HTAAProt.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h $(CMN)HTUU.h + +SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make \ + $(CMN)CommonMakefile $(CMN)Makefile \ + $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD $(WWW)/Makefile +SPECIFIC = $(WWW)/All/*/Makefile.include $(WWW)/All/Implementation/Makefile* \ + $(VMS)/descrip.mms $(VMS)/build_multinet.com \ + $(VMS)/COPYING.LIB $(VMS)/setup.com $(VMS)/multinet.opt \ + $(VMS)/patchlevel.h $(VMS)/ufc-crypt.h \ + $(VMS)/crypt.c $(VMS)/crypt_util.c \ + $(VMS)/getline.c $(VMS)/getpass.c \ + $(VMS)/HTVMSUtils.h $(VMS)/HTVMSUtils.c + + +# Library +# +# On SGI, ranlib is unnecessary and does not exist so we ignore errors +# for that step +$(LOB)/libwww.a : $(COMMON) + ar r $(LOB)/libwww.a $(COMMON) + -ranlib $(LOB)/libwww.a + +# Clean up everything generatable except final products +clean : + rm $(LOB)/*.o + -rmdir $(LOB) + +# Clean up everything generatable including final products + +cleanall : clean + rm $(LOB)/libwww.a + +# Install W3 library into system space (not normally necessary) + +install : libwww.a + if [ ! -r $(LIBDIR) ] mkdir $(LIBDIR) + cp libwww.a $(LIBDIR)/libwww.a + +uninstall : + rm $(LIBDIR)/libwww.a + +# Distribution use only: +# ---------------------- + +# Needs www version 2.4 or later to do this +inc : $(HFILES) + echo Include files generated from hypertext. + +binary : /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + echo FTP archive binary Libray $(VC) for $(WWW_MACH) up to date. + + +/pub/www/bin/$(WWW_MACH)/libwww_$(VC).a : libwww.a + -mkdir /pub/www/bin/$(WWW_MACH) + cp libwww.a /pub/www/bin/$(WWW_MACH)/libwww_$(VC).a + +# Source Distribution: + +distribute : /pub/www/README.txt /pub/www/Copyright.txt + (cd $(WWW)/..; WWW=WWW ABS=`pwd`/ make $(MFLAGS) \ + -f WWW/Library/Implementation/CommonMakefile \ + /pub/www/src/WWWLibrary_$(VC).tar.Z) + (cd ../Implementation; cvs tag \ + `sed -e 's/VC = /v/' Version.make | sed -e 's?\.?/?'` ) + echo Distribution of Library version $(VC) up to date. + +/pub/www/src/WWWLibrary_$(VC).tar.Z : $(SOURCES) + tar cf /pub/www/src/WWWLibrary_$(VC).tar \ + $(SOURCES) $(SPECIFIC) $(WC)/*/Makefile + compress /pub/www/src/WWWLibrary_$(VC).tar + + +# Hypertext supplied in text format +# --------------------------------- + +$(WWW)/README.txt : $(WWW)/../README.html + www -n -p66 http://www.w3.org/hypertext/README.html \ + > $(WWW)/README.txt +/pub/www/README.txt : $(WWW)/README.txt + cp $(WWW)/README.txt /pub/www/README.txt + +$(WWW)/Copyright.txt : $(WWW)/../Copyright.html + www -n -p66 http://www.w3.org/hypertext/Copyright.html \ + > $(WWW)/Copyright.txt +/pub/www/Copyright.txt : $(WWW)/Copyright.txt + cp $(WWW)/Copyright.txt /pub/www/Copyright.txt + +# Common code +# ----------- + +# Directory for object files + +$(LOB)/HTList.o : $(OE) $(CMN)HTList.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTList.c + +$(LOB)/HTAnchor.o : $(OE) $(CMN)HTAnchor.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAnchor.c + +$(LOB)/HTFormat.o : $(OE) $(CMN)HTFormat.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFormat.c + +$(LOB)/HTMIME.o : $(OE) $(CMN)HTMIME.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMIME.c + +$(LOB)/HTHistory.o : $(OE) $(CMN)HTHistory.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTHistory.c + +$(LOB)/HTDOS.o : $(OE) $(CMN)HTDOS.c $(CMN)HTUtils.h $(CMN)../../../userdefs.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTDOS.c + +$(LOB)/HTNews.o : $(OE) $(CMN)HTNews.c $(CMN)HTUtils.h $(CMN)HTList.h\ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTNews.c + +$(LOB)/HTGopher.o : $(OE) $(CMN)HTGopher.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGopher.c + +$(LOB)/HTTelnet.o : $(OE) $(CMN)HTTelnet.c $(CMN)HTUtils.h $(CMN)HTTelnet.h $(CMN)../../../userdefs.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTelnet.c + +$(LOB)/HTFinger.o : $(OE) $(CMN)HTFinger.c $(CMN)HTUtils.h $(CMN)HTList.h \ + $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFinger.c + +$(LOB)/HTStyle.o : $(OE) $(CMN)HTStyle.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTStyle.c + +$(LOB)/HTAtom.o : $(OE) $(CMN)HTAtom.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAtom.c + +$(LOB)/HTChunk.o : $(OE) $(CMN)HTChunk.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTChunk.c + +$(LOB)/HTString.o : $(OE) $(CMN)HTString.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTString.c + +$(LOB)/HTRules.o : $(OE) $(CMN)HTRules.c $(CMN)HTUtils.h $(CMN)Version.make \ + $(CMN)HTAAServ.h $(CMN)HTAAProt.h + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTRules.c + +$(LOB)/SGML.o : $(OE) $(CMN)SGML.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)SGML.c + +$(LOB)/HTMLGen.o : $(OE) $(CMN)HTMLGen.c $(CMN)HTUtils.h $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLGen.c + +$(LOB)/HTMLDTD.o : $(OE) $(CMN)HTMLDTD.c $(CMN)SGML.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLDTD.c + +$(LOB)/HTPlain.o : $(OE) $(CMN)HTPlain.c $(CMN)HTPlain.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPlain.c + +$(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + +$(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c + +$(LOB)/HTWriter.o : $(OE) $(CMN)HTWriter.c $(CMN)HTWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWriter.c + + +# Access Authorization + +$(LOB)/HTAAUtil.o : $(OE) $(CMN)HTAAUtil.c $(CMN)HTAAUtil.h \ + $(CMN)HTUtils.h $(CMN)HTString.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAUtil.c + +$(LOB)/HTAAFile.o : $(OE) $(CMN)HTAAFile.c $(CMN)HTAAFile.h \ + $(CMN)HTAAUtil.h $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAFile.c + +$(LOB)/HTPasswd.o : $(OE) $(CMN)HTPasswd.c $(CMN)HTPasswd.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPasswd.c + +$(LOB)/HTGroup.o : $(OE) $(CMN)HTGroup.c $(CMN)HTGroup.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGroup.c + +$(LOB)/HTACL.o : $(OE) $(CMN)HTACL.c $(CMN)HTACL.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTGroup.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTACL.c + +$(LOB)/HTAuth.o : $(OE) $(CMN)HTAuth.c $(CMN)HTAuth.h \ + $(CMN)HTAAUtil.h $(CMN)HTPasswd.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAuth.c + +$(LOB)/HTAAServ.o : $(OE) $(CMN)HTAAServ.c $(CMN)HTAAServ.h \ + $(CMN)HTAAUtil.h $(CMN)HTAAFile.h $(CMN)HTPasswd.h \ + $(CMN)HTGroup.h $(CMN)HTACL.h $(CMN)HTAuth.h \ + $(CMN)HTUU.h $(CMN)HTParse.h $(CMN)HTList.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTRules.h \ + $(CMN)HTAAProt.h $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAServ.c + +$(LOB)/HTAABrow.o : $(OE) $(CMN)HTAABrow.c $(CMN)HTAABrow.h \ + $(CMN)HTAAUtil.h $(CMN)HTUU.h \ + $(CMN)HTUtils.h $(CMN)HTString.h \ + $(CMN)HTParse.h $(CMN)HTList.h $(CMN)HTAlert.h \ + $(CMN)HTAssoc.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAABrow.c + +$(LOB)/HTAAProt.o : $(OE) $(CMN)HTAAProt.c $(CMN)HTAAProt.h \ + $(CMN)HTUtils.h $(CMN)HTAAUtil.h $(CMN)HTAAFile.h \ + $(CMN)HTAssoc.h $(CMN)HTLex.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAAProt.c + +$(LOB)/HTAssoc.o : $(OE) $(CMN)HTAssoc.c $(CMN)HTAssoc.h \ + $(CMN)HTUtils.h $(CMN)HTString.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAssoc.c + +$(LOB)/HTLex.o : $(OE) $(CMN)HTLex.c $(CMN)HTLex.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTLex.c + +$(LOB)/HTUU.o : $(OE) $(CMN)HTUU.c $(CMN)HTUU.h $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTUU.c + + +# Communications & Files + +$(LOB)/HTTP.o : $(OE) $(CMN)HTTP.c $(CMN)HTUtils.h $(CMN)HTAABrow.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTP.c + +$(LOB)/HTTCP.o : $(OE) $(CMN)HTTCP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTCP.c + +$(LOB)/HTFile.o : $(OE) $(CMN)HTFile.c $(CMN)HTUtils.h \ + $(CMN)HTMLDTD.h $(CMN)HTAAServ.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFile.c + +$(LOB)/HTBTree.o : $(OE) $(CMN)HTBTree.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTBTree.c + +$(LOB)/HTFTP.o : $(OE) $(CMN)HTFTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFTP.c + +$(LOB)/HTAccess.o : $(OE) $(CMN)HTAccess.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAccess.c + +$(LOB)/HTParse.o : $(OE) $(CMN)HTParse.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTParse.c + diff --git a/gnu/usr.bin/lynx/WWW/Library/djgpp/makefile b/gnu/usr.bin/lynx/WWW/Library/djgpp/makefile new file mode 100644 index 00000000000..d7272e45eca --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/djgpp/makefile @@ -0,0 +1,30 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = djgpp + +# The ASIS repository's name for the machine we are on +#ASIS_MACH = hardware/os + +CFLAGS = -O3 -DUSE_ZLIB -DDOSPATH -DNOUSERS -DDEBUG -I../../../djgpp/tcplib/include -I../../../djgpp/tcplib/include/tcp \ +-I../../../src -I../../.. +LFLAGS = +CC = gcc + +# Directory for installed binary: +!BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + +include $(WWW)/Library/Implementation/Version.make +#include $(WWW)/Library/Implementation/CommonMakefile +include ./CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/duns/Makefile b/gnu/usr.bin/lynx/WWW/Library/duns/Makefile new file mode 100644 index 00000000000..4852817e856 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/duns/Makefile @@ -0,0 +1,489 @@ +# Makefile generated by imake - do not edit! +# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $ +# +# The cpp used on this machine replaces all newlines and multiple tabs and +# spaces in a macro expansion with a single space. Imake tries to compensate +# for this, but is not always successful. +# + +########################################################################### +# Makefile generated from "Imake.tmpl" and </tmp/IIf.a00214> +# $XConsortium: Imake.tmpl,v 1.77 89/12/18 17:01:37 jim Exp $ +# +# Platform-specific parameters may be set in the appropriate .cf +# configuration files. Site-wide parameters may be set in the file +# site.def. Full rebuilds are recommended if any parameters are changed. +# +# If your C preprocessor doesn't define any unique symbols, you'll need +# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing +# "make Makefile", "make Makefiles", or "make World"). +# +# If you absolutely can't get imake to work, you'll need to set the +# variables at the top of each Makefile as well as the dependencies at the +# bottom (makedepend will do this automatically). +# + +########################################################################### +# platform-specific configuration parameters - edit sun.cf to change + +# platform: $XConsortium: sun.cf,v 1.38 89/12/23 16:10:10 jim Exp $ +# operating system: SunOS 4.0.3 + +########################################################################### +# site-specific configuration parameters - edit site.def to change + + SHELL = /bin/sh + + TOP = . + CURRENT_DIR = . + + AR = ar clq + BOOTSTRAPCFLAGS = + CC = cc + + COMPRESS = compress + CPP = /lib/cpp $(STD_CPP_DEFINES) + PREPROCESSCMD = cc -E $(STD_CPP_DEFINES) + INSTALL = install + LD = ld + LINT = lint + LINTLIBFLAG = -C + LINTOPTS = -axz + LN = ln -s + MAKE = make + MV = mv + CP = cp + RANLIB = ranlib + RANLIBINSTFLAGS = + RM = rm -f + STD_INCLUDES = + STD_CPP_DEFINES = + STD_DEFINES = + EXTRA_LOAD_FLAGS = + EXTRA_LIBRARIES = + TAGS = ctags + + SHAREDCODEDEF = -DSHAREDCODE + SHLIBDEF = -DSUNSHLIB + + PROTO_DEFINES = + + INSTPGMFLAGS = + + INSTBINFLAGS = -m 0755 + INSTUIDFLAGS = -m 4755 + INSTLIBFLAGS = -m 0664 + INSTINCFLAGS = -m 0444 + INSTMANFLAGS = -m 0444 + INSTDATFLAGS = -m 0444 + INSTKMEMFLAGS = -m 4755 + + DESTDIR = + + TOP_INCLUDES = -I$(INCROOT) + + CDEBUGFLAGS = -O + CCOPTIONS = + COMPATFLAGS = + + ALLINCLUDES = $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES) + ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS) + CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) + LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) + LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) + LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) + LDCOMBINEFLAGS = -X -r + + MACROFILE = sun.cf + RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut + + IMAKE_DEFINES = + + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) + + ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \ + $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \ + $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES) + +########################################################################### +# X Window System Build Parameters +# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $ + +########################################################################### +# X Window System make variables; this need to be coordinated with rules +# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $ + + PATHSEP = / + USRLIBDIR = $(DESTDIR)/usr/lib + BINDIR = $(DESTDIR)/usr/bin/X11 + INCROOT = $(DESTDIR)/usr/include + BUILDINCROOT = $(TOP) + BUILDINCDIR = $(BUILDINCROOT)/X11 + BUILDINCTOP = .. + INCDIR = $(INCROOT)/X11 + ADMDIR = $(DESTDIR)/usr/adm + LIBDIR = $(USRLIBDIR)/X11 + CONFIGDIR = $(LIBDIR)/config + LINTLIBDIR = $(USRLIBDIR)/lint + + FONTDIR = $(LIBDIR)/fonts + XINITDIR = $(LIBDIR)/xinit + XDMDIR = $(LIBDIR)/xdm + AWMDIR = $(LIBDIR)/awm + TWMDIR = $(LIBDIR)/twm + GWMDIR = $(LIBDIR)/gwm + MANPATH = $(DESTDIR)/usr/man + MANSOURCEPATH = $(MANPATH)/man + MANDIR = $(MANSOURCEPATH)n + LIBMANDIR = $(MANSOURCEPATH)3 + XAPPLOADDIR = $(LIBDIR)/app-defaults + + SOXLIBREV = 4.2 + SOXTREV = 4.0 + SOXAWREV = 4.0 + SOOLDXREV = 4.0 + SOXMUREV = 4.0 + SOXEXTREV = 4.0 + + FONTCFLAGS = -t + + INSTAPPFLAGS = $(INSTDATFLAGS) + + IMAKE = imake + DEPEND = makedepend + RGB = rgb + FONTC = bdftosnf + MKFONTDIR = mkfontdir + MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier.sh + + CONFIGSRC = $(TOP)/config + CLIENTSRC = $(TOP)/clients + DEMOSRC = $(TOP)/demos + LIBSRC = $(TOP)/lib + FONTSRC = $(TOP)/fonts + INCLUDESRC = $(TOP)/X11 + SERVERSRC = $(TOP)/server + UTILSRC = $(TOP)/util + SCRIPTSRC = $(UTILSRC)/scripts + EXAMPLESRC = $(TOP)/examples + CONTRIBSRC = $(TOP)/../contrib + DOCSRC = $(TOP)/doc + RGBSRC = $(TOP)/rgb + DEPENDSRC = $(UTILSRC)/makedepend + IMAKESRC = $(CONFIGSRC) + XAUTHSRC = $(LIBSRC)/Xau + XLIBSRC = $(LIBSRC)/X + XMUSRC = $(LIBSRC)/Xmu + TOOLKITSRC = $(LIBSRC)/Xt + AWIDGETSRC = $(LIBSRC)/Xaw + OLDXLIBSRC = $(LIBSRC)/oldX + XDMCPLIBSRC = $(LIBSRC)/Xdmcp + BDFTOSNFSRC = $(FONTSRC)/bdftosnf + MKFONTDIRSRC = $(FONTSRC)/mkfontdir + EXTENSIONSRC = $(TOP)/extensions + + DEPEXTENSIONLIB = + EXTENSIONLIB = -lXext + + DEPXLIB = $(DEPEXTENSIONLIB) + XLIB = $(EXTENSIONLIB) -lX11 + + DEPXAUTHLIB = $(USRLIBDIR)/libXau.a + XAUTHLIB = -lXau + + DEPXMULIB = + XMULIB = -lXmu + + DEPOLDXLIB = + OLDXLIB = -loldX + + DEPXTOOLLIB = + XTOOLLIB = -lXt + + DEPXAWLIB = + XAWLIB = -lXaw + + LINTEXTENSIONLIB = $(USRLIBDIR)/llib-lXext.ln + LINTXLIB = $(USRLIBDIR)/llib-lX11.ln + LINTXMU = $(USRLIBDIR)/llib-lXmu.ln + LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln + LINTXAW = $(USRLIBDIR)/llib-lXaw.ln + + DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + + DEPLIBS1 = $(DEPLIBS) + DEPLIBS2 = $(DEPLIBS) + DEPLIBS3 = $(DEPLIBS) + +########################################################################### +# Imake rules for building libraries, programs, scripts, and data files +# rules: $XConsortium: Imake.rules,v 1.67 89/12/18 17:14:15 jim Exp $ + +########################################################################### +# start of Imakefile + +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +TK_WWW_SOURCE_PATH=/a/dxcern/userd/tbl/hypertext/WWW/TkWWW/Tcl + +TK_WWW_INSTALL_PATH=/a/dxcern/userd/tbl/hypertext/WWW/TkWWW/$(WWW_MACH) + +TK_WWW_HOME_PAGE=http://www.w3.org/default.html +TK_WWW_START_PAGE=$(TK_WWW_HOME_PAGE) + +CC = gcc -fno-builtin -Wall + +CDEBUGFLAGS = -O3 -pipe + +COMPATFLAGS = -I/afs/athena.mit.edu/course/other/cdsdev/www-compat +CCOPTIONS = + +BINDIR = $(TK_WWW_INSTALL_PATH) + +# For W3 distribution, machine type for subdirectories +WWW_MACH = unix.x + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = /tmp + +# Common Makefile for W3 Library Code +# ----------------------------------- +# +# (c) CERN 1990, 1991 -- see Copyright.html for conditions +# +# This file should be invariant between systems. +# DEPENDENCIES NOT COMPLETE + +# +# make Compile and link the software (private version) +# make clean Remove intermediate files + +WC = $(WWW)/Library +CMN = $(WWW)/Library/Implementation/ + +# Where shall we put the objects and built library? + +LOB = $(WTMP)/Library/$(WWW_MACH) + +# Bug: This path, if relative, is taken relative to the directory +# in which this makefile is, not the pwd. This screws up the +# recursive invocation + +VC = 2.14 + +CFLAGS2 = $(CFLAGS) -I$(CMN) + +CERNLIBBIN = $(WWW)/bin + +COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ + $(LOB)/HTFile.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ + $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ + $(LOB)/HTPlain.o $(LOB)/HTWriter.o $(LOB)/HTFWriter.o \ + $(LOB)/HTMLGen.o \ + $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ + $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ + $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ + $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ + $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) + +CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ + $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ + $(CMN)HTMLDTD.c \ + $(CMN)HTPlain.c $(CMN)HTWriter.c $(CMN)HTFWriter.c $(CMN)HTMLGen.c \ + $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ + $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ + $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ + $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ + $(CMN)HTWAIS.c $(CMN)HTWSRC.c + +HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ + $(CMN)HTFTP.h $(CMN)HTTCP.h \ + $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ + $(CMN)HTPlain.h $(CMN)HTWriter.h \ + $(CMN)HTFWriter.h $(CMN)HTMLGen.h \ + $(CMN)HTStream.h \ + $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ + $(CMN)HTList.h \ + $(CMN)HTString.h $(CMN)HTAlert.h $(CMN)HTRules.h \ + $(CMN)HTFormat.h $(CMN)HTInit.h \ + $(CMN)HTMIME.h $(CMN)HTHistory.h $(CMN)HTNews.h \ + $(CMN)HTGopher.h \ + $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)WWW.h $(CMN)HText.h \ + $(CMN)HTTelnet.h \ + $(CMN)HTWAIS.h $(CMN)HTWSRC.h + +SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make $(CMN)CommonMakefile \ + $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD +SPECIFIC = $(WWW)/All + +# Library +# +# On SGI, ranlib is unnecessary and does not exist so we ignore errors +# for that step +all: $(LOB)/libwww.a + $(MV) $(LOB)/libwww.a $(WC)/$(WWW_MACH) + +$(LOB)/libwww.a : $(COMMON) + ar r $(LOB)/libwww.a $(COMMON) + -ranlib $(LOB)/libwww.a + +# Clean up everything generatable except final products +clean :: + $(RM) $(LOB) + +# Clean up everything generatable including final products + +cleanall :: clean + $(RM) $(LOB)/libwww.a + +# Common code +# ----------- + +# Directory for object files - .created checks it exists + +OE = $(LOB)/.created +$(OE) : + -mkdir $(WTMP) + -mkdir $(WTMP)/Library + -mkdir $(WTMP)/Library/$(WWW_MACH) + touch $@ + +$(LOB)/HTList.o : $(OE) $(CMN)HTList.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTList.c + +$(LOB)/HTAnchor.o : $(OE) $(CMN)HTAnchor.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAnchor.c + +$(LOB)/HTFormat.o : $(OE) $(CMN)HTFormat.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFormat.c + +$(LOB)/HTInit.o : $(OE) $(CMN)HTInit.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTInit.c + +$(LOB)/HTMIME.o : $(OE) $(CMN)HTMIME.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMIME.c + +$(LOB)/HTHistory.o : $(OE) $(CMN)HTHistory.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTHistory.c + +$(LOB)/HTNews.o : $(OE) $(CMN)HTNews.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTNews.c + +$(LOB)/HTGopher.o : $(OE) $(CMN)HTGopher.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGopher.c + +$(LOB)/HTTelnet.o : $(OE) $(CMN)HTTelnet.c $(CMN)HTUtils.h $(CMN)HTTelnet.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTelnet.c + +$(LOB)/HTStyle.o : $(OE) $(CMN)HTStyle.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTStyle.c + +$(LOB)/HTAtom.o : $(OE) $(CMN)HTAtom.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAtom.c + +$(LOB)/HTChunk.o : $(OE) $(CMN)HTChunk.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTChunk.c + +$(LOB)/HTString.o : $(OE) $(CMN)HTString.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTString.c + +$(LOB)/HTAlert.o : $(OE) $(CMN)HTAlert.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTAlert.c + +$(LOB)/HTRules.o : $(OE) $(CMN)HTRules.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTRules.c + +$(LOB)/SGML.o : $(OE) $(CMN)SGML.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)SGML.c + +$(LOB)/HTMLGen.o : $(OE) $(CMN)HTMLGen.c $(CMN)HTUtils.h $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLGen.c + +$(LOB)/HTMLDTD.o : $(OE) $(CMN)HTMLDTD.c $(CMN)SGML.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLDTD.c + +$(LOB)/HTPlain.o : $(OE) $(CMN)HTPlain.c $(CMN)HTPlain.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPlain.c + +$(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + +$(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c + +$(LOB)/HTWriter.o : $(OE) $(CMN)HTWriter.c $(CMN)HTWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWriter.c + +$(LOB)/HTFWriter.o : $(OE) $(CMN)HTFWriter.c $(CMN)HTFWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFWriter.c + +# Communications & Files + +$(LOB)/HTTP.o : $(OE) $(CMN)HTTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTP.c + +$(LOB)/HTTCP.o : $(OE) $(CMN)HTTCP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTCP.c + +$(LOB)/HTFile.o : $(OE) $(CMN)HTFile.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFile.c + +$(LOB)/HTFTP.o : $(OE) $(CMN)HTFTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFTP.c + +$(LOB)/HTAccess.o : $(OE) $(CMN)HTAccess.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAccess.c + +$(LOB)/HTParse.o : $(OE) $(CMN)HTParse.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTParse.c + +########################################################################### +# common rules for all Makefiles - do not edit + +emptyrule:: + +clean:: + $(RM_CMD) \#* + +Makefile:: + -@if [ -f Makefile ]; then \ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) + +tags:: + $(TAGS) -w *.[ch] + $(TAGS) -xw *.[ch] > TAGS + +saber: + #load $(ALLDEFINES) $(SRCS) + +osaber: + #load $(ALLDEFINES) $(OBJS) + +########################################################################### +# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install in $(CURRENT_DIR) done" + +install.man:: + @echo "install.man in $(CURRENT_DIR) done" + +Makefiles:: + +includes:: + +########################################################################### +# dependencies generated by makedepend + diff --git a/gnu/usr.bin/lynx/WWW/Library/freebsd/Makefile b/gnu/usr.bin/lynx/WWW/Library/freebsd/Makefile new file mode 100644 index 00000000000..a82f13b8757 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/freebsd/Makefile @@ -0,0 +1,27 @@ +# Make WWW under FreeBSD +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = freebsd + +# The ASIS repository's name for the machine we are on +ASIS_MACH = i386/FreeBSD + + +CFLAGS += -DDEBUG +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/isc/Makefile b/gnu/usr.bin/lynx/WWW/Library/isc/Makefile new file mode 100644 index 00000000000..29de6885626 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/isc/Makefile @@ -0,0 +1,30 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = isc + +# The ASIS repository's name for the machine we are on +ASIS_MACH = intel/isc + + +CFLAGS = -DDEBUG -O -DISC -Dvfork=fork +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/mips/Makefile b/gnu/usr.bin/lynx/WWW/Library/mips/Makefile new file mode 100644 index 00000000000..1c84cbe089c --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/mips/Makefile @@ -0,0 +1,29 @@ +# Makefile for WWW under svr4 +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = mips + +# The ASIS repository's name for the machine we are on +ASIS_MACH = mips/mips + + +#CFLAGS = -DDEBUG -systype svr3 -DMIPS -DNO_BCOPY +CFLAGS = -O -DDEBUG -systype svr3 -I/svr3/usr/include/bsd +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/netbsd/Makefile b/gnu/usr.bin/lynx/WWW/Library/netbsd/Makefile new file mode 100644 index 00000000000..ae92760a5b8 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/netbsd/Makefile @@ -0,0 +1,29 @@ +# Make WWW under NetBSD +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = netbsd + +# The ASIS repository's name for the machine we are on +ASIS_MACH = i386/NetBSD + + +CFLAGS = -O -DUSE_DIRENT +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/next/Makefile b/gnu/usr.bin/lynx/WWW/Library/next/Makefile new file mode 100644 index 00000000000..bd35c89a9d0 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/next/Makefile @@ -0,0 +1,40 @@ +# Platform-specific Makefile for W3 Library (NeXT) +# ----------------------------------------- +# +# Library compiled with fudge to alow XMOSAIC to +# pick up binary files... for now. + +WWW = ../.. + +# Where should temporary (object) files go? Normally, WTMP = $(WWW) +#WTMP = /tmp +WTMP = $(WWW) + +# For MACH 3.0 it seems -bsd is needed to order to define errno +# in /usr/include/bsd/sys/errno.h. But __STRICT_BSD__ is needed for +# errno. + +CFLAGS = -Wall -O -DXMOSAIC_HACK + +# Yes please, I want direct WAIS access +# +#WAIS = ../../../freeWAIS +#WAISINC = -I$(WAIS)/ir +#WAISCFLAGS = -DDIRECT_WAIS +#WAISLIB = $(WAIS)/bin/client.a $(WAIS)/bin/wais.a +# $(WAIS)/bin/inv.a $(WAIS)/bin/wais.a +#HTWAIS = $(WTMP)/Library/$(WWW_MACH)/HTWAIS.o + +CC = cc +# For testing memory leaks only! Use /NextDeveloper/MallocDebug app +LFLAGS = -lMallocDebug +#LFLAGS = + +WWW_MACH = next +ASIS_MACH = next/2.0 + + +# Directory for installed binary: +LIBDIR = /usr/local/lib + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/osf/Makefile b/gnu/usr.bin/lynx/WWW/Library/osf/Makefile new file mode 100644 index 00000000000..a81457a60e9 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/osf/Makefile @@ -0,0 +1,23 @@ +# Platform-specific Makefile for W3 Library (decstation) +# ----------------------------------------- +# + +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +#CFLAGS = +CFLAGS = -DSYS5 +CC = cc -O +#LFLAGS = +LFLAGS = + +ASIS_MACH = alpha/osf1 +WWW_MACH = osf + +# Directory for installed binary: +LIBDIR = /usr/local/lib + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/ptx/Makefile b/gnu/usr.bin/lynx/WWW/Library/ptx/Makefile new file mode 100644 index 00000000000..772d6c6a038 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/ptx/Makefile @@ -0,0 +1,29 @@ +# Make WWW under Sequent's DYNIX/ptx +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = ptx + +# The ASIS repository's name for the machine we are on +ASIS_MACH = Sequent/ptx + + +CFLAGS = -O -DDEBUG -DUSE_DIRENT -DSVR4 -DNO_IOCTL -DUSE_FCNTL +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/rs6000/Makefile b/gnu/usr.bin/lynx/WWW/Library/rs6000/Makefile new file mode 100644 index 00000000000..334a5a4afbd --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/rs6000/Makefile @@ -0,0 +1,29 @@ +# Make WWW under unix for rs6000 with no gcc +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = rs6000 + +# For ASIS +ASIS_MACH = ibm-rs6000/aix-3.2 + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# The AIX compiler does not define unix... AIX will do it and avoid realloc bug + +CFLAGS = -O -DDEBUG +CC = cc +LFLAGS = + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = $(WWW) + +# Where is the W3 object library? +LIBDIR = /usr/local/lib + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/sco/Makefile b/gnu/usr.bin/lynx/WWW/Library/sco/Makefile new file mode 100644 index 00000000000..a00a948b069 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/sco/Makefile @@ -0,0 +1,33 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = sco + +# The ASIS repository's name for the machine we are on +# SCO does not presently have ranlib. Ignore the error +# message about that when the CommonMakefile tries to +# invoke it. +ASIS_MACH = intel/sco + + +CFLAGS = -O -DDEBUG -DSVR4 +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/sgi/Makefile b/gnu/usr.bin/lynx/WWW/Library/sgi/Makefile new file mode 100644 index 00000000000..24530722fb7 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/sgi/Makefile @@ -0,0 +1,30 @@ +# Make WWW for Silicon Graphics +# +# For W3 distribution, machine type for subdirectories +WWW_MACH = sgi + +# Architecutre in ASIS scheme +# SGI does not presently have ranlib. Ignore the error +# message about that when the CommonMakefile tries to +# invoke it. +ASIS_MACH = sgi/iris-3.5 + +CFLAGS = -DDEBUG -O -cckr +CC = cc +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/snake/Makefile b/gnu/usr.bin/lynx/WWW/Library/snake/Makefile new file mode 100644 index 00000000000..06db3012bf1 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/snake/Makefile @@ -0,0 +1,33 @@ +# Make WWW under unix for HP 700 or 800 (Snake) using cc +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = snake + +# Distribution point for ASIS repository +ASIS_MACH = hp-700/hpux-8.0 + +CFLAGS = -O -DDEBUG + +# Link with BSD library for getwd() +LFLAGS = -lBSD + +#CC = cc +#CC = gcc + +# Directory for installed binary: +BINDIR = /usr/local/bin + + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/solaris2/Makefile b/gnu/usr.bin/lynx/WWW/Library/solaris2/Makefile new file mode 100644 index 00000000000..a390cae9d0e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/solaris2/Makefile @@ -0,0 +1,29 @@ +# Make WWW under unix for sun 4 +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = solaris2 + +# The ASIS repository's name for the machine we are on +ASIS_MACH = sun-4/sunos-5.2 + + +CFLAGS = -O -DDEBUG -DNGROUPS=16 -Dd_namlen=d_reclen -DNO_BCOPY -DSOLARIS2 -DSVR4 -DUSE_DIRENT +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/sun3/Makefile b/gnu/usr.bin/lynx/WWW/Library/sun3/Makefile new file mode 100644 index 00000000000..ee9c6288e13 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/sun3/Makefile @@ -0,0 +1,29 @@ +# Make WWW under unix for sun 3 +# +# For W3 distribution, machine type for subdirectories +WWW_MACH = sun3 + +# For ASIS installation, the ASIS code for the machine/os +ASIS_MACH = sun-3/sunos-4.1.1 + +# Directory for installed binary: +BINDIR = /usr/local/bin + +CFLAGS = -DDEBUG -O +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/sun4/Makefile b/gnu/usr.bin/lynx/WWW/Library/sun4/Makefile new file mode 100644 index 00000000000..cf14decbcbf --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/sun4/Makefile @@ -0,0 +1,29 @@ +# Make WWW under unix for sun 4 +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = sun4 + +# The ASIS repository's name for the machine we are on +ASIS_MACH = sun-4/sunos-4.1.1 + + +CFLAGS = -DDEBUG -O +LFLAGS = + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/svr4/Makefile b/gnu/usr.bin/lynx/WWW/Library/svr4/Makefile new file mode 100644 index 00000000000..a97e6656555 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/svr4/Makefile @@ -0,0 +1,29 @@ +# Make WWW under svr4 +# + +# For W3 distribution, machine type for subdirectories +WWW_MACH = svr4 + +# The ASIS repository's name for the machine we are on +ASIS_MACH = generic/svr4 + + +CFLAGS = -O -DDEBUG -DUSE_DIRENT -DSVR4 +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/umaxv-m88k/Makefile b/gnu/usr.bin/lynx/WWW/Library/umaxv-m88k/Makefile new file mode 100644 index 00000000000..79c323c0d59 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/umaxv-m88k/Makefile @@ -0,0 +1,30 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = umaxv-m88k + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + + +CFLAGS = -O -DDEBUG -D_SYSV3 +LFLAGS = +CC = cc + +# Directory for installed binary: +BINDIR = /usr/local/bin + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = ../.. + + +include $(WWW)/Library/Implementation/CommonMakefile + diff --git a/gnu/usr.bin/lynx/WWW/Library/unix/makefile.in b/gnu/usr.bin/lynx/WWW/Library/unix/makefile.in new file mode 100644 index 00000000000..94918497d7f --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/unix/makefile.in @@ -0,0 +1,62 @@ +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +# For W3 distribution, machine type for subdirectories +WWW_MACH = unix + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + +LFLAGS = + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = $(srcdir) + +LYFLAGS = # FIXME: set in parent makefile + +CC = @CC@ +DEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +CPPOPTS = $(DEFS) $(CPPFLAGS) $(LYFLAGS) -I../../.. -I../../../src -I$(top_srcdir) -I$(top_srcdir)/src +LY_CFLAGS = @CFLAGS@ +CFLAGS = $(CPPOPTS) $(LY_CFLAGS) + +# Directory for installed binary: +BINDIR = @bindir@ + +# Where is the W3 object library to be installed (not normally done)? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = $(top_srcdir)/WWW + +# Where should temporary (object) files go? +WTMP = ../.. + +@make_include_left@$(WWW)/Library/Implementation/Version.make@make_include_right@ +@make_include_left@$(WWW)/Library/Implementation/CommonMakefile@make_include_right@ + +# Override values set in CommonMakefile + +RANLIB = @RANLIB@ + +all : $(LOB)/libwww.a + +.SUFFIXES: .i .h .html + +.c.o: +@RULE_CC@ + @ECHO_CC@$(CC) $(CPPOPTS) $(CFLAGS) -c $(srcdir)/$*.c + +.c.i: +@RULE_CC@ + @ECHO_CC@$(CPP) -C $(CPPOPTS) $*.c >$@ + +depend : + makedepend -fmakefile -- $(CFLAGS) -- $(CFILES) + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/gnu/usr.bin/lynx/WWW/Library/unix_x/Makefile b/gnu/usr.bin/lynx/WWW/Library/unix_x/Makefile new file mode 100644 index 00000000000..23c12453cf7 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/unix_x/Makefile @@ -0,0 +1,491 @@ +# Makefile generated by imake - do not edit! +# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $ +# +# The cpp used on this machine replaces all newlines and multiple tabs and +# spaces in a macro expansion with a single space. Imake tries to compensate +# for this, but is not always successful. +# + +########################################################################### +# Makefile generated from "Imake.tmpl" and </tmp/IIf.a02602> +# $XConsortium: Imake.tmpl,v 1.77 89/12/18 17:01:37 jim Exp $ +# +# Platform-specific parameters may be set in the appropriate .cf +# configuration files. Site-wide parameters may be set in the file +# site.def. Full rebuilds are recommended if any parameters are changed. +# +# If your C preprocessor doesn't define any unique symbols, you'll need +# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing +# "make Makefile", "make Makefiles", or "make World"). +# +# If you absolutely can't get imake to work, you'll need to set the +# variables at the top of each Makefile as well as the dependencies at the +# bottom (makedepend will do this automatically). +# + +########################################################################### +# platform-specific configuration parameters - edit sun.cf to change + +# platform: $XConsortium: sun.cf,v 1.38 89/12/23 16:10:10 jim Exp $ +# operating system: SunOS 4.1.1 + +########################################################################### +# site-specific configuration parameters - edit site.def to change + +# site: $XConsortium: site.def,v 1.21 89/12/06 11:46:50 jim Exp $ + + SHELL = /bin/sh + + TOP = ../../../. + CURRENT_DIR = ./../Library/unix_x + + AR = ar cq + BOOTSTRAPCFLAGS = + CC = gcc -DNOSTDHDRS -fstrength-reduce -fpcc-struct-return -fwritable-strings -traditional + + COMPRESS = compress + CPP = /lib/cpp $(STD_CPP_DEFINES) + PREPROCESSCMD = gcc -DNOSTDHDRS -fstrength-reduce -fpcc-struct-return -fwritable-strings -traditional -E $(STD_CPP_DEFINES) + INSTALL = install + LD = ld + LINT = lint + LINTLIBFLAG = -C + LINTOPTS = -axz + LN = ln -s + MAKE = make + MV = mv + CP = cp + RANLIB = ranlib + RANLIBINSTFLAGS = + RM = rm -f + STD_INCLUDES = + STD_CPP_DEFINES = + STD_DEFINES = + EXTRA_LOAD_FLAGS = + EXTRA_LIBRARIES = + TAGS = ctags + + SHAREDCODEDEF = -DSHAREDCODE + SHLIBDEF = -DSUNSHLIB + + PROTO_DEFINES = + + INSTPGMFLAGS = + + INSTBINFLAGS = -m 0755 + INSTUIDFLAGS = -m 4755 + INSTLIBFLAGS = -m 0664 + INSTINCFLAGS = -m 0444 + INSTMANFLAGS = -m 0444 + INSTDATFLAGS = -m 0444 + INSTKMEMFLAGS = -m 4755 + + DESTDIR = + + TOP_INCLUDES = -I$(INCROOT) + + CDEBUGFLAGS = -O + CCOPTIONS = + COMPATFLAGS = + + ALLINCLUDES = $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES) + ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS) + CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) + LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) + LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) + LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) + LDCOMBINEFLAGS = -X -r + + MACROFILE = sun.cf + RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut + + IMAKE_DEFINES = + + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) + + ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \ + $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \ + $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES) + +########################################################################### +# X Window System Build Parameters +# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $ + +########################################################################### +# X Window System make variables; this need to be coordinated with rules +# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $ + + PATHSEP = / + USRLIBDIR = $(DESTDIR)/usr/lib + BINDIR = $(DESTDIR)/usr/bin/X11 + INCROOT = $(DESTDIR)/usr/include + BUILDINCROOT = $(TOP) + BUILDINCDIR = $(BUILDINCROOT)/X11 + BUILDINCTOP = .. + INCDIR = $(INCROOT)/X11 + ADMDIR = $(DESTDIR)/usr/adm + LIBDIR = $(USRLIBDIR)/X11 + CONFIGDIR = $(LIBDIR)/config + LINTLIBDIR = $(USRLIBDIR)/lint + + FONTDIR = $(LIBDIR)/fonts + XINITDIR = $(LIBDIR)/xinit + XDMDIR = $(LIBDIR)/xdm + AWMDIR = $(LIBDIR)/awm + TWMDIR = $(LIBDIR)/twm + GWMDIR = $(LIBDIR)/gwm + MANPATH = $(DESTDIR)/usr/man + MANSOURCEPATH = $(MANPATH)/man + MANDIR = $(MANSOURCEPATH)n + LIBMANDIR = $(MANSOURCEPATH)3 + XAPPLOADDIR = $(LIBDIR)/app-defaults + + SOXLIBREV = 4.2 + SOXTREV = 4.0 + SOXAWREV = 4.0 + SOOLDXREV = 4.0 + SOXMUREV = 4.0 + SOXEXTREV = 4.0 + + FONTCFLAGS = -t + + INSTAPPFLAGS = $(INSTDATFLAGS) + + IMAKE = imake + DEPEND = makedepend + RGB = rgb + FONTC = bdftosnf + MKFONTDIR = mkfontdir + MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier.sh + + CONFIGSRC = $(TOP)/config + CLIENTSRC = $(TOP)/clients + DEMOSRC = $(TOP)/demos + LIBSRC = $(TOP)/lib + FONTSRC = $(TOP)/fonts + INCLUDESRC = $(TOP)/X11 + SERVERSRC = $(TOP)/server + UTILSRC = $(TOP)/util + SCRIPTSRC = $(UTILSRC)/scripts + EXAMPLESRC = $(TOP)/examples + CONTRIBSRC = $(TOP)/../contrib + DOCSRC = $(TOP)/doc + RGBSRC = $(TOP)/rgb + DEPENDSRC = $(UTILSRC)/makedepend + IMAKESRC = $(CONFIGSRC) + XAUTHSRC = $(LIBSRC)/Xau + XLIBSRC = $(LIBSRC)/X + XMUSRC = $(LIBSRC)/Xmu + TOOLKITSRC = $(LIBSRC)/Xt + AWIDGETSRC = $(LIBSRC)/Xaw + OLDXLIBSRC = $(LIBSRC)/oldX + XDMCPLIBSRC = $(LIBSRC)/Xdmcp + BDFTOSNFSRC = $(FONTSRC)/bdftosnf + MKFONTDIRSRC = $(FONTSRC)/mkfontdir + EXTENSIONSRC = $(TOP)/extensions + + DEPEXTENSIONLIB = $(USRLIBDIR)/libXext.a + EXTENSIONLIB = -lXext + + DEPXLIB = $(DEPEXTENSIONLIB) + XLIB = $(EXTENSIONLIB) -lX11 + + DEPXAUTHLIB = $(USRLIBDIR)/libXau.a + XAUTHLIB = -lXau + + DEPXMULIB = + XMULIB = -lXmu + + DEPOLDXLIB = + OLDXLIB = -loldX + + DEPXTOOLLIB = + XTOOLLIB = -lXt + + DEPXAWLIB = + XAWLIB = -lXaw + + LINTEXTENSIONLIB = $(USRLIBDIR)/llib-lXext.ln + LINTXLIB = $(USRLIBDIR)/llib-lX11.ln + LINTXMU = $(USRLIBDIR)/llib-lXmu.ln + LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln + LINTXAW = $(USRLIBDIR)/llib-lXaw.ln + + DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + + DEPLIBS1 = $(DEPLIBS) + DEPLIBS2 = $(DEPLIBS) + DEPLIBS3 = $(DEPLIBS) + +########################################################################### +# Imake rules for building libraries, programs, scripts, and data files +# rules: $XConsortium: Imake.rules,v 1.67 89/12/18 17:14:15 jim Exp $ + +########################################################################### +# start of Imakefile + +# Make WWW under unix for a.n.other unix system (bsd) +# Use this as a template + +TK_WWW_SOURCE_PATH=/a/dxcern/userd/tbl/hypertext/WWW/TkWWW/Tcl + +TK_WWW_INSTALL_PATH=/a/dxcern/userd/tbl/hypertext/WWW/TkWWW/$WWW_MACH + +TK_WWW_HOME_PAGE=http://www.w3.org/default.html +TK_WWW_START_PAGE=$(TK_WWW_HOME_PAGE) + +CC = gcc -fno-builtin -Wall + +CDEBUGFLAGS = -O3 -pipe + +COMPATFLAGS = -I/afs/athena.mit.edu/course/other/cdsdev/www-compat +CCOPTIONS = + +BINDIR = $(TK_WWW_INSTALL_PATH) + +# For W3 distribution, machine type for subdirectories +WWW_MACH = unix_x + +# The ASIS repository's name for the machine we are on +ASIS_MACH = hardware/os + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = /tmp + +# Common Makefile for W3 Library Code +# ----------------------------------- +# +# (c) CERN 1990, 1991 -- see Copyright.html for conditions +# +# This file should be invariant between systems. +# DEPENDENCIES NOT COMPLETE + +# +# make Compile and link the software (private version) +# make clean Remove intermediate files + +WC = $(WWW)/Library +CMN = $(WWW)/Library/Implementation/ + +# Where shall we put the objects and built library? + +LOB = $(WTMP)/Library/$(WWW_MACH) + +# Bug: This path, if relative, is taken relative to the directory +# in which this makefile is, not the pwd. This screws up the +# recursive invocation + +VC = 2.14 + +CFLAGS2 = $(CFLAGS) -I$(CMN) + +CERNLIBBIN = $(WWW)/bin + +COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ + $(LOB)/HTBTree.o \ + $(LOB)/HTFile.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ + $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ + $(LOB)/HTPlain.o $(LOB)/HTWriter.o $(LOB)/HTFWriter.o \ + $(LOB)/HTMLGen.o \ + $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ + $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ + $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ + $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ + $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) + +CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTBTree.c \ + $(CMN)HTFile.c \ + $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ + $(CMN)HTMLDTD.c \ + $(CMN)HTPlain.c $(CMN)HTWriter.c $(CMN)HTFWriter.c $(CMN)HTMLGen.c \ + $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ + $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ + $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ + $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ + $(CMN)HTWAIS.c $(CMN)HTWSRC.c + +HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTBTree.h \ + $(CMN)HTFile.h \ + $(CMN)HTFTP.h $(CMN)HTTCP.h \ + $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ + $(CMN)HTPlain.h $(CMN)HTWriter.h \ + $(CMN)HTFWriter.h $(CMN)HTMLGen.h \ + $(CMN)HTStream.h \ + $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ + $(CMN)HTList.h \ + $(CMN)HTString.h $(CMN)HTAlert.h $(CMN)HTRules.h \ + $(CMN)HTFormat.h $(CMN)HTInit.h \ + $(CMN)HTMIME.h $(CMN)HTHistory.h $(CMN)HTNews.h \ + $(CMN)HTGopher.h \ + $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)WWW.h $(CMN)HText.h \ + $(CMN)HTTelnet.h \ + $(CMN)HTWAIS.h $(CMN)HTWSRC.h + +SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make $(CMN)CommonMakefile \ + $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD +SPECIFIC = $(WWW)/All + +# Library +# +# On SGI, ranlib is unnecessary and does not exist so we ignore errors +# for that step +all: $(LOB)/libwww.a + $(MV) $(LOB)/libwww.a $(WC)/$(WWW_MACH) + +$(LOB)/libwww.a : $(COMMON) + ar r $(LOB)/libwww.a $(COMMON) + -ranlib $(LOB)/libwww.a + +# Clean up everything generatable except final products +clean :: + $(RM) $(LOB) + +# Clean up everything generatable including final products + +cleanall :: clean + $(RM) $(LOB)/libwww.a + +# Common code +# ----------- + +# Directory for object files - .created checks it exists + +OE = $(LOB)/.created +$(OE) : + -mkdir $(WTMP) + -mkdir $(WTMP)/Library + -mkdir $(WTMP)/Library/$(WWW_MACH) + touch $@ + +$(LOB)/HTList.o : $(OE) $(CMN)HTList.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTList.c + +$(LOB)/HTAnchor.o : $(OE) $(CMN)HTAnchor.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAnchor.c + +$(LOB)/HTFormat.o : $(OE) $(CMN)HTFormat.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFormat.c + +$(LOB)/HTInit.o : $(OE) $(CMN)HTInit.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTInit.c + +$(LOB)/HTMIME.o : $(OE) $(CMN)HTMIME.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMIME.c + +$(LOB)/HTHistory.o : $(OE) $(CMN)HTHistory.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTHistory.c + +$(LOB)/HTNews.o : $(OE) $(CMN)HTNews.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTNews.c + +$(LOB)/HTGopher.o : $(OE) $(CMN)HTGopher.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTGopher.c + +$(LOB)/HTTelnet.o : $(OE) $(CMN)HTTelnet.c $(CMN)HTUtils.h $(CMN)HTTelnet.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTelnet.c + +$(LOB)/HTStyle.o : $(OE) $(CMN)HTStyle.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTStyle.c + +$(LOB)/HTAtom.o : $(OE) $(CMN)HTAtom.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAtom.c + +$(LOB)/HTChunk.o : $(OE) $(CMN)HTChunk.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTChunk.c + +$(LOB)/HTString.o : $(OE) $(CMN)HTString.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTString.c + +$(LOB)/HTAlert.o : $(OE) $(CMN)HTAlert.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTAlert.c + +$(LOB)/HTRules.o : $(OE) $(CMN)HTRules.c $(CMN)HTUtils.h $(CMN)Version.make + $(CC) -c -o $@ $(CFLAGS2) -DVC=\"$(VC)\" $(CMN)HTRules.c + +$(LOB)/SGML.o : $(OE) $(CMN)SGML.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)SGML.c + +$(LOB)/HTMLGen.o : $(OE) $(CMN)HTMLGen.c $(CMN)HTUtils.h $(CMN)HTMLDTD.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLGen.c + +$(LOB)/HTMLDTD.o : $(OE) $(CMN)HTMLDTD.c $(CMN)SGML.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTMLDTD.c + +$(LOB)/HTPlain.o : $(OE) $(CMN)HTPlain.c $(CMN)HTPlain.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTPlain.c + +$(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + +$(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c + +$(LOB)/HTWriter.o : $(OE) $(CMN)HTWriter.c $(CMN)HTWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWriter.c + +$(LOB)/HTFWriter.o : $(OE) $(CMN)HTFWriter.c $(CMN)HTFWriter.h $(CMN)HTStream.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFWriter.c + +# Communications & Files + +$(LOB)/HTTP.o : $(OE) $(CMN)HTTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTP.c + +$(LOB)/HTTCP.o : $(OE) $(CMN)HTTCP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTTCP.c + +$(LOB)/HTBTree.o : $(OE) $(CMN)HTBTree.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTBTree.c + +$(LOB)/HTFile.o : $(OE) $(CMN)HTFile.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFile.c + +$(LOB)/HTFTP.o : $(OE) $(CMN)HTFTP.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTFTP.c + +$(LOB)/HTAccess.o : $(OE) $(CMN)HTAccess.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTAccess.c + +$(LOB)/HTParse.o : $(OE) $(CMN)HTParse.c $(CMN)HTUtils.h + $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTParse.c + +########################################################################### +# common rules for all Makefiles - do not edit + +emptyrule:: + +clean:: + $(RM_CMD) \#* + +Makefile:: + -@if [ -f Makefile ]; then \ + echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) + +tags:: + $(TAGS) -w *.[ch] + $(TAGS) -xw *.[ch] > TAGS + +########################################################################### +# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install in $(CURRENT_DIR) done" + +install.man:: + @echo "install.man in $(CURRENT_DIR) done" + +Makefiles:: + +includes:: + +########################################################################### +# dependencies generated by makedepend + diff --git a/gnu/usr.bin/lynx/WWW/Library/vax_ultrix/Makefile b/gnu/usr.bin/lynx/WWW/Library/vax_ultrix/Makefile new file mode 100644 index 00000000000..2caf766cc0e --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/vax_ultrix/Makefile @@ -0,0 +1,33 @@ +# Make WWW under ultrix with gcc +# + + +# For W3 distribution, machine type for subdirectories +WWW_MACH = vax_ultrix + +# For ASIS installation, the ASIS code for the machine/os +ASIS_MACH = none + +CC = gcc +CFLAGS = -O -DDEBUG -Wall +LFLAGS = -O + +# This is bug fix for out-of-date ultrix on cernvax +# LFLAGS = -O pfcode.o -lresolv + +# Directory for installed binary: +BINDIR = /usr/local/unix + + +#_________________ OK if normal W3 distribution +# Where is the WWW source root? +WWW = ../.. + +# Where should temporary (object) files go? +WTMP = /tmp + + +# Where is the W3 object library? +LIBDIR = $(WWW)/Library/Implementation/$(WWW_MACH) + +include $(WWW)/Library/Implementation/CommonMakefile diff --git a/gnu/usr.bin/lynx/WWW/Library/vms/COPYING.LIB b/gnu/usr.bin/lynx/WWW/Library/vms/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/vms/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/lynx/WWW/Library/vms/descrip.mms b/gnu/usr.bin/lynx/WWW/Library/vms/descrip.mms new file mode 100644 index 00000000000..216e6aee654 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/vms/descrip.mms @@ -0,0 +1,255 @@ +! Make WorldWideWeb LIBRARY under VMS +! ======================================================= +! +! History: +! 14 Aug 91 (TBL) Reconstituted +! 25 Jun 92 (JFG) Added TCP socket emulation over DECnet +! 07 Sep 93 (MD) Remade for version 2.09a +! 10 Dec 93 (FM) Upgrade for version 2.14 with Lynx v2.1 +! 13 Dec 93 (FM) Added conditional compilations for VAXC vs. DECC +! (MMS can't handle a MODULE list as large as the +! WWWLibrary has become, so this just illustrates +! how you'd set it up if it could 8-). +! 26 Oct 94 (RLD) Updated to work with VAX/VMS v5.5-1 and AXP/VMS v6.1 +! 31 Oct 94 (RLD) Updated for Lynx v2.3.4, supporting OpenCMU and +! TCPWare +! 18 Nov 94 (FM) Updated for SOCKETSHR/NETLIB +! 07 Dec 94 (FM) Updated for DECC/VAX, VAXC/VAX and DECC/AXP +! 03 May 95 (FM) Include /NoMember for DECC (not the default on AXP, +! and the code assumes byte alignment). +! 07 Jul 95 (FM) Added GNUC support. +! +! Bugs: +! The dependencies are anything but complete - they were +! just enough to allow the files to be compiled. +! +! Instructions: +! Copy [WWW.LIBRARY.VMS]DESCRIP.MMS into [WWW.LIBRARY.IMPLEMENTATION] +! Use the correct command line for your TCP/IP implementation, +! inside the IMPLEMENTATION directory: +! +! $ MMS/MACRO=(MULTINET=1) for VAXC - MultiNet +! $ MMS/MACRO=(WIN_TCP=1) for VAXC - Wollongong TCP/IP +! $ MMS/MACRO=(UCX=1) for VAXC - UCX +! $ MMS/MACRO=(CMU_TCP=1) for VAXC - OpenCMU TCP/IP +! $ MMS/MACRO=(SOCKETSHR_TCP=1) for VAXC - SOCKETSHR/NETLIB +! $ MMS/MACRO=(TCPWARE=1) for VAXC - TCPWare TCP/IP +! $ MMS/MACRO=(DECNET=1) for VAXC - socket emulation over DECnet +! +! $ MMS/MACRO=(MULTINET=1,DEC_C=1) for DECC - MultiNet +! $ MMS/MACRO=(WIN_TCP=1,DEC_C=1) for DECC - Wollongong TCP/IP +! $ MMS/MACRO=(UCX=1,DEC_C=1) for DECC - UCX +! $ MMS/MACRO=(CMU_TCP=1,DEC_C=1) for DECC - OpenCMU TCP/IP +! $ MMS/MACRO=(SOCKETSHR_TCP=1,DEC_C=1) for DECC - SOCKETSHR/NETLIB +! $ MMS/MACRO=(TCPWARE=1,DEC_C=1) for DECC - TCPWare TCP/IP +! $ MMS/MACRO=(DECNET=1,DEC_C=1) for DECC - socket emulation over DECnet +! +! $ MMS/MACRO=(MULTINET=1,GNU_C=1) for GNUC - MultiNet +! $ MMS/MACRO=(WIN_TCP=1,GNU_C=1) for GNUC - Wollongong TCP/IP +! $ MMS/MACRO=(UCX=1,GNU_C=1) for GNUC - UCX +! $ MMS/MACRO=(CMU_TCP=1,GNU_C=1) for GNUC - OpenCMU TCP/IP +! $ MMS/MACRO=(SOCKETSHR_TCP=1,GNU_C=1) for GNUC - SOCKETSHR/NETLIB +! $ MMS/MACRO=(TCPWARE=1,GNU_C=1) for GNUC - TCPWare TCP/IP +! $ MMS/MACRO=(DECNET=1,GNU_C=1) for GNUC - socket emulation over DECnet +! +! To compile with debug mode: +! +! $ MMS/MACRO=(MULTINET=1, DEBUG=1) for Multinet +! +! +! If you are on HEP net and want to build using the really latest sources on +! PRIAM:: then define an extra macro U=PRIAM::, e.g. +! +! $ MMS/MACRO=(MULTINET=1, U=PRIAM::) for Multinet +! +! This will copy the sources from PRIAM as necessary. You can also try +! +! $ MMS/MACRO=(U=PRIAM::) descrip.mms +! +! to update this file. + + +.include Version.make + +! debug flags +.ifdef DEBUG +DEBUGFLAGS = /Debug /NoOptimize +.endif + +! defines valid for all compilations +EXTRADEFINES = DEBUG, ACCESS_AUTH, VC="""$(VC)""" + +! DECC flags for all compilations +.ifdef DEC_C +DCFLAGS = /NoMember /Warning=(disable=implicitfunc) +.endif + +.ifdef UCX +TCP = UCX +.ifdef DEC_C +CFLAGS = /decc/Prefix=All $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), UCX) +.else +CFLAGS = $(DEBUGFLAGS) /Define=($(EXTRADEFINES), UCX) +.endif +.endif + +.ifdef TCPWARE +TCP = TCPWARE +.ifdef DEC_C +CFLAGS = /decc/Prefix=All $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), UCX, TCPWARE) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), UCX, TCPWARE) +.endif +.endif + +.ifdef MULTINET +TCP = MULTINET +.ifdef DEC_C +CFLAGS = /decc/Prefix=ANSI $(DEBUGFLAGS) $(DCFLAGS) /Define=(_DECC_V4_SOURCE, __SOCKET_TYPEDEFS, $(EXTRADEFINES), MULTINET) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), MULTINET) +.endif +.endif + +.ifdef WIN_TCP +TCP = WIN_TCP +.ifdef DEC_C +CFLAGS = /decc/Prefix=ANSI $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), WIN_TCP) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), WIN_TCP) +.endif +.endif + +.ifdef CMU_TCP +TCP = CMU_TCP +.ifdef DEC_C +CFLAGS = /decc/Prefix=ANSI $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), CMU_TCP) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), CMU_TCP) +.endif +.endif + +.ifdef SOCKETSHR_TCP +TCP = SOCKETSHR_TCP +.ifdef DEC_C +CFLAGS = /decc/Prefix=ANSI $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), SOCKETSHR_TCP) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), SOCKETSHR_TCP) +.endif +.endif + +.ifdef DECNET +TCP = DECNET +.ifdef DEC_C +CFLAGS = /decc/Prefix=All $(DEBUGFLAGS) $(DCFLAGS) /Define=($(EXTRADEFINES), DECNET) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), DECNET) +.endif +.endif + +.ifdef TCP +.else +TCP = MULTINET ! (Default to MULTINET) +.ifdef DEC_C +CFLAGS = /decc/Prefix=ANSI $(DEBUGFLAGS) $(DCFLAGS) /Define=(_DECC_V4_SOURCE, __SOCKET_TYPEDEFS, $(EXTRADEFINES), MULTINET) +.else +CFLAGS = $(DEBUGFLAGS) /Define = ($(EXTRADEFINES), MULTINET) +.endif +.endif + +.ifdef GNU_C +CC = gcc +.endif + +!HEADERS = HTUtils.h, HTStream.h, tcp.h, HText.h - +! HTParse.h, HTAccess.h, HTTP.h, HTFile.h, - +! HTBTree.h, HTTCP.h, SGML.h, - +! HTML.h, HTMLDTD.h, HTChunk.h, HTPlain.h, - +! HTWriter.h, HTFwriter.h, HTMLGen.h, - +! HTAtom.h, HTAnchor.h, HTStyle.h, - +! HTList.h, HTString.h, HTAlert.h, - +! HTRules.h, HTFormat.h, HTInit.h, - +! HTMIME.h, HTHistory.h, HTTelnet.h, - +! HTFinger.h, HTAABrow.h, HTAAFile.h, - +! HTAAProt.h, HTAAServ.h, HTAAUtil.h, - +! HTAssoc.h, HTPasswd.h, HTAuth.h, HTUU.h, - +! HTVMSUtils.h, ufc-crypt.h, patchlevel.h + +MODULES = HTParse, HTAccess, HTTP, HTFile, HTBTree, HTFTP, HTTCP, HTString, - + SGML, HTMLDTD, HTChunk, HTPlain, HTWriter, HTMLGen, - + HTAtom, HTAnchor, HTStyle, HTList, HTRules, HTFormat, - + HTMIME, HTHistory, HTNews, HTGopher, HTTelnet, HTFinger, - + HTWSRC, HTAAUtil, HTAABrow, HTAAServ, HTAAFile, HTPasswd, HTGroup, - + HTACL, HTAuth, HTAAProt, HTAssoc, HTLex, HTUU, HTVMSUtils, getpass, - + getline, crypt, crypt_util, HTWAIS, HTVMS_WaisUI, HTVMS_WaisProt + +!.ifdef DECNET ! Strip FTP, Gopher, News, WAIS +!HEADERS = $(COMMON_HEADERS) +!MODULES = $(COMMON_MODULES) +!.else +!HEADERS = $(COMMON_HEADERS), $(EXTRA_HEADERS), $(WAIS_HEADER) +!MODULES = $(COMMON_MODULES), $(EXTRA_MODULES), $(WAIS_MODULE) +!.endif + +!___________________________________________________________________ +! WWW Library + +!library : $(HEADERS) wwwlib_$(TCP)($(MODULES)) +library : wwwlib_$(TCP)($(MODULES)) + @ Continue + +build_$(TCP).com : descrip.mms + $(MMS) /NoAction /From_Sources /Output = Build_$(TCP).com /Macro = ($(TCP)=1) + +clean : + - Set Protection = (Owner:RWED) *.*;-1 + - Purge /NoLog /NoConfirm + - Delete /NoLog /NoConfirm *.obj;,*.olb; + +!___________________________________________________________________ +! Simple Dependencies + + +!HTString.obj : HTString.c HTString.h tcp.h Version.make HTUtils.h +!HTAtom.obj : HTAtom.c HTAtom.h HTUtils.h HTString.h +!HTChunk.obj : HTChunk.c HTChunk.h HTUtils.h +!HTList.obj : HTList.c HTList.h HTUtils.h +!HTBTree.obj : HTBTree.c HTBTree.h HTUtils.h +!HTMLDTD.obj : HTMLDTD.c HTMLDTD.h SGML.h +!HTPlain.obj : HTPlain.c HTPlain.h HTStream.h +!HTWriter.obj : HTWriter.c HTWriter.h HTStream.h +!HTMLGen.obj : HTMLGen.c HTMLGen.h HTUtils.h HTMLDTD.h +!HTRules.obj : HTRules.c HTRules.h HTUtils.h Version.make +!HTMIME.obj : HTMIME.c HTMIME.h HTUtils.h HTList.h +!HTTelnet.obj : HTTelnet.c HTTelnet.h HTUtils.h +!HTWAIS.obj : HTWAIS.c HTWAIS.h HTUtils.h HTList.h +!HTWSRC.obj : HTWSRC.c HTWSRC.h HTUtils.h HTList.h +!HTAccess.obj : HTAccess.c HTAccess.h HTUtils.h +!HTAnchor.obj : HTAnchor.c HTAnchor.h HTUtils.h HTList.h +!HTFile.obj : HTFile.c HTFile.h HTUtils.h HTVMSUtils.h +!HTFormat.obj : HTFormat.c HTFormat.h HTUtils.h HTML.h SGML.h HTPlain.h HTMLGen.h HTList.h +!HTFTP.obj : HTFTP.c HTFTP.h HTUtils.h +!HTGopher.obj : HTGopher.c HTGopher.h HTUtils.h HTList.h +!HTFinger.obj : HTFinger.c HTFinger.h HTUtils.h HTList.h +!HTHistory.obj : HTHistory.c HTHistory.h HTUtils.h HTList.h +!HTNews.obj : HTNews.c HTNews.h HTUtils.h HTList.h +!HTParse.obj : HTParse.c HTParse.h HTUtils.h +!HTStyle.obj : HTStyle.c HTStyle.h HTUtils.h +!HTTCP.obj : HTTCP.c HTTCP.h HTUtils.h tcp.h +!HTTP.obj : HTTP.c HTTP.h HTUtils.h +!SGML.obj : SGML.c SGML.h HTUtils.h +!HTAABrow.obj : HTAABrow.c HTUtils.h +!HTAAFile.obj : HTAAFile.c HTUtils.h +!HTAAProt.obj : HTAAProt.c HTUtils.h +!HTAAServ.obj : HTAAServ.c HTUtils.h +!HTAAUtil.obj : HTAAUtil.c HTUtils.h +!HTACL.obj : HTACL.c HTUtils.h +!HTGroup.obj : HTGroup.c HTUtils.h +!HTLex.obj : HTLex.c HTUtils.h +!HTAssoc.obj : HTAssoc.c HTAssoc.h HTAAUtil.h HTString.h +!HTPasswd.obj : HTPasswd.c HTPasswd.h HTUtils.h HTAAUtil.h HTFile.h tcp.h +!HTAuth.obj : HTAuth.c HTAuth.h HTUtils.h HTPasswd.h HTAssoc.h HTUU.h +!HTUU.obj : HTUU.c HTUU.h HTUtils.h +!crypt.obj : crypt.c ufc-crypt.h +!HTVMSUtils.obj : HTVMSUtils.c HTVMSUtils.h HTUtils.h +!crypt_util.obj : crypt_util.c ufc-crypt.h patchlevel.h diff --git a/gnu/usr.bin/lynx/WWW/Library/vms/libmake.com b/gnu/usr.bin/lynx/WWW/Library/vms/libmake.com new file mode 100644 index 00000000000..96223f00407 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/vms/libmake.com @@ -0,0 +1,201 @@ +$ v = 'f$verify(0)' +$! LIBMAKE.COM +$! +$! Command file to build the WWWLibrary on VMS systems. +$! +$! 08-Oct-1997 F.Macrides macrides@sci.wfeb.edu +$! Added comments and minor tweaks for convenient addition of +$! compiler definitions and compiler and linker options. +$! 26-Jul-1995 F.Macrides macrides@sci.wfeb.edu +$! Adding support for GNUC. +$! 03-May-1995 F.Macrides macrides@sci.wfeb.edu +$! Include /nomember for compilations with DECC. It's not the +$! default on AXP and the code assumes byte alignment. +$! 07-Dec-1994 F.Macrides macrides@sci.wfeb.edu +$! Updated for DECC/VAX, VAXC/VAX and DECC/AXP +$! 03-NOV-1994 A.Harper A.Harper@kcl.ac.uk +$! Mods to support SOCKETSHR/NETLIB and add a /DEBUG/NOOPT option +$! 02-Jun-1994 F.Macrides macrides@sci.wfeb.edu +$! Mods to support TCPWare (To use non-blocking connects, you need +$! the DRIVERS_V405B.INC patch from FTP.PROCESS.COM for TCPware for +$! OpenVMS Version 4.0-5, or a higher version of TCPWare, which will +$! have that bug in the TCPDRIVER fixed. Otherwise, add NO_IOCTL to +$! the /define=(...) list.) +$! 20-May-1994 Andy Harper A.Harper@bay.cc.kcl.ac.uk +$! Added support for the CMU TCP/IP transport +$! 13-Dec-1993 F.Macrides macrides@sci.wfeb.edu +$! Mods for conditional compilations with VAXC versus DECC +$! 10-Dec-1993 F.Macrides macrides@sci.wfeb.edu +$! Initial version, for WWWLibrary v2.14 with Lynx v2.1 +$! +$ ON CONTROL_Y THEN GOTO CLEANUP +$ ON ERROR THEN GOTO CLEANUP +$! +$! Compiler definitions can be added here as a comma separated +$! list with a lead comma, e.g., ",HAVE_FOO_H,DO_BLAH". They +$! will apply only to the libwww-FM modules. - FM +$! +$ extra = "" +$! +$! If no TCP/IP agent is specified (as the first argument), +$! prompt for a number from the list. Note that the agent +$! must be the first argument if the debugger mode is to be +$! set via a second argument (see below). - FM +$! +$ agent = 0 +$ IF P1 .EQS. "" +$ THEN +$ write sys$output "Acceptable TCP/IP agents are" +$ write sys$output " [1] MultiNet (default)" +$ write sys$output " [2] UCX" +$ write sys$output " [3] WIN_TCP" +$ write sys$output " [4] CMU_TCP" +$ write sys$output " [5] SOCKETSHR_TCP" +$ write sys$output " [6] TCPWARE" +$ write sys$output " [7] DECNET" +$ read sys$command/prompt="Agent [1,2,3,4,5,6,7] (RETURN = [1]) " agent +$ ENDIF +$ if agent .eq. 1 .or. agent .eqs. "" .or. p1 .eqs. "MULTINET" then - + transport = "MULTINET" +$ if agent .eq. 2 .or. p1 .eqs. "UCX" then transport = "UCX" +$ if agent .eq. 3 .or. p1 .eqs. "WIN_TCP" then transport = "WIN_TCP" +$ if agent .eq. 4 .or. p1 .eqs. "CMU_TCP" then transport = "CMU_TCP" +$ if agent .eq. 5 .or. p1 .eqs. "SOCKETSHR_TCP" then transport = "SOCKETSHR_TCP" +$ if agent .eq. 6 .or. p1 .eqs. "TCPWARE" then transport = "TCPWARE" +$ if agent .eq. 7 .or. p1 .eqs. "DECNET" then transport = "DECNET" +$! +$ if transport .eqs. "TCPWARE" then extra = extra + ",UCX" +$! +$! Compiler options can be specified here. If there was +$! a second argument (with any value), then debugger mode +$! with no optimization will be specified as well. - FM +$! +$ cc_opts = "" +$ if p2 .nes. "" then cc_opts = cc_opts + "/DEBUG/NOOPT" +$! +$ IF f$trnlnm("VAXCMSG") .eqs. "DECC$MSG" .or. - + f$trnlnm("DECC$CC_DEFAULT") .eqs. "/DECC" .or. - + f$trnlnm("DECC$CC_DEFAULT") .eqs. "/VAXC" +$ THEN +$ v1 = f$verify(1) +$! DECC: +$ v1 = 'f$verify(0)' +$ If transport .eqs. "UCX" .or. transport .eqs. "TCPWARE" +$ Then +$ v1 = f$verify(1) +$! +$ cc/decc/prefix=all /nomember 'cc_opts'- + /warning=(disable=implicitfunc)- + /DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra',VC="""2.14""")- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) - + [-.Implementation]HTString.c +$! +$ cc := cc/decc/prefix=all /nomember 'cc_opts'- + /warning=(disable=implicitfunc)- + /DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra')- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) +$! +$ v1 = 'f$verify(0)' +$ Else +$ if transport .eqs. "MULTINET" then - + extra = extra + ",_DECC_V4_SOURCE,__SOCKET_TYPEDEFS" +$ v1 = f$verify(1) +$! +$ cc/decc/prefix=ansi /nomember 'cc_opts'- + /warning=(disable=implicitfunc)- + /DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra',VC="""2.14""")- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) - + [-.Implementation]HTString.c +$! +$ cc := cc/decc/prefix=ansi /nomember 'cc_opts'- + /warning=(disable=implicitfunc)- + /DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra')- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) +$! +$ v1 = 'f$verify(0)' +$ EndIf +$ ELSE +$ IF f$search("gnu_cc:[000000]gcclib.olb") .nes. "" +$ THEN +$ v1 = f$verify(1) +$! GNUC: +$! +$ gcc/DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra',VC="""2.14""") 'cc_opts'- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) - + [-.Implementation]HTString.c +$! +$ cc := gcc/DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra') 'cc_opts'- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) +$! +$ v1 = 'f$verify(0)' +$ ELSE +$ v1 = f$verify(1) +$! VAXC: +$! +$ cc/DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra',VC="""2.14""") 'cc_opts'- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) - + [-.Implementation]HTString.c +$! +$ cc := cc/DEFINE=(DEBUG,ACCESS_AUTH,'transport''extra') 'cc_opts'- + /INCLUDE=([-.Implementation],[---.src],[---.src.chrtrans],[---]) +$! +$ v1 = 'f$verify(0)' +$ ENDIF +$ ENDIF +$ v1 = f$verify(1) +$ cc [-.Implementation]HTParse.c +$ cc [-.Implementation]HTAccess.c +$ cc [-.Implementation]HTTP.c +$ cc [-.Implementation]HTFile.c +$ cc [-.Implementation]HTBTree.c +$ cc [-.Implementation]HTFTP.c +$ cc [-.Implementation]HTTCP.c +$ cc [-.Implementation]SGML.c +$ cc [-.Implementation]HTMLDTD.c +$ cc [-.Implementation]HTChunk.c +$ cc [-.Implementation]HTPlain.c +$ cc [-.Implementation]HTWriter.c +$ cc [-.Implementation]HTMLGen.c +$ cc [-.Implementation]HTAtom.c +$ cc [-.Implementation]HTAnchor.c +$ cc [-.Implementation]HTStyle.c +$ cc [-.Implementation]HTList.c +$ cc [-.Implementation]HTRules.c +$ cc [-.Implementation]HTFormat.c +$ cc [-.Implementation]HTMIME.c +$ cc [-.Implementation]HTHistory.c +$ cc [-.Implementation]HTNews.c +$ cc [-.Implementation]HTGopher.c +$ cc [-.Implementation]HTTelnet.c +$ cc [-.Implementation]HTFinger.c +$ cc [-.Implementation]HTWSRC.c +$ cc [-.Implementation]HTAAUtil.c +$ cc [-.Implementation]HTAABrow.c +$ cc [-.Implementation]HTAAServ.c +$ cc [-.Implementation]HTAAFile.c +$ cc [-.Implementation]HTPasswd.c +$ cc [-.Implementation]HTGroup.c +$ cc [-.Implementation]HTACL.c +$ cc [-.Implementation]HTAuth.c +$ cc [-.Implementation]HTAAProt.c +$ cc [-.Implementation]HTAssoc.c +$ cc [-.Implementation]HTLex.c +$ cc [-.Implementation]HTUU.c +$ cc [-.Implementation]HTVMSUtils.c +$ cc [-.Implementation]getpass.c +$ cc [-.Implementation]getline.c +$ cc [-.Implementation]crypt.c +$ cc [-.Implementation]crypt_util.c +$ cc [-.Implementation]HTWAIS.c +$ cc [-.Implementation]HTVMS_WaisUI.c +$ cc [-.Implementation]HTVMS_WaisProt.c +$! +$ If f$search("[-.Implementation]WWWLib_''transport'.olb") .eqs. "" Then - + LIBRARY/Create [-.Implementation]WWWLib_'transport'.olb +$ LIBRARY/Replace [-.Implementation]WWWLib_'transport'.olb *.obj +$ Delete/nolog/noconf *.obj;* +$! +$ v1 = 'f$verify(0)' +$ CLEANUP: +$ v1 = f$verify(v) +$exit diff --git a/gnu/usr.bin/lynx/WWW/Makefile b/gnu/usr.bin/lynx/WWW/Makefile new file mode 100644 index 00000000000..41a90056fb3 --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Makefile @@ -0,0 +1,9 @@ +# Make basic WWW distribution +# +# See the README and the documentation on the web. +# When you have done BUILD you will have www so you will be able to +# read the documentation online. +# +all : + BUILD + diff --git a/gnu/usr.bin/lynx/WWW/README.txt b/gnu/usr.bin/lynx/WWW/README.txt new file mode 100644 index 00000000000..ad5d8bee56d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/README.txt @@ -0,0 +1,208 @@ + Read Me + WORLDWIDEWEB CERN-DISTRIBUTED CODE + + See the CERN copyright[1] . This is the README file which you get when you + unwrap one of our tar files. These files contain information about + hypertext, hypertext systems, and the WorldWideWeb project. If you have + taken this with a .tar file, you will have only a subset of the files. + + THIS FILE IS A VERY ABRIDGED VERSION OF THE INFORMATION AVAILABLE ON THE + WEB. IF IN DOUBT, READ THE WEB DIRECTLY. If you have not got ANY browser + installed yet, do this by telnet to info.cern.ch (no username or password). + + Files from info.cern.ch are also mirrored on ftp.ripe.net. + +Archive Directory structure + + Under /pub/www[2] , besides this README file, you'll find bin[3] , src[4] + and doc[5] directories. The main archives are as follows: + + bin/xxx/bbbb Executable binaries of program bbbb for system xxx. + Check what's there before you bother compiling. (Note + HP700/8800 series is "snake") + + bin/next/WorldWideWeb_v.vv.tar.Z + The Hypertext Browser/editor for the NeXT -- binary. + + src/WWWLibrary_v.vv.tar.Z + The W3 Library. All source, and Makefiles for + selected systems. + + src/WWWLineMode_v.vv.tar.Z + The Line mode browser - all source, and Makefiles for + selected systems. Requires the Library[6] . + + src/WWWDaemon_v.vv.tar.Z + The HTTP daemon, and WWW-WAIS gateway programs. + Source. Requires the Library. + + src/WWWMailRobot_v.vv.tar.Z + The Mail Robot. + + doc/WWWBook.tar.Z A snapshot of our internal documentation - we prefer + you to access this on line -- see warnings below. + +Basic WWW software installation from source + + This applies to the line mode client and the server. Below, $prod means + LineMode or Daemon depending on which you are building. + + GENERATED DIRECTORY STRUCTURE + + The tar files are all designed to be unwrapped in the same (this) directory. + They create different parts of a common directory tree under that directory. + There may be some duplication. They also generate a few files in this + directory: README.*, Copyright.*, and some installation instructions (.txt). + + The directory structure is, for product $prod and machine $WWW_MACH + + WWW/$prod/Implementation + Source files for a given product + + WWW/$prod/Implementation/CommonMakefile + The machine-independent parts of the Makefile for this + product + + + Read Me (65/66) + WWW/$prod/$WWW_MACH/ Area for compiling for a given system + + WWW/All/$WWW_MACH/Makefile.include + The machine-dependent parts of the makefile for any + product + + WWW/All/Implementation/Makefile.product + A makefile which includes both parts above and so can + be used from any product, any machine. + + COMPILATION ON ALREADY SUPPORTED PLATFORMS + + You must get the WWWLibrary tar file as well as the products you want and + unwrap them all from the same directory. + + You must define the environmant variable WWW_MACH to be the architecure of + your machine (sun4, decstation, rs6000, sgi, snake, etc) + + In directory WWW, type BUILD. + + COMPILATION ON NEW PLATFORMS + + If your machine is not on the list: + + Make up a new subdirectory of that name under WWW/$prod and WWW/All, + copying the contents of a basically similar architecture's directory. + + Check the WWW/All/$WWW_MACH/Makefile.include for suitable directory and + flag definitions. + + Check the file tcp.h for the system-specific include file coordinates, + etc. + + Send any changes you have to make back to www-request@info.cern.ch for + inclusion into future releases. + + Once you have this set up, type BUILD. + +NeXTStep Browser/Editor + + The browser for the NeXT is those files contained in the application + directory WWW/Next/Implementation/WorldWideWeb.app and is compiled. When you + install the app, you may want to configure the default page, + WorldWideWeb.app/default.html. These must point to some useful information! + You should keep it up to date with pointers to info on your site and + elsewhere. If you use the CERN home page note there is a link at the bottom + to the master copy on our server. You should set up the address of your + local news server with + + dwrite WorldWideWeb NewsHost news + + replacing the last word with the actual address of your news host. See + Installation instructions[7] . + +Line Mode browser + + Binaries of this for some systems are available in /pub/www/bin/ . The + binaries can be picked up, set executable, and run immediately. + + If there is no binary, see "Installation from source" above. + + (See Installation notes[8] ). Do the same thing (in the same directory) to + the WWWLibrary_v.cc.tar.Z file to get the common library. + + + Read Me (65/130) + You will have an ASCII printable manual in the file + WWW/LineMode/Defaults/line-mode-guide.txt which you can print out at this + stage. This is a frozen copy of some of the online documentation. + + Whe you install the browser, you may configure a default page. This is + /usr/local/lib/WWW/default.html for the line mode browser. This must point + to some useful information! You should keep it up to date with pointers to + info on your site and elsewhere. If you use the CERN home page note there is + a link at the bottom to the master copy on our server. + + Some basic documentation on the browser is delivered with the home page in + the directory WWW/LineMode/Defaults. A separate tar file of that directory + (WWWLineModeDefaults.tar.Z) is available if you just want to update that. + + The rest of the documentation is in hypertext, and so wil be readable most + easily with a browser. We suggest that after installing the browser, you + browse through the basic documentation so that you are aware of the options + and customisation possibilities for example. + +Server + + The server can be run very simply under the internet daemon, to export a + file directory tree as a browsable hypertext tree. Binaries are avilable + for some platofrms, otherwise follow instructions above for compiling and + then go on to " Installing the basic W3 server[9] ". + +XMosaic + + XMosaic is an X11/Motif W3 browser. + + The sources and binaries are distributed separately from + FTP.NCSA.UIUC.EDU[10] , in /Web/xmosaic[11] . Binaries are available for + some platforms. If you have to build from source, check the README in the + distribution. + + The binaries can be picked up, uncompressed, set "executable" and run + immediately. + +Viola browser for X11 + + Viola is an X11 application for reading global hypertext. If a binary is + available from your machine, in /pub/www/bin/.../viola*, then take that and + also the Viola "apps" tar file which contains the scripts you will need. + + To generate this from source, you will need both the W3 library and the + Viola source files. There is an Imakefile with the viola source directory. + You will need to generate the XPA and XPM libraries and the W3 library + befere you make viola itself. + +Documentation + + In the /pub/www/doc[12] directory are a number articles, preprints and + guides on the web. + + See the online WWW bibliography[13] for a list of these and other articles, + books, etc. and also the list of WWW Manuals[14] available in text and + postscript form. + +General + + Your comments will of course be most appreciated, on code, or information on + the web which is out of date or misleading. If you write your own hypertext + and make it available by anonymous ftp or using a server, tell us and we'll + put some pointers to it in ours. Thus spreads the web... + + Read Me (66/195) + Tim Berners-Lee + + WorldWideWeb project + + CERN, 1211 Geneva 23, Switzerland + + Tel: +41 22 767 3755; Fax: +41 22 767 7155; email: timbl@info.cern.ch + + |