summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/lynx/WWW
diff options
context:
space:
mode:
authorMats O Jansson <maja@cvs.openbsd.org>1998-03-11 17:48:09 +0000
committerMats O Jansson <maja@cvs.openbsd.org>1998-03-11 17:48:09 +0000
commit69de3a9e357327c17caa3b7bb058035e263573bc (patch)
treef6260f228c4d949b174128d017a7e323c7122f32 /gnu/usr.bin/lynx/WWW
parentb81973f175db7d3f4c763069b191dd57f4bd83d3 (diff)
Lynx 2.8
Diffstat (limited to 'gnu/usr.bin/lynx/WWW')
-rw-r--r--gnu/usr.bin/lynx/WWW/BUILD42
-rw-r--r--gnu/usr.bin/lynx/WWW/Copyright.txt22
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/BSDI_Makefile405
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/CommonMakefile373
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c1309
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.h150
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.c210
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAFile.h126
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.c598
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAProt.h231
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.c686
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAServ.h148
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.c621
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAAUtil.h361
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.c221
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTACL.h109
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.c1370
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAccess.h325
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.c126
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAlert.h128
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.c1325
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAnchor.h447
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.c87
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAssoc.h44
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.c169
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAtom.h49
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.c210
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTAuth.h66
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.c720
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTBTree.h104
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTCJK.h110
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.c204
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTChunk.h171
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.c94
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTDOS.h32
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.c3399
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFTP.h77
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.c358
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFWriter.h37
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.c2426
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFile.h210
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.c441
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFinger.h24
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.c1093
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTFormat.h441
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.c2004
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTGopher.h27
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.c772
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTGroup.h189
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.c157
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTHistory.h112
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.c176
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTInit.h23
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.c142
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTLex.h64
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.c314
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTList.h146
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.c2599
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMIME.h87
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.c1674
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLDTD.h1006
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.c544
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTMLGen.h32
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.c2824
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTNews.h46
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.c901
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTParse.h167
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.c301
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTPasswd.h129
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.c665
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTPlain.h21
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.c418
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTRules.h165
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTStream.h61
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.c344
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTString.h63
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.c363
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTStyle.h182
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.c1142
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTCP.h120
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c1854
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.h33
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.c590
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTelnet.h24
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.c207
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTUU.h29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTUtils.h447
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.c1264
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMSUtils.h116
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.c2501
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisProt.h376
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.c2448
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTVMS_WaisUI.h674
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.c1093
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWAIS.h44
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.c473
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWSRC.h48
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.c189
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTWriter.h28
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HText.h265
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/LYLeaks.h183
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/LYexit.h58
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.c3576
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/SGML.h272
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/UCAux.h70
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/UCDefs.h86
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/UCMap.h48
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/Version.make1
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/crypt.c129
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/crypt_util.c981
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/entities.h1084
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/getline.c74
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/getpass.c64
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/patchlevel.h24
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/tcp.h681
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/ufc-crypt.h108
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/apollo_m68k/Makefile38
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/clix/Makefile30
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/convex/Makefile32
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/decstation/Makefile23
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/djgpp/CommonMakefile371
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/djgpp/makefile30
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/duns/Makefile489
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/freebsd/Makefile27
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/isc/Makefile30
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/mips/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/netbsd/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/next/Makefile40
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/osf/Makefile23
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/ptx/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/rs6000/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/sco/Makefile33
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/sgi/Makefile30
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/snake/Makefile33
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/solaris2/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/sun3/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/sun4/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/svr4/Makefile29
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/umaxv-m88k/Makefile30
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/unix/makefile.in62
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/unix_x/Makefile491
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/vax_ultrix/Makefile33
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/vms/COPYING.LIB481
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/vms/descrip.mms255
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/vms/libmake.com201
-rw-r--r--gnu/usr.bin/lynx/WWW/Makefile9
-rw-r--r--gnu/usr.bin/lynx/WWW/README.txt208
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, "&lt;");
+ l++;
+ i += 4;
+ buf[i] = '\0';
+ } else if (*l == '>') {
+ strcat(buf, "&gt;");
+ 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, "&lt;");
+ l++;
+ i += 4;
+ buf[i] = '\0';
+ } else if (*l == '>') {
+ strcat(buf, "&gt;");
+ 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: /* &#xA0; */
+ HTMLGen_put_character(me, 'A');
+ HTMLGen_put_character(me, '0');
+ break;
+ case HT_EM_SPACE: /* &#x2003; */
+ 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: /* &#xAD; */
+ 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, "&#34;");
+ }
+ }
+ 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,&#127; raw. */
+PUBLIC BOOL HTPassHighCtrlNum = FALSE; /* Pass &#128;-&#159; 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 &#153; 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
+
+