*** empty log message *** v_2_9_3
authoroes <oes@users.sourceforge.net>
Tue, 15 May 2001 13:59:57 +0000 (13:59 +0000)
committeroes <oes@users.sourceforge.net>
Tue, 15 May 2001 13:59:57 +0000 (13:59 +0000)
91 files changed:
Junkbuster Status.URL [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
aclfile [new file with mode: 0644]
amiga.c [new file with mode: 0644]
amiga.h [new file with mode: 0644]
blocklist [new file with mode: 0644]
config [new file with mode: 0644]
config.h [new file with mode: 0644]
config.h.in [new file with mode: 0644]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
cookiefile [new file with mode: 0644]
cygwin.h [new file with mode: 0644]
doc/USER_DOC_IS_WIDELY_OBSOLETED [new file with mode: 0644]
doc/changes.txt [new file with mode: 0644]
doc/gpl.html [new file with mode: 0644]
doc/ijbfaq.html [new file with mode: 0644]
doc/ijbman.html [new file with mode: 0644]
encode.c [new file with mode: 0644]
encode.h [new file with mode: 0644]
errlog.c [new file with mode: 0644]
errlog.h [new file with mode: 0644]
filters.c [new file with mode: 0644]
filters.h [new file with mode: 0644]
forward [new file with mode: 0644]
gateway.c [new file with mode: 0644]
gateway.h [new file with mode: 0644]
icons/denyrule.ico [new file with mode: 0644]
icons/ico00001.ico [new file with mode: 0644]
icons/ico00002.ico [new file with mode: 0644]
icons/ico00003.ico [new file with mode: 0644]
icons/ico00004.ico [new file with mode: 0644]
icons/ico00005.ico [new file with mode: 0644]
icons/ico00006.ico [new file with mode: 0644]
icons/ico00007.ico [new file with mode: 0644]
icons/ico00008.ico [new file with mode: 0644]
icons/icon1.ico [new file with mode: 0644]
icons/idle.ico [new file with mode: 0644]
icons/junkbust.ico [new file with mode: 0644]
imagelist [new file with mode: 0644]
jbsockets.c [new file with mode: 0644]
jbsockets.h [new file with mode: 0644]
jcc.c [new file with mode: 0644]
jcc.h [new file with mode: 0644]
junkbstr.txt [new file with mode: 0644]
junkbuster.1 [new file with mode: 0644]
junkbuster.init [new file with mode: 0644]
junkbuster.logrotate [new file with mode: 0644]
junkbuster.monthly [new file with mode: 0644]
junkbuster.weekly [new file with mode: 0644]
killpopup.c [new file with mode: 0644]
killpopup.h [new file with mode: 0644]
loadcfg.c [new file with mode: 0644]
loadcfg.h [new file with mode: 0644]
loaders.c [new file with mode: 0644]
loaders.h [new file with mode: 0644]
miscutil.c [new file with mode: 0644]
miscutil.h [new file with mode: 0644]
parsers.c [new file with mode: 0644]
parsers.h [new file with mode: 0644]
pcre/chartables.c [new file with mode: 0644]
pcre/config.h [new file with mode: 0644]
pcre/ltmain.sh [new file with mode: 0644]
pcre/pcre.c [new file with mode: 0644]
pcre/pcre.h [new file with mode: 0644]
pcre/pcre.in [new file with mode: 0644]
pcre/pcreposix.c [new file with mode: 0644]
pcrs.c [new file with mode: 0644]
pcrs.h [new file with mode: 0644]
popup [new file with mode: 0644]
project.h [new file with mode: 0644]
re_filterfile [new file with mode: 0644]
showargs.c [new file with mode: 0644]
showargs.h [new file with mode: 0644]
ssplit.c [new file with mode: 0644]
ssplit.h [new file with mode: 0644]
trust [new file with mode: 0644]
vc_junkbuster.dsp [new file with mode: 0644]
vc_junkbuster.dsw [new file with mode: 0644]
w32.aps [new file with mode: 0644]
w32.rc [new file with mode: 0644]
w32log.c [new file with mode: 0644]
w32log.h [new file with mode: 0644]
w32res.h [new file with mode: 0644]
w32rulesdlg.c [new file with mode: 0644]
w32rulesdlg.h [new file with mode: 0644]
w32taskbar.c [new file with mode: 0644]
w32taskbar.h [new file with mode: 0644]
win32.c [new file with mode: 0644]
win32.h [new file with mode: 0644]

diff --git a/Junkbuster Status.URL b/Junkbuster Status.URL
new file mode 100644 (file)
index 0000000..6c95de6
Binary files /dev/null and b/Junkbuster Status.URL differ
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..8c670b8
--- /dev/null
@@ -0,0 +1,281 @@
+# Note:  Makefile is built automatically from Makefile.in
+#
+# $Id: Makefile.in,v 1.2 2001/05/13 22:04:51 administrator Exp $
+#
+# Written by and Copyright (C) 2001 the SourceForge
+# IJBSWA team.  http://ijbswa.sourceforge.net
+#
+# Based on the Internet Junkbuster originally written
+# by and Copyright (C) 1997 Anonymous Coders and 
+# Junkbusters Corporation.  http://www.junkbusters.com
+#
+# This program is free software; you can redistribute it 
+# and/or modify it under the terms of the GNU General
+# Public License as published by the Free Software
+# Foundation; either version 2 of the License, 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.
+#
+# The GNU General Public License should be included with
+# this file.  If not, you can view it at
+# http://www.gnu.org/copyleft/gpl.html
+# or write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# $Log: Makefile.in,v $
+#
+
+
+# define version (will be wired into the rpm.)
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_POINT = @VERSION_POINT@
+VERSION       = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_POINT)
+RPM_VERSION   = $(VERSION)
+
+# The version is currently specified in config.h, which is
+# written by "configure".
+#
+#VERSION_CFLAGS = -DVERSION_MAJOR=$(VERSION_MAJOR) \
+#                 -DVERSION_MINOR=$(VERSION_MINOR) \
+#                 -DVERSION_POINT=$(VERSION_POINT) \
+#                 -DVERSION="$(VERSION)"
+
+# Directories for "make install"
+DEST        = /etc/junkbuster
+SBIN_DEST   = @sbindir@
+MAN_DEST    = @mandir@
+
+# The flag "-mno-win32" can be used by Cygwin to emulate a un?x type install.
+# The flag "-mwindows -mno-cygwin" will cause Cygwin to use MingW32 for Win32 install.
+CYGWIN_FLAGS = @CYGWIN_FLAGS@
+
+# Need to define this in order to link PCRE statically under Win32
+# Also define under UNIX to use system PCRE headers.
+PCRE_WIN_FLAGS = @STATIC_PCRE_ONLY@-DSTATIC
+
+# Either/Or of these next two lines
+#DEBUG_CFLAGS = -g
+DEBUG_CFLAGS  = -O3
+
+# Solaris needs a special define:
+# FIXME: This is always commented out
+SOLARIS_FLAGS = @SOLARIS_ONLY@-D__EXTENSIONS__=1
+
+#  -DSTDC_HEADERS Now in config.h
+# Do we need  -DHAVE_STRING  ???
+CFLAGS = @CFLAGS@ @CPPFLAGS@ \
+         -D__MT__=1 -D__STDC__=1 $(SOLARIS_FLAGS) -DHAVE_STRING $(DEBUG_CFLAGS) \
+         -Ipcre $(CYGWIN_FLAGS) $(PCRE_WIN_FLAGS)
+
+PROGRAM = junkbuster@EXEEXT@
+CC      = gcc
+ECHO    = echo
+GZIP    = gzip
+INSTALL = cp -f
+LD      = gcc
+OBJEXT  = @OBJEXT@
+RM      = rm -f
+STRIP   = strip
+
+C_SRC  = encode.c errlog.c filters.c gateway.c jbsockets.c jcc.c \
+         killpopup.c loadcfg.c loaders.c miscutil.c parsers.c \
+         showargs.c ssplit.c
+         
+C_OBJS = $(C_SRC:.c=.$(OBJEXT))
+C_HDRS = $(C_SRC:.c=.h) project.h
+
+W32_SRC   = @WIN_ONLY@w32log.c w32rulesdlg.c w32taskbar.c win32.c
+W32_FILES = @WIN_ONLY@w32.res
+W32_OBJS  = @WIN_ONLY@$(W32_SRC:.c=.$(OBJEXT)) $(W32_FILES)
+W32_HDRS  = @WIN_ONLY@w32log.h w32res.h w32rulesdlg.h w32taskbar.h
+W32_LIB   = @WIN_ONLY@-lwsock32 -lcomctl32
+W32_INIS  = @WIN_ONLY@junkbstr.txt saclfile.txt sblock.txt scookie.txt  \
+            @WIN_ONLY@sforward.txt simage.txt spopup.txt strust.txt sregexp.txt
+
+PCRS_SRC     = @PCRS_ONLY@pcrs.c
+PCRS_OBJS    = $(PCRS_SRC:.c=.$(OBJEXT))
+PCRS_HDRS    = $(PCRS_SRC:.c=.h)
+
+PCRE_SRC     = @STATIC_PCRE_ONLY@pcre/get.c pcre/maketables.c pcre/study.c pcre/pcre.c
+PCRE_OBJS    = @STATIC_PCRE_ONLY@$(PCRE_SRC:.c=.$(OBJEXT))
+PCRE_HDRS    = @STATIC_PCRE_ONLY@pcre/config.h pcre/chartables.c pcre/internal.h pcre/pcre.h
+PCRE_LIB     = @LIBRARY_PCRE_ONLY@-lpcre
+
+# No REGEX:
+@NO_REGEX_ONLY@REGEX_SRC    =
+# Without PCRE:
+@GNU_REGEX_ONLY@REGEX_SRC    = gnu_regex.c
+# With PCRE:
+@PCRE_REGEX_ONLY@REGEX_SRC    = @STATIC_PCRE_ONLY@pcre/pcreposix.c
+
+REGEX_OBJS   = $(REGEX_SRC:.c=.$(OBJEXT))
+REGEX_HDRS   = $(REGEX_SRC:.c=.h)
+
+# Dependencies introduced by #include "project.h".
+PROJECT_H_DEPS = project.h $(REGEX_HDRS) $(PCRS_HDRS) @STATIC_PCRE_ONLY@pcre/pcre.h
+
+# Only need this on Solaris
+# FIXME: This is always commented out
+SOCKET_LIB   = @SOLARIS_ONLY@-lsocket -lnsl
+
+LIBS         = $(PCRE_LIB) $(W32_LIB) $(SOCKET_LIB)
+
+SRCS         = $(C_SRC)  $(W32_SRC)  $(PCRS_SRC)  $(PCRE_SRC)  $(REGEX_SRC)
+OBJS         = $(C_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS)
+HDRS         = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS)
+
+
+# -------------------------------------------------------------------------
+# Do not change anything below this line
+# And there should NOT be any targets above this line.
+# -------------------------------------------------------------------------
+LDFLAGS = $(DEBUG_CFLAGS) $(CYGWIN_FLAGS)
+
+
+all: $(PROGRAM)
+
+
+SUFFIX     = .txt:o
+.SUFFIXES  : .txt
+
+%.txt:
+       sed -e 's/$$//' < $< > $@
+
+inifiles: $(W32_INIS)
+
+junkbstr.txt: config
+       sed     -e 's!\(/etc/junkbuster\|.\)/blocklist!sblock.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/popup!spopup.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/cookiefile!scookie.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/forward!sforward.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/trust!strust.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/aclfile!sacl.txt!' \
+                       -e 's!\(/var/log/junkbuster\|.\)/jarfile!jar.log!' \
+                       -e 's!\(/var/log/junkbuster\|.\)/junkbuster\.log!junkbstr.log!' \
+                       -e 's!\(/etc/junkbuster\|.\)/imagelist!simage.txt!' \
+                       -e 's!\(/etc/junkbuster\|.\)/re_filterfile!sregexp.txt!' \
+                       -e 's!$$!!' \
+       < $< > $@
+
+saclfile.txt: aclfile
+sblock.txt: blocklist
+scookie.txt: cookiefile
+sforward.txt: forward
+simage.txt: imagelist
+spopup.txt: popup
+strust.txt: trust
+sregexp.txt: re_filterfile
+
+
+# -------------------------------------------------------------------------
+#
+# -------------------------------------------------------------------------
+rpm-dist:
+       @make clean
+# verify that i'm root needs to be done
+       cd .. && tar --exclude "ijb/CVS" -cvzf ijb.tar.gz ijb/
+# verify all version strings, FLAGS, etc. in the spec file
+       cat ../../SPECS/junkbuster.spec | sed 's/^Version:.*/Version: $(RPM_VERSION)/g' | sed 's/^Release:.*/Release: $(VERSION_POINT)/g' > /tmp/abc && cp -f /tmp/abc ../../SPECS/junkbuster.spec
+       cd ../../ && rpm -ba SPECS/junkbuster.spec
+       chmod -R a+r ../../RPMS
+       chmod -R a+r ../../SRPMS
+
+# -------------------------------------------------------------------------
+#
+# -------------------------------------------------------------------------
+win-dist:
+       $(ECHO) Not implemented.
+
+# -------------------------------------------------------------------------
+#
+# -------------------------------------------------------------------------
+tarball-dist:
+       @make clean
+       make $(PROGRAM) 
+#      remove all objects and create the tarball with the binary
+       cd .. && $(RM) ijb/a.out ijb/core ijb/*.$(OBJEXT) && tar --exclude "ijb/CVS" -cvzf ../ijb-distribution-$(VERSION).tar.gz ijb/
+       chmod a+r ../../ijb-distribution-$(VERSION).tar.gz
+       @$(ECHO) Tarball with binary created.
+
+# -------------------------------------------------------------------------
+#
+# -------------------------------------------------------------------------
+
+encode.@OBJEXT@:    encode.c    encode.h    config.h
+errlog.@OBJEXT@:    errlog.c    errlog.h    config.h $(PROJECT_H_DEPS) @WIN_ONLY@w32log.h
+filters.@OBJEXT@:   filters.c   filters.h   config.h $(PROJECT_H_DEPS) errlog.h encode.h gateway.h jbsockets.h jcc.h loadcfg.h parsers.h showargs.h ssplit.h @WIN_ONLY@win32.h 
+gateway.@OBJEXT@:   gateway.c   gateway.h   config.h $(PROJECT_H_DEPS) errlog.h jbsockets.h jcc.h loadcfg.h
+jbsockets.@OBJEXT@: jbsockets.c jbsockets.h config.h $(PROJECT_H_DEPS) filters.h
+jcc.@OBJEXT@:       jcc.c       jcc.h       config.h $(PROJECT_H_DEPS) errlog.h filters.h gateway.h jbsockets.h killpopup.h loadcfg.h loaders.h miscutil.h parsers.h showargs.h @WIN_ONLY@w32log.h win32.h
+killpopup.@OBJEXT@: killpopup.c killpopup.h config.h $(PROJECT_H_DEPS) jcc.h loadcfg.h
+loadcfg.@OBJEXT@:   loadcfg.c   loadcfg.h   config.h $(PROJECT_H_DEPS) errlog.h filters.h gateway.h jbsockets.h jcc.h killpopup.h loaders.h miscutil.h parsers.h showargs.h @WIN_ONLY@w32log.h win32.h
+loaders.@OBJEXT@:   loaders.c   loaders.h   config.h $(PROJECT_H_DEPS) errlog.h encode.h filters.h gateway.h jcc.h loadcfg.h miscutil.h parsers.h ssplit.h
+miscutil.@OBJEXT@:  miscutil.c  miscutil.h  config.h
+parsers.@OBJEXT@:   parsers.c   parsers.h   config.h $(PROJECT_H_DEPS) errlog.h encode.h filters.h jbsockets.h jcc.h loadcfg.h loaders.h miscutil.h showargs.h ssplit.h
+showargs.@OBJEXT@:  showargs.c  showargs.h  config.h $(PROJECT_H_DEPS) errlog.h encode.h gateway.h jcc.h loadcfg.h miscutil.h parsers.h
+ssplit.@OBJEXT@:    ssplit.c    ssplit.h    config.h miscutil.h
+
+# GNU regex
+gnu_regex.@OBJEXT@: gnu_regex.c gnu_regex.h config.h
+
+# PCRS
+pcrs.@OBJEXT@: pcrs.c pcre/pcre.h pcrs.h
+
+# PCRE
+pcre/get.@OBJEXT@:        pcre/get.c        pcre/config.h pcre/internal.h pcre/pcre.h
+pcre/maketables.@OBJEXT@: pcre/maketables.c pcre/config.h pcre/internal.h pcre/pcre.h
+pcre/pcre.@OBJEXT@:       pcre/pcre.c       pcre/config.h pcre/internal.h pcre/pcre.h pcre/chartables.c 
+pcre/pcreposix.@OBJEXT@:  pcre/pcreposix.c  pcre/config.h pcre/internal.h pcre/pcre.h pcre/pcreposix.h
+pcre/study.@OBJEXT@:      pcre/study.c      pcre/config.h pcre/internal.h pcre/pcre.h
+
+# An auxiliary program makes the PCRE default character table source
+
+pcre/chartables.c:   pcre/dftables
+               pcre/dftables >pcre/chartables.c
+
+pcre/dftables:       pcre/dftables.c pcre/maketables.c pcre/pcre.h pcre/internal.h pcre/config.h
+               $(CC) -o pcre/dftables $(CFLAGS) pcre/dftables.c
+
+# Win32
+w32log.@OBJEXT@: w32log.c errlog.h config.h jcc.h loadcfg.h miscutil.h pcre/pcre.h pcre/pcreposix.h pcrs.h project.h w32log.h w32rulesdlg.h w32taskbar.h win32.h
+w32rulesdlg.@OBJEXT@: w32rulesdlg.c config.h w32rulesdlg.h win32.h
+w32taskbar.@OBJEXT@: w32taskbar.c config.h w32log.h w32taskbar.h
+win32.@OBJEXT@: win32.c config.h jcc.h loadcfg.h pcre/pcre.h pcre/pcreposix.h pcrs.h project.h w32log.h win32.h
+
+w32.res: w32.rc w32res.h icons/denyrule.ico icons/ico00001.ico icons/ico00002.ico icons/ico00003.ico icons/ico00004.ico icons/ico00005.ico icons/ico00006.ico icons/ico00007.ico icons/ico00008.ico icons/icon1.ico icons/idle.ico icons/junkbust.ico config.h
+       windres -D__MINGW32__=0.2 -O coff -i $< -o $@
+
+
+$(PROGRAM): $(OBJS) $(W32_FILES)
+       $(LD) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS)
+
+clean:
+       $(RM) a.out core $(OBJS) $(W32_FILES) $(W32_INIS)
+
+clobber: clean
+       $(RM) $(PROGRAM) *.pdb *.lib *.exp TAGS junkbuster.log
+
+tags: $(SRCS) $(HDRS)
+       etags $(SRCS) $(HDRS)
+
+install: all
+       $(STRIP) $(PROGRAM)
+       $(INSTALL) $(PROGRAM) $(SBIN_DEST)
+       $(INSTALL) README README.TOO README.WIN README.re_filter README.cygwin $(DEST)
+       $(INSTALL) aclfile blocklist config cookiefile forward imagelist \
+               popup re_filterfile trust $(DEST)
+       # FIXME: On SuSE, these are not found.  Where do they go?
+       $(ECHO) junkbuster.logrotate junkbuster.monthly junkbuster.weekly
+       $(GZIP) -c junkbuster.1 > $(MAN_DEST)/junkbuster.1.gz
+       $(INSTALL) junkbuster.init /sbin/init.d/junkbuster
+
+
+## Local Variables:
+## tab-width: 3
+## end:
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..edf5c08
--- /dev/null
@@ -0,0 +1,178 @@
+#ifndef _CONFIG_H
+#define _CONFIG_H
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/acconfig.h,v $
+ *
+ * Purpose     :  This file should be the first thing included in every
+ *                .c file.  (Before even system headers).  It contains 
+ *                #define statements for various features.  It was
+ *                introduced because the compile command line started
+ *                getting ludicrously long with feature defines.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: acconfig.h,v $
+ *
+ *********************************************************************/
+\f
+@TOP@
+
+/*
+ * Version number - Major (X._._)
+ */
+#undef VERSION_MAJOR
+
+/*
+ * Version number - Minor (_.X._)
+ */
+#undef VERSION_MINOR
+
+/*
+ * Version number - Point (_._.X)
+ */
+#undef VERSION_POINT
+
+/*
+ * Version number, as a string
+ */
+#undef VERSION
+
+/*
+ * Regular expression matching for URLs.  (Highly recommended).  If this is 
+ * not defined then you can ony use prefix matching.
+ */
+#undef REGEX
+
+/*
+ * Allow JunkBuster to be "disabled" so it is just a normal non-blocking
+ * non-anonymizing proxy.  This is useful if you're trying to access a
+ * blocked or broken site - just change the setting in the config file
+ * and send a SIGHUP (UN*X), or use the handy "Disable" menu option (Windows
+ * GUI).
+ */
+#undef TOGGLE
+
+/*
+ * Enables arbitrary content modification regexps
+ */
+#undef PCRS
+
+/*
+ * If a stream is compressed via gzip (Netscape specific I think), then
+ * it cannot be modified with Perl regexps.  This forces it to be 
+ * uncompressed.
+ */
+#undef DENY_GZIP
+
+/*
+ * Enables statistics function.
+ */
+#undef STATISTICS
+
+/*
+ * Bypass filtering for 1 page only
+ */
+#undef FORCE_LOAD
+
+/*
+ * Split the show-proxy-args page into a page for each config file.
+ */
+#undef SPLIT_PROXY_ARGS
+
+/*
+ * Kills JavaScript popups - window.open, onunload, etc.
+ */
+#undef KILLPOPUPS
+
+/*
+ * Support for webDAV - e.g. so Microsoft Outlook can access HotMail e-mail
+ */
+#undef WEBDAV
+
+/*
+ * Detect image requests automatically for MSIE.  Will fall back to
+ * other image-detection methods (i.e. USE_IMAGE_LIST) for other
+ * browsers.
+ *
+ * It detects the following header pair as an image request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: * / *
+ *
+ * And the following as a HTML request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, * / *
+ *
+ * And no, I haven't got that backwards - IE is being wierd.
+ *
+ * Known limitations: 
+ * 1) If you press shift-reload on a blocked HTML page, you get
+ *    the image "blocked" page, not the HTML "blocked" page.
+ * 2) Once an image "blocked" page has been sent, viewing it 
+ *    in it's own browser window *should* bring up the HTML
+ *    "blocked" page, but it doesn't.  You need to clear the 
+ *    browser cache to get the HTML version again.
+ *
+ * These limitations are due to IE making inconsistent choices
+ * about which "Accept:" header to send.
+ */
+#undef DETECT_MSIE_IMAGES
+
+/*
+ * Use image list to detect images.
+ * If you do not define this then everything is treated as HTML.
+ *
+ * Whatever the setting of this value, DETECT_MSIE_IMAGES will 
+ * override it for people using Internet Explorer.
+ */
+#undef USE_IMAGE_LIST
+
+/*
+ * Allows the use of ACL files to control access to the proxy by IP address.
+ */
+#undef ACL_FILES
+
+/*
+ * Allows the use of trust files.
+ */
+#undef TRUST_FILES
+
+/*
+ * Allows the use of jar files to capture cookies.
+ */
+#undef JAR_FILES
+
+/*
+ * Use PCRE rather than GNU Regex
+ */
+#undef PCRE
+
+@BOTTOM@
+
+#endif /* _CONFIG_H */
diff --git a/aclfile b/aclfile
new file mode 100644 (file)
index 0000000..6a265a8
--- /dev/null
+++ b/aclfile
@@ -0,0 +1,102 @@
+#  Access Control List for the Internet Junkbuster 2.0
+#
+# Copyright 1997-8 Junkbusters Corp.  For distribution, modification and use
+# under the GNU General Public License. These files come with NO WARRANTY.
+# See http://www.junkbusters.com/ht/en/gpl.html or README file for details.
+#
+# Access controls are included at the request of some ISPs and systems
+# administrators, and are not usually needed by individual users.
+# Please note the warnings in the FAQ that this proxy is not
+# intended to be a substitute for a firewall or to encourage anyone
+# to defer addressing basic security weaknesses.
+# For details see http://www.junkbusters.com/ht/en/ijbman.html#aclfile
+
+# For this file to have any effect, the line beginning "aclfile"
+# must be commented in, with the name of this file following the word "aclfile"
+
+# If no access file is specified, the proxy talks to anyone that connects.
+# If an access file is specified, the proxy talks only to IP addresses
+# permitted somewhere in this file and not denied later in this file.
+#
+# Summary -- if using an ACL:
+#
+#  Client must have permission to receive service
+#  LAST match in ACL file wins
+#  Default behavior is to deny service
+#
+# Syntax for an entry in an Access Control List is:
+#
+# ACTION    SRC_ADDR[/SRC_MASKLEN]    [ DST_ADDR[/DST_MASKLEN] ]
+#
+# where the fields are
+#
+# ACTION      = "permit" | "deny"
+#
+# SRC_ADDR    = client hostname or dotted IP address
+# SRC_MASKLEN = number of bits in the subnet mask for the source
+#
+# DST_ADDR    = server or forwarder hostname or dotted IP address
+# DST_MASKLEN = number of bits in the subnet mask for the target
+#
+# field separator (FS) is whitespace (space or tab)
+#
+# IMPORTANT NOTE
+# ==============
+# If the junkbuster is using a forwarder or a gateway for a particular 
+# destination URL, the DST_ADDRR that is examined is the address of
+# the forwarder or the gateway and NOT the address of the ultimate target.
+# This is necessary because it may be impossible for the local
+# junkbuster to determine the address of the ultimate target
+# (that's often what gateways are used for).
+#
+# Here are a few examples to show how the ACL works:
+
+# localhost is OK --  no DST_ADDR implies that ALL destination addresses are OK
+# permit localhost
+
+# a silly example to illustrate:
+#
+# permit any host on the class-C subnet with junkbusters to go anywhere
+#
+# permit www.junkbusters.com/24
+#
+# except deny one particular IP address from using it at all
+#
+# deny      ident.junkbusters.com
+
+# another example
+#
+# You can specify an explicit network address and subnet mask.
+# Explicit addresses do not have to be resolved to be used.
+#
+# permit 207.153.200.0/24
+
+# a subnet mask of 0 matches anything, so the next line permits everyone.
+#
+# permit 0.0.0.0/0
+
+# Note:  you cannot say
+#
+# permit .org
+#
+# to allow all .org domains; every IP-address listed must resolve fully.
+
+# An ISP may want to provide a junkbuster that is accessible by "the world"
+# and yet restrict use of some of their private content to hosts on its
+# internal network (i.e. its own subscribers).  Say, for instance the
+# ISP owns the Class-B IP address block 123.124.0.0 (a 16 bit netmask).
+# This is how they could do it:
+
+# permit 0.0.0.0/0   0.0.0.0/0   # other clients can go anywhere 
+#                with the following exceptions:
+#
+# deny   0.0.0.0/0   123.124.0.0/16 # block all external requests for
+#                                         sites on the ISP's network
+#
+# permit 0.0.0.0/0   www.my_isp.com # except for the ISP's main web site
+#
+# permit 123.124.0.0/16 0.0.0.0/0   # the ISP's clients can go anywhere
+
+# Note that some hostnames may be listed with multiple IP addresses;
+# the primary value returned by gethostbyname() is used.
+#
diff --git a/amiga.c b/amiga.c
new file mode 100644 (file)
index 0000000..cd22898
--- /dev/null
+++ b/amiga.c
@@ -0,0 +1,234 @@
+const char amiga_rcs[] = "$Id: amiga.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/jcc.c,v $
+ *
+ * Purpose     :  Amiga-specific declarations.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jcc.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#ifdef AMIGA
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "amiga.h"
+
+chonst char amiga_h_rcs[] = AMIGA_H_VERSION;
+
+unsigned long __stack = 20*1024;
+/* static char ver[] = "$VER: junkbuster " __AMIGAVERSION__ " (" __AMIGADATE__ ")"; */
+struct Task *main_task = NULL;
+int childs = 0;
+
+void serve(struct client_state *csp);
+
+__saveds ULONG server_thread(void)
+{
+   struct client_state *local_csp;
+   struct UserData UserData;
+   struct Task *me=FindTask(NULL);
+
+   Wait(SIGF_SINGLE);
+   local_csp=(struct client_state *)(me->tc_UserData);
+   me->tc_UserData=&UserData;
+   SocketBase=(APTR)OpenLibrary("bsdsocket.library",3);
+   if(SocketBase)
+   {
+      SetErrnoPtr(&(UserData.eno),sizeof(int));
+      local_csp->cfd=ObtainSocket(local_csp->cfd, AF_INET, SOCK_STREAM, 0);
+      if(-1!=local_csp->cfd)
+      {
+         Signal(main_task,SIGF_SINGLE);
+         serve((struct client_state *) local_csp);
+      } else {
+         local_csp->active = 0;
+         Signal(main_task,SIGF_SINGLE);
+      }
+      CloseLibrary(SocketBase);
+   } else {
+      local_csp->active = 0;
+      Signal(main_task,SIGF_SINGLE);
+   }
+   childs--;
+   return 0;
+}
+
+void amiga_exit(void)
+{
+   if(SocketBase)
+   {
+      CloseLibrary(SocketBase);
+   }
+}
+
+static struct SignalSemaphore memsem;
+static struct SignalSemaphore *memsemptr = NULL;
+static struct UserData GlobalUserData;
+
+void InitAmiga(void)
+{
+   main_task = FindTask(NULL);
+   main_task->tc_UserData = &GlobalUserData;
+
+   if (((struct Library *)SysBase)->lib_Version < 39)
+   {
+      exit(RETURN_FAIL);
+   }
+
+   signal(SIGINT,SIG_IGN);
+   SocketBase = (APTR)OpenLibrary("bsdsocket.library",3);
+   if (!SocketBase)
+   {
+      fprintf(stderr, "Can't open bsdsocket.library V3+\n");
+      exit(RETURN_ERROR);
+   }
+   SetErrnoPtr(&(GlobalUserData.eno),sizeof(int));
+   InitSemaphore(&memsem);
+   memsemptr = &memsem;
+
+   atexit(amiga_exit);
+}
+
+#ifdef __GNUC__
+#ifdef libnix
+/* multitaskingsafe libnix replacements */
+static void *memPool=NULL;
+
+void *malloc (size_t s)
+{
+   ULONG *mem;
+   LONG size = s;
+
+   if (size<=0)
+   {
+      return NULL;
+   }
+   if (!memPool)
+   {
+      if (!(memPool=CreatePool(MEMF_ANY,32*1024,8*1024)))
+      {
+         return NULL;
+      }
+   }
+   size += sizeof(ULONG) + MEM_BLOCKMASK;
+   size &= ~MEM_BLOCKMASK;
+   if (memsemptr)
+   {
+      ObtainSemaphore(memsemptr);
+   }
+   if ((mem=AllocPooled(memPool,size)))
+   {
+      *mem++=size;
+   }
+   if (memsemptr)
+   {
+      ReleaseSemaphore(memsemptr);
+   }
+   return mem;
+}
+
+void free (void *m)
+{
+   ULONG *mem = m;
+
+   if(mem && memPool)
+   {
+      ULONG size=*--mem;
+
+      if (memsemptr)
+      {
+         ObtainSemaphore(memsemptr);
+      }
+      FreePooled(memPool,mem,size);
+      if (memsemptr)
+      {
+         ReleaseSemaphore(memsemptr);
+      }
+   }
+}
+
+void *realloc (void *old, size_t ns)
+{
+   void *new;
+   LONG osize, *o = old;
+   LONG nsize = ns;
+
+   if (!old)
+   {
+      return malloc(nsize);
+   }
+   osize = (*(o-1)) - sizeof(ULONG);
+   if (nsize <= osize)
+   {
+      return old;
+   }
+   if ((new = malloc(nsize)))
+   {
+      ULONG *n = new;
+
+      osize >>= 2;
+      while(osize--)
+      {
+         *n++ = *o++;
+      }
+      free(old);
+   }
+   return new;
+}
+
+void __memCleanUp (void)
+{
+   if (memsemptr)
+   {
+      ObtainSemaphore(memsemptr);
+   }
+   if (memPool)
+   {
+      DeletePool(memPool);
+   }
+   if (memsemptr)
+   {
+      ReleaseSemaphore(memsemptr);
+   }
+}
+
+#define ADD2LIST(a,b,c) asm(".stabs \"_" #b "\"," #c ",0,0,_" #a )
+#define ADD2EXIT(a,pri) ADD2LIST(a,__EXIT_LIST__,22); \
+                        asm(".stabs \"___EXIT_LIST__\",20,0,0," #pri "+128")
+ADD2EXIT(__memCleanUp,-50);
+#elif !defined(ixemul)
+#error No libnix and no ixemul!?
+#endif /* libnix */
+#else
+#error Only GCC is supported, multitasking safe malloc/free required.
+#endif /* __GNUC__ */
+
+#endif /* def AMIGA */
diff --git a/amiga.h b/amiga.h
new file mode 100644 (file)
index 0000000..6f132d0
--- /dev/null
+++ b/amiga.h
@@ -0,0 +1,88 @@
+#ifdef AMIGA
+#ifndef _AMIGA_H
+#define _AMIGA_H
+#define AMIGA_H_VERSION "$Id: amiga.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/amiga.h,v $
+ *
+ * Purpose     :  Amiga-specific declarations.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jcc.h,v $
+ *
+ *********************************************************************/
+\f
+
+#define _KERNEL
+#include <sys/socket.h>
+#undef _KERNEL
+
+#define __NOLIBBASE__
+#include <proto/socket.h>
+#undef __NOLIBBASE__
+
+#include <proto/exec.h>
+#include <exec/tasks.h>
+#include <proto/dos.h>
+#include <dos/dostags.h>
+
+struct UserData
+{
+       struct Library *sb;
+       int eno;
+};
+
+#define SocketBase ((struct Library *)(((struct UserData *)(FindTask(NULL)->tc_UserData))->sb))
+#define errno (((struct UserData *)(FindTask(NULL)->tc_UserData))->eno)
+#define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,NULL)
+#define inet_ntoa(x) Inet_NtoA(x.s_addr)
+
+extern int childs;
+extern struct Task *main_task;
+
+void InitAmiga(void);
+void amiga_exit(void);
+void __memCleanUp(void);
+__saveds ULONG server_thread(void);
+
+#define exit(x)\
+{\
+   if(main_task)\
+   {\
+      if(main_task == FindTask(NULL))\
+      {\
+         while(childs) Delay(10*TICKS_PER_SECOND); exit(x);\
+      } else {\
+         CloseLibrary(SocketBase);\
+         childs--;\
+         RemTask(NULL);\
+      }\
+   }\
+}
+
+#define EINTR 0
+
+#endif /* ndef _AMIGA_H */
+#endif /* def AMIGA */
diff --git a/blocklist b/blocklist
new file mode 100644 (file)
index 0000000..7b48f3a
--- /dev/null
+++ b/blocklist
@@ -0,0 +1,1060 @@
+#
+# This is /etc/junkbuster/blocklist which was put here by a junkbuster rpm
+#
+# $Id: blocklist,v 1.3 2000/09/17 07:29:18 swa Exp $
+#
+# Last modified on Mon Sep 25 20:41:50 2000 (CEST)
+#
+# --------------------------------------------------------------------------
+#
+# Newest version is always available from 
+#
+#          http://www.waldherr.org/blocklist 
+#
+# Read http://www.waldherr.org/junkbuster/update.shtml on how to keep
+# this file up-to-date.
+#
+# This list is Copyright (c) Stefan Waldherr <stefan@waldherr.org>.
+#
+# No distribution of this list without acknowledgement of the author(s). 
+# No selling of thist list without prior written agreement.
+#
+# --------------------------------------------------------------------------
+#
+# Contributors are listed in the Hall Of Fame at
+#
+#        http://www.waldherr.org/junkbuster/hof.shtml
+#
+#  PS: I know that there are a ton of redundant regexps in this 
+#      file, but I haven't had time to fix them. Any help 
+#      appreciated.
+#
+# --------------------------------------------------------------------------
+#
+# For more detail, see http://www.junkbusters.com/ht/en/ijbfaq.html#blocking
+#
+# --------------------------------------------------------------------------
+#
+# Empty lines and lines beginning with a `#' are ignored.
+# The following line should be included to block use of telnet (port 23)
+:23
+
+# --------------------------------------------------------------------------
+#
+# generic paths
+#
+# --------------------------------------------------------------------------
+
+/*.*/(.*[-_.])?ads?[0-9]?(/|[-_.].*|\.(gif|jpe?g))
+/*.*/(.*[-_.])?count(er)?(\.cgi|\.dll|\.exe|[?/])
+/*.*/(ng)?adclient\.cgi
+/*.*/(plain|live|rotate)[-_.]?ads?/
+
+/*.*/(sponsor)s?[0-9]?/
+###/*.*/(sponsor|banner)s?[0-9]?/
+###/*.*/.*banner([-_]?[a-z0-9]+)?\.(gif|jpg)
+
+/*.*/_?(plain|live)?ads?(-banners)?/
+/*.*/abanners/
+/*.*/ad(sdna_image|gifs?)/
+/*.*/ad(server|stream|juggler)\.(cgi|pl|dll|exe)
+/*.*/adbanners/
+/*.*/adserver
+/*.*/adstream\.cgi
+/*.*/adv((er)?ts?|ertis(ing|ements?))?/
+/*.*/anzei(gen)?/?
+/*.*/ban[-_]cgi/
+/*.*/banner_?ads/
+/*.*/banner_?anzeigen
+/*.*/bannerimage/
+/*.*/banners?/
+/*.*/banners?\.cgi/
+/*.*/cgi-bin/centralad/getimage
+/*.*/images/addver\.gif
+/*.*/images/advert\.gif
+/*.*/images/marketing/.*\.(gif|jpe?g)
+/*.*/place-ads
+/*.*/popupads/
+/*.*/promobar.*
+/*.*/publicite/
+/*.*/randomads/.*\.(gif|jpe?g)
+/*.*/reklama/.*\.(gif|jpe?g)
+/*.*/reklame/.*\.(gif|jpe?g)
+/*.*/reklaam/.*\.(gif|jpe?g)
+/*.*/siteads/
+/*.*/sponsor.*\.gif
+/*.*/sponsors?[0-9]?/
+/*.*/ucbandeimg/
+/*.*/werb\..*
+/*.*/werbebanner/
+/*.*/werbung/.*\.(gif|jpe?g)
+/.*/adv\.      # www.telegraaf.nl
+/.*/advert[0-9]+\.jpg
+/.*bann\.gif
+/Media/Images/Adds/
+/_banner/
+/ad_images/
+/adgenius/
+/adimages/
+/*.*/ads/
+/*.*/ads\\
+/viewad/
+/adserve/
+/adverts/
+/annonser?/
+/bando/
+/bannerad/
+/bannerfarm/
+/bin/getimage.cgi/...\?AD
+/bin/nph-oma.count/ct/default.shtml
+/bin/nph-oma.count/ix/default.html
+/cgi-bin/getimage.cgi/....\?GROUP=
+/cgi-bin/nph-load
+/cgi-bin/webad.dll/ad
+/cwmail/acc\.gif
+/cwmail/amzn-bm1\.gif
+/db_area/banrgifs/
+/gif/teasere/
+/grafikk/annonse/
+/graphics/defaultAd/
+/grf/annonif
+/htmlad/
+/image\.ng/AdType
+/image\.ng/transactionID
+/images/.*/.*_anim\.gif # alvin brattli
+/ip_img/.*\.(gif|jpe?g)
+/marketpl*/
+/minibanners/
+/netscapeworld/nw-ad/
+/promotions/houseads/
+/rotads/ 
+/rotateads/
+/rotations/ 
+/torget/jobline/.*\.gif
+/viewad/
+/werbung/
+/worldnet/ad\.cgi
+/zhp/auktion/img/
+/cgi-bin/nph-adclick.exe/
+/*.*/Image/BannerAdvertising/
+/*.*/ad-bin/
+/*.*/adlib/server\.cgi
+/*.*/gsa_bs/gsa_bs.cmdl
+/autoads/
+/anz/pics/
+
+# for our finnish friends, by Kai Puolamaki <Kai.Puolamaki@iki.fi>
+/*.*/mainos/*.*/.*\.gif
+/*.*/mainos/*.*/.*\.jpe?g
+
+# more from a finnish friend Petri Haapio <pha@iki.fi>
+cgi.tietovalta.fi
+keltaisetsivut.fi/web/img/\.*gif
+haku.net/pics/pana\.*gif
+www.fi/guvat/\.*gif
+/*.*/(.*[-_.].*)?maino(kset|nta|s).*(/|\.(gif|html?|jpe?g|png))
+/*.*/(ilm(oitus)?|kampanja)(hallinta|kuvat?)(/|\.(gif|html?|jpe?g|png))
+
+# and even more from a finnish friend Hannu Napari <Hannu.Napari@hut.fi>
+194.251.243.50/cgi-bin/banner
+
+www.dime.net/ad
+www.iltalehti.fi/ad
+www.iltalehti.fi/ilmkuvat
+www.mtv3.fi/mainoskuvat
+
+# <jwz@jwz.org>
+/*.*/adfinity
+/*.*/[?]adserv
+/*.*/bizgrphx/
+/*.*/smallad2\.gif
+/*.*/ana2ad\.gif
+/*.*/adimg/
+/*.*/.*counter\.pl
+/*.*/spin_html/
+/*.*/images/topics/topicgimp\.gif
+discovery.com/.*banner_id
+/*.*/.*bannr\.gif
+cruel.com/images/
+idrink.com/frm_bottom.htm
+/*.*/.*pb_ihtml\.gif
+/*.*/ph-ad.*\.focalink\.com
+/cgi-bin/adjuggler
+
+/we_ba/ # hausfrauenseite.de *bwhahahaaaaa*
+
+# ms sucks !
+/.*(ms)?backoff(ice)?.*\.(gif|jpe?g)
+/.*(/ie4|/ie3|msie|sqlbans|powrbybo|activex|backoffice|explorer|netnow|getpoint|ntbutton|hmlink).*\.(gif|jpe?g)
+/.*activex.*(gif|jpe?g)
+/.*explorer?.(gif|jpe?g)
+/.*freeie\.(gif|jpe?g)
+/.*/ie_?(buttonlogo|static?|anim.*)?\.(gif|jpe?g)
+/.*ie_sm\.(gif|jpe?g)
+/.*msie(30)?\.(gif|jpe?g)
+/.*msnlogo\.(gif|jpe?g)
+/.*office97_ad1\.(gif|jpe?g)
+/.*pbbobansm\.(gif|jpe?g)
+/.*powrbybo\.(gif|jpe?g)
+/.*sqlbans\.(gif|jpe?g)
+/.*exc_ms\.gif
+/.*ie4get_animated\.gif
+/.*ie4_animated\.gif
+/.*n_iemap\.gif
+/.*ieget\.gif
+/.*logo_msnhm_*
+/.*mcsp2\.gif
+/.*msn2\.gif
+/.*add_active\.gif
+/.*n_msnmap\.gif
+/.*Ad00\.gif
+/.*s_msn\.gif
+/.*addchannel\.gif
+/.*adddesktop\.gif
+/.*/ns4\.gif
+/.*/v3sban\.gif
+/.*/?FPCreated\.gif
+/.*/opera35\.gif
+/.*/opera13\.gif
+/.*/opera_b\.gif
+/.*/ie_horiz\.gif
+/.*/ie_logo\.gif
+
+# ... and even more!
+/.*/favicon\.ico
+
+# generally useless information and promo stuff (commented out)
+#/*.*/(counter|getpcbutton|BuiltByNOF|netscape|hotmail|vcr(rated)?|rsaci(rated)?|freeloader|cache_now(_anim)?|apache_pb|now_(anim_)?button|ie_?(buttonlogo|static?|.*ani.*)?)\.(gif|jpe?g)
+
+/*.*/images/na/us/brand/
+/*.*/advantage\.(gif|jpg)
+/*.*/advanbar\.(gif|jpg)
+/*.*/advanbtn\.(gif|jpg)
+/*.*/biznetsmall\.(gif|jpg)
+/*.*/utopiad\.(gif|jpg)
+/*.*/epipo\.(gif|jpg)
+/*.*/amazon([a-zA-Z0-9]+)\.(gif|jpg)
+/*.*/bnlogo.(gif|jpg)
+/*.*/buynow([a-zA-Z0-9]+)\.(gif|jpg)
+
+/p/d/publicid
+
+
+# for the dutch folks by a dutch friend gertjan@west.nl
+/*.*/Advertenties/
+/.*./Adverteerders/
+netdirect.nl/nd_servlet/___
+
+# --------------------------------------------------------------------------
+#
+# specific servers
+#
+# --------------------------------------------------------------------------
+
+# the next two lines work 
+12.16.1.10/web_GIF
+12.16.1.10/~web_ani
+193.158.37.3/cgi-bin/impact
+193.210.156.114
+193.98.1.160/img
+194.221.183.222/mailsentlu
+194.221.183.223
+194.221.183.224
+194.221.183.225
+194.221.183.226
+194.221.183.227
+194.231.79.38
+195.124.124.56
+195.27.70.69
+195.30.94.21
+195.63.104.222//inbox
+195.63.104.222//log    # www.weltbild.de
+195.63.104.222//meld
+195.63.104.222//menu
+195.63.104.222/folderlu
+195.63.104.222/folderru
+195.63.104.222/inbox
+195.63.104.222/loginlu
+195.63.104.222/loginmu
+195.63.104.222/loginru
+195.63.104.222/logoutlu
+195.63.104.222/logoutmu
+195.63.104.222/logoutru
+195.63.104.61//inbox
+195.63.104.61//log     # www.weltbild.de
+195.63.104.61//meld
+195.63.104.61//menu
+195.63.104.61/inbox
+195.63.104.61/loginlu
+195.63.104.61/loginmu
+195.63.104.61/loginru
+195.63.104.61/logoutlu
+195.63.104.61/logoutmu
+195.63.104.61/logoutru
+199.78.52.10
+1st-fuss.com
+204.253.46.71:1977
+204.94.67.40/wc/
+205.153.208.93
+205.216.163.62
+205.217.103.58:1977
+206.165.5.162/images/gcanim\.gif
+206.221.254.181:80
+206.50.219.33
+207.137.96.35
+207.159.129.131/abacus
+207.159.135.72
+207.82.250.9
+207.87.15.234
+207.87.27.10/tool/includes/gifs/
+208.156.39.142
+208.156.39.144
+208.156.60.230
+208.156.60.234
+208.156.60.235
+209.1.112.252/adgraph/
+209.1.135.142:1971
+209.1.135.144:1971
+209.132.97.164/IMG/
+209.185.222.45
+209.185.222.60
+209.185.253.199
+209.207.224.220/servfu.pl 
+209.207.224.222/servfu.pl
+209.239.37.214/cgi-pilotfaq/getimage\.cgi
+209.297.224.220
+209.75.21.6
+209.85.89.183/cgi-bin/cycle\?host
+212.63.155.122/(banner|concret|softwareclub)
+216.15.157.34
+216.27.61.150
+216.49.10.236/web1000/
+247media.com
+62.144.115.12/dk/
+ICDirect.com/cgi-bin
+Shannon.Austria.Eu.net/\.cgi/
+WebSiteSponsor.de
+207.181.220.145
+213.165.64.42
+
+#
+# generic hosts (probably most effective)
+#
+ad*.*.*
+ad*.*.*.*
+*.ads.*.*
+banner*.*.*
+banner*.*.*.*
+
+*.admaximize.com
+*.imgis.com
+/*.*/*preferences.com*
+1ad.prolinks.de
+adwisdom.com
+akamaitech.net/.*/Banners/
+altavista.telia.com/av/pix/sponsors/
+amazon.com/g/associates/logos/
+annonce.insite.dk
+asinglesplace.com/asplink\.gif
+athand.com/rotation
+automatiseringgids.nl/gfx/advertenties/
+#avenuea.com/Banners/
+avenuea.com/view/
+badservant.guj.de
+befriends.net/personals/matchmaking\.jpg
+bizad.nikkeibp.co.jp
+bs.gsanet.com/gsa_bs/
+cash-for-clicks.de
+cda.at/customer/
+cgicounter.puretec.de/cgi-bin/
+ciec.org/images/countdown\.gif
+classic.adlink.de/cgi-bin/accipiter/adserver.exe
+click..wisewire.com
+clickhere.egroups.com/img/
+imagine-inc.com
+commonwealth.riddler.com/Commonwealth/bin/statdeploy\?[0-9]+
+customad.cnn.com
+dagbladet.no/ann-gif
+deja.com/jump/
+digits.com/wc/
+dino.mainz.ibm.de
+dn.adzerver.com/image.ad
+ds.austriaonline.at
+emap.admedia.net
+etrade.com/promo/
+eur.yimg.com/a/
+eur.a1.yimg.com/eur.yimg.com/a/
+us.a1.yimg.com/us.yimg.com/a/
+eurosponsor.de
+fastcounter.linkexchange.com
+flycast.com
+focalink.com/SmartBanner
+freepage.de/cgi-bin/feets/freepage_ext/.*/rw_banner
+freespace.virgin.net/andy.drake
+futurecard.com/images/
+gaia.occ.com/click.*
+globaltrack.com
+globaltrak.net
+go.com/cimages\?SEEK_
+gp.dejanews.com/gtplacer
+gtp.dejanews.com/gtplacer
+deja.com/gifs/onsale/
+hitbox.com 
+home.miningco.com/event.ng/.*AdID
+hurra.de
+hyperbanner.net
+icount.com/.*count
+image*.narrative.com/news/.*\.(gif|jpe?g)
+image.click2net.com
+image.linkexchange.com
+images.nytimes.com
+images.yahoo.com/adv/
+images.yahoo.com/promotions/
+imageserv.adtech.de
+img.web.de
+impartner.de/cgi-bin
+informer2.comdirect.de:6004/cd/banner2
+infoseek.go.com/cimages
+ins.at/asp/images/
+kaufwas.com/cgi-bin/zentralbanner\.cgi
+leader.linkexchange.com
+link4ads.com
+link4link.com
+linktrader.com/cgi-bin/
+logiclink.nl/cgi-bin/
+lucky.theonion.com/cgi-bin/oniondirectin\.cgi
+lucky.theonion.com/cgi-bin/onionimp\.cgi
+lucky.theonion.com/cgi-bin/onionimpin\.cgi
+m.doubleclick.net
+mailorderbrides.com/mlbrd2\.gif
+media.priceline.com
+mediaplex.com
+members.sexroulette.com
+messenger.netscape.com
+miningco.com/zadz/
+# movielink became moviefone
+moviefone.com/.*banner
+moviefone.com/.*newbutton
+moviefone.com/.*ad\.gif
+moviefone.com/.*mmail
+moviefone.com/.*poster\.gif
+moviefone.com/.*btyb
+moviefone.com/.*h_guy
+moviefone.com/.*h_showtick
+moviefone.com/.*h_aML
+moviefone.com/.*/m_
+moviefone.com/.*/icon_
+moviefone.com/.*/NF_.*back
+moviefone.com/.*/h_.*gif
+moviefone.com/media/imagelinks
+moviefone.com/media/imagelinks/MF.(ad|sponsor)
+moviefone.com/media/art
+mqgraphics.mapquest.com/graphics/Advertisements/
+netgravity.*
+newads.cmpnet.com
+news.com/cgi-bin/acc_clickthru
+ngadcenter.net
+ngserve.pcworld.com/adgifs/
+nol.at:81
+nrsite.com
+nytsyn.com/gifs
+offers.egroups.com
+pagecount.com
+ph-ad.*\.focalink.com
+preferences.com
+promotions.yahoo.com/
+pub.nomade.fr
+qsound.com/tracker/tracker.exe
+resource-marketing.com/tb/
+revenue.infi.net
+rtl.de/homepage/wb/images/
+schnellsuche.de/images/*
+shout-ads.com/cgibin/shout.php3
+sjmercury.com/advert/
+smartclicks.com/.*/smart(img|banner|host|bar|site)
+smh.com.au/adproof/
+spinbox1.filez.com
+static.wired.com/advertising/
+swiftad.com
+sysdoc.pair.com/cgi-sys/cgiwrap/sysdoc/sponsor\.gif
+t-online.de/home/040255162-001/*
+taz.de/taz/anz/
+tcsads.tcs.co.at
+teleauskunft.de/commercial/
+thecounter.com/id
+tm.intervu.net
+tvguide.com/rbitmaps/
+ubl.com/graphics/
+ubl.com/images/
+ultra.multimania.com
+ultra1.socomm.net
+uproar.com
+us.yimg.com/a/
+us.yimg.com/promotions/
+valueclick.com
+valueclick.net
+victory.cnn.com
+videoserver.kpix.com
+washingtonpost.com/wp-adv/
+webconnect.net/cgi-bin/webconnect.dll
+webcounter.goweb.de
+webserv.vnunet.com/ip_img/.*ban
+werbung.pro-sieben.de/cgi-bin
+whatis.com/cgi-bin/getimage.exe/
+www..bigyellow.com/......mat.*
+www.adclub.net
+www.addme.com/link8\.gif
+www.aftonbladet.se/annons
+www.americanpassage.com/
+www.angelfire.com/in/twistriot/images/wish4\.gif
+www.bizlink.ru/cgi-bin/irads\.cgi
+www.blacklightmedia.com/adlemur
+www.bluesnews.com/flameq\.gif
+www.bluesnews.com/images/ad[0-9]+\.gif
+www.bluesnews.com/images/gcanim3\.gif
+www.bluesnews.com/images/throbber2\.gif
+www.bluesnews.com/miscimages/fragbutton\.gif
+www.businessweek.com/sponsors/
+www.canoe.ca/AdsCanoe/
+www.cdnow.com/MN/client.banners
+www.clickagents.com
+www.clickthrough.ca
+www.clicmoi.com/cgi-bin/pub\.exe
+www.dailycal.org/graphics/adbanner-ab\.gif
+www.detelefoongids.com/pic/[0-9]*
+www.dhd.de/CGI/werbepic
+www.dsf.de/cgi-bin/site_newiac.adpos
+www.firsttarget.com/cgi-bin/klicklog.cgi
+www.forbes.com/forbes/gifs/ads
+www.forbes.com/tool/includes/gifs/
+www.fxweb.holowww.com/.*\.cgi
+www.geocities.com/TimesSquare/Zone/5267/
+www.goto.com/images-promoters/
+www.handelsblatt.de/hbad
+www.hotlinks.de/cgi-bin/barimage\.cgi
+www.infoseek.com/cimages
+www.infoworld.com/pageone/gif
+www.isys.net/customer/images
+www.javaworld.com/javaworld/jw-ad
+www.kron.com/place-ads/
+www.leo.org/leoclick/
+www.linkexchange.ru/cgi-bin/erle\.cgi
+www.linkstation.de/cgi-bin/zeige
+www.linux.org/graphic/miniature/
+www.linux.org/graphic/square/
+www.linux.org/graphic/standard/
+www.luncha.se/annonsering
+www.mediashower.com
+www.ml.org/gfx/spon/icom/
+www.ml.org/gfx/spon/wmv
+www.musicblvd.com/mb2/graphics/netgravity/
+nedstat.nl/cgi-bin/
+www.news.com/Midas/Images/
+www.newscientist.com/houseads
+www.nextcard.com/affiliates/
+www.nikkeibp.asiabiztech.com/image/NAIS4\.gif
+www.nordlys.no/imaker/.*/.*/.*/.....\.gif      # alvin brattli
+www.nordlys.no/imaker/.*/.*/.*/..003           # alvin brattli
+www.oanda.com/server/banner
+omdispatch.co.uk
+www.oneandonlynetwork.com
+www.page2page.de/cgi-bin/
+www.prnet.de/.*/bannerschnippel/.*\.(gif|jpe?g)
+www.promptsoftware.com/marketing/
+#www.reklama.ru/cgi-bin/banners/
+www.riddler.com/sponsors/
+www.rle.ru/cgi-bin/erle\.cgi
+www.rock.com/images/affiliates/search_black\.gif
+www.rtl.de/search/.*kunde
+#www.search.com/Banners
+www.sfgate.com/place-ads/
+www.shareware.com/midas/images/borders-btn\.gif
+#www.sjmercury.com/products/marcom/banners/
+www.smartclicks.com:81
+www.sol.dk/graphics/portalmenu
+www.sponsornetz.de/jump/show.exe
+www.sponsorpool.net
+www.sunworld.com/sunworldonline/icons/adinfo.sm\.gif
+www.swwwap.com/cgi-bin/
+www.taz.de/~taz/anz/
+www.telecom.at/icons/.*film\.(gif|jpe?g)
+www.theonion.com/bin/
+www.topsponsor.de/cgi-bin/show.exe
+www.ugo.net
+www.ugu.com/images/EJ\.gif
+www.warzone.com/pics/banner/
+www.warzone.com/wzfb/ads.cgi
+www.webpeep.com
+www.websitepromote.com/partner/img/
+www.winjey.com/onlinewerbung/*\.gif
+www.wishing.com/webaudit
+www.www-pool.de/cgi-bin/banner-pool
+www2.blol.com/agrJRU\.gif
+www3.exn.net:80
+yahoo.com/CategoryID=0
+yahoo.de/adv/images
+~cpan.valueclick.com
+~www.hitbox.com
+
+#swa
+www.bannerland.de/click.exe
+*.cyberclick.net
+*.eu-adcenter.net/
+www.web-stat.com
+www.slate.com/snav/
+www.slate.com/redirect/
+www.slate.com/articleimages/
+usads.imdb.com
+www.forbes.com/tool/images/frontend/
+www.zserver.com
+www.spinbox.com
+pathfinder.com/shopping/marketplace/images/
+/*.*/adbanner*
+/*.*/adgraphic*
+static.wired.com/images
+perso.estat.com/cgi-bin/perso/
+dinoadserver1.roka.net
+fooladclient*.fool.com
+affiliate.aol.com/static/
+cybereps.com:8000
+iadnet.com
+orientserve.com
+wvolante.com
+findcommerce.com
+smartage.com
+
+# www.sunday-times.co.uk
+www.sunday-times.co.uk/standing/newsint/ticker
+
+# Für Germany.Net-User: Germany.Net (fast) banner- u. grafikfrei!
+germany.net/gebu-frei\.gif
+germany.net/bilder/menue/leiste\.gif
+germany.net/bilder/gn_logos/*
+germany.net/bilder/90x90/*
+germany.net/banner-homepage/*
+germany.net/downloadshop/*
+germany.net/bilder/action/promopoly/germanynet/basisdienste/hilfe/*
+
+# Block as much of GeoCities as possible
+# All geocities-owned images
+www.geocities.com/images
+www.geocities.com/MemberBanners/live/
+pic.geocities.com/images
+# And the popup (it still pops up, but does not eat up precious bandwidth)
+#www.geocities.com/ad_container/pop.html # already fixed by other regexp
+
+# from corion@informatik.uni-frankfurt.de
+sam.songline.com/@
+img.getstats.com/
+#ads.xmonitor.net/xadengine.cgi # fixed by above regexp
+# Also block the japanese geocities popups
+www.geocities.co.jp/images
+# Also block the come.to, surf.to etc. popups
+v3.come.to/pop.asp
+
+# Also block the xoom stuff.
+xb.xoom.com
+home.talkcity.com/homepopup.html.*
+
+# Max Maischein <max.maischein@econsult.de> again ...
+# Halflife.net uses WON banners
+# Banners from Freeserve
+#banner.freeservers.com/cgi-bin/fs_adbar # fixed by above regexp
+# And those nasty va-popups !
+/.*/?va_banner.html
+# And an all-around hit against advert*.jpg
+/.*/advert[0-9]+\.jpg
+# And yet another Internet Explorer gif ...
+/.*/ie_horiz\.gif
+# Some uninteresting buttons I think...
+mircx.com/images/buttons/
+services.mircx.com/.*\.gif
+# Ooops - UserFriendly (Iambe) has a banner that gets eaten ...
+~www.userfriendly.org/images/banners/banner_dp_heart\.gif
+# Easyspace - yet another "free disk space" provider with <yuck> banner popups
+www.easyspace.com/(fpub)?banner.html
+www.easyspace.com/100\.gif
+# Some russian banner exchanges
+banner.ricor.ru/cgi-bin/banner.pl
+#www.bizlink.ru/cgi-bin/irads.cgi # already fixed by other regexp
+stx9.sextracker.com/stx/send/
+# And even more of geocities :
+www.geocities.com/pictures/
+# Gaah - www.angelfire.com - another webspace provider with popups
+angelfire.com/sys/download.html
+# Gamasutra.com uses this ad provider
+sally.songline.com/@
+
+# Eule.de (search engine)
+# maybe images.eule.de as a whole...
+www.eule.de/cgi-bin/
+images.eule.de/comdirect\.gif 
+images.eule.de/wp\.gif
+aladin.de/125_1\.gif
+images.eule.de/neu/books\.gif
+
+# --------------------------------------------------------------------------
+#
+# some images
+#
+# --------------------------------------------------------------------------
+
+# some images on cnn's website just suck!
+/.*cnnstore\.gif
+/.*book.search\.gif
+/.*cnnpostopinionhome.\.gif
+/.*custom_feature\.gif
+/.*explore.anim.*gif
+/.*infoseek\.gif
+/.*pathnet.warner\.gif
+/.*images/cnnfn_infoseek\.gif
+/.*images/pathfinder_btn2\.gif
+/.*img/gen/fosz_front_em_abc\.gif
+/.*img/promos/bnsearch\.gif
+/.*navbars/nav_partner_logos\.gif
+/BarnesandNoble/images/bn.recommend.box.*
+/digitaljam/images/digital_ban\.gif
+/hotstories/companies/images/companies_banner\.gif
+/markets/images/markets_banner\.gif
+/ows-img/bnoble\.gif
+/ows-img/nb_Infoseek\.gif
+cnn.com/images/custom/totale\.gif
+cnn.com/images/lotd/custom.wheels\.gif
+cnn.com/images/.*/by/main.12\.gif
+cnn.com/images/.*/find115\.gif
+cnn.com/.*/free.email.120\.gif
+cnnfn.com/images/left_banner\.gif
+focus.de/A/AF/AFL/
+www.cnn.com/images/.*/bn/books\.gif
+www.cnn.com/images/.*/pointcast\.gif
+www.cnn.com/images/.*/fusa\.gif
+cnn.com/images/.*/start120\.gif
+images.cnn.com/SHOP/
+/.*by/main\.gif
+/.*gutter117\.gif
+/.*barnes_logo\.gif
+# the / indicates the beginning of the path (and no longer the FQDN)
+/.*nbclogo\.gif
+/.*microdell\.gif
+/.*secureit\.gif
+
+g.deja.com/gifs/(q|us)west_120x120\.gif
+
+#
+/gif/buttons/banner_.*
+/gif/buttons/cd_shop_.*
+/gif/cd_shop/cd_shop_ani_.*
+
+#altavista
+/av/gifs/av_map\.gif
+/av/gifs/av_logo\.gif
+/av/gifs/new/ns\.gif
+altavista.com/i/valsdc3\.gif
+jump.altavista.com/gn_sf
+
+# tucows
+tucows.*.*/images/locallogo\.gif
+#tucows.dsuper.net/images/locallogo\.gif
+
+#
+mt_freshmeat\.jpg
+
+# simpliemu.hypermart.net/frames.html
+go2net.com/mgic/adpopup
+go2net.com/metaspy/images/exposed\.gif
+go2net.com/metaspy/images/ms_un\.gif
+
+#
+www.cebu-usa.com/cwbanim1\.gif
+www.cebu-usa.com/Connection\.jpg
+www.cebu-usa.com/phonead\.gif
+www.cebu-usa.com/ban3\.jpg
+www.cebu-usa.com/tlban\.gif
+www.cebu-usa.com/apwlogo1\.gif
+www.cebu-usa.com/rose\.gif
+
+# fnet
+www.fnet.de/img/geldboerselogo\.jpg
+
+# hirsch@mathcs.emory.edu
+/images/getareal2\.gif
+
+www.assalom.com/aziza/logos/cniaffil\.gif
+www.assalom.com/aziza/logos/4starrl1\.gif
+www.phantomstar.com/images/media/m1\.gif
+
+#
+wahlstreet.de/MediaW\$/tsponline\.gif
+wahlstreet.de/MediaW\$/dzii156x60\.gif
+wahlstreet.de/MediaW\$/etban156x60_2_opt2\.gif
+
+# linuxtoday.com
+/pics/gotlx1\.gif
+/pics/getareal1\.gif
+/pics/amzn-b5\.gif
+/ltbs/cgi-bin/click.cgi
+linuxtoday.com/ltbs/pics/
+
+# Geocities popups
+/ad[-_]container/
+/include/watermark/v2/
+
+# Reinier Bikker <R.P.Bikker@phys.uu.nl>
+# Banner.xxLINK.nl/
+
+# Mark Lutz <luma@nikocity.de>
+/.*/*werb.*\.(gif|jpe?g) # hope that's not to restrictive
+
+#Free Yellow thing at bottom of pages (HereticPC)
+www.freeyellow.com/images/powerlink5a\.gif
+www.freeyellow.com/images/powerlink5b\.gif
+www.freeyellow.com/images/powerlink5c\.gif
+www.freeyellow.com/images/powerlink5d\.gif
+www.freeyellow.com/images/powerlink5e\.gif
+
+#HereticPC
+www.eads.com/images/refbutton\.gif
+www.fortunecity.com/console2/newnav/*
+www.goldetc.net/search\.gif
+www.cris.com/~Lzrdking/carpix/cars3-le\.gif
+www.justfreestuff.com/scott\.gif
+www.cyberthrill.com/entrance\.gif
+secure.pec.net/images/pec69ani\.gif
+www.new-direction.com/avviva\.gif
+internetmarketingcenter\.gif
+www.new-direction.com/wp-linkexchange-loop\.gif
+www.new-direction.com/windough\.gif
+www.digitalwork.com/universal_images/affiliate/dw_le_3\.gif
+service.bfast.com/bfast/click/*
+www.new-direction.com/magiclearning\.gif
+www.new-direction.com/mailloop\.gif
+
+www.free-banners.com/images/hitslogo\.gif
+rob.simplenet.com/dyndns/fortune5\.gif
+nasdaq-amex.com/images/bn_ticker\.gif
+
+#
+# navilor@hotmail.com
+#
+#
+# wayne@staff.msen.com
+#
+a*.*.*.yimg.com/([0-9]*|\/)*us.yimg.com/*
+ad.doubleclick.net
+www.dnps.com/ads
+www.realtop50.com/cgi-bin/ad
+~a*.*.*.yimg.com/([0-9]|\/)*us.yimg.com/i/*
+
+#
+www.yacht.de/images/(my_ani|eissingani|chartertrans|fum|schnupper|fysshop|garmin)\.gif
+www.sponsorweb.de/web-sponsor/nt-bin/show.exe
+
+#
+# Club-internet pops up a complain if you refuse cookie (still pops up...)
+perso.club-internet.fr/html/Popup/popup_frame_nocookie.html
+perso.club-internet.fr/pagesperso/popup_nocookie.html
+
+gmx.net/images/newsbanner/
+cash4banner.de
+
+quicken.lexware.de/images/us7-468x60.gif
+/img/special/chatpromo\.gif
+www.travelocity.com/images/promos/
+
+# wonder that that does...
+p01.com/1x1.dyn
+
+/*.*/phpAds/viewbanner.php
+/*.*/phpAds/phpads.php
+
+www.linux-magazin.de/banner    
+comtrack.comclick.com
+click-fr.com
+iac-online.de/filler
+
+media.interadnet.com
+stat.www.fi/cgi-bin
+/cgi/banners.cgi
+ads-digi.sol.no
+fp.buy.com
+disneystoreaffiliates.com
+
+powerwork.mobile.de/cgi-bin/getimage\.cgi
+
+
+
+####################################################
+# Jon's addition:
+#
+# Register ads
+#www.theregister.co.uk/media/155\.gif
+www.theregister.dealtime.co.uk/BannerIn/
+#www.theregister.co.uk/media/SearchDomainRed\.gif
+#www.theregister.co.uk/media/ByDomainbusterRed\.gif
+#www.theregister.co.uk/media/454\.gif
+#www.theregister.co.uk/media/461\.gif
+#www.theregister.co.uk/media/dealtime-lh\.gif
+# Ad target:
+www.domainbuster.com/cgi-bin/domainbuster/dpro\.pl
+
+#www.theregister.co.uk/media/.*\.swf
+#www.theregister.co.uk/media/.*\.js
+
+# get agressive:
+www.theregister.co.uk/media/
+
+# Dilbert:
+www.dilbert.com/comics/dilbert/images/.*_140x800.*\.gif
+
+# stattrack.com
+# Uses URL: http://www.stattrack.com/cgi-bin/stats/image.cgi
+/cgi-bin/stats/
+# And loads JavaScript from http://www.stattrack.com/stats/code
+www.stattrack.com/stats/
+
+#GeoCities crap
+##geo.yahoo.com/serv
+##visit.geocities.com/visit.gif
+*.*.*.yimg.com/*/www.geocities.com/js_source
+#http://us.toto.geo.yahoo.com/toto?s=76001086
+##*.toto.geo.yahoo.com
+
+# Nuke GeoCities rubbish
+*.*.geo.yahoo.com
+*.geo.yahoo.com
+geo.yahoo.com
+visit.geocities.com
+*.*.*.yimg.com/.*/www.geocities.com/
+
+#http://counter16.bravenet.com/counter.php
+counter*.*.*
+
+#http://stat.cybermonitor.com/7emezone_p?1707_USdvd
+stat*.*.*
+
+#http://members.tripod.com/adm/popup/.....
+members.tripod.com/adm/popup/
+
+#This is the worst ad idea ever!  Bye bye!
+#count.exitexchange.com/exit/1100661
+#count.exitexchange.com/clients/navbar.html
+#(used in http://skyhivisuals.tripod.com/malfunctions_.htm)
+exitexchange.com
+
+#SourceForge ads.
+sfads.osdn.com
+
+#Crap trapping sites
+webhideout.com
+
+####################################################
+
+
+
+#
+# some regexps are simply too aggressive ...
+#
+# equalizer to /*.*(.*[-_.])?ads?[0-9]?(/|[-_.].*|.(gif|jpe?g)) 
+# or other regexps
+#
+#
+~adamwhone.co.uk
+~adsl.tin.it
+~stsci.edu
+~tgs.com
+~sun.com
+~povray.org
+~admin.*.*
+~admin.*.*.*
+~ad.siemens.de             # SIEMENS Automation & Drives
+~add-url.altavista.com
+~adis.on.ca
+~address*.*.*
+~address*.*.*.*
+~add*.*.*
+~add*.*.*.*
+~adu*.*.*
+~adu*.*.*.*
+~advice.*.*
+~advice.*.*.*
+
+# univ. don't advertise, do they :-)
+~*.*.edu
+~*.*.*.edu
+~www.ugu.com/sui/ugu/adv
+~adfa.edu.au
+~adsl*.*.*
+
+~clubs.yahoo.com/clubs
+~edit.my.yahoo.com/config/show_identity
+~www.ix.de/newsticker/data/ad
+~www.heise.de/newsticker/data/ad
+~www.careernet.de/anzeige
+~www.careernet.de/bewerber/stellenanzeigen
+~www.baumgartner.de/stellenmarkt/anzeigen
+~www.dspartner.de/Anzeigen
+~www.aws-jobs.de/Anzeigen
+~www.jobware.de/.*/anzeigen/
+~www.jobworld.de/bilder/
+~www.cnn.com/TECH/computing/.*/internet.ads/
+~www.financial.de/shop/
+~gnn.de/.*\.html
+~www.auktionen.de
+
+~194.221.152.2/phptelefontmp
+~harvard.edu/images/banner/
+
+~adswww.harvard.edu
+~www.dhd.de/CGI/anzeigen/
+
+~ads.web.de/web/
+~img.web.de/web/img/
+
+~www.segel.de/menu/bilder/anzeigen\.gif
+~www.corel.com/graphics/banners/
+~www.software.ibm.com/ad/
+~www.omg.org/docs/ad/
+
+~sperrmuell.de/scripts/anzeigen
+www.freenet.de/index.html
+www.01019freenet.de/index.html
+~www.freenet.de/freenet/
+~www.01019freenet.de/freenet/
+~webfactory.de/anzeigen.php
+~www.cdmag.com
+~www.internatif.org/bortzmeyer/debian/sponsor/
+~hp.com
+
+~www.software.hosting.ibm.com/ad/
+~www.ibm.com/software/ad/
+~brickshelf.com
+
+~www.debian.org/Pics/banner-blue\.gif
+~www.linux.de/pics/Nachrichten_banner\.gif
+~www.werbekurier.de
+
+~finder.shopping.yahoo.com/shop/
+~national.com/pf
+~mozilla.org
+~eidos.de
+~e-sheep.com
+~punkassgear.com
+~mozilla.org
+~mozillazine.org
+~adbusters.org
+~annoy.com
+~consumer-direct.com
+~www.iez-auktion.de
+~ibm.com
+~sgi.com
+
+# my banking stuff => no ads. last regexp for fast access :-)
+~comdirekt.de
+~comdirect.de
+~teledata.de
+
+
+~msdn.microsoft.com
+
+# do not forget newline at the end of this file!!!
+
diff --git a/config b/config
new file mode 100644 (file)
index 0000000..3ba741b
--- /dev/null
+++ b/config
@@ -0,0 +1,207 @@
+#  Sample Configuration file for the Internet Junkbuster 2.0
+
+#
+# $Id: config,v 1.2 2001/04/30 03:05:11 rodney Exp $
+#
+
+#
+#
+# Copyright 1997-8 Junkbusters Corp.  For distribution, modification and use
+# under the GNU General Public License. These files come with NO WARRANTY.
+# See http://www.junkbusters.com/ht/en/gpl.html or README file for details.
+#
+# When starting the proxy, give the name of this file as an argument.
+# Any changes made to this file are *not* automatically loaded; you have 
+# to stop and restart the proxy.
+
+# For information see http://www.junkbusters.com/ht/en/ijbman.html
+# or the documentation that came with the release
+
+# Lines beginning with a # character are comments; they are ignored.
+# Many example lines are provided here commented out
+
+# the blockfile contains patterns to be blocked by the proxy
+blockfile      ./blocklist # comments are OK here, too
+
+# the imagefile contains patterns to detect blocked images
+imagefile      ./imagelist
+
+# the popfile contains patterns of servers where javascript popups are disabled
+#
+# if the next line is not commented out, all javascript popups from the sites 
+# that match the patterns in popup will be blocked
+# popupfile     ./popup
+
+# File containing content modification rules
+#re_filterfile   ./re_filterfile
+
+# Uncomment to filter *all* traffic. Default is to
+# filter only if we wouldn't send a cookie either.
+#
+#re_filter_all
+
+
+# the cookiefile contains patterns to specify the cookie management policy
+#
+cookiefile     ./cookiefile
+
+# the logfile is where all logging and error messages are written
+#
+logfile        ./junkbuster.log
+
+# the jarfile is where cookies can be stored
+#
+#jarfile    ./jarfile
+
+# the forwardfile defines domain-specific routing
+#
+#forwardfile    ./forward
+
+# file which lists and into which trusted domains are written
+#
+#trustfile     ./trust
+# files specify locations of "for information about trusted referers, see.."
+# multiple trust_info_url lines are OK
+#
+# trust_info_url     http://internet.junkbuster.com/
+# trust_info_url     http://www.yoursite.com/our_trust_policy.html
+#
+
+# The access control list file can be used to restrict IP addresses
+# that are permitted to use the proxy (see warnings in the FAQ).
+#
+#aclfile ./aclfile
+
+# add an "X-Forwarded-For:" specification to each request header
+#
+#add-forwarded-header
+
+# if logging cookies into a jarfile, and no other wafers were
+# explicity set, then by default a vanilla wafer is sent with
+# each request.
+#
+# setting 'suppress-vanilla-wafer' stops this vanilla wafer from
+# being sent.
+#
+suppress-vanilla-wafer
+
+# add these wafers to each request header
+# multiple wafer lines are OK
+#
+#wafer    NOTE=Like most people, I want my browsing to be anonymous.
+#wafer    WARNING=Please do not attempt to track me.
+
+# Anything can be added to the request headers. Please don't litter.
+# multiple add-header lines are OK
+#
+#add-header     Forwarded: by http://stay-out-of-my-backyard.net
+#add-header    Forwarded: by http://pro-privacy-isp.net
+#add-header    Proxy-Connection: Keep-Alive
+
+# listen-address specifies where the Junkbuster will listen for connections
+# Specifying a port is optional; if unspecified the defaults is 8000.
+# Before Version 2.0.2 the default was to bind to all IP addresses (INADDR_ANY)
+# This has been restricted to localhost to avoid unintended security breaches.
+# To open the proxy to all, uncomment the following line:
+#listen-address      :8000
+# other example usage:
+#listen-address      124.207.250.245:8080
+# to explicitly state what is now the default:
+#listen-address      localhost
+# or equivalently:
+listen-address    127.0.0.1:8000
+
+# user-agent specifies treatment of the "User-Agent:" (and "UA-*:") header(s)
+# default: Forge the "User-Agent:" 
+# 'text' : Always send <text> as the "User-Agent:"
+# .      : Pass the "User-Agent:" unchanged
+# @      : Pass the "User-Agent:" if the server is in the cookie file,
+#          forge the "User-Agent:" otherwise
+#user-agent     @
+
+# note: Russian browsers may be confused if user agent misidentifies
+# the operating system (Mac vs Windows); see FAQ
+user-agent    .
+
+# referer specifies treatment of the "Referer:" header
+# New option by "Andreas S. Oesterhelt" <oes@paradis.rhein.de>
+#
+# default: Kill the referrer-header from the client
+# 'text' : Always send <text> as the referrer
+# .      : Pass the referrer unchanged
+# @      : Pass the referrer if the server is in the cookie file,
+#          kill the referrer otherwise
+# Â§      : Pass the referrer if the server is in the cookie file,
+#       send a forged referrer that points to the root-diretory URL
+#       of the current request otherwise
+referer     Â§
+
+# from specifies value to be subsituted if browser provides a "From:" header
+#
+#from        spam-me-senseless@sittingduck.net
+
+# tinygif allows you to change the appearance of blocked images
+#
+# tinygif      0  # Show a "broken icon"
+# tinygif      1  # Show a GIF of one transparent pixel
+# tinygif      2  # Show a GIF with the word "JUNKBUSTER"
+tinygif     2
+# tinygif  3 http://localhost/1x1.gif   # Temporary redirect to this URL
+
+# Andrew <anw@tirana.freewire.co.uk> added
+# The following can be used to suppress display of the block lists when the
+# page http://x.x/show-proxy-args is displayed. With a long block list this
+# accelerates loading of the configuration page and also hides the contents of
+# the block lists (for whatever reason). Maintainers of junkbuster proxies for 
+# multiple use can specify a message for any use who wants to know what is in
+# these files.
+#
+#suppress-blocklists Contact sysadmin@example.com for details.
+# suppress-blocklists
+
+# debug sets the level of debugging information to log in the logfile
+#
+# debug         1 # GPC  = show each GET/POST/CONNECT request
+# debug         2 # CONN = show each connection status
+# debug         4 # IO   = show I/O status
+# debug         8 # HDR  = show header parsing
+# debug        16 # LOG  = log all data into the logfile
+# debug        32 # FRC  = debug force feature
+# debug        64 # REF  = debug regular expression filter 
+#
+# multiple "debug" directives, are OK - they're logical-OR'd together
+#
+#debug         15 # same as setting the first 4 listed above
+debug 1
+#debug 255
+
+# single-threaded operation (i.e. disallows multiple threads or processes)
+# This is most often used for debugging because it keeps the
+# debugging output "in order" for easy reading.
+#
+#single-threaded
+
+# Toggle flag.  0 => disabled, anything else (ie. 1) => enabled
+toggle 1
+
+
+# Win32 GUI specific options.  Moved here from ijbw32.ini
+# in hopes of keep all of our config settings together.
+
+activity-animation      1
+log-messages            1
+log-highlight-messages  1
+log-buffer-size         1
+log-max-lines           200
+log-font-name           Comic Sans MS
+log-font-size           8
+show-on-task-bar        0
+close-button-minimizes  1
+
+# hide-console is used only on Win32 console mode. It instructs
+# the Internet Junkbuster to disconnect from and hide the
+# command console.
+#
+#hide-console
+
+
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..4d71f86
--- /dev/null
+++ b/config.h
@@ -0,0 +1,195 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+#ifndef _CONFIG_H
+#define _CONFIG_H
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/acconfig.h,v $
+ *
+ * Purpose     :  This file should be the first thing included in every
+ *                .c file.  (Before even system headers).  It contains 
+ *                #define statements for various features.  It was
+ *                introduced because the compile command line started
+ *                getting ludicrously long with feature defines.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: acconfig.h,v $
+ *
+ *********************************************************************/
+\f
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/*
+ * Version number - Major (X._._)
+ */
+#define VERSION_MAJOR 2
+
+/*
+ * Version number - Minor (_.X._)
+ */
+#define VERSION_MINOR 9
+
+/*
+ * Version number - Point (_._.X)
+ */
+#define VERSION_POINT 3
+
+/*
+ * Version number, as a string
+ */
+#define VERSION "2.9.3"
+
+/*
+ * Regular expression matching for URLs.  (Highly recommended).  If this is 
+ * not defined then you can ony use prefix matching.
+ */
+#define REGEX 1
+
+/*
+ * Allow JunkBuster to be "disabled" so it is just a normal non-blocking
+ * non-anonymizing proxy.  This is useful if you're trying to access a
+ * blocked or broken site - just change the setting in the config file
+ * and send a SIGHUP (UN*X), or use the handy "Disable" menu option (Windows
+ * GUI).
+ */
+#define TOGGLE 1
+
+/*
+ * Enables arbitrary content modification regexps
+ */
+#define PCRS 1
+
+/*
+ * If a stream is compressed via gzip (Netscape specific I think), then
+ * it cannot be modified with Perl regexps.  This forces it to be 
+ * uncompressed.
+ */
+#define DENY_GZIP 1
+
+/*
+ * Enables statistics function.
+ */
+#define STATISTICS 1
+
+/*
+ * Bypass filtering for 1 page only
+ */
+#define FORCE_LOAD 1
+
+/*
+ * Split the show-proxy-args page into a page for each config file.
+ */
+#define SPLIT_PROXY_ARGS 1
+
+/*
+ * Kills JavaScript popups - window.open, onunload, etc.
+ */
+#define KILLPOPUPS 1
+
+/*
+ * Support for webDAV - e.g. so Microsoft Outlook can access HotMail e-mail
+ */
+#define WEBDAV 1
+
+/*
+ * Detect image requests automatically for MSIE.  Will fall back to
+ * other image-detection methods (i.e. USE_IMAGE_LIST) for other
+ * browsers.
+ *
+ * It detects the following header pair as an image request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: * / *
+ *
+ * And the following as a HTML request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, * / *
+ *
+ * And no, I haven't got that backwards - IE is being wierd.
+ *
+ * Known limitations: 
+ * 1) If you press shift-reload on a blocked HTML page, you get
+ *    the image "blocked" page, not the HTML "blocked" page.
+ * 2) Once an image "blocked" page has been sent, viewing it 
+ *    in it's own browser window *should* bring up the HTML
+ *    "blocked" page, but it doesn't.  You need to clear the 
+ *    browser cache to get the HTML version again.
+ *
+ * These limitations are due to IE making inconsistent choices
+ * about which "Accept:" header to send.
+ */
+#define DETECT_MSIE_IMAGES 1
+
+/*
+ * Use image list to detect images.
+ * If you do not define this then everything is treated as HTML.
+ *
+ * Whatever the setting of this value, DETECT_MSIE_IMAGES will 
+ * override it for people using Internet Explorer.
+ */
+#define USE_IMAGE_LIST 1
+
+/*
+ * Allows the use of ACL files to control access to the proxy by IP address.
+ */
+#define ACL_FILES 1
+
+/*
+ * Allows the use of trust files.
+ */
+#define TRUST_FILES 1
+
+/*
+ * Allows the use of jar files to capture cookies.
+ */
+#define JAR_FILES 1
+
+/*
+ * Use PCRE rather than GNU Regex
+ */
+#define PCRE 1
+
+/* Define if you have the bcopy function.  */
+#define HAVE_BCOPY 1
+
+/* Define if you have the memmove function.  */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the strerror function.  */
+#define HAVE_STRERROR 1
+
+#endif /* _CONFIG_H */
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..930ca66
--- /dev/null
@@ -0,0 +1,194 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+#ifndef _CONFIG_H
+#define _CONFIG_H
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/acconfig.h,v $
+ *
+ * Purpose     :  This file should be the first thing included in every
+ *                .c file.  (Before even system headers).  It contains 
+ *                #define statements for various features.  It was
+ *                introduced because the compile command line started
+ *                getting ludicrously long with feature defines.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: acconfig.h,v $
+ *
+ *********************************************************************/
+\f
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/*
+ * Version number - Major (X._._)
+ */
+#undef VERSION_MAJOR
+
+/*
+ * Version number - Minor (_.X._)
+ */
+#undef VERSION_MINOR
+
+/*
+ * Version number - Point (_._.X)
+ */
+#undef VERSION_POINT
+
+/*
+ * Version number, as a string
+ */
+#undef VERSION
+
+/*
+ * Regular expression matching for URLs.  (Highly recommended).  If this is 
+ * not defined then you can ony use prefix matching.
+ */
+#undef REGEX
+
+/*
+ * Allow JunkBuster to be "disabled" so it is just a normal non-blocking
+ * non-anonymizing proxy.  This is useful if you're trying to access a
+ * blocked or broken site - just change the setting in the config file
+ * and send a SIGHUP (UN*X), or use the handy "Disable" menu option (Windows
+ * GUI).
+ */
+#undef TOGGLE
+
+/*
+ * Enables arbitrary content modification regexps
+ */
+#undef PCRS
+
+/*
+ * If a stream is compressed via gzip (Netscape specific I think), then
+ * it cannot be modified with Perl regexps.  This forces it to be 
+ * uncompressed.
+ */
+#undef DENY_GZIP
+
+/*
+ * Enables statistics function.
+ */
+#undef STATISTICS
+
+/*
+ * Bypass filtering for 1 page only
+ */
+#undef FORCE_LOAD
+
+/*
+ * Split the show-proxy-args page into a page for each config file.
+ */
+#undef SPLIT_PROXY_ARGS
+
+/*
+ * Kills JavaScript popups - window.open, onunload, etc.
+ */
+#undef KILLPOPUPS
+
+/*
+ * Support for webDAV - e.g. so Microsoft Outlook can access HotMail e-mail
+ */
+#undef WEBDAV
+
+/*
+ * Detect image requests automatically for MSIE.  Will fall back to
+ * other image-detection methods (i.e. USE_IMAGE_LIST) for other
+ * browsers.
+ *
+ * It detects the following header pair as an image request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: * / *
+ *
+ * And the following as a HTML request:
+ *
+ * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
+ * Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, * / *
+ *
+ * And no, I haven't got that backwards - IE is being wierd.
+ *
+ * Known limitations: 
+ * 1) If you press shift-reload on a blocked HTML page, you get
+ *    the image "blocked" page, not the HTML "blocked" page.
+ * 2) Once an image "blocked" page has been sent, viewing it 
+ *    in it's own browser window *should* bring up the HTML
+ *    "blocked" page, but it doesn't.  You need to clear the 
+ *    browser cache to get the HTML version again.
+ *
+ * These limitations are due to IE making inconsistent choices
+ * about which "Accept:" header to send.
+ */
+#undef DETECT_MSIE_IMAGES
+
+/*
+ * Use image list to detect images.
+ * If you do not define this then everything is treated as HTML.
+ *
+ * Whatever the setting of this value, DETECT_MSIE_IMAGES will 
+ * override it for people using Internet Explorer.
+ */
+#undef USE_IMAGE_LIST
+
+/*
+ * Allows the use of ACL files to control access to the proxy by IP address.
+ */
+#undef ACL_FILES
+
+/*
+ * Allows the use of trust files.
+ */
+#undef TRUST_FILES
+
+/*
+ * Allows the use of jar files to capture cookies.
+ */
+#undef JAR_FILES
+
+/*
+ * Use PCRE rather than GNU Regex
+ */
+#undef PCRE
+
+/* Define if you have the bcopy function.  */
+#undef HAVE_BCOPY
+
+/* Define if you have the memmove function.  */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+#endif /* _CONFIG_H */
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..6c620ec
--- /dev/null
+++ b/configure
@@ -0,0 +1,1968 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-mingw32        Use mingw32 for a Windows GUI"
+ac_help="$ac_help
+  --disable-regex         Don't allow regular expressions in the blockfile"
+ac_help="$ac_help
+  --disable-pcre-regex    Use old, slow GNU Regex instead of PCRE."
+ac_help="$ac_help
+  --disable-toggle        Don't support temporary disable"
+ac_help="$ac_help
+  --disable-pcrs          Don't support arbitrary content modification"
+ac_help="$ac_help
+  --disable-force         Don't allow blockfle to be bypassed"
+ac_help="$ac_help
+  --disable-killpopup     Never block popups"
+ac_help="$ac_help
+  --disable-stats         Don't keep statistics"
+ac_help="$ac_help
+  --disable-split-proxy-args  One big show-proxy-args page, not one per file."
+ac_help="$ac_help
+  --disable-webdav        Don't support WebDAV.  This option stops MS Outlook
+                          Express from accessing HotMail e-mail."
+ac_help="$ac_help
+  --disable-ie-images     Don't auto-detect whether a request from MS Internet
+                          Explorer is for an image or HTML."
+ac_help="$ac_help
+  --disable-image-list    Don't try to figure out whether a request is for an
+                          image or HTML using the imagelist - assume HTML."
+ac_help="$ac_help
+  --disable-acl-files     Prevents the use of ACL files to control access to
+                          the proxy by IP address."
+ac_help="$ac_help
+  --disable-trust-files   Prevents the use of trust files."
+ac_help="$ac_help
+  --disable-jar-files     Prevents the use of jar files to capture cookies."
+ac_help="$ac_help
+  --disable-static-pcre   Link dynamically with the pcre and pcreposix
+                          libraries.  You must build the libraries seperately."
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=jcc.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+VERSION_MAJOR=2
+VERSION_MINOR=9
+VERSION_POINT=3
+
+
+
+
+
+cat >> confdefs.h <<EOF
+#define VERSION_MAJOR ${VERSION_MAJOR}
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION_MINOR ${VERSION_MINOR}
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION_POINT ${VERSION_POINT}
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}"
+EOF
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:592: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:622: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:673: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:705: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 716 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:721: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:747: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:752: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:761: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:780: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:812: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 827 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:833: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 844 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:850: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 861 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:867: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
+echo "configure:893: checking for mingw32 environment" >&5
+if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 898 "configure"
+#include "confdefs.h"
+
+int main() {
+return __MINGW32__;
+; return 0; }
+EOF
+if { (eval echo configure:905: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_mingw32=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_mingw32=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_mingw32" 1>&6
+MINGW32=
+test "$ac_cv_mingw32" = yes && MINGW32=yes
+echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:922: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 927 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:938: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_cygwin=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+
+
+echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
+echo "configure:957: checking for executable suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
+  ac_cv_exeext=.exe
+else
+  rm -f conftest*
+  echo 'int main () { return 0; }' > conftest.$ac_ext
+  ac_cv_exeext=
+  if { (eval echo configure:967: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+    for file in conftest.*; do
+      case $file in
+      *.c | *.o | *.obj) ;;
+      *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
+      esac
+    done
+  else
+    { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
+  fi
+  rm -f conftest*
+  test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
+fi
+fi
+
+EXEEXT=""
+test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
+echo "$ac_t""${ac_cv_exeext}" 1>&6
+ac_exeext=$EXEEXT
+
+echo $ac_n "checking for object suffix""... $ac_c" 1>&6
+echo "configure:988: checking for object suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftest*
+echo 'int i = 1;' > conftest.$ac_ext
+if { (eval echo configure:994: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  for ac_file in conftest.*; do
+    case $ac_file in
+    *.c) ;;
+    *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;;
+    esac
+  done
+else
+  { echo "configure: error: installation or configuration problem; compiler does not work" 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_objext" 1>&6
+OBJEXT=$ac_cv_objext
+ac_objext=$ac_cv_objext
+
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1014: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1019 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1027: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1044 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1062 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1083 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1094: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1119: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1124 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1173: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1194: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1199 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+
+for ac_func in strerror bcopy memmove
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1230: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1235 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1258: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+# Check whether --enable-mingw32 or --disable-mingw32 was given.
+if test "${enable_mingw32+set}" = set; then
+  enableval="$enable_mingw32"
+  if test $enableval = yes; then
+    WIN_ONLY=
+    CYGWIN_FLAGS="-mwindows -mno-cygwin"
+    echo "Using mingw32 (Win32 GUI)"
+  else
+    WIN_ONLY=#
+    if test "$CYGWIN" = "yes"; then
+      CYGWIN_FLAGS="-mno-win32"
+      echo "Using Cygnus (Win32 command line)"
+    else
+      CYGWIN_FLAGS=
+    fi
+  fi
+else
+  if test "$MINGW32" = "yes"; then
+    WIN_ONLY=
+    CYGWIN_FLAGS="-mwindows -mno-cygwin"
+    echo "Using mingw32 (Win32 GUI)"
+  else
+    WIN_ONLY=#
+    if test "$CYGWIN" = "yes"; then
+      CYGWIN_FLAGS="-mno-win32"
+      echo "Using Cygnus (Win32 command line)"
+    else
+      CYGWIN_FLAGS=
+    fi
+  fi
+fi
+
+
+
+
+
+SOLARIS_ONLY=#
+
+
+
+
+GNU_REGEX_ONLY=
+PCRE_REGEX_ONLY=
+NO_REGEX_ONLY=#
+
+# Check whether --enable-regex or --disable-regex was given.
+if test "${enable_regex+set}" = set; then
+  enableval="$enable_regex"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define REGEX 1
+EOF
+
+else
+  NO_REGEX_ONLY=
+  GNU_REGEX_ONLY=#
+  PCRE_REGEX_ONLY=#
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define REGEX 1
+EOF
+
+fi
+
+
+# Check whether --enable-pcre-regex or --disable-pcre-regex was given.
+if test "${enable_pcre_regex+set}" = set; then
+  enableval="$enable_pcre_regex"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define PCRE 1
+EOF
+
+  GNU_REGEX_ONLY=#
+else
+  PCRE_REGEX_ONLY=#
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define PCRE 1
+EOF
+
+  GNU_REGEX_ONLY=#
+
+fi
+
+
+
+
+
+
+
+
+# Check whether --enable-toggle or --disable-toggle was given.
+if test "${enable_toggle+set}" = set; then
+  enableval="$enable_toggle"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define TOGGLE 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define TOGGLE 1
+EOF
+
+fi
+
+
+PCRS_ONLY=
+# Check whether --enable-pcrs or --disable-pcrs was given.
+if test "${enable_pcrs+set}" = set; then
+  enableval="$enable_pcrs"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define PCRS 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define DENY_GZIP 1
+EOF
+
+else
+  PCRS_ONLY=#
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define PCRS 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define DENY_GZIP 1
+EOF
+
+fi
+
+
+
+# Check whether --enable-force or --disable-force was given.
+if test "${enable_force+set}" = set; then
+  enableval="$enable_force"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define FORCE_LOAD 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define FORCE_LOAD 1
+EOF
+
+fi
+
+
+# Check whether --enable-killpopup or --disable-killpopup was given.
+if test "${enable_killpopup+set}" = set; then
+  enableval="$enable_killpopup"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define KILLPOPUPS 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define KILLPOPUPS 1
+EOF
+
+fi
+
+
+# Check whether --enable-stats or --disable-stats was given.
+if test "${enable_stats+set}" = set; then
+  enableval="$enable_stats"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define STATISTICS 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define STATISTICS 1
+EOF
+
+fi
+
+
+# Check whether --enable-split-proxy-args or --disable-split-proxy-args was given.
+if test "${enable_split_proxy_args+set}" = set; then
+  enableval="$enable_split_proxy_args"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define SPLIT_PROXY_ARGS 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define SPLIT_PROXY_ARGS 1
+EOF
+
+fi
+
+
+# Check whether --enable-webdav or --disable-webdav was given.
+if test "${enable_webdav+set}" = set; then
+  enableval="$enable_webdav"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define WEBDAV 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define WEBDAV 1
+EOF
+
+fi
+
+
+# Check whether --enable-ie-images or --disable-ie-images was given.
+if test "${enable_ie_images+set}" = set; then
+  enableval="$enable_ie_images"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define DETECT_MSIE_IMAGES 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define DETECT_MSIE_IMAGES 1
+EOF
+
+fi
+
+
+# Check whether --enable-image-list or --disable-image-list was given.
+if test "${enable_image_list+set}" = set; then
+  enableval="$enable_image_list"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define USE_IMAGE_LIST 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define USE_IMAGE_LIST 1
+EOF
+
+fi
+
+
+# Check whether --enable-acl-files or --disable-acl-files was given.
+if test "${enable_acl_files+set}" = set; then
+  enableval="$enable_acl_files"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define ACL_FILES 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define ACL_FILES 1
+EOF
+
+fi
+
+
+# Check whether --enable-trust-files or --disable-trust-files was given.
+if test "${enable_trust_files+set}" = set; then
+  enableval="$enable_trust_files"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define TRUST_FILES 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define TRUST_FILES 1
+EOF
+
+fi
+
+
+# Check whether --enable-jar-files or --disable-jar-files was given.
+if test "${enable_jar_files+set}" = set; then
+  enableval="$enable_jar_files"
+  if test $enableval = yes; then
+  cat >> confdefs.h <<\EOF
+#define JAR_FILES 1
+EOF
+
+fi
+else
+  cat >> confdefs.h <<\EOF
+#define JAR_FILES 1
+EOF
+
+fi
+
+
+LIBRARY_PCRE_ONLY=#
+STATIC_PCRE_ONLY=
+# Check whether --enable-static-pcre or --disable-static-pcre was given.
+if test "${enable_static_pcre+set}" = set; then
+  enableval="$enable_static_pcre"
+  if test $enableval = no; then
+  LIBRARY_PCRE_ONLY=
+  STATIC_PCRE_ONLY=#
+fi
+fi
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@VERSION_MAJOR@%$VERSION_MAJOR%g
+s%@VERSION_MINOR@%$VERSION_MINOR%g
+s%@VERSION_POINT@%$VERSION_POINT%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@EXEEXT@%$EXEEXT%g
+s%@OBJEXT@%$OBJEXT%g
+s%@WIN_ONLY@%$WIN_ONLY%g
+s%@CYGWIN_FLAGS@%$CYGWIN_FLAGS%g
+s%@SOLARIS_ONLY@%$SOLARIS_ONLY%g
+s%@GNU_REGEX_ONLY@%$GNU_REGEX_ONLY%g
+s%@PCRE_REGEX_ONLY@%$PCRE_REGEX_ONLY%g
+s%@NO_REGEX_ONLY@%$NO_REGEX_ONLY%g
+s%@PCRS_ONLY@%$PCRS_ONLY%g
+s%@LIBRARY_PCRE_ONLY@%$LIBRARY_PCRE_ONLY%g
+s%@STATIC_PCRE_ONLY@%$STATIC_PCRE_ONLY%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..492d6ed
--- /dev/null
@@ -0,0 +1,257 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl 
+dnl $Id: configure.in,v 1.2 2001/05/13 22:04:51 administrator Exp $
+dnl 
+dnl Written by and Copyright (C) 2001 the SourceForge
+dnl IJBSWA team.  http://ijbswa.sourceforge.net
+dnl
+dnl Based on the Internet Junkbuster originally written
+dnl by and Copyright (C) 1997 Anonymous Coders and 
+dnl Junkbusters Corporation.  http://www.junkbusters.com
+dnl
+dnl This program is free software; you can redistribute it 
+dnl and/or modify it under the terms of the GNU General
+dnl Public License as published by the Free Software
+dnl Foundation; either version 2 of the License, or (at
+dnl your option) any later version.
+dnl 
+dnl This program is distributed in the hope that it will
+dnl be useful, but WITHOUT ANY WARRANTY; without even the
+dnl implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.  See the GNU General Public
+dnl License for more details.
+dnl 
+dnl The GNU General Public License should be included with
+dnl this file.  If not, you can view it at
+dnl http://www.gnu.org/copyleft/gpl.html
+dnl or write to the Free Software Foundation, Inc., 59
+dnl Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+dnl 
+dnl $Log: configure.in,v $
+dnl 
+AC_INIT(jcc.c)
+AC_CONFIG_HEADER(config.h)
+
+VERSION_MAJOR=2
+VERSION_MINOR=9
+VERSION_POINT=3
+
+AC_SUBST(VERSION_MAJOR)
+AC_SUBST(VERSION_MINOR)
+AC_SUBST(VERSION_POINT)
+
+AC_DEFINE_UNQUOTED(VERSION_MAJOR,${VERSION_MAJOR})
+AC_DEFINE_UNQUOTED(VERSION_MINOR,${VERSION_MINOR})
+AC_DEFINE_UNQUOTED(VERSION_POINT,${VERSION_POINT})
+AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}")
+
+dnl Checks for programs.
+dnl AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_CPP
+dnl AC_PROG_INSTALL
+dnl AC_PROG_LN_S
+dnl AC_PROG_MAKE_SET
+dnl RANLIB is for PCRE:
+dnl AC_PROG_RANLIB
+
+AC_MINGW32
+AC_CYGWIN
+AC_EXEEXT
+AC_OBJEXT
+
+dnl Checks for libraries.
+dnl AC_CHECK_LIB(pcre, pcre_compile)
+dnl AC_CHECK_LIB(pcreposix, regcomp, pcre)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+dnl AC_HEADER_SYS_WAIT
+dnl AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/time.h unistd.h)
+dnl limits.h is for PCRE:
+dnl AC_CHECK_HEADERS(limits.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+dnl Checks for library functions.
+dnl AC_TYPE_SIGNAL
+dnl AC_CHECK_FUNC(strstr)
+dnl bcopy and memmove are for PCRE
+AC_CHECK_FUNCS(strerror bcopy memmove)
+
+dnl Build type
+
+AC_ARG_ENABLE(mingw32,
+[  --enable-mingw32        Use mingw32 for a Windows GUI],
+[if test $enableval = yes; then
+    WIN_ONLY=
+    CYGWIN_FLAGS="-mwindows -mno-cygwin"
+    echo "Using mingw32 (Win32 GUI)"
+  else
+    WIN_ONLY=#
+    if test "$CYGWIN" = "yes"; then
+      CYGWIN_FLAGS="-mno-win32"
+      echo "Using Cygnus (Win32 command line)"
+    else
+      CYGWIN_FLAGS=
+    fi
+  fi],
+[if test "$MINGW32" = "yes"; then
+    WIN_ONLY=
+    CYGWIN_FLAGS="-mwindows -mno-cygwin"
+    echo "Using mingw32 (Win32 GUI)"
+  else
+    WIN_ONLY=#
+    if test "$CYGWIN" = "yes"; then
+      CYGWIN_FLAGS="-mno-win32"
+      echo "Using Cygnus (Win32 command line)"
+    else
+      CYGWIN_FLAGS=
+    fi
+  fi])
+
+AC_SUBST(WIN_ONLY)
+AC_SUBST(CYGWIN_FLAGS)
+
+SOLARIS_ONLY=#
+AC_SUBST(SOLARIS_ONLY)
+
+dnl Features
+
+dnl Regex engine:
+
+GNU_REGEX_ONLY=
+PCRE_REGEX_ONLY=
+NO_REGEX_ONLY=#
+
+AC_ARG_ENABLE(regex,
+[  --disable-regex         Don't allow regular expressions in the blockfile],
+[if test $enableval = yes; then
+  AC_DEFINE(REGEX)
+else
+  NO_REGEX_ONLY=
+  GNU_REGEX_ONLY=#
+  PCRE_REGEX_ONLY=#
+fi],AC_DEFINE(REGEX))
+
+AC_ARG_ENABLE(pcre-regex,
+[  --disable-pcre-regex    Use old, slow GNU Regex instead of PCRE.],
+[if test $enableval = yes; then
+  AC_DEFINE(PCRE)
+  GNU_REGEX_ONLY=#
+else
+  PCRE_REGEX_ONLY=#
+fi],[AC_DEFINE(PCRE)
+  GNU_REGEX_ONLY=#
+])
+
+AC_SUBST(GNU_REGEX_ONLY)
+AC_SUBST(PCRE_REGEX_ONLY)
+AC_SUBST(NO_REGEX_ONLY)
+
+
+dnl Other features:
+
+AC_ARG_ENABLE(toggle,
+[  --disable-toggle        Don't support temporary disable],
+[if test $enableval = yes; then
+  AC_DEFINE(TOGGLE)
+fi],AC_DEFINE(TOGGLE))
+
+PCRS_ONLY=
+AC_ARG_ENABLE(pcrs,
+[  --disable-pcrs          Don't support arbitrary content modification],
+[if test $enableval = yes; then
+  AC_DEFINE(PCRS)
+  AC_DEFINE(DENY_GZIP)
+else
+  PCRS_ONLY=#
+fi],[AC_DEFINE(PCRS) AC_DEFINE(DENY_GZIP)])
+AC_SUBST(PCRS_ONLY)
+
+AC_ARG_ENABLE(force,
+[  --disable-force         Don't allow blockfle to be bypassed],
+[if test $enableval = yes; then
+  AC_DEFINE(FORCE_LOAD)
+fi],AC_DEFINE(FORCE_LOAD))
+
+AC_ARG_ENABLE(killpopup,
+[  --disable-killpopup     Never block popups],
+[if test $enableval = yes; then
+  AC_DEFINE(KILLPOPUPS)
+fi],AC_DEFINE(KILLPOPUPS))
+
+AC_ARG_ENABLE(stats,
+[  --disable-stats         Don't keep statistics],
+[if test $enableval = yes; then
+  AC_DEFINE(STATISTICS)
+fi],AC_DEFINE(STATISTICS))
+
+AC_ARG_ENABLE(split-proxy-args,
+[  --disable-split-proxy-args  One big show-proxy-args page, not one per file.],
+[if test $enableval = yes; then
+  AC_DEFINE(SPLIT_PROXY_ARGS)
+fi],AC_DEFINE(SPLIT_PROXY_ARGS))
+
+AC_ARG_ENABLE(webdav,
+[  --disable-webdav        Don't support WebDAV.  This option stops MS Outlook
+                          Express from accessing HotMail e-mail.],
+[if test $enableval = yes; then
+  AC_DEFINE(WEBDAV)
+fi],
+AC_DEFINE(WEBDAV))
+
+AC_ARG_ENABLE(ie-images,
+[  --disable-ie-images     Don't auto-detect whether a request from MS Internet
+                          Explorer is for an image or HTML.],
+[if test $enableval = yes; then
+  AC_DEFINE(DETECT_MSIE_IMAGES)
+fi],
+AC_DEFINE(DETECT_MSIE_IMAGES))
+
+AC_ARG_ENABLE(image-list,
+[  --disable-image-list    Don't try to figure out whether a request is for an
+                          image or HTML using the imagelist - assume HTML.],
+[if test $enableval = yes; then
+  AC_DEFINE(USE_IMAGE_LIST)
+fi],
+AC_DEFINE(USE_IMAGE_LIST))
+
+AC_ARG_ENABLE(acl-files,
+[  --disable-acl-files     Prevents the use of ACL files to control access to
+                          the proxy by IP address.],
+[if test $enableval = yes; then
+  AC_DEFINE(ACL_FILES)
+fi],
+AC_DEFINE(ACL_FILES))
+
+AC_ARG_ENABLE(trust-files,
+[  --disable-trust-files   Prevents the use of trust files.],
+[if test $enableval = yes; then
+  AC_DEFINE(TRUST_FILES)
+fi],
+AC_DEFINE(TRUST_FILES))
+
+AC_ARG_ENABLE(jar-files,
+[  --disable-jar-files     Prevents the use of jar files to capture cookies.],
+[if test $enableval = yes; then
+  AC_DEFINE(JAR_FILES)
+fi],
+AC_DEFINE(JAR_FILES))
+
+LIBRARY_PCRE_ONLY=#
+STATIC_PCRE_ONLY=
+AC_ARG_ENABLE(static-pcre,
+[  --disable-static-pcre   Link dynamically with the pcre and pcreposix
+                          libraries.  You must build the libraries seperately.],
+[if test $enableval = no; then
+  LIBRARY_PCRE_ONLY=
+  STATIC_PCRE_ONLY=#
+fi])
+AC_SUBST(LIBRARY_PCRE_ONLY)
+AC_SUBST(STATIC_PCRE_ONLY)
+
+AC_OUTPUT(Makefile)
+
diff --git a/cookiefile b/cookiefile
new file mode 100644 (file)
index 0000000..f17f4b0
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# This is /etc/junkbuster/cookefile which was put here by a junkbuster rpm
+#
+# Last modified on Sun Jan 31 22:36:03 1999 (CEST)
+#
+# --------------------------------------------------------------------------
+#
+# Newest version is always available from 
+#
+#          http://www.waldherr.org/cookiefile
+#
+# Read http://www.waldherr.org/junkbuster/update.shtml on how to keep
+# this file up-to-date.
+#
+# For more detail, see http://www.junkbusters.com/ht/en/ijbfaq.html#cookies
+#
+# Empty lines and lines beginning with a # are ignored.
+# To permit an entire site to set cookies, simply include its domain name:
+# really-trustyworthy-people.org
+#
+# You can allow cookies out, but stop them coming in:
+# >send-user-cookies.com
+#
+#>egroups.com
+#>tvguide.com
+#>wired.com/news/
+#americanexpress.com
+#cnn.com
+#www.nytimes.com
+#yahoo.com
+#amazon.de
+#amazon.co.uk
+#slashdot.org
+#www.palmgear.com
+#onelist.com
+#freshmeat.net
+
+# Sites that need cookies
+javasoft.com
+sun.com
+msdn.microsoft.com
+sourceforge.net
+yahoo.com
+anonymizer.com
+
+# Experimenting
+ashleycars.co.uk
+
+# Shopping
+dabs.com
+overclockers.co.uk
+worldpay.com   # for quietpc.com
+jungle.com
+scan.co.uk
+
+#Shopping: Micro Warehouse's site
+#inmac.co.uk
+#technomatic.co.uk
+
+# This is stupid.  Without these two entries, the link from McAfee's website
+# to their online UK shop gives a 500 server error.
+#mcafee.com
+#mcafeestoreuk.beyond.com
+
+
+
+
diff --git a/cygwin.h b/cygwin.h
new file mode 100644 (file)
index 0000000..4568ea8
--- /dev/null
+++ b/cygwin.h
@@ -0,0 +1,63 @@
+#ifndef _CYGWIN_H
+#define _CYGWIN_H
+#define CYGWIN_H_VERSION "$Id: cygwin.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/cygwin.h,v $
+ *
+ * Purpose     :  The windows.h file seems to be a *tad* different, so I
+ *                will bridge the gaps here.  Perhaps I should convert the
+ *                latest SDK too?  Shudder, I think not.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: cygwin.h,v $
+ *
+ *********************************************************************/
+
+/* Conditionally include this whole file. */
+#ifdef __MINGW32__
+
+/* Hmmm, seems to be overlooked. */
+#define _RICHEDIT_VER 0x0300
+
+/*
+ * Named slightly different ... but not in Cygwin v1.3.1 ...
+ *
+ * #define LVITEM   LV_ITEM
+ * #define LVCOLUMN LV_COLUMN
+ */
+
+#endif /* def __MINGW32__ */
+#endif /* ndef _CYGWIN_H */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/doc/USER_DOC_IS_WIDELY_OBSOLETED b/doc/USER_DOC_IS_WIDELY_OBSOLETED
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/changes.txt b/doc/changes.txt
new file mode 100644 (file)
index 0000000..6aa1482
--- /dev/null
@@ -0,0 +1,991 @@
+This file contains details of the changes made to JunkBuster, in
+chronological order.  Scroll down to the bottom for the newest 
+additions!
+
+
+*****************************************************************************
+* Copied from old README                                                    *
+*****************************************************************************
+
+README for the Internet Junkbuster Proxy (TM) Copyright 1997-8 Junkbusters Corp.
+
+   Id: README,v 1.1 2001/04/16 21:10:38 rodney Exp 
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2 of the License,
+   or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+The version of the code with this makefile is Version 2.0.2.
+No CHANGES file is included here; for a history of previous versions see
+   http://www.junkbusters.com/ht/en/ijbdist.html#previous
+This version tightens security over 2.0.1; some multi-user sites will need
+to change the listen-address in the configuration file (see previous URL).
+
+For installation on Windows see http://www.junkbusters.com/ht/en/ijbwin.html
+An executable is provided so you don't need nmake or a C compiler.
+
+For UNIX and other systems see the FAQ. If you just want to test it with its
+defaults of simply stopping cookies and private info, all you need to do now
+on most Unix systems is type make, run junkbuster & and configure your browser.
+
+This directory should contain the following files.  The .html files are also
+in http://www.junkbusters.com/ht/en/ and http://internet.junkbuster.com
+You are welcome to publish copies of the .html files on your local web server,
+according to the GNU General Public License.
+
+gpl.html GNU General Public Licence
+junkbstr.exe   Executable (binary) for Windows 95/NT
+Makefile A very bland Makefile; Most versions of Unix except HP & Suns
+      compile without change. Windows requires the changes indicated.
+ijbman.html Manual for the Internet Junkbuster, HTML format
+junkbuster.1   Manual for the Internet Junkbuster, man macro format:
+         man ./junkbuster.1 # or nroff -man junkbuster.1 | more
+ijbfaq.html FAQ: Frequently Asked Questions on the Internet Junkbuster
+      Includes installation instructions
+junkbstr.ini   Sample configuration file with almost all options commented out
+sblock.ini  Sample blockfile (which doesn't really block much, see FAQ)
+scookie.ini Sample cookiefile (permits little; you decide who to trust)
+saclfile.ini   Sample access control file (block access to everyone)
+sforward.ini   Sample forwardfile (does no fowarding, no gateways, so SOCKS)
+strust.ini  Sample trustfile (has no trusted sites and blocks nothing)
+conn.c, bind.c, encode.c, loaders.c, parsers.c, ssplit.c   Various utilities
+socks4.c Code for SOCKS4 and SOCKS4A gateways
+jcc.c    The main program
+jcc.h    #included declarations etc
+gnu_regex.c, gnu_regex.h:  Regular expression code from the FSF, not us.
+win32.c     A few lines of code specific to the Windows version (95 & NT)
+acl.c    Access controls (new in version 2.0) - doesn't replace firewalls
+filters.c   Strings for the presentation of messages to user
+
+If you find that the Internet Junkbuster improves the quality of your life
+online, we hope you'll visit http://www.junkbusters.com to see how our free
+services can help you bust other kinds of junk out of your life:
+junk mail, spam, telemarketing, and invasions of your private data.
+And please tell your friends about this free product, and help them set it up.
+
+If your company finds this software useful in protecting its confidential
+information and making its people happier and more productive, please consider
+purchasing one of our our commercial support packages:
+   http://www.junkbusters.com/ht/en/ijbfaq.html#commercial
+
+We don't advertise, so please tell others in your community about us.
+
+Junkbusters Corp.    http://www.junkbusters.com
+
+
+*****************************************************************************
+* Copied from old README.too                                                *
+*****************************************************************************
+
+Id: README.TOO,v 1.1 2001/04/16 21:10:38 rodney Exp
+
+This is the README.TOO file for Stefan's version of the Internet
+Junkbuster (from http://www.waldherr.org/junkbuster/).
+
+
+
+Installation:
+-------------
+Install the RPM with the usual command `rpm -Uvh foobar.rpm'. Since we
+run the Junkbuster as user `nobody', cd to a directory where `nobody'
+has read access (in particular NOT /root) and issue (as root)
+
+   /etc/rc.d/init.d/junkbuster start
+
+This will be done automagically for you any time you boot your machine.
+
+
+
+Configuration:
+--------------
+To let Junkbuster take `care' of the ads, you have to setup your
+browser to use the Junkbuster.
+
+  Short instructions for the advanced user:
+
+   Configure Netscape to use 127.0.0.1 on port 8000 as 
+        a proxy server.
+
+  Detailed instructions for the beginner:
+
+        Remove Internet Explorer and install Netscape. No `real' 
+        user would ever use MSIE. Though the Junkbuster works 
+        with IE as well. Read 
+        http://www.junkbusters.com/ht/en/ijbfaq.html#browser
+
+Check to see if the Junkbuster works correctly by surfing to
+
+   http://127.0.0.1/show-proxy-args
+
+or any other place and add the text `/show-proxy-args' to the URL.
+Ok? Then enjoy your ad-free surfing.
+
+
+
+Mailinglists:
+-------------
+In case you are interested in the Junkbuster, there are two
+mailinglists (junkbuster-users and junkbuster-announce). Instructions
+on how to subscribe and unsubscribe are at
+
+   http://www.waldherr.org/junkbuster/
+
+Bugs:
+-----
+Please fill out
+
+   http://sourceforge.net/bugs/?func=addbug&group_id=11118
+
+Patches:
+--------
+Please fill out
+
+   http://sourceforge.net/patch/?func=addpatch&group_id=11118
+
+Need Help?
+----------
+Please fill out
+
+   http://sourceforge.net/support/?func=addsupport&group_id=11118
+
+
+Comments:
+---------
+I would greatly appreciate feedback for this program. Send comments to
+Stefan Waldherr <stefan@waldherr.org> (in either German or English). I
+prefer plain text. If you happen to see an ad which got thru the filter
+PLEASE use the `contribute' form at http://www.waldherr.org/junkbuster/.
+
+Have fun,
+Stefan.
+
+
+*****************************************************************************
+* Copied from old README.win                                                *
+*****************************************************************************
+
+$Id: README.WIN,v 1.1 2001/04/16 21:10:38 rodney Exp $
+
+This is the README.WIN file for the Windows version of the Internet
+Junkbuster (from http://www.waldherr.org/junkbuster/).
+
+Installation:
+-------------
+Congrats, since you are reading this file, you have already unzipped
+the archive correctly.
+
+Start the Junkbuster with `junkbstr' (i.e., click on the icon in the
+ijb subdirectory). If you want to start Junkbuster automatically,
+make a link to the program in the `Autostart' folder.
+
+
+
+Configuration:
+--------------
+To let Junkbuster take `care' of the ads, you have to setup your
+browser to use the Junkbuster.
+
+  Short instructions for the advanced user:
+
+   Configure Netscape to use 127.0.0.1 on port 8000 as 
+        a proxy server.
+
+  Detailed instructions for the beginner:
+
+        Remove Internet Explorer and install Netscape. No `real' 
+        user would ever use MSIE. Though the Junkbuster works 
+        with IE as well. Read 
+        http://www.junkbusters.com/ht/en/ijbfaq.html#browser
+
+Check to see if the Junkbuster works correctly by surfing to
+
+   http://127.0.0.1/show-proxy-args
+
+or any other place and add the text `/show-proxy-args' to the URL.
+Ok? Then enjoy your ad-free surfing.
+
+
+
+Mailinglists:
+-------------
+In case you are interested in the Junkbuster, there are two
+mailinglists (junkbuster-users and junkbuster-announce). Instructions
+on how to subscribe and unsubscribe are at
+
+   http://www.waldherr.org/junkbuster/
+
+Bugs:
+-----
+Please fill out
+
+   http://sourceforge.net/bugs/?func=addbug&group_id=11118
+
+Patches:
+--------
+Please fill out
+
+   http://sourceforge.net/patch/?func=addpatch&group_id=11118
+
+Need Help?
+----------
+Please fill out
+
+   http://sourceforge.net/support/?func=addsupport&group_id=11118
+
+Comments:
+---------
+I would greatly appreciate feedback for this program. Send comments to
+Stefan Waldherr <stefan@waldherr.org> (in either German or English). I
+prefer plain text. If you happen to see an ad which got thru the filter
+PLEASE use the `contribute' form at http://www.waldherr.org/junkbuster/.
+
+Have fun,
+Stefan.
+
+
+*****************************************************************************
+* Copied from old README.re_filter                                          *
+*****************************************************************************
+
+DISCLAIMER:
+   This is pre-alpha code. Using it in any other way
+   than just reading it is a high risk activity and
+   the author disclaims all liability for any damage.
+
+   See the GNU General Public License at
+   http://www.gnu.org/copyleft/gpl.html for details.
+
+
+Dear alpha-Tester,
+
+Thank you for trying out the experimental re_filter feature of
+Junkbuster. As this is still a very early pre-release version,
+and I'm neither much of an autoconf or make wizard, building
+the patched junkbuster involves some manual work, that is 
+described below. Please also see the Request for Thoughts section,
+as the whole point of this pre-release ist to collect ideas for
+improvement and bug reports.
+
+
+INSTALLATION:
+
+  - Get and install pcre from
+    ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
+    Version 3.1 or any later one will do. I recommend 3.4.
+    It *should* install on Win32 as well, but I haven't tried
+    that. Don't forget to run ldconfig afterwards.
+
+  - Now you have two options:
+
+    A) Install pcrs as a shared library:
+       pcrs.c and pcrs.h are included in the (patched) ijb subdirectory.
+       1.) patch Makefile < Makefile.re_shared.diff  
+       2.) gcc -Wall -fPIC -c pcrs.c  
+       3.) gcc -shared -Wl,-soname,libpcrs.so.1 -o libpcrs.so.1.0.1 pcrs.o -lc -lpcre
+       If this worked OK,
+       4.) copy libpcrs.so.1.0.1 to /usr/local/lib
+       5.) ln -s /usr/local/lib/libpcrs.1.0.1 /usr/local/lib/libpcrs.so
+       6.) ldconfig (Or whatever the equivalent on your platform might be)
+       7.) cp pcrs.h /usr/local/include
+
+    OR
+
+    B) Incorporate pcrs into the junkbuster (much easier):
+       Smile and relax. You're done.
+
+  - Edit the provided re_filterfile to suit your needs and place it
+    with the rest of junkbusters configfiles.
+
+  - Now junkbuster should build with a simple 'make'.
+    Note: Setting debug = REF in jcc.c will enable debugging
+    for the re_filter.
+
+  - Include a line "re_filterfile <wherever>" in your junkbuster
+    config file, pointing at the re_filterfile
+
+  - (Optional:) Include a line "re_filter_all" in the config
+    file. This will set the Policy to filter content from all sites.
+    Default is to filter only from sites that you wouldn't send a
+    cookie either. 
+
+  - Fire up junkbuster.
+
+HOW IT WORKS:
+
+    Nah, not tonight anymore ;-)
+
+REQUEST FOR THOUGHTS:
+
+  - The main decision is whether to filter on-the-fly or to buffer
+    up the whole document and then run the filter on it. I've built
+    both versions and currently prefer buffering.
+
+    The advantage of on-the-fly-filtering is obviously that the
+    document begins to display before it's fully loaded. The big
+    disadvantage is that with arbitraty content altering in place,
+    you don't know the size that the document will have after
+    altering when the Content-Length Header is to be sent. Only
+    option is to chew it altogether.
+
+    Apart from preserving the ability to generate a valid Content-Length
+    header (which the patch currently does not yet do), buffering up
+    the document has some advantages from the filtering point of view:
+
+     - Reliability. Patterns in the document cannot be ripped apart
+       and are reliably found. (If you look at the document fragment-wise
+       while it's being transmitted, you miss any pattern that spans
+       a fragment border) This is especially bad for patterns that do
+       serious HTML reformatting, as fragments are typically in the order
+       of 1500 bytes each.
+
+     - Flexibility: The re_filter gives you the choice whether you want
+       to replace only the pattern's first occurance or replace it globally.
+       This becomes meningless with fragments. (Solution possible, though.)
+
+    As the filter only processes objects of MIME type text/*, which are typically
+    rather small compared to binary multimedia (sic) type data, I don't think
+    that the disadvantage of delayed display of the first bytes is really grave.
+
+    What do you think?
+
+  - Is the choice between a radical (filter all) and semi-smart (filter only when
+    also crunching cookies) flexible enough? Should I really introduce yet another
+    configfile for specifying the domains to filter content from? Would anyone use
+    that?
+
+  - Should I use pcre as a shared library and work out a nice installation
+    automagic, or should the relevant functions be incorporated in re_filter.c?
+
+  - Even if yes, do we really want an extension that relies on an external library
+    like pcre?
+
+  - Any bugs, stupid parts in the code ?
+
+  - Cool suggestions for the re_filterfile? (PLEASE!)
+
+  - Should character set translation along the lines of Perl's 'tr' operator
+    be included?
+
+  - Is the whole feature just pathetic?
+
+FEEDBACK:
+
+    A whole lot of work has gone into this feature (the pcrs code was also
+    just written for this) and I'd really like to know if and how you like
+    it. Since I'm more of a perl than C programmer (and after doing so much
+    string manipulation in C I'm once again glad abaout that!), I'm sure there
+    is much to improve. Please send any suggestions/observations/hellos to
+    oes@paradis.rhein.de. I would also be very glad about any assistance for
+    a autoconf/make procedure for prcs.
+
+Well, have fun!
+--Andreas
+
+
+*****************************************************************************
+* Copied from old README.cygwin                                             *
+*****************************************************************************
+
+Id: README.cygwin,v 1.2 2001/04/29 23:16:29 rodney Exp
+
+
+What I did:  I saw too many "personalities" in IJB; so I
+ran the code through a couple of regexp's and then let XEmacs
+reformat the whole shebang!  The results is a uniform
+looking code base; aka. as if 1 person created the whole
+project.
+
+Why I did it:  (1) it is easier to maintain  (2) easier for
+a new person to make changes/additions  (3) it *looks* more
+professional  (4) IMHO, it is easier to read (this is very
+much a personal preference).
+
+What I propose: A IJB standards list be included in the
+distro and all source/patch checkins be checked for
+compliance.  We don't need to be an arse on this point, but
+submitters should make a valiant attempt to support the
+standards.
+
+Note: do not even try to diff my code with another code
+base, you will be overwhelmed.  After all, the regexps did a
+good bit of changing and XEmacs reformatter did a great deal
+more.
+
+One more note: these changes include conditional compilation for
+un?x (namely Linux), cygwin (un?x like compile for WIN32), and
+mingw32 (WIN32 like compilation w/o VC++).  Right now, all seems
+fully functional except cygwin.  The cygwin compile will work,
+but includes code to make it single threaded.  I need to debug
+the fork issues, but that will have to come later.
+
+
+Specific changes to expect:
+
+
+1: I've majorly reworked the Makefiles.  The existing Makefile was
+too *spaghetti* for me!  For one, I eliminated the "-I." from the
+include path (ugly).  Use #include "" for local directory files
+and #include <> for path found files (that's basic even to c).
+
+
+2: In accordance with #1, I changed #include "windows.h" to
+#include <windows.h> and #include <gnu_regex.h> to #include
+"gnu_regex.h".
+
+
+3: As part of my standards suggestions (to come later in this
+file), I added a standard comment block to every function.  There
+were too many functions with *no* comment and about 20 different
+styles to those that did.  This is an example of the block I used:
+/*********************************************************************
+ *
+ * Function    :  block_acl
+ *
+ * Description :  Block this request?
+ *                Decide yes or no based on ACL file.
+ *
+ * Parameters  :
+ *          1  :  src = Address the browser/user agent is requesting.
+ *          2  :  dst = The proxy or gateway address this is going to.
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     : 0 = FALSE (don't block) and 1 = TRUE (do block)
+ *
+ *********************************************************************/
+
+
+4: Some files prototyped like this:
+      void
+      func(param1)
+      int param1;
+      {
+      }
+and other like this:
+      void func(int param1)
+      {
+      }
+I made all look like the second.
+
+
+5: Made:
+      if(  to be  if (
+      while(  to be  while (
+      switch(  to be switch (
+      etc ...
+The former looks too much like a function call.
+
+
+6: Put braces on their own line and aligned under the
+reserved word:
+      if () {
+      } else {
+      }
+to be:
+      if ()
+      {
+      }
+      else
+      {
+      }
+The same for while, do, etc...
+
+
+7: Casted malloc in several places, e.g.:
+      p = malloc(n);
+to be:
+      p = (char *)malloc(n);
+This eliminates compiler warnings.
+
+
+8: Applied the Perl regexp patch and made it fully conditionally
+compiled (-DPCRS=TRUE).
+
+
+9: It *appears* that if MINGW32 sees a "main" function, it will
+try to link it and start with main (ala console mode).  Since I
+need MINGW32 to find WinMain instead, I conditionally changed
+"main" to "_main" (for MINGW32 only!).
+
+
+10: Changed popup.c to be killpopup.c.  This was necessary to
+clean up the Makefile.  Since there was an ini type file called
+"popup" and "popup.c", make got confused on target names.  No
+other ini file has a .c file with the same name, so I hope this
+isn't a big deal.  Plus, it fits its config variable
+(kill_all_popups) much better.
+
+
+11: Added:
+  /*
+    Local Variables:
+    tab-width: 3
+    end:
+  */
+to all .c and .h files.  I use 3 character tabs and this will make
+the files display correctly in Emacs editors.  This is just my
+default setting.  Perhaps I will filter all files via "expand
+-t3", so not to pi$$ everyone off.  Vi is capable of using 3
+character tabs, as I am sure VC++ would be.
+
+
+12: Several places included regexp code with out "#ifdef REGEX"
+which broke the ability to compile w/o regexp's.  I fixed the code
+and can compile w/o regexp (which I don't normally do, but now I
+*can*).
+
+
+13: In WinMain, changed:
+      pszLastTok = strchr(pszLastTok, ' ');
+to be:
+      pszLastTok = strchr(pszLastTok+1, ' ');
+The former causes an infinite loop with 2 or more parameters.
+
+
+14: Added my own strdup for Cygwin, see jcc.c for why.
+
+
+15: Added defines in the Makefile and this to jcc.h:
+      #define VERSION VERSION_MAJOR "." VERSION_MINOR "." VERSION_POINT
+This makes "update the numbers also in jcc.h manually" unnecessary
+(see your Makefile for this quote).
+
+
+16: Split the "inifiles" target in Makefile into separate targets,
+this way each file can be regenerated individually according to
+the same implicit rule.
+
+
+17: With the Makefile restructure, I can only provide for
+Cygwin/gcc.  Hopefully this is a bit cleaner and others can add
+their compilers w/o re-spaghetting the file.  I have provided
+several makefiles as examples only, I do not intend for the
+project to start maintaining multiple Makefiles.  Perhaps some of
+the platform specific Makefile code could be split out into
+separate files and we could use the "include" directive to read in
+the correct one.
+
+Better than this, let's get a configure.in guru on the project and
+dynamically create the Makefiles!
+
+
+18: In an effort to get this to market (you knew this was coming
+eh?), I am going to put the standards suggestions in another file
+and ship this one as is.  But then, you can probably guess most of
+the standards by the changes you see.
+
+
+19: Added a really quick and dirty "install" target to the
+Makefile.  This needs to be cleaned up and proper directories put
+in for each platform.
+
+
+-- release 1 (obsoleted) --
+
+
+20: Incorporated the TOGGLE and webDAV support patches into my
+Cygwin patch.  I added conditional compilation to both features.
+I changed "extern BOOL g_bToggleIJB;" to be of type "int".  This
+makes jcc.h independent of "windows.h".  The inclusion of such
+should not (and is not) necessary for compilation on all
+platforms.  Besides, BOOL is really only a char or an int anyway!
+
+
+21: Added a new ini!  I modified the usual un?x type config file
+to M$ type ini file for a Perl regexp compile.  This was necessary
+to call EditFile on the Perl regexp config file.  The new ini
+filename is "sregexp.ini" (naturally).  I then added menu items to
+edit the popup.ini and sregexp.ini files.
+
+
+22: I made "dot h" files for all the "dot c" files.  I used this
+command to do the *dirty* work:
+    grep -e "^[A-z]" *.c | sed -e "/=/d" -e "/^[^(]*$/d" \
+         -e "/^extern/d" -e "/^static/d" -e "/;$/d"
+
+And I made each "dot h" file be immune to multiple inclusion via
+conditional compilation.  Ie. the "jcc.h" file will only include
+itself if _JCC_H is undefined.
+
+After this was done, I compiled the project source by source and
+let the compiler tell me what each file was dependent on.  Once I
+got all the objects to compile, I included the new dependencies in
+the Makefiles.
+
+BTW, I intend to get the Makefile to be generated by a configure
+script.  Whether this is a GNU "configure.in" type file or a shell
+script, I do not know.  All I do know is that this is a must for a
+"Go/No go" type decision.  We cannot proceed with the philosophy
+"leave it up to the user to get it to work".
+
+
+23: I broke out the code to load the config file from main.  I put
+this code into a function called load_config.  I made this routine
+be called from a signal "HUP".  This means we can restart
+junkbusters from the command line or from the daemon script via
+"restart" without actually killing it and restarting it.  This is
+common behavior to un?x daemons (see inetd for example).  I fixed
+the junkbusters.init script to take advantage of this.  I intend
+to make a M$ menu complement to this as soon as I can.
+
+
+24: BTW, if you have not already noticed by my postings and/or
+code, I have added patches and made them all conditionally
+compiled.  Ie. #ifdef TOGGLE, #ifdef WEBDAV, #ifdef PCRS, etc...
+I think that all extensions to IJB should be submitted in this
+way.  Not only can you compile IJB to be as "tight" as you want,
+it also gives the user a "smorgasbord" of options to
+choose from.  This is quite common in the free software world (you
+need look no farther than emacs to see this) and provides maximum
+flexibility.
+
+
+25: As promised, I obsoleted the "ijbw32.ini" file.  I was a bit
+confused by the "close-behaviour=1" entry.  It seems to me that it
+duplicated the "close-button-minimizes=1" entry.  And (by looking
+at the code) it was unused.  Anyway, I eliminated the "ijbw32.ini"
+file and assimilated the settings into the config file.  Bye Bye
+"ijbw32.ini", hello "config" (aka. don't unnecessarily duplicate
+files and/or data types).
+
+
+26: Eliminated re_filter.c.  This only defined
+(un)load_re_filterfile and re_process_buffer.  I moved
+(un)load_re_filterfile to loaders.c and re_process_buffer to
+filters.c. I also modified the Makefiles to reflect this.  In the
+doing, I modified the loader and unloader to use the "files"
+variable and moved joblist to "re_filterfile_spec" struct.  I
+added "plist" to the client_state so that all Perl regexp code
+could find the latest parsing of the re_filterfile ini.
+
+This is in keeping with the IJB data structures philosophies.
+
+
+27: Eliminated acl.c.  This (as pcre) only defined
+(un)load_aclfile and block_acl.  I moved (un)load_aclfile to
+loaders.c and block_acl to filters.c.  I also modified the
+Makefiles to reflect this.
+
+
+28: Since I created "dot h" files for all the "dot c" files, I
+eliminated all the "extern ...variable;" and all the "extern
+...function;" statements that I could find in the "dot c" files.
+Instead, I included the proper "dot h" files to do this for us.
+
+
+29: Corrected the "install" Makefile target for un?x.  I will do
+the same for WIN32 targets.
+
+
+30: Note on the "TOGGLE" patch: since I made IJB fully restartable
+via a NOHUP signal; I thought the TOGGLE patch should apply to
+both un?x and WIN32.  Thus, I eliminated the WIN32 dependencies in
+that patch and added "toggle" to the config file.  Now everything
+works fine for either platform.  Still to come is a restart menu
+command in WIN32 (See: note 23).
+
+
+31: Just a possible programmer note, we REALLY need a generic
+linked list module.  Since text lists, client states, filter
+files, etc... implement list creation and destruction over and
+over; I suggest a generic list that can handle *any* type of list
+(ala template classes in C++).  If this module included an
+iterator (of sorts), we could eliminate the myriad of "for ( top=x;
+NULL != x->next; x=x->next )" type statements that are all over
+IJB.
+
+After all, this was taught in the basic "Intro to Data Types"
+class (for all you CS majors).
+
+
+32: Renamed all of the .INI files to be .TXT files.  I did this
+because the .INI files were NOT *really* ini files; which
+potentially be confusing.  I used the .TXT extension to make sure
+that EditFile still worked.
+
+
+33: Removed the "initialed comments", such as "/* swa */".  This
+leads to less readable code (because it becomes fragmented) and
+retains the "multiple personality" syndrome.  Comments such as
+this can always be figured out from the versioning system.  Also,
+these comments really should be pooled in one place : the README
+files.
+
+
+34: Perhaps we should break with the current versioning tactic of 
+a "tail version" and start fresh.  Perhaps a new major version
+release is in order?  Version = 3.0.0?
+
+
+35: Added a "Accept-Encoding: gzip" cruncher.  If a stream is
+compressed via gzip (Netscape specific I think), then it cannot
+be modified with Perl regexps.  So I added this as an option in
+the Makefiles.
+
+
+36: As promised in one of my postings, I have make a
+configure-esk script to generate the Makefiles.  I would still
+like to have a full blown configure.in compatible system, but this 
+will do in the meantime.  Note: this configure script covers
+linux, cygwin, and mingw32.  At this point I do not have VC++ to
+test any of my changes.  But the configure script should be
+flexible enough to handle this platform.
+
+
+--
+
+Please give any feedback to the ijb egroups and, if you feel you
+need quicker contact, CC me at IwantToKeepAnon@yahoo.com
+
+Let me say once more, this has a *lot* of changes and may (aka
+WILL) break a lot of existing patches.  But I hope the "idea" will
+catch on.  Perhaps this could be made the baseline code base and
+other patches added and standardized later.
+
+*****************************************************************************
+* Date:        7 May 2001                                                   *
+* Version:     ??                                                           *
+* Description: Changes for MS Visual C++                                    *
+* Author:      Jon Foster <jon@jon-foster.co.uk>                            *
+*****************************************************************************
+(Based on Stromlund's version 0.20)
+
+I have made several changes to make this compile under VC++ 97, and add new
+features.
+
+Code changes:
+
+1) If you disable IJB (using the TOGGLE patch) it now turns PCRS off.
+2) "Missing function prototype" warnings have been corrected by adding
+   appropriate #include statements
+3) The _DIST_URL define removed and hardcoded.  There are hardcoded URLs all 
+   over the place that need fixing - one more doesn't matter.  We do really 
+   need to come up with a long-term solution though.  (Suggestion: Host a 
+   redirector on the SourceForge web space.  e.g 
+   "http://ijbswa.sourceforge.net/redirect.php?ver=2.0.2-10&target=faq",
+   "http://ijbswa.sourceforge.net/redirect.php?ver=2.0.2-10&target=download",
+   etc.  This allows us to move the pages around easily, and the SourceForge
+   space can be maintained by anyone who's interested, it's not tied to a 
+   particular individual.  This is similar to the approach taken by 
+   Microsoft and Netscape in their browsers.)
+4) New file ijbconfig.h is #included everywhere.  This provides me with a
+   place to define VERSION, PCRS, etc.  You can still define VERSION_xxx
+   on the command line, but the other defines are in the header file.
+   There were just too many #defines - so many that the VC++ 97 IDE 
+   broke when I tried to define them on the command line.  We probably 
+   should fix the configure script so that it modifies this file.
+5) Deleted empty file afxres.h - we needed to use the VC++ system header 
+   file of that name.  However, it's easier to just delete it and put 
+   the relevent #defines in w32res.h.
+6) New #define: NO_PROGRAM_NAME_DISPLAY uses "IJB" as the program name in 
+   the log file instead of "H:\Documents and Settings\Administrator\My 
+   Documents\Prog\VC\ijb2\Release\junkbuter.exe" or similar.  The reason 
+   for this should be obvious!
+7) New #define: STATISTICS enables the statistics feature
+8) Statistics is thread-safe, I think.  However, loading up the
+   statistics page now counts as a blocked request.
+9) New, shorter message if a setting in the config file is recognised 
+   but unsupported by the current build.  It doesn't have "WARNING:" in
+   front of it either.  We may want to actually take this message out 
+   and have it just silently ignore these entries.
+10) New feature: #define SPLIT_PROXY_ARGS and the show-proxy-settings 
+    page will split each file out to a seperate page.  This is 
+    because the files are quite big, and having to do 1 extra click to 
+    get to them is no problem.  This #define also disables the 
+    suppress_blocklists feature (because I believe the original intent 
+    of suppress_blocklists was similar?).  It also saves memory by 
+    reading the config files to generate the HTML on the fly, rather 
+    than storing prepared HTML constantly in memory.
+11) Marked global constants with "const" attribute.  This has a 
+    knock-on effect on pointers in function prototypes, so these have
+    also been marked const where needed.
+12) Rewrote encode.c to have tables pre-initialized, so it can be 
+    marked constant.  Also split into 3 distinct functions so that
+    the tables (which are realy an implementation detail) are not
+    visible outside that file.
+13) Changes to how files are reloaded when you reload the config 
+    file.  Previous method didn't free memory (or if you uncommented 
+    the free() calls, it was not thread-safe.)  It is now handled 
+    automatically - files are reloaded whenever the filename to 
+    read changes, or the file's timestamp changes.  The code in
+    loaders.c which handles this test has been moved to a single
+    utility function.
+14) killpopup changes:
+     * Only compiled if you #define KILLPOPUPS
+     * Call to filter_popups() moved from read_socket() to chat().
+     * Writing 1 past end of buffer bug fixed.
+     * It was scanning the whole buffer even if only partially filled.
+     * Moved load/unload to loaders.c and changed file handling to 
+       follow standard.
+15) Auto-detect whether we want an image or HTML implemented for 
+    Microsoft IE.  :-)
+    There doesn't seem to be a way to tell with the latest build 
+    of Mozilla. :-(
+16) Image file code conditionally compiled.
+17) Provided option (SPLIT_PROXY_ARGS) to split the show-proxy-args
+    page into a main page, and then a page for each config file.  
+    This option will also save memory by loading the files when 
+    required for display, rather than saving them in memory when
+    they are initially loaded.
+18) Force page loading ("noijb.") patch applied.  #define FORCE_LOAD
+
+
+Packaging changes:
+
+1) PCRE 3.4 (less it's test and demo programs) is now included in the 
+   pcre directory.  It will be statically linked with Junkbuster.  (On 
+   win32, DLLs cause a lot of hassle - with a library this small it isn't 
+   worth it.  I don't know if it would be better to dynamically link under
+   UNIX?)
+2) junkbustr.dsp and junkbustr.dsw VC++97 project and workspace files are
+   included.
+3) win32build/junkbustr.exe Win32 binary is included.  It should not require
+   any DLLs.  It was compiled with all features supported.
+4) All README.xyz files put together in this file.
+5) Unused files (acl.c, pthread.c, ...) deleted.
+6) My block & cookie files used (based on the Waldherr ones).
+
+Known bug: The Adobe Acrobat 4 plug-in fails when I try to view PDF files in
+MSIE.  Workaround: disable "web browser integration" in the Adobe Acrobat 
+settings.
+
+*****************************************************************************
+* Date:        14 May 2001 (early morning)                                  *
+* Version:     Reported as 2.9.0                                            *
+* Description: Various updates                                              *
+* Author:      Jon Foster <jon@jon-foster.co.uk>                            *
+*****************************************************************************
+
+1)  Now use PCRE, not GNU REGEX.  I have not yet had chance to check the
+    syntax of the block/image/cookie file to ensure that they match what
+    is expected - however they seem to work.
+2)  Replaced "configure" script with one generated by "autoconf".  Also 
+    use a header "config.h" (was ijbconfig.h in my previous release) for 
+    the #defines.  "config.h" is now generated with "autoheader" from 
+    "acconfig.h" and "configure.in".  (Note that to install you do not
+    need autoconf or autoheader - just run "./configure".)
+    To see command-line options, run "./configure --help".
+    This is my first ever autoconf script, so it has some rough edges
+    (how PCRE is handled is the roughest).
+3)  Error logging code replaced with new module errlog.c, based on the
+    one from JunkBusterMT (but with the threading code removed).
+4)  Most of Rodney's 0.21 and 0.21A patches applied. (Marked *).  I did not
+    apply all of these, since I had already independently done conditional
+    popup file, conditional image file, and integration of popup code.
+5*) ACL, Jar and trust files conditionally compiled.
+6*) New source file headers.
+7*) Various cosmetic changes.  (But I have not consistently ordered the 
+    config files - I think that's worthwhile, but it's 1am and I want to
+    get this released!)
+8*) RCS tags on .h files.
+9)  RCS tags are const char[] rather than const char *.  (Saves 4 bytes
+    per tag ;-)
+10) VC++ project files renamed to vc_junkbuster.*.
+11) show-proxy-args now shows status of all conditionals, not just REGEX
+12) Various functions moved around.  Most notably all the system-specific
+    sockets code which was spread between jcc.c, bind.c, and connect.c,
+    has been moved to "jbsockets.c".  The non-system-specific code from
+    connect.c and socks4.c has been movet to "gateway.c".  Also, the
+    config file loader and the global variables it writes to have been
+    moved to "loadcfg.c".  (Maybe this should go into loaders.c?)
+    And candidate for the "worst filename ever" award is "miscutil.c",
+    which contains, well, miscellaneous utility functions like zalloc.
+    (Suggestions for a better name for this file are welcome!)
+13) Loaders now use a common function to read a line and skip comments,
+    and this function also stores the proxy_args.
+14) Added ./junkbuster --help     (Not for Win32 GUI)
+15) Added ./junkbuster --version  (Not for Win32 GUI)
+16) Win32 resources are now all marked as "U.S. English", rather than
+    being a mix of "U.S. English", "U.K. English" and "Irish English".
+17) Version number changes to 2.9.0
+
+Known bugs:
+- See (1) above about blockfiles.
+- Sending SIGHUP (under Red Hat Linux 7.1) causes a crash.  v0.21A hangs
+  after a SIGHUP.  This needs investigating, but pthreads support will 
+  almost certainly help here, so it may not be worth investigating
+  immediately.
+- Compiling with shared system pcre and pcreposix libraries is supported
+  via a switch to configure, but completely untested.
+
+Please note that there are now 2^14 == 16384 combinations of conditional 
+defines, and 4 major compilers (VC, Linux, mingw32, cygwin) for a total 
+of 65536 different builds.  We cannot possibly test all of them!  My 
+standard build is "everything on", and I've tested that on each compiler,
+along with a few variants.  You may uncover new bugs (probably compiler 
+errors) if you use an exotic combination of switches.
+
+*****************************************************************************
+* Date:        14 May 2001                                                  *
+* Version:     2.9.1                                                        *
+* Description: Various updates                                              *
+* Author:      Andreas S. Oesterhelt <oes@oesterhelt.org>                   *
+*****************************************************************************
+(From his e-mail:)
+
+ - in parsers.c, fixed two #ifdef FORCE to #ifdef FORCE_LOAD
+   (BTW: I think FORCE is precise enough, since loading remote
+   data is the whole purpose of a proxy..)
+ - Set the FORCE_PREFIX (back) to 'IJB-FORCE-LOAD-'. While 'noijb.'
+   is more elegant and looks like a hostname in the URL, it doesn't
+   make clear to the inexperienced user that the proxy is bypassed. It
+   also has a higher name collision risk.
+ - Filled in the function header templates for my functions in
+   parsers.c (again). They obviously got lost in our current
+   patch war ;-)
+ - Cut the credit for the Â§-referrer-option from the config file,
+   that Stefan had placed there.
+ - Improved the re_filterfile 
+
+*****************************************************************************
+* Date:        14 May 2001                                                  *
+* Version:     2.9.2                                                        *
+* Description: FORCE patch (again!)                                         *
+* Author:      Andreas S. Oesterhelt <oes@oesterhelt.org>                   *
+*****************************************************************************
+(These notes written by Jon)
+
+- Andreas applied the latest version of the FORCE patch.
+
+*****************************************************************************
+* Date:        14 May 2001 (late afternoon)                                 *
+* Version:     2.9.3                                                        *
+* Description: Various updates                                              *
+* Author:      Jon Foster <jon@jon-foster.co.uk>                            *
+*****************************************************************************
+
+1) Incorporated updates from current CVS tree, including:
+   - Amiga support (completely untested by me - I don't have an Amiga)
+   - "tinygif 3" support (redirects blocked images to a specified URL, so
+     the browser doesn't have to load and cache many copies of the same
+     image).
+   - one case where there were both local and global "referrer" variables
+     (yuck!) clarified by renaming the local one to "refer".
+   - Fixed some places where close() was used instead of close_socket().
+   Thanks to Jörg Strohmayer (joergs at users.sourceforge.net) for these.
+2) Temporary hack to get FORCE_LOAD to work with IE.  I just lowercased the
+   FORCE_LOAD_PREFIX.  Needs fixing properly.
+3) Most URLs hardcoded into JunkBuster were changed to go through a script
+   e.g. http://ijbswa.sourceforge.net/redirect.php?v=2.9.3&to=faq
+   The only other URLs left are the GNU GPL:
+     http://www.fsf.org/copyleft/gpl.html
+   and the home page:
+     http://ijbswa.sourceforge.net/
+   ... and various URLs which will be intercepted by JunkBuster anyway.
+   TODO: Still need to do something with the URLs in JunkBuster Corp's 
+   copyright/trademark notice on the bottom of the show-proxy-args page.
+4) PCRE or GNU Regex is now a #define option.
+
+*****************************************************************************
+* End of file                                                               *
+*****************************************************************************
+
diff --git a/doc/gpl.html b/doc/gpl.html
new file mode 100644 (file)
index 0000000..7f0b610
--- /dev/null
@@ -0,0 +1,567 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\r
+<html>\r
+<head>\r
+<!-- Copyright 1996-8 Junkbusters Corporation -->\r
+<!-- This work comes with NO WARRANTY -->\r
+<!-- It may be redistributed and modified under the GNU GPL-->\r
+<!-- See the body of http://www.junkbusters.com/ht/en/gpl.html for details-->\r
+<!-- Junkbusters is a registered trade mark of Junkbusters Corporation -->\r
+<!-- Generated 1998/10/31 03:58:25 UTC -->\r
+<meta name="Generator" content="Junkbusters Ebira $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $">\r
+<!-- Document  ID: $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $ -->\r
+<title>\r
+The GNU General Public License\r
+</title>\r
+<base href="http://www.junkbusters.com/ht/en/gpl.html">\r
+<meta name="description" content="We did not write the GPL: the Free Software Foundation did | The GPL allows copying and changing of copyrighted documents | Version 2, June 1991 | Preamble | GNU General Public License: Terms and Conditions for Copying, Distribution and Modification | Appendix: How to Apply These Terms to Your New Programs">\r
+<meta name="keywords" content="stop, junk, busters, junkbusters, junkbuster, mail, email, e-mail, direct, spam, spamoff, declare, telemarketing, telemarketers, privacy, sharing, names, renting, direct, marketing, database, databases, junk mail, lists, environment, conservation, recycling, catalogs, consumer, sending, opt out ">\r
+<link rel="next" href="precre.html">\r
+<link rel="previous" href="precre.html">\r
+<link rel="contents" href="toc.html">\r
+</head>\r
+<body bgcolor="#f8f8f0" link="#000078" alink="#ff0022" vlink="#787878">\r
+<p align="center">\r
+<a name="top_of_page" href="legal.html#marks">\r
+<img border=0 width=160 height=34 src="/images/trans_tn.gif" alt="Junkbusters"></a>\r
+</p>\r
+\r
+<center>\r
+<h1>The GNU General Public License\r
+</h1>\r
+</center>\r
+<!-- Translators: no -->\r
+<center>\r
+<h2><a name="notus"><font face="arial, helvetica">\r
+We did not write the GPL: the Free Software Foundation did\r
+</font></a>\r
+</h2>\r
+</center>\r
+\r
+<h3><a name="allows" href="/cgi-bin/gp?pg=gpl&pr=allows"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+The GPL allows copying and changing of copyrighted documents\r
+</h3>\r
+<p>\r
+<a name="fsf">The Free Software Foundation</a>\r
+<a href="http://www.fsf.org/fsf/fsf.html">(FSF)</a>\r
+is a non-profit institution\r
+that designed the GNU General Public License (GPL) to promote the\r
+publication of free software.\r
+The GPL is used by thousands of programmers\r
+who want to give others the right to copy and modify\r
+the source code of their programs. Millions of people benefit from this.\r
+<p>\r
+<a name="junkbuster">We use the GPL</a>\r
+to allow everyone to use, copy and modify the\r
+<a href="ijb.html">Internet Junkbuster</a>\r
+as they wish.\r
+<a name="separate">Companies can use it for commercial purposes,</a>\r
+but they are not permitted to use it in products that they claim\r
+as their property\r
+without negotiating a separate agreement with us beforehand.\r
+<p>\r
+<a name="text">The GPL</a>\r
+<a href="http://dsl.org/copyleft/">can also be used</a>\r
+on documents written in human languages.\r
+We give everyone permission to use everything on our web site under the GPL.\r
+This means that you do not have to break copyright laws in order\r
+to print a page or email a screen of the text to someone, for example.\r
+Many sites do not permit you to do these things.\r
+<p>\r
+<a name="best">If you have a home page,</a>\r
+we recommend that you consider using the GPL to\r
+allow others the right to copy and use all the documents you create for it.\r
+If you just mark a page as copyright, they won't even\r
+legally be able to print it.\r
+If you don't state you are its copyright owner,\r
+they could change it slightly and claim it as their own property. \r
+By marking it with both copyright and GPL notices\r
+you allow them to copy it but not to claim\r
+anything derived from it as their own.\r
+<p>\r
+<a name="protect">The GPL protects your</a>\r
+<a href="declare.html">J<small>UNK<i>BUSTERS</i></small> D<small>ECLARATION</small></a>,\r
+<a href="spamoff.html">Spam Offer</a>,\r
+and all documents from us that you publish on your home page\r
+or distribute to direct marketers by any other means.\r
+By making your\r
+D<small>ECLARATION</small>\r
+available to them under the GPL, you are\r
+<a href="precre.html#gpl">permitting them use to it, but never to claim it as their property,</a>\r
+even if they transform it.\r
+<p>\r
+<a name="rest">The</a>\r
+remainder of this page is the text of the GPL.\r
+As legal documents go it's relatively clear,\r
+but unfortunately it's fairly long because it has to cover\r
+a lot of details specific to computer programs\r
+that may not be relevant to\r
+D<small>ECLARATION</small>s.\r
+The hypertext links are ours, and should not be misinterpreted\r
+as an indication of emphasis by the FSF.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<center>\r
+<h2><a name="v2"><font face="arial, helvetica">\r
+Version 2, June 1991\r
+</font></a>\r
+</h2>\r
+</center>\r
+<blockquote>\r
+<a name="crn">Copyright 1989, 1991</a>\r
+<br>\r
+<a name="address">Free Software Foundation, Inc.</a>\r
+<br>\r
+675 Mass Ave.\r
+<br>\r
+Cambridge, MA 02139\r
+<br>\r
+USA\r
+</blockquote>\r
+<a name="changing">Everyone</a>\r
+is permitted to copy and distribute verbatim copies\r
+of this license document, but changing it is not allowed.\r
+\r
+<h3><a name="pream" href="/cgi-bin/gp?pg=gpl&pr=pream"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Preamble\r
+</h3>\r
+<p>\r
+The licenses for most software are designed to take away your\r
+freedom to share and change it.  By contrast, the GNU General Public\r
+License is intended to guarantee your freedom to share and change free\r
+software--to make sure the software is free for all its users.  This\r
+General Public License applies to most of the Free Software\r
+Foundation's software and to any other program whose authors commit to\r
+using it.  (Some other Free Software Foundation software is covered by\r
+the GNU Library General Public License instead.)  You can apply it to\r
+your programs, too.\r
+<p>\r
+<a name="freedom">When we speak of free software,</a>\r
+we are referring to freedom, not\r
+price.  Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+this service if you wish), that you receive source code or can get it\r
+if you want it, that you can change the software or use pieces of it\r
+in new free programs; and that you know you can do these things.\r
+<p>\r
+<a name="forbid">To protect your rights,</a>\r
+we need to make restrictions that forbid\r
+anyone to deny you these rights or to ask you to surrender the rights.\r
+These restrictions translate to certain responsibilities for you if you\r
+distribute copies of the software, or if you modify it.\r
+<p>\r
+<a name="allrights">For example,</a>\r
+if you distribute copies of such a program, whether\r
+gratis or for a fee, you must give the recipients all the rights that\r
+you have.  You must make sure that they, too, receive or can get the\r
+source code.  And you must show them these terms so they know their\r
+rights.\r
+<p>\r
+<a name="steps">We protect your rights with two steps:</a>\r
+(1) copyright the software, and\r
+(2) offer you this license which gives you legal permission to copy,\r
+distribute and/or modify the software.\r
+<p>\r
+<a name="protection">Also,</a>\r
+for each author's protection and ours, we want to make certain\r
+that everyone understands that there is no warranty for this free\r
+software.  If the software is modified by someone else and passed on, we\r
+want its recipients to know that what they have is not the original, so\r
+that any problems introduced by others will not reflect on the original\r
+authors' reputations.\r
+<p>\r
+<a name="threat">Finally,</a>\r
+any free program is threatened constantly by software\r
+patents.  We wish to avoid the danger that redistributors of a free\r
+program will individually obtain patent licenses, in effect making the\r
+program proprietary.  To prevent this, we have made it clear that any\r
+patent must be licensed for everyone's free use or not licensed at all.\r
+<p>\r
+<a name="terms">The precise terms and conditions</a>\r
+for copying, distribution and\r
+modification follow.\r
+</p>\r
+\r
+<h3><a name="tnc" href="/cgi-bin/gp?pg=gpl&pr=tnc"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+GNU General Public License: Terms and Conditions for Copying, Distribution and Modification\r
+</h3>\r
+<p>\r
+<a name="applies">O.</a>\r
+This License applies to any program or other work which contains\r
+a notice placed by the copyright holder saying it may be distributed\r
+under the terms of this General Public License.  The "Program", below,\r
+refers to any such program or work, and a "work based on the Program"\r
+means either the Program or any derivative work under copyright law:\r
+that is to say, a work containing the Program or a portion of it,\r
+either verbatim or with modifications and/or translated into another\r
+language.  (Hereinafter,\r
+<a href="bus-ops.html#trans">translation</a>\r
+is included without limitation in\r
+the term "modification".)  Each licensee is addressed as "you".\r
+<p>\r
+<a name="scope">Activities</a>\r
+<a href="faqs.html#copying">other than copying, distribution and modification are not covered by this License;</a>\r
+they are outside its scope.  The act of\r
+running the Program is not restricted, and the output from the Program\r
+is covered only if its contents constitute a work based on the\r
+Program (independent of having been made by running the Program).\r
+<p>\r
+<a name="depends">Whether that is true depends on what the Program does.</a>\r
+<br><ol  type="1">\r
+<li>\r
+<a name="verbatim">You may copy</a>\r
+and distribute verbatim copies of the Program's\r
+source code as you receive it, in any medium, provided that you\r
+conspicuously and appropriately publish on each copy an appropriate\r
+copyright notice and disclaimer of warranty; keep intact all the\r
+notices that refer to this License and to the absence of any warranty;\r
+and give any other recipients of the Program a copy of this License\r
+along with the Program.\r
+<p>\r
+<a name="fee">You may charge a fee</a>\r
+for the physical act of transferring a copy, and\r
+you may at your option offer warranty protection in exchange for a fee.\r
+<li>\r
+<a name="modify">You may modify</a>\r
+your copy or copies of the Program or any portion\r
+of it, thus forming a work based on the Program, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+<br><ol  type="a">\r
+<li>\r
+<a name="notices">You must cause</a>\r
+the modified files to carry prominent notices\r
+stating that you changed the files and the date of any change.\r
+<li>\r
+<a name="nocharge">You must</a>\r
+cause any work that you distribute or publish, that in\r
+whole or in part contains or is derived from the Program or any\r
+part thereof, to be licensed as a whole at no charge to all third\r
+parties under the terms of this License.\r
+<li>\r
+<a name="interactive">If the modified program</a>\r
+normally reads commands interactively\r
+when run, you must cause it, when started running for such\r
+interactive use in the most ordinary way, to print or display an\r
+announcement including an appropriate copyright notice and a\r
+notice that there is no warranty (or else, saying that you provide\r
+a warranty) and that users may redistribute the program under\r
+these conditions, and telling the user how to view a copy of this\r
+License.  (Exception: if the Program itself is interactive but\r
+does not normally print such an announcement, your work based on\r
+the Program is not required to print an announcement.)\r
+</ol>\r
+<p>\r
+<a name="sections">These requirements</a>\r
+apply to the modified work as a whole.  If\r
+identifiable sections of that work are not derived from the Program,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works.  But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Program, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote it.\r
+<p>\r
+<a name="intent">Thus,</a>\r
+it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Program.\r
+<p>\r
+<a name="aggregation">In addition,</a>\r
+mere aggregation of another work not based on the Program\r
+with the Program (or with a work based on the Program) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+<li>\r
+<a name="exeutable">You may copy</a>\r
+and distribute the Program (or a work based on it,\r
+under Section 2) in object code or executable form under the terms of\r
+Sections 1 and 2 above provided that you also do one of the following:\r
+<br><ol  type="a">\r
+<li>\r
+<a name="medium">Accompany it</a>\r
+with the complete corresponding machine-readable\r
+source code, which must be distributed under the terms of Sections\r
+1 and 2 above on a medium customarily used for software interchange; or,\r
+<li>\r
+<a name="written">Accompany it with a written offer,</a>\r
+valid for at least three\r
+years, to give any third party, for a charge no more than your\r
+cost of physically performing source distribution, a complete\r
+machine-readable copy of the corresponding source code, to be\r
+distributed under the terms of Sections 1 and 2 above on a medium\r
+customarily used for software interchange; or,\r
+<li>\r
+<a name="distrib">Accompany it</a>\r
+with the information you received as to the offer\r
+to distribute corresponding source code.  (This alternative is\r
+allowed only for noncommercial distribution and only if you\r
+received the program in object code or executable form with such\r
+an offer, in accord with Subsection b above.)\r
+</ol>\r
+<p>\r
+<a name="preferred">The source code</a>\r
+for a work means the preferred form of the work for\r
+making modifications to it.  For an executable work, complete source\r
+code means all the source code for all modules it contains, plus any\r
+associated interface definition files, plus the scripts used to\r
+control compilation and installation of the executable.  However, as a\r
+special exception, the source code distributed need not include\r
+anything that is normally distributed (in either source or binary\r
+form) with the major components (compiler, kernel, and so on) of the\r
+operating system on which the executable runs, unless that component\r
+itself accompanies the executable.\r
+<p>\r
+<a name="access">If distribution of executable or object code is made</a>\r
+by offering\r
+access to copy from a designated place, then offering equivalent\r
+access to copy the source code from the same place counts as\r
+distribution of the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+<li>\r
+<a name="otherwise">You may not copy,</a>\r
+modify, sublicense, or distribute the Program\r
+except as expressly provided under this License.  Any attempt\r
+otherwise to copy, modify, sublicense or distribute the Program is\r
+void, and will automatically terminate your rights under this License.\r
+However, parties who have received copies, or rights, from you under\r
+this License will not have their licenses terminated so long as such\r
+parties remain in full compliance.\r
+<li>\r
+<a name="voluntary">You are not required</a>\r
+to accept this License, since you have not\r
+signed it.  However, nothing else grants you permission to modify or\r
+distribute the Program or its derivative works.  These actions are\r
+prohibited by law if you do not accept this License.  Therefore, by\r
+modifying or distributing the Program (or any work based on the\r
+Program), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Program or works based on it.\r
+<li>\r
+<a name="redistrib">Each time you redistribute</a>\r
+the Program (or any work based on the\r
+Program), the recipient automatically receives a license from the\r
+original licensor to copy, distribute or modify the Program subject to\r
+these terms and conditions.  You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties to\r
+this License.\r
+<li>\r
+<a name="patent">If, as a consequence of a court judgment</a>\r
+or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Program at all.  For example, if a patent\r
+license would not permit royalty-free redistribution of the Program by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Program.\r
+<p>\r
+<a name="invalid">If any portion</a>\r
+of this section is held invalid or unenforceable under\r
+any particular circumstance, the balance of the section is intended to\r
+apply and the section as a whole is intended to apply in other\r
+circumstances.\r
+<p>\r
+<a name="induce">It is not the purpose</a>\r
+of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system, which is\r
+implemented by public license practices.  Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+<p>\r
+<a name="clarify">This section</a>\r
+is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+<li>\r
+<a name="geog">If the distribution</a>\r
+and/or use of the Program is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Program under this License\r
+may add an explicit geographical distribution limitation excluding\r
+those countries, so that distribution is permitted only in or among\r
+countries not thus excluded.  In such case, this License incorporates\r
+the limitation as if written in the body of this License.\r
+<li>\r
+<a name="revise">The Free Software Foundation</a>\r
+may publish revised and/or new versions   \r
+of the General Public License from time to time.  Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+Each version is given a distinguishing version number.  If the Program\r
+specifies a version number of this License which applies to it and "any\r
+later version", you have the option of following the terms and conditions\r
+either of that version or of any later version published by the Free\r
+Software Foundation.  If the Program does not specify a version number of\r
+this License, you may choose any version ever published by the Free Software\r
+Foundation.\r
+<li>\r
+<a name="permission">If you wish to incorporate parts</a>\r
+of the Program into other free\r
+programs whose distribution conditions are different, write to the author\r
+to ask for permission.  For software which is copyrighted by the Free\r
+Software Foundation, write to the Free Software Foundation; we sometimes\r
+make exceptions for this.  Our decision will be guided by the two goals\r
+of preserving the free status of all derivatives of our free software and\r
+of promoting the sharing and reuse of software generally.\r
+<p>\r
+<a name="nowarr">NO WARRANTY</a>\r
+<li>\r
+<a name="foc">BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,</a>\r
+THERE IS NO WARRANTY\r
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\r
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\r
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\r
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\r
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\r
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\r
+REPAIR OR CORRECTION.\r
+<li>\r
+<a name="liable">IN NO EVENT UNLESS REQUIRED</a>\r
+BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\r
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\r
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\r
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\r
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\r
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\r
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGES.\r
+</ol>\r
+END OF TERMS AND CONDITIONS\r
+</p>\r
+\r
+<h3><a name="append" href="/cgi-bin/gp?pg=gpl&pr=append"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Appendix: How to Apply These Terms to Your New Programs\r
+</h3>\r
+<p>\r
+If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+<p>\r
+<a name="attach">To do so,</a>\r
+attach the following notices to the program.  It is safest\r
+to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+<blockquote>\r
+&lt;one line\r
+to give the program's name and a brief idea of what it\r
+does.&gt;\r
+Copyright (C) 19yy\r
+&lt;name of\r
+author&gt;\r
+<p>\r
+<a name="free">This program is free software;</a>\r
+you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+<p>\r
+<a name="merchant">This program</a>\r
+is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+<p>\r
+<a name="ifnot">You should</a>\r
+have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+</blockquote>\r
+<p>\r
+<a name="contact">Also add</a>\r
+information on how to contact you by electronic and paper mail.\r
+<p>\r
+<a name="short">If the program is interactive,</a>\r
+make it output a short notice like this\r
+when it starts in an interactive mode:\r
+<blockquote>\r
+Gnomovision version 69, Copyright (C) 19yy name of author\r
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+This is free software, and you are welcome to redistribute it\r
+under certain conditions; type `show c' for details.\r
+</blockquote>\r
+<p>\r
+<a name="hypo">The hypothetical</a>\r
+commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License.  Of course, the commands you use may\r
+be called something other than `show w' and `show c'; they could even be\r
+mouse-clicks or menu items--whatever suits your program.\r
+<p>\r
+<a name="disclaimer">You should also get your employer</a>\r
+(if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the program, if\r
+necessary.  Here is a sample; alter the names:\r
+<blockquote>\r
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program\r
+`Gnomovision' (which makes passes at compilers) written by James Hacker.\r
+\r
+&lt;signature\r
+of\r
+Ty Coon&gt;,\r
+1 April 1989\r
+<br>\r
+Ty Coon, President of Vice\r
+</blockquote>\r
+<p>\r
+<a name="library">This General Public License</a>\r
+does not permit incorporating your program into\r
+proprietary programs.  If your program is a subroutine library, you may\r
+consider it more useful to permit linking proprietary applications with the\r
+library.  If this is what you want to do, use the GNU Library General\r
+Public License instead of this License.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<font face="arial, helvetica">\r
+<a rel="begin" href="index.html">Home</a> <font color="#ff0000">\r
+<b> &#183; </b></font>\r
+<a rel="next" href="precre.html">Next</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="lopt.html">Site Map</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="legal.html">Legal</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkdata.html">Privacy</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="cookies.html">Cookies</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijb.html">Banner Ads</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="telemarketing.html">Telemarketing</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkmail.html">Mail</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkemail.html">Spam</a>\r
+\r
+</font><form action="/cgi-bin/search" method="GET">\r
+<input type="text" name="q" size=60 maxlength=120 value="">\r
+<input type="submit" value="Search"></form>\r
+<small>\r
+<small>\r
+<p>\r
+<a href="legal.html#copy">Copyright</a> &#169; 1996-8 Junkbusters\r
+<a href="legal.html#marks">&#174;</a> Corporation.\r
+Copying and distribution permitted under\r
+the <a href="gpl.html"><small>GNU</small></a>\r
+General Public License.\r
+</small>\r
+<tt>\r
+1998/10/31\r
+http://www.junkbusters.com/ht/en/gpl.html\r
+</tt>\r
+<address><kbd>webmaster&#64;junkbusters.com</kbd></address>\r
+</small>\r
+</body>\r
+</html>\r
diff --git a/doc/ijbfaq.html b/doc/ijbfaq.html
new file mode 100644 (file)
index 0000000..ab7e798
--- /dev/null
@@ -0,0 +1,3186 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\r
+<html>\r
+<head>\r
+<!-- Copyright 1996-8 Junkbusters Corporation -->\r
+<!-- This work comes with NO WARRANTY -->\r
+<!-- It may be redistributed and modified under the GNU GPL-->\r
+<!-- See the body of http://www.junkbusters.com/ht/en/gpl.html for details-->\r
+<!-- Junkbusters is a registered trade mark of Junkbusters Corporation -->\r
+<!-- Generated 1998/10/31 03:58:25 UTC -->\r
+<meta name="Generator" content="Junkbusters Ebira $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $">\r
+<!-- Document  ID: $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $ -->\r
+<title>\r
+Internet Junkbuster Frequently Asked Questions\r
+</title>\r
+<base href="http://www.junkbusters.com/ht/en/ijbfaq.html">\r
+<meta name="description" content="An extensive FAQ on the Internet Junkbuster, free software to removes banner ads, cookies, and other stuff you don't want from your web browser.">\r
+<meta name="keywords" content="stop, junk, busters, junkbusters, junkbuster, mail, email, e-mail, direct, spam, spamoff, declare, telemarketing, telemarketers, privacy, sharing, names, renting, direct, marketing, database, databases, junk mail, lists, environment, conservation, recycling, catalogs, consumer, sending, opt out , privacy, advertising, direct, marketing, targeting, through, click, trails, http_referer, cookie, cutter, iff, internet fast forward, Cookie Management Tool">\r
+<link rel="next" href="ijbman.html">\r
+<link rel="previous" href="ijb.html">\r
+<link rel="contents" href="toc.html">\r
+</head>\r
+<body bgcolor="#f8f8f0" link="#000078" alink="#ff0022" vlink="#787878">\r
+<center>\r
+<h1><a name="top_of_page">Internet J<small>UNK<i><font color=red>BUSTER</font></i></small> Frequently Asked Questions\r
+</a></h1>\r
+</center>\r
+<font face="arial, helvetica">\r
+<p align="center">\r
+<a href="#u">Download for UNIX</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijbwin.html#zip">(Download for Windows 95/NT)</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijbdist.html#top_of_page">(Other OS)</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#browser">Configuring Browsers</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#local">Installation</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#companies">For Companies</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#blocking">Blocking</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#cookies">Cookies</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#anonymity">Anonymity</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#security">Security</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijbman.html#top_of_page">(Technical Manual)</a>\r
+</p>\r
+</font><br>\r
+<center>\r
+<h2><a name="top"><font face="arial, helvetica">\r
+The Top Ten Questions\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>For a list of the questions on this page (without the answers),\r
+see our\r
+<a href="toc.html#ijbfaq">Table of Contents.</a>\r
+It also contains detailed pointers into our pages\r
+on\r
+<a href="cookies.html">cookies</a>\r
+and on busting \r
+<a href="junkemail.html">junk e-mail,</a>\r
+<a href="junkmail.html">junk mail</a>\r
+and\r
+<a href="telemarketing.html">telemarketing calls.</a>\r
+\r
+<h3><a name="what" href="/cgi-bin/gp?pg=ijbfaq&pr=what"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What is the Internet Junkbuster Proxy and what does it do for me?\r
+</h3>\r
+<p>\r
+The\r
+Internet Junkbuster\r
+Proxy\r
+<a href="legal.html#marks"><small><sup>TM</sup></small></a>\r
+is\r
+<a href="ijbfaq.html#free">free</a>\r
+privacy-enhancing software that can be run on your PC or by your\r
+<small>ISP</small>\r
+or company.\r
+It blocks requests for\r
+<small>URL</small>s\r
+(typically banner ads)\r
+that match its\r
+<a href="ijbfaq.html#blocking">blockfile.</a>\r
+It also deletes unauthorized\r
+<a href="ijbfaq.html#cookies">cookies</a>\r
+and other\r
+unwanted identifying\r
+<a href="ijbfaq.html#anonymity">header information</a>\r
+that is exchanged between web servers and browsers.\r
+These headers are not normally accessible to users\r
+(even though they may contain information that's important to your privacy),\r
+but with the\r
+Internet Junkbuster\r
+you can see almost\r
+<a href="ijbman.html#o_d">anything you want</a>\r
+and control everything you're likely to need.\r
+<b>You</b>\r
+<a href="over.html#you_def">decide what's junk.</a>\r
+<a href="legal.html#marks"><small><sup>SM</sup></small></a>\r
+Many people\r
+<a href="ijbfaq.html#readymade">publish</a>\r
+their blockfiles to help others get started.\r
+</p>\r
+\r
+<h3><a name="free" href="/cgi-bin/gp?pg=ijbfaq&pr=free"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Is there a license fee / warranty / registration form / expiration?\r
+</h3>\r
+<p>\r
+No, none of these.\r
+It's completely free of charge.\r
+Junkbusters\r
+offers you the software to copy, use, modify and distribute\r
+as you wish, forever, at\r
+<a href="over.html#nobucks">no charge</a>\r
+under the\r
+<a href="gpl.html">GNU General Public License.</a>\r
+<p>\r
+<a name="warranty">It comes with</a>\r
+<a href="gpl.html#nowarr">no warranty of any kind.</a>\r
+<p>\r
+<a name="register">You don't have to register,</a>\r
+in fact we don't even provide a way to do so:\r
+the practice of registering software is\r
+usually just an\r
+excuse\r
+to send you solicitations and\r
+<a href="self.html#warranty">sell your name</a>\r
+and information about your behavior.\r
+You are welcome to obtain and use our software as anonymously you wish.\r
+(Your\r
+<small>IP</small>\r
+address will naturally be\r
+<a href="http://www.junkbusters.com/cgi-bin/privacy">disclosed</a>\r
+when you download it,\r
+so if you work for a web ad company\r
+you might want to use a service such as the\r
+<a href="ijbfaq.html#anonymizing">lpwa.com</a>\r
+when you get it.\r
+We\r
+<a href="over.html#nopriv">never</a>\r
+want to be given any information that you consider private or confidential.)\r
+<p>\r
+<a name="why">We are often asked why we give away a product that many</a>\r
+would happily pay for.\r
+The answer is that we are determined to carry out our\r
+<a href="over.html">mission:</a>\r
+to free the world from junk communications.\r
+</p>\r
+\r
+<h3><a name="windows" href="/cgi-bin/gp?pg=ijbfaq&pr=windows"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Does it run on Windows? On a Mac? On the AOL browser?\r
+</h3>\r
+<p>\r
+For the latest information on availability, see the\r
+<a href="ijbdist.html">Distribution Information</a>\r
+page.\r
+We\r
+<a href="ijbdist.html#win3.1">don't</a>\r
+think it will ever run on\r
+Windows 3.1.\r
+But you don't need to have it running on your computer\r
+if you get your\r
+<small>ISP</small>\r
+or Systems Administrator at\r
+<a href="ijbfaq.html#companies">work</a>\r
+to run it.\r
+</p>\r
+\r
+<h3><a name="isp" href="/cgi-bin/gp?pg=ijbfaq&pr=isp"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How can I get my ISP to run the Internet Junkbuster?\r
+</h3>\r
+<p>\r
+Try their sales or support department\r
+(depending on whether you are already a customer).\r
+<a name="unaware">You might send them email including the following</a>\r
+<small>URL</small>:\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>http://www.junkbusters.com/ht/en/ijbfaq.html#isps</kbd></big>\r
+<br>\r
+<a name="switch">You could mention that many</a>\r
+<a href="ijbfaq.html#does">other</a>\r
+<small>ISP</small>s\r
+provide it,\r
+and that you regard it as an important part of your decision on\r
+where to buy Internet service.\r
+</p>\r
+\r
+<h3><a name="who" href="/cgi-bin/gp?pg=ijbfaq&pr=who"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Who chooses the options that control what is blocked?\r
+</h3>\r
+<p>\r
+Whoever starts the\r
+Internet Junkbuster\r
+chooses the options and the blockfile.\r
+If your \r
+<small>ISP</small>\r
+runs it for you, they have to make these decision\r
+(though\r
+<a href="http://www.lunatech.com/proxy/">some</a>\r
+may give you a choice of proxies,\r
+and a way to suggest new\r
+<small>URL</small>s\r
+to block).\r
+If you run it on your computer,\r
+<b>You</b>\r
+<a href="over.html#you_def">decide what's junk.</a>\r
+<a href="legal.html#marks"><small><sup>SM</sup></small></a>\r
+</p>\r
+\r
+<h3><a name="self" href="/cgi-bin/gp?pg=ijbfaq&pr=self"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I download and run the program on my computer?\r
+</h3>\r
+<p>\r
+It depends on your platform.\r
+If you are using Windows 95 or NT,\r
+see our separate page on\r
+<a href="ijbwin.html">installing under Windows.</a>\r
+If you have a C compiler and are using almost any flavor of\r
+<small>UNIX <a href="legal.html#not_our_trademark">&#174;</a></small>\r
+you\r
+<a href="ijbfaq.html#local">download it, compile it, start it running,</a>\r
+and then\r
+<a href="ijbfaq.html#browser">configure your browser.</a>\r
+Several precompiled packages are also available through links in our\r
+<a href="ijbdist.html">distribution page</a>,\r
+which lists all available platforms.\r
+<p>\r
+<a name="port">If you are using a platform for which we have no current</a>\r
+availability,\r
+you are welcome to port the code.\r
+If you do this and you would like us to consider publishing your ported version,\r
+please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=port">tell us.</a>\r
+</p>\r
+\r
+<h3><a name="show" href="/cgi-bin/gp?pg=ijbfaq&pr=show"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How can I tell which blockfile and options are being used?\r
+</h3>\r
+<p>\r
+Just point your browser to\r
+<a href="http://internet.junkbuster.com/cgi-bin/show-proxy-args">http://internet.junkbuster.com/cgi-bin/show-proxy-args</a>\r
+or to any\r
+<small>URL</small>\r
+ending in\r
+<big><kbd>show-proxy-args</kbd></big>\r
+(even if it doesn't exist).\r
+It needn't exist because the\r
+Internet Junkbuster 2.0\r
+intercepts the request, blocks it,\r
+and returns in its place\r
+information about itself.\r
+Using the\r
+<small>URL</small>\r
+above is useful for checking that your browser really is\r
+going through an\r
+Internet Junkbuster,\r
+because the\r
+<big><kbd>junkbuster.com</kbd></big>\r
+server returns a warning if the request actually gets to it.\r
+Some people set the home page of their browser to such a\r
+<small>URL</small>\r
+to be sure that it is configured to use the proxy.\r
+<p>\r
+<a name="headers">If you wish to check the header information</a>\r
+your proxy is actually sending,\r
+a visit to\r
+<a href="http://internet.junkbuster.com/cgi-bin/show-http-headers">http://internet.junkbuster.com/cgi-bin/show-http-headers</a>\r
+will give you the more relevant ones first.\r
+You might also like to turn the proxy\r
+<a href="ijbfaq.html#discontinue">off</a>\r
+and compare the difference. (Don't forget to turn it back on again.)\r
+</p>\r
+\r
+<h3><a name="responding" href="/cgi-bin/gp?pg=ijbfaq&pr=responding"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+My browser started giving me ``server not responding'' messages\r
+</h3>\r
+<p>\r
+Once your browser is told to use a proxy such as the\r
+Internet Junkbuster,\r
+it thinks of it as its server for everything,\r
+so this message means it can't talk to the proxy.\r
+The\r
+Internet Junkbuster\r
+may not be running,\r
+or you may have specified its proxy\r
+<a href="ijbfaq.html#address">address</a>\r
+incorrectly.\r
+Check that the details you entered are correct.\r
+If you have\r
+<big><kbd>telnet</kbd></big>\r
+you can try connecting to the appropriate port to see if the\r
+Internet Junkbuster\r
+is running.\r
+If your\r
+<small>ISP</small>\r
+is running the\r
+Internet Junkbuster,\r
+you may want to check with them.\r
+If you are running it yourself under\r
+<small>UNIX <a href="legal.html#not_our_trademark">&#174;</a></small>,\r
+try looking at a\r
+<big><kbd>ps ax</kbd></big>\r
+to see if it is running.\r
+The\r
+<a href="ijbman.html#o_h">port</a>\r
+specified in its options should be the same one as your\r
+browser has configured.\r
+</p>\r
+\r
+<h3><a name="idea" href="/cgi-bin/gp?pg=ijbfaq&pr=idea"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+I've got this great idea for a new feature. Who do I tell?\r
+</h3>\r
+<p>\r
+We'd be very interested to hear it, but please bear a few things in mind.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="considered">Please check this FAQ to see if we've already considered</a>\r
+the idea,\r
+such as\r
+<a href="ijbfaq.html#size">automatic detection</a>\r
+of banner ads\r
+and\r
+<a href="ijbfaq.html#broken">replacing ads</a>\r
+with something else such as a\r
+transparent\r
+<small>GIF</small>.\r
+<li>\r
+<a name="confidential">Don't tell us anything you want to keep confidential</a>\r
+or retain some right over.\r
+<li>\r
+<a name="wish">We currently have a</a>\r
+long wish list of things that we may or may not do\r
+in the near future, including\r
+a version for your favorite computer and a plug-in version.\r
+<li>\r
+<a name="go4it">If you don't want to wait</a>\r
+you're welcome to improve on our code, publish your version on the Web,\r
+and\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=idea">tell us</a>\r
+where to find it.\r
+Projects that are especially welcome\r
+include\r
+a port to the Mac\r
+and extensions for\r
+<small>HTTP</small>\r
+1.1.\r
+</ul>\r
+</p>\r
+\r
+<h3><a name="other" href="/cgi-bin/gp?pg=ijbfaq&pr=other"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+My question isn't listed here. Who do I ask for support?\r
+</h3>\r
+<p>\r
+<a name="harder">If you find using our free product</a>\r
+harder than you're used to for consumer software,\r
+there are many\r
+<a href="links.html#WebWiper">commercial alternatives</a>\r
+that you could consider.\r
+<p>\r
+<a name="RTM">The answer to detailed technical questions may be answered in</a>\r
+<a href="ijbman.html">manual page</a>,\r
+or in the source code.\r
+Also double-check this page for an answer:\r
+using the ``find'' feature on your browser for likely keywords may help.\r
+Our site also has a\r
+<a href="search.html">search</a>\r
+feature.\r
+<p>\r
+<a name="Use">Many people post requests for help and responses on</a>\r
+<a href="http://search.dejanews.com/dnquery.xp?query=junkbuster&site=excite">Usenet.</a>\r
+<p>\r
+<a name="them">If your</a>\r
+<small>ISP</small>\r
+is providing\r
+the\r
+Internet Junkbuster\r
+for you,\r
+and your question is about how to use it,\r
+check their web page before asking them.\r
+<p>\r
+<a name="us">Even though we don't offer the kind of</a>\r
+support you might expect if you paid a lot of money for a software product,\r
+you can still ask us.\r
+But before you do, please consider whether\r
+you could ask someone closer to you.\r
+And please be patient if we're slow to reply: we\r
+<a href="over.html#nobucks">never charge consumers </a>\r
+for our services,\r
+so we have to subsidize consumers with revenue from companies,\r
+and our resources are limited.\r
+<p>\r
+<a name="quote">If your company or organization</a>\r
+would be interested in a maintenance contract\r
+with phone and email support,\r
+hard copy documentation and source code and pre-compiled binaries on tape\r
+or disk,\r
+please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=quote">ask us</a>\r
+for a quote.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="browser"><font face="arial, helvetica">\r
+Configuring your browser to talk to the Internet Junkbuster\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>\r
+<h3><a name="address" href="/cgi-bin/gp?pg=ijbfaq&pr=address"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What is the proxy address of the Internet Junkbuster?\r
+</h3>\r
+<p>\r
+<a name="localhost">If you set up</a>\r
+the\r
+Internet Junkbuster\r
+to run on the computer you browse from\r
+(rather than your\r
+<small>ISP</small>'s server\r
+or some networked computer at work),\r
+the proxy will be on\r
+<big><kbd>localhost</kbd></big>\r
+(which is the special name used by every computer on the Internet to\r
+refer to itself)\r
+and\r
+the port will be\r
+<big><kbd>8000</kbd></big>\r
+(unless you have told the\r
+Internet Junkbuster\r
+to\r
+run on a different port with the\r
+<a href="ijbman.html#listen-address">listen-address</a>\r
+option).\r
+So you when\r
+<a href="ijbfaq.html#set">configuring your browser's proxy settings</a>\r
+you typically enter the word\r
+<big><kbd>localhost</kbd></big>\r
+in the two boxes next to\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>\r
+and\r
+<b><font face="arial, helvetica">\r
+Secure</font></b>,\r
+and the number\r
+<big><kbd>8000</kbd></big>\r
+in the two boxes labelled\r
+to the right of those boxes.\r
+<p>\r
+<a name="remote">If your</a>\r
+<small>ISP</small>\r
+or company is running \r
+the\r
+Internet Junkbuster\r
+for you,\r
+they will tell you the address to use.\r
+It will be the name of the computer it's running on\r
+(or possibly its numeric IP address),\r
+plus a port number.\r
+Port 8000 is the default, so assume this number if it is not specified.\r
+Sometimes a colon is used to glue them together,\r
+as in\r
+<big><kbd>junkbuster.fictitous-pro-privacy-isp.net:8000</kbd></big>\r
+but\r
+with most browsers\r
+you do not type the colon,\r
+you enter the address and port number in separate boxes.\r
+</p>\r
+\r
+<h3><a name="set" href="/cgi-bin/gp?pg=ijbfaq&pr=set"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I tell the browser where to find the Internet Junkbuster?\r
+</h3>\r
+<p>\r
+All current browsers can be told the address of a proxy to use.\r
+You enter the same information in two fields in your browser's proxy\r
+configuration screen (see list below): one for\r
+<small>HTTP</small>,\r
+and one for the Secure Protocol (assuming your browser supports\r
+<small>SSL</small>).\r
+If you find some information already entered for your proxy,\r
+see the\r
+<a href="ijbfaq.html#already">next question.</a>\r
+Here are the menus you go through to get to the proxy configuration settings.\r
+(We also recommend that you\r
+<a href="links.html#java">disable Java</a>,\r
+which is a separate operation.)\r
+<strong>Make notes on the changes you make so you know how to undo them!</strong>\r
+You will need to know what you did\r
+in case you wish to\r
+<a href="ijbfaq.html#discontinue">discontinue</a>\r
+using the proxy.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="netscape">For</a>\r
+<a href="http://www.netscape.com/comprod/products/navigator/version_3.0/index.html">Netscape</a>\r
+2.01, 2.02 and 3.0\r
+<a href="/images/pcn30.gif">[Graphic Illustration]:</a>\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Network Preferences</font></b>;\r
+<b><font face="arial, helvetica">\r
+Proxies</font></b>;\r
+<b><font face="arial, helvetica">\r
+Manual Proxy Configuration View ;</font></b>\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+under\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>\r
+and\r
+<b><font face="arial, helvetica">\r
+Security Proxy</font></b>;\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>;\r
+click on the next\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+<br>\r
+With Netscape 2.0,\r
+follow with\r
+<b><font face="arial, helvetica">\r
+Options</font></b>,\r
+<b><font face="arial, helvetica">\r
+Save Options</font></b>.\r
+<br>\r
+<a name="Netscape4.02">With Netscape 4.X series, you first have to go through</a>\r
+<b><font face="arial, helvetica">\r
+Edit/Preferences</font></b>.\r
+<a href="/images/pcn405.gif">[Graphic Illustration]</a>\r
+Then in the frame on the left,\r
+click on triangle pointing to the right towards the word\r
+<b><font face="arial, helvetica">\r
+Advanced</font></b>;\r
+it will switch to a triangle pointing down;\r
+and the words\r
+<b><font face="arial, helvetica">\r
+Cache</font></b>,\r
+<b><font face="arial, helvetica">\r
+Proxies</font></b>\r
+and\r
+<b><font face="arial, helvetica">\r
+Disk Space</font></b>\r
+appear.\r
+Click on\r
+<b><font face="arial, helvetica">\r
+Proxies</font></b>\r
+and the frame on the right will\r
+display a banner saying\r
+<b><font face="arial, helvetica">\r
+Proxies Configure proxies to access the Internet</font></b>.\r
+Click the radio button labeled\r
+<b><font face="arial, helvetica">\r
+Manual proxy configuration</font></b>\r
+then click the button labeled\r
+<b><font face="arial, helvetica">\r
+View</font></b>;\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+under\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>\r
+and\r
+<b><font face="arial, helvetica">\r
+Security Proxy</font></b>;\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>;\r
+click on the next\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+<li>\r
+<a name="explorer3">For</a>\r
+<a href="http://www.microsoft.com/ie/support/docs/tech30/">Internet Explorer 3.0:</a>\r
+<b><font face="arial, helvetica">\r
+View</font></b>;\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Connections</font></b>;\r
+tick\r
+<b><font face="arial, helvetica">\r
+Connect through proxy server</font></b>\r
+box;\r
+<b><font face="arial, helvetica">\r
+Settings</font></b>;\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>\r
+Box, with port number in the second box;\r
+same with\r
+<b><font face="arial, helvetica">\r
+Secure</font></b>;\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+<li>\r
+<a name="explorer2">For Internet Explorer 2.0: </a>\r
+<b><font face="arial, helvetica">\r
+View</font></b>;\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Proxy</font></b>;\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+<li>\r
+<a name="nt">On NT for MS-IE:</a>\r
+<b><font face="arial, helvetica">\r
+Control Panel</font></b>;\r
+<b><font face="arial, helvetica">\r
+Internet</font></b>;\r
+<b><font face="arial, helvetica">\r
+Advanced</font></b>;\r
+<b><font face="arial, helvetica">\r
+Proxy</font></b>.\r
+<li>\r
+<a name="if">For MS-IE 4.0: seems to be almost the same as for</a>\r
+<a href="ijbfaq.html#explorer3">3.0</a>,\r
+<b><font face="arial, helvetica">\r
+View</font></b>;\r
+<b><font face="arial, helvetica">\r
+Internet Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Connections</font></b>;\r
+tick\r
+<b><font face="arial, helvetica">\r
+Connect through proxy server</font></b>\r
+box;\r
+<b><font face="arial, helvetica">\r
+Settings</font></b>;\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>\r
+Box, with port number in the second box;\r
+same with\r
+<b><font face="arial, helvetica">\r
+Secure</font></b>;\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+Note that 4.0 has\r
+<b><font face="arial, helvetica">\r
+Advanced</font></b>\r
+settings to allow\r
+<small>HTTP</small>\r
+1.1 through proxies;\r
+these must be disabled because the proxy does not currently understand\r
+<small>HTTP</small>\r
+1.1.\r
+Please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=set">tell us</a>\r
+if you see any other differences.\r
+<li>\r
+<a name="mosaic">For NCSA Mosaic for Windows:</a>\r
+<b><font face="arial, helvetica">\r
+Options</font></b>,\r
+<b><font face="arial, helvetica">\r
+Preferences</font></b>,\r
+<b><font face="arial, helvetica">\r
+Proxy</font></b>;\r
+enter\r
+<a href="ijbfaq.html#address">proxy address details</a>\r
+under\r
+<b><font face="arial, helvetica">\r
+HTTP</font></b>.\r
+<li>\r
+<a name="Opera">For</a>\r
+Opera:\r
+<b><font face="arial, helvetica">\r
+Preferences</font></b>,\r
+<b><font face="arial, helvetica">\r
+Proxy servers</font></b>;\r
+check the box next to HTTP;\r
+enter the server and port number in the box on the other side;\r
+click on\r
+<b><font face="arial, helvetica">\r
+OK</font></b>.\r
+<li>\r
+<a name="lynx">For</a>\r
+<a href="http://www.yahoo.com/Computers_and_Internet/Software/Internet/World_Wide_Web/Browsers/Lynx">Lynx,</a>\r
+<a href="http://www.yahoo.com/Computers_and_Internet/Software/Internet/World_Wide_Web/Browsers/Mosaic/">Mosaic/X,</a>\r
+<a name ="grail" href="http://monty.cnri.reston.va.us/grail-0.3/">Grail,</a>\r
+and\r
+W3O\r
+<a href="http://www.w3.org/pub/WWW/Arena/">Arena,</a>\r
+you can specify the proxy via environment variables\r
+before starting the application.\r
+This will probably be done with something like either\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>setenv http_proxy http://localhost:8000/</kbd></big>\r
+<br>\r
+or\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>http_proxy=http://junkbuster.fictitous-pro-privacy-isp.net:8000/ export http_proxy</kbd></big>\r
+<br>\r
+depending on your shell and where the\r
+Internet Junkbuster\r
+lives.\r
+</ul>\r
+If your browser is not listed here,\r
+or if you notice an error, please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=set">tell us</a>\r
+the correct procedure.\r
+</p>\r
+\r
+<h3><a name="already" href="/cgi-bin/gp?pg=ijbfaq&pr=already"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What should I do if I find another proxy is already configured?\r
+</h3>\r
+<p>\r
+Some\r
+<small>ISP</small>s\r
+and companies require all Web traffic to go through their proxy.\r
+In this case you would find your proxy configuration with values already set,\r
+possibly under\r
+<a name="Automatic">Automatic Proxy Configuration</a>\r
+(in the case of \r
+<a href="http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html">Netscape</a>\r
+and\r
+<a href="http://ieak.microsoft.com/">MS-IE 3.0</a>\r
+and above).\r
+It's probably a firewall proxy between your company and the outside world,\r
+<a name="cache">or a</a>\r
+<a href="http://vancouver-webpages.com/CacheNow/">caching proxy</a>\r
+if you're using an \r
+<small>ISP</small>.\r
+<p>\r
+<a name="f">What needs to be done in this case is to</a>\r
+use the\r
+<a href="ijbman.html#forwardfile">forwardfile</a>\r
+option\r
+to tell the\r
+Internet Junkbuster\r
+the address of the other proxy.\r
+Specify a different (unused) port number\r
+with the\r
+<a href="ijbman.html#listen-address">listen-address</a>\r
+option,\r
+and configure your browser to\r
+<a href="ijbfaq.html#chain">use that port.</a>\r
+If you haven't done this kind of thing before,\r
+it's probably best to consult your systems administrator or \r
+<small>ISP</small>\r
+about it;\r
+check their web page first.\r
+</p>\r
+\r
+<h3><a name="discontinue" href="/cgi-bin/gp?pg=ijbfaq&pr=discontinue"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What if I want to stop using the Internet Junkbuster?\r
+</h3>\r
+<p>\r
+Just go through the same procedure you used to start your\r
+browser using the\r
+Internet Junkbuster,\r
+but remove the details you put in\r
+(or if there was something there before, restore it).\r
+You may need to use\r
+<b><font face="arial, helvetica">\r
+Save Options</font></b>\r
+to make this change permanent.\r
+On Netscape 3.0 you can go through\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Network Preferences</font></b>;\r
+<b><font face="arial, helvetica">\r
+Proxies</font></b>\r
+and click on\r
+<b><font face="arial, helvetica">\r
+No Proxy</font></b>\r
+to turn it off, and later click on\r
+<b><font face="arial, helvetica">\r
+Manual Proxy Configuration</font></b>\r
+if you want to start using it again.\r
+(No need to enter the again details under\r
+<b><font face="arial, helvetica">\r
+View</font></b>\r
+as you did the\r
+<a href="ijbfaq.html#netscape">first time;</a>\r
+they should remain there unchanged.)\r
+<p>\r
+<a name="shut">This stops your browser talking to the proxy;</a>\r
+<a href="ijbfaq.html#shutdown">shutting down the proxy</a>\r
+is a different matter.\r
+</p>\r
+\r
+<h3><a name="dial" href="/cgi-bin/gp?pg=ijbfaq&pr=dial"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Automatic dialing isn't working any more. How do I fix it?\r
+</h3>\r
+<p>\r
+Some browsers (such as MSIE-4) can be configured to dial your\r
+<small>ISP</small>\r
+automatically when you click on a link,\r
+but this feature gets disabled if you specify a proxy running on your\r
+own computer\r
+(with address\r
+<big><kbd>localhost</kbd></big>\r
+or\r
+<big><kbd>127.0.0.1</kbd></big>)\r
+because these addresses don't require dialing.\r
+The\r
+Internet Junkbuster\r
+knows nothing about dialing, so it doesn't work.\r
+To make automatic dialing work,\r
+make up a name such as\r
+<big><kbd>junkbuster.ijb</kbd></big>\r
+and use that name in the proxy settings\r
+instead of\r
+<big><kbd>localhost</kbd></big>,\r
+and then add the line\r
+<big><kbd>127.0.0.1 junkbuster.ijb</kbd></big>\r
+to the file\r
+<big><kbd>c:\windows\hosts</kbd></big>\r
+(if there already is a line beginning with\r
+<big><kbd>127.0.0.1</kbd></big>\r
+just add\r
+<big><kbd>junkbuster.ijb</kbd></big>\r
+at the end of it.)\r
+<p>\r
+<a name="also">This should also work Netscape Communicator 4 on</a>\r
+machines where IE-4 has been installed.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="local"><font face="arial, helvetica">\r
+Setting up the Internet Junkbuster on your local computer\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>The next two sections assume you wish to compile the code\r
+with your own C compiler.\r
+<a name="install">If you just want to use the</a>\r
+<big><kbd>.exe</kbd></big>\r
+file provided for Windows,\r
+see the\r
+<a href="ijbwin.html">Windows Installation page.</a>\r
+\r
+<h3><a name="u" href="/cgi-bin/gp?pg=ijbfaq&pr=u"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I compile the code under Unix?\r
+</h3>\r
+<p>\r
+If you are running Redhat\r
+<a href="aboutus.html#linux">Linux</a>\r
+you may prefer to use the\r
+<a href="ijbdist.html#red">rpm</a>\r
+instead of the following procedure.\r
+<br><ol  type="1">\r
+<li>\r
+<a name="download">First</a>\r
+<a href="ijb20.tar.Z">download the tar file</a>\r
+(~286k)\r
+<a name="tar">and</a>\r
+uncompress and extract the files from it with this command\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>uncompress -c ijb20.tar.Z | tar xf -</kbd></big>\r
+<p>\r
+<li>\r
+<a name="sun">If your operating system is from</a>\r
+<a href="legal.html#not_our_trademark">Sun</a>\r
+or\r
+<a href="legal.html#not_our_trademark">HP</a>\r
+examine the\r
+<big><kbd>Makefile</kbd></big>\r
+and make any changes indicated inside.\r
+<li>\r
+<a name="make">Run</a>\r
+<br>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>make</kbd></big>\r
+<p>\r
+<li>\r
+<a name="defaults">Copy the sample configuration file</a>\r
+(<big><kbd>junkbstr.ini</kbd></big>,\r
+previously called\r
+<big><kbd>sconfig.txt</kbd></big>\r
+and other names in earlier releases)\r
+to some convenient place such as\r
+<big><kbd>/usr/local/lib/junkbuster/configfile</kbd></big>\r
+or whatever you choose.\r
+The sample file has all the options commented out.\r
+You can remove the\r
+<big><kbd>#</kbd></big>\r
+character on any that you want, but it may be better to\r
+leave this until to later.\r
+Run it asynchronously:\r
+<br>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>junkbuster configfile &</kbd></big>\r
+<p>\r
+If you are running a version earlier than 2.0 you can start it with\r
+<big><kbd>junkbuster &</kbd></big>\r
+<p>\r
+<li>\r
+<a name="config">Configure your browser (described</a>\r
+<a href="ijbfaq.html#browser">above).</a>\r
+<li>\r
+<a name="test">Verify that the</a>\r
+Internet Junkbuster\r
+is working (described\r
+<a href="ijbfaq.html#show">above).</a>\r
+<li>\r
+<a name="restart">Decide on the options you really want,</a>\r
+<big><kbd>kill</kbd></big>\r
+the\r
+<a href="ijbfaq.html#pid">process</a>\r
+and start it again. The most popular option is\r
+<a href="ijbman.html#blockfile">blockfile</a>\r
+to block ads.\r
+<a name="comprehensive">A sample blockfile is provided as an illustration,</a>\r
+but it doesn't really stop many ads.\r
+More comprehensive ones are available\r
+<a href="ijbfaq.html#readymade">elsewhere</a>.\r
+<li>\r
+<a name="rc">You'll probably want to add an entry to</a>\r
+<big><kbd>/etc/rc.d/rc.local</kbd></big>\r
+or equivalent to start it at boot time.\r
+(Any output you specify should be redirected to a file.\r
+And don't forget the\r
+&amp;\r
+at the end to run it asynchronously or your system will seize\r
+up after the next reboot.)\r
+</ol>\r
+</p>\r
+\r
+<h3><a name="win" href="/cgi-bin/gp?pg=ijbfaq&pr=win"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I compile the code under Windows?\r
+</h3>\r
+<p>\r
+A binary is currently being supplied with the source code,\r
+but if you prefer to compile it yourself here is the likely procedure.\r
+Most of these steps are repeated in our checklist for\r
+<a href="ijbwin.html">installation under Windows.</a>\r
+<br><ol  type="1">\r
+<li>\r
+<a name="zip">First</a>\r
+<a href="ijb20.zip">click here to download the zip file</a>\r
+called\r
+<big><kbd>ijb20.zip</kbd></big>\r
+(~208k),\r
+then uncompress and unpack the zip archive using a tool like\r
+<a href="http://www.winzip.com/">WinZip</a>.\r
+<li>\r
+<a name="change">Now the distribution (source and sample files)</a>\r
+will be in a folder\r
+called\r
+<big><kbd>ijb20</kbd></big>.\r
+Go into that folder and then edit the Makefile for\r
+your system,\r
+removing the comment character\r
+(<big><kbd>#</kbd></big>)\r
+in the lines related to Win32.\r
+Then type:\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>nmake</kbd></big>\r
+<br>\r
+This should create an executable called\r
+<big><kbd>junkbstr.exe</kbd></big>.\r
+<a name="compilers">For information on issues with various compilers, see the</a>\r
+<a href="ijbdist.html#compilers">Distribution Information</a>\r
+page.\r
+<li>\r
+<a name="attempt">Run the executable with the command:</a>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>junkbstr</kbd></big>\r
+<br>\r
+The program will produce a message\r
+indicating that it has started and is ready to serve.\r
+<p>\r
+<a name="ini">(Version 2.0.1 and above uses</a>\r
+the file\r
+<big><kbd>junkbstr.ini</kbd></big>\r
+as the config file\r
+if it exists and no argument was given. If you have an earlier\r
+version or if you want it to use a different config file,\r
+simply specify that file as the argument.)\r
+<li>\r
+<a name="configures">Configure your browser (described</a>\r
+<a href="ijbfaq.html#browser">above).</a>\r
+<li>\r
+<a name="work">Check the proxy is working (described</a>\r
+<a href="ijbfaq.html#check">below</a>).\r
+<li>\r
+<a name="shortcut">To have the proxy start itself automatically</a>\r
+when you login to Win95,\r
+drop the ``shortcut'' to the\r
+<big><kbd>junkbstr</kbd></big>\r
+executable into the StartUp folder:\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>C:\Windows\Start Menu\Programs\StartUp</kbd></big>\r
+<br>\r
+You might want to change the shortcut's\r
+<big><kbd>Properties-&gt;Shortcut</kbd></big>\r
+to\r
+<big><kbd>Run: Minimized</kbd></big>.\r
+If you specify the\r
+<a href="ijbman.html#hide-console">hide-console</a>\r
+option then the\r
+<small>DOS</small>\r
+window will vanish after it starts.\r
+<p>\r
+<a name="NT">WinNT users can put it into their own</a>\r
+StartUp folders or the Administrator\r
+can put it into the system's global StartUp folder.\r
+For details on how to make this a service under NT\r
+see our\r
+<a href="ijbwin.html#service">Windows page</a>.\r
+</ol>\r
+</p>\r
+\r
+<h3><a name="check" href="/cgi-bin/gp?pg=ijbfaq&pr=check"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I check that the proxy is working?\r
+</h3>\r
+<p>\r
+Pick a page from somewhere (such as your bookmarks, or just one\r
+that your browser was pointing to)\r
+and\r
+<b><font face="arial, helvetica">\r
+Reload</font></b>\r
+it.\r
+If you get a message along the lines of ``server not responding,\r
+using cached copy instead,'' see the advice\r
+<a href="ijbfaq.html#responding">above.</a>\r
+If the page reloads OK, check that your browser is actually\r
+talking to the proxy by going to\r
+<a href="http://internet.junkbuster.com/cgi-bin/show-proxy-args">http://internet.junkbuster.com/cgi-bin/show-proxy-args</a>\r
+or any\r
+<small>URL</small>\r
+ending in\r
+<big><kbd>show-proxy-args</kbd></big>\r
+(as described\r
+<a href="ijbfaq.html#show">below</a>,\r
+the proxy should intercept the request.)\r
+When you see ``Internet Junkbuster Proxy Status,''\r
+you'll know it's working.\r
+</p>\r
+\r
+<h3><a name="chain" href="/cgi-bin/gp?pg=ijbfaq&pr=chain"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How and why would I have this proxy chained with other proxies?\r
+</h3>\r
+<p>\r
+You may need the \r
+<a href="ijbman.html#forwardfile">forwarding</a>\r
+feature to ``daisy chain'' the\r
+Internet Junkbuster\r
+to another proxy, perhaps an\r
+<a href="ijbfaq.html#anonymizing">anonymizing</a>\r
+proxy to\r
+<a href="ijbfaq.html#conceal">conceal</a>\r
+your\r
+<small>IP</small>\r
+address,\r
+or a\r
+<a href="ijbfaq.html#cache">caching proxy</a>\r
+from your\r
+<small>ISP</small>,\r
+or a\r
+<a href="ijbfaq.html#firewall">firewall</a>\r
+proxy between your company and the outside world.\r
+Version 2.0\r
+can be even configured to forward\r
+<a href="ijbman.html#forwardfile">selectively</a>\r
+according to the\r
+<small>URL</small>\r
+requested:\r
+for example, connecting directly to trusted hosts,\r
+but going through an anonymizing or firewall proxy for all other hosts.\r
+<p>\r
+<a name="administrator">Network administrators might use it to provide</a>\r
+transparent access to multiple networks without\r
+modifying browser configurations.\r
+<a name="direct">Most browsers also provide a way of</a>\r
+specifying hosts that the browser\r
+connects to directly, bypassing the proxy. Some provide a method for\r
+<a href="ijbfaq.html#Automatic">Automatic Proxy Configuration.</a>\r
+A well written\r
+Internet Junkbuster\r
+configuration can be much more flexible and powerful.\r
+<p>\r
+<a name="example">An</a>\r
+<small>ISP</small>'s\r
+caching proxy\r
+would typically be called something like\r
+<big><kbd>cache.your-isp.net:8080</kbd></big>\r
+(as described on you\r
+<small>ISP</small>'s\r
+web page);\r
+you would put this information in your\r
+<a href="ijbman.html#forwardfile">forwardfile</a>\r
+as described in our manual.\r
+Your browser would be configured to\r
+the\r
+Internet Junkbuster\r
+for\r
+<small>HTTP</small>\r
+and Security Proxies as before,\r
+but you probably want to tell it to use the caching proxy\r
+for\r
+<small>FTP</small>\r
+and other protocols.\r
+<a name="nonlocal">If your</a>\r
+<small>ISP</small>\r
+is running\r
+the\r
+Internet Junkbuster\r
+for you,\r
+they have probably already decided whether to chain with a caching proxy.\r
+</p>\r
+\r
+<h3><a name="socks" href="/cgi-bin/gp?pg=ijbfaq&pr=socks"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How does the Internet Junkbuster work with SOCKS gateways?\r
+</h3>\r
+<p>\r
+There is support for some\r
+<a href="http://www.leverage.com/users/tlod/ssockd/ssockd.html">gateways</a>\r
+in\r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and above.\r
+The gateway protocol used to be specified on the command line;\r
+it is\r
+now specified\r
+in the same file as\r
+<a href="ijbman.html#forwardfile">forwarding.</a>\r
+Note that the browser's proxy configuration must\r
+<em>not</em>\r
+specify a\r
+<big><kbd>SOCKS</kbd></big>\r
+host;\r
+it should specify the proxy as described\r
+<a href="ijbfaq.html#set">above.</a>\r
+</p>\r
+\r
+<h3><a name="plain" href="/cgi-bin/gp?pg=ijbfaq&pr=plain"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I configure it to be just a plain old proxy?\r
+</h3>\r
+<p>\r
+To get the proxy to do as little as possible (which means not deleting any\r
+sensitive headers), place in your\r
+configuration file the following three lines (each ending in a space\r
+then a period) to stop it changing sensitive headers:\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>referer .</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>from .</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>user-agent .</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>cookiefile mycookiefile</kbd></big>\r
+<br>\r
+The fourth line is also needed to specify a\r
+<a href="ijbman.html#o_c">cookiefile</a>\r
+that might be called\r
+<big><kbd>mycookiefile</kbd></big>\r
+containing a single line with a\r
+<big><kbd>*</kbd></big>\r
+character, to allow all cookies through.\r
+</p>\r
+\r
+<h3><a name="shutdown" href="/cgi-bin/gp?pg=ijbfaq&pr=shutdown"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I shut down the proxy (to restart it)?\r
+</h3>\r
+<p>\r
+It depends on your platform. Under Windows, use\r
+<b><font face="arial, helvetica">\r
+Ctrl-Break</font></b>\r
+in the \r
+<small>DOS</small>\r
+window or\r
+the old three-fingered salute of\r
+<b><font face="arial, helvetica">\r
+Ctrl-Alt-Delete</font></b>\r
+and select\r
+<b><font face="arial, helvetica">\r
+End Task</font></b>.\r
+Under\r
+<small>UNIX <a href="legal.html#not_our_trademark">&#174;</a></small>\r
+you'll need to\r
+<big><kbd>kill</kbd></big>\r
+the\r
+<b><kbd>junkbuster</kbd></b>\r
+process.\r
+<a name="pid">If you don't know the process number to give to</a>\r
+<big><kbd>kill</kbd></big>, try this:\r
+<big><kbd>ps ax | grep junkbuster</kbd></big>\r
+<br>\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="companies"><font face="arial, helvetica">\r
+Information for companies\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>\r
+<h3><a name="think" href="/cgi-bin/gp?pg=ijbfaq&pr=think"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What do advertising companies think of this kind of technology?\r
+</h3>\r
+<p>\r
+We've seen only a few public comments from the advertising industry on this,\r
+other than\r
+<a href="links.html#adverse">SEC filings.</a>\r
+First, the president of the Internet Advertising Bureau told\r
+<a href="new.html#Rich">CNET</a>\r
+that he wasn't worried by banner blockers.\r
+Second, after the Federal Trade Commission's\r
+<a href="ftc.html">workshop</a>\r
+where we gave a live demonstration of our proxy before\r
+many eminent representatives of the industry,\r
+the\r
+<a href="self.html#dma">Direct Marketing Association</a>\r
+made the following\r
+statement in the closing paragraphs\r
+of their\r
+<a href="http://www.ftc.gov/bcp/privacy/wkshp97/comments2/dma027a.htm">summary comments</a>\r
+to the Commission.\r
+<blockquote>\r
+Clever shareware developers have come up with products that\r
+can obliterate cookies and advertisements for those consumers\r
+who have these concerns.\r
+The Internet is a market that is so democratic and flexible\r
+that it is easy for companies and software\r
+developers to respond to a perceived market need. \r
+</blockquote>\r
+Their attitude seems to be that they would prefer that\r
+people use technical solutions\r
+to protect their privacy than have protections\r
+imposed by legislation or government regulations.\r
+So, do you perceive a market need?\r
+Then here are some ways to flex your democratic muscles.\r
+</p>\r
+\r
+<h3><a name="nobrainer" href="/cgi-bin/gp?pg=ijbfaq&pr=nobrainer"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Should we provide the Internet Junkbuster for our employees?\r
+</h3>\r
+<p>\r
+That depends. Try this quick three-point test.\r
+<br><ol  type="1">\r
+<li>\r
+<a name="waste">Do you want to spend your communications budget</a>\r
+on bandwidth that wastes your employees' time by forcing them to wait\r
+for a lot of annoying distractions while they're trying to\r
+do their jobs?\r
+<li>\r
+<a name="surveillance">Do you want current and potential vendors</a>\r
+to know quantitative details about the\r
+<a href="ijbfaq.html#agent">software and hardware platforms</a>\r
+that you have?\r
+<li>\r
+<a name="intelligence">Do you want your competitors to be able to</a>\r
+<a href="cookies.html">track</a>\r
+exactly which of your\r
+employees are checking out their web sites?\r
+</ol>\r
+If the answer to all three questions is yes,\r
+then you probably don't have any need for this kind of product.\r
+</p>\r
+\r
+<h3><a name="commercial" href="/cgi-bin/gp?pg=ijbfaq&pr=commercial"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can our company get commercial support for the software?\r
+</h3>\r
+<p>\r
+Yes,\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=commercial">ask us</a>\r
+for a quote on a maintenance contract with your choice of\r
+phone and email support,\r
+hard copy documentation,\r
+source code and pre-compiled binaries on tape or disk,\r
+and email alerting of upgrades and issues.\r
+We also offer consulting services to help set up ``stealth browsing''\r
+capabilities to help reduce the footprints left while doing competitive\r
+analysis and other Web work where confidentiality is critical.\r
+</p>\r
+\r
+<h3><a name="isps" href="/cgi-bin/gp?pg=ijbfaq&pr=isps"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+I run an ISP. What issues should I consider before offering it?\r
+</h3>\r
+<p>\r
+Many\r
+<small>ISP</small>s\r
+who offer the proxy to their customers have told us that\r
+most of their customers are \r
+delighted with it\r
+(although one reported that a customer complaint that without banner ads,\r
+surfing was like reading a novel: we recommend making it optional).\r
+Many\r
+<small>ISP</small>s\r
+like it because it reduces bandwidth requirements.\r
+To help get you started,\r
+here's a checklist we've developed from working with a few\r
+<small>ISP</small>s.\r
+You may think of more,\r
+and we'd be interested if you're willing to\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=isps">share them</a>\r
+with us.\r
+<br><ol  type="1">\r
+<li>\r
+<a name="pending">If you get more than one request for</a>\r
+the\r
+Internet Junkbuster\r
+you may want to tell your customers on your News page that you\r
+<a href="ijbfaq.html#isp">already</a>\r
+know about it and are assessing it.\r
+<li>\r
+<a name="try">Try the software and</a>\r
+<a href="ijbfaq.html#install">verify</a>\r
+that it performs satisfactorily.\r
+<li>\r
+<a name="value">Determine whether your customers perceive the service as</a>\r
+<a href="ijbfaq.html#switch">valuable</a>\r
+(and therefore worth the time to set up).\r
+We've had reports of many delighted customers.\r
+<li>\r
+<a name="secure">Assess the</a>\r
+level of\r
+<a href="ijbfaq.html#others">security</a>\r
+associated with the software.\r
+If access is to be\r
+<a href="ijbfaq.html#restrict">restricted</a>\r
+(to just dial-in ports, for example)\r
+how is this to be done?\r
+<li>\r
+<a name="costs">Consider</a>\r
+whether to expect any additional load on computing resources required,\r
+and any change in use of bandwidth due to the blocking of large\r
+<small>GIF</small>s.\r
+<li>\r
+<a name="opt">Choose the</a>\r
+<a href="ijbman.html">options</a>\r
+you wish to provide.\r
+<li>\r
+<a name="multiple">Decide whether you want</a>\r
+to offer a choice of configurations, such some of these four.\r
+<br><ol  type="A">\r
+<li>\r
+<a name="banner">Banners</a>\r
+<a href="ijbfaq.html#blocking">Blocked,</a>\r
+Wafer with\r
+<a href="ijbfaq.html#notice">No-Cookie-Copyright</a>\r
+notice\r
+<li>\r
+<a name="low">Cookies</a>\r
+not stopped\r
+(<a href="ijbman.html#cookiefile">cookiefile</a>\r
+with just a\r
+<big><kbd>*</kbd></big>\r
+in it),\r
+<a href="ijbfaq.html#header">User Agent</a>\r
+specified as\r
+<a href="ijbfaq.html#lynx">Lynx</a>\r
+<li>\r
+<a name="oneway">Cookies from browser</a>\r
+<a href="ijbfaq.html#one">allowed</a>,\r
+permitting\r
+<a href="ijbfaq.html#registration">registered services</a>\r
+<li>\r
+<a name="kid">A proxy for</a>\r
+<a href="ijbfaq.html#children">kids.</a>\r
+</ol>\r
+<a name="caching">If you run a</a>\r
+<a href="ijbfaq.html#chain">caching proxy,</a>\r
+decide whether the \r
+Internet Junkbuster\r
+will chain with it by default,\r
+and whether to offer an alternate with no caching.\r
+(Some\r
+<small>ISP</small>s\r
+don't, because they want to give customers an incentive to use caching\r
+and save bandwidth.)\r
+<li>\r
+<a name="naming">Decide on a naming scheme for your</a>\r
+proxies.\r
+If you're running only one\r
+proxy on one machine,\r
+the simplest way is to just use port 8000 on your main machine,\r
+such as\r
+<big><kbd>our-isp.net.</kbd></big>\r
+But it would probably be safer to put an entry in your name server\r
+and call it something like\r
+<big><kbd>junkbuster.our-isp.net.</kbd></big>\r
+If running several proxies, you could either use different ports\r
+on the same machine, or if you have\r
+the opportunity to distribute the load over\r
+a few machines \r
+you could\r
+use different hostname aliases such as\r
+<big><kbd>banner.junkbuster.our-isp.net</kbd></big>,\r
+<big><kbd>lynx.junkbuster.our-isp.net</kbd></big>\r
+and\r
+<big><kbd>oneway.junkbuster.our-isp.net</kbd></big>\r
+(corresponding to the examples in the previous point).\r
+You may want to set up\r
+<a href="ijbfaq.html#Automatic">Automatic Proxy Configuration.</a>\r
+<li>\r
+<a name="document">Prepare a page</a>\r
+explaining the\r
+Internet Junkbuster\r
+to your customers.\r
+<a name="does">Here's are some examples from</a>\r
+<a href="http://www.cia.com.au/us/help/faq-proxy.html">Australia</a>,\r
+<a href="http://www.rhein-ruhr.de/info/junkbuster.html">Germany</a>,\r
+<a href="http://www.packet.net/ijb/">Florida</a>,\r
+<a href="http://www.eclipse.net/adfilter/index.html">New York/New Jersey/Pennsylvania,</a>\r
+<a href="http://a-o.com/proxy/proxy.html">North Carolina</a>,\r
+<a href="http://www.trip.net/junkbuster/">Texas</a>,\r
+and\r
+<a href="http://www.inconnect.com/proxy.html">Utah</a>.\r
+<a name="reuse">You are welcome to copy and modify</a>\r
+material\r
+from\r
+Junkbusters\r
+according to the\r
+<a href="gpl.html">GPL</a>.\r
+You might want to set up a process to check this page periodically\r
+and update it when it changes.\r
+(A few links can probably serve as well as lot of copying however.)\r
+A typical page would probably specify the following.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="abstract">A brief explanation stating what</a>\r
+the\r
+Internet Junkbuster\r
+does, with a link to this page.\r
+<li>\r
+<a name="addresses">The addresses of the proxy or proxies,</a>\r
+with their port number(s).\r
+<li>\r
+<a name="options">The options used,</a>\r
+and how to view the contents of the blockfile (which you can place on\r
+your web pages,\r
+preferably in a file called\r
+<big><kbd>blocklist.html</kbd></big>\r
+or\r
+<big><kbd>blocklist.txt</kbd></big>).\r
+<li>\r
+<a name="additions">An indication</a>\r
+of whether suggestions for the blocklist are considered,\r
+and if so, how to submit them: to a particular email address,\r
+via web-based form, etc.\r
+<li>\r
+<a name="configuration">Instructions</a>\r
+on how to\r
+configure a browser.\r
+You may want to include details for only the two major browsers\r
+and leave the others to a link.\r
+<li>\r
+<a name="service">Procedures on how to report problems, give feedback etc.</a>\r
+</ul>\r
+<li>\r
+<a name="beta">Invite a small number of technologically sophisticated</a>\r
+customers to beta-test the service.\r
+<li>\r
+<a name="announce">Announce general availability on your ``News'' page.</a>\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=isps">Tell us</a>\r
+if you would like to be included on a list of\r
+<small>ISP</small>s\r
+offering the\r
+Internet Junkbuster.\r
+</ol>\r
+</p>\r
+\r
+<h3><a name="ps2" href="/cgi-bin/gp?pg=ijbfaq&pr=ps2"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What's a Proxy Server Server and how can I make money as one?\r
+</h3>\r
+<p>\r
+Other organizations with web presence and some bandwidth to spare\r
+can set up as\r
+<i><dfn>Proxy Server Servers</dfn></i>\r
+<!-- Aside: All this, and... -->\r
+(<small>PS<sup>2</sup></small>s).\r
+The idea here is to allow users to choose their proxy configuration,\r
+and provide it to them on a semi-permanent basis.\r
+Users would fill in a form specifying what options they want in\r
+their proxy,\r
+possibly even at a very high level, such as\r
+``no ads''\r
+or ``no nudity.''\r
+This information is sent to a\r
+<small>CGI</small>\r
+script that\r
+configures a proxy, starts it running, and returns its address and port number\r
+(possibly along with configuration instructions for the browser\r
+that the user specified.)\r
+<p>\r
+<a name="revenue">Users</a>\r
+could be charged\r
+a subscription fee,\r
+or the service could be thrown in free in the hope of\r
+improving customer retention for some existing business\r
+(which is what\r
+<small>ISP</small>s\r
+are doing).\r
+It might be possible to make money by\r
+inserting new ads in the holes left where others were blocked,\r
+but the original owners might object.\r
+<small>PS<sup>2</sup></small>s\r
+could differentiate themselves\r
+by providing frequently updated and comprehensive\r
+blocking of ads, or of offensive material based on their own grading system.\r
+Some content providers might do it for the chance to be the\r
+only company that the consumer permits to set cookies.\r
+(Identification could even be done via cookies,\r
+but this might not be popular with the kind of user who wants a proxy.)\r
+<small>PS<sup>2</sup></small>s\r
+might sell specific or aggregate information about their\r
+users' browsing habits,\r
+so the agreement with users on whether they are permitted to do this\r
+would be important to both sides.\r
+<p>\r
+<a name="publicize">If your organization</a>\r
+establishes a \r
+Proxy Server Service\r
+you would like publicized,\r
+please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=publicize">notify us.</a>\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="blocking"><font face="arial, helvetica">\r
+Blocking\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>\r
+<h3><a name="readymade" href="/cgi-bin/gp?pg=ijbfaq&pr=readymade"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Where can I get an example blockfile that stops most ads?\r
+</h3>\r
+<p>\r
+The sample blockfile we provide blocks almost nothing,\r
+and we do not publish blockfiles that stop almost all banner ads.\r
+But others have; you can find them by\r
+<a href="http://www.altavista.com/cgi-bin/query?pg=q&what=web&fmt=.&q=%2Bjunkbuster+%2Burl%3Ablocklist">asking Altavista.</a>\r
+You can add any part of the new file to your old one\r
+(probably called\r
+<big><kbd>sblock.ini</kbd></big>\r
+if you haven't changed the default name in the latest version)\r
+or your just replace it completely.\r
+You\r
+<a href="ijbfaq.html#cover">probably</a>\r
+don't need to restart the proxy.\r
+<p>\r
+<a name="pub">If you develop an interesting blocklist and publish it on the Web,</a>\r
+you might want to include the word ``junkbuster'' in it\r
+and use the word ``blocklist'' in the file name given in the\r
+<small>URL</small>\r
+so that others can find it with the query given in the previous sentence.\r
+</p>\r
+\r
+<h3><a name="zap" href="/cgi-bin/gp?pg=ijbfaq&pr=zap"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+If I see an ad I wish I hadn't, how do I stop it?\r
+</h3>\r
+<p>\r
+If your\r
+<small>ISP</small>\r
+is running the\r
+Internet Junkbuster,\r
+they should have a policy on whether they accept suggestions from\r
+their customers on what to block. Consult their web page.\r
+<p>\r
+<a name="cover">If you are running</a>\r
+the\r
+Internet Junkbuster\r
+yourself, you have complete control over what gets through.\r
+Just add a pattern to cover the offending \r
+<small>URL</small>\r
+to your blockfile.\r
+Version 1.3 and later automatically rereads the blockfile when it changes,\r
+but if you're running an earlier version you'll\r
+have to\r
+<a href="ijbfaq.html#shutdown">stop it</a>\r
+and restart it.\r
+<p>\r
+<a name="target">To choose a pattern you'll first need to find the</a>\r
+<small>URL</small>\r
+of the ad you want cover.\r
+<p>\r
+<a name="pinpoint">Some people use the</a>\r
+<a href="ijbman.html#debug">debug</a>\r
+<big><kbd>1</kbd></big>\r
+option to display each \r
+<small>URL</small>\r
+in a window as the request is sent to the server.\r
+It's then usually an easy task to pick the offending \r
+<small>URL</small>\r
+from the list of recent candidates.\r
+<p>\r
+<a name="source">Alternatively,</a>\r
+you can use\r
+<b><font face="arial, helvetica">\r
+View Document Info</font></b>\r
+(or\r
+<b><font face="arial, helvetica">\r
+View Document Source</font></b>\r
+if your browser doesn't have that).\r
+The\r
+<b><font face="arial, helvetica">\r
+Info</font></b>\r
+feature has the advantage of showing you the full\r
+<small>URL</small>\r
+including the host name,\r
+which may not be specified in the source:\r
+there you might see something like\r
+<big><kbd>SRC="/ads/click_here_or_die.gif"</kbd></big>\r
+indicating only the\r
+<i><dfn>path</dfn></i>.\r
+(The host name is assumed to be the same as the one the page came from.)\r
+<p>\r
+<a name="offsite">But ads often</a>\r
+come from a different site, in which case you\r
+might see something like\r
+<big><kbd>SRC="grabem.n.trackem.com/Ad/Infinitum/SpaceID=1666"</kbd></big>\r
+or longer.\r
+<a name="warehouse">If the company looks like a pure ad warehouse</a>\r
+(as in the last case),\r
+you may want to place just its domain name in the blockfile,\r
+which blocks all \r
+<small>URL</small>s\r
+from that site.\r
+<p>\r
+<a name="wanted">If the ad comes from a server</a>\r
+that you really want some content from,\r
+you can include enough of the path\r
+to avoid zapping stuff you might want.\r
+In the first example above,\r
+<big><kbd>/ads/</kbd></big>\r
+would seem to be enough.\r
+If you don't include the domain name,\r
+the pattern applies to all sites,\r
+so you don't want such patterns\r
+to be too general:\r
+for example\r
+<big><kbd>/ad</kbd></big>\r
+would block\r
+<big><kbd>/admin/salaries/</kbd></big>\r
+on your company's internal site.\r
+<p>\r
+<a name="image">To speed the blocking of images, some</a>\r
+<small>UNIX <a href="legal.html#not_our_trademark">&#174;</a></small>\r
+users create a\r
+shell script called\r
+<big><kbd>Image:</kbd></big>\r
+containing a line such as\r
+<big><kbd>echo $1 | sed s/http:..// &gt;&gt; $HOME/lib/blockfile</kbd></big>\r
+that adds its argument to the user's blockfile.\r
+Once an offending image has been be found using\r
+<b><font face="arial, helvetica">\r
+View Document Info</font></b>\r
+it's easy to cut-and-paste the line (or part of it) into a shell window.\r
+The same script can be linked to a file called\r
+<big><kbd>Frame:</kbd></big>\r
+to dealing with framed documents,\r
+and\r
+<big><kbd>junkbuster:</kbd></big>\r
+to accept the output of the\r
+<a href="ijbman.html#debug">debug</a>\r
+option.\r
+<p>\r
+<a name="partial">When compiled without the</a>\r
+<i><dfn>regular expressions</dfn></i>\r
+option, the\r
+Internet Junkbuster\r
+uses only very simple (and fast) matching methods.\r
+The pattern\r
+<big><kbd>/banners</kbd></big>\r
+will not stop\r
+<big><kbd>/images/banners/huge.gif</kbd></big>\r
+getting through: you would have to include the pattern\r
+<big><kbd>/images/banners</kbd></big>\r
+or something that matches in full from the left.\r
+<a name="regex">So you can get what you want here,</a>\r
+the matcher understands\r
+<small>POSIX</small>\r
+regular expressions:\r
+you can use\r
+<big><kbd>/*.*/banners</kbd></big>\r
+to block\r
+and any\r
+<small>URL</small>\r
+containing\r
+<big><kbd>/banners</kbd></big>\r
+(even in the middle of the path).\r
+<a name="posix">(In Versions 1.1 through 1.4</a>\r
+they were an option at compile time;\r
+from Version 2.0 they have become the default.)\r
+Regular expressions give you\r
+<a href="http://theory.uwinnipeg.ca/localfiles/infofiles/gcc/rx_toc.html">many more features</a>\r
+than this,\r
+but if you're not already familiar with them you probably won't \r
+need to know anything beyond the\r
+<big><kbd>/*.*/</kbd></big>\r
+idiom.\r
+If you do, a\r
+<big><kbd>man egrep</kbd></big>\r
+is probably a good starting point).\r
+<p>\r
+<a name="slash">Don't forget the</a>\r
+<big><kbd>/</kbd></big>\r
+(slash)\r
+at the beginning of the path.\r
+If you leave it out the line will be interpreted as a domain name,\r
+so\r
+<big><kbd>ad</kbd></big>\r
+would block all sites from Andorra\r
+(since\r
+<big><kbd>.ad</kbd></big>\r
+is the two-letter\r
+<a href="reference.html#country">country code</a>\r
+for that principality).\r
+<p>\r
+<a name="detail">For a detailed technical description</a>\r
+of how pattern matching is done,\r
+see the\r
+<a href="ijbman.html#o_b">manual.</a>\r
+</p>\r
+\r
+<h3><a name="despite" href="/cgi-bin/gp?pg=ijbfaq&pr=despite"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How come this ad is still getting through anyway?\r
+</h3>\r
+<p>\r
+If the ad had been displayed before you included its\r
+<small>URL</small>\r
+in the blockfile,\r
+it will probably be held in cache for some time,\r
+so it will be displayed without the need for any request to the server.\r
+Using the\r
+<a href="ijbman.html#debug">debug</a>\r
+<big><kbd>1</kbd></big>\r
+option to show each\r
+<small>URL</small>\r
+as it is fetched is a good way to see exactly what is happening.\r
+<p>\r
+<a name="otherwise">If new items seem to be getting through,</a>\r
+check that you are\r
+<a href="ijbfaq.html#show">really running</a>\r
+the proxy with the right blockfile in the options.\r
+Check the blockfile for\r
+<a href="ijbfaq.html#exceptions">exceptions.</a>\r
+<p>\r
+<a name="java">Some sites may have different ways of inserting ads,</a>\r
+such as via\r
+<a href="cookies.html#java">Java.</a>\r
+If you have ideas on how to block new kinds\r
+of junk not currently covered, please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=java">tell us.</a>\r
+</p>\r
+\r
+<h3><a name="exceptions" href="/cgi-bin/gp?pg=ijbfaq&pr=exceptions"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How do I stop it blocking a URL that I actually want?\r
+</h3>\r
+<p>\r
+You can change the patterns so they don't cover it,\r
+or use a simple feature in Version 1.1 and later: a line beginning with a\r
+<big><kbd>~</kbd></big>\r
+character means that a\r
+<small>URL</small>\r
+blocked by previous patterns that matches the rest of\r
+the line is let through.\r
+For example,\r
+the pattern\r
+<big><kbd>/ad</kbd></big>\r
+would block\r
+<big><kbd>/addasite.html</kbd></big>\r
+but not if followed by\r
+<big><kbd>~/addasite</kbd></big>\r
+in the blockfile.\r
+Or suppose you want to see everything that comes from\r
+a site you like, even if it looks like an ad: simply put\r
+<big><kbd>~aSiteYouLike.com</kbd></big>\r
+at the\r
+<em>end</em>\r
+of the blockfile.\r
+(Order is important, because the last matching line wins.)\r
+<p>\r
+<a name="agreed">As well as unblocking</a>\r
+pages that were unintentionally blocked,\r
+this feature is useful for unblocking ads from a specific source.\r
+This might be because you are interested in those particular ones,\r
+or if you have an explicit agreement to accept certain ads,\r
+such as those from a free web-based email provider.\r
+</p>\r
+\r
+<h3><a name="children" href="/cgi-bin/gp?pg=ijbfaq&pr=children"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can I block sites I don't want my children to see?\r
+</h3>\r
+<p>\r
+Yes, but remember that\r
+<a name="savvy">children who are technically sophisticated enough</a>\r
+to use the browsers' proxy configuration options\r
+could of course bypass any proxy.\r
+This kind of technology can be used as a gentle barrier to remind\r
+or guide the child,\r
+but nobody should expect it to replace the parent's role\r
+in setting and enforcing standards of online behavior for their children.\r
+<p>\r
+<a name="recommend">Some</a>\r
+<small>ISP</small>s\r
+are starting to provide specialized proxies to protect children.\r
+There are two basic approaches: the ``black list'' and the ``white list''\r
+approach.\r
+<a name="negative">The black list approach allows the child</a>\r
+to go anywhere not explicitly prohibited; the white list permits visits\r
+only to sites explicitly designated as acceptable.\r
+<p>\r
+<a name="positive">It's very easy for</a>\r
+anyone to\r
+compile a white list from a page of ``recommended\r
+kids sites'' and to configure an\r
+Internet Junkbuster\r
+to allow access to those sites only.\r
+If you compile with the\r
+<a href="ijbfaq.html#regex">regex</a>\r
+option,\r
+you can place a\r
+<big><kbd>*</kbd></big>\r
+(asterisk) as the first line of the blockfile (which blocks everything),\r
+and then list\r
+<a href="ijbfaq.html#exceptions">exceptions</a>\r
+after that.\r
+Be careful to make the exception sufficiently broad:\r
+for example, using\r
+<big><kbd>~www.uexpress.com/ups/comics/ch/</kbd></big>\r
+as the exception for\r
+<a href="http://www.uexpress.com/ups/comics/ch/"><cite>Calvin and Hobbes</cite></a>\r
+would block some of the graphic elements on the page;\r
+you would probably want a wider exception such as\r
+<big><kbd>~www.uexpress.com/ups/</kbd></big>\r
+to permit them.\r
+<p>\r
+<a name="trust">Version 2.0 has an experimental feature</a>\r
+to permit only sites mentioned in a nominated\r
+<a href="ijbman.html#trustfile">trusted site.</a>\r
+This allows organizations to build lists of sites for kids to browse,\r
+and the software automatically restricts access to those on the list.\r
+<p>\r
+<a name="scan">Many filtering</a>\r
+<a href="links.html#blocking">products</a>\r
+actually scan for keywords in\r
+the text of pages they retrieve\r
+before presenting it,\r
+but\r
+the\r
+Internet Junkbuster\r
+does not do this.\r
+Building a perfectly reliable black list system is hard,\r
+because it's very difficult to state\r
+in advance\r
+exactly\r
+what is obscene or unsuitable.\r
+For more info see our\r
+<a href="links.html#parents">links</a>\r
+page.\r
+</p>\r
+\r
+<h3><a name="message" href="/cgi-bin/gp?pg=ijbfaq&pr=message"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What do I see when a page or graphic is blocked by the proxy?\r
+</h3>\r
+<p>\r
+You usually see a broken image icon,\r
+but it depends on several factors beyond the proxy's control.\r
+If asked for a\r
+<small>URL</small>\r
+matching its blockfile, the proxy returns an\r
+<small>HTML</small>\r
+page containing a message identifying itself\r
+(currently the two words ``Internet Junkbuster'')\r
+with a status 202 (Accepted) instead of the usual 200 (OK).\r
+(Versions 1.X returned an error 404: Forbidden, which caused\r
+strange behavior in some cases.)\r
+Status 202 is described in the\r
+<small>HTTP</small>\r
+<a href="http://www.ics.uci.edu/pub/ietf/http/rfc1945.html#Code202">RFC</a>\r
+as indicating that the request has been accepted but not completed,\r
+and that it might complete successfully in the future\r
+(in our case, if the blockfile were changed).\r
+<p>\r
+<a name="depends">The broken image icon is most common</a>\r
+because the browser is usually expecting a graphic.\r
+But if it was expecting text, or if the page happens to be using certain\r
+<small>HTML</small>\r
+extensions\r
+such as\r
+<big><kbd>layer</kbd></big>\r
+and your browser is a late model from Microsoft,\r
+you may see the words ``Internet Junkbuster'' displayed as a hot link.\r
+<p>\r
+<a name="click">Clicking on the link takes you to an explanation of</a>\r
+the pattern in the blockfile that caused the block,\r
+so that you can edit the blockfile and go back and reload if you really\r
+want to see what was blocked. The explanatory link is generated by\r
+the proxy and is automatically intercepted based on its ending in\r
+<big><kbd>ij-blocked-url</kbd></big>;\r
+even though the site is specified as\r
+<big><kbd>http://internet.junkbuster.com</kbd></big>\r
+no request should actually made to that site.\r
+If one is, it means that the proxy was been removed after it\r
+generated the link.\r
+<p>\r
+<a name="layer">To summarize:</a>\r
+the identifying link to the blocking explanation\r
+is usually turned into a broken image icon,\r
+but it may be displayed on a page alone,\r
+or they may may be restricted to the particular frame, layer or graphic area\r
+specified in the page containing them.\r
+The proxy has no way of knowing the context in which a\r
+<small>URL</small>\r
+will be used and cannot control how the blocking message will be rendered.\r
+</p>\r
+\r
+<h3><a name="broken" href="/cgi-bin/gp?pg=ijbfaq&pr=broken"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Why not replace blocked banners with something invisible?\r
+</h3>\r
+<p>\r
+<a name="infringe">Many users have suggested to us</a>\r
+that blocked banners should be replaced by a something like a\r
+1x1 transparent\r
+<small>GIF</small>\r
+to make the page would look as if there was nothing ever there.\r
+Apart from making it harder to catch unintended blocking,\r
+this might also displease the owners of the page,\r
+who could argue that such a change constitutes a copyright infringement.\r
+We think that merely failing to allow an included graphic to be accessed\r
+would probably not be considered an infringement:\r
+after all this is what happens when a browser\r
+is configured not to load images automatically.\r
+However, we are\r
+<a href="over.html#notlaw">not</a>\r
+lawyers,\r
+so anyone in doubt should take appropriate advice.\r
+<p>\r
+<a name="done">In a context where the copyright issue is resolved</a>\r
+satisfactorily,\r
+a proxy could simply return a status 301 or 302 and\r
+specify a replacement\r
+<small>URL</small>\r
+in a\r
+<big><kbd>Location</kbd></big>\r
+and/or\r
+<big><kbd>URI</kbd></big>\r
+header.\r
+An alternative would be to use inline code to return a\r
+1 x 1 clear\r
+<small>GIF</small>.\r
+We do not publish sample code for this,\r
+and we have no way of stopping\r
+<a href="ijbdist.html#others">others</a>\r
+who have.\r
+</p>\r
+\r
+<h3><a name="size" href="/cgi-bin/gp?pg=ijbfaq&pr=size"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Why not block banners based on the dimensions of the image?\r
+</h3>\r
+<p>\r
+Many users have pointed out that most banner ads come in standard sizes,\r
+so why not block all\r
+<small>GIF</small>s\r
+of those sizes?\r
+This would theoretically be without fetching the object \r
+because the dimensions are usually given in the\r
+<big><kbd>IMG</kbd></big>\r
+tag,\r
+but it would require substantial changes in the code,\r
+and we doubt whether it would be much more effective than a good block list.\r
+</p>\r
+\r
+<h3><a name="embedded" href="/cgi-bin/gp?pg=ijbfaq&pr=embedded"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What about non-graphic advertising within the pages I want?\r
+</h3>\r
+<p>\r
+The\r
+Internet Junkbuster\r
+deliberately\r
+does not provide a way of automatically editing the contents of a page,\r
+to remove textual advertising or\r
+to repair the holes left by blocked banners.\r
+Other packages such as\r
+<a href="links.html#webfilter">WebFilter</a>\r
+do.\r
+<p>\r
+<a name="base">For the same reason,</a>\r
+it has no way of stopping a new browser\r
+window being created, because this is done through the\r
+<big><kbd>target</kbd></big>\r
+attribute in the\r
+<big><kbd>&lt;a&gt;</kbd></big>\r
+and\r
+<big><kbd>&lt;base&gt;</kbd></big>\r
+elements,\r
+not through headers.\r
+Nor do we plan to add a feature to\r
+<a href="http://simmons.starkville.ms.us/tips/081097/">paralyze animated</a>\r
+<small>GIF</small>s.\r
+</p>\r
+\r
+<h3><a name="push" href="/cgi-bin/gp?pg=ijbfaq&pr=push"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Does it block ads on the broadcasting ``push'' systems? How about pop-up ads?\r
+</h3>\r
+<p>\r
+We haven't tried it but we expect it would probably\r
+work on image ads on push channels.\r
+See also\r
+<a href="links.html#adchoice">adchoice</a>.\r
+<p>\r
+<a name="pop">Disabling</a>\r
+<a href="cookies.html#java">Javascript</a>\r
+stops some pop-up ads.\r
+One problem is that some advertisers throw open a new\r
+browser window to frame the ad. The ad is easily blocked,\r
+but the empty window remains. You can kill it easily, but this is a chore.\r
+We don't see how to stop them other than editing the\r
+<small>HTML</small>\r
+from the parent window, which we\r
+<a href="ijbfaq.html#broken">don't</a>\r
+like to do.\r
+<p>\r
+<a name="TBTD">The</a>\r
+<a href="http://www.tbtf.com/archive/10-06-97.html">TBTF</a>\r
+newsletter warned subscribers to push information that\r
+<a name="LOGTARGET">in IE4,</a>\r
+<a href="http://www.microsoft.com/standards/cdf.htm#Logging">LOGTARGET</a>\r
+allows\r
+servers to determine the\r
+<small>URL</small>s\r
+viewed at their site even if accessed from cache or through a proxy.\r
+If you use this browser see our instructions on\r
+<a href="cookies.html#counting">how to disable</a>\r
+this.\r
+<p>\r
+<a name="pushy">If you find you have experience using the proxy with push,</a>\r
+or have any other advice about it, please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=pushy">tell us.</a>\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="cookies"><font face="arial, helvetica">\r
+Cookies\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>For background information on cookies see our\r
+<a href="cookies.html">page describing their dangers.</a>\r
+\r
+<h3><a name="breakthrough" href="/cgi-bin/gp?pg=ijbfaq&pr=breakthrough"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Might some cookies still get through? How can I stop them?\r
+</h3>\r
+<p>\r
+Yes, you should expect the occasional cookie to make it through to your browser.\r
+We know of at least three ways this can happen;\r
+please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=breakthrough">tell us</a>\r
+if you find any others.\r
+One way is in secure documents, which are explained\r
+<a href="ijbfaq.html#secure">below.</a>\r
+<p>\r
+<a name="EQUIV">A</a>\r
+<a href="links.html#JavaScript">few</a>\r
+sites set cookies using a line such as\r
+<big><kbd>&lt;META HTTP-EQUIV="Set-Cookie" CONTENT="flavor=chocolate"&gt;</kbd></big>\r
+in the\r
+<big><kbd>HEAD</kbd></big>\r
+section of an\r
+<small>HTML</small>\r
+document.\r
+<a name="javascript">Cookies can also be</a>\r
+<!-- IEM: http://cgi.netscape.com/eng/mozilla/Gold/handbook/javascript/ref_a-c.html#cookie_property -->\r
+set and read\r
+in\r
+JavaScript.\r
+To see if this is happening in a document,\r
+view its source, look in the\r
+<big><kbd>head</kbd></big>\r
+for a section tagged\r
+<big><kbd>script language="JavaScript"</kbd></big>.\r
+If it contains a reference to\r
+<big><kbd>document.cookie</kbd></big>,\r
+the page can manipulate your cookie file without sending any cookie headers.\r
+The\r
+Internet Junkbuster\r
+does not tamper with these methods.\r
+Fortunately they are rarely used at the moment.\r
+If a cookie gets set, it should be stopped\r
+by the proxy on its way back to the server when a page is requested,\r
+but it can still be read in Javascript.\r
+bu\r
+<p>\r
+<a name="alert">To prevent cookies breaking through,</a>\r
+<strong>always</strong>\r
+keep\r
+<a href="cookies.html#disable">cookie alerts</a>\r
+turned on in your browser,\r
+and\r
+<a href="cookies.html#java">disable</a>\r
+Java and Javascript.\r
+Making the files\r
+<a href="cookies.html#only">hard to write</a>\r
+may also help.\r
+</p>\r
+\r
+<h3><a name="method" href="/cgi-bin/gp?pg=ijbfaq&pr=method"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Exactly how do cookies get created and stored anyway?\r
+</h3>\r
+<p>\r
+When a web site's server sends you a page it also sends\r
+certain ``header information'' which your browser records but does not display.\r
+One of these is a\r
+<big><kbd>Set-Cookie</kbd></big>\r
+header, which specifies the cookie information that the server wants your browser to record.\r
+Similarly, when your browser requests a page it also sends headers, specifying\r
+information such as the graphics formats it understands.\r
+If a cookie has previously been set by a site that matches the\r
+<small>URL</small>\r
+it is about to request,\r
+your browser adds a\r
+<big><kbd>Cookie</kbd></big>\r
+header quoting the previous information.\r
+<p>\r
+<a name="privacy">For more background information on how cookies</a>\r
+can damage your privacy, see our\r
+<a href="cookies.html">page on cookies.</a>\r
+For highly detailed technical information see the\r
+<a href="links.html#kristol">RFC.</a>\r
+The\r
+Internet Junkbuster\r
+will show you all headers you use the\r
+<a href="ijbman.html#debug">debug</a>\r
+<big><kbd>8</kbd></big>\r
+option,\r
+or you can get a sample from our\r
+<a href="ijbfaq.html#headers">demonstration page.</a>\r
+</p>\r
+\r
+<h3><a name="break" href="/cgi-bin/gp?pg=ijbfaq&pr=break"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+If cookies can't get through, will some things stop working for me?\r
+</h3>\r
+<p>\r
+Possibly.\r
+Some personalized services including certain\r
+<!-- IEM: http://my.yahoo.com -->\r
+chat\r
+rooms\r
+require cookies.\r
+<a name="registration">Newspapers that require</a>\r
+<!-- IEM: http://www.nytimes.com/subscribe/sub-bin/new_sub.cgi#agree -->\r
+registration\r
+or\r
+<!-- IEM: http://interactive5.wsj.com/regUser.html -->\r
+subscription\r
+will not automatically recognize you if you don't send them the cookie they\r
+assigned you. And there are a very small number of sites that do\r
+strange things with cookies; they don't work for anyone that blocks\r
+cookies by any means.\r
+Some sites such as\r
+<a href="links.html#withhold">Microsoft</a>\r
+explain that their content is so wonderfully compelling that\r
+they will withhold it from you unless you submit to their\r
+inserting cookies.\r
+<p>\r
+<a name="want">If you want such sites to be given your cookies,</a>\r
+you can use the\r
+<a href="ijbman.html#cookiefile">cookiefile</a>\r
+option provided you are running\r
+<a href="ijbfaq.html#crumble">Version 1.2 or later</a>\r
+yourself.\r
+Simply include the domain name of those sites in the\r
+<i>cookiefile</i>\r
+specified by this option.\r
+If it still doesn't work,\r
+the problem may be in\r
+<a href="ijbfaq.html#breakage">other headers.</a>\r
+<p>\r
+<a name="one">It's possible to let cookies out but not in,</a>\r
+which is enough to keep some sites happy, but not all of them:\r
+one newspaper site seems to go into an endless frenzy\r
+if deprived of fresh cookies.\r
+A cookiefile containing\r
+a single line consisting of the two characters\r
+<big><kbd>&gt;*</kbd></big>\r
+(greater-than and star) permits server-bound cookies only.\r
+The\r
+<big><kbd>*</kbd></big>\r
+is a\r
+<a href="ijbman.html#wildcard">wildcard</a>\r
+that matches all domains.\r
+<p>\r
+<a name="else">If someone else is running the</a>\r
+Internet Junkbuster\r
+for you and has a version\r
+that\r
+<!-- IAM: ijbfaq.html#registration -->\r
+passes server-bound cookies through,\r
+you can try editing your browser's cookie\r
+file to contain just the ones you want,\r
+and restart your browser.\r
+<a name="window">To subscribe to a new service like this</a>\r
+after you have started using the\r
+Internet Junkbuster,\r
+you can try the following:\r
+tell your browser to\r
+<a href="ijbfaq.html#discontinue">stop using</a>\r
+the\r
+Internet Junkbuster,\r
+fill out and submit your subscription details\r
+(allowing that web site to set a cookie),\r
+then\r
+reconfigure your browser to use the\r
+Internet Junkbuster\r
+again\r
+(and stop more cookies being sent).\r
+This also requires the\r
+<a href="ijbman.html#cookiefile">cookiefile</a>\r
+option,\r
+and its success depends on the Web site\r
+not wanting to change your cookies at every session.\r
+For this reason it does not work at some major newspaper sites, for example.\r
+<a name="buyers">But you may prefer to</a>\r
+look at whether other sites provide the same\r
+or better services without demanding the opportunity\r
+to track your behavior.\r
+The web is a buyer's market where most prices are zero:\r
+very few people pay\r
+for content with money, so why should you pay with your privacy?\r
+</p>\r
+\r
+<h3><a name="crumble" href="/cgi-bin/gp?pg=ijbfaq&pr=crumble"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can I control cookies on a per-site basis?\r
+</h3>\r
+<p>\r
+<a name="discard">Yes, since version 1.2 the</a>\r
+Internet Junkbuster\r
+has included advanced cookie management facilities.\r
+Unless you specify otherwise,\r
+cookies are discarded (``crumbled'') by the\r
+Internet Junkbuster\r
+whether they came from the server or the browser.\r
+In Version 1.2 and later you can\r
+use the\r
+<a href="ijbman.html#cookiefile">cookiefile</a>\r
+option\r
+to specify when cookies are to be passed through intact.\r
+It uses the same syntax and\r
+<a href="ijbman.html#o_b">matching</a>\r
+algorithm as the blockfile.\r
+<p>\r
+<a name="cook">If the</a>\r
+<small>URL</small>\r
+matches a pattern in the\r
+<i><dfn>cookiefile</dfn></i>\r
+then cookies are let through in both the browser's request for the\r
+<small>URL</small>\r
+and in the server's response.\r
+<a name="directional">One-way permissions can be</a>\r
+specified by starting the line with the\r
+<big><kbd>&gt;</kbd></big>\r
+or\r
+<big><kbd>&lt;</kbd></big>\r
+character.\r
+For example, a cookiefile consisting of the four lines\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>org</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>&gt;send-user-cookies.org</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>&lt;accept-server-cookies.org</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>~block-all-cookies.org</kbd></big>\r
+<br>\r
+allows cookies to and from\r
+<big><kbd>.org</kbd></big>\r
+domains only, with the following exceptions:\r
+<br><ol  type="1">\r
+<li>\r
+<a name="fed">Cookies sent from servers in the domain</a>\r
+<big><kbd>send-user-cookies.org</kbd></big>\r
+are blocked on their way to the client,\r
+but cookies sent by the browser to that domain are still be fed to them.\r
+<li>\r
+<a name="take">The cookies of</a>\r
+<big><kbd>accept-server-cookies.org</kbd></big>\r
+check in to the proxy and are passed through to the browser,\r
+but when they come back to the proxy they never check out.\r
+<li>\r
+<a name="deny">All cookies to and from</a>\r
+<big><kbd>block-all-cookies.org</kbd></big>\r
+are blocked.\r
+</ol>\r
+<p>\r
+<a name="paths">If</a>\r
+the\r
+<b><kbd>junkbuster</kbd></b>\r
+was compiled with the regular expressions option\r
+they may be used in paths.\r
+Any logging to a\r
+<a href="ijbfaq.html#jar">``cookie jar''</a>\r
+is separate and not affected.\r
+<p>\r
+<a name="breadth">It's important to give hosts you want to be able</a>\r
+to set cookies sufficient breadth. For example,\r
+instead of\r
+<big><kbd>www.yahoo.com</kbd></big>\r
+use\r
+<big><kbd>yahoo.com</kbd></big>\r
+because the company uses many different hosts ending in that domain.\r
+</p>\r
+\r
+<h3><a name="wafers" href="/cgi-bin/gp?pg=ijbfaq&pr=wafers"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can I make up my own fake cookies (wafers) to feed to servers?\r
+</h3>\r
+<p>\r
+Yes,\r
+using the\r
+<a href="ijbman.html#wafer">wafer</a>\r
+option.\r
+We coined the term\r
+<i><dfn>wafer</dfn></i>\r
+to describe cookies chosen by a user,\r
+not the Web server.\r
+Servers may not find wafers as tasty as the cookies\r
+they make themselves.\r
+But users may enjoy controlling servers' diets for various reasons,\r
+such as the following.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="retaliate">Users who consider cookies to</a>\r
+be an unwelcome intrusion and a waste\r
+of their disk space can respond in kind.\r
+By writing ``signature wafers'' they can\r
+express their feelings about cookies,\r
+in a place that the people\r
+in charge of them are most likely to notice.\r
+<li>\r
+<a name="notice">Sites running a proxy</a>\r
+that logs cookies to a file\r
+(such as the\r
+Internet Junkbuster\r
+does with the\r
+<a href="ijbman.html#jarfile">jarfile</a>\r
+option on)\r
+may want to notify\r
+servers that their cookies are being intercepted,\r
+deleted or copied.\r
+One possible reason for doing this is the uncertain copyright status\r
+of cookie strings.\r
+<a href="over.html#notlaw">Nothing</a>\r
+here should be taken as legal advice: we are simply raising a question\r
+for any interested parties to consider,\r
+and make no representation that such measures are necessary or sufficient.\r
+Concerned proxy sites might decide to send a wafer\r
+(named ``NOTICE'' for example)\r
+containing text along the lines of the following.\r
+<blockquote>\r
+<p>\r
+<a name="licenses_on_cookies_refused">TO WHOM IT MAY CONCERN</a>\r
+<i>\r
+<br>\r
+<br>\r
+Do not send me any copyrighted information other than the\r
+document that I am requesting or any of its necessary components.\r
+<br>\r
+<br>\r
+In particular do not send me any cookies that\r
+are subject to a claim of copyright by anybody.\r
+Take notice that I refuse to be bound by any license condition\r
+(copyright or otherwise) applying to any cookie.\r
+</i>\r
+</blockquote>\r
+Any company that tries to argue in court that the proxy site\r
+was breaching their copyright in the cookies would\r
+be met with the defense that the proxy site gave that company\r
+the opportunity to protect its copyright by simply\r
+not sending cookies after receiving the notice. \r
+<p>\r
+<a name="pointer">Cookies can be as long as four thousand characters,</a>\r
+so there's plenty of space for lawyerly verbosity,\r
+but white space, commas, and semi-colons are\r
+<a href="ijbman.html#o_w">prohibited.</a>\r
+Spaces can be turned into underscores.\r
+Alternatively,\r
+a\r
+<small>URL</small>\r
+could be sent as the cookie value,\r
+pointing to a document containing a notice,\r
+perhaps with a suggestive value such as\r
+<br>\r
+<big><kbd>http://www.junkbusters.com/ht/en/ijbfaq.html#licenses_on_cookies_refused</kbd></big>\r
+<br>\r
+But including the notice directly would probably be preferable\r
+because the addressee does not have to look it up.\r
+<p>\r
+<a name="vanilla">The</a>\r
+Internet Junkbuster 2.0\r
+currently sends a full notice as a\r
+``vanilla wafer''\r
+if cookies are being logged to a cookie jar\r
+and no other wafers have been specified.\r
+It can be suppressed with the\r
+<a href="ijbman.html#suppress-vanilla-wafer">suppress-vanilla-wafer</a>\r
+option,\r
+which might be used in situations where there is an established understanding\r
+between the proxy and all who serve it.\r
+</ul>\r
+<p>\r
+<a name="gimme">Junkbusters provides a</a>\r
+<small>CGI</small>\r
+script that lets you\r
+<a href="ijbfaq.html#headers">see</a>\r
+your wafers as they appear to servers.\r
+<p>\r
+<a name="malfunction">Wafers confuse a few fragile servers.</a>\r
+If this troubles you, don't use this option.\r
+<p>\r
+<a name="regardless">Any wafers specified are sent to</a>\r
+all sites regardless of the cookiefile.\r
+<a name="compliant">They are appended after any genuine cookies,</a>\r
+to maintain compliance with\r
+<a href="links.html#kristol">RFC 2109</a>\r
+in the event that a path was specified for a cookie.\r
+The\r
+<small>RFC</small>'s provisions regarding the\r
+<big><kbd>$</kbd></big>\r
+character\r
+(such as the\r
+<big><kbd>Version</kbd></big>\r
+attribute)\r
+are transparent\r
+to the proxy; it simply quotes what was recited by the browser.\r
+<p>\r
+<a name="personalize">If you want to send wafers only to specific sites,</a>\r
+you could try putting them your browser's cookie file in a format\r
+conforming to the Netscape\r
+<a href="links.html#netscape">specification</a>,\r
+and then specify in the proxy's cookiefile that cookies are to be\r
+<a href="ijbfaq.html#directional">sent to</a>\r
+but not accepted from those sites, so they can't overwrite the file.\r
+This may work with Netscape but not all other browsers.\r
+</p>\r
+\r
+<h3><a name="jar" href="/cgi-bin/gp?pg=ijbfaq&pr=jar"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Why would anyone want to save their cookies in a ``cookie jar?''\r
+</h3>\r
+<p>\r
+We provided this capability just in case anyone wants it.\r
+There are a few possible reasons.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="pay">It's conceivable that</a>\r
+marketing companies might one day\r
+<a href="new.html#hagel">buy</a>\r
+history files and cookie jars from consumers\r
+in the same way that they currently pay them to fill out survey forms.\r
+With this information they could\r
+gather psychographic information,\r
+see which competitors' sites the consumer has visited,\r
+and discover what advertising is being targeted at them.\r
+<li>\r
+<a name="choose">Some consumers might</a>\r
+employ semi-automated means of sorting through\r
+their cookie jars, selecting which ones to place in their cookies\r
+file for use by their browsers.\r
+Their decisions could be based on payments offered,\r
+privacy rating systems such as\r
+<a href="links.html#truste">TRUSTe</a>\r
+proposes,\r
+or their own opinion of the company.\r
+It could be done manually or with software.\r
+<li>\r
+<a name="share">Users may even start ``sharing'' cookies among themselves,</a>\r
+sending back cookies that servers generated for other visitors.\r
+Servers that aren't expecting this possibility\r
+will be misled about their visitors' identities.\r
+Cookies could be shared among users on a single machine,\r
+or across continents via\r
+<small>FTP</small>\r
+and anonymous remailers.\r
+<a name="disinformation">Privacy activists may promote</a>\r
+cookie disinformation campaigns\r
+as a way to defend the public against abuse.\r
+If a significant percentage of people send disinformative cookies,\r
+user tracking via cookies may become less reliable and less used.\r
+</ul>\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="anonymity"><font face="arial, helvetica">\r
+Anonymity\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>For details\r
+on how your identity can be revealed while you surf,\r
+see our page on\r
+<a href="http://www.junkbusters.com/cgi-bin/privacy">privacy.</a>\r
+Once you start using\r
+the\r
+Internet Junkbuster\r
+you should find that much of the information\r
+previously indicated on that page will no longer be provided.\r
+If the\r
+<big><kbd>REMOTE HOST</kbd></big>\r
+indicating your IP address is too close for comfort,\r
+see our suggestions\r
+<a href="ijbfaq.html#conceal">below</a>\r
+on how to\r
+conceal\r
+your IP address.\r
+We also recommend that you\r
+<a href="cookies.html">disable JavaScript</a>\r
+and\r
+<a href="links.html#java">Java.</a>\r
+\r
+<h3><a name="disclose" href="/cgi-bin/gp?pg=ijbfaq&pr=disclose"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+If I use the Internet Junkbuster, will my anonymity be guaranteed?\r
+</h3>\r
+<p>\r
+No. Your chances of remaining anonymous are improved,\r
+but unless you are an expert on Internet security\r
+it would be safest to assume that everything you do on the Web\r
+can be attributed to you personally.\r
+<p>\r
+<a name="happen">The</a>\r
+Internet Junkbuster\r
+removes various information about you,\r
+but it's still possible that web sites can find out who you are.\r
+Here's one way this can happen.\r
+<p>\r
+<a name="ftp">A few browsers</a>\r
+<a href="http://www.junkbusters.com/cgi-bin/privacy">disclose the user's email address</a>\r
+in certain situations, such as when transferring a file by\r
+<small>FTP</small>.\r
+The\r
+Internet Junkbuster 2.0\r
+does not filter the\r
+<small>FTP</small>\r
+stream.\r
+If you need this feature, or are concerned about the mail handler\r
+of your browser disclosing your email address,\r
+you might consider\r
+products such as\r
+<a href="links.html#nsclean">NSClean</a>.\r
+<p>\r
+<a name="binaries">Browsers downloaded as binaries</a>\r
+could use non-standard headers to give out any information\r
+they can have access to: see the manufacturer's license agreement.\r
+It's impossible to anticipate and prevent every breach of privacy that\r
+might occur.\r
+The professionally paranoid prefer browsers available as source code,\r
+because anticipating their behavior is easier.\r
+</p>\r
+\r
+<h3><a name="should" href="/cgi-bin/gp?pg=ijbfaq&pr=should"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Why should I trust my ISP or Junkbusters with my browsing data?\r
+</h3>\r
+<p>\r
+You shouldn't have to trust us, and you certainly don't have to.\r
+We do not run the proxy as a service,\r
+where we could observe your online behavior.\r
+We provide source code so that everyone can see that the proxy isn't\r
+doing anything sneaky.\r
+<p>\r
+<a name="awful">You are already trusting your</a>\r
+<small>ISP</small>\r
+not to look at an awful lot of information on what you do.\r
+They probably post a\r
+<a href="links.html#policy">privacy policy</a>\r
+on their site to reassure you.\r
+If they run a proxy for you, using it could actually\r
+make it slightly easier for them to monitor you,\r
+but we doubt that any sane\r
+<small>ISP</small>\r
+would try this,\r
+because if it were discovered customers would desert them.\r
+</p>\r
+\r
+<h3><a name="header" href="/cgi-bin/gp?pg=ijbfaq&pr=header"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What private information from server-bound headers is removed?\r
+</h3>\r
+<p>\r
+The\r
+Internet Junkbuster\r
+pounces on the following\r
+<small>HTTP</small>\r
+headers in requests to servers,\r
+unless instructed otherwise in the options.\r
+<br><ul  type="1">\r
+<li>\r
+<a name="from">The</a>\r
+<big><kbd>FROM</kbd></big>\r
+header,\r
+which a few browsers use to tell your email address to servers,\r
+is dropped\r
+unless the\r
+<a href="ijbman.html#from">from</a>\r
+option is set.\r
+<li>\r
+<a name="agent">The</a>\r
+<big><kbd>USER_AGENT</kbd></big>\r
+<a name="infer">header</a>\r
+is changed to indicate that the browser is\r
+currently Mozilla (Netscape) 3.01 Gold\r
+with an unremarkable Macintosh configuration.\r
+Misidentification helps resist certain\r
+<a href="ijbfaq.html#misidentify">attacks.</a>\r
+If your browser and hardware happen to be accurately identified,\r
+you might want to change the default.\r
+(Earlier versions of the\r
+Internet Junkbuster\r
+indicated different details;\r
+by altering them periodically we aim to hinder anyone trying to\r
+<a href="ijbfaq.html#detect">infer</a>\r
+whether our proxy is present.)\r
+<a name="lying">If you don't like the idea</a>\r
+of incorrectly identifying your computer as a Mac,\r
+set it accordingly.\r
+<!-- Aside: or read Kundera's Unbearable Lightness of Being, 5:5, ``It is a tragicomic fact..'' (p187?) -->\r
+<li>\r
+<a name="referer">The</a>\r
+<big><kbd>REFERER</kbd></big>\r
+header\r
+(which indicates where the\r
+<small>URL</small>\r
+currently being requested was found)\r
+is dropped.\r
+A single static referer to replace all\r
+real referers may be specified using the \r
+<a href="ijbman.html#referer">referer</a>\r
+option.\r
+Where no referer is provided by the browser, none is added;\r
+the\r
+<a href="ijbman.html#add-header">add-header</a>\r
+option with arguments such as\r
+<big><kbd>-x 'Referer: http://me.me.me'</kbd></big>\r
+can be used to send a bogus referer with every request.\r
+</ul>\r
+In \r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and later you can use the\r
+<a href="ijbman.html#o_r">-r @</a>\r
+option to selectively disclose\r
+<big><kbd>REFERER</kbd></big>\r
+and\r
+<big><kbd>USER_AGENT</kbd></big>\r
+to only those sites you nominate.\r
+<p>\r
+<a name="UA">Some browsers</a>\r
+send Referer and User-Agent information under different non-standard headers.\r
+The\r
+Internet Junkbuster 2.0\r
+stops\r
+<big><kbd>UA</kbd></big>\r
+headers,\r
+but others may get through.\r
+This information is also available via JavaScript,\r
+so\r
+<a href="cookies.html">disable disable</a>\r
+it.\r
+<a name="indexers">Some search engines</a>\r
+<a href="cookies.html#queries">encode the query you typed</a>\r
+in the\r
+<small>URL</small>\r
+that goes to advertisers to target a banner ad at you,\r
+so you will need to block the ad as well as the referer header,\r
+unless you want them (and anyone they might\r
+<a href="cookies.html#set">buy data</a>\r
+from)\r
+to know\r
+<a href="links.html#search">everything you ever search for.</a>\r
+<p>\r
+<a name="JavaScript">If you have JavaScript enabled (the default on</a>\r
+most browsers) servers can use it to obtain Referer and User Agent,\r
+as well as your plug-ins.\r
+We recommend\r
+<a href="cookies.html#java">disabling</a>\r
+JavaScript and Java.\r
+<p>\r
+<a name="response">Currently no</a>\r
+<small>HTTP</small>\r
+response headers (browser bound)\r
+are removed,\r
+not even the\r
+<big><kbd>Forwarded:</kbd></big>\r
+or\r
+<big><kbd>X-Forwarded-For:</kbd></big>\r
+headers.\r
+Nor are any added,\r
+<a href="ijbman.html#o_y">unless requested.</a>\r
+We are considering a more flexible header management system for\r
+a future version.\r
+</p>\r
+\r
+<h3><a name="breakage" href="/cgi-bin/gp?pg=ijbfaq&pr=breakage"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Might some things break because header information is changed?\r
+</h3>\r
+<p>\r
+Possibly.  If used with a browser less advanced than Netscape 3.0 or IE-3,\r
+indicating an advanced browser\r
+may encourage pages containing extensions that confuse your browser.\r
+If this becomes a problem\r
+upgrade your browser or\r
+use the\r
+<a href="ijbman.html#user-agent">user-agent</a>\r
+option to indicate an\r
+<a href="ijbfaq.html#low">older browser.</a>\r
+In \r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and later you can selectively reveal your real browser\r
+to only those sites you nominate.\r
+<p>\r
+<a name="Russian">Because different browsers</a>\r
+use different encodings of Russian characters,\r
+certain web servers convert pages on-the-fly according to the User Agent\r
+header. Giving a User Agent with the wrong operating system or\r
+browser manufacturer causes some Russian sites to be garbled;\r
+Russian surfers should\r
+<a href="ijbman.html#o_r">change it</a>\r
+to something closer.\r
+<p>\r
+<a name="counters">Some</a>\r
+<a href="http://www.yahoo.com/Computers_and_Internet/Internet/World_Wide_Web/Programming/Access_Counts/">page access counters</a>\r
+work by looking at the referer;\r
+they may fail or break when deprived.\r
+<p>\r
+<a name="wired">Some sites depend on getting a referer header,</a>\r
+such as\r
+<big><kbd>uclick.com</kbd></big>,\r
+which serves comic strips\r
+for many newspaper sites,\r
+including\r
+<a href="http://www.uclick.com/?feature=db"><cite>Doonsbury</cite></a>\r
+for the\r
+<a href="http://www.washingtonpost.com/wp-srv/style/longterm/comics/comics.htm"><cite>Washington Post.</cite></a>\r
+(If you click on that last link, you can then get to a page containing\r
+the strip via the\r
+same\r
+<small>URL</small>\r
+we've linked to under\r
+<cite>Doonsbury</cite>,\r
+but if you click on the\r
+<cite>Doonsbury</cite>\r
+link directly, it gives you an error message suggesting that you\r
+use a browser that supports referers.)\r
+In \r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and later you can use the\r
+<a href="ijbman.html#o_r">-r @</a>\r
+option\r
+and place a line like\r
+<big><kbd>&gt;uclick.com</kbd></big>\r
+in your cookiefile.\r
+<a href="http://www.wired.com/news/">Wired News</a>\r
+used to use referer to decide whether to add a navigation column to\r
+the page, but they have changed that.\r
+<p>\r
+<a name="Intellicast">The weather maps of</a>\r
+<a href="links.html#Intellicast">Intellicast</a>\r
+have been blocked by their server when no referer or cookie is provided.\r
+You can use the same countermeasure with a line such as\r
+<big><kbd>&gt;208.194.150.32</kbd></big>\r
+(or simply get your weather information\r
+<a href="ijbfaq.html#buyers">elsewhere</a>).\r
+<p>\r
+<a name="decide">Some software vendors, including</a>\r
+<a href="http://www.intuit.com/quicken_store/">Intuit</a>\r
+use\r
+<big><kbd>USER_AGENT</kbd></big>\r
+to decide which versions of their products to display to you.\r
+With the\r
+<a href="ijbfaq.html#agent">default</a>\r
+you get Mac versions.\r
+<p>\r
+<a name="resort">As a last resort if a site you need doesn't seem to be working,</a>\r
+the\r
+<a href="ijbfaq.html#set">proxy configuration</a>\r
+of many browsers allow you to specify\r
+<b><font face="arial, helvetica">\r
+No Proxy For</font></b>\r
+any hostname you want.\r
+<p>\r
+<a name="What">We had reports that on some versions of Netscape the</a>\r
+<a href="http://home.netscape.com/home/whats-new.html">What's New</a>\r
+feature did not work with the proxy,\r
+but we think we fixed this in Version 2.0.1.\r
+</p>\r
+\r
+<h3><a name="misidentify" href="/cgi-bin/gp?pg=ijbfaq&pr=misidentify"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How is misidentifying my browser good for security and privacy?\r
+</h3>\r
+<p>\r
+Almost\r
+<a href="new.html#Browser">every</a>\r
+major release of both leading browsers has contained\r
+bugs that allow malicious servers to compromise your privacy and security.\r
+Known bugs are quickly fixed, but millions of copies of the affected\r
+software remain out there, and yours is probably one of them.\r
+The\r
+<a href="ijbfaq.html#agent">header</a>\r
+that normally identifies your browser tells such servers exactly which attacks\r
+to use against you.\r
+By misidentifying your browser you reduce the likelihood that they\r
+will be able to mount a successful attack.\r
+</p>\r
+\r
+<h3><a name="conceal" href="/cgi-bin/gp?pg=ijbfaq&pr=conceal"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Does the Internet Junkbuster conceal my IP address?\r
+</h3>\r
+<p>\r
+Web sites get the IP address of any proxy or browser they serve pages to.\r
+If you run the proxy on your own computer the IP address disclosed\r
+is the same as your browser would, unless you use the\r
+<a href="ijbman.html#forwardfile">forwardfile</a>\r
+option is used to chain to another proxy,\r
+in which case servers only get the last IP address in the chain.\r
+Chaining slightly slows browsing of course, but it improves anonymity.\r
+<p>\r
+<a name="anonymizing">One public proxy that you can</a>\r
+forward to is\r
+<a href="new.html#LPWA">lpwa.com</a>\r
+port 8000.\r
+Read about its privacy-enhancing\r
+features and the authentication procedures first,\r
+and note that it blocks\r
+<a href="ijbfaq.html#wired">referer</a>\r
+in almost all cases,\r
+as well as some\r
+<a href="http://lpwa.com:8000/system.html#principles:header">other headers.</a>\r
+</p>\r
+\r
+<h3><a name="authorize" href="/cgi-bin/gp?pg=ijbfaq&pr=authorize"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+How can I set the proxy to remember my LPWA password?\r
+</h3>\r
+<p>\r
+After you log in to\r
+<a href="http://lpwa.com">LPWA</a>\r
+it tells your browser to send a\r
+<big><kbd>Proxy-authorization</kbd></big>\r
+header with each request.\r
+Whenever you shut down the browser and start again with a new browser,\r
+you need to log in again.\r
+If you are the only person using the\r
+Internet Junkbuster\r
+proxy, you can avoid repeated logins to\r
+<a href="http://lpwa.com">LPWA</a>\r
+by telling the\r
+Internet Junkbuster\r
+to send the information by placing a line such as\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>add-header Proxy-authorization: Basic ZHVtbXk=.</kbd></big>\r
+<br>\r
+in the configuration file.\r
+The exact example above\r
+<em>does not work</em>\r
+because the code\r
+<big><kbd>ZHVtbXk=.</kbd></big>\r
+is a bogus one that\r
+<a href="http://lpwa.com">LPWA</a>\r
+would never generate;\r
+follow the procedure below to generate a valid one.\r
+<br><ol  type="1">\r
+<li>\r
+<a name="eight">Restart your</a>\r
+Internet Junkbuster\r
+with\r
+<big><kbd>debug 8</kbd></big>\r
+so you can see the\r
+<a href="ijbman.html#o_d">headers.</a>\r
+<li>\r
+<a name="login">Log in to</a>\r
+<a href="http://lpwa.com">LPWA</a>\r
+and go to any other site.\r
+<li>\r
+<a name="observe">Find the</a>\r
+<big><kbd>Proxy-authorization</kbd></big>\r
+header from the debug output and paste it\r
+after the word\r
+<a href="ijbman.html#add-header">add-header</a>\r
+into the config file.\r
+Also change the debug value back again.\r
+<li>\r
+<a name="return">Shut down your browser, start it up again, and</a>\r
+restart the proxy. Test that it works.\r
+</ol>\r
+This trick is convenient for sole users, but is not suitable when\r
+more than one person uses the proxy, because they will all get the\r
+same\r
+<a href="http://lpwa.com">LPWA</a>\r
+identity.\r
+</p>\r
+\r
+<h3><a name="ident" href="/cgi-bin/gp?pg=ijbfaq&pr=ident"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Does the Internet Junkbuster thwart identification by identd?\r
+</h3>\r
+<p>\r
+We think so,\r
+provided you are not the user running the\r
+proxy.\r
+If your computer (or your\r
+<small>ISP</small>'s)\r
+is running the\r
+<a href="links.html#identd"><kbd>identd</kbd></a>\r
+demon,\r
+servers can ask it for the identity of the\r
+user making the request at time you request a page from them.\r
+But if you're going through a proxy,\r
+they will identify the user name associated with the proxy, not you.\r
+A visit to\r
+<a href="http://ident.junkbusters.com">http://ident.junkbusters.com</a>\r
+lets you see what's happening.\r
+This test is (quite rightly) blocked by many\r
+<a href="ijbfaq.html#firewall">firewalls;</a>\r
+just interrupt the transfer if you get an abnormal wait after clicking.\r
+Running other applications\r
+may also expose you via\r
+<a href="links.html#identd"><kbd>identd</kbd></a>;\r
+the proxy of course doesn't help then.\r
+</p>\r
+\r
+<h3><a name="detect" href="/cgi-bin/gp?pg=ijbfaq&pr=detect"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can web sites tell that I'm using the Internet Junkbuster?\r
+</h3>\r
+<p>\r
+With the default options the proxy doesn't announce itself.\r
+Obvious indications such as\r
+<a href="links.html#alive">Keep-Alive</a>\r
+headers are\r
+<a href="ijbman.html#o_x">deleted,</a>\r
+but sites might notice that you can cancel cookies faster than\r
+any human could possibly click on a mouse.\r
+(If you want to provide a\r
+plausible explanation for this,\r
+change the User Agent header to a\r
+<a href="ijbfaq.html#lynx">cookie-free</a>\r
+or\r
+<a href="cookies.html#communicator">cookie-crunching</a>\r
+browser).\r
+<p>\r
+<a name="figure">But when certain options</a>\r
+are used they could figure out something's going on,\r
+even if they're not pushing cookies.\r
+If you use blocking\r
+they can tell from their logs that the graphics in their pages\r
+are not being requested selectively.\r
+The\r
+<a href="ijbman.html#add-forwarded-header">add-forwarded-header</a>\r
+option explicitly announces to the server that a proxy is present,\r
+and\r
+sending them\r
+<a href="ijbfaq.html#wafers">wafers</a>\r
+is of course a dead giveaway.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<br>\r
+<center>\r
+<h2><a name="security"><font face="arial, helvetica">\r
+Security\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>\r
+<h3><a name="encrypt" href="/cgi-bin/gp?pg=ijbfaq&pr=encrypt"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+What happens with Secure Documents (SSL, https:)?\r
+</h3>\r
+<p>\r
+If you enter a\r
+``Secure Document Area,''\r
+cookies and other header information\r
+such as User Agent and Referer\r
+are sent encrypted,\r
+so they cannot be filtered.\r
+We recommend getting your browser to alert you when this happens.\r
+(On Netscape:\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Security</font></b>;\r
+<b><font face="arial, helvetica">\r
+General</font></b>;\r
+<b><font face="arial, helvetica">\r
+Show an alert before entering a secure document space</font></b>.) \r
+We also recommend adding the line\r
+<big><kbd>:443</kbd></big>\r
+to the blockfile to stop all but sites specified in an exception\r
+after that line from using SSL.\r
+<p>\r
+<a name="passage">It may be possible to filter encrypted cookies</a>\r
+by combining the blocking proxy with a cryptographic proxy along\r
+the lines of\r
+<a href="http://stronghold.ukweb.com/safepassage/">SafePassage</a>,\r
+but we have not tried this.\r
+</p>\r
+\r
+<h3><a name="ssl" href="/cgi-bin/gp?pg=ijbfaq&pr=ssl"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Will using this as my Security Proxy compromise security?\r
+</h3>\r
+<p>\r
+We're not security experts, but we don't think so.\r
+The whole point of\r
+<small>SSL</small>\r
+is that the\r
+contents of messages are\r
+<!-- IEM: http://addy.com/dc/html/what_is_ssl_.html -->\r
+encrypted\r
+by the time\r
+they leave the browser and the server.\r
+Eavesdroppers (including proxies) can see where your messages are going\r
+whether you are running a proxy or not,\r
+but they only get to see the contents after they have been encrypted.\r
+</p>\r
+\r
+<h3><a name="restrict" href="/cgi-bin/gp?pg=ijbfaq&pr=restrict"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Can I restrict use of the proxy to a set of nominated IP addresses?\r
+</h3>\r
+<p>\r
+Yes, we added an\r
+<a href="ijbman.html#aclfile">access control</a>\r
+file in Version 2.0.\r
+But before you use it please consider why you want to do it.\r
+If the reason is security,\r
+it probably means you need a firewall.\r
+<p>\r
+<a name="selective">The</a>\r
+<a href="ijbman.html#listen-address">listen-address</a>\r
+option provides a way of binding the proxy to a single IP address/port.\r
+The right way to do this is to choose a port inside your firewall, and\r
+deny access to it to those outside the firewall.\r
+The\r
+Internet Junkbuster\r
+is not a firewall proxy;\r
+it should not be expected to solve security problems.\r
+<p>\r
+<a name="firewall">For background information on firewalls,</a>\r
+see\r
+<a href="http://www.yahoo.com/Computers_and_Internet/Security_and_Encryption/Firewalls/">Yahoo</a>\r
+or a\r
+<a href="http://www.netscapeworld.com/ned-02-1998/ned-02-firewall.html">magazine article</a>\r
+or these well-known books:\r
+<a href="http://www.amazon.com/exec/obidos/ISBN=0201633574/junkbusterscomA/"><cite>Firewalls and Internet Security: Repelling the Wily Hacker</cite></a>\r
+by\r
+<person>William R. Cheswick</person>\r
+and\r
+<person>Steven M. Bellovin</person>\r
+or\r
+<a href="http://www.amazon.com/exec/obidos/ISBN=1565921240/junkbusterscomA/"><cite>Building Internet Firewalls</cite></a>\r
+by\r
+<person>D. Brent Chapman</person>\r
+and\r
+<person>Elizabeth D. Zwicky</person>.\r
+There's\r
+<!-- IEM: http://www.wmd.de/wmd/staff/pauck/misc/fwtk_on_linux.html -->\r
+free Linux software\r
+available,\r
+and a large number of\r
+<a href="http://www.yahoo.com/Business_and_Economy/Companies/Computers/Software/System_Utilities/Security/Firewalls/">commercial</a>\r
+products and services.\r
+For an excellent security overview, primer, and compendium reference, see\r
+<a href="http://www.amazon.com/exec/obidos/ISBN=1565921488/junkbusterscomA/"><cite>Practical Unix and Internet Security</cite></a>\r
+by\r
+<person>Simson Garfinkel</person>\r
+and\r
+<person>Gene Spafford</person>.\r
+</p>\r
+\r
+<h3><a name="others" href="/cgi-bin/gp?pg=ijbfaq&pr=others"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Are there any security risks for ISPs or others who offer the proxy?\r
+</h3>\r
+<p>\r
+Yes.\r
+As with any service offered over the Internet,\r
+hackers can try to misuse it.\r
+A well-run\r
+<small>ISP</small>\r
+will have professionals who are experienced at assessing and containing\r
+these risks.\r
+<p>\r
+<a name="outside">It's possible to set up your machine so</a>\r
+that other people can have access to your proxy,\r
+but if you lack expertise in computer security\r
+you probably shouldn't have your computer configured to offer\r
+this or any other service to the outside world.\r
+<p>\r
+<a name="attack">Hackers can attempt to gain access</a>\r
+to the machine by various attacks,\r
+which we have tried to guard against but don't guarantee to thwart.\r
+They can also use the ``anonymizing'' quality of proxies\r
+to try to cover their tracks while hacking other computers.\r
+For this reason we recommend preventing it being used\r
+as an anonymous\r
+<big><kbd>telnet</kbd></big>\r
+by putting the pattern\r
+<big><kbd>:23</kbd></big>\r
+in the blockfile (it's included as standard equipment).\r
+(Actually the current implementation incidentally blocks telnet due to the\r
+way headers are handled, but it's best not to rely on this.)\r
+If you wish to block all ports except the default\r
+<small>HTTP</small>\r
+port 80,\r
+you can put the lines\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>:</kbd></big>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>~:80</kbd></big>\r
+<br>\r
+at the beginning of the blockfile, but be aware that some servers\r
+run on non-default ports (e.g. 8080). You might also want to add the line\r
+<big><kbd>~:443</kbd></big>\r
+to allow\r
+<small>SSL</small>.\r
+<p>\r
+<a name="root">On</a>\r
+<small>UNIX <a href="legal.html#not_our_trademark">&#174;</a></small>\r
+systems it is neither necessary nor desirable for the proxy to run as root.\r
+<p>\r
+<a name="patched">Versions 2.0.1 and below may be vulnerable to remote</a>\r
+exploitation of a memory buffer bug; for security reasons all users\r
+are encouraged to\r
+<a href="ijbdist.html#upgrade">upgrade.</a>\r
+<p>\r
+<a name="holes">If you find any security holes in the code</a>\r
+please\r
+<a href="/cgi-bin/gp?pg=ijbfaq&pr=holes">tell us,</a>\r
+along with any suggestions you may have for fixing it.\r
+However, we do not claim that we will be able to do so.\r
+<p>\r
+<a name="useful">We distribute this code in the hope that people</a>\r
+will find it useful, but we provide\r
+<a href="ijbfaq.html#free">no warranty</a>\r
+for it,\r
+and we are not responsible for anyone's use or misuse of it.\r
+<p>\r
+<a name="updates">You may also want to check back periodically for updated versions of the code.</a>\r
+We do not\r
+maintain a mailing list.\r
+To get quick updates, bookmark our\r
+<a href="ijbdist.html#versions">Distribution Information</a>\r
+page.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<font face="arial, helvetica">\r
+<a rel="begin" href="index.html">Home</a> <font color="#ff0000">\r
+<b> &#183; </b></font>\r
+<a rel="next" href="ijbman.html">Next</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="lopt.html">Site Map</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="legal.html">Legal</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkdata.html">Privacy</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="cookies.html">Cookies</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijb.html">Banner Ads</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="telemarketing.html">Telemarketing</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkmail.html">Mail</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkemail.html">Spam</a>\r
+\r
+</font><form action="/cgi-bin/search" method="GET">\r
+<input type="text" name="q" size=60 maxlength=120 value="">\r
+<input type="submit" value="Search"></form>\r
+<small>\r
+<small>\r
+<p>\r
+<a href="legal.html#copy">Copyright</a> &#169; 1996-8 Junkbusters\r
+<a href="legal.html#marks">&#174;</a> Corporation.\r
+Copying and distribution permitted under\r
+the <a href="gpl.html"><small>GNU</small></a>\r
+General Public License.\r
+</small>\r
+<tt>\r
+1998/10/31\r
+http://www.junkbusters.com/ht/en/ijbfaq.html\r
+</tt>\r
+<address><kbd>webmaster&#64;junkbusters.com</kbd></address>\r
+</small>\r
+</body>\r
+</html>\r
diff --git a/doc/ijbman.html b/doc/ijbman.html
new file mode 100644 (file)
index 0000000..710cddb
--- /dev/null
@@ -0,0 +1,920 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\r
+<html>\r
+<head>\r
+<!-- Copyright 1996-8 Junkbusters Corporation -->\r
+<!-- This work comes with NO WARRANTY -->\r
+<!-- It may be redistributed and modified under the GNU GPL-->\r
+<!-- See the body of http://www.junkbusters.com/ht/en/gpl.html for details-->\r
+<!-- Junkbusters is a registered trade mark of Junkbusters Corporation -->\r
+<!-- Generated 1998/10/31 03:58:25 UTC -->\r
+<meta name="Generator" content="Junkbusters Ebira $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $">\r
+<!-- Document  ID: $Revision: 1.1 $ $Date: 2001/04/16 21:10:38 $ -->\r
+<title>\r
+Internet Junkbuster Technical Information\r
+</title>\r
+<base href="http://www.junkbusters.com/ht/en/ijbman.html">\r
+<meta name="description" content="The manual page for the Internet Junkbuster, free software to removes banner ads, cookies, and other stuff you don't want from your web browser.">\r
+<meta name="keywords" content="stop, junk, busters, junkbusters, junkbuster, mail, email, e-mail, direct, spam, spamoff, declare, telemarketing, telemarketers, privacy, sharing, names, renting, direct, marketing, database, databases, junk mail, lists, environment, conservation, recycling, catalogs, consumer, sending, opt out ">\r
+<link rel="next" href="cookies.html">\r
+<link rel="previous" href="ijbfaq.html">\r
+<link rel="contents" href="toc.html">\r
+</head>\r
+<body bgcolor="#f8f8f0" link="#000078" alink="#ff0022" vlink="#787878">\r
+<center>\r
+<h1><a name="top_of_page">Internet J<small>UNK<i><font color=red>BUSTER</font></i></small> Technical Information\r
+</a></h1>\r
+</center>\r
+<font face="arial, helvetica">\r
+<p align="center">\r
+<a href="#description">Options</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#show">Checking Options</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#install">Installation</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="#copyright">Copyright</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijbfaq.html#top_of_page">(FAQ)</a>\r
+</p>\r
+</font><br>\r
+<center>\r
+<h2><a name="man"><font face="arial, helvetica">\r
+Manual Page\r
+</font></a>\r
+</h2>\r
+</center>\r
+<br>A copy of this page\r
+in standard\r
+<big><kbd>man</kbd></big>\r
+macro format\r
+is included in the\r
+<a href="ijbfaq.html#tar">tar archive</a>.\r
+\r
+<h3><a name="name" href="/cgi-bin/gp?pg=ijbman&pr=name"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Name\r
+</h3>\r
+<p>\r
+<b><kbd>junkbuster</kbd></b>\r
+- The\r
+Internet Junkbuster\r
+Proxy\r
+<a href="legal.html#marks"><small><sup>TM</sup></small></a>\r
+</p>\r
+\r
+<h3><a name="synopsis" href="/cgi-bin/gp?pg=ijbman&pr=synopsis"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Synopsis\r
+</h3>\r
+<p>\r
+<b><kbd>junkbuster</kbd></b>\r
+<i>configfile</i>\r
+(Version 2.0 onwards)\r
+<br>\r
+<b><kbd>junkbstr.exe</kbd></b>\r
+<i>configfile</i>\r
+(Windows)\r
+<br>\r
+<b><kbd>junkbuster</kbd></b>\r
+<a href="#o_a">[-a]</a>\r
+<a href="#o_y">[-y]</a>\r
+<a href="#o_s">[-s]</a>\r
+<a href="#o_c">[-c]</a>\r
+<a href="#o_v">[-v]</a>\r
+<br>\r
+<a href="#o_u">[-u user_agent]</a>\r
+<a href="#o_r">[-r referer]</a>\r
+<a href="#o_t">[-t from]</a>\r
+<br>\r
+<a href="#o_b">[-b blockfile]</a>\r
+<a href="#o_j">[-j jarfile]</a>\r
+<a href="#o_l">[-l logfile]</a>\r
+<br>\r
+<a href="#o_w">[-w NAME=VALUE]</a>\r
+<a href="#o_x">[-x Header_text]</a>\r
+<br>\r
+<a href="#o_h">[-h [bind_host_address][:bind_port]]</a>\r
+<br>\r
+<a href="#o_f">[-f forward_host[:port]]</a>\r
+<a href="#o_d">[-d N]</a>\r
+<br>\r
+<a href="#o_g">[-g gw_protocol[:[gw_host][:gw_port]]]</a>\r
+<br>\r
+(Version 1.4 and earlier)\r
+</p>\r
+\r
+<h3><a name="description" href="/cgi-bin/gp?pg=ijbman&pr=description"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Description\r
+</h3>\r
+<p>\r
+<b><kbd>junkbuster</kbd></b>\r
+is an instrumentable proxy that filters the \r
+<small>HTTP</small>\r
+stream between\r
+web servers and browsers.\r
+Its main purpose is to enhance privacy.\r
+<p>\r
+<a name="dual">Versions before 2.0 used command-line options;</a>\r
+Versions from 2.0 onward use a configuration file.\r
+The following descriptions of the options first give the older\r
+command-line usage, then the new configfile line.\r
+<p>\r
+<a name="won">In Versions 2.0.1 upwards on Windows,</a>\r
+a start-up message is printed and the configuration is read from the file\r
+<big><kbd>junkbstr.ini</kbd></big>\r
+if it exists and no argument was given.\r
+<p>\r
+<a name="reread">All files except the configfile</a>\r
+are checked for changes before each page is fetched,\r
+so they may edited without restarting the proxy.\r
+<h4>Options\r
+</h4>\r
+<dl><p><dt><i><a name="o_b">-b blockfile</a></i><br><a name="blockfile"><tt>blockfile</tt>&#160;&#160;<i>blockfile</i></a><dd>\r
+<a href="ijbfaq.html#blocking">Block</a>\r
+requests to\r
+<small>URL</small>s\r
+matching any pattern given in the lines of the\r
+<i>blockfile</i>.\r
+The\r
+<b><kbd>junkbuster</kbd></b>\r
+instead returns status 202, indicating that the request has been accepted\r
+(though not completed),\r
+and a\r
+<a href="ijbfaq.html#show">message identifying itself</a>\r
+(though the browser may\r
+display only a broken image icon).\r
+(Versions before 2.0 returned an error 403 (Forbidden).)\r
+The syntax of a pattern is\r
+<big><kbd>[domain][:port][/path]</kbd></big>\r
+(the\r
+<big><kbd>http://</kbd></big>\r
+or\r
+<big><kbd>https://</kbd></big>\r
+protocol part is omitted).\r
+To decide if a pattern matches a target, the domains are compared first,\r
+then the paths. \r
+<p>\r
+<a name="compare">To compare the domains,</a>\r
+the pattern domain and the target\r
+domain specified in the\r
+<small>URL</small>\r
+are each broken into their components.\r
+(Components are separated by the\r
+<big><kbd>.</kbd></big>\r
+(period) character.)\r
+Next each of the target components\r
+is compared with the corresponding pattern component: last with last,\r
+next-to-last with next-to-last, and so on.\r
+(This is called\r
+<i><dfn>right-anchored</dfn></i>\r
+matching.)\r
+If all of the pattern components find their match in the target,\r
+then the domains are considered a match.\r
+Case is irrelevant when comparing domain components.\r
+<p>\r
+<a name="substring">A successfully</a>\r
+matching pattern can be an anchored substring of a target, but\r
+not vice versa.\r
+Thus if a pattern doesn't specify a domain,\r
+it matches all domains.\r
+<a name="wildcard">Furthermore, when comparing two components,</a>\r
+the components must either match in their entirety or up to a wildcard\r
+<big><kbd>* </kbd></big>\r
+(star character) in the pattern.  The wildcard feature\r
+implements only a "prefix" match capability ("abc*" vs. "abcdefg"),\r
+not suffix matching ("*efg" vs. "abcdefg") or\r
+infix matching ("abc*efg" vs. "abcdefg").\r
+The feature is restricted to the domain component;\r
+it is unrelated to the optional\r
+regular expression\r
+feature in the path\r
+<a href="ijbman.html#regex">(described below).</a>\r
+<p>\r
+<a name="numeric">If a numeric port</a>\r
+is specified in the pattern domain, then the target port must\r
+match as well.  The default port in a target is port 80.\r
+<p>\r
+<a name="onward">If the domain and port match,</a>\r
+then the target\r
+<small>URL</small>\r
+path is checked for\r
+a match against the path in the pattern.\r
+Paths are compared with a simple case-sensitive\r
+left-anchored substring comparison.\r
+Once again, the pattern can be an\r
+anchored substring of the target, but not vice versa.\r
+A path of\r
+<big><kbd>/</kbd></big>\r
+(slash) would match all paths.  Wildcards are not considered in\r
+path comparisons.\r
+<p>\r
+<a name="example">For example, the target</a>\r
+<small>URL</small>\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>the.yellow-brick-road.com/TinMan/has_no_brain</kbd></big>\r
+<br>\r
+would be matched (and blocked) by the following patterns\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>yellow-brick-road.com</kbd></big>\r
+<br>\r
+and\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>Yellow*.COM</kbd></big>\r
+<br>\r
+and\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>/TinM</kbd></big>\r
+<br>\r
+but not\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>follow.the.yellow-brick-road.com</kbd></big>\r
+<br>\r
+or\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>/tinman</kbd></big>\r
+<br>\r
+<p>\r
+<a name="comments">Comments in a blockfile start with a</a>\r
+<big><kbd>#</kbd></big>\r
+(hash) character and end at a new line.\r
+Blank lines are also ignored.\r
+<p>\r
+<a name="except">Lines beginning with a</a>\r
+<big><kbd>~</kbd></big>\r
+(tilde) character are taken to be\r
+<a href="ijbfaq.html#exceptions">exceptions:</a>\r
+a\r
+<small>URL</small>\r
+blocked by previous patterns that matches the rest of\r
+the line is let through. (The last match wins.)\r
+<p>\r
+<a name="regex">Patterns</a>\r
+may contain\r
+<small>POSIX</small>\r
+<a href="ijbfaq.html#regex">regular expressions</a>\r
+provided the\r
+<b><kbd>junkbuster</kbd></b>\r
+was compiled with this option\r
+(the default in Version 2.0 on).\r
+The idiom\r
+<big><kbd>/*.*/ad</kbd></big>\r
+can then be used\r
+to match any\r
+<small>URL</small>\r
+containing\r
+<big><kbd>/ad</kbd></big>\r
+(such as\r
+<big><kbd>http://nomatterwhere.com/images/advert/g3487.gif</kbd></big>\r
+for example).\r
+These expressions\r
+<a href="ijbman.html#substring">don't work</a>\r
+in the domain part.\r
+<p>\r
+<a name="rereads">In version 1.3 and later</a>\r
+the blockfile and cookiefile are checked for changes before each request.\r
+<p><dt><i><a name="o_w">-w NAME=VALUE</a></i><br><a name="wafer"><tt>wafer</tt>&#160;&#160;<i>NAME=VALUE</i></a><dd>\r
+Specifies a pair to be sent as a cookie with every request\r
+<a href="ijbfaq.html#wafers">to the server.</a>\r
+(Such boring cookies are called\r
+<i>wafers</i>.)\r
+This option may be called more than once to generate multiple wafers.\r
+The original\r
+Netscape specification\r
+prohibited\r
+semi-colons, commas and white space;\r
+these characters will be\r
+<small>URL</small>-encoded\r
+if used in wafers.\r
+<!-- Aside: genuine cookies are not encoded -->\r
+<!-- Aside: we could use quoted string as specified in the new RFC -->\r
+The Path and Domain attributes are not currently supported.\r
+<p><dt><i><a name="o_c">-c cookiefile</a></i><br><a name="cookiefile"><tt>cookiefile</tt>&#160;&#160;<i>cookiefile</i></a><dd>\r
+Enforce the cookie management policy specified in the\r
+<i>cookiefile.</i>\r
+<a name="java">If this option is not used all cookies are silently crunched,</a>\r
+so that users who never want cookies aren't bothered by browsers\r
+asking whether each cookie should be accepted.\r
+However, cookies can\r
+<a href="ijbfaq.html#breakthrough">still get through</a>\r
+via\r
+<a href="links.html#javascript">JavaScript</a>\r
+and\r
+<small>SSL</small>,\r
+so alerts should be left on.\r
+<p>\r
+<a name="dropping">In Version 1.2 and later</a>\r
+this option must be followed by a\r
+<a href="ijbfaq.html#crumble">filename</a>\r
+containing instructions on which sites are allowed to\r
+receive and set cookies.\r
+<a name="drop">By default cookies are dropped in both the browser's request</a>\r
+and the server's response, unless the\r
+<small>URL</small>\r
+requested matches an entry in the\r
+<i>cookiefile</i>.\r
+The matching algorithm is the same as for the blockfile.\r
+A leading\r
+<big><kbd>&gt;</kbd></big>\r
+character allows\r
+<a href="ijbfaq.html#directional">server-bound</a>\r
+cookies only;\r
+a\r
+<big><kbd>&lt;</kbd></big>\r
+allows only browser-bound cookies;\r
+a\r
+<big><kbd>~</kbd></big>\r
+character stops cookies in\r
+<a href="ijbfaq.html#crumble">both directions.</a>\r
+Thus a cookiefile containing a single line with the two characters\r
+<big><kbd>&gt;*</kbd></big>\r
+will pass on all cookies to servers but not give any new ones to the browser.\r
+<p><dt><i><a name="o_j">-j jarfile</a></i><br><a name="jarfile"><tt>jarfile</tt>&#160;&#160;<i>jarfile</i></a><dd>\r
+All Set-cookie attempts by the server are\r
+<a href="ijbfaq.html#jar">logged</a>\r
+to\r
+<i>jarfile</i>.\r
+If no wafer is specified,\r
+one containing a\r
+<a href="ijbfaq.html#notice">canned notice</a>\r
+(the \r
+<i>vanilla wafer</i>)\r
+is added as an alert to the server\r
+unless the\r
+<a href="ijbman.html#suppress-vanilla-wafer">suppress-vanilla-wafer</a>\r
+<!-- Aside: (no vanilla~wafer) -->\r
+option is invoked.\r
+<p><dt><i><a name="o_v">-v</a></i><br><a name="suppress-vanilla-wafer"><tt>suppress-vanilla-wafer</tt></a><dd>\r
+Suppress the vanilla wafer.\r
+<p><dt><i><a name="o_t">-t from</a></i><br><a name="from"><tt>from</tt>&#160;&#160;<i>from</i></a><dd>\r
+If the browser\r
+<a href="ijbfaq.html#from">discloses an email address</a>\r
+in the\r
+<big><kbd>FROM</kbd></big>\r
+header (most don't),\r
+replace it with\r
+<i>from.</i>\r
+If\r
+<i>from</i>\r
+is set to\r
+<b>.</b>\r
+(the period character)\r
+the\r
+<big><kbd>FROM</kbd></big>\r
+is passed to the server unchanged.\r
+The default is to delete the\r
+<big><kbd>FROM</kbd></big>\r
+header.\r
+<p><dt><i><a name="o_r">-r referer</a></i><br><a name="referer"><tt>referer</tt>&#160;&#160;<i>referer</i></a><dd>\r
+Whenever the browser discloses the\r
+<small>URL</small>\r
+that\r
+<a href="ijbfaq.html#referer">led to</a>\r
+the current request,\r
+replace it with\r
+<i>referer.</i>\r
+If\r
+<i>referer</i>\r
+is set to\r
+<b>.</b>\r
+(period)\r
+the \r
+<small>URL</small>\r
+is passed to the server unchanged.\r
+In \r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and later, if referer is set to \r
+<b>@</b>\r
+(at) the\r
+<small>URL</small>\r
+is sent in cases where the cookiefile\r
+specifies that a cookie would be sent.\r
+(No way to send bogus referers selectively is provided.)\r
+The default is to delete Referer.\r
+<p>\r
+<a name="referrer">Version 2.0 also accepts the spelling</a>\r
+<big><kbd>referrer</kbd></big>,\r
+which most dictionaries consider correct.\r
+<p><dt><i><a name="o_u">-u user-agent</a></i><br><a name="user-agent"><tt>user-agent</tt>&#160;&#160;<i>user-agent</i></a><dd>\r
+Information disclosed by the browser\r
+<a href="ijbfaq.html#agent">about itself</a>\r
+is replaced with the value\r
+<i>user-agent.</i>\r
+If\r
+<i>user-agent</i>\r
+is set to\r
+<b>.</b>\r
+(period)\r
+the\r
+<big><kbd>User-Agent</kbd></big>\r
+header is passed to the server unchanged,\r
+along with any\r
+<big><kbd>UA</kbd></big>\r
+headers produced by\r
+<small>MS-IE</small>\r
+(which would otherwise be deleted).\r
+In \r
+Version <a href="ijbdist.html#c4">1.4</a>\r
+and later, if\r
+<i>user-agent</i>\r
+is set to\r
+<b>@</b>\r
+(at) these headers are sent unchanged in cases where the cookiefile\r
+specifies that a cookie would be sent,\r
+otherwise only default\r
+<big><kbd>User-Agent</kbd></big>\r
+header is sent.\r
+That default\r
+is Mozilla/3.0 (Netscape)\r
+with an unremarkable\r
+<a href="ijbfaq.html#infer">Macintosh</a>\r
+configuration.\r
+If used with a browser less advanced than Mozilla/3.0 or IE-3, the default\r
+may encourage pages containing extensions that confuse the browser.\r
+<!-- Aside: Some servers use extensions to everyone anyway.  But in that case it's probably ignoring cookies anyway.  Some servers attempt to send cookies only to browsers identifying themselves as Mozilla. -->\r
+<p><dt><i><a name="o_h">-h [host][:port]</a></i><br><a name="listen-address"><tt>listen-address</tt>&#160;&#160;<i>[host][:port]</i></a><dd>\r
+If\r
+<i>host</i>\r
+is specified,\r
+bind the\r
+<b><kbd>junkbuster</kbd></b>\r
+to that\r
+<small>IP</small>\r
+address.\r
+If a\r
+<i>port</i>\r
+is specified, use it.\r
+The default\r
+port\r
+is 8000;\r
+the default host is\r
+<big><kbd>localhost</kbd></big>.\r
+Before Version 2.0.2,\r
+the default was to bind to all \r
+<small>IP</small>\r
+addresses\r
+(<big><kbd>INADDR_ANY</kbd></big>);\r
+but this has been restricted to\r
+<big><kbd>localhost</kbd></big>\r
+to avoid unintended security breaches.\r
+(To open the proxy to all, use the line\r
+<br>\r
+&#160;&#160;&#160;<big><kbd>listen-address :8000</kbd></big>\r
+<br>\r
+in the configuration file.)\r
+<p><dt><i><a name="o_f">-f forward_host[:port]</a></i><br><a name="forwardfile"><tt>forwardfile</tt>&#160;&#160;<i>forwardfile</i></a><dd>\r
+Version 1.X required all\r
+<small>HTTP</small>\r
+requests from the client to be forwarded to the same destination.\r
+Version 2.0 takes its routing specification from a\r
+<i>forwardfile</i>,\r
+allowing selection of the proxy (a.k.a. forwarding host) and gateway\r
+according to the\r
+<small>URL</small>.\r
+Here is a typical line.\r
+<br>\r
+<pre>\r
+*         lpwa.com:8000      .      .\r
+</pre>\r
+<p>\r
+<a name="lines">Each line contains four fields:</a>\r
+<big><kbd>target</kbd></big>,\r
+<big><kbd>forward_to</kbd></big>,\r
+<big><kbd>via_gateway_type</kbd></big>\r
+and\r
+<big><kbd>gateway</kbd></big>.\r
+As usual, the\r
+<a href="ijbman.html#compare">last</a>\r
+<big><kbd>target</kbd></big>\r
+domain that matches the requested\r
+<small>URL</small>\r
+wins,\r
+and the\r
+<big><kbd>*</kbd></big>\r
+character alone matches any domain.\r
+The target domain need not be a fully qualified\r
+hostname; it can be a general domain such as\r
+<big><kbd>com</kbd></big>\r
+or\r
+<big><kbd>co.uk</kbd></big>\r
+or even just a port number.\r
+<a name="nose">For example, because</a>\r
+<a href="http://lpwa.com">LPWA</a>\r
+does not handle\r
+<a href="ijbfaq.html#encrypt">SSL</a>,\r
+the line above will typically be followed by a line such as\r
+<br>\r
+<pre>\r
+:443  .      .      .\r
+</pre>\r
+to allow SSL transactions to proceed directly.\r
+The cautious would also\r
+add an entry in their blockfile to stop transactions\r
+to port 443 for all but specified trusted sites.\r
+<p>\r
+<a name="forward">If the winning</a>\r
+<big><kbd>forward_to</kbd></big>\r
+field is\r
+<big><kbd>.</kbd></big>\r
+(the dot character) the proxy connects \r
+directly to the server given in the\r
+<small>URL</small>,\r
+otherwise it forwards to the host and port number specified.\r
+The default port is 8000.\r
+The\r
+<big><kbd>via_gateway_type</kbd></big>\r
+and\r
+<big><kbd>gateway</kbd></big>\r
+fields also use a dot to indicate no gateway protocol.\r
+The gateway protocols are explained\r
+<a href="ijbman.html#o_g">below</a>.\r
+<p>\r
+<a name="old">The example line above in a forwardfile alone</a>\r
+would send everything through port 8000 at\r
+<big><kbd>lpwa.com</kbd></big>\r
+with no gateway protocol,\r
+and is equivalent to the old\r
+<big><kbd>-f lpwa.com:8000</kbd></big>\r
+with no\r
+<big><kbd>-g</kbd></big>\r
+option.\r
+For more information see the example file provided with the distribution.\r
+<p>\r
+<a name="loop">Configure with care: no loop detection is performed.</a>\r
+When setting up chains of proxies that might loop back, try adding\r
+<a href="ijbman.html#squid">Squid.</a>\r
+<p><dt><i><a name="o_g">-g gw_protocol[:[gw_host][:gw_port]]</a></i><dd>\r
+Use\r
+<i>gw_protocol</i>\r
+as the gateway protocol.\r
+This option was introduced in Version 1.4,\r
+but was folded into the\r
+<a href="ijbman.html#forwardfile">forwardfile</a>\r
+option in Version 2.0.\r
+The default is to use no gateway protocol;\r
+this may be explicitly specified as\r
+<big><kbd>direct</kbd></big>\r
+on the command line\r
+or the dot character in the forwardfile.\r
+The\r
+<big><kbd>SOCKS4</kbd></big>\r
+protocol may be specified as\r
+<big><kbd>socks</kbd></big>\r
+or\r
+<big><kbd>socks4</kbd></big>.\r
+The\r
+<big><kbd>SOCKS4A</kbd></big>\r
+protocol is specified as\r
+<big><kbd>socks4a</kbd></big>.\r
+The\r
+<big><kbd>SOCKS5</kbd></big>\r
+protocol is not currently supported.\r
+The default\r
+<small>SOCKS</small>\r
+<i>gw_port</i>\r
+is 1080.\r
+<p>\r
+<a name="configure">The user's browser should</a>\r
+<em>not</em>\r
+be\r
+<a href="ijbfaq.html#socks">configured</a>\r
+to use\r
+<big><kbd>SOCKS</kbd></big>;\r
+the proxy conducts the negotiations, not the browser.\r
+<p>\r
+<a name="identify">The user identification capabilities of</a>\r
+<big><kbd>SOCKS4</kbd></big>\r
+are deliberately not used;\r
+the user is always identified to the\r
+<big><kbd>SOCKS</kbd></big>\r
+server as\r
+<big><kbd>userid=anonymous</kbd></big>.\r
+If the server's policy is to reject requests from\r
+<big><kbd>anonymous</kbd></big>,\r
+the proxy will not work.\r
+Use a\r
+<a href="ijbman.html#o_d">debug</a>\r
+value of 3\r
+to see the status returned by the server.\r
+<p><dt><i><a name="o_d">-d N</a></i><br><a name="debug"><tt>debug</tt>&#160;&#160;<i>N</i></a><dd>\r
+Set debug mode.\r
+The most common value is 1,\r
+to\r
+<a href="ijbfaq.html#pinpoint">pinpoint</a>\r
+offensive\r
+<small>URL</small>s,\r
+so they can be added to the blockfile.\r
+The value of\r
+<b>N</b>\r
+is a bitwise\r
+logical-<small>OR</small>\r
+of the following values:\r
+<br>\r
+1 =  URLs (show each URL requested by the browser);<br>\r
+2 =  Connections (show each connection to or from the proxy);<br>\r
+4 =  I/O (log I/O errors);<br>\r
+8 =  Headers (as each header is scanned, show the header and what is done to it);<br>\r
+16 =  Log everything (including debugging traces and the contents of the pages).<br>\r
+<a name="or">Multiple</a>\r
+<big><kbd>debug</kbd></big>\r
+lines are permitted; they are logical OR-ed together.\r
+<p>\r
+<a name="single">Because most browsers send several requests in parallel</a>\r
+the debugging output may appear intermingled, so the\r
+<a href="ijbman.html#single-threaded">single-threaded</a>\r
+option is recommended when using\r
+<a href="ijbman.html#debug">debug</a>\r
+with\r
+<b>N</b>\r
+greater than 1.\r
+<!-- Aside: Yes, it's clumsy, but it's easy to parse. -->\r
+<p><dt><i><a name="o_y">-y</a></i><br><a name="add-forwarded-header"><tt>add-forwarded-header</tt></a><dd>\r
+Add \r
+<big><kbd>X-Forwarded-For</kbd></big>\r
+headers to the server-bound \r
+<small>HTTP</small>\r
+stream\r
+indicating the client \r
+<small>IP</small>\r
+address\r
+<a href="ijbfaq.html#detect">to the server,</a>\r
+in the new style of\r
+<a href="ijbman.html#squid">Squid 1.1.4.</a>\r
+If you want the traditional\r
+<big><kbd>HTTP_FORWARDED</kbd></big>\r
+response header, add it manually with the\r
+<a href="ijbman.html#o_x">-x</a>\r
+option.\r
+<!-- Aside: Not a default, since the end-client usually doesn't wish to be identified, but may be helpful in debugging chains. -->\r
+<p><dt><i><a name="o_x">-x HeaderText</a></i><br><a name="add-header"><tt>add-header</tt>&#160;&#160;<i>HeaderText</i></a><dd>\r
+Add the\r
+<i>HeaderText</i>\r
+verbatim to requests to the server.\r
+Typical uses include\r
+adding old-style forwarding notices such as\r
+<big><kbd>Forwarded: by http://pro-privacy-isp.net</kbd></big>\r
+and reinstating the\r
+<big><kbd>Proxy-Connection: Keep-Alive</kbd></big>\r
+header\r
+(which the\r
+<b><kbd>junkbuster</kbd></b>\r
+deletes so as\r
+<a href="ijbfaq.html#detect">not</a>\r
+to reveal its existence).\r
+No checking is done for correctness or plausibility,\r
+so it can be used to throw any old trash into the server-bound \r
+<small>HTTP</small>\r
+stream.\r
+Please don't litter.\r
+<!-- Aside: this represents "more than enough rope" -->\r
+<p><dt><i><a name="o_s">-s</a></i><br><a name="single-threaded"><tt>single-threaded</tt></a><dd>\r
+Doesn't\r
+<big><kbd>fork()</kbd></big>\r
+a separate process\r
+(or create a separate thread)\r
+to handle each connection.\r
+Useful when debugging to keep the process single threaded.\r
+<p><dt><i><a name="o_l">-l logfile</a></i><br><a name="logfile"><tt>logfile</tt>&#160;&#160;<i>logfile</i></a><dd>\r
+Write all debugging data into\r
+<i>logfile.</i>\r
+The default\r
+<i>logfile</i>\r
+is the standard output.\r
+<p><dt><br><a name="aclfile"><tt>aclfile</tt>&#160;&#160;<i>aclfile</i></a><dd>\r
+Unless this option is used, the proxy talks to anyone who can connect to it,\r
+and everyone who can has equal permissions on where they can go.\r
+An access file allows restrictions to be placed on these two policies,\r
+by distinguishing some\r
+<i><dfn>source</dfn></i>\r
+<small>IP</small>\r
+addresses and/or\r
+some\r
+<i><dfn>destination</dfn></i>\r
+addresses.\r
+(If a\r
+<a href="ijbman.html#forwardfile">forwarder or a gateway</a>\r
+is being used, its address is considered the destination address,\r
+not the ultimate\r
+<small>IP</small>\r
+address of the\r
+<small>URL</small>\r
+requested.)\r
+<p>\r
+<a name="permit">Each line of the access file begins with</a>\r
+either the word\r
+<big><kbd>permit</kbd></big>\r
+or\r
+<big><kbd>deny</kbd></big>\r
+followed by source and (optionally) destination addresses \r
+to be matched against those of the\r
+<small>HTTP</small>\r
+request.\r
+The last matching line specifies the result: if it was a\r
+<big><kbd>deny</kbd></big>\r
+line or if no line matched,\r
+the request will be refused.\r
+<p>\r
+<a name="various">A source or destination</a>\r
+can be specified as a single numeric\r
+<small>IP</small>\r
+address,\r
+or with a hostname, provided that the host's name\r
+can be resolved to a numeric address: this cannot be used to block all\r
+<big><kbd>.mil </kbd></big>\r
+domains for example,\r
+because there is no single address associated with that domain name.\r
+Either form may be followed by a slash and an integer\r
+<big><kbd>N</kbd></big>,\r
+specifying a subnet mask of\r
+<big><kbd>N</kbd></big>\r
+bits.\r
+For example,\r
+<big><kbd>permit 207.153.200.72/24</kbd></big>\r
+matches the entire Class-C subnet from\r
+207.153.200.0\r
+through 207.153.200.255.\r
+(A netmask of 255.255.255.0 corresponds to 24 bits of\r
+ones in the netmask, as with\r
+<big><kbd>*_MASKLEN=24</kbd></big>.)\r
+A value of 16 would be used for a Class-B subnet.\r
+A value of zero for\r
+<big><kbd>N</kbd></big>\r
+in the subnet mask length will cause any address to match;\r
+this can be used to express a default rule.\r
+For more information see the example file provided with the distribution.\r
+<p>\r
+<a name="false">If you like these access controls</a>\r
+you should probably have\r
+<a href="ijbfaq.html#firewall">firewall</a>;\r
+they are not intended to replace one.\r
+<p><dt><br><a name="trustfile"><tt>trustfile</tt>&#160;&#160;<i>trustfile</i></a><dd>\r
+This feature is experimental, has not been fully documented and is\r
+very subject to change.\r
+The goal is for parents to be able to choose a page or site whose\r
+links they regard suitable for their\r
+<a href="ijbfaq.html#children">young children</a>\r
+and for the proxy to allow access only to sites mentioned there.\r
+To do this the proxy examines the\r
+<a href="ijbman.html#o_r">referer</a>\r
+variable on each page request to check they resulted from\r
+a click on the ``trusted referer'' site: if so the referred site\r
+is added to a list of trusted sites, so that the child can\r
+then move around that site.\r
+There are several uncertainties in this scheme that experience may be\r
+able to iron out; check back in the months ahead.\r
+<p><dt><br><a name="trust_info_url"><tt>trust_info_url</tt>&#160;&#160;<i>trust_info_url</i></a><dd>\r
+When access is denied due to lack of a trusted referer, this\r
+<small>URL</small>\r
+is displayed with a message pointing the user to it for further information.\r
+<p><dt><br><a name="hide-console"><tt>hide-console</tt></a><dd>\r
+In the Windows version only, instructs the program\r
+to disconnect from and hide the command console after starting.\r
+<p><dt><i><a name="o_a">-a</a></i><dd>\r
+(Obsolete) Accept the server's\r
+<big><kbd>Set-cookie</kbd></big>\r
+headers, passing them through to the browser.\r
+<a name="obsolete">This option was removed in Version 1.2</a>\r
+and replaced by an improvement to the\r
+<a href="ijbman.html#o_c">-c</a>\r
+option.\r
+</dl>\r
+</p>\r
+\r
+<h3><a name="install" href="/cgi-bin/gp?pg=ijbman&pr=install"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Installation and Use\r
+</h3>\r
+<p>\r
+Browsers must be told where to find the\r
+<b><kbd>junkbuster</kbd></b>\r
+(e.g.\r
+<big><kbd>localhost</kbd></big>\r
+port 8000).\r
+To set the \r
+<small>HTTP</small>\r
+proxy in Netscape 3.0,\r
+go through:\r
+<b><font face="arial, helvetica">\r
+Options</font></b>;\r
+<b><font face="arial, helvetica">\r
+Network Preferences</font></b>;\r
+<b><font face="arial, helvetica">\r
+Proxies</font></b>;\r
+<b><font face="arial, helvetica">\r
+Manual Proxy Configuration</font></b>;\r
+<b><font face="arial, helvetica">\r
+View</font></b>.\r
+See the\r
+<a href="ijbfaq.html"><small>FAQ</small></a>\r
+for other browsers.\r
+The\r
+<a href="ijbfaq.html#security">Security Proxy</a>\r
+should also be set to the same values,\r
+otherwise\r
+<big><kbd>shttp:</kbd></big>\r
+<small>URL</small>s\r
+won't work.\r
+<p>\r
+<a name="limitations">Note the limitations</a>\r
+explained in the\r
+<a href="ijbfaq.html"><small>FAQ</small></a>.\r
+</p>\r
+\r
+<h3><a name="show" href="/cgi-bin/gp?pg=ijbman&pr=show"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Checking Options\r
+</h3>\r
+<p>\r
+To allow users to\r
+<a href="ijbfaq.html#show">check</a>\r
+that a\r
+<b><kbd>junkbuster</kbd></b>\r
+is running and how it is configured,\r
+it intercepts requests for any\r
+<small>URL</small>\r
+ending in\r
+<big><kbd>/show-proxy-args</kbd></big>\r
+and blocks it,\r
+returning instead returns information on its\r
+version number and\r
+current configuration\r
+including the contents of its blockfile.\r
+To get an explicit warning that no\r
+<b><kbd>junkbuster</kbd></b>\r
+intervened if the proxy was not configured,\r
+it's best to point it to a\r
+<small>URL</small>\r
+that does this, such as\r
+<a href="http://internet.junkbuster.com/cgi-bin/show-proxy-args">http://internet.junkbuster.com/cgi-bin/show-proxy-args</a>\r
+on Junkbusters's website.\r
+</p>\r
+\r
+<h3><a name="also" href="/cgi-bin/gp?pg=ijbman&pr=also"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+See Also\r
+</h3>\r
+<p>\r
+<a href="ijbfaq.html">http://www.junkbusters.com/ht/en/ijbfaq.html</a>\r
+<br>\r
+<a href="cookies.html">http://www.junkbusters.com/ht/en/cookies.html</a>\r
+<br>\r
+<a href="http://internet.junkbuster.com/cgi-bin/show-proxy-args">http://internet.junkbuster.com/cgi-bin/show-proxy-args</a>\r
+<br>\r
+<a name ="kristol" href="http://www.cis.ohio-state.edu/htbin/rfc/rfc2109.html">http://www.cis.ohio-state.edu/htbin/rfc/rfc2109.html</a>\r
+<br>\r
+<a name ="squid" href="http://squid.nlanr.net/Squid/">http://squid.nlanr.net/Squid/</a>\r
+<br>\r
+<a href="http://www-math.uni-paderborn.de/~axel/">http://www-math.uni-paderborn.de/~axel/</a>\r
+</p>\r
+\r
+<h3><a name="copyright" href="/cgi-bin/gp?pg=ijbman&pr=copyright"><img border=0 width=14 height=14 src="/images/fb.gif" alt="&lt;Feedback&gt"></a>&#160;\r
+Copyright and GPL\r
+</h3>\r
+<p>\r
+Written and copyright by the Anonymous Coders and Junkbusters Corporation\r
+and made available under the\r
+<a href="gpl.html">GNU General Public License (GPL).</a>\r
+This software comes with\r
+<a href="gpl.html#nowarr">NO WARRANTY.</a>\r
+Internet Junkbuster\r
+Proxy\r
+is a\r
+<a href="legal.html#marks">trademark</a>\r
+of Junkbusters Corporation.\r
+</p>\r
+<p align="center"><a href="#top_of_page"><img border=0 width=250 height=15 src="/images/top.gif" alt="--- Back to Top of Page ---"></a></p>\r
+<font face="arial, helvetica">\r
+<a rel="begin" href="index.html">Home</a> <font color="#ff0000">\r
+<b> &#183; </b></font>\r
+<a rel="next" href="cookies.html">Next</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="lopt.html">Site Map</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="legal.html">Legal</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkdata.html">Privacy</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="cookies.html">Cookies</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="ijb.html">Banner Ads</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="telemarketing.html">Telemarketing</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkmail.html">Mail</a>\r
+<font color="#ff0000">\r
+<b> &#183; </b></font><a href="junkemail.html">Spam</a>\r
+\r
+</font><form action="/cgi-bin/search" method="GET">\r
+<input type="text" name="q" size=60 maxlength=120 value="">\r
+<input type="submit" value="Search"></form>\r
+<small>\r
+<small>\r
+<p>\r
+<a href="legal.html#copy">Copyright</a> &#169; 1996-8 Junkbusters\r
+<a href="legal.html#marks">&#174;</a> Corporation.\r
+Copying and distribution permitted under\r
+the <a href="gpl.html"><small>GNU</small></a>\r
+General Public License.\r
+</small>\r
+<tt>\r
+1998/10/31\r
+http://www.junkbusters.com/ht/en/ijbman.html\r
+</tt>\r
+<address><kbd>webmaster&#64;junkbusters.com</kbd></address>\r
+</small>\r
+</body>\r
+</html>\r
diff --git a/encode.c b/encode.c
new file mode 100644 (file)
index 0000000..42d0744
--- /dev/null
+++ b/encode.c
@@ -0,0 +1,400 @@
+const char encode_rcs[] = "$Id: encode.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/encode.c,v $
+ *
+ * Purpose     :  Functions to encode and decode URLs, and also to
+ *                encode cookies and HTML text.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: encode.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+\r
+#include "encode.h"
+
+const char encode_h_rcs[] = ENCODE_H_VERSION;
+
+/* Maps special characters in a URL to their equivalent % codes. */
+static const char * const url_code_map[256] = {
+   NULL, "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09",
+   "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13",
+   "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D",
+   "%1E", "%1F", "+",   "%21", "%22", "%23", "%24", "%25", "%26", "%27",
+   "%28", "%29", NULL,  "%2B", "%2C", NULL,  NULL,  "%2F", NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  "%3A", "%3B",
+   "%3C", "%3D", "%3E", "%3F", NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  "%5B", "%5C", "%5D", "%5E", NULL,  "%60", NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81",
+   "%82", "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8A", "%8B",
+   "%8C", "%8D", "%8E", "%8F", "%90", "%91", "%92", "%93", "%94", "%95",
+   "%96", "%97", "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
+   "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", "%A8", "%A9",
+   "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", "%B0", "%B1", "%B2", "%B3",
+   "%B4", "%B5", "%B6", "%B7", "%B8", "%B9", "%BA", "%BB", "%BC", "%BD",
+   "%BE", "%BF", "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
+   "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", "%D0", "%D1",
+   "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", "%D8", "%D9", "%DA", "%DB",
+   "%DC", "%DD", "%DE", "%DF", "%E0", "%E1", "%E2", "%E3", "%E4", "%E5",
+   "%E6", "%E7", "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
+   "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", "%F8", "%F9",
+   "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
+};
+
+/* Maps special characters in HTML to their equivalent entites. */
+static const char * const html_code_map[256] = {
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL,"&quot;",NULL,NULL,NULL,"&amp;",NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   "&lt;",NULL,"&gt;",NULL,NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* Maps special characters in a cookie to their equivalent % codes. */
+static const char * const cookie_code_map[256] = {
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, "+",  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, "%2C",NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "%3B",
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+/*********************************************************************
+ *
+ * Function    :  html_encode
+ *
+ * Description :  Encodes a string so it's not interpreted as
+ *                containing HTML tags or entities.
+ *                Replaces <, >, &, and " with the appropriate HTML
+ *                entities.
+ *
+ * Parameters  :
+ *          1  :  s = String to encode.  Null-terminated.
+ *
+ * Returns     :  Encoded string, newly allocated on the heap. 
+ *                Caller is responsible for freeing it with free().
+ *
+ *********************************************************************/
+char * html_encode(const char *s)
+{
+   /* each input char can expand to at most 6 chars */
+   char * buf = (char *) malloc((strlen(s) * 6) + 1);
+
+   if (buf)
+   {
+      char c;
+      char * p = buf;
+      while ( (c = *s++) != '\0')
+      {
+         const char * replace_with = html_code_map[(unsigned char) c];
+         if(replace_with != NULL)
+         {
+            strcpy(p, replace_with);
+            p += strlen(replace_with);
+         }
+         else
+         {
+            *p++ = c;
+         }
+      }
+
+      *p = '\0';
+   }
+
+   return(buf);
+}
+
+/*********************************************************************
+ *
+ * Function    :  cookie_encode
+ *
+ * Description :  Encodes a string so it can be used in a cookie.
+ *                Replaces " ", ",", and ";" with the appropriate
+ *                codes.
+ *
+ * Parameters  :
+ *          1  :  s = String to encode.  Null-terminated.
+ *
+ * Returns     :  Encoded string, newly allocated on the heap. 
+ *                Caller is responsible for freeing it with free().
+ *
+ *********************************************************************/
+char * cookie_encode(const char *s)
+{
+   /* each input char can expand to at most 3 chars */
+   char * buf = (char *) malloc((strlen(s) * 3) + 1);
+
+   if (buf)
+   {
+      char c;
+      char * p = buf;
+      while ( (c = *s++) != '\0')
+      {
+         const char * replace_with = cookie_code_map[(unsigned char) c];
+         if (replace_with != NULL)
+         {
+            strcpy(p, replace_with);
+            p += strlen(replace_with);
+         }
+         else
+         {
+            *p++ = c;
+         }
+      }
+
+      *p = '\0';
+   }
+
+   return(buf);
+}
+
+/*********************************************************************
+ *
+ * Function    :  url_encode
+ *
+ * Description :  Encodes a string so it can be used in a URL
+ *                query string.  Replaces special characters with\r
+ *                the appropriate %xx codes.
+ *
+ * Parameters  :
+ *          1  :  s = String to encode.  Null-terminated.
+ *
+ * Returns     :  Encoded string, newly allocated on the heap. 
+ *                Caller is responsible for freeing it with free().
+ *
+ *********************************************************************/
+char * url_encode(const char *s)
+{\r
+   /* each input char can expand to at most 3 chars */\r
+   char * buf = (char *) malloc((strlen(s) * 3) + 1);
+\r
+   if (buf)
+   {\r
+      char c;
+      char * p = buf;
+      while( (c = *s++) != '\0')
+      {
+         const char * replace_with = url_code_map[(unsigned char) c];
+         if (replace_with != NULL)
+         {
+            strcpy(p, replace_with);
+            p += strlen(replace_with);
+         }
+         else
+         {
+            *p++ = c;
+         }
+      }
+
+      *p = '\0';
+\r
+   }
+\r
+   return(buf);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  xdtoi
+ *
+ * Description :  Converts a single hex digit to an integer.
+ *
+ * Parameters  :
+ *          1  :  d = in the range of ['0'..'9', 'A'..'F', 'a'..'f']
+ *
+ * Returns     :  The integer value, or -1 for non-hex characters.
+ *
+ *********************************************************************/
+static int xdtoi(char d)
+{
+   if ((d >= '0') && (d <= '9'))
+   {
+      return(d - '0');
+   }
+   else if ((d >= 'a') && (d <= 'f')) 
+   {
+      return(d - 'a' + 10);
+   }
+   else if ((d >= 'A') && (d <= 'F'))
+   {
+      return(d - 'A' + 10);
+   }
+   else
+   {
+      return(-1);
+   }
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  xtoi
+ *
+ * Description :  Hex string to integer conversion.
+ *
+ * Parameters  :
+ *          1  :  s = a 2 digit hex string (e.g. "1f").  Only the
+ *                    first two characters will be looked at.
+ *
+ * Returns     :  The integer value, or 0 for non-hex strings.
+ *
+ *********************************************************************/
+static int xtoi(const char *s)
+{
+   int d1, d2;
+
+   d1 = xdtoi(*s++);
+   if(d1 >= 0)
+   {
+      d2 = xdtoi(*s);
+      if(d2 >= 0)
+      {
+         return (d1 << 4) + d2;
+      }
+   }
+
+   return 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  url_decode
+ *
+ * Description :  Decodes a URL query string, replacing %xx codes
+ *                with their decoded form.
+ *
+ * Parameters  :
+ *          1  :  s = String to decode.  Null-terminated.
+ *
+ * Returns     :  Decoded string, newly allocated on the heap. 
+ *                Caller is responsible for freeing it with free().
+ *
+ *********************************************************************/
+char *url_decode(const char * s)
+{
+   char *buf = malloc(strlen(s) + 1);
+   char *q = buf;
+\r
+   if (buf)\r
+   {\r
+      while (*s)
+      {
+         switch (*s)
+         {
+            case '+':
+               s++;
+               *q++ = ' ';
+               break;
+
+            case '%':
+               if ((*q = xtoi(s + 1)))
+               {
+                  s += 3;
+                  q++;
+               }
+               else
+               {
+                  /* malformed, just use it */
+                  *q++ = *s++;
+               }
+               break;
+
+            default:
+               *q++ = *s++;
+               break;
+         }
+      }
+      *q = '\0';\r
+   }
+\r
+   return(buf);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/encode.h b/encode.h
new file mode 100644 (file)
index 0000000..ba0b6cf
--- /dev/null
+++ b/encode.h
@@ -0,0 +1,65 @@
+#ifndef _ENCODE_H
+#define _ENCODE_H
+#define ENCODE_H_VERSION "$Id: encode.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/encode.h,v $
+ *
+ * Purpose     :  Functions to encode and decode URLs, and also to
+ *                encode cookies and HTML text.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: encode.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char * html_encode(const char *s);
+extern char * cookie_encode(const char *s);
+extern char * url_encode(const char *s);
+extern char * url_decode(const char *str);
+
+/* Revision control strings from this header and associated .c file */
+extern const char encode_rcs[];
+extern const char encode_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _ENCODE_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/errlog.c b/errlog.c
new file mode 100644 (file)
index 0000000..54b2687
--- /dev/null
+++ b/errlog.c
@@ -0,0 +1,407 @@
+const char errlog_rcs[] = "$Id: errlog.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/errlog.c,v $
+ *
+ * Purpose     :  Log errors to a designated destination in an elegant,
+ *                printf-like fashion.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: errlog.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif /* ndef _WIN32 */
+
+#include <errno.h>
+/* #include <pthread.h> */
+
+#ifdef _WIN32
+#include <windows.h>
+#include "w32log.h"
+#endif /* def _WIN32 */
+
+#include "errlog.h"
+#include "project.h"
+
+const char errlog_h_rcs[] = ERRLOG_H_VERSION;
+
+/* LOG_LEVEL_ERROR and LOG_LEVEL_INFO cannot be turned off */
+#define LOG_LEVEL_MINIMUM  (LOG_LEVEL_ERROR | LOG_LEVEL_INFO)
+
+/* where to log (default: stderr) */
+static FILE *logfp = NULL;
+
+/* where to log (NULL == stderr) */
+static char * logfilename = NULL;
+
+/* logging detail level.  */
+static int debug = LOG_LEVEL_MINIMUM;  
+
+
+/*********************************************************************
+ *
+ * Function    :  init_errlog
+ *
+ * Description :  Initializes the logging module.  Must call before
+ *                calling log_error.
+ *
+ * Parameters  :
+ *          1  :  prog_name  = The program name.
+ *          2  :  logfname   = The logfile name, or NULL for stderr.
+ *          3  :  debuglevel = The debugging level.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
+{
+   FILE *fp;
+
+   /* FIXME RACE HAZARD: should start critical section error_log_use here */
+
+   /* set the logging detail level */
+   debug = debuglevel | LOG_LEVEL_MINIMUM;
+
+   if ((logfp != NULL) && (logfp != stderr))
+   {
+      fclose(logfp);
+   }
+   logfp = stderr;
+
+   /* set the designated log file */
+   if( logfname )
+   {
+      if( !(fp = fopen(logfname, "a")) )
+      {
+         log_error(LOG_LEVEL_ERROR, "init_errlog(): can't open logfile: %s", logfname);
+#if defined(_WIN32) && ! defined (_WIN_CONSOLE)
+            MessageBox(NULL, "init_errlog(): can't open logfile", "Internet JunkBuster Error", 
+               MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
+#endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
+         exit(1);
+      }
+
+      /* set logging to be completely unbuffered */
+      setbuf(fp, NULL);
+
+      logfp = fp;
+   }
+
+   log_error(LOG_LEVEL_INFO, "Internet JunkBuster version " VERSION);
+   if (prog_name != NULL)
+   {
+      log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
+   }
+
+   /* FIXME RACE HAZARD: should end critical section error_log_use here */
+
+} /* init_error_log */
+
+
+/*********************************************************************
+ *
+ * Function    :  log_error
+ *
+ * Description :  This is the error-reporting and logging function.
+ *
+ * Parameters  :
+ *          1  :  loglevel  = the type of message to be logged
+ *          2  :  fmt       = the main string we want logged, printf-like
+ *          3  :  ...       = arguments to be inserted in fmt (printf-like).
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void log_error(int loglevel, char *fmt, ...)
+{
+   va_list ap;
+   char outbuf[BUFSIZ];
+   char * src = fmt;
+   int outc = 0;
+   long this_thread = 1;  /* was: pthread_t this_thread;*/
+
+   /* verify if loglevel applies to current settings and bail out if negative */
+   if(!(loglevel & debug))
+   {
+      return;
+   }
+
+   /* FIXME get current thread id */
+   /* this_thread = (long)pthread_self(); */
+
+   switch (loglevel)
+   {
+      case LOG_LEVEL_ERROR:
+         outc = sprintf(outbuf, "IJB(%d) Error: ", this_thread);
+         break;
+      case LOG_LEVEL_GPC:
+         outc = sprintf(outbuf, "IJB(%d) Request: ", this_thread);
+         break;
+      case LOG_LEVEL_CONNECT:
+         outc = sprintf(outbuf, "IJB(%d) Connect: ", this_thread);
+         break;
+      case LOG_LEVEL_HEADER:
+         outc = sprintf(outbuf, "IJB(%d) Header: ", this_thread);
+         break;
+      case LOG_LEVEL_INFO:
+         outc = sprintf(outbuf, "IJB(%d) Info: ", this_thread);
+         break;
+      default:
+         outc = sprintf(outbuf, "IJB(%d) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
+         break;
+   }
+   
+   /* get ready to scan var. args. */
+   va_start( ap, fmt );
+
+   /* build formatted message from fmt and var-args */
+   while ((*src) && (outc < BUFSIZ-2))
+   {
+      char tempbuf[BUFSIZ];
+      char *sval;
+      int ival;
+      unsigned uval;
+      long lval;
+      unsigned long ulval;
+      int oldoutc;
+      char ch;
+      
+      ch = *src++;
+      if( ch != '%' )
+      {
+         outbuf[outc++] = ch;
+         continue;
+      }
+
+      ch = *src++;
+      switch (ch) {
+         case '%':
+            outbuf[outc++] = '%';
+            break;
+         case 'd':
+            ival = va_arg( ap, int );
+            oldoutc = outc;
+            outc += sprintf(tempbuf, "%d", ival);
+            if (outc < BUFSIZ-1) 
+            {
+               strcpy(outbuf + oldoutc, tempbuf);
+            }
+            else
+            {
+               outbuf[oldoutc] = '\0';
+            }
+            break;
+         case 'u':
+            uval = va_arg( ap, unsigned );
+            oldoutc = outc;
+            outc += sprintf(tempbuf, "%u", uval);
+            if (outc < BUFSIZ-1) 
+            {
+               strcpy(outbuf + oldoutc, tempbuf);
+            }
+            else
+            {
+               outbuf[oldoutc] = '\0';
+            }
+            break;
+         case 'l':
+            /* this is a modifier that must be followed by u or d */
+            ch = *src++;
+            if (ch == 'd')
+            {
+               lval = va_arg( ap, long );
+               oldoutc = outc;
+               outc += sprintf(tempbuf, "%ld", lval);
+            }
+            else if (ch == 'u')
+            {
+               ulval = va_arg( ap, unsigned long );
+               oldoutc = outc;
+               outc += sprintf(tempbuf, "%lu", ulval);
+            }
+            else
+            {
+               /* Error */
+               sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
+                               "Format = \"%s\"\n"
+                               "Exiting.", this_thread, fmt);
+               /* FIXME RACE HAZARD: should start critical section error_log_use here */
+               if( !logfp )
+               {
+                  logfp = stderr;
+               }
+               fputs(outbuf, logfp);
+               /* FIXME RACE HAZARD: should end critical section error_log_use here */
+#if defined(_WIN32) && ! defined (_WIN_CONSOLE)
+               MessageBox(NULL, outbuf, "Internet JunkBuster Error", 
+                  MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
+#endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
+               exit(1);
+               break;
+            }
+            if (outc < BUFSIZ-1) 
+            {
+               strcpy(outbuf + oldoutc, tempbuf);
+            }
+            else
+            {
+               outbuf[oldoutc] = '\0';
+            }
+            break;
+         case 'c':
+            /*
+             * Note that char paramaters are converted to int, so we need to
+             * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
+             */
+            outbuf[outc++] = (char) va_arg( ap, int );
+            break;
+         case 's':
+            sval = va_arg( ap, char * );
+            oldoutc = outc;
+            outc += strlen(sval);
+            if (outc < BUFSIZ-1) 
+            {
+               strcpy(outbuf + oldoutc, sval);
+            }
+            else
+            {
+               outbuf[oldoutc] = '\0';
+            }
+            break;
+         case 'E':
+            /* Non-standard: Print error code from errno */
+            ival = errno;
+#ifndef NOSTRERROR
+            sval = strerror(ival);
+#else /* def NOSTRERROR */
+            sval = NULL
+#endif /* def NOSTRERROR */
+            if (sval == NULL)
+            {
+               sprintf(tempbuf, "(errno = %d)", ival);
+               sval = tempbuf;
+            }
+            oldoutc = outc;
+            outc += strlen(sval);
+            if (outc < BUFSIZ-1) 
+            {
+               strcpy(outbuf + oldoutc, sval);
+            }
+            else
+            {
+               outbuf[oldoutc] = '\0';
+            }
+            break;
+         default:
+            sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
+                            "Format = \"%s\"\n"
+                            "Exiting.", this_thread, fmt);
+            /* FIXME RACE HAZARD: should start critical section error_log_use here */
+            if( !logfp )
+            {
+               logfp = stderr;
+            }
+            fputs(outbuf, logfp);
+            /* FIXME RACE HAZARD: should end critical section error_log_use here */
+#if defined(_WIN32) && ! defined (_WIN_CONSOLE)
+            MessageBox(NULL, outbuf, "Internet JunkBuster Error", 
+               MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
+#endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
+            exit(1);
+            break;
+
+      } /* switch( p ) */
+
+   } /* for( p ... ) */
+   
+   /* done with var. args */
+   va_end( ap );
+   
+   if (outc >= BUFSIZ-2)
+   {
+      /* insufficient room for newline and trailing null. */
+
+      static const char warning[] = "... [too long, truncated]\n";
+
+      if (outc < BUFSIZ)
+      {
+         /* Need to add terminating null in this case. */
+         outbuf[outc] = '\0';
+      }
+
+      /* Truncate output */
+      outbuf[BUFSIZ - sizeof(warning)] = '\0';
+
+      /* Append warning */
+      strcat(outbuf, warning);
+   }
+   else
+   {
+      /* Add terminating newline and null */
+      outbuf[outc++] = '\n';
+      outbuf[outc] = '\0';
+   }
+
+   /* FIXME RACE HAZARD: should start critical section error_log_use here */
+
+   /* deal with glibc stupidity - it won't let you initialize logfp */
+   if( !logfp )
+   {
+      logfp = stderr;
+   }
+
+   fputs(outbuf, logfp);
+
+   /* FIXME RACE HAZARD: should end critical section error_log_use here */
+
+#if defined(_WIN32) && !defined(_WIN_CONSOLE)
+   /* Write to display */
+   LogPutString(outbuf);
+   LogShowActivity();
+#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
+
diff --git a/errlog.h b/errlog.h
new file mode 100644 (file)
index 0000000..24ce285
--- /dev/null
+++ b/errlog.h
@@ -0,0 +1,80 @@
+#ifndef _ERRLOG_H
+#define _ERRLOG_H
+#define ERRLOG_H_VERSION "$Id: errlog.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/errlog.h,v $
+ *
+ * Purpose     :  Log errors to a designated destination in an elegant,
+ *                printf-like fashion.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: errlog.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Debug level for errors */
+
+#define LOG_LEVEL_GPC     0x0001
+#define LOG_LEVEL_CONNECT 0x0002
+#define LOG_LEVEL_IO      0x0004
+#define LOG_LEVEL_HEADER  0x0008
+#define LOG_LEVEL_LOG     0x0010
+#ifdef PCRS
+#define LOG_LEVEL_FRC     0x0020
+#define LOG_LEVEL_REF     0x0040
+#endif /* def PCRS */
+
+/* Following are always on: */
+#define LOG_LEVEL_ERROR   0x1000
+#define LOG_LEVEL_INFO    0x2000
+
+extern void init_error_log(const char *prog_name, const char *logfname, int debuglevel);
+extern void log_error(int loglevel, char *fmt, ...);
+
+/* Revision control strings from this header and associated .c file */
+extern const char errlog_rcs[];
+extern const char errlog_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _ERRLOG_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
+
diff --git a/filters.c b/filters.c
new file mode 100644 (file)
index 0000000..29cee47
--- /dev/null
+++ b/filters.c
@@ -0,0 +1,1529 @@
+const char filters_rcs[] = "$Id: filters.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/filters.c,v $
+ *
+ * Purpose     :  Declares functions to parse/crunch headers and pages.
+ *                Functions declared include:
+ *                   `acl_addr', `add_stats', `block_acl', `block_imageurl',
+ *                   `block_url', `cookie_url', `domaincmp', `dsplit',
+ *                   `filter_popups', `forward_url',
+ *                   `ij_untrusted_url', `intercept_url', `re_process_buffer',
+ *                   `show_proxy_args', and `trust_url'
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: filters.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#endif
+
+#include "project.h"
+#include "filters.h"
+#include "encode.h"
+#include "jcc.h"
+#include "showargs.h"
+#include "parsers.h"
+#include "ssplit.h"
+#include "gateway.h"
+#include "jbsockets.h"
+#include "errlog.h"
+#include "jbsockets.h"
+
+#ifdef _WIN32
+#include "win32.h"
+#endif
+
+const char filters_h_rcs[] = FILTERS_H_VERSION;
+
+/* Fix a problem with Solaris.  There should be no effect on other
+ * platforms.
+ * Solaris's isspace() is a macro which uses it's argument directly
+ * as an array index.  Therefore we need to make sure that high-bit
+ * characters generate +ve values, and ideally we also want to make
+ * the argument match the declared parameter type of "int".
+ */
+#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
+
+
+static const char CBLOCK[] = 
+#ifdef AMIGA 
+       "HTTP/1.0 403 Request for blocked URL\n" 
+#else /* ifndef AMIGA */
+       "HTTP/1.0 202 Request for blocked URL\n"
+#endif /* ndef AMIGA */
+       "Pragma: no-cache\n"
+       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
+       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
+       "Content-Type: text/html\n\n"
+       "<html>\n"
+       "<head>\n"
+       "<title>Internet Junkbuster: Request for blocked URL</title>\n"
+       "</head>\n"
+       WHITEBG
+       "<center><h1>"
+       BANNER
+       "</h1></center>\n"
+      "<p align=center>Your request for <b>%s%s</b><br>\n"
+      "was blocked because it matches the following pattern "
+      "in the blockfile: <b>%s</b>\n</p>"
+#ifdef FORCE_LOAD
+       "<p align=center><a href=\"http://" FORCE_PREFIX
+        "%s%s\">Go there anyway.</a></p>"
+#endif /* def FORCE_LOAD */
+      "</body>\n"
+      "</html>\n";
+
+#ifdef TRUST_FILES
+static const char CTRUST[] =
+#ifdef AMIGA 
+       "HTTP/1.0 403 Request for untrusted URL\n"
+#else /* ifndef AMIGA */
+       "HTTP/1.0 202 Request for untrusted URL\n"
+#endif /* ndef AMIGA */
+       "Pragma: no-cache\n"
+       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
+       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
+       "Content-Type: text/html\n\n"
+       "<html>\n"
+       "<head>\n"
+       "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
+       "</head>\n"
+       WHITEBG
+       "<center>"
+       "<a href=http://internet.junkbuster.com/ij-untrusted-url?%s+%s+%s>"
+       BANNER
+       "</a>"
+       "</center>"
+       "</body>\n"
+       "</html>\n";
+#endif /* def TRUST_FILES */
+
+
+#ifdef ACL_FILES
+/*********************************************************************
+ *
+ * Function    :  block_acl
+ *
+ * Description :  Block this request?
+ *                Decide yes or no based on ACL file.
+ *
+ * Parameters  :
+ *          1  :  src = Address the browser/user agent is requesting.
+ *          2  :  dst = The proxy or gateway address this is going to.
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     : 0 = FALSE (don't block) and 1 = TRUE (do block)
+ *
+ *********************************************************************/
+int block_acl(struct access_control_addr *src, struct access_control_addr *dst, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct access_control_list *a, *acl;
+   struct access_control_addr s[1], d[1];
+
+   /* if not using an access control list, then permit the connection */
+   if (((fl = csp->alist) == NULL) || ((acl = fl->f) == NULL))
+   {
+      return(0);
+   }
+
+   /* search the list */
+   for (a = acl->next ; a ; a = a->next)
+   {
+      *s = *src;
+      *d = *dst;
+
+      s->addr &= a->src->mask;
+      d->addr &= a->dst->mask;
+
+      if ((s->addr  == a->src->addr)
+      && (d->addr  == a->dst->addr)
+      && ((s->port == a->src->port)
+       || (s->port == 0)
+       || (a->src->port == 0))
+      && ((d->port == a->dst->port)
+       || (d->port == 0)
+       || (a->dst->port == 0)))
+      {
+         if (a->action == ACL_PERMIT)
+         {
+            return(0);
+         }
+         else
+         {
+            return(1);
+         }
+      }
+   }
+
+   return(1);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  acl_addr
+ *
+ * Description :  Called from `load_aclfile'.  FIXME: I can't say more.
+ *
+ * Parameters  :
+ *          1  :  aspec = (what?)
+ *          2  :  aca = (what?)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int acl_addr(char *aspec, struct access_control_addr *aca)
+{
+   int i, masklength, port;
+   char *p;
+
+   masklength = 32;
+   port       =  0;
+
+   if ((p = strchr(aspec, '/')))
+   {
+      *p++ = '\0';
+
+      if (ijb_isdigit(*p) == 0)
+      {
+         return(-1);
+      }
+      masklength = atoi(p);
+   }
+
+   if ((masklength < 0) || (masklength > 32))
+   {
+      return(-1);
+   }
+
+   if ((p = strchr(aspec, ':')))
+   {
+      *p++ = '\0';
+
+      if (ijb_isdigit(*p) == 0)
+      {
+         return(-1);
+      }
+      port = atoi(p);
+   }
+
+   aca->port = port;
+
+   aca->addr = ntohl(resolve_hostname_to_ip(aspec));
+
+   if (aca->addr == -1)
+   {
+      log_error(LOG_LEVEL_ERROR, "can't resolve address for %s", aspec);
+      return(-1);
+   }
+
+   /* build the netmask */
+   aca->mask = 0;
+   for (i=1; i <= masklength ; i++)
+   {
+      aca->mask |= (1 << (32 - i));
+   }
+
+   /* now mask off the host portion of the ip address
+    * (i.e. save on the network portion of the address).
+    */
+   aca->addr = aca->addr & aca->mask;
+
+   return(0);
+
+}
+#endif /* def ACL_FILES */
+
+
+/*********************************************************************
+ *
+ * Function    :  block_url
+ *
+ * Description :  Called from `chat'.  Check to see if we need to block this.
+ *
+ * Parameters  :
+ *          1  :  http = http_request request to "check" for blocked
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL => unblocked, else string to HTML block description.
+ *
+ *********************************************************************/
+char *block_url(struct http_request *http, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct block_spec *b;
+   struct url_spec url[1];
+   char *p;
+   int n;
+
+   if (((fl = csp->blist) == NULL) || ((b = fl->f) == NULL))
+   {
+      return(NULL);
+   }
+
+   *url = dsplit(http->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) return(NULL);
+
+   for (b = b->next; b ; b = b->next)
+   {
+      if ((b->url->port == 0) || (b->url->port == http->port))
+      {
+         if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
+         {
+            if ((b->url->path == NULL) ||
+#ifdef REGEX
+               (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
+#endif
+            )
+            {
+               freez(url->dbuf);
+               freez(url->dvec);
+
+               if (b->reject == 0) return(NULL);
+
+               n  = strlen(CBLOCK);
+               n += strlen(http->hostport);
+               n += strlen(http->path);
+               n += strlen(b->url->spec);
+#ifdef FORCE_LOAD
+               n += strlen(http->hostport);
+               n += strlen(http->path);
+#endif /* def FORCE_LOAD */
+
+               p = (char *)malloc(n);
+
+#ifdef FORCE_LOAD
+               sprintf(p, CBLOCK, http->hostport, http->path, b->url->spec, http->hostport, http->path);
+#else
+               sprintf(p, CBLOCK, http->hostport, http->path, b->url->spec);
+#endif /* def FORCE_LOAD */
+
+               return(p);
+            }
+         }
+      }
+   }
+   freez(url->dbuf);
+   freez(url->dvec);
+   return(NULL);
+
+}
+
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+/*********************************************************************
+ *
+ * Function    :  block_imageurl
+ *
+ * Description :  Given a URL which is blocked, decide whether to 
+ *                send the "blocked" image or HTML.
+ *
+ * Parameters  :
+ *          1  :  http = URL to check.
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  True (nonzero) if URL is in image list, false (0)
+ *                otherwise
+ *
+ *********************************************************************/
+int block_imageurl(struct http_request *http, struct client_state *csp)
+{
+#ifdef DETECT_MSIE_IMAGES
+   if ((csp->accept_types 
+       & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
+       == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE))
+   {
+      return 1;
+   }
+   else if ((csp->accept_types 
+       & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
+       == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_HTML))
+   {
+      return 0;
+   }
+#endif
+
+#if defined(USE_IMAGE_LIST)
+   return block_imageurl_using_imagelist(http, csp);
+#else
+   /* Don't know - assume HTML */
+   return 0;
+#endif
+}
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+
+#ifdef USE_IMAGE_LIST
+/*********************************************************************
+ *
+ * Function    :  block_imageurl
+ *
+ * Description :  Test if a URL is in the imagelist.
+ *
+ * Parameters  :
+ *          1  :  http = URL to check.
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  True (nonzero) if URL is in image list, false (0)
+ *                otherwise
+ *
+ *********************************************************************/
+int block_imageurl_using_imagelist(struct http_request *http, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct block_spec *b;
+   struct url_spec url[1];
+
+   if (((fl = csp->ilist) == NULL) || ((b  = fl->f) == NULL))
+   {
+      return(0);
+   }
+
+   *url = dsplit(http->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) return(0);
+
+   for (b = b->next; b ; b = b->next)
+   {
+
+      if ((b->url->port == 0) || (b->url->port == http->port))
+      {
+         /* port matches, check domain */
+         if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
+         {
+            /* domain matches, check path */
+            if ((b->url->path == NULL) ||
+#ifdef REGEX
+               (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
+#endif
+            )
+            {
+               /* Matches */
+               freez(url->dbuf);
+               freez(url->dvec);
+
+               if (b->reject == 0) return(0);
+
+               return(1);
+            }
+         }
+      }
+   }
+   freez(url->dbuf);
+   freez(url->dvec);
+   return(0);
+
+}
+#endif /* def USE_IMAGE_LIST */
+
+
+#ifdef PCRS
+/*********************************************************************
+ *
+ * Function    :  re_process_buffer
+ *
+ * Description :  Apply all jobs from the joblist (aka. Perl regexp's) to
+ *                the text buffer that's been accumulated in csp->iob->buf.
+ *                Then, write the modified buffer out to the client
+ *                (Maybe this should happen from jcc.c via flush_socket
+ *                for better readability).
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void re_process_buffer(struct client_state *csp)
+{
+   int hits=0;
+   int size = csp->iob->eod - csp->iob->cur;
+   char *old=csp->iob->cur, *new = NULL;
+   pcrs_job *job, *joblist;
+
+   struct file_list *fl;
+   struct re_filterfile_spec *b;
+
+   /* Sanity first ;-) */
+   if (size <= 0) return;
+
+   if ( ( NULL == (fl = csp->rlist) ) || ( NULL == (b = fl->f) ) )
+   {
+      log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
+      return;
+   }
+
+   joblist = b->joblist;
+
+
+   log_error(LOG_LEVEL_REF, "re_filtering %s%s (size %d) ...",
+              csp->http->hostport, csp->http->path, size);
+
+   /* Apply all jobs from the joblist */
+   for (job = joblist; NULL != job; job = job->next)
+   {
+      hits += pcrs_exec_substitution(job, old, size, &new, &size);
+      if (old != csp->iob->cur) free(old);
+      old=new;
+   }
+
+   log_error(LOG_LEVEL_REF, " produced %d hits (new size %d).", hits, size);
+
+   if (write_socket(csp->cfd, old, size) != size)
+   {
+      log_error(LOG_LEVEL_ERROR, "write to client failed.");
+   }
+
+   /* fwiw, reset the iob */
+   IOB_RESET(csp);
+   freez(new);
+   return;
+
+}
+#endif /* def PCRS */
+
+
+#ifdef TRUST_FILES
+/*********************************************************************
+ *
+ * Function    :  trust_url
+ *
+ * Description :  Should we "trust" this URL?  See "trustfile" line in config.
+ *
+ * Parameters  :
+ *          1  :  http = http_request request for requested URL
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL => trusted, else string to HTML "untrusted" description.
+ *
+ *********************************************************************/
+char *trust_url(struct http_request *http, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct block_spec *b;
+   struct url_spec url[1], **tl, *t;
+   char *p, *h;
+   char *hostport, *path, *refer;
+   struct http_request rhttp[1];
+   int n;
+
+   if (((fl = csp->tlist) == NULL) || ((b  = fl->f) == NULL))
+   {
+      return(NULL);
+   }
+
+   *url = dsplit(http->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) return(NULL);
+
+   memset(rhttp, '\0', sizeof(*rhttp));
+
+   for (b = b->next; b ; b = b->next)
+   {
+      if ((b->url->port == 0) || (b->url->port == http->port))
+      {
+         if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
+         {
+            if ((b->url->path == NULL) ||
+#ifdef REGEX
+               (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
+#endif
+            )
+            {
+               freez(url->dbuf);
+               freez(url->dvec);
+
+               if (b->reject == 0) return(NULL);
+
+               hostport = url_encode(http->hostport);
+               path     = url_encode(http->path);
+
+               if (csp->referrer)
+               {
+                  refer = url_encode(csp->referrer);
+               }
+               else
+               {
+                  refer = url_encode("undefined");
+               }
+
+               n  = strlen(CTRUST);
+               n += strlen(hostport);
+               n += strlen(path);
+               n += strlen(refer);
+
+               p = (char *)malloc(n);
+
+               sprintf(p, CTRUST, hostport, path, refer);
+
+               freez(hostport);
+               freez(path);
+               freez(refer);
+
+               return(p);
+            }
+         }
+      }
+   }
+
+   freez(url->dbuf);
+   freez(url->dvec);
+
+   if ((csp->referrer == NULL)|| (strlen(csp->referrer) <= 9))
+   {
+      /* no referrer was supplied */
+      goto trust_url_not_trusted;
+   }
+
+   /* forge a URL from the referrer so we can use
+    * convert_url() to parse it into its components.
+    */
+
+   p = NULL;
+   p = strsav(p, "GET ");
+   p = strsav(p, csp->referrer + 9);   /* skip over "Referer: " */
+   p = strsav(p, " HTTP/1.0");
+
+   parse_http_request(p, rhttp, csp);
+
+   if (rhttp->cmd == NULL)
+   {
+      freez(p);
+      goto trust_url_not_trusted;
+   }
+
+   freez(p);
+
+   *url = dsplit(rhttp->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) goto trust_url_not_trusted;
+
+   for (tl = trust_list; (t = *tl) ; tl++)
+   {
+      if ((t->port == 0) || (t->port == rhttp->port))
+      {
+         if ((t->domain[0] == '\0') || domaincmp(t, url) == 0)
+         {
+            if ((t->path == NULL) ||
+#ifdef REGEX
+               (regexec(t->preg, rhttp->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(t->path, rhttp->path, t->pathlen) == 0)
+#endif
+            )
+            {
+               /* if the URL's referrer is from a trusted referrer, then
+                * add the target spec to the trustfile as an unblocked
+                * domain and return NULL (which means it's OK).
+                */
+
+               FILE *fp;
+
+               freez(url->dbuf);
+               freez(url->dvec);
+
+               if ((fp = fopen(trustfile, "a")))
+               {
+                  h = NULL;
+
+                  h = strsav(h, "~");
+                  h = strsav(h, http->hostport);
+
+                  p = http->path;
+                  if ((*p++ == '/')
+                  && (*p++ == '~'))
+                  {
+                  /* since this path points into a user's home space
+                   * be sure to include this spec in the trustfile.
+                   */
+                     if ((p = strchr(p, '/')))
+                     {
+                        *p = '\0';
+                        h = strsav(h, http->path);
+                        h = strsav(h, "/");
+                     }
+                  }
+
+                  free_http_request(rhttp);
+
+                  fprintf(fp, "%s\n", h);
+                  freez(h);
+                  fclose(fp);
+               }
+               return(NULL);
+            }
+         }
+      }
+   }
+
+trust_url_not_trusted:
+   free_http_request(rhttp);
+
+   hostport = url_encode(http->hostport);
+   path     = url_encode(http->path);
+
+   if (csp->referrer)
+   {
+      refer = url_encode(csp->referrer);
+   }
+   else
+   {
+      refer = url_encode("undefined");
+   }
+
+   n  = strlen(CTRUST);
+   n += strlen(hostport);
+   n += strlen(path);
+   n += strlen(refer);
+
+   p = (char *)malloc(n);
+   sprintf(p, CTRUST, hostport, path, refer);
+
+   freez(hostport);
+   freez(path);
+   freez(refer);
+
+   return(p);
+
+}
+#endif /* def TRUST_FILES */
+
+
+/*********************************************************************
+ *
+ * Function    :  intercept_url
+ *
+ * Description :  checks the URL `basename' against a list of URLs to
+ *                snarf. If it matches, it calls the associated function
+ *                which returns an HTML page to send back to the client.
+ *                Right now, we snarf:
+ *                      "show-proxy-args", and
+ *                      "ij-untrusted-url" (optional w/TRUST_FILES)
+ *
+ * Parameters  :
+ *          1  :  http = http_request request, check `basename's of blocklist
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL for no recognized URLs, or an HTML description page.
+ *
+ *********************************************************************/
+char *intercept_url(struct http_request *http, struct client_state *csp)
+{
+   char *basename;
+   const struct interceptors *v;
+
+   basename = strrchr(http->path, '/');
+
+   if (basename == NULL) return(NULL);
+
+   basename ++; /* first char past the last slash */
+
+   if (*basename)
+   {
+      for (v = intercept_patterns; v->str; v++)
+      {
+         if (strncmp(basename, v->str, v->len) == 0)
+         {
+            return((v->interceptor)(http, csp));
+         }
+      }
+   }
+
+   return(NULL);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  cookie_url
+ *
+ * Description :  Accept this cookie, or no?  See "cookiefile" setting.
+ *
+ * Parameters  :
+ *          1  :  http = http_request request for blocked URLs
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL => accept, cookie_spec pointer to crunch.
+ *
+ *********************************************************************/
+struct cookie_spec *cookie_url(struct http_request *http, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct cookie_spec *b;
+   struct url_spec url[1];
+
+   if (((fl = csp->clist) == NULL) || ((b = fl->f) == NULL))
+   {
+      return(NULL);
+   }
+
+   *url = dsplit(http->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) return(NULL);
+
+   for (b = b->next; NULL != b; b = b->next)
+   {
+      if ((b->url->port == 0) || (b->url->port == http->port))
+      {
+         if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
+         {
+            if ((b->url->path == NULL) ||
+#ifdef REGEX
+               (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
+#endif
+            )
+            {
+               freez(url->dbuf);
+               freez(url->dvec);
+               return(b);
+            }
+         }
+      }
+   }
+
+   freez(url->dbuf);
+   freez(url->dvec);
+   return(NULL);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  forward_url
+ *
+ * Description :  Should we forward this to another proxy?
+ *
+ * Parameters  :
+ *          1  :  http = http_request request for current URL
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Return gw_default for no forward match,
+ *                else a gateway pointer to a specific forwarding proxy.
+ *
+ *********************************************************************/
+const struct gateway *forward_url(struct http_request *http, struct client_state *csp)
+{
+   struct file_list *fl;
+   struct forward_spec *b;
+   struct url_spec url[1];
+
+   if (((fl = csp->flist) == NULL) || ((b = fl->f) == NULL))
+   {
+      return(gw_default);
+   }
+
+   *url = dsplit(http->host);
+
+   /* if splitting the domain fails, punt */
+   if (url->dbuf == NULL) return(gw_default);
+
+   for (b = b->next; b ; b = b->next)
+   {
+      if ((b->url->port == 0) || (b->url->port == http->port))
+      {
+         if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
+         {
+            if ((b->url->path == NULL) ||
+#ifdef REGEX
+               (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
+#else
+               (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
+#endif
+            )
+            {
+               freez(url->dbuf);
+               freez(url->dvec);
+               return(b->gw);
+            }
+         }
+      }
+   }
+
+   freez(url->dbuf);
+   freez(url->dvec);
+   return(gw_default);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  dsplit
+ *
+ * Description :  Takes a domain and returns a pointer to a url_spec
+ *                structure populated with dbuf, dcnt and dvec.  The
+ *                other fields in the structure that is returned are zero.
+ *
+ * Parameters  :
+ *          1  :  domain = a URL address
+ *
+ * Returns     :  url_spec structure populated with dbuf, dcnt and dvec.
+ *
+ *********************************************************************/
+struct url_spec dsplit(char *domain)
+{
+   struct url_spec ret[1];
+   char *v[BUFSIZ];
+   int size;
+   char *p;
+
+   memset(ret, '\0', sizeof(*ret));
+
+   if ((p = strrchr(domain, '.')))
+   {
+      if (*(++p) == '\0')
+      {
+         ret->toplevel = 1;
+      }
+   }
+
+   ret->dbuf = strdup(domain);
+
+   /* map to lower case */
+   for (p = ret->dbuf; *p ; p++) *p = tolower(*p);
+
+   /* split the domain name into components */
+   ret->dcnt = ssplit(ret->dbuf, ".", v, SZ(v), 1, 1);
+
+   if (ret->dcnt <= 0)
+   {
+      memset(ret, '\0', sizeof(ret));
+      return(*ret);
+   }
+
+   /* save a copy of the pointers in dvec */
+   size = ret->dcnt * sizeof(*ret->dvec);
+
+   if ((ret->dvec = (char **)malloc(size)))
+   {
+      memcpy(ret->dvec, v, size);
+   }
+
+   return(*ret);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  domaincmp
+ *
+ * Description :  Compare domain names.
+ *                domaincmp("a.b.c" , "a.b.c")  => 0 (MATCH)
+ *                domaincmp("a*.b.c", "a.b.c")  => 0 (MATCH)
+ *                domaincmp("b.c"   , "a.b.c")  => 0 (MATCH)
+ *                domaincmp(""      , "a.b.c")  => 0 (MATCH)
+ *
+ * Parameters  :
+ *          1  :  pattern = a domain that may contain a '*' as a wildcard.
+ *          2  :  fqdn = domain name against which the patterns are compared.
+ *
+ * Returns     :  0 => domains are equivalent, else no match.
+ *
+ *********************************************************************/
+int domaincmp(struct url_spec *pattern, struct url_spec *fqdn)
+{
+   char **pv, **fv;  /* vectors  */
+   int    pn,   fn;  /* counters */
+   char  *p,   *f;   /* chars    */
+
+   pv = pattern->dvec;
+   pn = pattern->dcnt;
+
+   fv = fqdn->dvec;
+   fn = fqdn->dcnt;
+
+   while ((pn > 0) && (fn > 0))
+   {
+      p = pv[--pn];
+      f = fv[--fn];
+
+      while (*p && *f && (*p == tolower(*f)))
+      {
+         p++, f++;
+      }
+
+      if ((*p != tolower(*f)) && (*p != '*')) return(1);
+   }
+
+   if (pn > 0) return(1);
+
+   return(0);
+
+}
+
+
+/* intercept functions */
+
+/*********************************************************************
+ *
+ * Function    :  show_proxy_args
+ *
+ * Description :  This "crunch"es "http:/any.thing/show-proxy-args" and
+ *                returns a web page describing the current status of IJB.
+ *
+ * Parameters  :
+ *          1  :  http = ignored
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A string that contains the current status of IJB.
+ *
+ *********************************************************************/
+char *show_proxy_args(struct http_request *http, struct client_state *csp)
+{
+   char *s = NULL;
+
+#ifdef SPLIT_PROXY_ARGS
+   FILE * fp;
+   char buf[BUFSIZ];
+   char * p;
+   const char * filename = NULL;
+   const char * file_description = NULL;
+   char * query_string = strrchr(http->path, '?');
+   char which_file = '\0';
+
+
+   if (query_string != NULL)
+   {
+      /* first char past the last '?' (maybe '\0')*/
+      which_file = query_string[1];
+   }
+   switch (which_file)
+   {
+   case 'b':
+      if (csp->blist)
+      {
+         filename = csp->blist->filename;
+         file_description = "Block List";
+      }
+      break;
+   case 'c':
+      if (csp->clist)
+      {
+         filename = csp->clist->filename;
+         file_description = "Cookie List";
+      }
+      break;
+   case 'f':
+      if (csp->flist)
+      {
+         filename = csp->flist->filename;
+         file_description = "Forward List";
+      }
+      break;
+
+#ifdef ACL_FILES
+   case 'a':
+      if (csp->alist)
+      {
+         filename = csp->alist->filename;
+         file_description = "Access Control List";
+      }
+      break;
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+   case 'i':
+      if (csp->ilist)
+      {
+         filename = csp->ilist->filename;
+         file_description = "Image List";
+      }
+      break;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+   case 'p':
+      if (csp->plist)
+      {
+         filename = csp->plist->filename;
+         file_description = "Popup list";
+      }
+      break;
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+   case 'r':
+      if (csp->rlist)
+      {
+         filename = csp->rlist->filename;
+         file_description = "RE Filter List";
+      }
+      break;
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+   case 't':
+      if (csp->tlist)
+      {
+         filename = csp->tlist->filename;
+         file_description = "Trust List";
+      }
+      break;
+#endif /* def TRUST_FILES */
+   }
+
+   if (filename)
+   {
+      /* Display specified file */
+      /* FIXME: Add HTTP headers so this isn't cached */
+      s = strsav(s,
+         "HTTP/1.0 200 OK\n"
+         "Server: IJ/" VERSION "\n"
+         "Content-type: text/html\n"
+         "Pragma: no-cache\n"
+         "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
+         "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
+         "\n"
+
+         "<html>"
+         "<head>"
+         "<title>Internet Junkbuster Proxy Status - ");
+      s = strsav(s, file_description);
+      s = strsav(s, 
+         "</title>"
+         "</head>\n"
+         "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
+         "<center>\n"
+         "<h1>" BANNER "\n");
+      s = strsav(s, file_description);
+      s = strsav(s, 
+         "</h1></center>\n"
+         "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
+         "<h2>");
+      s = strsav(s, file_description);
+      s = strsav(s,
+         "</h2>\n"
+         "Contents of file &quot;<code>");
+      p = html_encode(filename);
+      s = strsav(s, p);
+      freez(p);
+      s = strsav(s,
+         "</code>&quot;:<br>\n"
+         "</p>\n"
+         "<pre>");
+      
+      if ((fp = fopen(filename, "r")) == NULL)
+      {
+         s = strsav(s, "</pre><h1>ERROR OPENING FILE!</h1><pre>");
+      }
+      else
+      {
+         while (fgets(buf, sizeof(buf), fp))
+         {
+            p = html_encode(buf);
+            if (p)
+            {
+               s = strsav(s, p);
+               freez(p);
+               s = strsav(s, "<br>");
+            }
+         }
+         fclose(fp);
+      }
+
+      s = strsav(s,
+         "</pre>\n"
+         "<br>\n"
+         "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
+         "<br>\n"
+         "<small><small><p>\n"
+         "Code and documentation of the " BANNER " Proxy"
+         "<sup><small>TM</small></sup>\n"
+         "<a href=\"http://www.junkbusters.com/ht/en/legal.html#copy\">\n" "Copyright</a>&#169; 1997 Junkbusters Corporation\n"
+         "<a href=\"http://www.junkbusters.com/ht/en/legal.html#marks\"><sup><small>TM</small></sup></a><br>\n"
+         "Copying and distribution permitted under the"
+         "<a href=\"http://www.gnu.org/copyleft/gpl.html\">\n"
+         "<small>GNU</small></a> "
+         "General Public License.\n"
+         "</small>"
+         "<address><kbd>webmaster@junkbusters.com</kbd></address>"
+         "</small>"
+         "</body></html>\n");
+      return(s);
+   }
+#endif /* def SPLIT_PROXY_ARGS */
+   
+   s = strsav(s, proxy_args->header);
+   s = strsav(s, proxy_args->invocation);
+#ifdef STATISTICS
+   s = add_stats(s);
+#endif /* def STATISTICS */
+   s = strsav(s, proxy_args->gateways);
+
+#ifdef SPLIT_PROXY_ARGS
+   s = strsav(s, 
+      "<h2>The following files are in use:</h2>\n"
+      "<p>(Click a filename to view it)</p>\n"
+      "<ul>\n");
+
+   if (csp->blist)
+   {
+      s = strsav(s, "<li>Block List: <a href=\"show-proxy-args?block\"><code>");
+      s = strsav(s, csp->blist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+
+   if (csp->clist)
+   {
+      s = strsav(s, "<li>Cookie List: <a href=\"show-proxy-args?cookie\"><code>");
+      s = strsav(s, csp->clist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+
+   if (csp->flist)
+   {
+      s = strsav(s, "<li>Forward List: <a href=\"show-proxy-args?forward\"><code>");
+      s = strsav(s, csp->flist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+
+#ifdef ACL_FILES
+   if (csp->alist)
+   {
+      s = strsav(s, "<li>Access Control List: <a href=\"show-proxy-args?acl\"><code>");
+      s = strsav(s, csp->alist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+   if (csp->ilist)
+   {
+      s = strsav(s, "<li>Image List: <a href=\"show-proxy-args?image\"><code>");
+      s = strsav(s, csp->ilist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+   if (csp->plist)
+   {
+      s = strsav(s, "<li>Popup List: <a href=\"show-proxy-args?popup\"><code>");
+      s = strsav(s, csp->plist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+   if (csp->rlist)
+   {
+      s = strsav(s, "<li>RE Filter List: <a href=\"show-proxy-args?re\"><code>");
+      s = strsav(s, csp->rlist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+   if (csp->tlist)
+   {
+      s = strsav(s, "<li>Trust List: <a href=\"show-proxy-args?trust\"><code>");
+      s = strsav(s, csp->tlist->filename);
+      s = strsav(s, "</code></a></li>\n");
+   }
+#endif /* def TRUST_FILES */
+
+   s = strsav(s, "</ul>");
+
+#else /* ifndef SPLIT_PROXY_ARGS */
+   if (csp->blist)
+   {
+      s = strsav(s, csp->blist->proxy_args);
+   }
+
+   if (csp->clist)
+   {
+      s = strsav(s, csp->clist->proxy_args);
+   }
+
+   if (csp->flist)
+   {
+      s = strsav(s, csp->flist->proxy_args);
+   }
+
+#ifdef ACL_FILES
+   if (csp->alist)
+   {
+      s = strsav(s, csp->alist->proxy_args);
+   }
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+   if (csp->ilist)
+   {
+      s = strsav(s, csp->ilist->proxy_args);
+   }
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+   if (csp->plist)
+   {
+      s = strsav(s, csp->plist->proxy_args);
+   }
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+   if (csp->rlist)
+   {
+      s = strsav(s, csp->rlist->proxy_args);
+   }
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+   if (csp->tlist)
+   {
+      s = strsav(s, csp->tlist->proxy_args);
+   }
+#endif /* def TRUST_FILES */
+
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   s = strsav(s, proxy_args->trailer);
+
+   return(s);
+
+}
+
+
+#ifdef TRUST_FILES
+/*********************************************************************
+ *
+ * Function    :  ij_untrusted_url
+ *
+ * Description :  This "crunch"es "http:/any.thing/ij-untrusted-url" and
+ *                returns a web page describing why it was untrusted.
+ *
+ * Parameters  :
+ *          1  :  http = http_request request for crunched URL
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A string that contains why this was untrusted.
+ *
+ *********************************************************************/
+char *ij_untrusted_url(struct http_request *http, struct client_state *csp)
+{
+   int n;
+   char *hostport, *path, *refer, *p, *v[9];
+   char buf[BUFSIZ];
+   struct url_spec **tl, *t;
+
+
+   static const char format[] =
+      "HTTP/1.0 200 OK\r\n"
+      "Pragma: no-cache\n"
+      "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
+      "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
+      "Content-Type: text/html\n\n"
+      "<html>\n"
+      "<head>\n"
+      "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
+      "</head>\n"
+      BODY
+      "<center><h1>"
+      BANNER
+      "</h1></center>"
+      "The " BANNER " Proxy "
+      "<A href=\"" HOME_PAGE_URL "\">"
+      "(" HOME_PAGE_URL ") </A>"
+      "intercepted the request for %s%s\n"
+      "because the URL is not trusted.\n"
+      "<br><br>\n";
+
+   if ((n = ssplit(http->path, "?+", v, SZ(v), 0, 0)) == 4)
+   {
+      hostport = url_decode(v[1]);
+      path     = url_decode(v[2]);
+      refer    = url_decode(v[3]);
+   }
+   else
+   {
+      hostport = strdup("undefined_host");
+      path     = strdup("/undefined_path");
+      refer    = strdup("undefined");
+   }
+
+   n  = sizeof(format);
+   n += strlen(hostport);
+   n += strlen(path    );
+
+   if ((p = (char *)malloc(n)))
+   {
+      sprintf(p, format, hostport, path);
+   }
+
+   strsav(p, "The referrer in this request was <strong>");
+   strsav(p, refer);
+   strsav(p, "</strong><br>\n");
+
+   freez(hostport);
+   freez(path    );
+   freez(refer   );
+
+   p = strsav(p, "<h3>The following referrers are trusted</h3>\n");
+
+   for (tl = trust_list; (t = *tl) ; tl++)
+   {
+      sprintf(buf, "%s<br>\n", t->spec);
+      p = strsav(p, buf);
+   }
+
+   if (trust_info->next)
+   {
+      struct list *l;
+
+      strcpy(buf,
+         "<p>"
+         "You can learn more about what this means "
+         "and what you may be able to do about it by "
+         "reading the following documents:<br>\n"
+         "<ol>\n"
+      );
+
+      p = strsav(p, buf);
+
+      for (l = trust_info->next; l ; l = l->next)
+      {
+         sprintf(buf,
+            "<li> <a href=%s>%s</a><br>\n",
+               l->str, l->str);
+         p = strsav(p, buf);
+      }
+
+      p = strsav(p, "</ol>\n");
+   }
+
+   p = strsav(p, "</body>\n" "</html>\n");
+
+   return(p);
+
+}
+#endif /* def TRUST_FILES */
+
+
+#ifdef STATISTICS
+/*********************************************************************
+ *
+ * Function    :  add_stats
+ *
+ * Description :  Statistics function of JB.  Called by `show_proxy_args'.
+ *
+ * Parameters  :
+ *          1  :  s = string that holds the proxy args description page
+ *
+ * Returns     :  A pointer to the descriptive status web page.
+ *
+ *********************************************************************/
+char *add_stats(char *s)
+{
+   /*
+    * Output details of the number of requests rejected and
+    * accepted. This is switchable in the junkbuster config.
+    * Does nothing if this option is not enabled.
+    */
+
+   float perc_rej;   /* Percentage of http requests rejected */
+   char out_str[81];
+   int local_urls_read     = urls_read;
+   int local_urls_rejected = urls_rejected;
+
+   /*
+    * Need to alter the stats not to include the fetch of this
+    * page.
+    *
+        * Can't do following thread safely! doh!
+        *
+    * urls_read--;
+    * urls_rejected--; * This will be incremented subsequently *
+        */
+
+   s = strsav(s,"<h2>Statistics for this " BANNER ":</h2>\n");
+
+   if (local_urls_read == 0)
+   {
+
+      s = strsav(s,"No activity so far!\n");
+
+   }
+   else
+   {
+
+      perc_rej = (float)local_urls_rejected * 100.0F /
+            (float)local_urls_read;
+
+      sprintf(out_str,
+         "%d requests received, %d filtered "
+         "(%6.2f %%).",
+         local_urls_read, 
+         local_urls_rejected, perc_rej);
+
+      s = strsav(s,out_str);
+   }
+
+   return(s);
+}
+#endif /* def STATISTICS */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/filters.h b/filters.h
new file mode 100644 (file)
index 0000000..68af519
--- /dev/null
+++ b/filters.h
@@ -0,0 +1,106 @@
+#ifndef _FILTERS_H
+#define _FILTERS_H
+#define FILTERS_H_VERSION "$Id: filters.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/filters.h,v $
+ *
+ * Purpose     :  Declares functions to parse/crunch headers and pages.
+ *                Functions declared include:
+ *                   `acl_addr', `add_stats', `block_acl', `block_imageurl',
+ *                   `block_url', `cookie_url', `domaincmp', `dsplit',
+ *                   `filter_popups', `forward_url'
+ *                   `ij_untrusted_url', `intercept_url', `re_process_buffer',
+ *                   `show_proxy_args', and `trust_url'
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: filters.h,v $
+ *
+ *********************************************************************/
+\f\r
+
+#include "project.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ACL_FILES
+extern int block_acl(struct access_control_addr *src, struct access_control_addr *dst, struct client_state *csp);
+extern int acl_addr(char *aspec, struct access_control_addr *aca);
+#endif /* def ACL_FILES */
+
+extern char *block_url(struct http_request *http, struct client_state *csp);
+#ifdef TRUST_FILES
+extern char *trust_url(struct http_request *http, struct client_state *csp);
+#endif /* def TRUST_FILES */
+extern char *intercept_url(struct http_request *http, struct client_state *csp);
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+extern int block_imageurl(struct http_request *http, struct client_state *csp);
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+#ifdef USE_IMAGE_LIST
+extern int block_imageurl_using_imagelist(struct http_request *http, struct client_state *csp);
+#endif /* def USE_IMAGE_LIST */
+
+extern struct cookie_spec *cookie_url(struct http_request *http, struct client_state *csp);
+extern const struct gateway *forward_url(struct http_request *http, struct client_state *csp);
+
+extern struct url_spec dsplit(char *domain);
+extern int domaincmp(struct url_spec *pattern, struct url_spec *fqdn);
+
+extern char *show_proxy_args(struct http_request *http, struct client_state *csp);
+
+#ifdef TRUST_FILES
+extern char *ij_untrusted_url(struct http_request *http, struct client_state *csp);
+#endif /* def TRUST_FILES */
+
+#ifdef STATISTICS
+extern char *add_stats(char *s);
+#endif /* def STATISTICS */
+
+#ifdef PCRS
+extern void re_process_buffer(struct client_state *csp);
+#endif /* def PCRS */
+
+/* Revision control strings from this header and associated .c file */
+extern const char filters_rcs[];
+extern const char filters_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _FILTERS_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/forward b/forward
new file mode 100644 (file)
index 0000000..be4c787
--- /dev/null
+++ b/forward
@@ -0,0 +1,97 @@
+#      Forwarding specification for Internet Junkbuster 2.0
+#
+# Copyright 1997-8 Junkbusters Corp.  For distribution, modification and use
+# under the GNU General Public License. These files come with NO WARRANTY.
+# See http://www.junkbusters.com/ht/en/gpl.html or README file for details.
+
+# For this file to have any effect, the line beginning "forwardfile" must
+# be commented in, with the name of this file following the word "forwardfile"
+
+#
+# This feature allows routing of HTTP requests via multiple proxies.
+# It can be used to better protect privacy and confidentiality when
+# accessing specific domains by routing requests to those domains
+# to a special purpose filtering proxy such as lpwa.com
+#
+# It can also be used in an environment with multiple networks to route
+# requests via multiple gateways allowing transparent access to multiple
+# networks without having to modify browser configurations.
+#
+# Also specified here are special gateway protocols such as SOCKS.
+
+# The syntax of each line is
+#
+# target_domain[:port][/path]  forwarding_domain[:port]        gateway_type    gateway_domain[:port]
+#
+
+# A '.' in the forwarding domain/port means that requests made to the
+# target domain are not forwarded but are made directly by the proxy
+# (though the proxy may still use a gateway to contact the server)
+#
+# Lines are checked in turn, and the last match wins.
+#
+# There is an implicit line equivalent to the following, which specifies that
+# anything not finding a match on the list is to go out without forwarding
+# or gateway protocol; like so:
+#
+# *    .       .       .       # implicit
+
+# In the following common configuration, everything goes to Lucent's LPWA,
+# except SSL on port 443 (which it doesn't handle)
+# *            lpwa.com:8000   .       .
+# :443         .               .       .
+
+# See the FAQ for instructions on how to automate the login procedure for LPWA.
+# Some users have reported difficulties related to LPWA's use of . as the
+# last element of the domain, and have said that this can be fixed with this:
+# lpwa.   lpwa.com:8000   .       .
+
+# In this fictitious example, everything goes via an ISP's caching proxy,
+# except requests to that ISP:
+#
+# *            caching.myisp.net:8000  .       .
+# myisp.net    .                       .       .
+
+# For the @home network, we're told the forwarding configuration is this:
+# *       proxy:8080      .       .
+# Also, we're told they insist on getting cookies and Javascript, so you need
+# to add home.com to the cookie file. We consider Javascript a security risk;
+# see our page on cookies. Java need not be enabled.
+
+# In this example direct connections are made to all "internal" domains,
+# but everything else goes through Lucent's LPWA by way of the company's
+# SOCKS gateway to the Internet.
+#
+# *                    lpwa.com:8000   socks   argyle.my_company.com:1080
+# my_company.com       .               .       .
+
+# This is how you could set up a site that always uses SOCKS but no forwarders
+#
+# *                    .               socks   knee.my_company.com:1080
+
+# An advanced example for network administrators.
+#
+# If you have links to multiple ISPs that provide various special
+#content to their subscribers, you can configure forwarding to pass
+# requests to the specific host that's connected to that ISP
+# so that everybody can see
+# all of the content on all of the ISPs.
+#
+# This is tricky, but here's a sample:
+# 
+# host-a has a PPP connection to isp-a.com
+# host-b has a PPP connection to isp-b.com
+
+# host-a can run an Internet Junkbuster proxy with forwarding like this:
+#
+# /            .               .       .
+# isp-b.com    host-b:8000     .       .
+#
+# host-b can run an Internet Junkbuster proxy with forwarding like this:
+# /            .               .       .
+# isp-a.com    host-a:8000     .       .
+#
+# Now, *anyone* on the Internet (including users on host-a and host-b)
+# can set their browser's proxy to *either* host-a or host-b and
+# be able to browse the content on isp-a or isp-b.
+
diff --git a/gateway.c b/gateway.c
new file mode 100644 (file)
index 0000000..2ccf167
--- /dev/null
+++ b/gateway.c
@@ -0,0 +1,287 @@
+const char gateway_rcs[] = "$Id: gateway.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/gateway.c,v $
+ *
+ * Purpose     :  Contains functions to connect to a server, possibly
+ *                using a "gateway" (i.e. HTTP proxy and/or SOCKS4
+ *                proxy).  Also contains the list of gateway types.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: gateway.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif /* def _WIN32 */
+
+#include "jcc.h"
+#include "errlog.h"
+#include "jbsockets.h"
+#include "gateway.h"
+
+const char gateway_h_rcs[] = GATEWAY_H_VERSION;
+
+#define SOCKS_4      40    /* original SOCKS 4 protocol */
+#define SOCKS_4A     41    /* as modified for hosts w/o external DNS */
+
+const struct gateway gateways[] = {
+   /* type        function          gw type/host/port, fw host/port */
+   { "direct",    direct_connect,   0,          NULL, 0,    NULL, 0 },
+   { ".",         direct_connect,   0,          NULL, 0,    NULL, 0 },
+   { "socks",     socks4_connect,   SOCKS_4,    NULL, 1080, NULL, 0 },
+   { "socks4",    socks4_connect,   SOCKS_4,    NULL, 1080, NULL, 0 },
+   { "socks4a",   socks4_connect,   SOCKS_4A,   NULL, 1080, NULL, 0 },
+   { NULL,        NULL,             0,          NULL, 0,    NULL, 0 }
+};
+
+const struct gateway *gw_default = gateways; /* direct */
+
+
+#define SOCKS_REQUEST_GRANTED          90
+#define SOCKS_REQUEST_REJECT           91
+#define SOCKS_REQUEST_IDENT_FAILED     92
+#define SOCKS_REQUEST_IDENT_CONFLICT   93
+
+/* structure of a socks client operation */
+struct socks_op {
+   unsigned char vn;          /* socks version number */
+   unsigned char cd;          /* command code */
+   unsigned char dstport[2];  /* destination port */
+   unsigned char dstip[4];    /* destination address */
+   unsigned char userid;      /* first byte of userid */
+   /* more bytes of the userid follow, terminated by a NULL */
+};
+
+/* structure of a socks server reply */
+struct socks_reply {
+   unsigned char vn;          /* socks version number */
+   unsigned char cd;          /* command code */
+   unsigned char dstport[2];  /* destination port */
+   unsigned char dstip[4];    /* destination address */
+};
+
+static const char socks_userid[] = "anonymous";
+
+
+/*********************************************************************
+ *
+ * Function    :  direct_connect
+ *
+ * Description :  Direct how we connect to the web.  This can be:
+ *                directly    : no forwarding, or
+ *                indirectly  : through another proxy such as squid.
+ *
+ * Parameters  :
+ *          1  :  gw = pointer to a gateway structure (such as gw_default)
+ *          2  :  http = the http request and apropos headers
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  -1 => failure, else it is the socket file descriptor.
+ *
+ *********************************************************************/
+int direct_connect(const struct gateway *gw, struct http_request *http, struct client_state *csp)
+{
+   if (gw->forward_host)
+   {
+      return(connect_to(gw->forward_host, gw->forward_port, csp));
+   }
+   else
+   {
+      return(connect_to(http->host, http->port, csp));
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  socks4_connect
+ *
+ * Description :  Connect to the SOCKS server, and connect through
+ *                it to the web server or web proxy.   This handles
+ *                all the SOCKS negotiation, and returns a file
+ *                descriptor for a socket which can be treated as a
+ *                normal (non-SOCKS) socket.
+ *
+ * Parameters  :
+ *          1  :  gw = pointer to a gateway structure (such as gw_default)
+ *          2  :  http = the http request and apropos headers
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  -1 => failure, else a socket file descriptor.
+ *
+ *********************************************************************/
+int socks4_connect(const struct gateway *gw, struct http_request *http, struct client_state *csp)
+{
+   int web_server_addr;
+   unsigned char cbuf[BUFSIZ];
+   unsigned char sbuf[BUFSIZ];
+   struct socks_op    *c = (struct socks_op    *)cbuf;
+   struct socks_reply *s = (struct socks_reply *)sbuf;
+   int n, csiz, sfd, target_port;
+   int err = 0;
+   char *errstr, *target_host;
+
+   if ((gw->gateway_host == NULL) || (*gw->gateway_host == '\0'))
+   {
+      log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
+      err = 1;
+   }
+
+   if (gw->gateway_port <= 0)
+   {
+      log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
+      err = 1;
+   }
+
+   if (err)
+   {
+      errno = EINVAL;
+      return(-1);
+   }
+
+   if (gw->forward_host)
+   {
+      target_host = gw->forward_host;
+      target_port = gw->forward_port;
+   }
+   else
+   {
+      target_host = http->host;
+      target_port = http->port;
+   }
+
+   /* build a socks request for connection to the web server */
+
+   strcpy((char *)&(c->userid), socks_userid);
+
+   csiz = sizeof(*c) + sizeof(socks_userid) - 1;
+
+   switch (gw->type)
+   {
+      case SOCKS_4:
+         web_server_addr = htonl(resolve_hostname_to_ip(target_host));
+         break;
+      case SOCKS_4A:
+         web_server_addr = 0x00000001;
+         n = csiz + strlen(target_host) + 1;
+         if (n > sizeof(cbuf))
+         {
+            errno = EINVAL;
+            return(-1);
+         }
+         strcpy(((char *)cbuf) + csiz, http->host);
+         csiz = n;
+         break;
+      default:
+         /* Should never get here */
+         log_error(LOG_LEVEL_ERROR, "SOCKS4 impossible internal error - bad SOCKS type.");
+         errno = EINVAL;
+         return(-1);
+   }
+
+   c->vn          = 4;
+   c->cd          = 1;
+   c->dstport[0]  = (target_port       >> 8  ) & 0xff;
+   c->dstport[1]  = (target_port             ) & 0xff;
+   c->dstip[0]    = (web_server_addr   >> 24 ) & 0xff;
+   c->dstip[1]    = (web_server_addr   >> 16 ) & 0xff;
+   c->dstip[2]    = (web_server_addr   >>  8 ) & 0xff;
+   c->dstip[3]    = (web_server_addr         ) & 0xff;
+
+   /* pass the request to the socks server */
+   sfd = connect_to(gw->gateway_host, gw->gateway_port, csp);
+
+   if (sfd < 0)
+   {
+      return(-1);
+   }
+
+   if ((n = write_socket(sfd, (char *)c, csiz)) != csiz)
+   {
+      log_error(LOG_LEVEL_CONNECT, "SOCKS4 negotiation write failed...");
+      close_socket(sfd);
+      return(-1);
+   }
+
+   if ((n = read_socket(sfd, sbuf, sizeof(sbuf))) != sizeof(*s))
+   {
+      log_error(LOG_LEVEL_CONNECT, "SOCKS4 negotiation read failed...");
+      close_socket(sfd);
+      return(-1);
+   }
+
+   switch (s->cd)
+   {
+      case SOCKS_REQUEST_GRANTED:
+         return(sfd);
+         break;
+      case SOCKS_REQUEST_REJECT:
+         errstr = "SOCKS request rejected or failed";
+         errno = EINVAL;
+         break;
+      case SOCKS_REQUEST_IDENT_FAILED:
+         errstr = "SOCKS request rejected because "
+            "SOCKS server cannot connect to identd on the client";
+         errno = EACCES;
+         break;
+      case SOCKS_REQUEST_IDENT_CONFLICT:
+         errstr = "SOCKS request rejected because "
+            "the client program and identd report "
+            "different user-ids";
+         errno = EACCES;
+         break;
+      default:
+         errstr = (char *) cbuf;
+         errno = ENOENT;
+         sprintf(errstr,
+                 "SOCKS request rejected for reason code %d\n", s->cd);
+   }
+
+   log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s ...", errstr);
+
+   close_socket(sfd);
+   return(-1);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/gateway.h b/gateway.h
new file mode 100644 (file)
index 0000000..6914555
--- /dev/null
+++ b/gateway.h
@@ -0,0 +1,69 @@
+#ifndef _GATEWAY_H
+#define _GATEWAY_H
+#define GATEWAY_H_VERSION "$Id: gateway.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/gateway.h,v $
+ *
+ * Purpose     :  Contains functions to connect to a server, possibly
+ *                using a "gateway" (i.e. HTTP proxy and/or SOCKS4
+ *                proxy).  Also contains the list of gateway types.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: gateway.h,v $
+ *
+ *********************************************************************/
+\f
+
+#include "project.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const struct gateway gateways[];
+extern const struct gateway *gw_default;
+
+extern int socks4_connect(const struct gateway *gw, struct http_request *http, struct client_state *csp);
+extern int direct_connect(const struct gateway *gw, struct http_request *http, struct client_state *csp);
+
+/* Revision control strings from this header and associated .c file */
+extern const char gateway_rcs[];
+extern const char gateway_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _GATEWAY_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/icons/denyrule.ico b/icons/denyrule.ico
new file mode 100644 (file)
index 0000000..e5aa250
Binary files /dev/null and b/icons/denyrule.ico differ
diff --git a/icons/ico00001.ico b/icons/ico00001.ico
new file mode 100644 (file)
index 0000000..a01ccfc
Binary files /dev/null and b/icons/ico00001.ico differ
diff --git a/icons/ico00002.ico b/icons/ico00002.ico
new file mode 100644 (file)
index 0000000..b7de068
Binary files /dev/null and b/icons/ico00002.ico differ
diff --git a/icons/ico00003.ico b/icons/ico00003.ico
new file mode 100644 (file)
index 0000000..99e0980
Binary files /dev/null and b/icons/ico00003.ico differ
diff --git a/icons/ico00004.ico b/icons/ico00004.ico
new file mode 100644 (file)
index 0000000..35b76d4
Binary files /dev/null and b/icons/ico00004.ico differ
diff --git a/icons/ico00005.ico b/icons/ico00005.ico
new file mode 100644 (file)
index 0000000..db9bddf
Binary files /dev/null and b/icons/ico00005.ico differ
diff --git a/icons/ico00006.ico b/icons/ico00006.ico
new file mode 100644 (file)
index 0000000..5e1f3fa
Binary files /dev/null and b/icons/ico00006.ico differ
diff --git a/icons/ico00007.ico b/icons/ico00007.ico
new file mode 100644 (file)
index 0000000..6ec504d
Binary files /dev/null and b/icons/ico00007.ico differ
diff --git a/icons/ico00008.ico b/icons/ico00008.ico
new file mode 100644 (file)
index 0000000..e6bc72f
Binary files /dev/null and b/icons/ico00008.ico differ
diff --git a/icons/icon1.ico b/icons/icon1.ico
new file mode 100644 (file)
index 0000000..b96fe7c
Binary files /dev/null and b/icons/icon1.ico differ
diff --git a/icons/idle.ico b/icons/idle.ico
new file mode 100644 (file)
index 0000000..99470b5
Binary files /dev/null and b/icons/idle.ico differ
diff --git a/icons/junkbust.ico b/icons/junkbust.ico
new file mode 100644 (file)
index 0000000..41aafd0
Binary files /dev/null and b/icons/junkbust.ico differ
diff --git a/imagelist b/imagelist
new file mode 100644 (file)
index 0000000..e83fed0
--- /dev/null
+++ b/imagelist
@@ -0,0 +1,34 @@
+#
+# This is /etc/junkbuster/imagelist which was put here by a junkbuster rpm
+#
+# Last modified on Fri Oct  1 22:42:21 1999 (CEST)
+#
+# --------------------------------------------------------------------------
+#
+# Newest version is always available from 
+#
+#          http://www.waldherr.org/imagelist
+#
+# Read http://www.waldherr.org/junkbuster/update.shtml on how to keep
+# this file up-to-date.
+#
+# Comments: Stefan Waldherr <stefan@waldherr.org>
+#
+# Note that the regexp is split into domain and path, hence the `/' as the 
+# beginning of a path.
+#
+
+# generic, most powerful regepxs, path contains `.gif', `.jpeg' or `.jpg'
+/.*\.gif
+/.*\.jpe?g
+
+adforce.imgis.com
+ad.preferences.com/image.*
+ads.web.aol.com
+focalink.com
+ad-adex3.flycast.com
+ad.doubleclick.net
+connect.247media.ads.link4ads.com
+ln.doubleclick.net
+mojofarm.mediaplex.com/ad/
+www.carbuyer.com/cgi-carbuyer/getimage.cgi
diff --git a/jbsockets.c b/jbsockets.c
new file mode 100644 (file)
index 0000000..c5f73c9
--- /dev/null
@@ -0,0 +1,476 @@
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/jbsockets.c,v $
+ *
+ * Purpose     :  Contains wrappers for system-specific sockets code,
+ *                so that the rest of JunkBuster can be more
+ *                OS-independent.  Contains #ifdefs to make this work
+ *                on many platforms.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jbsockets.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <sys/timeb.h>
+#include <io.h>
+
+#else
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+#ifndef __BEOS__
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#else
+#include <socket.h>
+#endif
+
+#endif
+
+#include "project.h"
+#include "jbsockets.h"
+#include "filters.h"
+
+const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
+
+
+/*********************************************************************
+ *
+ * Function    :  connect_to
+ *
+ * Description :  Open a socket and connect to it.  Will check
+ *                that this is allowed according to ACL.
+ *
+ * Parameters  :
+ *          1  :  host = hostname to connect to
+ *          2  :  portnum = port to connent on
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *                      Not modified, only used for source IP and ACL.
+ *
+ * Returns     :  -1 => failure, else it is the socket file descriptor.
+ *
+ *********************************************************************/
+int connect_to(char *host, int portnum, struct client_state *csp)
+{
+   struct sockaddr_in inaddr;
+   int   fd, addr;
+   fd_set wfds;
+   struct timeval tv[1];
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+   int   flags;
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+
+#ifdef ACL_FILES
+   struct access_control_addr src[1], dst[1];
+#endif /* def ACL_FILES */
+
+   memset((char *)&inaddr, 0, sizeof inaddr);
+
+   if ((addr = resolve_hostname_to_ip(host)) == -1)
+   {
+      return(-1);
+   }
+
+#ifdef ACL_FILES
+   src->addr = csp->ip_addr_long;
+   src->port = 0;
+
+   dst->addr = ntohl(addr);
+   dst->port = portnum;
+
+   if (block_acl(src, dst, csp))
+   {
+      errno = EPERM;
+      return(-1);
+   }
+#endif /* def ACL_FILES */
+
+   inaddr.sin_addr.s_addr = addr;
+   inaddr.sin_family      = AF_INET;
+
+   if (sizeof(inaddr.sin_port) == sizeof(short))
+   {
+      inaddr.sin_port = htons((short)portnum);
+   }
+   else
+   {
+      inaddr.sin_port = htonl(portnum);
+   }
+
+   if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
+   {
+      return(-1);
+   }
+
+#ifdef TCP_NODELAY
+   {  /* turn off TCP coalescence */
+      int mi = 1;
+      setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
+   }
+#endif /* def TCP_NODELAY */
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)\r
+   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
+   {
+      flags |= O_NDELAY;
+      fcntl(fd, F_SETFL, flags);
+   }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+
+   while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1)
+   {
+#ifdef _WIN32
+      if (errno == WSAEINPROGRESS)
+#else /* ifndef _WIN32 */
+      if (errno == EINPROGRESS)
+#endif /* ndef _WIN32 */
+      {
+         break;
+      }
+
+      if (errno != EINTR)
+      {
+         close_socket(fd);
+         return(-1);
+      }
+   }
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+   if (flags != -1)
+   {
+      flags &= ~O_NDELAY;
+      fcntl(fd, F_SETFL, flags);
+   }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+
+   /* wait for connection to complete */
+   FD_ZERO(&wfds);
+   FD_SET(fd, &wfds);
+
+   tv->tv_sec  = 30;
+   tv->tv_usec = 0;
+
+   if (select(fd + 1, NULL, &wfds, NULL, tv) <= 0)
+   {
+      close_socket(fd);
+      return(-1);
+   }
+   return(fd);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  write_socket
+ *
+ * Description :  Write the contents of buf (for n bytes) to socket fd.
+ *
+ * Parameters  :
+ *          1  :  fd = file descriptor (aka. handle) of socket to write to.
+ *          2  :  buf = pointer to data to be written.
+ *          3  :  len = length of data to be written to the socket "fd".
+ *
+ * Returns     :  Win32: If no error occurs, returns the total number of
+ *                bytes sent, which can be less than the number
+ *                indicated by len. Otherwise, returns (-1).
+ *                Unix: ??? (Please fill me in!)
+ *
+ *********************************************************************/
+int write_socket(int fd, const char *buf, int len)
+{
+   if (len <= 0) return(0);
+
+   /* if (DEBUG(LOG)) fwrite(buf, n, 1, logfp); */
+
+#if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA)
+   return( send(fd, buf, len, 0));
+#else
+   return( write(fd, buf, len));
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  read_socket
+ *
+ * Description :  Read from a TCP/IP socket in a platform independent way.
+ *
+ * Parameters  :
+ *          1  :  fd = file descriptor of the socket to read
+ *          2  :  buf = pointer to buffer where data will be written
+ *                Must be >= len bytes long.
+ *          3  :  len = maximum number of bytes to read
+ *
+ * Returns     :  On success, the number of bytes read is returned (zero
+ *                indicates end of file), and the file position is advanced
+ *                by this number.  It is not an error if this number is
+ *                smaller than the number of bytes requested; this may hap-
+ *                pen for example because fewer bytes are actually available
+ *                right now (maybe because we were close to end-of-file, or
+ *                because we are reading from a pipe, or from a terminal),
+ *                or because read() was interrupted by a signal.  On error,
+ *                -1 is returned, and errno is set appropriately.  In this
+ *                case it is left unspecified whether the file position (if
+ *                any) changes.
+ *
+ *********************************************************************/
+int read_socket(int fd, char *buf, int len)
+{
+   if (len <= 0)
+   {
+      return(0);
+   }
+
+#if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA)
+   return( recv(fd, buf, len, 0));
+#else
+   return( read(fd, buf, len));
+#endif
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  close_socket
+ *
+ * Description :  Closes a TCP/IP socket
+ *
+ * Parameters  :
+ *          1  :  fd = file descriptor of socket to be closed
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+void close_socket(int fd)
+{
+#if defined(_WIN32) || defined(__BEOS__)
+   closesocket(fd);
+#elif defined(AMIGA)\r
+   CloseSocket(fd); \r
+#else
+   close(fd);
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  bind_port
+ *
+ * Description :  Call socket, set socket options, and listen.
+ *                Called by listen_loop to "boot up" our proxy address.
+ *
+ * Parameters  :
+ *          1  :  hostnam = TCP/IP address to bind/listen to
+ *          2  :  portnum = port to listen on
+ *
+ * Returns     :  if success, return file descriptor
+ *                if failure, returns -2 if address is in use, otherwise -1
+ *
+ *********************************************************************/
+int bind_port(const char *hostnam, int portnum)
+{
+   struct sockaddr_in inaddr;
+   int fd;
+   int one = 1;
+
+   memset((char *)&inaddr, '\0', sizeof inaddr);
+
+   inaddr.sin_family      = AF_INET;
+   inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
+
+   if (sizeof(inaddr.sin_port) == sizeof(short))
+   {
+      inaddr.sin_port = htons((short)portnum);
+   }
+   else
+   {
+      inaddr.sin_port = htonl(portnum);
+   }
+
+   fd = socket(AF_INET, SOCK_STREAM, 0);
+
+   if (fd < 0)
+   {
+      return(-1);
+   }
+
+   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
+
+   if (bind (fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
+   {
+      close_socket (fd);
+#ifdef _WIN32
+      if (errno == WSAEADDRINUSE)
+#else
+      if (errno == EADDRINUSE)
+#endif
+      {
+         return(-2);
+      }
+      else
+      {
+         return(-1);
+      }
+   }
+
+   while (listen(fd, 5) == -1)
+   {
+      if (errno != EINTR)
+      {
+         return(-1);
+      }
+   }
+
+   return fd;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  accept_connection
+ *
+ * Description :  Accepts a connection on a socket.  Socket must have
+ *                been created using bind_port().
+ *
+ * Parameters  :
+ *          1  :  csp = Client state, cfd, ip_addr_str, and 
+ *                ip_addr_long will be set by this routine.
+ *          2  :  fd  = file descriptor returned from bind_port
+ *
+ * Returns     :  when a connection is accepted, it returns 1 (TRUE).
+ *                On an error it returns 0 (FALSE).
+ *
+ *********************************************************************/
+int accept_connection(struct client_state * csp, int fd)
+{
+   struct sockaddr raddr;
+   struct sockaddr_in *rap = (struct sockaddr_in *) &raddr;
+   int   afd, raddrlen;
+
+   raddrlen = sizeof raddr;
+   do
+   {
+      afd = accept (fd, &raddr, &raddrlen);
+   } while (afd < 1 && errno == EINTR);
+
+   if (afd < 0)
+   {
+      return 0;
+   }
+
+   csp->cfd    = afd;
+   csp->ip_addr_str  = strdup(inet_ntoa(rap->sin_addr));
+   csp->ip_addr_long = ntohl(rap->sin_addr.s_addr);
+
+   return 1;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  resolve_hostname_to_ip
+ *
+ * Description :  Resolve a hostname to an internet tcp/ip address.
+ *                NULL or an empty string resolve to INADDR_ANY.
+ *
+ * Parameters  :
+ *          1  :  host = hostname to resolve
+ *
+ * Returns     :  -1 => failure, INADDR_ANY or tcp/ip address if succesful.
+ *
+ *********************************************************************/
+int resolve_hostname_to_ip(const char *host)
+{
+   struct sockaddr_in inaddr;
+   struct hostent *hostp;
+
+   if ((host == NULL) || (*host == '\0'))
+   {
+      return(INADDR_ANY);
+   }
+
+   memset((char *) &inaddr, 0, sizeof inaddr);
+
+   if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
+   {
+      if ((hostp = gethostbyname(host)) == NULL)
+      {
+         errno = EINVAL;
+         return(-1);
+      }
+      if (hostp->h_addrtype != AF_INET)
+      {
+#ifdef _WIN32
+         errno = WSAEPROTOTYPE;
+#else
+         errno = EPROTOTYPE;
+#endif
+         return(-1);
+      }
+      memcpy(
+         (char *) &inaddr.sin_addr,
+         (char *) hostp->h_addr,
+         sizeof(inaddr.sin_addr)
+      );
+   }
+   return(inaddr.sin_addr.s_addr);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/jbsockets.h b/jbsockets.h
new file mode 100644 (file)
index 0000000..6d77c4c
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _JBSOCKETS_H
+#define _JBSOCKETS_H
+#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/jbsockets.h,v $
+ *
+ * Purpose     :  Contains wrappers for system-specific sockets code,
+ *                so that the rest of JunkBuster can be more
+ *                OS-independent.  Contains #ifdefs to make this work
+ *                on many platforms.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jbsockets.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int connect_to(char *host, int portnum, struct client_state *csp);
+extern int write_socket(int fd, const char *buf, int n);
+extern int read_socket(int fd, char *buf, int n);
+extern void close_socket(int fd);
+
+extern int bind_port(const char *hostnam, int portnum);
+extern int accept_connection(struct client_state * csp, int fd);
+
+extern int resolve_hostname_to_ip(const char *host);
+
+/* Revision control strings from this header and associated .c file */
+extern const char jbsockets_rcs[];
+extern const char jbsockets_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _JBSOCKETS_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/jcc.c b/jcc.c
new file mode 100644 (file)
index 0000000..e6d06bd
--- /dev/null
+++ b/jcc.c
@@ -0,0 +1,1224 @@
+const char jcc_rcs[] = "$Id: jcc.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/jcc.c,v $
+ *
+ * Purpose     :  Main file.  Contains main() method, main loop, and 
+ *                the main connection-handling function.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jcc.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef _WIN32
+
+# include <sys/timeb.h>
+# include <windows.h>
+# include <io.h>
+# include <process.h>
+# ifdef TOGGLE
+#  include <time.h>
+# endif /* def TOGGLE */
+
+# include "win32.h"
+# ifndef _WIN_CONSOLE
+#  include "w32log.h"
+# endif /* ndef _WIN_CONSOLE */
+
+#else /* ifndef _WIN32 */
+
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <signal.h>
+
+# ifdef __BEOS__
+#  include <socket.h>  /* BeOS has select() for sockets only. */
+#  include <OS.h>      /* declarations for threads and stuff. */
+# endif
+
+# ifndef FD_ZERO
+#  include <select.h>
+# endif
+
+#endif
+
+#include "project.h"
+#include "jcc.h"
+#include "filters.h"
+#include "loaders.h"
+#include "showargs.h"
+#include "parsers.h"
+#include "killpopup.h"
+#include "miscutil.h"
+#include "errlog.h"
+#include "jbsockets.h"
+#include "gateway.h"
+
+const char jcc_h_rcs[] = JCC_H_VERSION;
+const char project_h_rcs[] = PROJECT_H_VERSION;
+
+const char DEFAULT_USER_AGENT[] ="User-Agent: Mozilla (X11; I; Linux 2.0.32 i586)";
+
+struct client_state  clients[1];
+struct file_list     files[1];
+
+#ifdef STATISTICS
+int urls_read     = 0;     /* total nr of urls read inc rejected */
+int urls_rejected = 0;     /* total nr of urls rejected */
+#endif /* def STATISTICS */
+
+
+static void listen_loop(void);
+static void chat(struct client_state *csp);
+static void serve(struct client_state *csp);
+#ifdef __BEOS__
+static int32 server_thread(void *data);
+#endif /* def __BEOS__ */
+
+
+#define BODY   "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
+
+static const char CFAIL[] =
+   "HTTP/1.0 503 Connect failed\n"
+   "Content-Type: text/html\n\n"
+   "<html>\n"
+   "<head>\n"
+   "<title>Internet Junkbuster: Connect failed</title>\n"
+   "</head>\n"
+   BODY
+   "<h1><center>"
+   BANNER
+   "</center></h1>"
+   "TCP connection to '%s' failed: %s.\n<br>"
+   "</body>\n"
+   "</html>\n";
+
+static const char CNXDOM[] =
+   "HTTP/1.0 404 Non-existent domain\n"
+   "Content-Type: text/html\n\n"
+   "<html>\n"
+   "<head>\n"
+   "<title>Internet Junkbuster: Non-existent domain</title>\n"
+   "</head>\n"
+   BODY
+   "<h1><center>"
+   BANNER
+   "</center></h1>"
+   "No such domain: %s\n"
+   "</body>\n"
+   "</html>\n";
+
+static const char CSUCCEED[] =
+   "HTTP/1.0 200 Connection established\n"
+   "Proxy-Agent: IJ/" VERSION "\n\n";
+
+static const char CHEADER[] =
+   "HTTP/1.0 400 Invalid header received from browser\n\n";
+
+static const char SHEADER[] =
+   "HTTP/1.0 502 Invalid header received from server\n\n";
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+static const char BLANKGIF[] =
+   "HTTP/1.0 200 OK\r\n"
+   "Pragma: no-cache\r\n"
+   "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Content-type: image/gif\r\n\r\n"
+   "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000"
+   "\000!\371\004\001\000\000\000\000,\000\000\000\000\001"
+   "\000\001\000\000\002\002D\001\000;";
+
+static const char JBGIF[] =
+   "HTTP/1.0 200 OK\r\n"
+   "Pragma: no-cache\r\n"
+   "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Content-type: image/gif\r\n\r\n"
+   "GIF89aD\000\013\000\360\000\000\000\000\000\377\377\377!"
+   "\371\004\001\000\000\001\000,\000\000\000\000D\000\013\000"
+   "\000\002a\214\217\251\313\355\277\000\200G&K\025\316hC\037"
+   "\200\234\230Y\2309\235S\230\266\206\372J\253<\3131\253\271"
+   "\270\215\342\254\013\203\371\202\264\334P\207\332\020o\266"
+   "N\215I\332=\211\312\3513\266:\026AK)\364\370\365aobr\305"
+   "\372\003S\275\274k2\354\254z\347?\335\274x\306^9\374\276"
+   "\037Q\000\000;";
+\r
+static const char FWGIF[] =\r
+   "HTTP/1.0 302 Blocked Advert\r\n" \r
+   "Pragma: no-cache\r\n"\r
+   "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"\r
+   "Location: ";\r
+\r
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+#ifdef _WIN32
+#define sleep(N)  Sleep(((N) * 1000))
+#endif
+
+
+/*********************************************************************
+ *
+ * Function    :  chat
+ *
+ * Description :  Once a connection to the client has been accepted,
+ *                this function is called (via serve()) to handle the
+ *                main business of the communication.  When this 
+ *                function returns, the caller must close the client
+ *                socket handle.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  On success, the number of bytes written are returned (zero
+ *                indicates nothing was written).  On error, -1 is returned,
+ *                and errno is set appropriately.  If count is zero and the
+ *                file descriptor refers to a regular file, 0 will be
+ *                returned without causing any other effect.  For a special
+ *                file, the results are not portable.
+ *
+ *********************************************************************/
+static void chat(struct client_state *csp)
+{
+   char buf[BUFSIZ], *hdr, *p, *req;
+   char *err = NULL;
+   char *eno;
+   fd_set rfds;
+   int n, maxfd, server_body, ms_iis5_hack = 0;
+   struct cookie_spec *cs;
+   const struct gateway *gw;
+   struct http_request *http;
+#ifdef PCRS
+   int filtering = 0;
+#endif /* def PCRS */
+
+   http = csp->http;
+
+   /*
+    * Read the client's request.  Note that since we're not using select() we
+    * could get blocked here if a client connected, then didn't say anything!
+    */
+
+   while (FOREVER)
+   {
+      n = read_socket(csp->cfd, buf, sizeof(buf));
+
+      if (n <= 0) break;      /* error! */
+
+      add_to_iob(csp, buf, n);
+
+      req = get_header(csp);
+
+      if (req == NULL)\r
+      {\r
+         break;    /* no HTTP request! */\r
+      }
+
+      if (*req == '\0')\r
+      {\r
+         continue;   /* more to come! */\r
+      }
+#ifdef FORCE_LOAD
+      /* If this request contains the FORCE_PREFIX,
+                * better get rid of it now and set the force flag --oes
+       */
+
+               if(strstr(req, FORCE_PREFIX))
+      {
+                  strclean(req, FORCE_PREFIX);
+                  /* if DEBUG(FRC) fprintf(logfp, "%s: Enforcing request \"%s\".\n", prog, req); */
+                  csp->force = 1;
+               } 
+      else
+      {
+                  csp->force = 0;
+               }
+#endif /* def FORCE_LOAD */
+  
+      parse_http_request(req, http, csp);
+      freez(req);
+      break;
+   }
+
+   if (http->cmd == NULL)
+   {
+      strcpy(buf, CHEADER);
+      write_socket(csp->cfd, buf, strlen(buf));
+      return;
+   }
+
+   /* decide how to route the HTTP request */
+
+   if ((gw = forward_url(http, csp)) == NULL)
+   {
+      log_error(LOG_LEVEL_ERROR, "gateway spec is NULL!?!?  This can't happen!");
+      abort();
+   }
+
+   /* build the http request to send to the server
+    * we have to do one of the following:
+    *
+    * create = use the original HTTP request to create a new
+    *          HTTP request that has only the path component
+    *          without the http://domainspec
+    * pass   = pass the original HTTP request unchanged
+    *
+    * drop   = drop the HTTP request
+    *
+    * here's the matrix:
+    *                        SSL
+    *                    0        1
+    *                +--------+--------+
+    *                |        |        |
+    *             0  | create | drop   |
+    *                |        |        |
+    *  Forwarding    +--------+--------+
+    *                |        |        |
+    *             1  | pass   | pass   |
+    *                |        |        |
+    *                +--------+--------+
+    *
+    */
+
+   if (gw->forward_host)
+   {
+      /* if forwarding, just pass the request as is */
+      enlist(csp->headers, http->cmd);
+   }
+   else
+   {
+      if (http->ssl == 0)
+      {
+         /* otherwise elide the host information from the url */
+         p = NULL;
+         p = strsav(p, http->gpc);
+         p = strsav(p, " ");
+         p = strsav(p, http->path);
+         p = strsav(p, " ");
+         p = strsav(p, http->ver);
+         enlist(csp->headers, p);
+         freez(p);
+      }
+   }
+
+   /* decide what we're to do with cookies */
+
+#if defined(TOGGLE)
+   /*
+    * by haroon - most of credit to srt19170
+    * if toggled_on flag is false IJB is disabled, pass cookies thru
+    */
+   if (!csp->toggled_on)
+   {
+      csp->accept_server_cookie  = 1;
+      csp->send_user_cookie      = 1;
+   }
+   else
+#endif
+
+   if ((cs = cookie_url(http, csp)))
+   {
+      csp->accept_server_cookie  = cs->accept_server_cookie;
+      csp->send_user_cookie      = cs->send_user_cookie;
+   }
+   else
+   {
+      csp->accept_server_cookie  = 0;
+      csp->send_user_cookie      = 0;
+   }
+
+   /* grab the rest of the client's headers */
+
+   while (FOREVER)
+   {
+      if ( ( p = get_header(csp) ) && ( *p == '\0' ) )
+      {
+         n = read_socket(csp->cfd, buf, sizeof(buf));
+         if (n <= 0)
+         {
+            log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
+            return;
+         }
+         add_to_iob(csp, buf, n);
+         continue;
+      }
+
+      if (p == NULL) break;
+
+      enlist(csp->headers, p);
+      freez(p);
+   }
+
+   /* filter it as required */
+
+   hdr = sed(client_patterns, add_client_headers, csp);
+
+   destroy_list(csp->headers);
+
+#ifdef TOGGLE
+   /*
+    * by haroon - most of credit to srt19170
+    * if toggled_on flag is true then IJB is enabled, do the usual
+    * otherwise avoid crunching
+    */
+
+/* This next line is a little ugly, but it simplifies the if statement below. */
+/* Basically if TOGGLE, then we want the if to test "csp->toggled_on", else we don't */
+#define IS_TOGGLED_ON csp->toggled_on &&
+
+#else /* ifndef TOGGLE */
+
+/* We don't have TOGGLE, so we don't care about toggling. */
+#define IS_TOGGLED_ON
+
+#endif /* ndef TOGGLE */
+
+
+#ifdef TRUST_FILES
+/* This next line is a little ugly, but it simplifies the if statement below. */
+/* Basically if TRUST_FILES, then we want the if to call "trust_url", else we don't */
+#define IS_TRUSTED_URL (p = trust_url(http, csp)) ||
+
+#else /* ifndef TRUST_FILES */
+
+/* We don't have TRUST_FILES, so we don't care about trusted URL's. */
+#define IS_TRUSTED_URL
+
+#endif /* ndef TRUST_FILES */
+
+
+       /* Check the request against all rules, unless
+        * we're disabled or in force mode. 
+    */
+   if (IS_TOGGLED_ON
+#ifdef FORCE_LOAD
+       (!csp->force) && 
+#endif /* def FORCE_LOAD */
+       ( (p = intercept_url(http, csp)) ||
+         IS_TRUSTED_URL
+         (p = block_url(http, csp)) ))
+   {
+#ifdef STATISTICS
+      csp->rejected = 1;
+#endif /* def STATISTICS */
+
+      log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+      /* now use block_imageurl */
+      if ( (tinygif > 0) && block_imageurl(http, csp) )
+      {
+         /* Send "blocked" image */
+         log_error(LOG_LEVEL_GPC, "%s%s image crunch!",
+                   http->hostport, http->path);
+
+         if (tinygif == 1)
+         {
+            write_socket(csp->cfd, BLANKGIF, sizeof(BLANKGIF)-1);
+         }
+         else if ((tinygif == 3) && (tinygifurl))\r
+         {\r
+            write_socket(csp->cfd, FWGIF, sizeof(FWGIF)-1);\r
+            write_socket(csp->cfd, tinygifurl, strlen(tinygifurl));\r
+         }\r
+         else
+         {
+            write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
+         }
+      }
+      else
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+      {
+         /* Send HTML "blocked" message */
+         write_socket(csp->cfd, p, strlen(p));
+      }
+
+      log_error(LOG_LEVEL_LOG, "%s", p);
+
+      freez(p);
+      freez(hdr);
+      return;
+   }
+
+   log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path);
+
+   if (gw->forward_host)
+   {
+      log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
+               gw->forward_host, gw->forward_port, http->hostport);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
+   }
+
+   /* here we connect to the server, gateway, or the forwarder */
+
+   csp->sfd = (gw->conn)(gw, http, csp);
+
+   if (csp->sfd < 0)
+   {
+      log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
+                http->hostport);
+
+      if (errno == EINVAL)
+      {
+         err = zalloc(strlen(CNXDOM) + strlen(http->host));
+         sprintf(err, CNXDOM, http->host);
+      }
+      else
+      {
+         eno = safe_strerror(errno);
+         err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
+         sprintf(err, CFAIL, http->hostport, eno);
+      }
+
+      write_socket(csp->cfd, err, strlen(err));
+
+      log_error(LOG_LEVEL_LOG, err);
+
+      freez(err);
+      freez(hdr);
+      return;
+   }
+
+   log_error(LOG_LEVEL_CONNECT, "OK");
+
+   if (gw->forward_host || (http->ssl == 0))
+   {
+      /* write the client's (modified) header to the server
+       * (along with anything else that may be in the buffer)
+       */
+
+      n = strlen(hdr);
+
+      if ((write_socket(csp->sfd, hdr, n) != n)
+          || (flush_socket(csp->sfd, csp   ) <  0))
+      {
+         log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
+                    http->hostport);
+
+         eno = safe_strerror(errno);
+         err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
+         sprintf(err, CFAIL, http->hostport, eno);
+         write_socket(csp->cfd, err, strlen(err));
+
+         freez(err);
+         freez(hdr);
+         return;
+      }
+   }
+   else
+   {
+      /*
+       * We're running an SSL tunnel and we're not forwarding,
+       * so just send the "connect succeeded" message to the
+       * client, flush the rest, and get out of the way.
+       */
+      if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0)
+      {
+         freez(hdr);
+         return;
+      }
+      IOB_RESET(csp);
+   }
+
+   /* we're finished with the client's header */
+   freez(hdr);
+
+   maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
+
+   /* pass data between the client and server
+    * until one or the other shuts down the connection.
+    */
+
+   server_body = 0;
+
+   while (FOREVER)
+   {
+      FD_ZERO(&rfds);
+
+      FD_SET(csp->cfd, &rfds);
+      FD_SET(csp->sfd, &rfds);
+
+      n = select(maxfd+1, &rfds, NULL, NULL, NULL);
+
+      if (n < 0)
+      {
+         log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
+         return;
+      }
+
+      /* this is the body of the browser's request
+       * just read it and write it.
+       */
+
+      if (FD_ISSET(csp->cfd, &rfds))
+      {
+         n = read_socket(csp->cfd, buf, sizeof(buf));
+
+         if (n <= 0) break; /* "game over, man" */
+
+         if (write_socket(csp->sfd, buf, n) != n)
+         {
+            log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
+            return;
+         }
+         continue;
+      }
+
+      /*
+       * The server wants to talk.  It could be the header or the body.
+       * If `hdr' is null, then it's the header otherwise it's the body.
+       * FIXME: Does `hdr' really mean `host'?
+       */
+
+
+      if (FD_ISSET(csp->sfd, &rfds))
+      {
+         fflush( 0 );
+         n = read_socket(csp->sfd, buf, sizeof(buf) - 1);
+
+         if (n < 0)
+         {
+            log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
+
+            eno = safe_strerror(errno);
+            sprintf(buf, CFAIL, http->hostport, eno);
+            freez(eno);
+            write_socket(csp->cfd, buf, strlen(buf));
+            return;
+         }
+
+         /* Add a trailing zero.  This lets filter_popups
+          * use string operations.
+          */
+         buf[n] = '\0';
+
+#ifdef KILLPOPUPS
+         /* Filter the popups on this read. */
+         if ( IS_TOGGLED_ON
+              ( kill_all_popups ||
+              ( ( http->host != NULL ) && ( popupfile != NULL ) ) ) )
+         {
+            filter_popups(csp, http->host, buf, n);
+         }
+#endif /* def KILLPOPUPS */
+
+         /* Normally, this would indicate that we've read
+          * as much as the server has sent us and we can
+          * close the client connection.  However, Microsoft
+          * in its wisdom has released IIS/5 with a bug that
+          * prevents it from sending the trailing \r\n in
+          * a 302 redirect header (and possibly other headers).
+          * To work around this if we've haven't parsed
+          * a full header we'll append a trailing \r\n
+          * and see if this now generates a valid one.
+          *
+          * This hack shouldn't have any impacts.  If we've
+          * already transmitted the header or if this is a
+          * SSL connection, then we won't bother with this
+          * hack.  So we only work on partially received
+          * headers.  If we append a \r\n and this still
+          * doesn't generate a valid header, then we won't
+          * transmit anything to the client.
+          */
+         if (n == 0)
+         {
+            /* This hack must only be enforced for headers. */
+            if (server_body || http->ssl)
+            {
+#ifdef PCRS
+               if (filtering)
+               {
+                  re_process_buffer(csp);
+               }
+#endif /* def PCRS */
+               break; /* "game over, man" */
+            }
+
+            /* Let's pretend the server just sent us a blank line. */
+            n = sprintf(buf, "\r\n");
+
+            /*
+             * Now, let the normal header parsing algorithm below do its
+             * job.  If it fails, we'll exit instead of continuing.
+             */
+
+            ms_iis5_hack = 1;
+         }
+
+         /*
+          * If this is an SSL connection or we're in the body
+          * of the server document, just write it to the client.
+          */
+
+         if (server_body || http->ssl)
+         {
+#ifdef PCRS
+            if (filtering)
+            {
+               add_to_iob(csp, buf, n); /* Buffer the body for filtering */
+            }
+            else
+#endif /* def PCRS */
+            {
+               /* just write */
+               if (write_socket(csp->cfd, buf, n) != n)
+               {
+                  log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
+                  return;
+               }
+            }
+            continue;
+         }
+         else
+         {
+            /* we're still looking for the end of the
+             * server's header ... (does that make header
+             * parsing an "out of body experience" ?
+             */
+
+            /* buffer up the data we just read */
+            add_to_iob(csp, buf, n);
+
+            /* get header lines from the iob */
+
+            while ((p = get_header(csp)))
+            {
+               if (*p == '\0')
+               {
+                  /* see following note */
+                  break;
+               }
+               enlist(csp->headers, p);
+               freez(p);
+            }
+
+            /* NOTE: there are no "empty" headers so
+             * if the pointer `p' is not NULL we must
+             * assume that we reached the end of the
+             * buffer before we hit the end of the header.
+             */
+
+            if (p)
+            {
+               if (ms_iis5_hack)
+               {
+                  /* Well, we tried our MS IIS/5
+                   * hack and it didn't work.
+                   * The header is incomplete
+                   * and there isn't anything
+                   * we can do about it.
+                   */
+                  break;
+               }
+               else
+               {
+                  /* Since we have to wait for
+                   * more from the server before
+                   * we can parse the headers
+                   * we just continue here.
+                   */
+                  continue;
+               }
+            }
+
+            /* we have now received the entire header.
+             * filter it and send the result to the client
+             */
+
+            hdr = sed(server_patterns, add_server_headers, csp);
+            n   = strlen(hdr);
+
+            /* write the server's (modified) header to
+             * the client (along with anything else that
+             * may be in the buffer)
+             */
+
+#ifdef PCRS
+            /* Decide if we want to re_filter this. */
+
+            if (IS_TOGGLED_ON     /* Only filter if toggle is "on" */
+                csp->is_text  &&  /* It's a text / * MIME-Type */
+                re_filterfile &&  /* There are expressions to be used */
+                !http->ssl    &&  /* We talk plaintext */
+                (re_filter_all || !csp->send_user_cookie)) /* Policy allows */
+            {
+               filtering = 1;
+            }
+
+/* This next line is a little ugly, but it simplifies the if statement below. */
+/* Basically if using PCRS, we want the OR condition to require "!filtering"  */
+#define NOT_FILTERING_AND !filtering &&
+
+#else /* not def PCRS */
+
+#define NOT_FILTERING_AND
+
+#endif /* def PCRS */
+
+
+            if ((write_socket(csp->cfd, hdr, n) != n)
+                || (NOT_FILTERING_AND (flush_socket(csp->cfd, csp) < 0)))
+            {
+               log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
+
+               /* the write failed, so don't bother
+                * mentioning it to the client...
+                * it probably can't hear us anyway.
+                */
+               freez(hdr);
+               return;
+            }
+
+            /* we're finished with the server's header */
+
+            freez(hdr);
+            server_body = 1;
+
+            /* If this was a MS IIS/5 hack then it means
+             * the server has already closed the
+             * connection.  Nothing more to read.  Time
+             * to bail.
+             */
+            if (ms_iis5_hack)
+            {
+               break;
+            }
+         }
+         continue;
+      }
+
+      return; /* huh? we should never get here */
+   }
+
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  serve
+ *
+ * Description :  This is little more than chat.  We only "serve" to
+ *                to close any socket that chat may have opened.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void serve(struct client_state *csp)
+{
+   chat(csp);
+   close_socket(csp->cfd);
+
+   if (csp->sfd >= 0)
+   {
+      close_socket(csp->sfd);
+   }
+
+   csp->active = 0;
+
+}
+
+
+#ifdef __BEOS__
+
+/*********************************************************************
+ *
+ * Function    :  server_thread
+ *
+ * Description :  We only exist to call `serve' in a threaded environment.
+ *
+ * Parameters  :
+ *          1  :  data = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Always 0.
+ *
+ *********************************************************************/
+static int32 server_thread(void *data)
+{
+   serve((struct client_state *) data);
+   return 0;
+
+}
+
+#endif
+
+
+/*********************************************************************
+ *
+ * Function    :  main
+ *
+ * Description :  Load the config file and start the listen loop.
+ *                This function is a lot more *sane* with the `load_config'
+ *                and `listen_loop' functions; although it stills does
+ *                a *little* too much for my taste.
+ *
+ * Parameters  :
+ *          1  :  argc = Number of parameters (including $0).
+ *          2  :  argv = Array of (char *)'s to the parameters.
+ *
+ * Returns     :  1 if : can't open config file, unrecognized directive,
+ *                stats requested in multi-thread mode, can't open the
+ *                log file, can't open the jar file, listen port is invalid,
+ *                any load fails, and can't bind port.
+ *
+ *                Else main never returns, the process must be signaled
+ *                to terminate execution.  Or, on Windows, use the 
+ *                "File", "Exit" menu option.
+ *
+ *********************************************************************/
+#ifdef __MINGW32__
+int _main(int argc, const char *argv[])
+#else
+int main(int argc, const char *argv[])
+#endif
+{
+   configfile =
+#ifndef _WIN32
+   "config"
+#else
+   "junkbstr.txt"
+#endif
+      ;
+
+#if !defined(_WIN32) || defined(_WIN_CONSOLE)
+   if ((argc >= 2) && (strcmp(argv[1], "--help")==0))
+   {
+      printf("JunkBuster proxy version " VERSION ".\n\n"
+         "Usage: %s [configfile]\n\n"
+         "See " HOME_PAGE_URL " for details.\n"
+         "This program is distributed under the GNU GPL, version 2 or later.\n",
+         argv[0]);
+      exit(2);
+   }
+   if ((argc >= 2) && (strcmp(argv[1], "--version")==0))
+   {
+      printf(VERSION "\n");
+      exit(2);
+   }
+#endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */
+
+   Argc = argc;
+   Argv = argv;
+
+   if (argc > 1)
+   {
+      configfile = argv[1];
+   }
+
+   remove_all_loaders();
+   memset( proxy_args, 0, sizeof( proxy_args ) );
+   files->next = NULL;
+
+   load_config( 0 );
+
+   /*
+    * Since load_config acts as a signal handler too, it returns
+    * its status in configret.  Check it for an error in loading.
+    */
+   if ( 0 != configret )
+   {
+      /* load config failed!  Exit with error. */
+      return( 1 );
+   }
+
+#ifdef _WIN32
+   InitWin32();
+#endif
+
+
+#ifndef _WIN32
+   signal(SIGPIPE, SIG_IGN);
+   signal(SIGCHLD, SIG_IGN);
+   signal(SIGHUP, load_config);
+
+#else /* ifdef _WIN32 */
+# ifdef _WIN_CONSOLE
+   /*
+    * We *are* in a windows console app.
+    * Print a verbose messages about FAQ's and such
+    */
+   printf(win32_blurb);
+# endif /* def _WIN_CONSOLE */
+#endif /* def _WIN32 */
+
+
+   listen_loop();
+
+   /* NOTREACHED */
+   return(-1);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  listen_loop
+ *
+ * Description :  bind the listen port and enter a "FOREVER" listening loop.
+ *
+ * Parameters  :  N/A
+ *
+ * Returns     :  Never.
+ *
+ *********************************************************************/
+static void listen_loop(void)
+{
+   struct client_state *csp = NULL;
+   int bfd;
+
+   log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
+             haddr ? haddr : "INADDR_ANY", hport);
+
+   bfd = bind_port(haddr, hport);
+   config_changed = 0;
+
+   if (bfd < 0)
+   {
+      log_error(LOG_LEVEL_ERROR, "can't bind %s:%d: %E "
+         "- There may be another junkbuster or some other "
+         "proxy running on port %d", 
+         (NULL != haddr) ? haddr : "INADDR_ANY", hport, hport
+      );
+      return;
+   }
+
+
+   while (FOREVER)
+   {
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+      while (waitpid(-1, NULL, WNOHANG) > 0)
+      {
+         /* zombie children */
+      }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+      sweep();
+
+      if ( NULL == (csp = (struct client_state *) malloc(sizeof(*csp))) )
+      {
+         log_error(LOG_LEVEL_ERROR, "malloc(%d) for csp failed: %E", sizeof(*csp));
+         continue;
+      }
+
+      memset(csp, '\0', sizeof(*csp));
+
+      csp->active = 1;
+      csp->sfd    = -1;
+
+      if ( config_changed )
+      {
+         /*
+          * Since we were listening to the "old port", we will not see
+          * a "listen" param change until the next IJB request.  So, at
+          * least 1 more request must be made for us to find the new
+          * setting.  I am simply closing the old socket and binding the
+          * new one.
+          *
+          * Which-ever is correct, we will serve 1 more page via the
+          * old settings.  This should probably be a "show-proxy-args"
+          * request.  This should not be a so common of an operation
+          * that this will hurt people's feelings.
+          */
+         close_socket(bfd);
+
+         log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
+                   haddr ? haddr : "INADDR_ANY", hport);
+         bfd = bind_port(haddr, hport);
+
+         config_changed = 0;
+      }
+
+      log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
+
+      if (!accept_connection(csp, bfd))
+      {
+         log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
+\r
+#ifdef AMIGA\r
+         if(!childs)\r
+         {\r
+            exit(1); \r
+         }\r
+#endif\r
+         continue;
+      }
+      else
+      {
+         log_error(LOG_LEVEL_CONNECT, "OK");
+      }
+
+#if defined(TOGGLE)
+      /* by haroon - most of credit to srt19170 */
+      csp->toggled_on = g_bToggleIJB;
+#endif
+
+      /* add it to the list of clients */
+      csp->next = clients->next;
+      clients->next = csp;
+
+      if (run_loader(csp))
+      {
+         log_error(LOG_LEVEL_ERROR, "a loader failed - must exit");
+         return;
+      }
+
+      if (multi_threaded)
+      {
+         int child_id;
+
+/* this is a switch () statment in the C preprocessor - ugh */
+#undef SELECTED_ONE_OPTION
+
+#if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
+#define SELECTED_ONE_OPTION
+         child_id = _beginthread(
+            (void*)serve,
+            64 * 1024,
+            csp);
+#endif
+
+#if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
+#define SELECTED_ONE_OPTION
+         {
+            thread_id tid = spawn_thread
+               (server_thread, "server", B_NORMAL_PRIORITY, csp);
+
+            if ((tid >= 0) && (resume_thread(tid) == B_OK))
+            {
+               child_id = (int) tid;
+            }
+            else
+            {
+               child_id = -1;
+            }
+         }
+#endif
+
+#if defined(AMIGA) && !defined(SELECTED_ONE_OPTION)\r
+#define SELECTED_ONE_OPTION\r
+         csp->cfd = ReleaseSocket(csp->cfd, -1);\r
+         if((child_id = (int)CreateNewProcTags(\r
+            NP_Entry, (ULONG)server_thread,\r
+            NP_Output, Output(),\r
+            NP_CloseOutput, FALSE,\r
+            NP_Name, (ULONG)"junkbuster child",\r
+            NP_StackSize, 20*1024,\r
+            TAG_DONE)))\r
+         {\r
+            childs++;\r
+            ((struct Task *)child_id)->tc_UserData = csp;\r
+            Signal((struct Task *)child_id, SIGF_SINGLE);\r
+            Wait(SIGF_SINGLE);\r
+         }\r
+#endif\r
+\r
+#if !defined(SELECTED_ONE_OPTION)
+         child_id = fork();
+#endif
+
+#undef SELECTED_ONE_OPTION
+/* end of cpp switch () */
+
+         if (child_id < 0) /* failed */
+         {
+            char buf[BUFSIZ];
+
+            log_error(LOG_LEVEL_ERROR, "can't fork: %E");
+
+            sprintf(buf , "JunkBuster: can't fork: errno = %d", errno);
+
+            write_socket(csp->cfd, buf, strlen(buf));
+            close_socket(csp->cfd);
+            csp->active = 0;
+            sleep(5);
+            continue;
+         }
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+         /* This block is only needed when using fork().
+          * When using threads, the server thread was
+          * created and run by the call to _beginthread().
+          */
+         if (child_id == 0)   /* child */
+         {
+            serve(csp);
+            _exit(0);
+
+         }
+         else  /* parent */
+         {
+            /* in a fork()'d environment, the parent's
+             * copy of the client socket and the CSP
+             * are not used.
+             */
+
+#if !defined(_WIN32) && defined(__CYGWIN__)
+            wait( NULL );
+#endif /* !defined(_WIN32) && defined(__CYGWIN__) */
+            close_socket(csp->cfd);
+            csp->active = 0;
+         }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+      }
+      else
+      {
+         serve(csp);
+      }
+   }
+   /* NOTREACHED */
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/jcc.h b/jcc.h
new file mode 100644 (file)
index 0000000..fcafbb7
--- /dev/null
+++ b/jcc.h
@@ -0,0 +1,96 @@
+#ifndef _JCC_H
+#define _JCC_H
+#define JCC_H_VERSION "$Id: jcc.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/jcc.h,v $
+ *
+ * Purpose     :  Main file.  Contains main() method, main loop, and 
+ *                the main connection-handling function.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: jcc.h,v $
+ *
+ *********************************************************************/
+\f
+
+/* Declare struct FILE for vars and funcs. */
+#include <stdio.h>
+
+/* All of our project's data types. */
+#include "project.h"
+
+#include "loadcfg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define freez(X)  if(X) free(X); X = NULL
+
+
+/* Global variables */
+
+
+#ifdef STATISTICS
+extern int urls_read;
+extern int urls_rejected;
+#endif /*def STATISTICS*/
+
+extern struct client_state clients[];
+
+extern struct file_list    files[];
+
+/* Global constants */
+
+extern const char DEFAULT_USER_AGENT[];
+
+
+/* Functions */
+
+#ifdef __MINGW32__
+int _main(int argc, const char *argv[]);
+#else
+int main(int argc, const char *argv[]);
+#endif
+
+/* Revision control strings from this header and associated .c file */
+extern const char jcc_rcs[];
+extern const char jcc_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _JCC_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/junkbstr.txt b/junkbstr.txt
new file mode 100644 (file)
index 0000000..cbe2104
--- /dev/null
@@ -0,0 +1,206 @@
+#  Sample Configuration file for the Internet Junkbuster 2.0
+
+#
+# $Id: config,v 1.2 2001/04/30 03:05:11 rodney Exp $
+#
+
+#
+#
+# Copyright 1997-8 Junkbusters Corp.  For distribution, modification and use
+# under the GNU General Public License. These files come with NO WARRANTY.
+# See http://www.junkbusters.com/ht/en/gpl.html or README file for details.
+#
+# When starting the proxy, give the name of this file as an argument.
+# Any changes made to this file are *not* automatically loaded; you have 
+# to stop and restart the proxy.
+
+# For information see http://www.junkbusters.com/ht/en/ijbman.html
+# or the documentation that came with the release
+
+# Lines beginning with a # character are comments; they are ignored.
+# Many example lines are provided here commented out
+
+# the blockfile contains patterns to be blocked by the proxy
+blockfile      ./blocklist # comments are OK here, too
+
+# the imagefile contains patterns to detect blocked images
+imagefile      ./imagelist
+
+# the popfile contains patterns of servers where javascript popups are disabled
+#
+# if the next line is not commented out, all javascript popups from the sites 
+# that match the patterns in popup will be blocked
+# popupfile     ./popup
+
+# File containing content modification rules
+#re_filterfile   ./re_filterfile
+
+# Uncomment to filter *all* traffic. Default is to
+# filter only if we wouldn't send a cookie either.
+#
+#re_filter_all
+
+
+# the cookiefile contains patterns to specify the cookie management policy
+#
+cookiefile     ./cookiefile
+
+# the logfile is where all logging and error messages are written
+#
+logfile        ./junkbuster.log
+
+# the jarfile is where cookies can be stored
+#
+#jarfile    ./jarfile
+
+# the forwardfile defines domain-specific routing
+#
+forwardfile    ./forward
+
+# file which lists and into which trusted domains are written
+#
+#trustfile     ./trust
+# files specify locations of "for information about trusted referers, see.."
+# multiple trust_info_url lines are OK
+#
+# trust_info_url     http://internet.junkbuster.com/
+# trust_info_url     http://www.yoursite.com/our_trust_policy.html
+#
+
+# The access control list file can be used to restrict IP addresses
+# that are permitted to use the proxy (see warnings in the FAQ).
+#
+#aclfile ./aclfile
+
+# add an "X-Forwarded-For:" specification to each request header
+#
+#add-forwarded-header
+
+# if logging cookies into a jarfile, and no other wafers were
+# explicity set, then by default a vanilla wafer is sent with
+# each request.
+#
+# setting 'suppress-vanilla-wafer' stops this vanilla wafer from
+# being sent.
+#
+suppress-vanilla-wafer
+
+# add these wafers to each request header
+# multiple wafer lines are OK
+#
+#wafer    NOTE=Like most people, I want my browsing to be anonymous.
+#wafer    WARNING=Please do not attempt to track me.
+
+# Anything can be added to the request headers. Please don't litter.
+# multiple add-header lines are OK
+#
+#add-header     Forwarded: by http://stay-out-of-my-backyard.net
+#add-header    Forwarded: by http://pro-privacy-isp.net
+#add-header    Proxy-Connection: Keep-Alive
+
+# listen-address specifies where the Junkbuster will listen for connections
+# Specifying a port is optional; if unspecified the defaults is 8000.
+# Before Version 2.0.2 the default was to bind to all IP addresses (INADDR_ANY)
+# This has been restricted to localhost to avoid unintended security breaches.
+# To open the proxy to all, uncomment the following line:
+#listen-address      :8000
+# other example usage:
+#listen-address      124.207.250.245:8080
+# to explicitly state what is now the default:
+#listen-address      localhost
+# or equivalently:
+listen-address    127.0.0.1:8000
+
+# user-agent specifies treatment of the "User-Agent:" (and "UA-*:") header(s)
+# default: Forge the "User-Agent:" 
+# 'text' : Always send <text> as the "User-Agent:"
+# .      : Pass the "User-Agent:" unchanged
+# @      : Pass the "User-Agent:" if the server is in the cookie file,
+#          forge the "User-Agent:" otherwise
+#user-agent     @
+
+# note: Russian browsers may be confused if user agent misidentifies
+# the operating system (Mac vs Windows); see FAQ
+user-agent    .
+
+# referer specifies treatment of the "Referer:" header
+# New option by "Andreas S. Oesterhelt" <oes@paradis.rhein.de>
+#
+# default: Kill the referrer-header from the client
+# 'text' : Always send <text> as the referrer
+# .      : Pass the referrer unchanged
+# @      : Pass the referrer if the server is in the cookie file,
+#          kill the referrer otherwise
+# Â§      : Pass the referrer if the server is in the cookie file,
+#       send a forged referrer that points to the root-diretory URL
+#       of the current request otherwise
+referer     Â§
+
+# from specifies value to be subsituted if browser provides a "From:" header
+#
+#from        spam-me-senseless@sittingduck.net
+
+# tinygif allows you to change the appearance of blocked images
+#
+# tinygif  0  # Show a "broken icon"
+# tinygif  1  # Show a GIF of one transparent pixel
+tinygif  2  # Show a GIF with the word "JUNKBUSTER"
+# tinygif  3 http://localhost/1x1.gif   # Temporary redirect to this URL
+
+# Andrew <anw@tirana.freewire.co.uk> added
+# The following can be used to suppress display of the block lists when the
+# page http://x.x/show-proxy-args is displayed. With a long block list this
+# accelerates loading of the configuration page and also hides the contents of
+# the block lists (for whatever reason). Maintainers of junkbuster proxies for 
+# multiple use can specify a message for any use who wants to know what is in
+# these files.
+#
+#suppress-blocklists Contact sysadmin@example.com for details.
+# suppress-blocklists
+
+# debug sets the level of debugging information to log in the logfile
+#
+# debug         1 # GPC  = show each GET/POST/CONNECT request
+# debug         2 # CONN = show each connection status
+# debug         4 # IO   = show I/O status
+# debug         8 # HDR  = show header parsing
+# debug        16 # LOG  = log all data into the logfile
+# debug        32 # FRC  = debug force feature
+# debug        64 # REF  = debug regular expression filter 
+#
+# multiple "debug" directives, are OK - they're logical-OR'd together
+#
+#debug         15 # same as setting the first 4 listed above
+debug 1
+# debug 255        # Log *everything*
+
+# single-threaded operation (i.e. disallows multiple threads or processes)
+# This is most often used for debugging because it keeps the
+# debugging output "in order" for easy reading.
+#
+#single-threaded
+
+# Toggle flag.  0 => disabled, anything else (ie. 1) => enabled
+toggle 1
+
+
+# Win32 GUI specific options.  Moved here from ijbw32.ini
+# in hopes of keep all of our config settings together.
+
+activity-animation      1
+log-messages            1
+log-highlight-messages  1
+log-buffer-size         1
+log-max-lines           200
+log-font-name           Comic Sans MS
+log-font-size           8
+show-on-task-bar        0
+close-button-minimizes  1
+
+# hide-console is used only on Win32 console mode. It instructs
+# the Internet Junkbuster to disconnect from and hide the
+# command console.
+#
+#hide-console
+
+
diff --git a/junkbuster.1 b/junkbuster.1
new file mode 100644 (file)
index 0000000..d88294d
--- /dev/null
@@ -0,0 +1,871 @@
+.TH JUNKBUSTER 1 "http://www.junkbusters.com/ht/en/ijb2.0man.html"\r
+.SH NAME\r
+\fBjunkbuster\fP\r
+- The\r
+Internet Junkbuster\r
+Proxy\r
+\s-2(TM)\s+2\r
+.SH SYNOPSIS\r
+\fBjunkbuster\fP\r
+\fI\&configfile\fP\r
+(Version 2.0 onwards)\r
+.br\r
+\fBjunkbstr.exe\fP\r
+\fI\&configfile\fP\r
+(Windows)\r
+.br\r
+\fBjunkbuster\fP\r
+[-a]\r
+[-y]\r
+[-s]\r
+[-c]\r
+[-v]\r
+.br\r
+[-u user_agent]\r
+[-r referer]\r
+[-t from]\r
+.br\r
+[-b blockfile]\r
+[-j jarfile]\r
+[-l logfile]\r
+.br\r
+[-w NAME=VALUE]\r
+[-x Header_text]\r
+.br\r
+[-h [bind_host_address][:bind_port]]\r
+.br\r
+[-f forward_host[:port]]\r
+[-d N]\r
+.br\r
+[-g gw_protocol[:[gw_host][:gw_port]]]\r
+.br\r
+(Version 1.4 and earlier)\r
+.SH DESCRIPTION\r
+\fBjunkbuster\fP\r
+is an instrumentable proxy that filters the \r
+\s-2HTTP\s0\r
+stream between\r
+web servers and browsers.\r
+Its main purpose is to enhance privacy.\r
+.P\r
+Versions before 2.0 used command-line options;\r
+Versions from 2.0 onward use a configuration file.\r
+The following descriptions of the options first give the older\r
+command-line usage, then the new configfile line.\r
+.P\r
+In Versions 2.0.1 upwards on Windows,\r
+a start-up message is printed and the configuration is read from the file\r
+\fC\&junkbstr.ini\fP\r
+if it exists and no argument was given.\r
+.P\r
+All files except the configfile\r
+are checked for changes before each page is fetched,\r
+so they may edited without restarting the proxy.\r
+.SS OPTIONS\r
+.TP\r
+.\" anchor: o_b blockfile\r
+\fI-b blockfile\fP (Old) blockfile \fIblockfile\fP (New)\r
+Block\" ijbfaq.html#blocking\r
+requests to\r
+\s-2URL\s0s\r
+matching any pattern given in the lines of the\r
+\fI\&blockfile\fP.\r
+The\r
+\fBjunkbuster\fP\r
+instead returns status 202, indicating that the request has been accepted\r
+(though not completed),\r
+and a\r
+message identifying itself\" ijbfaq.html#show\r
+(though the browser may\r
+display only a broken image icon).\r
+(Versions before 2.0 returned an error 403 (Forbidden).)\r
+The syntax of a pattern is\r
+\fB\&[domain][:port][/path]\fP\r
+(the\r
+\fB\&http://\fP\r
+or\r
+\fB\&https://\fP\r
+protocol part is omitted).\r
+To decide if a pattern matches a target, the domains are compared first,\r
+then the paths. \r
+.P\r
+To compare the domains,\r
+the pattern domain and the target\r
+domain specified in the\r
+\s-2URL\s0\r
+are each broken into their components.\r
+(Components are separated by the\r
+\fC\&.\fP\r
+(period) character.)\r
+Next each of the target components\r
+is compared with the corresponding pattern component: last with last,\r
+next-to-last with next-to-last, and so on.\r
+(This is called\r
+\fIright-anchored\fP\r
+matching.)\r
+If all of the pattern components find their match in the target,\r
+then the domains are considered a match.\r
+Case is irrelevant when comparing domain components.\r
+.P\r
+A successfully\r
+matching pattern can be an anchored substring of a target, but\r
+not vice versa.\r
+Thus if a pattern doesn't specify a domain,\r
+it matches all domains.\r
+.\" anchor: wildcard\r
+Furthermore, when comparing two components,\r
+the components must either match in their entirety or up to a wildcard\r
+\fC\&* \fP\r
+(star character) in the pattern.  The wildcard feature\r
+implements only a "prefix" match capability ("abc*" vs. "abcdefg"),\r
+not suffix matching ("*efg" vs. "abcdefg") or\r
+infix matching ("abc*efg" vs. "abcdefg").\r
+The feature is restricted to the domain component;\r
+it is unrelated to the optional\r
+regular expression\r
+feature in the path\r
+(described below).\" ijbman.html#regex\r
+.P\r
+If a numeric port\r
+is specified in the pattern domain, then the target port must\r
+match as well.  The default port in a target is port 80.\r
+.P\r
+If the domain and port match,\r
+then the target\r
+\s-2URL\s0\r
+path is checked for\r
+a match against the path in the pattern.\r
+Paths are compared with a simple case-sensitive\r
+left-anchored substring comparison.\r
+Once again, the pattern can be an\r
+anchored substring of the target, but not vice versa.\r
+A path of\r
+\fC\&/\fP\r
+(slash) would match all paths.  Wildcards are not considered in\r
+path comparisons.\r
+.P\r
+For example, the target\r
+\s-2URL\s0\r
+.br\r
+.ti +0.25i\r
+\fB\&the.yellow-brick-road.com/TinMan/has_no_brain\fP\r
+.br\r
+would be matched (and blocked) by the following patterns\r
+.br\r
+.ti +0.25i\r
+\fB\&yellow-brick-road.com\fP\r
+.br\r
+and\r
+.br\r
+.ti +0.25i\r
+\fB\&Yellow*.COM\fP\r
+.br\r
+and\r
+.br\r
+.ti +0.25i\r
+\fB\&/TinM\fP\r
+.br\r
+but not\r
+.br\r
+.ti +0.25i\r
+\fB\&follow.the.yellow-brick-road.com\fP\r
+.br\r
+or\r
+.br\r
+.ti +0.25i\r
+\fB\&/tinman\fP\r
+.br\r
+.P\r
+Comments in a blockfile start with a\r
+\fB\&#\fP\r
+(hash) character and end at a new line.\r
+Blank lines are also ignored.\r
+.P\r
+Lines beginning with a\r
+\fC\&~\fP\r
+(tilde) character are taken to be\r
+exceptions:\" ijbfaq.html#exceptions\r
+a\r
+\s-2URL\s0\r
+blocked by previous patterns that matches the rest of\r
+the line is let through. (The last match wins.)\r
+.P\r
+Patterns\r
+may contain\r
+\s-2POSIX\s0\r
+regular expressions\" ijbfaq.html#regex\r
+provided the\r
+\fBjunkbuster\fP\r
+was compiled with this option\r
+(the default in Version 2.0 on).\r
+The idiom\r
+\fC\&/*.*/ad\fP\r
+can then be used\r
+to match any\r
+\s-2URL\s0\r
+containing\r
+\fC\&/ad\fP\r
+(such as\r
+\fC\&http://nomatterwhere.com/images/advert/g3487.gif\fP\r
+for example).\r
+These expressions\r
+don't work\" ijbman.html#substring\r
+in the domain part.\r
+.P\r
+In version 1.3 and later\r
+the blockfile and cookiefile are checked for changes before each request.\r
+.TP\r
+tinygif \fIN\fP\r
+Set appearance of blocked GIFs. You can select one of the following\r
+values:\r
+.br\r
+.br\r
+\h'-\w"0 = "u'0 = Show a ``broken icon'' in the browser\r
+.br\r
+\h'-\w"1 = "u'1 = Show a one pixel transparent GIF\r
+.br\r
+\h'-\w"2 = "u'2 = Show a GIF with the word ``JUNKBUSTER''\r
+.TP\r
+popupfile \fI\&popup\fP\r
+Sets the name of the popupfile. If uncommented, the popupfile\r
+controls on which sites Javascript popup windows are disabled.\r
+.TP\r
+.\" anchor: o_w wafer\r
+\fI-w NAME=VALUE\fP (Old) wafer \fINAME=VALUE\fP (New)\r
+Specifies a pair to be sent as a cookie with every request\r
+to the server.\" ijbfaq.html#wafers\r
+(Such boring cookies are called\r
+\fI\&wafers\fP.)\r
+This option may be called more than once to generate multiple wafers.\r
+The original\r
+Netscape specification\r
+prohibited\r
+semi-colons, commas and white space;\r
+these characters will be\r
+\s-2URL\s0-encoded\r
+if used in wafers.\r
+The Path and Domain attributes are not currently supported.\r
+.TP\r
+.\" anchor: o_c cookiefile\r
+\fI-c cookiefile\fP (Old) cookiefile \fIcookiefile\fP (New)\r
+Enforce the cookie management policy specified in the\r
+\fI\&cookiefile.\fP\r
+.\" anchor: java\r
+If this option is not used all cookies are silently crunched,\r
+so that users who never want cookies aren't bothered by browsers\r
+asking whether each cookie should be accepted.\r
+However, cookies can\r
+still get through\" ijbfaq.html#breakthrough\r
+via\r
+JavaScript\" links.html#javascript\r
+and\r
+\s-2SSL\s0,\r
+so alerts should be left on.\r
+.P\r
+In Version 1.2 and later\r
+this option must be followed by a\r
+filename\" ijbfaq.html#crumble\r
+containing instructions on which sites are allowed to\r
+receive and set cookies.\r
+.\" anchor: drop\r
+By default cookies are dropped in both the browser's request\r
+and the server's response, unless the\r
+\s-2URL\s0\r
+requested matches an entry in the\r
+\fI\&cookiefile\fP.\r
+The matching algorithm is the same as for the blockfile.\r
+A leading\r
+\fC\&>\fP\r
+character allows\r
+server-bound\" ijbfaq.html#directional\r
+cookies only;\r
+a\r
+\fC\&<\fP\r
+allows only browser-bound cookies;\r
+a\r
+\fC\&~\fP\r
+character stops cookies in\r
+both directions.\" ijbfaq.html#crumble\r
+Thus a cookiefile containing a single line with the two characters\r
+\fC\&>*\fP\r
+will pass on all cookies to servers but not give any new ones to the browser.\r
+.TP\r
+.\" anchor: o_j jarfile\r
+\fI-j jarfile\fP (Old) jarfile \fIjarfile\fP (New)\r
+All Set-cookie attempts by the server are\r
+logged\" ijbfaq.html#jar\r
+to\r
+\fI\&jarfile\fP.\r
+If no wafer is specified,\r
+one containing a\r
+canned notice\" ijbfaq.html#notice\r
+(the \r
+\fI\&vanilla wafer\fP)\r
+is added as an alert to the server\r
+unless the\r
+suppress-vanilla-wafer\" ijbman.html#suppress-vanilla-wafer\r
+option is invoked.\r
+.TP\r
+.\" anchor: o_v suppress-vanilla-wafer\r
+\fI-v\fP (Old) suppress-vanilla-wafer \fI\fP (New)\r
+Suppress the vanilla wafer.\r
+.TP\r
+.\" anchor: o_t from\r
+\fI-t from\fP (Old) from \fIfrom\fP (New)\r
+If the browser\r
+discloses an email address\" ijbfaq.html#from\r
+in the\r
+\fB\&FROM\fP\r
+header (most don't),\r
+replace it with\r
+\fI\&from.\fP\r
+If\r
+\fI\&from\fP\r
+is set to\r
+\fB\&.\fP\r
+(the period character)\r
+the\r
+\fB\&FROM\fP\r
+is passed to the server unchanged.\r
+The default is to delete the\r
+\fB\&FROM\fP\r
+header.\r
+.TP\r
+.\" anchor: o_r referer\r
+\fI-r referer\fP (Old) referer \fIreferer\fP (New)\r
+Whenever the browser discloses the\r
+\s-2URL\s0\r
+that\r
+led to\" ijbfaq.html#referer\r
+the current request,\r
+replace it with\r
+\fI\&referer.\fP\r
+If\r
+\fI\&referer\fP\r
+is set to\r
+\fB\&.\fP\r
+(period)\r
+the \r
+\s-2URL\s0\r
+is passed to the server unchanged.\r
+In \r
+Version 1.4\r
+and later, if referer is set to \r
+\fB\&@\fP\r
+(at) the\r
+\s-2URL\s0\r
+is sent in cases where the cookiefile\r
+specifies that a cookie would be sent.\r
+(No way to send bogus referers selectively is provided.)\r
+The default is to delete Referer.\r
+.P\r
+Version 2.0 also accepts the spelling\r
+\fC\&referrer\fP,\r
+which most dictionaries consider correct.\r
+.TP\r
+.\" anchor: o_u user-agent\r
+\fI-u user-agent\fP (Old) user-agent \fIuser-agent\fP (New)\r
+Information disclosed by the browser\r
+about itself\" ijbfaq.html#agent\r
+is replaced with the value\r
+\fI\&user-agent.\fP\r
+If\r
+\fI\&user-agent\fP\r
+is set to\r
+\fB\&.\fP\r
+(period)\r
+the\r
+\fB\&User-Agent\fP\r
+header is passed to the server unchanged,\r
+along with any\r
+\fB\&UA\fP\r
+headers produced by\r
+\s-2MS-IE\s0\r
+(which would otherwise be deleted).\r
+In \r
+Version 1.4\r
+and later, if\r
+\fI\&user-agent\fP\r
+is set to\r
+\fB\&@\fP\r
+(at) these headers are sent unchanged in cases where the cookiefile\r
+specifies that a cookie would be sent,\r
+otherwise only default\r
+\fB\&User-Agent\fP\r
+header is sent.\r
+That default\r
+is Mozilla/3.0 (Netscape)\r
+with an unremarkable\r
+Macintosh\" ijbfaq.html#infer\r
+configuration.\r
+If used with a browser less advanced than Mozilla/3.0 or IE-3, the default\r
+may encourage pages containing extensions that confuse the browser.\r
+.TP\r
+.\" anchor: o_h listen-address\r
+\fI-h [host][:port]\fP (Old) listen-address \fI[host][:port]\fP (New)\r
+If\r
+\fI\&host\fP\r
+is specified,\r
+bind the\r
+\fBjunkbuster\fP\r
+to that\r
+\s-2IP\s0\r
+address.\r
+If a\r
+\fI\&port\fP\r
+is specified, use it.\r
+The default\r
+port\r
+is 8000;\r
+the default host is\r
+\fC\&localhost\fP.\r
+Before Version 2.0.2,\r
+the default was to bind to all \r
+\s-2IP\s0\r
+addresses\r
+(\fB\&INADDR_ANY\fP);\r
+but this has been restricted to\r
+\fB\&localhost\fP\r
+to avoid unintended security breaches.\r
+(To open the proxy to all, use the line\r
+.br\r
+.ti +0.25i\r
+\fB\&listen-address :8000\fP\r
+.br\r
+in the configuration file.)\r
+.TP\r
+.\" anchor: o_f forwardfile\r
+\fI-f forward_host[:port]\fP (Old) forwardfile \fIforwardfile\fP (New)\r
+Version 1.X required all\r
+\s-2HTTP\s0\r
+requests from the client to be forwarded to the same destination.\r
+Version 2.0 takes its routing specification from a\r
+\fI\&forwardfile\fP,\r
+allowing selection of the proxy (a.k.a. forwarding host) and gateway\r
+according to the\r
+\s-2URL\s0.\r
+Here is a typical line.\r
+.br\r
+.ft CW\r
+.S 8\r
+.nf\r
+.sp\r
+*         lpwa.com:8000      .      .\r
+.S\r
+.ft\r
+.fi\r
+.sp\r
+\r
+.P\r
+Each line contains four fields:\r
+\fB\&target\fP,\r
+\fB\&forward_to\fP,\r
+\fB\&via_gateway_type\fP\r
+and\r
+\fB\&gateway\fP.\r
+As usual, the\r
+last\" ijbman.html#compare\r
+\fB\&target\fP\r
+domain that matches the requested\r
+\s-2URL\s0\r
+wins,\r
+and the\r
+\fC\&*\fP\r
+character alone matches any domain.\r
+The target domain need not be a fully qualified\r
+hostname; it can be a general domain such as\r
+\fC\&com\fP\r
+or\r
+\fC\&co.uk\fP\r
+or even just a port number.\r
+.\" anchor: nose\r
+For example, because\r
+<a href="http://lpwa.com">LPWA</a>\r
+does not handle\r
+SSL,\" ijbfaq.html#encrypt\r
+the line above will typically be followed by a line such as\r
+.br\r
+.ft CW\r
+.S 8\r
+.nf\r
+.sp\r
+:443  .      .      .\r
+.S\r
+.ft\r
+.fi\r
+.sp\r
+\r
+to allow SSL transactions to proceed directly.\r
+The cautious would also\r
+add an entry in their blockfile to stop transactions\r
+to port 443 for all but specified trusted sites.\r
+.P\r
+If the winning\r
+\fB\&forward_to\fP\r
+field is\r
+\fC\&.\fP\r
+(the dot character) the proxy connects \r
+directly to the server given in the\r
+\s-2URL\s0,\r
+otherwise it forwards to the host and port number specified.\r
+The default port is 8000.\r
+The\r
+\fC\&via_gateway_type\fP\r
+and\r
+\fC\&gateway\fP\r
+fields also use a dot to indicate no gateway protocol.\r
+The gateway protocols are explained\r
+below.\" ijbman.html#o_g\r
+.P\r
+The example line above in a forwardfile alone\r
+would send everything through port 8000 at\r
+\fC\&lpwa.com\fP\r
+with no gateway protocol,\r
+and is equivalent to the old\r
+\fC\&-f lpwa.com:8000\fP\r
+with no\r
+\fC\&-g\fP\r
+option.\r
+For more information see the example file provided with the distribution.\r
+.P\r
+Configure with care: no loop detection is performed.\r
+When setting up chains of proxies that might loop back, try adding\r
+Squid.\" ijbman.html#squid\r
+.TP\r
+.\" anchor: o_g \r
+\fI-g gw_protocol[:[gw_host][:gw_port]]\fP (Old) \r
+Use\r
+\fI\&gw_protocol\fP\r
+as the gateway protocol.\r
+This option was introduced in Version 1.4,\r
+but was folded into the\r
+forwardfile\" ijbman.html#forwardfile\r
+option in Version 2.0.\r
+The default is to use no gateway protocol;\r
+this may be explicitly specified as\r
+\fB\&direct\fP\r
+on the command line\r
+or the dot character in the forwardfile.\r
+The\r
+\fC\&SOCKS4\fP\r
+protocol may be specified as\r
+\fB\&socks\fP\r
+or\r
+\fB\&socks4\fP.\r
+The\r
+\fC\&SOCKS4A\fP\r
+protocol is specified as\r
+\fB\&socks4a\fP.\r
+The\r
+\fC\&SOCKS5\fP\r
+protocol is not currently supported.\r
+The default\r
+\s-2SOCKS\s0\r
+\fI\&gw_port\fP\r
+is 1080.\r
+.P\r
+The user's browser should\r
+\fInot\fP\r
+be\r
+configured\" ijbfaq.html#socks\r
+to use\r
+\fC\&SOCKS\fP;\r
+the proxy conducts the negotiations, not the browser.\r
+.P\r
+The user identification capabilities of\r
+\fC\&SOCKS4\fP\r
+are deliberately not used;\r
+the user is always identified to the\r
+\fC\&SOCKS\fP\r
+server as\r
+\fC\&userid=anonymous\fP.\r
+If the server's policy is to reject requests from\r
+\fC\&anonymous\fP,\r
+the proxy will not work.\r
+Use a\r
+debug\" ijbman.html#o_d\r
+value of 3\r
+to see the status returned by the server.\r
+.TP\r
+.\" anchor: o_d debug\r
+\fI-d N\fP (Old) debug \fIN\fP (New)\r
+Set debug mode.\r
+The most common value is 1,\r
+to\r
+pinpoint\" ijbfaq.html#pinpoint\r
+offensive\r
+\s-2URL\s0s,\r
+so they can be added to the blockfile.\r
+The value of\r
+\fB\&N\fP\r
+is a bitwise\r
+logical-\s-2OR\s0\r
+of the following values:\r
+.br\r
+.br\r
+\h'-\w"1 = "u'1 = URLs (show each URL requested by the browser);\r
+.br\r
+\h'-\w"2 = "u'2 = Connections (show each connection to or from the proxy);\r
+.br\r
+\h'-\w"4 = "u'4 = I/O (log I/O errors);\r
+.br\r
+\h'-\w"8 = "u'8 = Headers (as each header is scanned, show the header and what is done to it);\r
+.br\r
+\h'-\w"16 = "u'16 = Log everything (including debugging traces and the contents of the pages).\r
+.\" anchor: or\r
+Multiple\r
+\fB\&debug\fP\r
+lines are permitted; they are logical OR-ed together.\r
+.P\r
+Because most browsers send several requests in parallel\r
+the debugging output may appear intermingled, so the\r
+single-threaded\" ijbman.html#single-threaded\r
+option is recommended when using\r
+debug\" ijbman.html#debug\r
+with\r
+\fB\&N\fP\r
+greater than 1.\r
+.TP\r
+.\" anchor: o_y add-forwarded-header\r
+\fI-y\fP (Old) add-forwarded-header \fI\fP (New)\r
+Add \r
+\fB\&X-Forwarded-For\fP\r
+headers to the server-bound \r
+\s-2HTTP\s0\r
+stream\r
+indicating the client \r
+\s-2IP\s0\r
+address\r
+to the server,\" ijbfaq.html#detect\r
+in the new style of\r
+Squid 1.1.4.\" ijbman.html#squid\r
+If you want the traditional\r
+\fC\&HTTP_FORWARDED\fP\r
+response header, add it manually with the\r
+-x\" ijbman.html#o_x\r
+option.\r
+.TP\r
+.\" anchor: o_x add-header\r
+\fI-x HeaderText\fP (Old) add-header \fIHeaderText\fP (New)\r
+Add the\r
+\fI\&HeaderText\fP\r
+verbatim to requests to the server.\r
+Typical uses include\r
+adding old-style forwarding notices such as\r
+\fB\&Forwarded: by http://pro-privacy-isp.net\fP\r
+and reinstating the\r
+\fB\&Proxy-Connection: Keep-Alive\fP\r
+header\r
+(which the\r
+\fBjunkbuster\fP\r
+deletes so as\r
+not\" ijbfaq.html#detect\r
+to reveal its existence).\r
+No checking is done for correctness or plausibility,\r
+so it can be used to throw any old trash into the server-bound \r
+\s-2HTTP\s0\r
+stream.\r
+Please don't litter.\r
+.TP\r
+.\" anchor: o_s single-threaded\r
+\fI-s\fP (Old) single-threaded \fI\fP (New)\r
+Doesn't\r
+\fB\&fork()\fP\r
+a separate process\r
+(or create a separate thread)\r
+to handle each connection.\r
+Useful when debugging to keep the process single threaded.\r
+.TP\r
+.\" anchor: o_l logfile\r
+\fI-l logfile\fP (Old) logfile \fIlogfile\fP (New)\r
+Write all debugging data into\r
+\fI\&logfile.\fP\r
+The default\r
+\fI\&logfile\fP\r
+is the standard output.\r
+.TP\r
+.\" anchor: o_acl aclfile\r
+aclfile \fIaclfile\fP (New)\r
+Unless this option is used, the proxy talks to anyone who can connect to it,\r
+and everyone who can has equal permissions on where they can go.\r
+An access file allows restrictions to be placed on these two policies,\r
+by distinguishing some\r
+\fIsource\fP\r
+\s-2IP\s0\r
+addresses and/or\r
+some\r
+\fIdestination\fP\r
+addresses.\r
+(If a\r
+forwarder or a gateway\" ijbman.html#forwardfile\r
+is being used, its address is considered the destination address,\r
+not the ultimate\r
+\s-2IP\s0\r
+address of the\r
+\s-2URL\s0\r
+requested.)\r
+.P\r
+Each line of the access file begins with\r
+either the word\r
+\fB\&permit\fP\r
+or\r
+\fB\&deny\fP\r
+followed by source and (optionally) destination addresses \r
+to be matched against those of the\r
+\s-2HTTP\s0\r
+request.\r
+The last matching line specifies the result: if it was a\r
+\fB\&deny\fP\r
+line or if no line matched,\r
+the request will be refused.\r
+.P\r
+A source or destination\r
+can be specified as a single numeric\r
+\s-2IP\s0\r
+address,\r
+or with a hostname, provided that the host's name\r
+can be resolved to a numeric address: this cannot be used to block all\r
+\fB\&.mil \fP\r
+domains for example,\r
+because there is no single address associated with that domain name.\r
+Either form may be followed by a slash and an integer\r
+\fB\&N\fP,\r
+specifying a subnet mask of\r
+\fB\&N\fP\r
+bits.\r
+For example,\r
+\fB\&permit 207.153.200.72/24\fP\r
+matches the entire Class-C subnet from\r
+207.153.200.0\r
+through 207.153.200.255.\r
+(A netmask of 255.255.255.0 corresponds to 24 bits of\r
+ones in the netmask, as with\r
+\fC\&*_MASKLEN=24\fP.)\r
+A value of 16 would be used for a Class-B subnet.\r
+A value of zero for\r
+\fB\&N\fP\r
+in the subnet mask length will cause any address to match;\r
+this can be used to express a default rule.\r
+For more information see the example file provided with the distribution.\r
+.P\r
+If you like these access controls\r
+you should probably have\r
+firewall;\" ijbfaq.html#firewall\r
+they are not intended to replace one.\r
+.TP\r
+.\" anchor: o_tf trustfile\r
+trustfile \fItrustfile\fP (New)\r
+This feature is experimental, has not been fully documented and is\r
+very subject to change.\r
+The goal is for parents to be able to choose a page or site whose\r
+links they regard suitable for their\r
+young children\" ijbfaq.html#children\r
+and for the proxy to allow access only to sites mentioned there.\r
+To do this the proxy examines the\r
+referer\" ijbman.html#o_r\r
+variable on each page request to check they resulted from\r
+a click on the ``trusted referer'' site: if so the referred site\r
+is added to a list of trusted sites, so that the child can\r
+then move around that site.\r
+There are several uncertainties in this scheme that experience may be\r
+able to iron out; check back in the months ahead.\r
+.TP\r
+.\" anchor: o_ti trust_info_url\r
+trust_info_url \fItrust_info_url\fP (New)\r
+When access is denied due to lack of a trusted referer, this\r
+\s-2URL\s0\r
+is displayed with a message pointing the user to it for further information.\r
+.TP\r
+.\" anchor: o_hc hide-console\r
+hide-console \fI\fP (New)\r
+In the Windows version only, instructs the program\r
+to disconnect from and hide the command console after starting.\r
+.TP\r
+.\" anchor: o_a \r
+\fI-a\fP (Old) \r
+(Obsolete) Accept the server's\r
+\fB\&Set-cookie\fP\r
+headers, passing them through to the browser.\r
+.\" anchor: obsolete\r
+This option was removed in Version 1.2\r
+and replaced by an improvement to the\r
+-c\" ijbman.html#o_c\r
+option.\r
+.LE\r
+.SH INSTALLATION AND USE\r
+Browsers must be told where to find the\r
+\fBjunkbuster\fP\r
+(e.g.\r
+\fB\&localhost\fP\r
+port 8000).\r
+To set the \r
+\s-2HTTP\s0\r
+proxy in Netscape 3.0,\r
+go through:\r
+\fB\&Options\fP;\r
+\fB\&Network Preferences\fP;\r
+\fB\&Proxies\fP;\r
+\fB\&Manual Proxy Configuration\fP;\r
+\fB\&View\fP.\r
+See the\r
+\s-2FAQ\s0\r
+for other browsers.\r
+The\r
+Security Proxy\" ijbfaq.html#security\r
+should also be set to the same values,\r
+otherwise\r
+\fB\&shttp:\fP\r
+\s-2URL\s0s\r
+won't work.\r
+.P\r
+Note the limitations\r
+explained in the\r
+\s-2FAQ\s0.\r
+.SH CHECKING OPTIONS\r
+To allow users to\r
+check\" ijbfaq.html#show\r
+that a\r
+\fBjunkbuster\fP\r
+is running and how it is configured,\r
+it intercepts requests for any\r
+\s-2URL\s0\r
+ending in\r
+\fB\&/show-proxy-args\fP\r
+and blocks it,\r
+returning instead returns information on its\r
+version number and\r
+current configuration\r
+including the contents of its blockfile.\r
+To get an explicit warning that no\r
+\fBjunkbuster\fP\r
+intervened if the proxy was not configured,\r
+it's best to point it to a\r
+\s-2URL\s0\r
+that does this, such as\r
+http://internet.junkbuster.com/cgi-bin/show-proxy-args\r
+on Junkbusters's website.\r
+.SH SEE ALSO\r
+http://www.waldherr.org/junkbuster/\" waldherr.org#\r
+.br\r
+http://www.junkbusters.com/ht/en/ijbfaq.html\" ijbfaq.html#\r
+.br\r
+http://www.junkbusters.com/ht/en/cookies.html\" cookies.html#\r
+.br\r
+http://internet.junkbuster.com/cgi-bin/show-proxy-args\r
+.br\r
+http://www.cis.ohio-state.edu/htbin/rfc/rfc2109.html\r
+.br\r
+http://squid.nlanr.net/Squid/\r
+.br\r
+http://www-math.uni-paderborn.de/~axel/\r
+.SH COPYRIGHT AND GPL\r
+Written and copyright by the Anonymous Coders and Junkbusters Corporation\r
+and made available under the\r
+GNU General Public License (GPL).\" gpl.html#\r
+This software comes with\r
+NO WARRANTY.\" gpl.html#nowarr\r
+Internet Junkbuster\r
+Proxy\r
+is a\r
+trademark\" legal.html#marks\r
+of Junkbusters Corporation.\r
diff --git a/junkbuster.init b/junkbuster.init
new file mode 100644 (file)
index 0000000..c74b6b7
--- /dev/null
@@ -0,0 +1,149 @@
+#!/bin/sh\r
+#\r
+# $Id: junkbuster.init,v 1.2 2001/04/30 02:36:54 rodney Exp $\r
+#\r
+# This is file is either \r
+#\r
+#         /etc/rc.d/init.d/junkbuster \r
+#\r
+# or\r
+#\r
+#         /sbin/init.d/junkbuster\r
+#\r
+# and was put here by the junkbuster rpm\r
+#\r
+# junkbuster  This shell script takes care of starting and stopping\r
+#             junkbuster.\r
+#\r
+# This works only correctly if the user `nobody' is allowed\r
+# to be in the directory where this file is called \r
+# (for example: /root is NOT ok)\r
+# ---------------------------------------------------------------------------\r
+# Force /bin/sh as shell (padraic@renaghan.com).\r
+# Augmented with help by Sterling <wolffe@sempai.org>\r
+# Hints from mjohnson11@uswest.net\r
+# Hints from rochedav@primenet.com\r
+# ---------------------------------------------------------------------------\r
+# These lines are needed so Redhat's config tools will "see" this script:\r
+# chkconfig: 35 84 09\r
+# description: Blocks annoying ads from the internet, along with cookies \\r
+#              and a few other privacy features.      \r
+# processname: junkbuster\r
+# config: /etc/junkbuster/config\r
+\r
+\r
+# ---------------------------------------------------------------------------\r
+#\r
+# SuSE only\r
+#\r
+# ---------------------------------------------------------------------------\r
+if [ -f /etc/rc.config ]; then\r
+\r
+# Author: Daniel Bischof <daniel@suse.de>, 1999\r
+# Adjustment: Axel Braun <doc.b@gmx.de>, 17.08.2000 \r
+. /etc/rc.config\r
+#base=${0##*/}\r
+#link=${base#*[SK][0-9][0-9]}\r
+#test $link = $base && START_IJB=yes\r
+#test "$START_IJB" = "yes" || exit 0\r
+return=$rc_done\r
+case "$1" in\r
+    start)\r
+        echo -n "Starting The Internet Junkbuster"\r
+        su - nobody -c 'nohup /usr/sbin/junkbuster /etc/junkbuster/config < /dev/null > /dev/null &'         \r
+        sleep 1\r
+        echo -e "$return"\r
+        ;;\r
+    stop)\r
+        echo -n "Shutting down The Internet Junkbuster"\r
+        killproc -TERM /usr/sbin/junkbuster || return=$rc_failed\r
+        echo -e "$return"\r
+        ;;\r
+    restart|reload)\r
+        echo -n "Reload The Internet Junkbuster"\r
+        killproc -HUP /usr/sbin/junkbuster || return=$rc_failed\r
+        echo -e "$return"\r
+        ;;\r
+    status)\r
+        checkproc /usr/sbin/junkbuster && echo OK || echo No process\r
+        ;;\r
+    *)\r
+        echo "Usage: $0 {start|restart|status|stop}"\r
+        exit 1\r
+esac\r
+test "$return" = "$rc_done" || exit 1\r
+exit 0\r
+\r
+else\r
+# ---------------------------------------------------------------------------\r
+#\r
+# RedHat only\r
+#\r
+# ---------------------------------------------------------------------------\r
+\r
+# Source function library.\r
+if [ -f /etc/rc.d/init.d/functions ]; then\r
+. /etc/rc.d/init.d/functions\r
+fi\r
+\r
+if [ -f /etc/sysconfig/network ]; then\r
+. /etc/sysconfig/network\r
+fi\r
+\r
+#  Check that networking is up.\r
+[ ${NETWORKING} = "no" ] && exit 0\r
+\r
+[ -f /etc/junkbuster/config ] || exit 0\r
+\r
+[ -f /usr/sbin/junkbuster ] || exit 0\r
+\r
+RETVAL=0\r
+\r
+# See how we were called.\r
+case "$1" in\r
+\r
+   start)\r
+           # abort if already started\r
+      pid=`pidofproc junkbuster`\r
+      [ -n "$pid" ] && ps h $pid >/dev/null 2>&1 && \\r
+      echo -n "Already started: " && status junkbuster && \\r
+      exit 0\r
+\r
+      # Start daemon.\r
+      echo -n "Starting junkbuster:" && RETVAL=1\r
+      ulimit -c 0\r
+                su - nobody -s /bin/sh -c '/usr/sbin/junkbuster /etc/junkbuster/config' &\r
+      sleep 1\r
+      pid=`pidofproc junkbuster`\r
+      [ -n "$pid" ] && ps h $pid >/dev/null 2>&1 && RETVAL=0 && echo_success && touch /var/lock/subsys/junkbuster\r
+      [ $RETVAL -eq 1 ] && echo_failure\r
+      echo\r
+      ;;\r
+\r
+   stop)\r
+      # Stop daemon.\r
+      echo -n "Shutting down junkbuster:"\r
+                killproc junkbuster\r
+      RETVAL=$?\r
+      [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/junkbuster\r
+      echo\r
+      ;;\r
+\r
+   status)\r
+      status junkbuster\r
+      RETVAL=$?\r
+      ;;\r
+\r
+   restart|reload)\r
+                $0 stop && $0 start\r
+      ;;\r
+\r
+   *)\r
+      echo "Usage: junkbuster {start|stop|status|restart|reload}"\r
+      exit 1\r
+esac\r
+\r
+exit $RETVAL\r
+\r
+fi\r
+\r
diff --git a/junkbuster.logrotate b/junkbuster.logrotate
new file mode 100644 (file)
index 0000000..e8e8b92
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Logrotate file for Junkbuster RPM
+#
+# $Id: junkbuster.logrotate,v 1.1 2001/04/30 03:17:00 rodney Exp $
+
+# Fixed problems of 
+#  filename.1 -> filename.1.2 -> filename.1.3
+#  filename.1.2.2, filename.1.2.3, filename.1.3.2, filename.1.3.3
+#  filename.1.2.2.2, filename.1.2.2.3  ...
+# by explicitly listing each logfile in the directory instead of `*'.
+#
+
+/var/log/junkbuster/junkbuster {
+   compress
+        weekly
+}
+
+
+#/var/log/junkbuster/jarfile {
+#  compress
+#        weekly
+#}
diff --git a/junkbuster.monthly b/junkbuster.monthly
new file mode 100644 (file)
index 0000000..44ff349
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh\r
+\r
+# $Id: junkbuster.monthly,v 1.1 2001/04/16 21:10:38 rodney Exp $\r
+#\r
+# bug fixed, which downloaded all three files to the file blocklist\r
+#\r
+# Revised: Mon Dec 06 10:46:08 PST 1999 by Jon Hamkins\r
+# Hints by Ulrik Haugen <qha@lysator.liu.se>\r
+# Hints by mirjamv@theochem.kun.nl\r
+#\r
+set -e\r
+\r
+# blocklist\r
+wget -q --output-document=/etc/junkbuster/blocklist.new \\r
+     http://www.waldherr.org/blocklist\r
+\r
+mv -f /etc/junkbuster/blocklist.new /etc/junkbuster/blocklist\r
+\r
+if [ -f /etc/junkbuster/blocklist.local ] ; then\r
+   cat /etc/junkbuster/blocklist.local >> /etc/junkbuster/blocklist\r
+fi\r
+chmod 644 /etc/junkbuster/blocklist\r
+\r
+# cookiefile\r
+wget -q --output-document=/etc/junkbuster/cookiefile.new \\r
+     http://www.waldherr.org/cookiefile\r
+\r
+mv -f /etc/junkbuster/cookiefile.new /etc/junkbuster/cookiefile\r
+\r
+if [ -f /etc/junkbuster/cookiefile.local ] ; then\r
+   cat /etc/junkbuster/cookiefile.local >> /etc/junkbuster/cookiefile\r
+fi\r
+chmod 644 /etc/junkbuster/cookiefile\r
+\r
+# imagelist\r
+wget -q --output-document=/etc/junkbuster/imagelist.new \\r
+     http://www.waldherr.org/imagelist\r
+\r
+mv -f /etc/junkbuster/imagelist.new /etc/junkbuster/imagelist\r
+\r
+if [ -f /etc/junkbuster/imagelist.local ] ; then\r
+   cat /etc/junkbuster/imagelist.local >> /etc/junkbuster/imagelist\r
+fi\r
+chmod 644 /etc/junkbuster/imagelist\r
diff --git a/junkbuster.weekly b/junkbuster.weekly
new file mode 100644 (file)
index 0000000..bc07b23
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh\r
+\r
+# $Id: junkbuster.weekly,v 1.1 2001/04/16 21:10:38 rodney Exp $\r
+\r
+# Revised: Mon Dec 06 10:46:08 PST 1999 by Jon Hamkins\r
+# Hints by Ulrik Haugen <qha@lysator.liu.se>\r
+# Hints by mirjamv@theochem.kun.nl\r
+\r
+set -e\r
+\r
+# blocklist\r
+wget -q --output-document=/etc/junkbuster/blocklist.new \\r
+     http://www.waldherr.org/blocklist\r
+\r
+mv -f /etc/junkbuster/blocklist.new /etc/junkbuster/blocklist\r
+\r
+if [ -f /etc/junkbuster/blocklist.local ] ; then\r
+   cat /etc/junkbuster/blocklist.local >> /etc/junkbuster/blocklist\r
+fi\r
+\r
+chmod 644 /etc/junkbuster/blocklist\r
diff --git a/killpopup.c b/killpopup.c
new file mode 100644 (file)
index 0000000..7004962
--- /dev/null
@@ -0,0 +1,245 @@
+const char killpopup_rcs[] = "$Id: killpopup.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/killpopup.c,v $
+ *
+ * Purpose     :  Handles the filtering of popups.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: killpopup.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include "project.h"
+#include "killpopup.h"
+#include "jcc.h"
+
+const char killpopup_h_rcs[] = KILLPOPUP_H_VERSION;
+
+#ifdef KILLPOPUPS
+
+/* Change these for debug output.  *lots*. */
+/*#define POPUP_VERBOSE 1*/
+/* CHANGED - added the below and shifted the more spammy stuff into it ;-) */
+#undef POPUP_VERY_VERBOSE
+#undef POPUP_VERBOSE
+
+
+/*********************************************************************
+ *
+ * Function    :  filter_popups
+ *
+ * Description :  Filter the block of data that's been read from the server.
+ *                IF NECESSARY.
+ *
+ * Parameters  :
+ *          1  :  csp = Client state
+ *          2  :  host_name = hostname of originating web page to
+ *                look up on blocklist
+ *          3  :  buff = Buffer to scan and modify.  Null terminated.
+ *          4  :  size = Buffer size, excluding null terminator.
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+void filter_popups(struct client_state *csp, char *host_name, char *buff, int size)
+{
+   struct popup_settings * data;
+   struct popup_blocklist * cur;
+   int i;
+   int found = 0;
+   char *popup = NULL;
+   char *close = NULL;
+   char *p     = NULL;
+   char *q     = NULL; /* by BREITENB NEW! */
+
+   if ( (!csp->plist) || ((data = csp->plist->f) == NULL) )
+   {
+      /* Disabled. */
+      return;
+   }
+
+   /* If the hostname is on our list for blocking then mark it
+    * as a host to   block from.  (This may be later changed if the
+    * host is also on the list-to-allow list).
+    */
+
+   for (i=0; (i < 50) && (i < size); i++)   /* avoid scanning binary data! */
+   {
+      if ((unsigned int)(buff[i])>127)
+      {
+#ifdef  POPUP_VERBOSE
+         fprintf(logfp, "I'm not scanning binary stuff! (%i)\n",buff[i]);
+#endif
+         return;
+      }
+   }
+
+
+   for (cur = data->blocked ; cur ; cur = cur->next)
+   {
+      if ( host_name != 0 )
+      {
+         if ( strcmp( cur->host_name, host_name ) == 0 )
+         {
+#ifdef  POPUP_VERBOSE
+            fprintf(logfp, "Blocking %s\n", host_name );
+#endif
+            found = 1;
+         }
+      }
+   }
+
+   /* Force match if we're supposed to nuke _all_ popups, globally. */
+   if ( kill_all_popups != 0 )
+   {
+#ifdef POPUP_VERBOSE
+      fprintf(logfp, "Indescriminatly nuking popups..\n" );
+#endif
+      found = 1;
+   }
+   /* an exception-from blocking should still be an exception! by BREITENB NEW! */
+
+
+   /*    Now, if its allowed adjust the filtering, so it _doesn't_ happen. */
+   for (cur = data->allowed ; cur ; cur = cur->next)
+   {
+      if ( host_name != 0 )
+      {
+         if ( strcmp( cur->host_name, host_name ) == 0 )
+         {
+#ifdef POPUP_VERBOSE
+            fprintf(logfp, "Reversing block decision for %s\n", host_name );
+#endif
+            found = 0;
+         }
+      }
+   }
+
+   if ( found == 0)
+   {
+#ifdef POPUP_VERBOSE
+      fprintf(logfp, "Allowing %s\n", host_name );
+#endif
+      return;
+   }
+
+   while ((popup = strstr( buff, "window.open(" )) != NULL)
+      /* if ( popup  )  by BREITENB filter ALL popups! NEW! */
+   {
+#ifdef POPUP_VERBOSE
+      fprintf(logfp, "Found start of window open" );
+#endif
+      close = strstr( popup+1, ");" );
+      if ( close )
+      {
+#ifdef POPUP_VERBOSE
+         fprintf(logfp, "Found end of window open" );
+#endif
+         for ( p = popup; p != (close+1); p++ )
+         {
+            *p = ' ';
+         }
+#ifdef POPUP_VERBOSE
+         fprintf(logfp, "Blocked %s\n", host_name );
+#endif
+      }
+      else
+      {
+#ifdef POPUP_VERBOSE
+         fprintf(logfp, "Couldn't find end, turned into comment.  Read boundary?\n" );
+#endif
+         *popup = '/';
+         popup++;
+         *popup = '/';
+      }
+
+
+      q=popup; /* by BREITENB NEW! */
+      while (q>=buff)
+      {
+         if (*q==' ' || *q=='\t')
+            q--;
+         else break;
+      }
+      if (q>=buff)
+      {
+         if (*q=='=') *++q='1';
+         /* result of popup is assigned to a variable! ensure success. hehehe. */
+      }
+   }
+
+   /* Filter all other crap like onUnload onExit etc.  (by BREITENB) NEW!*/
+   popup=strstr( buff, "<body");
+   if (!popup) popup=strstr( buff, "<BODY");
+   if (!popup) popup=strstr( buff, "<Body");
+   if (!popup) popup=strstr( buff, "<BOdy");
+   if (popup)
+   {
+      q=strchr(popup,'>');
+      if (q)
+      {
+         /* we are now between <body and the ending > */
+         p=strstr(popup, "onUnload");
+         if (p)
+         {
+            strncpy(p,"_nU_",4);
+         }
+         p=strstr(popup, "onExit");
+         if (p)
+         {
+            strncpy(p,"_nE_",4);
+         }
+      }
+   }
+
+}
+
+#endif /* def KILLPOPUPS */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/killpopup.h b/killpopup.h
new file mode 100644 (file)
index 0000000..42602ea
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _KILLPOPUP_H
+#define _KILLPOPUP_H
+#define KILLPOPUP_H_VERSION "$Id: killpopup.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/killpopup.h,v $
+ *
+ * Purpose     :  Handles the filtering of popups.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: killpopup.h,v $
+ *
+ *********************************************************************/
+\f
+
+#include "project.h"
+
+#ifdef KILLPOPUPS
+
+extern void filter_popups(struct client_state *csp, char *host_name, char *buff, int size);
+
+#endif /* def KILLPOPUPS */
+
+/* Revision control strings from this header and associated .c file */
+extern const char killpopup_rcs[];
+extern const char killpopup_h_rcs[];
+
+#endif /* ndef _KILLPOPUP_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/loadcfg.c b/loadcfg.c
new file mode 100644 (file)
index 0000000..f29d665
--- /dev/null
+++ b/loadcfg.c
@@ -0,0 +1,869 @@
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/loadcfg.c,v $
+ *
+ * Purpose     :  Loads settings from the configuration file into
+ *                global variables.  This file contains both the 
+ *                routine to load the configuration and the global
+ *                variables it writes to.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: loadcfg.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifdef _WIN32
+
+# include <sys/timeb.h>
+# include <windows.h>
+# include <io.h>
+# include <process.h>
+# ifdef TOGGLE
+#  include <time.h>
+# endif /* def TOGGLE */
+
+# include "win32.h"
+# ifndef _WIN_CONSOLE
+#  include "w32log.h"
+# endif /* ndef _WIN_CONSOLE */
+
+#else /* ifndef _WIN32 */
+
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <signal.h>
+
+#endif
+
+#include "loadcfg.h"
+#include "jcc.h"
+#include "filters.h"
+#include "loaders.h"
+#include "showargs.h"
+#include "parsers.h"
+#include "killpopup.h"
+#include "miscutil.h"
+#include "errlog.h"
+#include "jbsockets.h"
+#include "gateway.h"
+
+const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
+
+/*
+ * Fix a problem with Solaris.  There should be no effect on other
+ * platforms.
+ * Solaris's isspace() is a macro which uses it's argument directly
+ * as an array index.  Therefore we need to make sure that high-bit
+ * characters generate +ve values, and ideally we also want to make
+ * the argument match the declared parameter type of "int".
+ */
+#define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
+#define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
+
+static const char VANILLA_WAFER[] =
+   "NOTICE=TO_WHOM_IT_MAY_CONCERN_"
+   "Do_not_send_me_any_copyrighted_information_other_than_the_"
+   "document_that_I_am_requesting_or_any_of_its_necessary_components._"
+   "In_particular_do_not_send_me_any_cookies_that_"
+   "are_subject_to_a_claim_of_copyright_by_anybody._"
+   "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_"
+   "(copyright_or_otherwise)_applying_to_any_cookie._";
+
+#ifdef TOGGLE
+/* by haroon - indicates if ijb is enabled */
+int g_bToggleIJB        = 1;   /* JunkBusters is enabled by default. */
+#endif
+
+int debug               = 0;
+int multi_threaded      = 1;
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+int tinygif             = 0;
+const char *tinygifurl  = NULL;\r
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+const char *logfile     = NULL;
+
+const char *configfile  = NULL;
+
+const char *blockfile   = NULL;
+const char *cookiefile  = NULL;
+const char *forwardfile = NULL;
+
+#ifdef ACL_FILES
+const char *aclfile     = NULL;
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+const char *imagefile   = NULL;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+const char *popupfile   = NULL;
+int kill_all_popups     = 0;     /* Not recommended really ... */
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+const char *re_filterfile = NULL;
+int re_filter_all       = 0;
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+const char *trustfile   = NULL;
+#endif /* def TRUST_FILES */
+
+#ifdef JAR_FILES
+const char *jarfile     = NULL;
+FILE *jar = NULL;
+#endif /* def JAR_FILES */
+
+const char *referrer    = NULL;
+const char *uagent      = NULL;
+const char *from        = NULL;
+
+#ifndef SPLIT_PROXY_ARGS
+const char *suppress_message = NULL;
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+int suppress_vanilla_wafer = 0;
+int add_forwarded       = 0;
+
+struct list wafer_list[1];
+struct list xtra_list[1];
+
+#ifdef TRUST_FILES
+struct list trust_info[1];
+struct url_spec *trust_list[64];
+#endif /* def TRUST_FILES */
+
+/*
+ * Port and IP to bind to.
+ * Defaults to HADDR_DEFAULT:HADDR_PORT == 127.0.0.1:8000
+ */
+const char *haddr = NULL;
+int         hport = 0;
+
+#ifndef SPLIT_PROXY_ARGS
+int suppress_blocklists = 0;  /* suppress listing sblock and simage */
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+struct proxy_args proxy_args[1];
+
+int configret = 0;
+int config_changed = 0;
+
+
+/*
+ * The load_config function is now going to call `init_proxy_args',
+ * so it will need argc and argv.  Since load_config will also be
+ * a signal handler, we need to have these globally available.
+ */
+int Argc = 0;
+const char **Argv = NULL;
+
+
+/*
+ * This takes the "cryptic" hash of each keyword and aliases them to
+ * something a little more readable.  This also makes changing the
+ * hash values easier if they should change or the hash algorthm changes.
+ * Use the included "hash" program to find out what the hash will be
+ * for any string supplied on the command line.
+ */
+
+#define hash_trustfile                 56494766ul
+#define hash_trust_info_url            449869467ul
+#define hash_debug                     78263ul
+#define hash_tinygif                   2227702ul
+#define hash_add_forwarded_header      3191044770ul
+#define hash_single_threaded           4250084780ul
+#define hash_suppress_vanilla_wafer    3121233547ul
+#define hash_wafer                     89669ul
+#define hash_add_header                237434619ul
+#define hash_cookiefile                247469766ul
+#define hash_logfile                   2114766ul
+#define hash_blockfile                 48845391ul
+#define hash_imagefile                 51447891ul
+#define hash_jarfile                   2046641ul
+#define hash_listen_address            1255650842ul
+#define hash_forwardfile               1268669141ul
+#define hash_aclfile                   1908516ul
+#define hash_popupfile                 54623516ul
+#define hash_kill_all_popups           2311539906ul
+#define hash_re_filterfile             3877522444ul
+#define hash_re_filter_all             3877521376ul
+#define hash_user_agent                283326691ul
+#define hash_referrer                  10883969ul
+#define hash_referer                   2176719ul
+#define hash_from                      16264ul
+#define hash_hide_console              2048809870ul
+#define hash_include_stats             2174146548ul
+#define hash_suppress_blocklists       1948693308ul
+#define hash_toggle                    447966ul
+
+#define hash_activity_animation        1817904738ul
+#define hash_log_messages              2291744899ul
+#define hash_log_highlight_messages    4032101240ul
+#define hash_log_buffer_size           2918070425ul
+#define hash_log_max_lines             2868344173ul
+#define hash_log_font_name             2866730124ul
+#define hash_log_font_size             2866731014ul
+#define hash_show_on_task_bar          215410365ul
+#define hash_close_button_minimizes    3651284693ul
+
+
+/*********************************************************************
+ *
+ * Function    :  load_config
+ *
+ * Description :  Load the config file and all parameters.
+ *
+ * Parameters  :
+ *          1  :  signum : this can be the signal SIGHUP or 0 (if from main).
+ *                In any case, we just ignore this and reload the config file.
+ *
+ * Returns     :  configret : 0 => Ok, everything else is an error.
+ *                Note: we use configret since a signal handler cannot
+ *                return a value, and this function does double duty.
+ *                Ie. Is is called from main and from signal( SIGHUP );
+ *
+ *********************************************************************/
+void load_config( int signum )
+{
+   char buf[BUFSIZ];
+   char *p, *q;
+   FILE *configfp = NULL;
+
+   configret = 0;
+   config_changed = 1;
+
+   log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
+
+   init_proxy_args(Argc, Argv);
+
+
+   /* (Waste of memory [not quite a "leak"] here.  The 
+    * last blockfile/popupfile/... etc will not be 
+    * unloaded until we load a new one.  If the 
+    * block/popup/... feature has been disabled in 
+    * the new config file, then we're wasting some 
+    * memory we could otherwise reclaim.
+    */
+
+   /* Disable all loaders. */
+   remove_all_loaders();
+
+   /*
+    * Reset to as close to startup state as we can.
+    * But leave changing the logfile until after we're done loading.
+    */
+
+   #ifdef JAR_FILES
+   if ( NULL != jar )
+   {
+      fclose( jar );
+      jar = NULL;
+   }
+   #endif /* def JAR_FILES */
+
+   debug             = 0;
+   multi_threaded    = 1;
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+   tinygif           = 0;\r
+   freez((char *)tinygifurl);
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+   suppress_vanilla_wafer = 0;
+   add_forwarded     = 0;
+   hport             = HADDR_PORT;
+
+#ifdef _WIN_CONSOLE
+   hideConsole       = 0;
+#endif /*def _WIN_CONSOLE*/
+
+#ifdef PCRS
+   re_filter_all     = 0;
+#endif /* def PCRS */
+
+#ifdef KILLPOPUPS
+   kill_all_popups   = 0;
+#endif /* def KILLPOPUPS */
+
+#ifdef TOGGLE
+   g_bToggleIJB      = 1;
+#endif
+
+#ifdef STATISTICS
+   urls_read         = 0;
+   urls_rejected     = 0;
+#endif /* def STATISTICS */
+
+#ifndef SPLIT_PROXY_ARGS
+   suppress_blocklists = 0;
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   freez((char *)from);
+   freez((char *)haddr);
+   freez((char *)uagent);
+   freez((char *)referrer);
+   freez((char *)logfile);
+
+
+   freez((char *)blockfile);
+   freez((char *)cookiefile);
+   freez((char *)forwardfile);
+
+#ifdef ACL_FILES
+   freez((char *)aclfile);
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+   freez((char *)imagefile);
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef JAR_FILES
+   freez((char *)jarfile);
+#endif /* def JAR_FILES */
+
+#ifdef KILLPOPUPS
+   freez((char *)popupfile);
+#endif /* def KILLPOPUPS */
+
+#ifndef SPLIT_PROXY_ARGS
+   freez((char *)suppress_message);
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+#ifdef TRUST_FILES
+   freez((char *)trustfile);
+#endif /* def TRUST_FILES */
+
+#ifdef PCRS
+   freez((char *)re_filterfile);
+#endif /* def PCRS */
+
+   if (NULL != configfile)
+   {
+      if ((configfp = fopen(configfile, "r")) == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR, "can't open configuration file '%s':  %E",
+                 configfile);
+         configret = 1;
+         return;
+      }
+   }
+
+   if (NULL != configfp)
+   {
+      memset (buf, 'j', sizeof(buf));
+      while (read_config_line(buf, sizeof(buf), configfp, NULL) != NULL)
+      {
+         char cmd[BUFSIZ];
+         char arg[BUFSIZ];
+         char tmp[BUFSIZ];
+
+         strcpy(tmp, buf);
+
+         /* Copy command (i.e. up to space or tab) into cmd */
+         p = buf;
+         q = cmd;
+         while (*p && (*p != ' ') && (*p != '\t'))
+         {
+            *q++ = *p++;
+         }
+         *q = '\0';
+
+         /* Skip over the whitespace in buf */
+         while (*p && ((*p == ' ') || (*p == '\t')))
+         {
+            p++;
+         }
+
+         /* Copy the argument into arg */
+         strcpy(arg, p);
+
+         /* Should never happen, but check this anyway */
+         if (*cmd == '\0')
+         {
+            continue;
+         }
+
+         /* Make sure the command field is lower case */
+         for (p=cmd; *p; p++)
+         {
+            if (ijb_isupper(*p))
+            {
+               *p = ijb_tolower(*p);
+            }
+         }
+
+         /* Save the argument for show-proxy-args */
+         savearg(cmd, arg);
+
+
+         switch( hash_string( cmd ) )
+         {
+#ifdef TRUST_FILES
+            case hash_trustfile :\r
+               freez((char *)trustfile);
+               trustfile = strdup(arg);
+               continue;
+
+            case hash_trust_info_url :
+               enlist(trust_info, arg);
+               continue;
+#endif /* def TRUST_FILES */
+
+            case hash_debug :
+               debug |= atoi(arg);
+               continue;
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+            case hash_tinygif :\r
+               freez((char *)tinygifurl);
+               tinygif = atoi(arg);
+               if(3 == tinygif)\r
+               {\r
+                  p = arg;\r
+                  while((*p >= '0') && (*p <= '9'))\r
+                  {\r
+                     p++;\r
+                  }\r
+                  while((*p == ' ') || (*p == '\t'))\r
+                  {\r
+                     p++;\r
+                  }\r
+                  if (*p)\r
+                  {\r
+                     q = malloc(strlen(p) + 5);\r
+                     if (q)\r
+                     {\r
+                        strcpy(q, p);\r
+                        strcat(q, "\r\n\r\n");\r
+                        tinygifurl = q;\r
+                     }\r
+                  }\r
+               }\r
+               if ((tinygif != 1) && \r
+                   (tinygif != 2) && \r
+                   ((tinygif != 3) || (tinygifurl==NULL)) )\r
+               {\r
+                  log_error(LOG_LEVEL_ERROR, "tinygif setting invalid.");\r
+               }\r
+               continue;
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+            case hash_add_forwarded_header :
+               add_forwarded = 1;
+               continue;
+
+            case hash_single_threaded :
+               multi_threaded = 0;
+               continue;
+
+            case hash_suppress_vanilla_wafer :
+               suppress_vanilla_wafer = 1;
+               continue;
+
+            case hash_wafer :
+               enlist(wafer_list, arg);
+               continue;
+
+            case hash_add_header :
+               enlist(xtra_list, arg);
+               continue;
+
+            case hash_cookiefile :\r
+               freez((char *)cookiefile);
+               cookiefile = strdup(arg);
+               continue;
+
+            case hash_logfile :\r
+               freez((char *)logfile);
+               logfile = strdup(arg);
+               continue;
+
+            case hash_blockfile :\r
+               freez((char *)blockfile);
+               blockfile = strdup(arg);
+               continue;
+
+#ifdef USE_IMAGE_LIST
+            case hash_imagefile :\r
+               freez((char *)imagefile);
+               imagefile = strdup(arg);
+               continue;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef JAR_FILES
+            case hash_jarfile :\r
+               freez((char *)jarfile);
+               jarfile = strdup(arg);
+               continue;
+#endif /* def JAR_FILES */
+
+            case hash_listen_address :\r
+               freez((char *)haddr);
+               haddr = strdup(arg);
+               continue;
+
+            case hash_forwardfile :\r
+               freez((char *)forwardfile);
+               forwardfile = strdup(arg);
+               continue;
+
+#ifdef ACL_FILES
+            case hash_aclfile :\r
+               freez((char *)aclfile);
+               aclfile = strdup(arg);
+               continue;
+#endif /* def ACL_FILES */
+
+#ifdef KILLPOPUPS
+            case hash_popupfile :\r
+               freez((char *)popupfile);
+               popupfile = strdup(arg);
+               continue;
+
+            case hash_kill_all_popups :
+               kill_all_popups = 1;
+               continue;
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+            case hash_re_filterfile :\r
+               freez((char *)re_filterfile);
+               re_filterfile = strdup(arg);
+               continue;
+
+            case hash_re_filter_all :
+               re_filter_all = 1;
+               log_error(LOG_LEVEL_REF, "re_filter policy is %s.",
+                          re_filter_all ? "RADICAL" : "SEMI-SMART");
+               continue;
+#endif /* def PCRS */
+
+            case hash_user_agent :\r
+               freez((char *)uagent);
+               uagent = strdup(arg);
+               continue;
+
+               /*
+                * Offer choice of correct spelling according to dictionary,
+                * or the misspelling used in the HTTP spec.
+                */
+            case hash_referrer :
+            case hash_referer :\r
+               freez((char *)referrer);
+               referrer = strdup(arg);
+               continue;
+
+            case hash_from :\r
+               freez((char *)from);
+               from = strdup(arg);
+               continue;
+
+#ifdef _WIN_CONSOLE
+            case hash_hide_console :
+               hideConsole = 1;
+               continue;
+#endif /*def _WIN_CONSOLE*/
+
+#ifndef SPLIT_PROXY_ARGS
+            case hash_suppress_blocklists :
+               if (arg[0] != '\0')
+               {
+                  suppress_message = strdup(arg);
+               }
+               else
+               {
+                  /* There will be NO reference in proxy-args. */
+                  suppress_message = NULL;
+               }
+
+               suppress_blocklists = 1;
+               continue;
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+#ifdef TOGGLE
+            case hash_toggle :
+               g_bToggleIJB = atoi(arg);
+               continue;
+#endif /* def TOGGLE */
+
+#if defined(_WIN32) && ! defined(_WIN_CONSOLE)
+            case hash_activity_animation :
+               g_bShowActivityAnimation = atoi(arg);
+               continue;
+
+            case hash_log_messages :
+               g_bLogMessages = atoi(arg);
+               continue;
+
+            case hash_log_highlight_messages :
+               g_bHighlightMessages = atoi(arg);
+               continue;
+
+            case hash_log_buffer_size :
+               g_bLimitBufferSize = atoi(arg);
+               continue;
+
+            case hash_log_max_lines :
+               g_nMaxBufferLines = atoi(arg);
+               continue;
+
+            case hash_log_font_name :
+               strcpy( g_szFontFaceName, arg );
+               continue;
+
+            case hash_log_font_size :
+               g_nFontSize = atoi(arg);
+               continue;
+
+            case hash_show_on_task_bar :
+               g_bShowOnTaskBar = atoi(arg);
+               continue;
+
+            case hash_close_button_minimizes :
+               g_bCloseHidesWindow = atoi(arg);
+               continue;
+#endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
+
+            /* Warnings about unsupported features */
+
+#ifndef TRUST_FILES
+            case hash_trustfile :
+            case hash_trust_info_url :
+#endif /* ndef TRUST_FILES */
+#ifndef USE_IMAGE_LIST
+            case hash_imagefile :
+#endif /* ndef USE_IMAGE_LIST */
+#ifndef PCRS
+            case hash_re_filterfile :
+            case hash_re_filter_all :
+#endif /* ndef PCRS */
+#ifndef TOGGLE
+            case hash_toggle :
+#endif /* ndef TOGGLE */
+#if defined(_WIN_CONSOLE) || ! defined(_WIN32)
+            case hash_activity_animation :
+            case hash_log_messages :
+            case hash_log_highlight_messages :
+            case hash_log_buffer_size :
+            case hash_log_max_lines :
+            case hash_log_font_name :
+            case hash_log_font_size :
+            case hash_show_on_task_bar :
+            case hash_close_button_minimizes :
+#endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
+#ifndef _WIN_CONSOLE
+            case hash_hide_console :
+#endif /* ndef _WIN_CONSOLE */
+#if !defined(DETECT_MSIE_IMAGES) && !defined(USE_IMAGE_LIST)
+            case hash_tinygif :
+#endif /* !defined(DETECT_MSIE_IMAGES) && !defined(USE_IMAGE_LIST) */
+#ifndef KILLPOPUPS
+            case hash_popupfile :
+            case hash_kill_all_popups :
+#endif /* ndef KILLPOPUPS */
+#ifndef JAR_FILES
+            case hash_jarfile :
+#endif /* ndef JAR_FILES */
+#ifndef ACL_FILES
+            case hash_aclfile :
+#endif /* ndef ACL_FILES */
+
+#ifdef SPLIT_PROXY_ARGS
+            case hash_suppress_blocklists :
+#endif /* def SPLIT_PROXY_ARGS */
+               log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd);
+               continue;
+
+            default :
+               log_error(LOG_LEVEL_ERROR, "Unrecognized directive (%lulu) in "
+                     "configuration file: \"%s\"", hash_string( cmd ), buf);
+               p = malloc( BUFSIZ );
+               if (p != NULL)
+               {
+                  sprintf( p, "<br>\nWARNING: unrecognized directive : %s<br><br>\n", buf );
+                  proxy_args->invocation = strsav( proxy_args->invocation, p );
+                  freez( p );
+               }
+               /*
+                * I decided that I liked this better as a warning than an
+                * error.
+                */
+
+               /*
+                * configret = 1;
+                * return;
+                */
+               continue;
+         }
+      }
+      fclose(configfp);
+   }
+
+   init_error_log(Argv[0], logfile, debug);
+
+   if (cookiefile)
+   {
+      add_loader(load_cookiefile);
+   }
+
+   if (blockfile)
+   {
+      add_loader(load_blockfile);
+   }
+
+#ifdef USE_IMAGE_LIST
+   if (imagefile)
+   {
+      add_loader(load_imagefile);
+   }
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef TRUST_FILES
+   if (trustfile)
+   {
+      add_loader(load_trustfile);
+   }
+#endif /* def TRUST_FILES */
+
+   if (forwardfile)
+   {
+      add_loader(load_forwardfile);
+   }
+
+#ifdef ACL_FILES
+   if (aclfile)
+   {
+      add_loader(load_aclfile);
+   }
+#endif /* def ACL_FILES */
+
+#ifdef KILLPOPUPS
+   if (popupfile)
+   {
+      add_loader(load_popupfile);
+   }
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+   if (re_filterfile)
+   {
+      add_loader(load_re_filterfile);
+   }
+#endif /* def PCRS */
+
+#ifdef JAR_FILES
+   if ( NULL != jarfile )
+   {
+      if ( NULL == (jar = fopen(jarfile, "a")) )
+      {
+         log_error(LOG_LEVEL_ERROR, "can't open jarfile '%s': %E", jarfile);
+         configret = 1;
+         return;
+      }
+      setbuf(jar, NULL);
+   }
+#endif /* def JAR_FILES */
+
+   if ( NULL == haddr )
+   {
+      haddr = strdup( HADDR_DEFAULT );
+   }
+
+   if ( NULL != haddr )
+   {
+      if ((p = strchr(haddr, ':')))
+      {
+         *p++ = '\0';
+         if (*p)
+         {
+            hport = atoi(p);
+         }
+      }
+
+      if (hport <= 0)
+      {
+         *--p = ':';
+         log_error(LOG_LEVEL_ERROR, "invalid bind port spec %s", haddr);
+         configret = 1;
+         return;
+      }
+      if (*haddr == '\0')
+      {
+         haddr = NULL;
+      }
+   }
+
+   if (run_loader(NULL))
+   {
+      configret = 1;
+      return;
+   }
+
+#ifdef JAR_FILES
+   /*
+    * If we're logging cookies in a cookie jar, and the user has not
+    * supplied any wafers, and the user has not told us to suppress the
+    * vanilla wafer, then send the vanilla wafer.
+    */
+   if ((jarfile != NULL)
+       && (wafer_list->next == NULL)
+       && (suppress_vanilla_wafer == 0))
+   {
+      enlist(wafer_list, VANILLA_WAFER);
+   }
+#endif /* def JAR_FILES */
+
+   end_proxy_args();
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/loadcfg.h b/loadcfg.h
new file mode 100644 (file)
index 0000000..e567b7e
--- /dev/null
+++ b/loadcfg.h
@@ -0,0 +1,168 @@
+#ifndef _LOADCFG_H
+#define _LOADCFG_H
+#define LOADCFG_H_VERSION "$Id: loadcfg.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/loadcfg.h,v $
+ *
+ * Purpose     :  Loads settings from the configuration file into
+ *                global variables.  This file contains both the 
+ *                routine to load the configuration and the global
+ *                variables it writes to.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: loadcfg.h,v $
+ *
+ *********************************************************************/
+\f
+
+/* Declare struct FILE for vars and funcs. */
+#include <stdio.h>
+
+/* All of our project's data types. */
+#include "project.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global variables */
+
+#ifdef TOGGLE
+/* indicates if ijb is enabled */
+extern int g_bToggleIJB;
+#endif
+
+extern int debug;
+extern int multi_threaded;
+
+#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
+extern int tinygif;
+extern const char *tinygifurl;\r
+#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
+
+extern const char *logfile;
+
+extern const char *configfile;
+
+#ifdef ACL_FILES
+extern const char *aclfile;
+#endif /* def ACL_FILES */
+
+extern const char *blockfile;
+extern const char *cookiefile;
+extern const char *forwardfile;
+
+#ifdef USE_IMAGE_LIST
+extern const char *imagefile;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+extern const char *popupfile;
+#endif /* def KILLPOPUPS */
+
+#ifdef TRUST_FILES
+extern const char *trustfile;
+#endif /* def TRUST_FILES */
+
+#ifdef PCRS
+extern const char *re_filterfile;
+#endif /* def PCRS */
+
+#ifdef PCRS
+extern int re_filter_all;
+#endif /* def PCRS */
+
+#ifdef KILLPOPUPS
+extern int kill_all_popups;     /* Not recommended really .. */
+#endif /* def KILLPOPUPS */
+
+#ifdef JAR_FILES
+extern const char *jarfile;
+extern FILE *jar;
+#endif /* def JAR_FILES */
+
+extern const char *referrer;
+extern const char *uagent;
+extern const char *from;
+
+#ifndef SPLIT_PROXY_ARGS
+extern const char *suppress_message;
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+extern int suppress_vanilla_wafer;
+extern int add_forwarded;
+
+extern struct list wafer_list[];
+extern struct list xtra_list[];
+
+#ifdef TRUST_FILES
+extern struct list trust_info[];
+extern struct url_spec *trust_list[];
+#endif /* def TRUST_FILES */
+
+extern const char *haddr;
+extern int   hport;
+
+#ifndef SPLIT_PROXY_ARGS
+extern int suppress_blocklists;  /* suppress listing sblock and simage */
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+extern struct proxy_args proxy_args[1];
+
+extern int configret;
+extern int config_changed;
+
+
+/* The load_config function is now going to call:
+ * init_proxy_args, so it will need argc and argv.
+ * Since load_config will also be a signal handler,
+ * we need to have these globally available.
+ */
+extern int Argc;
+extern const char **Argv;
+
+
+extern void load_config( int );
+
+
+/* Revision control strings from this header and associated .c file */
+extern const char loadcfg_rcs[];
+extern const char loadcfg_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _JCC_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/loaders.c b/loaders.c
new file mode 100644 (file)
index 0000000..71ff3fa
--- /dev/null
+++ b/loaders.c
@@ -0,0 +1,2254 @@
+const char loaders_rcs[] = "$Id: loaders.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/loaders.c,v $
+ *
+ * Purpose     :  Functions to load and unload the various
+ *                configuration files.  Also contains code to manage
+ *                the list of active loaders, and to automatically 
+ *                unload files that are no longer in use.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: loaders.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include "project.h"
+#include "loaders.h"
+#include "encode.h"
+#include "filters.h"
+#include "parsers.h"
+#include "jcc.h"
+#include "ssplit.h"
+#include "miscutil.h"
+#include "errlog.h"
+#include "gateway.h"
+
+#ifndef SPLIT_PROXY_ARGS
+/* For strsav */
+#include "showargs.h"
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+const char loaders_h_rcs[] = LOADERS_H_VERSION;
+
+/* Fix a problem with Solaris.  There should be no effect on other
+ * platforms.
+ * Solaris's isspace() is a macro which uses it's argument directly
+ * as an array index.  Therefore we need to make sure that high-bit
+ * characters generate +ve values, and ideally we also want to make
+ * the argument match the declared parameter type of "int".
+ */
+#define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
+
+
+#define NLOADERS 8
+static int (*loaders[NLOADERS])(struct client_state *);
+
+
+/*
+ * Currently active files.
+ * These are also entered in the main linked list of files.
+ */
+static struct file_list *current_blockfile      = NULL;
+static struct file_list *current_cookiefile     = NULL;
+static struct file_list *current_forwardfile    = NULL;
+
+#ifdef ACL_FILES
+static struct file_list *current_aclfile        = NULL;
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+static struct file_list *current_imagefile      = NULL;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+static struct file_list * current_popupfile     = NULL;
+#endif /* def KILLPOPUPS */
+
+#ifdef TRUST_FILES
+static struct file_list *current_trustfile      = NULL;
+#endif /* def TRUST_FILES */
+
+#ifdef PCRS
+static struct file_list *current_re_filterfile  = NULL;
+#endif /* def PCRS */
+
+
+/*********************************************************************
+ *
+ * Function    :  sweep
+ *
+ * Description :  Basically a mark and sweep garbage collector, it is run
+ *                (by the parent thread) every once in a while to reclaim memory.
+ *
+ * It uses a mark and sweep strategy:
+ *   1) mark all files as inactive
+ *
+ *   2) check with each client:
+ *       if it is active,   mark its files as active
+ *       if it is inactive, free its resources
+ *
+ *   3) free the resources of all of the files that
+ *      are still marked as inactive (and are obsolete).
+ *
+ *   N.B. files that are not obsolete don't have an unloader defined.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void sweep(void)
+{
+   struct file_list *fl, *nfl;
+   struct client_state *csp, *ncsp;
+
+   /* clear all of the file's active flags */
+   for ( fl = files->next; NULL != fl; fl = fl->next )
+   {
+      fl->active = 0;
+   }
+
+   for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
+   {
+      if (ncsp->active)
+      {
+         /* mark this client's files as active */
+
+         if (ncsp->blist)     /* block files */
+         {
+            ncsp->blist->active = 1;
+         }
+
+         if (ncsp->clist)     /* cookie files */
+         {
+            ncsp->clist->active = 1;
+         }
+
+         /* FIXME: These were left out of the "10" release.  Should they be here? */
+         if (ncsp->flist)     /* forward files */
+         {
+            ncsp->flist->active = 1;
+         }
+
+#ifdef ACL_FILES
+         if (ncsp->alist)     /* acl files */
+         {
+            ncsp->alist->active = 1;
+         }
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+         if (ncsp->ilist)     /* image files */
+         {
+            ncsp->ilist->active = 1;
+         }
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+         if (ncsp->plist)     /* killpopup files */
+         {
+            ncsp->plist->active = 1;
+         }
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+         if (ncsp->rlist)     /* perl re files */
+         {
+            ncsp->rlist->active = 1;
+         }
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+         if (ncsp->tlist)     /* trust files */
+         {
+            ncsp->tlist->active = 1;
+         }
+#endif /* def TRUST_FILES */
+
+      }
+      else
+      {
+         /* this client one is not active, release its resources */
+         csp->next = ncsp->next;
+
+         freez(ncsp->ip_addr_str);
+         freez(ncsp->referrer);
+         freez(ncsp->x_forwarded);
+         freez(ncsp->ip_addr_str);
+         freez(ncsp->iob->buf);
+
+         free_http_request(ncsp->http);
+
+         destroy_list(ncsp->headers);
+         destroy_list(ncsp->cookie_list);
+
+#ifdef STATISTICS
+         urls_read++;
+         if (ncsp->rejected)
+         {
+            urls_rejected++;
+         }
+#endif /* def STATISTICS */
+
+         freez(ncsp);
+      }
+   }
+
+   for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
+   {
+      if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
+      {
+         fl->next = nfl->next;
+
+         (nfl->unloader)(nfl->f);
+
+#ifndef SPLIT_PROXY_ARGS
+         freez(nfl->proxy_args);
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+         freez(nfl->filename);
+
+         freez(nfl);
+      }
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  unload_url
+ *
+ * Description :  Called from the "unloaders".  Freez the url
+ *                structure elements.
+ *
+ * Parameters  :
+ *          1  :  url = pointer to a url_spec structure.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_url(struct url_spec *url)
+{
+   if (url == NULL) return;
+
+   freez(url->spec);
+   freez(url->domain);
+   freez(url->dbuf);
+   freez(url->dvec);
+   freez(url->path);
+#ifdef REGEX
+   if (url->preg)
+   {
+      regfree(url->preg);
+      freez(url->preg);
+   }
+#endif
+
+}
+
+
+#ifdef ACL_FILES
+/*********************************************************************
+ *
+ * Function    :  unload_aclfile
+ *
+ * Description :  Unloads an aclfile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the aclfile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_aclfile(void *f)
+{
+   struct access_control_list *b = (struct access_control_list *)f;
+   if (b == NULL) return;
+
+   unload_aclfile(b->next);
+
+   freez(b);
+
+}
+#endif /* def ACL_FILES */
+
+/*********************************************************************
+ *
+ * Function    :  unload_blockfile
+ *
+ * Description :  Unloads a blockfile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the blockfile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_blockfile(void *f)
+{
+   struct block_spec *b = (struct block_spec *)f;
+   if (b == NULL) return;
+
+   unload_blockfile(b->next);
+
+   unload_url(b->url);
+
+   freez(b);
+
+}
+
+
+#ifdef USE_IMAGE_LIST
+/*********************************************************************
+ *
+ * Function    :  unload_imagefile
+ *
+ * Description :  Unloads an imagefile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the imagefile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_imagefile(void *f)
+{
+   struct block_spec *b = (struct block_spec *)f;
+   if (b == NULL) return;
+
+   unload_imagefile(b->next);
+
+   unload_url(b->url);
+
+   freez(b);
+
+}
+#endif /* def USE_IMAGE_LIST */
+
+
+/*********************************************************************
+ *
+ * Function    :  unload_cookiefile
+ *
+ * Description :  Unloads a cookiefile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the cookiefile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_cookiefile(void *f)
+{
+   struct cookie_spec *b = (struct cookie_spec *)f;
+   if (b == NULL) return;
+
+   unload_cookiefile(b->next);
+
+   unload_url(b->url);
+
+   freez(b);
+
+}
+
+
+#ifdef TRUST_FILES
+/*********************************************************************
+ *
+ * Function    :  unload_trustfile
+ *
+ * Description :  Unloads a trustfile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the trustfile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_trustfile(void *f)
+{
+   struct block_spec *b = (struct block_spec *)f;
+   if (b == NULL) return;
+
+   unload_trustfile(b->next);
+
+   unload_url(b->url);
+
+   freez(b);
+
+}
+#endif /* def TRUST_FILES */
+
+
+/*********************************************************************
+ *
+ * Function    :  unload_forwardfile
+ *
+ * Description :  Unloads a forwardfile.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the forwardfile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_forwardfile(void *f)
+{
+   struct forward_spec *b = (struct forward_spec *)f;
+   if (b == NULL) return;
+
+   unload_forwardfile(b->next);
+
+   unload_url(b->url);
+
+   freez(b->gw->gateway_host);
+   freez(b->gw->forward_host);
+
+   freez(b);
+
+}
+
+
+#ifdef PCRS
+/*********************************************************************
+ *
+ * Function    :  unload_re_filterfile
+ *
+ * Description :  Unload the re_filter list.
+ *
+ * Parameters  :
+ *          1  :  f = the data structure associated with the filterfile.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_re_filterfile(void *f)
+{
+   pcrs_job *joblist;
+   struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
+
+   if (b == NULL) return;
+
+   destroy_list(b->patterns);
+
+   joblist = b->joblist;
+   while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
+
+   freez(b);
+
+}
+#endif /* def PCRS */
+
+
+#ifdef KILLPOPUPS
+/*********************************************************************
+ *
+ * Function    :  unload_popupfile
+ *
+ * Description :  Free the lists of blocked, and allowed popup sites.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void unload_popupfile(void * b)
+{
+   struct popup_settings * data = (struct popup_settings *) b;
+   struct popup_blocklist * cur = NULL;
+   struct popup_blocklist * temp= NULL;
+
+   /* Free the blocked list. */
+   cur = data->blocked;
+   while (cur != NULL)
+   {
+      temp = cur->next;
+      freez (cur->host_name);
+      free  (cur);
+      cur  = temp;
+   }
+   data->blocked = NULL;
+
+   /* Free the allowed list. */
+   cur = data->allowed;
+   while (cur != NULL)
+   {
+      temp = cur->next;
+      freez (cur->host_name);
+      free  (cur);
+      cur  = temp;
+   }
+   data->allowed = NULL;
+
+}
+#endif /* def KILLPOPUPS */
+
+
+/*********************************************************************
+ *
+ * Function    :  check_file_changed
+ *
+ * Description :  Helper function to check if a file needs reloading.
+ *                If "current" is still current, return it.  Otherwise
+ *                allocates a new (zeroed) "struct file_list", fills 
+ *                in the disk file name and timestamp, and returns it.
+ *
+ * Parameters  :
+ *          1  :  current = The file_list currently being used - will
+ *                          be checked to see if it is out of date. 
+ *                          May be NULL (which is treated as out of
+ *                          date).
+ *          2  :  filename = Name of file to check.
+ *          3  :  newfl    = New file list. [Output only]
+ *                           This will be set to NULL, OR a struct
+ *                           file_list newly allocated on the
+ *                           heap, with the filename and lastmodified
+ *                           fields filled, standard header giving file
+ *                           name in proxy_args, and all others zeroed.
+ *                           (proxy_args is only filled in if
+ *                           SPLIT_PROXY_ARGS and !suppress_blocklists).
+ *
+ * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
+ *                If file changed: 1 and sets newfl != NULL
+ *                On error: 1 and sets newfl == NULL
+ *
+ *********************************************************************/
+static int check_file_changed(const struct file_list * current,
+                              const char * filename,
+                              struct file_list ** newfl)
+{
+   struct file_list *fs;
+   struct stat statbuf[1];
+
+   *newfl = NULL;
+
+   if (stat(filename, statbuf) < 0)
+   {
+      /* Error, probably file not found. */
+      return 1;
+   }
+
+   if (current
+       && (current->lastmodified == statbuf->st_mtime)
+       && (0 == strcmp(current->filename, filename)))
+   {
+      return 0;
+   }
+
+   fs = (struct file_list *)zalloc(sizeof(struct file_list));
+
+   if (fs == NULL)
+   {
+      /* Out of memory error */
+      return 1;
+   }
+
+   fs->filename = strdup(filename);
+   fs->lastmodified = statbuf->st_mtime;
+
+   if (fs->filename == NULL)
+   {
+      /* Out of memory error */
+      freez (fs);
+      return 1;
+   }
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      char * p = html_encode(filename);
+      if (p)
+      {
+         fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");\r
+         fs->proxy_args = strsav(fs->proxy_args, p);\r
+         fs->proxy_args = strsav(fs->proxy_args, \r
+            "' contains the following patterns</h2>\n");\r
+         freez(p);\r
+      }
+      fs->proxy_args = strsav(fs->proxy_args, "<pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   *newfl = fs;
+   return 1;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  read_config_line
+ *
+ * Description :  Read a single non-empty line from a file and return
+ *                it.  Trims comments, leading and trailing whitespace.
+ *                Also wites the file to fs->proxy_args.
+ *
+ * Parameters  :
+ *          1  :  buf = Buffer to use.
+ *          2  :  buflen = Size of buffer in bytes.
+ *          3  :  fp = File to read from
+ *          4  :  fs = File will be written to fs->proxy_args.  May
+ *                be NULL to disable this feature.
+ *
+ * Returns     :  NULL on EOF or error
+ *                Otherwise, returns buf.
+ *
+ *********************************************************************/
+char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
+{
+   char *p, *q;
+   char linebuf[BUFSIZ];
+
+   while (fgets(linebuf, sizeof(linebuf), fp))
+   {
+#ifndef SPLIT_PROXY_ARGS
+      if (fs && !suppress_blocklists)
+      {
+         char *html_line = html_encode(linebuf);
+         if (html_line != NULL)
+         {
+            fs->proxy_args = strsav(fs->proxy_args, html_line);
+            freez(html_line);
+         }
+         fs->proxy_args = strsav(fs->proxy_args, "<br>");
+      }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+      /* Trim off newline and any comment */
+      if ((p = strpbrk(linebuf, "\r\n#")) != NULL)
+      {
+         *p = '\0';
+      }
+      
+      /* Trim leading whitespace */
+      p = linebuf;
+      while (*p && ijb_isspace(*p))
+      {
+         *p++;
+      }
+
+      if (*p)
+      {
+         /* There is something other than whitespace on the line. */
+
+         /* Move the data to the start of buf */
+         if (p != linebuf)
+         {
+            /* strcpy that can cope with overlap. */
+            q = linebuf;
+            while ((*q++ = *p++) != '\0')
+            {
+               /* Do nothing */
+            }
+         }
+
+         /* Trim trailing whitespace */
+         p = linebuf + strlen(linebuf) - 1;
+
+         /*
+          * Note: the (p >= retval) below is paranoia, it's not really needed.
+          * When p == retval then ijb_isspace(*p) will be false and we'll drop
+          * out of the loop.
+          */
+         while ((p >= linebuf) && ijb_isspace(*p))
+         {
+            p--;
+         }
+         p[1] = '\0';
+
+         /* More paranoia.  This if statement is always true. */
+         if (*linebuf)
+         {
+            strcpy(buf, linebuf);
+            return buf;
+         }
+      }
+   }
+
+   /* EOF */
+   return NULL;
+}
+
+
+#ifdef ACL_FILES
+/*********************************************************************
+ *
+ * Function    :  load_aclfile
+ *
+ * Description :  Read and parse an aclfile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_aclfile(struct client_state *csp)
+{
+   FILE *fp;
+   char buf[BUFSIZ], *v[3], *p;
+   int i;
+   struct access_control_list *a, *bl;
+   struct file_list *fs;
+
+   if (!check_file_changed(current_aclfile, aclfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->alist = current_aclfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_aclfile_error;
+   }
+
+   fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      freez(fs->filename);
+      freez(fs);
+      goto load_aclfile_error;
+   }
+
+   fp = fopen(aclfile, "r");
+
+   if (fp == NULL)
+   {
+      goto load_aclfile_error;
+   }
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      i = ssplit(buf, " \t", v, SZ(v), 1, 1);
+
+      /* allocate a new node */
+      a = (struct access_control_list *) zalloc(sizeof(*a));
+
+      if (a == NULL)
+      {
+         fclose(fp);
+         freez(fs->f);
+         freez(fs->filename);
+         freez(fs);
+         goto load_aclfile_error;
+      }
+
+      /* add it to the list */
+      a->next  = bl->next;
+      bl->next = a;
+
+      switch (i)
+      {
+         case 3:
+            if (acl_addr(v[2], a->dst) < 0)
+            {
+               goto load_aclfile_error;
+            }
+            /* no break */
+
+         case 2:
+            if (acl_addr(v[1], a->src) < 0)
+            {
+               goto load_aclfile_error;
+            }
+
+            p = v[0];
+            if (strcmpic(p, "permit") == 0)
+            {
+               a->action = ACL_PERMIT;
+               break;
+            }
+
+            if (strcmpic(p, "deny") == 0)
+            {
+               a->action = ACL_DENY;
+               break;
+            }
+            /* no break */
+
+         default:
+            goto load_aclfile_error;
+      }
+   }
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   if (current_aclfile)
+   {
+      current_aclfile->unloader = unload_aclfile;
+   }
+
+   fs->next = files->next;
+   files->next = fs;
+   current_aclfile = fs;
+
+   if (csp)
+   {
+      csp->alist = fs;
+   }
+
+   return(0);
+
+load_aclfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load access control list %s: %E", aclfile);
+   return(-1);
+
+}
+#endif /* def ACL_FILES */
+
+
+/*********************************************************************
+ *
+ * Function    :  load_blockfile
+ *
+ * Description :  Read and parse a blockfile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_blockfile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct block_spec *b, *bl;
+   char  buf[BUFSIZ], *p, *q;
+   int port, reject;
+   struct file_list *fs;
+   struct url_spec url[1];
+
+   if (!check_file_changed(current_blockfile, blockfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->blist = current_blockfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_blockfile_error;
+   }
+
+   fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      goto load_blockfile_error;
+   }
+
+   if ((fp = fopen(blockfile, "r")) == NULL)
+   {
+      goto load_blockfile_error;
+   }
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      reject = 1;
+
+      if (*buf == '~')
+      {
+         reject = 0;
+         p = buf;
+         q = p+1;
+         while ((*p++ = *q++))
+         {
+            /* nop */
+         }
+      }
+
+      /* skip lines containing only ~ */
+      if (*buf == '\0')
+      {
+         continue;
+      }
+
+      /* allocate a new node */
+      if (((b = zalloc(sizeof(*b))) == NULL)
+#ifdef REGEX
+          || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
+#endif
+      )
+      {
+         fclose(fp);
+         goto load_blockfile_error;
+      }
+
+      /* add it to the list */
+      b->next  = bl->next;
+      bl->next = b;
+
+      /* save a copy of the orignal specification */
+      if ((b->url->spec = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_blockfile_error;
+      }
+
+      b->reject = reject;
+
+      if ((p = strchr(buf, '/')))
+      {
+         b->url->path    = strdup(p);
+         b->url->pathlen = strlen(b->url->path);
+         *p = '\0';
+      }
+      else
+      {
+         b->url->path    = NULL;
+         b->url->pathlen = 0;
+      }
+#ifdef REGEX
+      if (b->url->path)
+      {
+         int errcode;
+         char rebuf[BUFSIZ];
+
+         sprintf(rebuf, "^(%s)", b->url->path);
+
+         errcode = regcomp(b->url->preg, rebuf,
+               (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+         if (errcode)
+         {
+            size_t errlen =
+               regerror(errcode,
+                  b->url->preg, buf, sizeof(buf));
+
+            buf[errlen] = '\0';
+
+            log_error(LOG_LEVEL_ERROR, "error compiling %s: %s\n",
+                    b->url->spec, buf);
+            fclose(fp);
+            goto load_blockfile_error;
+         }
+      }
+      else
+      {
+         freez(b->url->preg);
+      }
+#endif
+      if ((p = strchr(buf, ':')) == NULL)
+      {
+         port = 0;
+      }
+      else
+      {
+         *p++ = '\0';
+         port = atoi(p);
+      }
+
+      b->url->port = port;
+
+      if ((b->url->domain = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_blockfile_error;
+      }
+
+      /* split domain into components */
+      *url = dsplit(b->url->domain);
+      b->url->dbuf = url->dbuf;
+      b->url->dcnt = url->dcnt;
+      b->url->dvec = url->dvec;
+   }
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if (current_blockfile)
+   {
+      current_blockfile->unloader = unload_blockfile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_blockfile = fs;
+
+   if (csp)
+   {
+      csp->blist = fs;
+   }
+
+   return(0);
+
+load_blockfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load blockfile '%s': %E", blockfile);
+   return(-1);
+
+}
+
+
+#ifdef USE_IMAGE_LIST
+/*********************************************************************
+ *
+ * Function    :  load_imagefile
+ *
+ * Description :  Read and parse an imagefile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_imagefile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct block_spec *b, *bl;
+   char  buf[BUFSIZ], *p, *q;
+   int port, reject;
+   struct file_list *fs;
+   struct url_spec url[1];
+
+   if (!check_file_changed(current_imagefile, imagefile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->ilist = current_imagefile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_imagefile_error;
+   }
+
+   fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      goto load_imagefile_error;
+   }
+
+   if ((fp = fopen(imagefile, "r")) == NULL)
+   {
+      goto load_imagefile_error;
+   }
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      reject = 1;
+
+      if (*buf == '~')
+      {
+         reject = 0;
+         p = buf;
+         q = p+1;
+         while ((*p++ = *q++))
+         {
+            /* nop */
+         }
+      }
+
+      /* skip lines containing only ~ */
+      if (*buf == '\0')
+      {
+         continue;
+      }
+
+      /* allocate a new node */
+      if (((b = zalloc(sizeof(*b))) == NULL)
+#ifdef REGEX
+      || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
+#endif
+      )
+      {
+         fclose(fp);
+         goto load_imagefile_error;
+      }
+
+      /* add it to the list */
+      b->next  = bl->next;
+      bl->next = b;
+
+      /* save a copy of the orignal specification */
+      if ((b->url->spec = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_imagefile_error;
+      }
+
+      b->reject = reject;
+
+      if ((p = strchr(buf, '/')))
+      {
+         b->url->path    = strdup(p);
+         b->url->pathlen = strlen(b->url->path);
+         *p = '\0';
+      }
+      else
+      {
+         b->url->path    = NULL;
+         b->url->pathlen = 0;
+      }
+#ifdef REGEX
+      if (b->url->path)
+      {
+         int errcode;
+         char rebuf[BUFSIZ];
+
+         sprintf(rebuf, "^(%s)", b->url->path);
+
+         errcode = regcomp(b->url->preg, rebuf,
+               (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+         if (errcode)
+         {
+            size_t errlen =
+               regerror(errcode,
+                  b->url->preg, buf, sizeof(buf));
+
+            buf[errlen] = '\0';
+
+            log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
+                    b->url->spec, buf);
+            fclose(fp);
+            goto load_imagefile_error;
+         }
+      }
+      else
+      {
+         freez(b->url->preg);
+      }
+#endif
+      if ((p = strchr(buf, ':')) == NULL)
+      {
+         port = 0;
+      }
+      else
+      {
+         *p++ = '\0';
+         port = atoi(p);
+      }
+
+      b->url->port = port;
+
+      if ((b->url->domain = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_imagefile_error;
+      }
+
+      /* split domain into components */
+      *url = dsplit(b->url->domain);
+      b->url->dbuf = url->dbuf;
+      b->url->dcnt = url->dcnt;
+      b->url->dvec = url->dvec;
+   }
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if (current_imagefile)
+   {
+      current_imagefile->unloader = unload_imagefile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_imagefile = fs;
+
+   if (csp)
+   {
+      csp->ilist = fs;
+   }
+
+   return(0);
+
+load_imagefile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load imagefile '%s': %E", imagefile);
+   return(-1);
+
+}
+#endif /* def USE_IMAGE_LIST */
+
+
+/*********************************************************************
+ *
+ * Function    :  load_cookiefile
+ *
+ * Description :  Read and parse a cookiefile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_cookiefile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct cookie_spec *b, *bl;
+   char  buf[BUFSIZ], *p, *q;
+   int port, user_cookie, server_cookie;
+   struct file_list *fs;
+   struct url_spec url[1];
+
+   if (!check_file_changed(current_cookiefile, cookiefile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->clist = current_cookiefile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_cookie_error;
+   }
+
+   fs->f = bl = (struct cookie_spec   *)zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      goto load_cookie_error;
+   }
+
+   if ((fp = fopen(cookiefile, "r")) == NULL)
+   {
+      goto load_cookie_error;
+   }
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      p = buf;
+
+      switch ((int)*p)
+      {
+         case '>':
+            server_cookie = 0;
+            user_cookie   = 1;
+            p++;
+            break;
+
+         case '<':
+            server_cookie = 1;
+            user_cookie   = 0;
+            p++;
+            break;
+
+         case '~':
+            server_cookie = 0;
+            user_cookie   = 0;
+            p++;
+            break;
+
+         default:
+            server_cookie = 1;
+            user_cookie   = 1;
+            break;
+      }
+
+      /*
+       * Elide any of the "special" chars from the
+       * front of the pattern
+       */
+      q = buf;
+      if (p > q) while ((*q++ = *p++))
+      {
+         /* nop */
+      }
+
+      /* skip lines containing only "special" chars */
+      if (*buf == '\0')
+      {
+         continue;
+      }
+
+      /* allocate a new node */
+      if (((b = zalloc(sizeof(*b))) == NULL)
+#ifdef REGEX
+      || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
+#endif
+      )
+      {
+         fclose(fp);
+         goto load_cookie_error;
+      }
+
+      /* add it to the list */
+      b->next  = bl->next;
+      bl->next = b;
+
+      /* save a copy of the orignal specification */
+      if ((b->url->spec = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_cookie_error;
+      }
+
+      b->send_user_cookie     = user_cookie;
+      b->accept_server_cookie = server_cookie;
+
+      if ((p = strchr(buf, '/')))
+      {
+         b->url->path    = strdup(p);
+         b->url->pathlen = strlen(b->url->path);
+         *p = '\0';
+      }
+      else
+      {
+         b->url->path    = NULL;
+         b->url->pathlen = 0;
+      }
+#ifdef REGEX
+      if (b->url->path)
+      {
+         int errcode;
+         char rebuf[BUFSIZ];
+
+         sprintf(rebuf, "^(%s)", b->url->path);
+
+         errcode = regcomp(b->url->preg, rebuf,
+               (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+         if (errcode)
+         {
+            size_t errlen =
+               regerror(errcode,
+                  b->url->preg, buf, sizeof(buf));
+
+            buf[errlen] = '\0';
+
+            log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
+                    b->url->spec, buf);
+            fclose(fp);
+            goto load_cookie_error;
+         }
+      }
+      else
+      {
+         freez(b->url->preg);
+      }
+#endif
+      if ((p = strchr(buf, ':')) == NULL)
+      {
+         port = 0;
+      }
+      else
+      {
+         *p++ = '\0';
+         port = atoi(p);
+      }
+
+      b->url->port = port;
+
+      if ((b->url->domain = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_cookie_error;
+      }
+
+      /* split domain into components */
+
+      *url = dsplit(b->url->domain);
+      b->url->dbuf = url->dbuf;
+      b->url->dcnt = url->dcnt;
+      b->url->dvec = url->dvec;
+   }
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if (current_cookiefile)
+   {
+      current_cookiefile->unloader = unload_cookiefile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_cookiefile = fs;
+
+   if (csp)
+   {
+      csp->clist = fs;
+   }
+
+   return(0);
+
+load_cookie_error:
+   log_error(LOG_LEVEL_ERROR, "can't load cookiefile '%s': %E", cookiefile);
+   return(-1);
+
+}
+
+
+#ifdef TRUST_FILES
+/*********************************************************************
+ *
+ * Function    :  load_trustfile
+ *
+ * Description :  Read and parse a trustfile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_trustfile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct block_spec *b, *bl;
+   struct url_spec **tl;
+
+   char  buf[BUFSIZ], *p, *q;
+   int port, reject, trusted;
+   struct file_list *fs;
+   struct url_spec url[1];
+
+   if (!check_file_changed(current_trustfile, trustfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->tlist = current_trustfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_trustfile_error;
+   }
+
+   fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      goto load_trustfile_error;
+   }
+
+   if ((fp = fopen(trustfile, "r")) == NULL)
+   {
+      goto load_trustfile_error;
+   }
+
+   tl = trust_list;
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      trusted = 0;
+      reject  = 1;
+
+      if (*buf == '+')
+      {
+         trusted = 1;
+         *buf = '~';
+      }
+
+      if (*buf == '~')
+      {
+         reject = 0;
+         p = buf;
+         q = p+1;
+         while ((*p++ = *q++))
+         {
+            /* nop */
+         }
+      }
+
+      /* skip blank lines */
+      if (*buf == '\0')
+      {
+         continue;
+      }
+
+      /* allocate a new node */
+      if (((b = zalloc(sizeof(*b))) == NULL)
+#ifdef REGEX
+      || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
+#endif
+      )
+      {
+         fclose(fp);
+         goto load_trustfile_error;
+      }
+
+      /* add it to the list */
+      b->next  = bl->next;
+      bl->next = b;
+
+      /* save a copy of the orignal specification */
+      if ((b->url->spec = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_trustfile_error;
+      }
+
+      b->reject = reject;
+
+      if ((p = strchr(buf, '/')))
+      {
+         b->url->path    = strdup(p);
+         b->url->pathlen = strlen(b->url->path);
+         *p = '\0';
+      }
+      else
+      {
+         b->url->path    = NULL;
+         b->url->pathlen = 0;
+      }
+#ifdef REGEX
+      if (b->url->path)
+      {
+         int errcode;
+         char rebuf[BUFSIZ];
+
+         sprintf(rebuf, "^(%s)", b->url->path);
+
+         errcode = regcomp(b->url->preg, rebuf,
+               (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+         if (errcode)
+         {
+            size_t errlen =
+               regerror(errcode,
+                  b->url->preg, buf, sizeof(buf));
+
+            buf[errlen] = '\0';
+
+            log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
+                    b->url->spec, buf);
+            fclose(fp);
+            goto load_trustfile_error;
+         }
+      }
+      else
+      {
+         freez(b->url->preg);
+      }
+#endif
+      if ((p = strchr(buf, ':')) == NULL)
+      {
+         port = 0;
+      }
+      else
+      {
+         *p++ = '\0';
+         port = atoi(p);
+      }
+
+      b->url->port = port;
+
+      if ((b->url->domain = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_trustfile_error;
+      }
+
+      /* split domain into components */
+      *url = dsplit(b->url->domain);
+      b->url->dbuf = url->dbuf;
+      b->url->dcnt = url->dcnt;
+      b->url->dvec = url->dvec;
+
+      /*
+       * save a pointer to URL's spec in the list of trusted URL's, too
+       */
+      if (trusted)
+      {
+         *tl++ = b->url;
+      }
+   }
+
+   *tl = NULL;
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if (current_trustfile)
+   {
+      current_trustfile->unloader = unload_trustfile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_trustfile = fs;
+
+   if (csp)
+   {
+      csp->tlist = fs;
+   }
+
+   return(0);
+
+load_trustfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load trustfile '%s': %E", trustfile);
+   return(-1);
+
+}
+#endif /* def TRUST_FILES */
+
+
+/*********************************************************************
+ *
+ * Function    :  load_forwardfile
+ *
+ * Description :  Read and parse a forwardfile and add to files list.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_forwardfile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct forward_spec *b, *bl;
+   char  buf[BUFSIZ], *p, *q, *tmp;
+   char  *vec[4];
+   int port, n, reject;
+   struct file_list *fs;
+   const struct gateway *gw;
+   struct url_spec url[1];
+
+   if (!check_file_changed(current_forwardfile, forwardfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->flist = current_forwardfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_forwardfile_error;
+   }
+
+   fs->f = bl = (struct forward_spec  *)zalloc(sizeof(*bl));
+
+   if ((fs == NULL) || (bl == NULL))
+   {
+      goto load_forwardfile_error;
+   }
+
+   if ((fp = fopen(forwardfile, "r")) == NULL)
+   {
+      goto load_forwardfile_error;
+   }
+
+   tmp = NULL;
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      freez(tmp);
+
+      tmp = strdup(buf);
+
+      n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
+
+      if (n != 4)
+      {
+         log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
+         continue;
+      }
+
+      strcpy(buf, vec[0]);
+
+      reject = 1;
+
+      if (*buf == '~')
+      {
+         reject = 0;
+         p = buf;
+         q = p+1;
+         while ((*p++ = *q++))
+         {
+            /* nop */
+         }
+      }
+
+      /* skip lines containing only ~ */
+      if (*buf == '\0')
+      {
+         continue;
+      }
+
+      /* allocate a new node */
+      if (((b = zalloc(sizeof(*b))) == NULL)
+#ifdef REGEX
+      || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
+#endif
+      )
+      {
+         fclose(fp);
+         goto load_forwardfile_error;
+      }
+
+      /* add it to the list */
+      b->next  = bl->next;
+      bl->next = b;
+
+      /* save a copy of the orignal specification */
+      if ((b->url->spec = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_forwardfile_error;
+      }
+
+      b->reject = reject;
+
+      if ((p = strchr(buf, '/')))
+      {
+         b->url->path    = strdup(p);
+         b->url->pathlen = strlen(b->url->path);
+         *p = '\0';
+      }
+      else
+      {
+         b->url->path    = NULL;
+         b->url->pathlen = 0;
+      }
+#ifdef REGEX
+      if (b->url->path)
+      {
+         int errcode;
+         char rebuf[BUFSIZ];
+
+         sprintf(rebuf, "^(%s)", b->url->path);
+
+         errcode = regcomp(b->url->preg, rebuf,
+               (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+         if (errcode)
+         {
+            size_t errlen = regerror(errcode, b->url->preg, buf, sizeof(buf));
+
+            buf[errlen] = '\0';
+
+            log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
+                    b->url->spec, buf);
+            fclose(fp);
+            goto load_forwardfile_error;
+         }
+      }
+      else
+      {
+         freez(b->url->preg);
+      }
+#endif
+      if ((p = strchr(buf, ':')) == NULL)
+      {
+         port = 0;
+      }
+      else
+      {
+         *p++ = '\0';
+         port = atoi(p);
+      }
+
+      b->url->port = port;
+
+      if ((b->url->domain = strdup(buf)) == NULL)
+      {
+         fclose(fp);
+         goto load_forwardfile_error;
+      }
+
+      /* split domain into components */
+      *url = dsplit(b->url->domain);
+      b->url->dbuf = url->dbuf;
+      b->url->dcnt = url->dcnt;
+      b->url->dvec = url->dvec;
+
+      /* now parse the gateway specs */
+
+      p = vec[2];
+
+      for (gw = gateways; gw->name; gw++)
+      {
+         if (strcmp(gw->name, p) == 0)
+         {
+            break;
+         }
+      }
+
+      if (gw->name == NULL)
+      {
+         goto load_forwardfile_error;
+      }
+
+      /* save this as the gateway type */
+      *b->gw = *gw;
+
+      /* now parse the gateway host[:port] spec */
+      p = vec[3];
+
+      if (strcmp(p, ".") != 0)
+      {
+         b->gw->gateway_host = strdup(p);
+
+         if ((p = strchr(b->gw->gateway_host, ':')))
+         {
+            *p++ = '\0';
+            b->gw->gateway_port = atoi(p);
+         }
+
+         if (b->gw->gateway_port <= 0)
+         {
+            goto load_forwardfile_error;
+         }
+      }
+
+      /* now parse the forwarding spec */
+      p = vec[1];
+
+      if (strcmp(p, ".") != 0)
+      {
+         b->gw->forward_host = strdup(p);
+
+         if ((p = strchr(b->gw->forward_host, ':')))
+         {
+            *p++ = '\0';
+            b->gw->forward_port = atoi(p);
+         }
+
+         if (b->gw->forward_port <= 0)
+         {
+            b->gw->forward_port = 8000;
+         }
+      }
+   }
+
+   freez(tmp);
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if (current_forwardfile)
+   {
+      current_forwardfile->unloader = unload_forwardfile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_forwardfile = fs;
+
+   if (csp)
+   {
+      csp->flist = fs;
+   }
+
+   return(0);
+
+load_forwardfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load forwardfile '%s': %E", forwardfile);
+   return(-1);
+
+}
+
+
+#ifdef PCRS
+/*********************************************************************
+ *
+ * Function    :  load_re_filterfile
+ *
+ * Description :  Load the re_filterfile. Each non-comment, non-empty
+ *                line is instantly added to the joblist, which is
+ *                a chained list of pcrs_job structs.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_re_filterfile(struct client_state *csp)
+{
+   FILE *fp;
+
+   struct re_filterfile_spec *bl;
+   struct file_list *fs;
+
+   char  buf[BUFSIZ];
+   int error;
+   pcrs_job *dummy;
+
+#ifndef SPLIT_PROXY_ARGS
+   char *p;
+#endif /* ndef SPLIT_PROXY_ARGS */
+   if (!check_file_changed(current_re_filterfile, re_filterfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->rlist = current_re_filterfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_re_filterfile_error;
+   }
+
+   fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
+   if (bl == NULL)
+   {
+      goto load_re_filterfile_error;
+   }
+
+   /* Open the file or fail */
+   if ((fp = fopen(re_filterfile, "r")) == NULL)
+   {
+      goto load_re_filterfile_error;
+   }
+
+   /* Read line by line */
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      enlist( bl->patterns, buf );
+
+      /* We have a meaningful line -> make it a job */
+      if ((dummy = pcrs_make_job(buf, &error)) == NULL)
+      {
+         log_error(LOG_LEVEL_REF, 
+               "Adding re_filter job %s failed with error %d.", buf, error);
+         continue;
+      }
+      else
+      {
+         dummy->next = bl->joblist;
+         bl->joblist = dummy;
+         log_error(LOG_LEVEL_REF, "Adding re_filter job %s succeeded.", buf);
+      }
+   }
+
+   fclose(fp);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if ( NULL != current_re_filterfile )
+   {
+      current_re_filterfile->unloader = unload_re_filterfile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_re_filterfile = fs;
+
+   if (csp)
+   {
+      csp->rlist = fs;
+   }
+
+   return( 0 );
+
+load_re_filterfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load re_filterfile '%s': %E", re_filterfile);
+   return(-1);
+
+}
+#endif /* def PCRS */
+
+
+#ifdef KILLPOPUPS
+/*********************************************************************
+ *
+ * Function    :  load_popupfile
+ *
+ * Description :  Load, and parse the popup blocklist.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => success, else there was an error.
+ *
+ *********************************************************************/
+int load_popupfile(struct client_state *csp)
+{
+   FILE *fp;
+   char  buf[BUFSIZ], *p, *q;
+   struct popup_blocklist *entry = NULL;
+   struct popup_settings * data;
+   struct file_list *fs;
+   p = buf;
+   q = buf;
+
+   if (!check_file_changed(current_popupfile, popupfile, &fs))
+   {
+      /* No need to load */
+      if (csp)
+      {
+         csp->plist = current_popupfile;
+      }
+      return(0);
+   }
+   if (!fs)
+   {
+      goto load_popupfile_error;
+   }
+
+   fs->f = data = (struct popup_settings  *)zalloc(sizeof(*data));
+   if (data == NULL)
+   {
+      goto load_popupfile_error;
+   }
+
+   if ((fp = fopen(popupfile, "r")) == NULL)
+   {
+      goto load_popupfile_error;
+   }
+
+   while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
+   {
+      entry = (struct popup_blocklist*)zalloc(sizeof(struct popup_blocklist));
+      if (!entry)
+      {
+         fclose( fp );
+         goto load_popupfile_error;
+      }
+
+      /* Handle allowed hosts. */
+      if ( *buf == '~' )
+      {
+         /* Rememeber: skip the tilde */
+         entry->host_name = strdup( buf + 1 );
+         if (!entry->host_name)
+         {
+            fclose( fp );
+            goto load_popupfile_error;
+         }
+
+         entry->next = data->allowed;
+         data->allowed = entry;
+      }
+      else
+      {
+         /* Blocked host */
+         entry->host_name = strdup( buf );
+         if (!entry->host_name)
+         {
+            fclose( fp );
+            goto load_popupfile_error;
+         }
+
+         entry->next = data->blocked;
+         data->blocked = entry;
+      }
+   }
+
+   fclose( fp );
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* the old one is now obsolete */
+   if ( NULL != current_popupfile )
+   {
+      current_popupfile->unloader = unload_popupfile;
+   }
+
+   fs->next    = files->next;
+   files->next = fs;
+   current_popupfile = fs;
+
+   if (csp)
+   {
+      csp->plist = fs;
+   }
+
+   return( 0 );
+
+load_popupfile_error:
+   log_error(LOG_LEVEL_ERROR, "can't load popupfile '%s': %E", popupfile);
+   return(-1);
+
+}
+#endif /* def KILLPOPUPS */
+
+
+
+/*********************************************************************
+ *
+ * Function    :  add_loader
+ *
+ * Description :  Called from `load_config'.  Called once for each input
+ *                file found in config.
+ *
+ * Parameters  :
+ *          1  :  loader = pointer to a function that can parse and load
+ *                the appropriate config file.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void add_loader(int (*loader)(struct client_state *))
+{
+   int i;
+
+   for (i=0; i < NLOADERS; i++)
+   {
+      if (loaders[i] == NULL)
+      {
+         loaders[i] = loader;
+         break;
+      }
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  run_loader
+ *
+ * Description :  Called from `load_config' and `listen_loop'.  This
+ *                function keeps the "csp" current with any file mods
+ *                since the last loop.  If a file is unchanged, the
+ *                loader functions do NOT reload the file.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int run_loader(struct client_state *csp)
+{
+   int ret = 0;
+   int i;
+
+   for (i=0; i < NLOADERS; i++)
+   {
+      if (loaders[i] == NULL)
+      {
+         break;
+      }
+      ret |= (loaders[i])(csp);
+   }
+   return(ret);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  remove_all_loaders
+ *
+ * Description :  Remove all loaders from the list.
+ *
+ * Parameters  :  N/A
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void remove_all_loaders(void)
+{
+   memset( loaders, 0, sizeof( loaders ) );
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/loaders.h b/loaders.h
new file mode 100644 (file)
index 0000000..0551a6e
--- /dev/null
+++ b/loaders.h
@@ -0,0 +1,103 @@
+#ifndef _LOADERS_H
+#define _LOADERS_H
+#define LOADERS_H_VERSION "$Id: loaders.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/loaders.h,v $
+ *
+ * Purpose     :  Functions to load and unload the various
+ *                configuration files.  Also contains code to manage
+ *                the list of active loaders, and to automatically 
+ *                unload files that are no longer in use.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: loaders.h,v $
+ *
+ *********************************************************************/
+\f
+
+#include "project.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void sweep(void);
+extern char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs);
+
+extern int load_blockfile(struct client_state *csp);
+extern int load_cookiefile(struct client_state *csp);
+extern int load_forwardfile(struct client_state *csp);
+  
+#ifdef ACL_FILES
+extern int load_aclfile(struct client_state *csp);
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+extern int load_imagefile(struct client_state *csp);
+#endif /* def USE_IMAGE_LIST */
+#ifdef KILLPOPUPS
+extern int load_popupfile(struct client_state *csp);
+#endif /* def KILLPOPUPS */
+
+#ifdef TRUST_FILES
+extern int load_trustfile(struct client_state *csp);
+#endif /* def TRUST_FILES */
+
+#ifdef PCRS
+extern int load_re_filterfile(struct client_state *csp);
+#endif /* def PCRS */
+
+extern void add_loader(int (*loader)(struct client_state *));
+extern int run_loader(struct client_state *csp);
+extern void remove_all_loaders(void);
+
+#ifdef PCRS
+extern int load_re_filterfile(struct client_state *csp);
+#endif /* def PCRS */
+
+#ifdef KILLPOPUPS
+extern int load_popupfile(struct client_state *csp);
+#endif /* def KILLPOPUPS */
+
+/* Revision control strings from this header and associated .c file */
+extern const char loaders_rcs[];
+extern const char loaders_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _LOADERS_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/miscutil.c b/miscutil.c
new file mode 100644 (file)
index 0000000..1257a99
--- /dev/null
@@ -0,0 +1,252 @@
+const char miscutil_rcs[] = "$Id: miscutil.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/miscutil.c,v $
+ *
+ * Purpose     :  zalloc, hash_string, safe_strerror, strcmpic,
+ *                strncmpic, and MinGW32 strdup functions.  These are
+ *                each too small to deserve their own file but don't 
+ *                really fit in any other file.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: miscutil.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#include "miscutil.h"
+
+const char miscutil_h_rcs[] = MISCUTIL_H_VERSION;
+
+/* Fix a problem with Solaris.  There should be no effect on other
+ * platforms.
+ * Solaris's isspace() is a macro which uses it's argument directly
+ * as an array index.  Therefore we need to make sure that high-bit
+ * characters generate +ve values, and ideally we also want to make
+ * the argument match the declared parameter type of "int".
+ */
+#define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
+
+/*********************************************************************
+ *
+ * Function    :  zalloc
+ *
+ * Description :  Malloc some memory and set it to '\0'.
+ *                The way calloc() ought to be -acjc
+ *
+ * Parameters  :
+ *          1  :  size = Size of memory chunk to return.
+ *
+ * Returns     :  Pointer to newly malloc'd memory chunk.
+ *
+ *********************************************************************/
+void *zalloc(int size)
+{
+   void * ret;
+
+   if ((ret = (void *)malloc(size)) != NULL)
+   {
+      memset(ret, 0, size);
+   }
+
+   return(ret);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  hash_string
+ *
+ * Description :  Take a string and compute a (hopefuly) unique numeric
+ *                integer value.  This has several uses, but being able
+ *                to "switch" a string the one of my favorites.
+ *
+ * Parameters  :
+ *          1  :  s : string to be hashed.
+ *
+ * Returns     :  an unsigned long variable with the hashed value.
+ *
+ *********************************************************************/
+unsigned long hash_string( const char* s )
+{
+   unsigned long h = 0ul; 
+
+   for ( ; *s; ++s )
+   {
+      h = 5 * h + *s;
+   }
+
+   return (h);
+
+}
+
+
+#ifdef __MINGW32__
+/*********************************************************************
+ *
+ * Function    :  strdup
+ *
+ * Description :  For some reason (which is beyond me), gcc and WIN32
+ *                don't like strdup.  When a "free" is executed on a
+ *                strdup'd ptr, it can at times freez up!  So I just
+ *                replaced it and problem was solved.
+ *
+ * Parameters  :
+ *          1  :  s = string to duplicate
+ *
+ * Returns     :  Pointer to newly malloc'ed copy of the string.
+ *
+ *********************************************************************/
+char *strdup( const char *s )
+{
+   char * result = (char *)malloc( strlen(s)+1 );
+
+   if (result != NULL)
+   {
+      strcpy( result, s );
+   }
+
+   return( result );
+}
+
+#endif /* def __MINGW32__ */
+
+
+
+/*********************************************************************
+ *
+ * Function    :  safe_strerror
+ *
+ * Description :  Variant of the library routine strerror() which will
+ *                work on systems without the library routine, and
+ *                which should never return NULL.
+ *
+ * Parameters  :
+ *          1  :  err = the `errno' of the last operation.
+ *
+ * Returns     :  An "English" string of the last `errno'.  Allocated
+ *                with strdup(), so caller frees.  May be NULL if the
+ *                system is out of memory.
+ *
+ *********************************************************************/
+char *safe_strerror(int err)
+{
+   char *s = NULL;
+   char buf[BUFSIZ];
+
+
+#ifndef NOSTRERROR
+   s = strerror(err);
+#endif /* NOSTRERROR */
+
+   if (s == NULL)
+   {
+      sprintf(buf, "(errno = %d)", err);
+      s = buf;
+   }
+
+   return(strdup(s));
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  strcmpic
+ *
+ * Description :  Case insensitive string comparison
+ *
+ * Parameters  :
+ *          1  :  s1 = string 1 to compare
+ *          2  :  s2 = string 2 to compare
+ *
+ * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
+ *
+ *********************************************************************/
+int strcmpic(char *s1, char *s2)
+{
+   while (*s1 && *s2)
+   {
+      if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
+      {
+         break;
+      }
+      s1++, s2++;
+   }
+   return(ijb_tolower(*s1) - ijb_tolower(*s2));
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  strncmpic
+ *
+ * Description :  Case insensitive string comparison (upto n characters)
+ *
+ * Parameters  :
+ *          1  :  s1 = string 1 to compare
+ *          2  :  s2 = string 2 to compare
+ *          3  :  n = maximum characters to compare
+ *
+ * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
+ *
+ *********************************************************************/
+int strncmpic(char *s1, char *s2, size_t n)
+{
+   if (n <= 0) return(0);
+
+   while (*s1 && *s2)
+   {
+      if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
+      {
+         break;
+      }
+
+      if (--n <= 0) break;
+
+      s1++, s2++;
+   }
+   return(ijb_tolower(*s1) - ijb_tolower(*s2));
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/miscutil.h b/miscutil.h
new file mode 100644 (file)
index 0000000..0a6b95e
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _MISCUTIL_H
+#define _MISCUTIL_H
+#define MISCUTIL_H_VERSION "$Id: miscutil.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/miscutil.h,v $
+ *
+ * Purpose     :  zalloc, hash_string, safe_strerror, strcmpic,
+ *                strncmpic, and MinGW32 strdup functions.  These are
+ *                each too small to deserve their own file but don't 
+ *                really fit in any other file.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: miscutil.h,v $
+ *
+ *********************************************************************/
+\f
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern void *zalloc(int size);
+
+extern unsigned long hash_string(const char* s);
+
+extern char *safe_strerror(int err);
+
+extern int strcmpic(char *s1, char *s2);
+extern int strncmpic(char *s1, char *s2, size_t n);
+
+#ifdef __MINGW32__
+extern char *strdup(const char *s);
+#endif /* def __MINGW32__ */
+
+/* Revision control strings from this header and associated .c file */
+extern const char miscutil_rcs[];
+extern const char miscutil_h_rcs[];
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* ndef _MISCUTIL_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/parsers.c b/parsers.c
new file mode 100644 (file)
index 0000000..f56c0b7
--- /dev/null
+++ b/parsers.c
@@ -0,0 +1,1298 @@
+const char parsers_rcs[] = "$Id: parsers.c,v 1.1 2001/05/13 21:57:06 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/parsers.c,v $
+ *
+ * Purpose     :  Declares functions to parse/crunch headers and pages.
+ *                Functions declared include:
+ *                   `add_to_iob', `client_cookie_adder', `client_from',
+ *                   `client_referrer', `client_send_cookie', `client_ua',
+ *                   `client_uagent', `client_x_forwarded',
+ *                   `client_x_forwarded_adder', `client_xtra_adder',
+ *                   `content_type', `crumble', `destroy_list', `enlist',
+ *                   `flush_socket', `free_http_request', `get_header',
+ *                   `list_to_text', `match', `parse_http_request', `sed',
+ *                   and `server_set_cookie'.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: parsers.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include "project.h"
+#include "parsers.h"
+#include "encode.h"
+#include "filters.h"
+#include "loaders.h"
+#include "showargs.h"
+#include "jcc.h"
+#include "ssplit.h"
+#include "errlog.h"
+#include "jbsockets.h"
+#include "miscutil.h"
+
+const char parsers_h_rcs[] = PARSERS_H_VERSION;
+
+/* Fix a problem with Solaris.  There should be no effect on other
+ * platforms.
+ * Solaris's isspace() is a macro which uses it's argument directly
+ * as an array index.  Therefore we need to make sure that high-bit
+ * characters generate +ve values, and ideally we also want to make
+ * the argument match the declared parameter type of "int".
+ * 
+ * Why did they write a character function that can't take a simple 
+ * "char" argument?  Doh!
+ */
+#define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
+#define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
+
+
+const struct parsers client_patterns[] = {
+   { "referer:",                 8,    client_referrer },
+   { "user-agent:",              11,   client_uagent },
+   { "ua-",                      3,    client_ua },
+   { "from:",                    5,    client_from },
+   { "cookie:",                  7,    client_send_cookie },
+   { "x-forwarded-for:",         16,   client_x_forwarded },
+   { "proxy-connection:",        17,   crumble },
+#ifdef DENY_GZIP
+   { "Accept-Encoding: gzip",    21,   crumble },
+#endif /* def DENY_GZIP */
+#if defined(DETECT_MSIE_IMAGES)
+   { "Accept:",                   7,   client_accept },
+#endif /* defined(DETECT_MSIE_IMAGES) */
+#ifdef FORCE_LOAD
+   { "Host:",                     5,   client_host },
+#endif /* def FORCE_LOAD */
+/* { "if-modified-since:",       18,   crumble }, */
+   { NULL,                       0,    NULL }
+};
+
+const struct interceptors intercept_patterns[] = {
+   { "show-proxy-args",    14, show_proxy_args },
+#ifdef TRUST_FILES
+   { "ij-untrusted-url",   14, ij_untrusted_url },
+#endif /* def TRUST_FILES */
+   { NULL, 0, NULL }
+};
+
+const struct parsers server_patterns[] = {
+   { "set-cookie:",        11, server_set_cookie },
+   { "connection:",        11, crumble },
+#ifdef PCRS
+   { "Content-Type:",      13, content_type },
+   { "Content-Length:",    15, crumble },
+#endif /* def PCRS */
+   { NULL, 0, NULL }
+};
+
+
+void (* const add_client_headers[])(struct client_state *) = {
+   client_cookie_adder,
+   client_x_forwarded_adder,
+   client_xtra_adder,
+   NULL
+};
+
+
+void (* const add_server_headers[])(struct client_state *) = {
+   NULL
+};
+
+
+/*********************************************************************
+ *
+ * Function    :  match
+ *
+ * Description :  Do a `strncmpic' on every pattern in pats.
+ *
+ * Parameters  :
+ *          1  :  buf = a string to match to a list of patterns
+ *          2  :  pats = list of strings to compare against buf.
+ *
+ * Returns     :  Return the matching "struct parsers *",
+ *                or NULL if no pattern matches.
+ *
+ *********************************************************************/
+static const struct parsers *match(char *buf, const struct parsers *pats)
+{
+   const struct parsers *v;
+
+   if (buf == NULL)
+   {
+      /* hit me */
+      log_error(LOG_LEVEL_ERROR, "NULL parameter to match()");
+      return(NULL);
+   }
+
+   for (v = pats; v->str ; v++)
+   {
+      if (strncmpic(buf, v->str, v->len) == 0)
+      {
+         return(v);
+      }
+   }
+   return(NULL);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  flush_socket
+ *
+ * Description :  Write any pending "buffered" content.
+ *
+ * Parameters  :
+ *          1  :  fd = file descriptor of the socket to read
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  On success, the number of bytes written are returned (zero
+ *                indicates nothing was written).  On error, -1 is returned,
+ *                and errno is set appropriately.  If count is zero and the
+ *                file descriptor refers to a regular file, 0 will be
+ *                returned without causing any other effect.  For a special
+ *                file, the results are not portable.
+ *
+ *********************************************************************/
+int flush_socket(int fd, struct client_state *csp)
+{
+   struct iob *iob = csp->iob;
+   int n = iob->eod - iob->cur;
+
+   if (n <= 0)
+   {
+      return(0);
+   }
+
+   n = write_socket(fd, iob->cur, n);
+   iob->eod = iob->cur = iob->buf;
+   return(n);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  add_to_iob
+ *
+ * Description :  Add content to the buffered page.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *          2  :  buf = holds the content to be added to the page
+ *          3  :  n = number of bytes to be added
+ *
+ * Returns     :  Number of bytes in the content buffer.
+ *
+ *********************************************************************/
+int add_to_iob(struct client_state *csp, char *buf, int n)
+{
+   struct iob *iob = csp->iob;
+   int have, need;
+   char *p;
+
+   have = iob->eod - iob->cur;
+
+   if (n <= 0)
+   {
+      return(have);
+   }
+
+   need = have + n;
+
+   if ((p = (char *)malloc(need + 1)) == NULL)
+   {
+      log_error(LOG_LEVEL_ERROR, "malloc() iob failed: %E");
+      return(-1);
+   }
+
+   if (have)
+   {
+      /* there is something in the buffer - save it */
+      memcpy(p, iob->cur, have);
+
+      /* replace the buffer with the new space */
+      freez(iob->buf);
+      iob->buf = p;
+
+      /* point to the end of the data */
+      p += have;
+   }
+   else
+   {
+      /* the buffer is empty, free it and reinitialize */
+      freez(iob->buf);
+      iob->buf = p;
+   }
+
+   /* copy the new data into the iob buffer */
+   memcpy(p, buf, n);
+
+   /* point to the end of the data */
+   p += n;
+
+   /* null terminate == cheap insurance */
+   *p = '\0';
+
+   /* set the pointers to the new values */
+   iob->cur = iob->buf;
+   iob->eod = p;
+
+   return(need);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  get_header
+ *
+ * Description :  This (odd) routine will parse the csp->iob
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Any one of the following:
+ *
+ * 1) a pointer to a dynamically allocated string that contains a header line
+ * 2) NULL  indicating that the end of the header was reached
+ * 3) ""    indicating that the end of the iob was reached before finding
+ *          a complete header line.
+ *
+ *********************************************************************/
+char *get_header(struct client_state *csp)
+{
+   struct iob *iob;
+   char *p, *q, *ret;
+   iob = csp->iob;
+
+   if ((iob->cur == NULL)
+      || ((p = strchr(iob->cur, '\n')) == NULL))
+   {
+      return(""); /* couldn't find a complete header */
+   }
+
+   *p = '\0';
+
+   ret = strdup(iob->cur);
+
+   iob->cur = p+1;
+
+   if ((q = strchr(ret, '\r'))) *q = '\0';
+
+   /* is this a blank linke (i.e. the end of the header) ? */
+   if (*ret == '\0')
+   {
+      freez(ret);
+      return(NULL);
+   }
+
+   return(ret);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  enlist
+ *
+ * Description :  Append a string into a specified string list.
+ *
+ * Parameters  :
+ *          1  :  h = pointer to list 'dummy' header
+ *          2  :  s = string to add to the list
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void enlist(struct list *h, const char *s)
+{
+   struct list *n = (struct list *)malloc(sizeof(*n));
+   struct list *l;
+
+   if (n)
+   {
+      n->str  = strdup(s);
+      n->next = NULL;
+
+      if ((l = h->last))
+      {
+         l->next = n;
+      }
+      else
+      {
+         h->next = n;
+      }
+
+      h->last = n;
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  destroy_list
+ *
+ * Description :  Destroy a string list (opposite of enlist)
+ *
+ * Parameters  :
+ *          1  :  h = pointer to list 'dummy' header
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void destroy_list(struct list *h)
+{
+   struct list *p, *n;
+
+   for (p = h->next; p ; p = n)
+   {
+      n = p->next;
+      freez(p->str);
+      freez(p);
+   }
+
+   memset(h, '\0', sizeof(*h));
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  list_to_text
+ *
+ * Description :  "Flaten" a string list into 1 long \r\n delimited string.
+ *
+ * Parameters  :
+ *          1  :  h = pointer to list 'dummy' header
+ *
+ * Returns     :  NULL on malloc error, else new long string.
+ *
+ *********************************************************************/
+static char *list_to_text(struct list *h)
+{
+   struct list *p;
+   char *ret = NULL;
+   char *s;
+   int size;
+
+   size = 0;
+
+   for (p = h->next; p ; p = p->next)
+   {
+      if (p->str)
+      {
+         size += strlen(p->str) + 2;
+      }
+   }
+
+   if ((ret = (char *)malloc(size + 1)) == NULL)
+   {
+      return(NULL);
+   }
+
+   ret[size] = '\0';
+
+   s = ret;
+
+   for (p = h->next; p ; p = p->next)
+   {
+      if (p->str)
+      {
+         strcpy(s, p->str);
+         s += strlen(s);
+         *s++ = '\r'; *s++ = '\n';
+      }
+   }
+
+   return(ret);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  sed
+ *
+ * Description :  add, delete or modify lines in the HTTP header streams.
+ *                On entry, it receives a linked list of headers space
+ *                that was allocated dynamically (both the list nodes
+ *                and the header contents).
+ *
+ *                As a side effect it frees the space used by the original
+ *                header lines.
+ *
+ * Parameters  :
+ *          1  :  pats = list of patterns to match against headers
+ *          2  :  more_headers = list of functions to add more
+ *                headers (client or server)
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Single pointer to a fully formed header.
+ *
+ *********************************************************************/
+char *sed(const struct parsers pats[], void (* const more_headers[])(struct client_state *), struct client_state *csp)
+{
+   struct list *p;
+   const struct parsers *v;
+   char *hdr;
+   void (* const *f)();
+
+   for (p = csp->headers->next; p ; p = p->next)
+   {
+      log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
+
+      if ((v = match(p->str, pats)))
+      {
+         hdr = v->parser(v, p->str, csp);
+         freez(p->str);
+         p->str = hdr;
+      }
+
+   }
+
+   /* place any additional headers on the csp->headers list */
+   for (f = more_headers; *f ; f++)
+   {
+      (*f)(csp);
+   }
+
+   /* add the blank line at the end of the header */
+   enlist(csp->headers, "");
+
+   hdr = list_to_text(csp->headers);
+
+   return(hdr);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  free_http_request
+ *
+ * Description :  Freez a http_request structure
+ *
+ * Parameters  :
+ *          1  :  http = points to a http_request structure to free
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void free_http_request(struct http_request *http)
+{
+   freez(http->cmd);
+   freez(http->gpc);
+   freez(http->host);
+   freez(http->hostport);
+   freez(http->path);
+   freez(http->ver);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  parse_http_request
+ *
+ * Description :  Parse out the host and port from the URL.  Find the
+ *                hostname & path, port (if ':'), and/or password (if '@')
+ *
+ * Parameters  :
+ *          1  :  req = URL (or is it URI?) to break down
+ *          2  :  http = pointer to the http structure to hold elements
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void parse_http_request(char *req, struct http_request *http, struct client_state *csp)
+{
+   char *buf, *v[10], *url, *p;
+   int n;
+
+   memset(http, '\0', sizeof(*http));
+
+   http->cmd = strdup(req);
+
+   buf = strdup(req);
+
+   n = ssplit(buf, " \r\n", v, SZ(v), 1, 1);
+
+   if (n == 3)
+   {
+      /* this could be a CONNECT request */
+      if (strcmpic(v[0], "connect") == 0)
+      {
+         http->ssl      = 1;
+         http->gpc      = strdup(v[0]);
+         http->hostport = strdup(v[1]);
+         http->ver      = strdup(v[2]);
+      }
+
+#ifdef WEBDAV
+
+/* This next line is a little ugly, but it simplifies the if statement below. */
+/* Basically if using webDAV, we want the OR condition to use these too.      */
+
+/*
+ * by haroon
+ * These are the headers as defined in RFC2518 to add webDAV support
+ */
+
+#define OR_WEBDAV || \
+         (0 == strcmpic(v[0], "propfind")) || \
+         (0 == strcmpic(v[0], "proppatch")) || \
+         (0 == strcmpic(v[0], "move")) || \
+         (0 == strcmpic(v[0], "copy")) || \
+         (0 == strcmpic(v[0], "mkcol")) || \
+         (0 == strcmpic(v[0], "lock")) || \
+         (0 == strcmpic(v[0], "unlock"))
+
+#else /* No webDAV support is enabled.  Provide an empty OR_WEBDAV macro. */
+
+#define OR_WEBDAV
+
+#endif
+
+      /* or it could be a GET or a POST (possibly webDAV too) */
+      if ((strcmpic(v[0], "get")  == 0) ||
+          (strcmpic(v[0], "head") == 0) OR_WEBDAV ||
+          (strcmpic(v[0], "post") == 0))
+      {
+         http->ssl      = 0;
+         http->gpc      = strdup(v[0]);
+         url            = v[1];
+         http->ver      = strdup(v[2]);
+
+         if (strncmpic(url, "http://",  7) == 0)
+         {
+            url += 7;
+         }
+         else if (strncmpic(url, "https://", 8) == 0)
+         {
+            url += 8;
+         }
+         else
+         {
+            url = NULL;
+         }
+
+         if (url && (p = strchr(url, '/')))
+         {
+            http->path = strdup(p);
+            *p = '\0';
+            http->hostport = strdup(url);
+         }
+      }
+   }
+
+   freez(buf);
+
+
+   if (http->hostport == NULL)
+   {
+      free_http_request(http);
+      return;
+   }
+
+   buf = strdup(http->hostport);
+
+
+   /* check if url contains password */
+   n = ssplit(buf, "@", v, SZ(v), 1, 1);
+   if (n == 2)
+   {
+      char * newbuf = NULL;
+      newbuf = strdup(v[1]);
+      freez(buf);
+      buf = newbuf;
+   }
+
+   n = ssplit(buf, ":", v, SZ(v), 1, 1);
+
+   if (n == 1)
+   {
+      http->host = strdup(v[0]);
+      http->port = 80;
+   }
+
+   if (n == 2)
+   {
+      http->host = strdup(v[0]);
+      http->port = atoi(v[1]);
+   }
+
+   freez(buf);
+
+   if (http->host == NULL)
+   {
+      free_http_request(http);
+   }
+
+   if (http->path == NULL)
+   {
+      http->path = strdup("");
+   }
+
+}
+
+
+/* here begins the family of parser functions that reformat header lines */
+
+
+/*********************************************************************
+ *
+ * Function    :  crumble
+ *
+ * Description :  This is called if a header matches a pattern to "crunch"
+ *
+ * Parameters  :
+ *          1  :  v = Pointer to parsers structure, which basically holds
+ *                headers (client or server) that we want to "crunch"
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Always NULL.
+ *
+ *********************************************************************/
+char *crumble(const struct parsers *v, char *s, struct client_state *csp)
+{
+   log_error(LOG_LEVEL_HEADER, "crunch!");
+   return(NULL);
+
+}
+
+
+#ifdef PCRS
+
+/*********************************************************************
+ *
+ * Function    :  content_type
+ *
+ * Description :  Is this a text/* or javascript MIME Type?
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header string we are "considering"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A duplicate string pointer to this header (ie. pass thru)
+ *
+ *********************************************************************/
+char *content_type(const struct parsers *v, char *s, struct client_state *csp)
+{
+   if (strstr (s, " text/") || strstr (s, "application/x-javascript"))
+      csp->is_text = 1;
+   else
+      csp->is_text = 0;
+
+   return(strdup(s));
+
+}
+
+#endif /* def PCRS */
+
+
+/*********************************************************************
+ *
+ * Function    :  client_referrer
+ *
+ * Description :  Handle the "referer" config setting properly.
+ *                Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL if crunched, or a malloc'ed string with the original
+ *                or modified header
+ *
+ *********************************************************************/
+char *client_referrer(const struct parsers *v, char *s, struct client_state *csp)
+{
+#ifdef FORCE_LOAD
+   /* Since the referrer can include the prefix even
+    * even if the request itself is non-forced, we must
+    * clean it unconditionally 
+    */
+   strclean(s, FORCE_PREFIX);
+#endif /* def FORCE_LOAD */
+
+   csp->referrer = strdup(s);
+
+   if (referrer == NULL)
+   {
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
+   }
+
+   if (*referrer == '.')
+   {
+      return(strdup(s));
+   }
+
+   if (*referrer == '@')
+   {
+      if (csp->send_user_cookie)
+      {
+         return(strdup(s));
+      }
+      else
+      {
+         log_error(LOG_LEVEL_HEADER, "crunch!");
+         return(NULL);
+      }
+   }
+
+   /*
+    * New option Â§: Forge a referer as http://[hostname:port of REQUEST]/
+    * to fool stupid checks for in-site links
+    */
+
+   if (*referrer == '§')
+   {
+      if (csp->send_user_cookie)
+      {
+         return(strdup(s));
+      }
+      else
+      {
+         log_error(LOG_LEVEL_HEADER, "crunch+forge!");
+         s = strsav(NULL, "Referer: ");
+         s = strsav(s, "http://");
+         s = strsav(s, csp->http->hostport);
+         s = strsav(s, "/");
+         return(s);
+      }
+   }
+
+   log_error(LOG_LEVEL_HEADER, "modified");
+
+   s = strsav( NULL, "Referer: " );
+   s = strsav( s, referrer );
+   return(s);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_uagent
+ *
+ * Description :  Handle the "user-agent" config setting properly.
+ *                Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A malloc'ed pointer to the default agent, or
+ *                a malloc'ed string pointer to this header (ie. pass thru).
+ *
+ *********************************************************************/
+char *client_uagent(const struct parsers *v, char *s, struct client_state *csp)
+{
+#ifdef DETECT_MSIE_IMAGES
+   if (strstr (s, "MSIE "))
+   {
+      /* This is Microsoft Internet Explorer.
+       * Enable auto-detect.
+       */
+      csp->accept_types |= ACCEPT_TYPE_IS_MSIE;
+   }
+#endif /* def DETECT_MSIE_IMAGES */
+
+   if (uagent == NULL)
+   {
+      log_error(LOG_LEVEL_HEADER, "default");
+      return(strdup(DEFAULT_USER_AGENT));
+   }
+
+   if (*uagent == '.')
+   {
+      return(strdup(s));
+   }
+
+   if (*uagent == '@')
+   {
+      if (csp->send_user_cookie)
+      {
+         return(strdup(s));
+      }
+      else
+      {
+         log_error(LOG_LEVEL_HEADER, "default");
+         return(strdup(DEFAULT_USER_AGENT));
+      }
+   }
+
+   log_error(LOG_LEVEL_HEADER, "modified");
+
+   s = strsav( NULL, "User-Agent: " );
+   s = strsav( s, uagent );
+   return(s);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_ua
+ *
+ * Description :  Handle "ua-" headers properly.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL if crunched, or a malloc'ed string to original header
+ *
+ *********************************************************************/
+char *client_ua(const struct parsers *v, char *s, struct client_state *csp)
+{
+   if (uagent == NULL)
+   {
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
+   }
+
+   if (*uagent == '.')
+   {
+      return(strdup(s));
+   }
+
+   if (*uagent == '@')
+   {
+      if (csp->send_user_cookie)
+      {
+         return(strdup(s));
+      }
+      else
+      {
+         log_error(LOG_LEVEL_HEADER, "crunch!");
+         return(NULL);
+      }
+   }
+
+   log_error(LOG_LEVEL_HEADER, "crunch!");
+   return(NULL);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_from
+ *
+ * Description :  Handle the "from" config setting properly.
+ *                Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  NULL if crunched, or a malloc'ed string to
+ *                modified/original header.
+ *
+ *********************************************************************/
+char *client_from(const struct parsers *v, char *s, struct client_state *csp)
+{
+   /* if not set, zap it */
+   if (from == NULL)
+   {
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
+   }
+
+   if (*from == '.')
+   {
+      return(strdup(s));
+   }
+
+   log_error(LOG_LEVEL_HEADER, " modified");
+
+   s = strsav( NULL, "From: " );
+   s = strsav( s, from );
+   return(s);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_send_cookie
+ *
+ * Description :  Handle the "cookie" header properly.  Called from `sed'.
+ *                If cookie is accepted, add it to the cookie_list,
+ *                else we crunch it.  Mmmmmmmmmmm ... cookie ......
+ *
+ * Parameters  :
+ *          1  :  v = pattern of cookie `sed' found matching
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Always NULL.
+ *
+ *********************************************************************/
+char *client_send_cookie(const struct parsers *v, char *s, struct client_state *csp)
+{
+   if (csp->send_user_cookie)
+   {
+      enlist(csp->cookie_list, s + v->len + 1);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_HEADER, " crunch!");
+   }
+
+   /*
+    * Always return NULL here.  The cookie header
+    * will be sent at the end of the header.
+    */
+   return(NULL);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_x_forwarded
+ *
+ * Description :  Handle the "x-forwarded-for" config setting properly,
+ *                also used in the add_client_headers list.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to "crunch"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Always NULL.
+ *
+ *********************************************************************/
+char *client_x_forwarded(const struct parsers *v, char *s, struct client_state *csp)
+{
+   if (add_forwarded)
+   {
+      csp->x_forwarded = strdup(s);
+   }
+
+   /*
+    * Always return NULL, since this information
+    * will be sent at the end of the header.
+    */
+
+   return(NULL);
+
+}
+
+#if defined(DETECT_MSIE_IMAGES)
+/*********************************************************************
+ *
+ * Function    :  client_accept
+ *
+ * Description :  Detect whether the client wants HTML or an image.
+ *                Clients do not always make this information available
+ *                in a sane way.  Always passes the header through
+ *                the proxy unchanged.
+ *
+ * Parameters  :
+ *          1  :  v = Ignored.
+ *          2  :  s = Header string.  Null terminated.
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Duplicate of argument s.
+ *
+ *********************************************************************/
+char *client_accept(const struct parsers *v, char *s, struct client_state *csp)
+{
+#ifdef DETECT_MSIE_IMAGES
+   if (strstr (s, "image/gif"))
+   {
+      /* Client will accept HTML.  If this seems counterintuitive,
+       * blame Microsoft. 
+       */
+      csp->accept_types |= ACCEPT_TYPE_MSIE_HTML;
+   }
+   else
+   {
+      csp->accept_types |= ACCEPT_TYPE_MSIE_IMAGE;
+   }
+#endif /* def DETECT_MSIE_IMAGES */
+
+   return(strdup(s));
+
+}
+#endif /* defined(DETECT_MSIE_IMAGES) */
+
+
+
+/* the following functions add headers directly to the header list */
+
+
+/*********************************************************************
+ *
+ * Function    :  client_cookie_adder
+ *
+ * Description :  Used in the add_client_headers list.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void client_cookie_adder(struct client_state *csp)
+{
+   struct list *l;
+   char *tmp = NULL;
+   char *e;
+
+   for (l = csp->cookie_list->next; l ; l = l->next)
+   {
+      if (tmp)
+      {
+         tmp = strsav(tmp, "; ");
+      }
+      tmp = strsav(tmp, l->str);
+   }
+
+   for (l = wafer_list->next;  l ; l = l->next)
+   {
+      if (tmp)
+      {
+         tmp = strsav(tmp, "; ");
+      }
+
+      if ((e = cookie_encode(l->str)))
+      {
+         tmp = strsav(tmp, e);
+         freez(e);
+      }
+   }
+
+   if (tmp)
+   {
+      char *ret;
+
+      ret = strdup("Cookie: ");
+      ret = strsav(ret, tmp);
+      log_error(LOG_LEVEL_HEADER, "addh: %s", ret);
+      enlist(csp->headers, ret);
+      freez(tmp);
+      freez(ret);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_xtra_adder
+ *
+ * Description :  Used in the add_client_headers list.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void client_xtra_adder(struct client_state *csp)
+{
+   struct list *l;
+
+   for (l = xtra_list->next; l ; l = l->next)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh: %s", l->str);
+      enlist(csp->headers, l->str);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  client_x_forwarded_adder
+ *
+ * Description :  Used in the add_client_headers list.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void client_x_forwarded_adder(struct client_state *csp)
+{
+   char *p = NULL;
+
+   if (add_forwarded == 0) return;
+
+   if (csp->x_forwarded)
+   {
+      p = strsav(p, csp->x_forwarded);
+      p = strsav(p, ", ");
+      p = strsav(p, csp->ip_addr_str);
+   }
+   else
+   {
+      p = strsav(p, "X-Forwarded-For: ");
+      p = strsav(p, csp->ip_addr_str);
+   }
+
+   log_error(LOG_LEVEL_HEADER, "addh: %s", p);
+   enlist(csp->headers, p);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  server_set_cookie
+ *
+ * Description :  Handle the server "cookie" header properly.
+ *                Log cookie to the jar file.  Then "crunch" it,
+ *                or accept it.  Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  v = parser pattern that matched this header
+ *          2  :  s = header that matched this pattern
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  `crumble' or a newly malloc'ed string.
+ *
+ *********************************************************************/
+char *server_set_cookie(const struct parsers *v, char *s, struct client_state *csp)
+{
+#ifdef JAR_FILES
+   if (jar)
+   {
+      fprintf(jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
+   }
+#endif /* def JAR_FILES */
+
+   if (csp->accept_server_cookie == 0)
+   {
+      return(crumble(v, s, csp));
+   }
+
+   return(strdup(s));
+
+}
+
+
+#ifdef FORCE_LOAD
+/*********************************************************************
+ *
+ * Function    :  client_host
+ *
+ * Description :  Clean the FORCE_PREFIX out of the 'host' http
+ *                header, if we use force
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header (from sed) to clean
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A malloc'ed pointer to the cleaned host header 
+ *
+ *********************************************************************/
+char *client_host(const struct parsers *v, char *s, struct client_state *csp)
+{
+   char *cleanhost = strdup(s);
+   if(csp->force)
+      strclean(cleanhost, FORCE_PREFIX);
+   return(cleanhost);
+}
+#endif /* def FORCE_LOAD */
+#ifdef FORCE_LOAD 
+/*********************************************************************
+ *
+ * Function    :  strclean
+ *
+ * Description :  In-Situ-Eliminate all occurances of substring in 
+ *                string
+ *
+ * Parameters  :
+ *          1  :  string = string to clean
+ *          2  :  substring = substring to eliminate
+ *
+ * Returns     :  Number of eliminations
+ *
+ *********************************************************************/
+int strclean(const char *string, const char *substring)
+{
+   int hits = 0, len = strlen(substring);
+   char *pos, *p;
+
+   while((pos = strstr(string, substring)))
+   {
+      p = pos + len;
+      do
+      {
+         *(p - len) = *p; 
+      }
+      while (*p++ != '\0');
+
+      hits++;
+   }
+
+   return(hits);
+}
+#endif /* def FORCE_LOAD */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/parsers.h b/parsers.h
new file mode 100644 (file)
index 0000000..1402544
--- /dev/null
+++ b/parsers.h
@@ -0,0 +1,114 @@
+#ifndef _PARSERS_H
+#define _PARSERS_H
+#define PARSERS_H_VERSION "$Id: parsers.h,v 1.1 2001/05/13 21:57:06 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/parsers.h,v $
+ *
+ * Purpose     :  Declares functions to parse/crunch headers and pages.
+ *                Functions declared include:
+ *                   `add_to_iob', `client_cookie_adder', `client_from',
+ *                   `client_referrer', `client_send_cookie', `client_ua',
+ *                   `client_uagent', `client_x_forwarded',
+ *                   `client_x_forwarded_adder', `client_xtra_adder',
+ *                   `content_type', `crumble', `destroy_list', `enlist',
+ *                   `flush_socket', `free_http_request', `get_header',
+ *                   `list_to_text', `match', `parse_http_request', `sed',
+ *                   and `server_set_cookie'.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: parsers.h,v $
+ *
+ *********************************************************************/
+\f
+
+#include "project.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const struct parsers client_patterns[];
+extern const struct parsers server_patterns[];
+extern const struct interceptors intercept_patterns[];
+
+extern void (* const add_client_headers[])(struct client_state *);
+extern void (* const add_server_headers[])(struct client_state *);
+
+extern int flush_socket(int fd, struct client_state *csp);
+extern int add_to_iob(struct client_state *csp, char *buf, int n);
+extern char *get_header(struct client_state *csp);
+extern void enlist(struct list *h, const char *s);
+extern void destroy_list(struct list *h);
+
+extern char *sed(const struct parsers pats[], void (* const more_headers[])(struct client_state *), struct client_state *csp);
+
+extern void free_http_request(struct http_request *http);
+extern void parse_http_request(char *req, struct http_request *http, struct client_state *csp);
+
+extern char *crumble(const struct parsers *v, char *s, struct client_state *csp);
+
+extern char *client_referrer(const struct parsers *v, char *s, struct client_state *csp);
+extern char *client_uagent(const struct parsers *v, char *s, struct client_state *csp);
+extern char *client_ua(const struct parsers *v, char *s, struct client_state *csp);
+extern char *client_from(const struct parsers *v, char *s, struct client_state *csp);
+extern char *client_send_cookie(const struct parsers *v, char *s, struct client_state *csp);
+extern char *client_x_forwarded(const struct parsers *v, char *s, struct client_state *csp);
+extern void client_cookie_adder(struct client_state *csp);
+extern void client_xtra_adder(struct client_state *csp);
+extern void client_x_forwarded_adder(struct client_state *csp);
+extern char *server_set_cookie(const struct parsers *v, char *s, struct client_state *csp);
+
+#ifdef PCRS
+extern char *content_type(const struct parsers *v, char *s, struct client_state *csp);
+#endif /* def PCRS */
+
+#ifdef FORCE_LOAD
+char *client_host(const struct parsers *v, char *s, struct client_state *csp);
+int strclean(const char *string, const char *substring);
+#endif /* def FORCE_LOAD */
+
+#if defined(DETECT_MSIE_IMAGES)
+extern char *client_accept(const struct parsers *v, char *s, struct client_state *csp);
+#endif /* defined(DETECT_MSIE_IMAGES) */
+
+/* Revision control strings from this header and associated .c file */
+extern const char parsers_rcs[];
+extern const char parsers_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _PARSERS_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/pcre/chartables.c b/pcre/chartables.c
new file mode 100644 (file)
index 0000000..9055da2
--- /dev/null
@@ -0,0 +1,183 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary 
+program. If you edit it by hand, you might like to edit the Makefile to 
+prevent its ever being regenerated.
+
+This file is #included in the compilation of pcre.c to build the default
+character tables which are used when no tables are passed to the compile
+function. */
+
+static unsigned char pcre_default_tables[] = {
+
+/* This table is a lower casing table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 65, 66, 67, 68, 69, 70, 71,
+   72, 73, 74, 75, 76, 77, 78, 79,
+   80, 81, 82, 83, 84, 85, 86, 87,
+   88, 89, 90,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes that have their own
+maps are: space, xdigit, digit, upper, lower, word, graph
+print, punct, and cntrl. Other classes are built from combinations. */
+
+  0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
+  0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x02   letter
+  0x04   decimal digit
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+  0x80   regular expression metacharacter or binary zero
+*/
+
+  0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
+  0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /*   8- 15 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
+  0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /*    - '  */
+  0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /*  ( - /  */
+  0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /*  0 - 7  */
+  0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /*  8 - ?  */
+  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  @ - G  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  H - O  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  P - W  */
+  0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /*  X - _  */
+  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  ` - g  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  h - o  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  p - w  */
+  0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /*  x -127 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* End of chartables.c */
diff --git a/pcre/config.h b/pcre/config.h
new file mode 100644 (file)
index 0000000..048b8c3
--- /dev/null
@@ -0,0 +1,34 @@
+/* config.h.  Generated automatically by configure.  */
+
+/* On Unix systems config.in is converted by configure into config.h. PCRE is
+written in Standard C, but there are a few non-standard things it can cope
+with, allowing it to run on SunOS4 and other "close to standard" systems.
+
+On a non-Unix system you should just copy this file into config.h and change
+the definitions of HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because
+of the way autoconf works, these cannot be made the defaults. If your system
+has bcopy() and not memmove(), change the definition of HAVE_BCOPY instead of
+HAVE_MEMMOVE. If your system has neither bcopy() nor memmove(), leave them both
+as 0; an emulation function will be used. */
+
+/* Define to empty if the keyword does not work. */
+
+/* #undef const */
+
+/* Define to `unsigned' if <stddef.h> doesn't define size_t. */
+
+/* #undef size_t */
+
+/* The following two definitions are mainly for the benefit of SunOS4, which
+doesn't have the strerror() or memmove() functions that should be present in
+all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
+normally be defined with the value 1 for other systems, but unfortunately we
+can't make this the default because "configure" files generated by autoconf
+will only change 0 to 1; they won't change 1 to 0 if the functions are not
+found. If HAVE_MEMMOVE is set to 1, the value of HAVE_BCOPY is not relevant. */
+
+#define HAVE_STRERROR 1
+#define HAVE_MEMMOVE  1
+#define HAVE_BCOPY    1
+
+/* End */
diff --git a/pcre/ltmain.sh b/pcre/ltmain.sh
new file mode 100644 (file)
index 0000000..50515ad
--- /dev/null
@@ -0,0 +1,4012 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun ltconfig.
+#
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell, and then maybe $echo will work.
+  exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit 0
+fi
+
+# The name of this program.
+progname=`$echo "$0" | sed 's%^.*/%%'`
+modename="$progname"
+
+# Constants.
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.3.4
+TIMESTAMP=" (1.385.2.196 1999/12/07 21:47:57)"
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+SP2NL='tr \040 \012'
+NL2SP='tr \015\012 \040\040'
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+  save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+  save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+if test "$LTCONFIG_VERSION" != "$VERSION"; then
+  echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2
+  echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit 1
+fi
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+  echo "$modename: not configured to build any kind of library" 1>&2
+  echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+# Parse our command line options once, thoroughly.
+while test $# -gt 0
+do
+  arg="$1"
+  shift
+
+  case "$arg" in
+  -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    case "$prev" in
+    execute_dlfiles)
+      eval "$prev=\"\$$prev \$arg\""
+      ;;
+    *)
+      eval "$prev=\$arg"
+      ;;
+    esac
+
+    prev=
+    prevopt=
+    continue
+  fi
+
+  # Have we seen a non-optional argument yet?
+  case "$arg" in
+  --help)
+    show_help=yes
+    ;;
+
+  --version)
+    echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+    exit 0
+    ;;
+
+  --config)
+    sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0
+    exit 0
+    ;;
+
+  --debug)
+    echo "$progname: enabling shell trace mode"
+    set -x
+    ;;
+
+  --dry-run | -n)
+    run=:
+    ;;
+
+  --features)
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+    exit 0
+    ;;
+
+  --finish) mode="finish" ;;
+
+  --mode) prevopt="--mode" prev=mode ;;
+  --mode=*) mode="$optarg" ;;
+
+  --quiet | --silent)
+    show=:
+    ;;
+
+  -dlopen)
+    prevopt="-dlopen"
+    prev=execute_dlfiles
+    ;;
+
+  -*)
+    $echo "$modename: unrecognized option \`$arg'" 1>&2
+    $echo "$help" 1>&2
+    exit 1
+    ;;
+
+  *)
+    nonopt="$arg"
+    break
+    ;;
+  esac
+done
+
+if test -n "$prevopt"; then
+  $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+  $echo "$help" 1>&2
+  exit 1
+fi
+
+if test -z "$show_help"; then
+
+  # Infer the operation mode.
+  if test -z "$mode"; then
+    case "$nonopt" in
+    *cc | *++ | gcc* | *-gcc*)
+      mode=link
+      for arg
+      do
+       case "$arg" in
+       -c)
+          mode=compile
+          break
+          ;;
+       esac
+      done
+      ;;
+    *db | *dbx | *strace | *truss)
+      mode=execute
+      ;;
+    *install*|cp|mv)
+      mode=install
+      ;;
+    *rm)
+      mode=uninstall
+      ;;
+    *)
+      # If we have no mode, but dlfiles were specified, then do execute mode.
+      test -n "$execute_dlfiles" && mode=execute
+
+      # Just use the default operation mode.
+      if test -z "$mode"; then
+       if test -n "$nonopt"; then
+         $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+       else
+         $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+       fi
+      fi
+      ;;
+    esac
+  fi
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+    $echo "$help" 1>&2
+    exit 1
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$modename --help --mode=$mode' for more information."
+
+  # These modes are in order of execution frequency so that they run quickly.
+  case "$mode" in
+  # libtool compile mode
+  compile)
+    modename="$modename: compile"
+    # Get the compilation command and the source file.
+    base_compile=
+    lastarg=
+    srcfile="$nonopt"
+    suppress_output=
+
+    user_target=no
+    for arg
+    do
+      # Accept any command-line options.
+      case "$arg" in
+      -o)
+       if test "$user_target" != "no"; then
+         $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+         exit 1
+       fi
+       user_target=next
+       ;;
+
+      -static)
+       build_old_libs=yes
+       continue
+       ;;
+      esac
+
+      case "$user_target" in
+      next)
+       # The next one is the -o target name
+       user_target=yes
+       continue
+       ;;
+      yes)
+       # We got the output file
+       user_target=set
+       libobj="$arg"
+       continue
+       ;;
+      esac
+
+      # Accept the current argument as the source file.
+      lastarg="$srcfile"
+      srcfile="$arg"
+
+      # Aesthetically quote the previous argument.
+
+      # Backslashify any backslashes, double quotes, and dollar signs.
+      # These are the only characters that are still specially
+      # interpreted inside of double-quoted scrings.
+      lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+      # Double-quote args containing other shell metacharacters.
+      # Many Bourne shells cannot handle close brackets correctly in scan
+      # sets, so we specify it separately.
+      case "$lastarg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       lastarg="\"$lastarg\""
+       ;;
+      esac
+
+      # Add the previous argument to base_compile.
+      if test -z "$base_compile"; then
+       base_compile="$lastarg"
+      else
+       base_compile="$base_compile $lastarg"
+      fi
+    done
+
+    case "$user_target" in
+    set)
+      ;;
+    no)
+      # Get the name of the library object.
+      libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+      ;;
+    *)
+      $echo "$modename: you must specify a target with \`-o'" 1>&2
+      exit 1
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    xform='[cCFSfmso]'
+    case "$libobj" in
+    *.ada) xform=ada ;;
+    *.adb) xform=adb ;;
+    *.ads) xform=ads ;;
+    *.asm) xform=asm ;;
+    *.c++) xform=c++ ;;
+    *.cc) xform=cc ;;
+    *.cpp) xform=cpp ;;
+    *.cxx) xform=cxx ;;
+    *.f90) xform=f90 ;;
+    *.for) xform=for ;;
+    esac
+
+    libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+    case "$libobj" in
+    *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+    *)
+      $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+      exit 1
+      ;;
+    esac
+
+    if test -z "$base_compile"; then
+      $echo "$modename: you must specify a compilation command" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $libobj"
+    else
+      removelist="$libobj"
+    fi
+
+    $run $rm $removelist
+    trap "$run $rm $removelist; exit 1" 1 2 15
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+      removelist="$removelist $output_obj $lockfile"
+      trap "$run $rm $removelist; exit 1" 1 2 15
+    else
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until ln "$0" "$lockfile" 2>/dev/null; do
+       $show "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+       echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit 1
+      fi
+      echo $srcfile > "$lockfile"
+    fi
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      # All platforms use -DPIC, to notify preprocessed assembler code.
+      command="$base_compile $srcfile $pic_flag -DPIC"
+      if test "$build_old_libs" = yes; then
+       lo_libobj="$libobj"
+       dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
+       if test "X$dir" = "X$libobj"; then
+         dir="$objdir"
+       else
+         dir="$dir/$objdir"
+       fi
+       libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
+
+       if test -d "$dir"; then
+         $show "$rm $libobj"
+         $run $rm $libobj
+       else
+         $show "$mkdir $dir"
+         $run $mkdir $dir
+         status=$?
+         if test $status -ne 0 && test ! -d $dir; then
+           exit $status
+         fi
+       fi
+      fi
+      if test "$compiler_o_lo" = yes; then
+       output_obj="$libobj"
+       command="$command -o $output_obj"
+      elif test "$compiler_c_o" = yes; then
+       output_obj="$obj"
+       command="$command -o $output_obj"
+      fi
+
+      $run $rm "$output_obj"
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+       test -n "$output_obj" && $run $rm $removelist
+       exit 1
+      fi
+
+      if test "$need_locks" = warn &&
+        test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+       echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit 1
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test x"$output_obj" != x"$libobj"; then
+       $show "$mv $output_obj $libobj"
+       if $run $mv $output_obj $libobj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+
+      # If we have no pic_flag, then copy the object into place and finish.
+      if test -z "$pic_flag" && test "$build_old_libs" = yes; then
+       # Rename the .lo from within objdir to obj
+       if test -f $obj; then
+         $show $rm $obj
+         $run $rm $obj
+       fi
+
+       $show "$mv $libobj $obj"
+       if $run $mv $libobj $obj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+
+       xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+       if test "X$xdir" = "X$obj"; then
+         xdir="."
+       else
+         xdir="$xdir"
+       fi
+       baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"`
+       libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
+       # Now arrange that obj and lo_libobj become the same file
+       $show "(cd $xdir && $LN_S $baseobj $libobj)"
+       if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then
+         exit 0
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+
+      # Allow error messages only from the first compilation.
+      suppress_output=' >/dev/null 2>&1'
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      command="$base_compile $srcfile"
+      if test "$compiler_c_o" = yes; then
+       command="$command -o $obj"
+       output_obj="$obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      $run $rm "$output_obj"
+      $show "$command"
+      if $run eval "$command"; then :
+      else
+       $run $rm $removelist
+       exit 1
+      fi
+
+      if test "$need_locks" = warn &&
+        test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+       echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $run $rm $removelist
+       exit 1
+      fi
+
+      # Just move the object if needed
+      if test x"$output_obj" != x"$obj"; then
+       $show "$mv $output_obj $obj"
+       if $run $mv $output_obj $obj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+
+      # Create an invalid libtool object if no PIC, so that we do not
+      # accidentally link it into a program.
+      if test "$build_libtool_libs" != yes; then
+       $show "echo timestamp > $libobj"
+       $run eval "echo timestamp > \$libobj" || exit $?
+      else
+       # Move the .lo from within objdir
+       $show "$mv $libobj $lo_libobj"
+       if $run $mv $libobj $lo_libobj; then :
+       else
+         error=$?
+         $run $rm $removelist
+         exit $error
+       fi
+      fi
+    fi
+
+    # Unlock the critical section if it was locked
+    if test "$need_locks" != no; then
+      $rm "$lockfile"
+    fi
+
+    exit 0
+    ;;
+
+  # libtool link mode
+  link)
+    modename="$modename: link"
+    case "$host" in
+    *-*-cygwin* | *-*-mingw* | *-*-os2*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invokation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+
+      # This is a source program that is used to create dlls on Windows
+      # Don't remove nor modify the starting and closing comments
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+      # This is a source program that is used to create import libraries
+      # on Windows for dlls which lack them. Don't remove nor modify the
+      # starting and closing comments
+# /* impgen.c starts here */
+# /*   Copyright (C) 1999 Free Software Foundation, Inc.
+# 
+#  This file is part of GNU libtool.
+# 
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+# 
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+# 
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#  */
+# 
+#  #include <stdio.h>          /* for printf() */
+#  #include <unistd.h>         /* for open(), lseek(), read() */
+#  #include <fcntl.h>          /* for O_RDONLY, O_BINARY */
+#  #include <string.h>         /* for strdup() */
+# 
+#  static unsigned int
+#  pe_get16 (fd, offset)
+#       int fd;
+#       int offset;
+#  {
+#    unsigned char b[2];
+#    lseek (fd, offset, SEEK_SET);
+#    read (fd, b, 2);
+#    return b[0] + (b[1]<<8);
+#  }
+# 
+#  static unsigned int
+#  pe_get32 (fd, offset)
+#      int fd;
+#      int offset;
+#  {
+#    unsigned char b[4];
+#    lseek (fd, offset, SEEK_SET);
+#    read (fd, b, 4);
+#    return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+#  }
+# 
+#  static unsigned int
+#  pe_as32 (ptr)
+#       void *ptr;
+#  {
+#    unsigned char *b = ptr;
+#    return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+#  }
+# 
+#  int
+#  main (argc, argv)
+#      int argc;
+#      char *argv[];
+#  {
+#      int dll;
+#      unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
+#      unsigned long export_rva, export_size, nsections, secptr, expptr;
+#      unsigned long name_rvas, nexp;
+#      unsigned char *expdata, *erva;
+#      char *filename, *dll_name;
+# 
+#      filename = argv[1];
+# 
+#      dll = open(filename, O_RDONLY|O_BINARY);
+#      if (!dll)
+#      return 1;
+# 
+#      dll_name = filename;
+#    
+#      for (i=0; filename[i]; i++)
+#      if (filename[i] == '/' || filename[i] == '\\'  || filename[i] == ':')
+#          dll_name = filename + i +1;
+# 
+#      pe_header_offset = pe_get32 (dll, 0x3c);
+#      opthdr_ofs = pe_header_offset + 4 + 20;
+#      num_entries = pe_get32 (dll, opthdr_ofs + 92);
+# 
+#      if (num_entries < 1) /* no exports */
+#      return 1;
+# 
+#      export_rva = pe_get32 (dll, opthdr_ofs + 96);
+#      export_size = pe_get32 (dll, opthdr_ofs + 100);
+#      nsections = pe_get16 (dll, pe_header_offset + 4 +2);
+#      secptr = (pe_header_offset + 4 + 20 +
+#            pe_get16 (dll, pe_header_offset + 4 + 16));
+# 
+#      expptr = 0;
+#      for (i = 0; i < nsections; i++)
+#      {
+#      char sname[8];
+#      unsigned long secptr1 = secptr + 40 * i;
+#      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+#      unsigned long vsize = pe_get32 (dll, secptr1 + 16);
+#      unsigned long fptr = pe_get32 (dll, secptr1 + 20);
+#      lseek(dll, secptr1, SEEK_SET);
+#      read(dll, sname, 8);
+#      if (vaddr <= export_rva && vaddr+vsize > export_rva)
+#      {
+#          expptr = fptr + (export_rva - vaddr);
+#          if (export_rva + export_size > vaddr + vsize)
+#              export_size = vsize - (export_rva - vaddr);
+#          break;
+#      }
+#      }
+# 
+#      expdata = (unsigned char*)malloc(export_size);
+#      lseek (dll, expptr, SEEK_SET);
+#      read (dll, expdata, export_size);
+#      erva = expdata - export_rva;
+# 
+#      nexp = pe_as32 (expdata+24);
+#      name_rvas = pe_as32 (expdata+32);
+# 
+#      printf ("EXPORTS\n");
+#      for (i = 0; i<nexp; i++)
+#      {
+#      unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
+#      printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
+#      }
+# 
+#      return 0;
+#  }
+# /* impgen.c ends here */
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    compile_command="$nonopt"
+    finalize_command="$nonopt"
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    linkopts=
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval lib_search_path=\`\$echo \"X \${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+    else
+      lib_search_path=
+    fi
+    # now prepend the system-specific ones
+    eval lib_search_path=\"$sys_lib_search_path_spec\$lib_search_path\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+    
+    avoid_version=no
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    link_against_libtool_libs=
+    ltlibs=
+    module=no
+    objs=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case "$arg" in
+      -all-static | -static)
+       if test "X$arg" = "X-all-static"; then
+         if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+           $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+         fi
+         if test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+       else
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+       fi
+       build_libtool_libs=no
+       build_old_libs=yes
+       prefer_static_libs=yes
+       break
+       ;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test $# -gt 0; do
+      arg="$1"
+      shift
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+       case "$prev" in
+       output)
+         compile_command="$compile_command @OUTPUT@"
+         finalize_command="$finalize_command @OUTPUT@"
+         ;;
+       esac
+
+       case "$prev" in
+       dlfiles|dlprefiles)
+         if test "$preload" = no; then
+           # Add the symbol object into the linking commands.
+           compile_command="$compile_command @SYMFILE@"
+           finalize_command="$finalize_command @SYMFILE@"
+           preload=yes
+         fi
+         case "$arg" in
+         *.la | *.lo) ;;  # We handle these cases below.
+         force)
+           if test "$dlself" = no; then
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         self)
+           if test "$prev" = dlprefiles; then
+             dlself=yes
+           elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+             dlself=yes
+           else
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         *)
+           if test "$prev" = dlfiles; then
+             dlfiles="$dlfiles $arg"
+           else
+             dlprefiles="$dlprefiles $arg"
+           fi
+           prev=
+           ;;
+         esac
+         ;;
+       expsyms)
+         export_symbols="$arg"
+         if test ! -f "$arg"; then
+           $echo "$modename: symbol file \`$arg' does not exist"
+           exit 1
+         fi
+         prev=
+         continue
+         ;;
+       expsyms_regex)
+         export_symbols_regex="$arg"
+         prev=
+         continue
+         ;;
+       release)
+         release="-$arg"
+         prev=
+         continue
+         ;;
+       rpath | xrpath)
+         # We need an absolute path.
+         case "$arg" in
+         [\\/]* | [A-Za-z]:[\\/]*) ;;
+         *)
+           $echo "$modename: only absolute run-paths are allowed" 1>&2
+           exit 1
+           ;;
+         esac
+         if test "$prev" = rpath; then
+           case "$rpath " in
+           *" $arg "*) ;;
+           *) rpath="$rpath $arg" ;;
+           esac
+         else
+           case "$xrpath " in
+           *" $arg "*) ;;
+           *) xrpath="$xrpath $arg" ;;
+           esac
+         fi
+         prev=
+         continue
+         ;;
+       *)
+         eval "$prev=\"\$arg\""
+         prev=
+         continue
+         ;;
+       esac
+      fi
+
+      prevarg="$arg"
+
+      case "$arg" in
+      -all-static)
+       if test -n "$link_static_flag"; then
+         compile_command="$compile_command $link_static_flag"
+         finalize_command="$finalize_command $link_static_flag"
+       fi
+       continue
+       ;;
+
+      -allow-undefined)
+       # FIXME: remove this flag sometime in the future.
+       $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+       continue
+       ;;
+
+      -avoid-version)
+       avoid_version=yes
+       continue
+       ;;
+
+      -dlopen)
+       prev=dlfiles
+       continue
+       ;;
+
+      -dlpreopen)
+       prev=dlprefiles
+       continue
+       ;;
+
+      -export-dynamic)
+       export_dynamic=yes
+       continue
+       ;;
+
+      -export-symbols | -export-symbols-regex)
+       if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+         $echo "$modename: not more than one -exported-symbols argument allowed"
+         exit 1
+       fi
+       if test "X$arg" = "X-export-symbols"; then
+         prev=expsyms
+       else
+         prev=expsyms_regex
+       fi
+       continue
+       ;;
+
+      -L*)
+       dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+       # We need an absolute path.
+       case "$dir" in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         absdir=`cd "$dir" && pwd`
+         if test -z "$absdir"; then
+           $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+           $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+           absdir="$dir"
+         fi
+         dir="$absdir"
+         ;;
+       esac
+       case " $deplibs " in
+       *" $arg "*) ;;
+       *) deplibs="$deplibs $arg";;
+       esac
+       case " $lib_search_path " in
+       *" $dir "*) ;;
+       *) lib_search_path="$lib_search_path $dir";;
+       esac
+       case "$host" in
+       *-*-cygwin* | *-*-mingw* | *-*-os2*)
+         dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
+         case ":$dllsearchpath:" in
+         ::) dllsearchpath="$dllsearchdir";;
+         *":$dllsearchdir:"*) ;;
+         *) dllsearchpath="$dllsearchpath:$dllsearchdir";;
+         esac
+         ;;
+       esac
+       ;;
+
+      -l*)
+       if test "$arg" = "-lc"; then
+         case "$host" in
+         *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
+           # These systems don't actually have c library (as such)
+           continue
+           ;;
+         esac
+       elif test "$arg" = "-lm"; then
+         case "$host" in
+         *-*-cygwin* | *-*-beos*)
+           # These systems don't actually have math library (as such)
+           continue
+           ;;
+         esac
+       fi
+       deplibs="$deplibs $arg"
+       ;;
+
+      -module)
+       module=yes
+       continue
+       ;;
+
+      -no-undefined)
+       allow_undefined=no
+       continue
+       ;;
+
+      -o) prev=output ;;
+
+      -release)
+       prev=release
+       continue
+       ;;
+
+      -rpath)
+       prev=rpath
+       continue
+       ;;
+
+      -R)
+       prev=xrpath
+       continue
+       ;;
+
+      -R*)
+       dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+       # We need an absolute path.
+       case "$dir" in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         $echo "$modename: only absolute run-paths are allowed" 1>&2
+         exit 1
+         ;;
+       esac
+       case "$xrpath " in
+       *" $dir "*) ;;
+       *) xrpath="$xrpath $dir" ;;
+       esac
+       continue
+       ;;
+
+      -static)
+       # If we have no pic_flag, then this is the same as -all-static.
+       if test -z "$pic_flag" && test -n "$link_static_flag"; then
+         compile_command="$compile_command $link_static_flag"
+         finalize_command="$finalize_command $link_static_flag"
+       fi
+       continue
+       ;;
+
+      -thread-safe)
+       thread_safe=yes
+       continue
+       ;;
+
+      -version-info)
+       prev=vinfo
+       continue
+       ;;
+
+      # Some other compiler flag.
+      -* | +*)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case "$arg" in
+       *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \   ]*|*]*)
+         arg="\"$arg\""
+         ;;
+       esac
+       ;;
+
+      *.o | *.obj | *.a | *.lib)
+       # A standard object.
+       objs="$objs $arg"
+       ;;
+
+      *.lo)
+       # A library object.
+       if test "$prev" = dlfiles; then
+         dlfiles="$dlfiles $arg"
+         if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then
+           prev=
+           continue
+         else
+           # If libtool objects are unsupported, then we need to preload.
+           prev=dlprefiles
+         fi
+       fi
+
+       if test "$prev" = dlprefiles; then
+         # Preload the old-style object.
+         dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"`
+         prev=
+       fi
+       libobjs="$libobjs $arg"
+       ;;
+
+      *.la)
+       # A libtool-controlled library.
+
+       dlname=
+       libdir=
+       library_names=
+       old_library=
+
+       # Check to see that this really is a libtool archive.
+       if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2
+         exit 1
+       fi
+
+       # If the library was installed with an old release of libtool,
+       # it will not redefine variable installed.
+       installed=yes
+
+       # Read the .la file
+       # If there is no directory component, then add one.
+       case "$arg" in
+       */* | *\\*) . $arg ;;
+       *) . ./$arg ;;
+       esac
+
+       # Get the name of the library we link against.
+       linklib=
+       for l in $old_library $library_names; do
+         linklib="$l"
+       done
+
+       if test -z "$linklib"; then
+         $echo "$modename: cannot find name of link library for \`$arg'" 1>&2
+         exit 1
+       fi
+
+       # Find the relevant object directory and library name.
+       name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'`
+
+       if test "X$installed" = Xyes; then
+         dir="$libdir"
+       else
+         dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+         if test "X$dir" = "X$arg"; then
+           dir="$objdir"
+         else
+           dir="$dir/$objdir"
+         fi
+       fi
+
+       if test -n "$dependency_libs"; then
+         # Extract -R and -L from dependency_libs
+         temp_deplibs=
+         for deplib in $dependency_libs; do
+           case "$deplib" in
+           -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+                case " $rpath $xrpath " in
+                *" $temp_xrpath "*) ;;
+                *) xrpath="$xrpath $temp_xrpath";;
+                esac;;
+           -L*) case "$compile_command $temp_deplibs " in
+                *" $deplib "*) ;;
+                *) temp_deplibs="$temp_deplibs $deplib";;
+                esac
+                temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+                case " $lib_search_path " in
+                *" $temp_dir "*) ;;
+                *) lib_search_path="$lib_search_path $temp_dir";;
+                esac
+                ;;
+           *) temp_deplibs="$temp_deplibs $deplib";;
+           esac
+         done
+         dependency_libs="$temp_deplibs"
+       fi
+
+       if test -z "$libdir"; then
+         # It is a libtool convenience library, so add in its objects.
+         convenience="$convenience $dir/$old_library"
+         old_convenience="$old_convenience $dir/$old_library"
+         deplibs="$deplibs$dependency_libs"
+         compile_command="$compile_command $dir/$old_library$dependency_libs"
+         finalize_command="$finalize_command $dir/$old_library$dependency_libs"
+         continue
+       fi
+
+       # This library was specified with -dlopen.
+       if test "$prev" = dlfiles; then
+         dlfiles="$dlfiles $arg"
+         if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then
+           # If there is no dlname, no dlopen support or we're linking statically,
+           # we need to preload.
+           prev=dlprefiles
+         else
+           # We should not create a dependency on this library, but we
+           # may need any libraries it requires.
+           compile_command="$compile_command$dependency_libs"
+           finalize_command="$finalize_command$dependency_libs"
+           prev=
+           continue
+         fi
+       fi
+
+       # The library was specified with -dlpreopen.
+       if test "$prev" = dlprefiles; then
+         # Prefer using a static library (so that no silly _DYNAMIC symbols
+         # are required to link).
+         if test -n "$old_library"; then
+           dlprefiles="$dlprefiles $dir/$old_library"
+         else
+           dlprefiles="$dlprefiles $dir/$linklib"
+         fi
+         prev=
+       fi
+
+       if test -n "$library_names" &&
+          { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+         link_against_libtool_libs="$link_against_libtool_libs $arg"
+         if test -n "$shlibpath_var"; then
+           # Make sure the rpath contains only unique directories.
+           case "$temp_rpath " in
+           *" $dir "*) ;;
+           *) temp_rpath="$temp_rpath $dir" ;;
+           esac
+         fi
+
+         # We need an absolute path.
+         case "$dir" in
+         [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+         *)
+           absdir=`cd "$dir" && pwd`
+           if test -z "$absdir"; then
+             $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+             $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+             absdir="$dir"
+           fi
+           ;;
+         esac
+         
+         # This is the magic to use -rpath.
+         # Skip directories that are in the system default run-time
+         # search path, unless they have been requested with -R.
+         case " $sys_lib_dlsearch_path " in
+         *" $absdir "*) ;;
+         *)
+           case "$compile_rpath " in
+           *" $absdir "*) ;;
+           *) compile_rpath="$compile_rpath $absdir" 
+           esac
+           ;;
+         esac
+
+         case " $sys_lib_dlsearch_path " in
+         *" $libdir "*) ;;
+         *)
+           case "$finalize_rpath " in
+           *" $libdir "*) ;;
+           *) finalize_rpath="$finalize_rpath $libdir"
+           esac
+           ;;
+         esac
+
+         lib_linked=yes
+         case "$hardcode_action" in
+         immediate | unsupported)
+           if test "$hardcode_direct" = no; then
+             compile_command="$compile_command $dir/$linklib"
+             deplibs="$deplibs $dir/$linklib"
+             case "$host" in
+             *-*-cygwin* | *-*-mingw* | *-*-os2*)
+               dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
+               if test -n "$dllsearchpath"; then
+                 dllsearchpath="$dllsearchpath:$dllsearchdir"
+               else
+                 dllsearchpath="$dllsearchdir"
+               fi
+               ;;
+             esac
+           elif test "$hardcode_minus_L" = no; then
+             case "$host" in
+             *-*-sunos*)
+               compile_shlibpath="$compile_shlibpath$dir:"
+               ;;
+             esac
+             case "$compile_command " in
+             *" -L$dir "*) ;;
+             *) compile_command="$compile_command -L$dir";;
+             esac
+             compile_command="$compile_command -l$name"
+             deplibs="$deplibs -L$dir -l$name"
+           elif test "$hardcode_shlibpath_var" = no; then
+             case ":$compile_shlibpath:" in
+             *":$dir:"*) ;;
+             *) compile_shlibpath="$compile_shlibpath$dir:";;
+             esac
+             compile_command="$compile_command -l$name"
+             deplibs="$deplibs -l$name"
+           else
+             lib_linked=no
+           fi
+           ;;
+
+         relink)
+           if test "$hardcode_direct" = yes; then
+             compile_command="$compile_command $absdir/$linklib"
+             deplibs="$deplibs $absdir/$linklib"
+           elif test "$hardcode_minus_L" = yes; then
+             case "$compile_command " in
+             *" -L$absdir "*) ;;
+             *) compile_command="$compile_command -L$absdir";;
+             esac
+             compile_command="$compile_command -l$name"
+             deplibs="$deplibs -L$absdir -l$name"
+           elif test "$hardcode_shlibpath_var" = yes; then
+             case ":$compile_shlibpath:" in
+             *":$absdir:"*) ;;
+             *) compile_shlibpath="$compile_shlibpath$absdir:";;
+             esac
+             compile_command="$compile_command -l$name"
+             deplibs="$deplibs -l$name"
+           else
+             lib_linked=no
+           fi
+           ;;
+
+         *)
+           lib_linked=no
+           ;;
+         esac
+
+         if test "$lib_linked" != yes; then
+           $echo "$modename: configuration error: unsupported hardcode properties"
+           exit 1
+         fi
+
+         # Finalize command for both is simple: just hardcode it.
+         if test "$hardcode_direct" = yes; then
+           finalize_command="$finalize_command $libdir/$linklib"
+         elif test "$hardcode_minus_L" = yes; then
+           case "$finalize_command " in
+           *" -L$libdir "*) ;;
+           *) finalize_command="$finalize_command -L$libdir";;
+           esac
+           finalize_command="$finalize_command -l$name"
+         elif test "$hardcode_shlibpath_var" = yes; then
+           case ":$finalize_shlibpath:" in
+           *":$libdir:"*) ;;
+           *) finalize_shlibpath="$finalize_shlibpath$libdir:";;
+           esac
+           finalize_command="$finalize_command -l$name"
+         else
+           # We cannot seem to hardcode it, guess we'll fake it.
+           case "$finalize_command " in
+           *" -L$dir "*) ;;
+           *) finalize_command="$finalize_command -L$libdir";;
+           esac
+           finalize_command="$finalize_command -l$name"
+         fi
+       else
+         # Transform directly to old archives if we don't build new libraries.
+         if test -n "$pic_flag" && test -z "$old_library"; then
+           $echo "$modename: cannot find static library for \`$arg'" 1>&2
+           exit 1
+         fi
+
+         # Here we assume that one of hardcode_direct or hardcode_minus_L
+         # is not unsupported.  This is valid on all known static and
+         # shared platforms.
+         if test "$hardcode_direct" != unsupported; then
+           test -n "$old_library" && linklib="$old_library"
+           compile_command="$compile_command $dir/$linklib"
+           finalize_command="$finalize_command $dir/$linklib"
+         else
+           case "$compile_command " in
+           *" -L$dir "*) ;;
+           *) compile_command="$compile_command -L$dir";;
+           esac
+           compile_command="$compile_command -l$name"
+           case "$finalize_command " in
+           *" -L$dir "*) ;;
+           *) finalize_command="$finalize_command -L$dir";;
+           esac
+           finalize_command="$finalize_command -l$name"
+         fi
+       fi
+
+       # Add in any libraries that this one depends upon.
+       compile_command="$compile_command$dependency_libs"
+       finalize_command="$finalize_command$dependency_libs"
+       continue
+       ;;
+
+      # Some other compiler argument.
+      *)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case "$arg" in
+       *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \   ]*|*]*)
+         arg="\"$arg\""
+         ;;
+       esac
+       ;;
+      esac
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+       compile_command="$compile_command $arg"
+       finalize_command="$finalize_command $arg"
+      fi
+    done
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      compile_command="$compile_command $arg"
+      finalize_command="$finalize_command $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+    libobjs_save="$libobjs"
+
+    case "$output" in
+    "")
+      $echo "$modename: you must specify an output file" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+      ;;
+
+    *.a | *.lib)
+      if test -n "$link_against_libtool_libs"; then
+       $echo "$modename: error: cannot link libtool libraries into archives" 1>&2
+       exit 1
+      fi
+
+      if test -n "$deplibs"; then
+       $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+       $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+       $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+       $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+      fi
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      ;;
+
+    *.la)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case "$outputname" in
+      lib*)
+       name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+       eval libname=\"$libname_spec\"
+       ;;
+      *)
+       if test "$module" = no; then
+         $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+       fi
+       if test "$need_lib_prefix" != no; then
+         # Add the "lib" prefix for modules if required
+         name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+         eval libname=\"$libname_spec\"
+       else
+         libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+       fi
+       ;;
+      esac
+
+      output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+      if test "X$output_objdir" = "X$output"; then
+       output_objdir="$objdir"
+      else
+       output_objdir="$output_objdir/$objdir"
+      fi
+
+      if test -n "$objs"; then
+       $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1
+       exit 1
+      fi
+
+      # How the heck are we supposed to write a wrapper for a shared library?
+      if test -n "$link_against_libtool_libs"; then
+        $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2
+        exit 1
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2
+      fi
+
+      set dummy $rpath
+      if test $# -gt 2; then
+       $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+      fi
+      install_libdir="$2"
+
+      oldlibs=
+      if test -z "$rpath"; then
+       if test "$build_libtool_libs" = yes; then
+         # Building a libtool convenience library.
+         libext=al
+         oldlibs="$output_objdir/$libname.$libext $oldlibs"
+         build_libtool_libs=convenience
+         build_old_libs=yes
+       fi
+       dependency_libs="$deplibs"
+
+       if test -n "$vinfo"; then
+         $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
+       fi
+
+       if test -n "$release"; then
+         $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+       fi
+      else
+
+       # Parse the version information argument.
+       IFS="${IFS=     }"; save_ifs="$IFS"; IFS=':'
+       set dummy $vinfo 0 0 0
+       IFS="$save_ifs"
+
+       if test -n "$8"; then
+         $echo "$modename: too many parameters to \`-version-info'" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+       fi
+
+       current="$2"
+       revision="$3"
+       age="$4"
+
+       # Check that each of the things are valid numbers.
+       case "$current" in
+       0 | [1-9] | [1-9][0-9]*) ;;
+       *)
+         $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit 1
+         ;;
+       esac
+
+       case "$revision" in
+       0 | [1-9] | [1-9][0-9]*) ;;
+       *)
+         $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit 1
+         ;;
+       esac
+
+       case "$age" in
+       0 | [1-9] | [1-9][0-9]*) ;;
+       *)
+         $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit 1
+         ;;
+       esac
+
+       if test $age -gt $current; then
+         $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+         $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+         exit 1
+       fi
+
+       # Calculate the version variables.
+       major=
+       versuffix=
+       verstring=
+       case "$version_type" in
+       none) ;;
+
+       irix)
+         major=`expr $current - $age + 1`
+         versuffix="$major.$revision"
+         verstring="sgi$major.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$revision
+         while test $loop != 0; do
+           iface=`expr $revision - $loop`
+           loop=`expr $loop - 1`
+           verstring="sgi$major.$iface:$verstring"
+         done
+         ;;
+
+       linux)
+         major=.`expr $current - $age`
+         versuffix="$major.$age.$revision"
+         ;;
+
+       osf)
+         major=`expr $current - $age`
+         versuffix=".$current.$age.$revision"
+         verstring="$current.$age.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$age
+         while test $loop != 0; do
+           iface=`expr $current - $loop`
+           loop=`expr $loop - 1`
+           verstring="$verstring:${iface}.0"
+         done
+
+         # Make executables depend on our current version.
+         verstring="$verstring:${current}.0"
+         ;;
+
+       sunos)
+         major=".$current"
+         versuffix=".$current.$revision"
+         ;;
+
+       freebsd-aout)
+         major=".$current"
+         versuffix=".$current.$revision";
+         ;;
+
+       freebsd-elf)
+         major=".$current"
+         versuffix=".$current";
+         ;;
+
+       windows)
+         # Like Linux, but with '-' rather than '.', since we only
+         # want one extension on Windows 95.
+         major=`expr $current - $age`
+         versuffix="-$major-$age-$revision"
+         ;;
+
+       *)
+         $echo "$modename: unknown library version type \`$version_type'" 1>&2
+         echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+         exit 1
+         ;;
+       esac
+
+       # Clear the version info if we defaulted, and they specified a release.
+       if test -z "$vinfo" && test -n "$release"; then
+         major=
+         verstring="0.0"
+         if test "$need_version" = no; then
+           versuffix=
+         else
+           versuffix=".0.0"
+         fi
+       fi
+
+       # Remove version info from name if versioning should be avoided
+       if test "$avoid_version" = yes && test "$need_version" = no; then
+         major=
+         versuffix=
+         verstring=""
+       fi
+       
+       # Check to see if the archive will have undefined symbols.
+       if test "$allow_undefined" = yes; then
+         if test "$allow_undefined_flag" = unsupported; then
+           $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+           build_libtool_libs=no
+           build_old_libs=yes
+         fi
+       else
+         # Don't allow undefined symbols.
+         allow_undefined_flag="$no_undefined_flag"
+       fi
+
+       dependency_libs="$deplibs"
+       case "$host" in
+       *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
+         # these systems don't actually have a c library (as such)!
+         ;;
+       *)
+         # Add libc to deplibs on all other systems.
+         deplibs="$deplibs -lc"
+         ;;
+       esac
+      fi
+
+      # Create the output directory, or remove our outputs if we need to.
+      if test -d $output_objdir; then
+       $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
+       $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
+      else
+       $show "$mkdir $output_objdir"
+       $run $mkdir $output_objdir
+       status=$?
+       if test $status -ne 0 && test ! -d $output_objdir; then
+         exit $status
+       fi
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+       oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+       # Transform .lo files to .o files.
+       oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+      fi
+
+      if test "$build_libtool_libs" = yes; then
+       # Transform deplibs into only deplibs that can be linked in shared.
+       name_save=$name
+       libname_save=$libname
+       release_save=$release
+       versuffix_save=$versuffix
+       major_save=$major
+       # I'm not sure if I'm treating the release correctly.  I think
+       # release should show up in the -l (ie -lgmp5) so we don't want to
+       # add it in twice.  Is that correct?
+       release=""
+       versuffix=""
+       major=""
+       newdeplibs=
+       droppeddeps=no
+       case "$deplibs_check_method" in
+       pass_all)
+         # Don't check for shared/static.  Everything works.
+         # This might be a little naive.  We might want to check
+         # whether the library exists or not.  But this is on
+         # osf3 & osf4 and I'm not really sure... Just
+         # implementing what was already the behaviour.
+         newdeplibs=$deplibs
+         ;;
+       test_compile)
+         # This code stresses the "libraries are programs" paradigm to its
+         # limits. Maybe even breaks it.  We compile a program, linking it
+         # against the deplibs as a proxy for the library.  Then we can check
+         # whether they linked in statically or dynamically with ldd.
+         $rm conftest.c
+         cat > conftest.c <<EOF
+         int main() { return 0; }
+EOF
+         $rm conftest
+         $CC -o conftest conftest.c $deplibs
+         if test $? -eq 0 ; then
+           ldd_output=`ldd conftest`
+           for i in $deplibs; do
+             name="`expr $i : '-l\(.*\)'`"
+             # If $name is empty we are operating on a -L argument.
+             if test "$name" != "" ; then
+               libname=`eval \\$echo \"$libname_spec\"`
+               deplib_matches=`eval \\$echo \"$library_names_spec\"`
+               set dummy $deplib_matches
+               deplib_match=$2
+               if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                 newdeplibs="$newdeplibs $i"
+               else
+                 droppeddeps=yes
+                 echo
+                 echo "*** Warning: This library needs some functionality provided by $i."
+                 echo "*** I have the capability to make that library automatically link in when"
+                 echo "*** you link to this library.  But I can only do this if you have a"
+                 echo "*** shared version of the library, which you do not appear to have."
+               fi
+             else
+               newdeplibs="$newdeplibs $i"
+             fi
+           done
+         else
+           # Error occured in the first compile.  Let's try to salvage the situation:
+           # Compile a seperate program for each library.
+           for i in $deplibs; do
+             name="`expr $i : '-l\(.*\)'`"
+            # If $name is empty we are operating on a -L argument.
+             if test "$name" != "" ; then
+               $rm conftest
+               $CC -o conftest conftest.c $i
+               # Did it work?
+               if test $? -eq 0 ; then
+                 ldd_output=`ldd conftest`
+                 libname=`eval \\$echo \"$libname_spec\"`
+                 deplib_matches=`eval \\$echo \"$library_names_spec\"`
+                 set dummy $deplib_matches
+                 deplib_match=$2
+                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                   newdeplibs="$newdeplibs $i"
+                 else
+                   droppeddeps=yes
+                   echo
+                   echo "*** Warning: This library needs some functionality provided by $i."
+                   echo "*** I have the capability to make that library automatically link in when"
+                   echo "*** you link to this library.  But I can only do this if you have a"
+                   echo "*** shared version of the library, which you do not appear to have."
+                 fi
+               else
+                 droppeddeps=yes
+                 echo
+                 echo "*** Warning!  Library $i is needed by this library but I was not able to"
+                 echo "***  make it link in!  You will probably need to install it or some"
+                 echo "*** library that it depends on before this library will be fully"
+                 echo "*** functional.  Installing it before continuing would be even better."
+               fi
+             else
+               newdeplibs="$newdeplibs $i"
+             fi
+           done
+         fi
+         ;;
+       file_magic*)
+         set dummy $deplibs_check_method
+         file_magic_regex="`expr \"$deplibs_check_method\" : \"$2 \(.*\)\"`"
+         for a_deplib in $deplibs; do
+           name="`expr $a_deplib : '-l\(.*\)'`"
+           # If $name is empty we are operating on a -L argument.
+           if test "$name" != "" ; then
+             libname=`eval \\$echo \"$libname_spec\"`
+             for i in $lib_search_path; do
+                   potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+                   for potent_lib in $potential_libs; do
+                     # Follow soft links.
+                     if ls -lLd "$potent_lib" 2>/dev/null \
+                        | grep " -> " >/dev/null; then
+                       continue 
+                     fi
+                     # The statement above tries to avoid entering an
+                     # endless loop below, in case of cyclic links.
+                     # We might still enter an endless loop, since a link
+                     # loop can be closed while we follow links,
+                     # but so what?
+                     potlib="$potent_lib"
+                     while test -h "$potlib" 2>/dev/null; do
+                       potliblink=`ls -ld $potlib | sed 's/.* -> //'`
+                       case "$potliblink" in
+                       [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+                       *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+                       esac
+                     done
+                     if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+                        | sed 10q \
+                        | egrep "$file_magic_regex" > /dev/null; then
+                       newdeplibs="$newdeplibs $a_deplib"
+                       a_deplib=""
+                       break 2
+                     fi
+                   done
+             done
+             if test -n "$a_deplib" ; then
+               droppeddeps=yes
+               echo
+               echo "*** Warning: This library needs some functionality provided by $a_deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have."
+             fi
+           else
+             # Add a -L argument.
+             newdeplibs="$newdeplibs $a_deplib"
+           fi
+         done # Gone through all deplibs.
+         ;;
+       none | unknown | *)
+         newdeplibs=""
+         if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+              -e 's/ -[LR][^ ]*//g' -e 's/[    ]//g' |
+            grep . >/dev/null; then
+           echo
+           if test "X$deplibs_check_method" = "Xnone"; then
+             echo "*** Warning: inter-library dependencies are not supported in this platform."
+           else
+             echo "*** Warning: inter-library dependencies are not known to be supported."
+           fi
+           echo "*** All declared inter-library dependencies are being dropped."
+           droppeddeps=yes
+         fi
+         ;;
+       esac
+       versuffix=$versuffix_save
+       major=$major_save
+       release=$release_save
+       libname=$libname_save
+       name=$name_save
+
+       if test "$droppeddeps" = yes; then
+         if test "$module" = yes; then
+           echo
+           echo "*** Warning: libtool could not satisfy all declared inter-library"
+           echo "*** dependencies of module $libname.  Therefore, libtool will create"
+           echo "*** a static module, that should work as long as the dlopening"
+           echo "*** application is linked with the -dlopen flag."
+           if test -z "$global_symbol_pipe"; then
+             echo
+             echo "*** However, this would only work if libtool was able to extract symbol"
+             echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+             echo "*** not find such a program.  So, this module is probably useless."
+             echo "*** \`nm' from GNU binutils and a full rebuild may help."
+           fi
+           if test "$build_old_libs" = no; then
+             oldlibs="$output_objdir/$libname.$libext"
+             build_libtool_libs=module
+             build_old_libs=yes
+           else
+             build_libtool_libs=no
+           fi
+         else
+           echo "*** The inter-library dependencies that have been dropped here will be"
+           echo "*** automatically added whenever a program is linked with this library"
+           echo "*** or is declared to -dlopen it."
+         fi
+       fi
+       # Done checking deplibs!
+       deplibs=$newdeplibs
+      fi
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+      
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+       # Get the real and link names of the library.
+       eval library_names=\"$library_names_spec\"
+       set dummy $library_names
+       realname="$2"
+       shift; shift
+
+       if test -n "$soname_spec"; then
+         eval soname=\"$soname_spec\"
+       else
+         soname="$realname"
+       fi
+
+       lib="$output_objdir/$realname"
+       for link
+       do
+         linknames="$linknames $link"
+       done
+
+       # Ensure that we have .o objects for linkers which dislike .lo
+       # (e.g. aix) in case we are running --disable-static
+       for obj in $libobjs; do
+         xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+         if test "X$xdir" = "X$obj"; then
+           xdir="."
+         else
+           xdir="$xdir"
+         fi
+         baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+         oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
+         if test ! -f $xdir/$oldobj; then
+           $show "(cd $xdir && ${LN_S} $baseobj $oldobj)"
+           $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $?
+         fi
+       done
+
+       # Use standard objects if they are pic
+       test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+       # Prepare the list of exported symbols
+       if test -z "$export_symbols"; then
+         if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+           $show "generating symbol list for \`$libname.la'"
+           export_symbols="$output_objdir/$libname.exp"
+           $run $rm $export_symbols
+           eval cmds=\"$export_symbols_cmds\"
+           IFS="${IFS=         }"; save_ifs="$IFS"; IFS='~'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             $show "$cmd"
+             $run eval "$cmd" || exit $?
+           done
+           IFS="$save_ifs"
+           if test -n "$export_symbols_regex"; then
+             $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+             $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+             $run eval '$mv "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+       fi
+
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+       fi
+
+       if test -n "$convenience"; then
+         if test -n "$whole_archive_flag_spec"; then
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+         else
+           gentop="$output_objdir/${outputname}x"
+           $show "${rm}r $gentop"
+           $run ${rm}r "$gentop"
+           $show "mkdir $gentop"
+           $run mkdir "$gentop"
+           status=$?
+           if test $status -ne 0 && test ! -d "$gentop"; then
+             exit $status
+           fi
+           generated="$generated $gentop"
+
+           for xlib in $convenience; do
+             # Extract the objects.
+             case "$xlib" in
+             [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+             *) xabs=`pwd`"/$xlib" ;;
+             esac
+             xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+             xdir="$gentop/$xlib"
+
+             $show "${rm}r $xdir"
+             $run ${rm}r "$xdir"
+             $show "mkdir $xdir"
+             $run mkdir "$xdir"
+             status=$?
+             if test $status -ne 0 && test ! -d "$xdir"; then
+               exit $status
+             fi
+             $show "(cd $xdir && $AR x $xabs)"
+             $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+             libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
+           done
+         fi
+       fi
+
+       if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+         eval flag=\"$thread_safe_flag_spec\"
+         linkopts="$linkopts $flag"
+       fi
+
+       # Do each of the archive commands.
+       if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+         eval cmds=\"$archive_expsym_cmds\"
+       else
+         eval cmds=\"$archive_cmds\"
+       fi
+       IFS="${IFS=     }"; save_ifs="$IFS"; IFS='~'
+       for cmd in $cmds; do
+         IFS="$save_ifs"
+         $show "$cmd"
+         $run eval "$cmd" || exit $?
+       done
+       IFS="$save_ifs"
+
+       # Create links to the real library.
+       for linkname in $linknames; do
+         if test "$realname" != "$linkname"; then
+           $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+           $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+         fi
+       done
+
+       # If -module or -export-dynamic was specified, set the dlname.
+       if test "$module" = yes || test "$export_dynamic" = yes; then
+         # On all known operating systems, these are identical.
+         dlname="$soname"
+       fi
+      fi
+      ;;
+
+    *.lo | *.o | *.obj)
+      if test -n "$link_against_libtool_libs"; then
+       $echo "$modename: error: cannot link libtool libraries into objects" 1>&2
+       exit 1
+      fi
+
+      if test -n "$deplibs"; then
+       $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+       $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+       $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+      fi
+
+      case "$output" in
+      *.lo)
+       if test -n "$objs"; then
+         $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+         exit 1
+       fi
+       libobj="$output"
+       obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+       ;;
+      *)
+       libobj=
+       obj="$output"
+       ;;
+      esac
+
+      # Delete the old objects.
+      $run $rm $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec
+      wl= 
+
+      if test -n "$convenience"; then
+       if test -n "$whole_archive_flag_spec"; then
+         eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+       else
+         gentop="$output_objdir/${obj}x"
+         $show "${rm}r $gentop"
+         $run ${rm}r "$gentop"
+         $show "mkdir $gentop"
+         $run mkdir "$gentop"
+         status=$?
+         if test $status -ne 0 && test ! -d "$gentop"; then
+           exit $status
+         fi
+         generated="$generated $gentop"
+
+         for xlib in $convenience; do
+           # Extract the objects.
+           case "$xlib" in
+           [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+           *) xabs=`pwd`"/$xlib" ;;
+           esac
+           xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+           xdir="$gentop/$xlib"
+
+           $show "${rm}r $xdir"
+           $run ${rm}r "$xdir"
+           $show "mkdir $xdir"
+           $run mkdir "$xdir"
+           status=$?
+           if test $status -ne 0 && test ! -d "$xdir"; then
+             exit $status
+           fi
+           $show "(cd $xdir && $AR x $xabs)"
+           $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+           reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
+         done
+       fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs"
+
+      output="$obj"
+      eval cmds=\"$reload_cmds\"
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+       IFS="$save_ifs"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+       if test -n "$gentop"; then
+         $show "${rm}r $gentop"
+         $run ${rm}r $gentop
+       fi
+
+       exit 0
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+       if test -n "$gentop"; then
+         $show "${rm}r $gentop"
+         $run ${rm}r $gentop
+       fi
+
+       # Create an invalid libtool object if no PIC, so that we don't
+       # accidentally link it into a program.
+       $show "echo timestamp > $libobj"
+       $run eval "echo timestamp > $libobj" || exit $?
+       exit 0
+      fi
+
+      if test -n "$pic_flag"; then
+       # Only do commands if we really have different PIC objects.
+       reload_objs="$libobjs $reload_conv_objs"
+       output="$libobj"
+       eval cmds=\"$reload_cmds\"
+       IFS="${IFS=     }"; save_ifs="$IFS"; IFS='~'
+       for cmd in $cmds; do
+         IFS="$save_ifs"
+         $show "$cmd"
+         $run eval "$cmd" || exit $?
+       done
+       IFS="$save_ifs"
+      else
+       # Just create a symlink.
+       $show $rm $libobj
+       $run $rm $libobj
+       xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
+       if test "X$xdir" = "X$libobj"; then
+         xdir="."
+       else
+         xdir="$xdir"
+       fi
+       baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
+       oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
+       $show "(cd $xdir && $LN_S $oldobj $baseobj)"
+       $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $?
+      fi
+
+      if test -n "$gentop"; then
+       $show "${rm}r $gentop"
+       $run ${rm}r $gentop
+      fi
+
+      exit 0
+      ;;
+
+    # Anything else should be a program.
+    *)
+      if test -n "$vinfo"; then
+       $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+      fi
+
+      if test -n "$release"; then
+       $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+      fi
+
+      if test "$preload" = yes; then
+       if test "$dlopen" = unknown && test "$dlopen_self" = unknown &&
+          test "$dlopen_self_static" = unknown; then
+         $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+       fi 
+      fi
+    
+      if test -n "$rpath$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       for libdir in $rpath $xrpath; do
+         # This is the magic to use -rpath.
+         case "$compile_rpath " in
+         *" $libdir "*) ;;
+         *) compile_rpath="$compile_rpath $libdir" ;;
+         esac
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) finalize_rpath="$finalize_rpath $libdir" ;;
+         esac
+       done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           rpath="$rpath $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$perm_rpath " in
+         *" $libdir "*) ;;
+         *) perm_rpath="$perm_rpath $libdir" ;;
+         esac
+       fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           rpath="$rpath $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$finalize_perm_rpath " in
+         *" $libdir "*) ;;
+         *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+         esac
+       fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+      if test "X$output_objdir" = "X$output"; then
+       output_objdir="$objdir"
+      else
+       output_objdir="$output_objdir/$objdir"
+      fi
+
+      # Create the binary in the object directory, then wrap it.
+      if test ! -d $output_objdir; then
+       $show "$mkdir $output_objdir"
+       $run $mkdir $output_objdir
+       status=$?
+       if test $status -ne 0 && test ! -d $output_objdir; then
+         exit $status
+       fi
+      fi
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+       # Transform all the library objects into standard objects.
+       compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+       finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+      fi
+
+      dlsyms=
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       if test -n "$NM" && test -n "$global_symbol_pipe"; then
+         dlsyms="${outputname}S.c"
+       else
+         $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+       fi
+      fi
+
+      if test -n "$dlsyms"; then
+       case "$dlsyms" in
+       "") ;;
+       *.c)
+         # Discover the nlist of each of the dlfiles.
+         nlist="$output_objdir/${outputname}.nm"
+
+         $show "$rm $nlist ${nlist}S ${nlist}T"
+         $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+         # Parse the name list into a source file.
+         $show "creating $output_objdir/$dlsyms"
+
+         test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+         if test "$dlself" = yes; then
+           $show "generating symbol list for \`$output'"
+
+           test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+           # Add our own program objects to the symbol list.
+           progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+           for arg in $progfiles; do
+             $show "extracting global C symbols from \`$arg'"
+             $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+           done
+
+           if test -n "$exclude_expsyms"; then
+             $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+             $run eval '$mv "$nlist"T "$nlist"'
+           fi
+           
+           if test -n "$export_symbols_regex"; then
+             $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+             $run eval '$mv "$nlist"T "$nlist"'
+           fi
+
+           # Prepare the list of exported symbols
+           if test -z "$export_symbols"; then
+             export_symbols="$output_objdir/$output.exp"
+             $run $rm $export_symbols
+             $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+           else
+             $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+             $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+             $run eval 'mv "$nlist"T "$nlist"'
+           fi
+         fi
+
+         for arg in $dlprefiles; do
+           $show "extracting global C symbols from \`$arg'"
+           name=`echo "$arg" | sed -e 's%^.*/%%'`
+           $run eval 'echo ": $name " >> "$nlist"'
+           $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+         done
+
+         if test -z "$run"; then
+           # Make sure we have at least an empty file.
+           test -f "$nlist" || : > "$nlist"
+
+           if test -n "$exclude_expsyms"; then
+             egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+             $mv "$nlist"T "$nlist"
+           fi
+
+           # Try sorting and uniquifying the output.
+           if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
+             :
+           else
+             grep -v "^: " < "$nlist" > "$nlist"S
+           fi
+
+           if test -f "$nlist"S; then
+             eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+           else
+             echo '/* NONE */' >> "$output_objdir/$dlsyms"
+           fi
+
+           $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+           sed -n -e 's/^: \([^ ]*\) $/  {\"\1\", (lt_ptr_t) 0},/p' \
+               -e 's/^. \([^ ]*\) \([^ ]*\)$/  {"\2", (lt_ptr_t) \&\2},/p' \
+                 < "$nlist" >> "$output_objdir/$dlsyms"
+
+           $echo >> "$output_objdir/$dlsyms" "\
+  {0, (lt_ptr_t) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+         fi
+
+         pic_flag_for_symtable=
+         case "$host" in
+         # compiling the symbol table file with pic_flag works around
+         # a FreeBSD bug that causes programs to crash when -lm is
+         # linked before any other PIC object.  But we must not use
+         # pic_flag when linking with -static.  The problem exists in
+         # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+         *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)\r
+           case "$compile_command " in
+           *" -static "*) ;;
+           *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";;
+           esac;;
+         *-*-hpux*)
+           case "$compile_command " in
+           *" -static "*) ;;
+           *) pic_flag_for_symtable=" $pic_flag -DPIC";;
+           esac
+         esac
+
+         # Now compile the dynamic symbol file.
+         $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+         $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+         # Clean up the generated files.
+         $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+         $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+         # Transform the symbol file into the correct name.
+         compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+         finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+         ;;
+       *)
+         $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+         exit 1
+         ;;
+       esac
+      else
+       # We keep going just in case the user didn't refer to
+       # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+       # really was required.
+
+       # Nullify the symbol file.
+       compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+       finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then
+       # Replace the output file specification.
+       compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+       link_command="$compile_command$compile_rpath"
+
+       # We have no uninstalled library dependencies, so finalize right now.
+       $show "$link_command"
+       $run eval "$link_command"
+       status=$?
+       
+       # Delete the generated files.
+       if test -n "$dlsyms"; then
+         $show "$rm $output_objdir/${outputname}S.${objext}"
+         $run $rm "$output_objdir/${outputname}S.${objext}"
+       fi
+
+       exit $status
+      fi
+
+      if test -n "$shlibpath_var"; then
+       # We should set the shlibpath_var
+       rpath=
+       for dir in $temp_rpath; do
+         case "$dir" in
+         [\\/]* | [A-Za-z]:[\\/]*)
+           # Absolute path.
+           rpath="$rpath$dir:"
+           ;;
+         *)
+           # Relative path: add a thisdir entry.
+           rpath="$rpath\$thisdir/$dir:"
+           ;;
+         esac
+       done
+       temp_rpath="$rpath"
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+       compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+       finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+       if test -n "$perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $perm_rpath; do
+           rpath="$rpath$dir:"
+         done
+         compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+       if test -n "$finalize_perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $finalize_perm_rpath; do
+           rpath="$rpath$dir:"
+         done
+         finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+      fi
+
+      if test "$hardcode_action" = relink; then
+       # Fast installation is not supported
+       link_command="$compile_var$compile_command$compile_rpath"
+       relink_command="$finalize_var$finalize_command$finalize_rpath"
+       
+       $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+       $echo "$modename: \`$output' will be relinked during installation" 1>&2
+      else
+       if test "$fast_install" != no; then
+         link_command="$finalize_var$compile_command$finalize_rpath"
+         if test "$fast_install" = yes; then
+           relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+         else
+           # fast_install is set to needless
+           relink_command=
+         fi
+       else
+         link_command="$compile_var$compile_command$compile_rpath"
+         relink_command="$finalize_var$finalize_command$finalize_rpath"
+       fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+      
+      # Delete the old output files.
+      $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      $show "$link_command"
+      $run eval "$link_command" || exit $?
+
+      # Now create the wrapper script.
+      $show "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+       relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Quote $echo for shipping.
+      if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
+       case "$0" in
+       [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
+       *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+       esac
+       qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+      else
+       qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if our run command is non-null.
+      if test -z "$run"; then
+       # win32 will think the script is a binary if it has
+       # a .exe suffix, so we strip it off here.
+       case $output in
+         *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
+       esac
+       $rm $output
+       trap "$rm $output; exit 1" 1 2 15
+
+       $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variable:
+  link_against_libtool_libs='$link_against_libtool_libs'
+else
+  # When we are sourced in execute mode, \$file and \$echo are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    echo=\"$qecho\"
+    file=\"\$0\"
+    # Make sure echo works.
+    if test \"X\$1\" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+      # Yippee, \$echo works!
+      :
+    else
+      # Restart under the correct shell, and then maybe \$echo will work.
+      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+    fi
+  fi\
+"
+       $echo >> $output "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+       if test "$fast_install" = yes; then
+         echo >> $output "\
+  program=lt-'$outputname'
+  progdir=\"\$thisdir/$objdir\"
+  
+  if test ! -f \"\$progdir/\$program\" || \\
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $mkdir \"\$progdir\"
+    else
+      $rm \"\$progdir/\$file\"
+    fi"
+
+         echo >> $output "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if (cd \"\$thisdir\" && eval \$relink_command); then :
+      else
+       $rm \"\$progdir/\$file\"
+       exit 1
+      fi
+    fi
+
+    $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $rm \"\$progdir/\$program\";
+      $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $rm \"\$progdir/\$file\"
+  fi"
+       else
+         echo >> $output "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+       fi
+
+       echo >> $output "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+       # Export our shlibpath_var if we have one.
+       if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+         $echo >> $output "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+       fi
+
+       # fixup the dll searchpath if we need to.
+       if test -n "$dllsearchpath"; then
+         $echo >> $output "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+       fi
+
+       $echo >> $output "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+"
+       case $host in
+       *-*-cygwin* | *-*-mingw | *-*-os2*)
+         # win32 systems need to use the prog path for dll
+         # lookup to work
+         $echo >> $output "\
+      exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+         ;;
+       *)
+         $echo >> $output "\
+      # Export the path to the program.
+      PATH=\"\$progdir:\$PATH\"
+      export PATH
+
+      exec \$program \${1+\"\$@\"}
+"
+         ;;
+       esac
+       $echo >> $output "\
+      \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+      exit 1
+    fi
+  else
+    # The program doesn't exist.
+    \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+    \$echo \"This script is just a wrapper for \$program.\" 1>&2
+    echo \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+       chmod +x $output
+      fi
+      exit 0
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+       oldobjs="$libobjs_save"
+       addlibs="$convenience"
+       build_libtool_libs=no
+      else
+       if test "$build_libtool_libs" = module; then
+         oldobjs="$libobjs_save"
+         build_libtool_libs=no
+       else
+         oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`
+       fi
+       addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+       gentop="$output_objdir/${outputname}x"
+       $show "${rm}r $gentop"
+       $run ${rm}r "$gentop"
+       $show "mkdir $gentop"
+       $run mkdir "$gentop"
+       status=$?
+       if test $status -ne 0 && test ! -d "$gentop"; then
+         exit $status
+       fi
+       generated="$generated $gentop"
+         
+       # Add in members from convenience archives.
+       for xlib in $addlibs; do
+         # Extract the objects.
+         case "$xlib" in
+         [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+         *) xabs=`pwd`"/$xlib" ;;
+         esac
+         xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+         xdir="$gentop/$xlib"
+
+         $show "${rm}r $xdir"
+         $run ${rm}r "$xdir"
+         $show "mkdir $xdir"
+         $run mkdir "$xdir"
+         status=$?
+         if test $status -ne 0 && test ! -d "$xdir"; then
+           exit $status
+         fi
+         $show "(cd $xdir && $AR x $xabs)"
+         $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+         oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+       done
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       eval cmds=\"$old_archive_from_new_cmds\"
+      else
+       # Ensure that we have .o objects in place in case we decided
+       # not to build a shared library, and have fallen back to building
+       # static libs even though --disable-static was passed!
+       for oldobj in $oldobjs; do
+         if test ! -f $oldobj; then
+           xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'`
+           if test "X$xdir" = "X$oldobj"; then
+             xdir="."
+           else
+             xdir="$xdir"
+           fi
+           baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'`
+           obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
+           $show "(cd $xdir && ${LN_S} $obj $baseobj)"
+           $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $?
+         fi
+       done
+
+       eval cmds=\"$old_archive_cmds\"
+      fi
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+       IFS="$save_ifs"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$generated"; then
+      $show "${rm}r$generated"
+      $run ${rm}r$generated
+    fi
+
+    # Now create the libtool archive.
+    case "$output" in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      $show "creating $output"
+
+      if test -n "$xrpath"; then
+       temp_xrpath=
+       for libdir in $xrpath; do
+         temp_xrpath="$temp_xrpath -R$libdir"
+       done
+       dependency_libs="$temp_xrpath $dependency_libs"
+      fi
+
+      # Only create the output if not a dry run.
+      if test -z "$run"; then
+       for installed in no yes; do
+         if test "$installed" = yes; then
+           if test -z "$install_libdir"; then
+             break
+           fi
+           output="$output_objdir/$outputname"i
+         fi
+         $rm $output
+         $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$dlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'\
+"
+       done
+      fi
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+      $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $?
+      ;;
+    esac
+    exit 0
+    ;;
+
+  # libtool install mode
+  install)
+    modename="$modename: install"
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then
+      # Aesthetically quote it.
+      arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+      case "$arg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$arg "
+      arg="$1"
+      shift
+    else
+      install_prog=
+      arg="$nonopt"
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+    case "$arg" in
+    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \      ]*|*]*)
+      arg="\"$arg\""
+      ;;
+    esac
+    install_prog="$install_prog$arg"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+       files="$files $dest"
+       dest="$arg"
+       continue
+      fi
+
+      case "$arg" in
+      -d) isdir=yes ;;
+      -f) prev="-f" ;;
+      -g) prev="-g" ;;
+      -m) prev="-m" ;;
+      -o) prev="-o" ;;
+      -s)
+       stripme=" -s"
+       continue
+       ;;
+      -*) ;;
+
+      *)
+       # If the previous option needed an argument, then skip it.
+       if test -n "$prev"; then
+         prev=
+       else
+         dest="$arg"
+         continue
+       fi
+       ;;
+      esac
+
+      # Aesthetically quote the argument.
+      arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+      case "$arg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$install_prog $arg"
+    done
+
+    if test -z "$install_prog"; then
+      $echo "$modename: you must specify an install program" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prev' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+       $echo "$modename: no file or destination specified" 1>&2
+      else
+       $echo "$modename: you must specify a destination" 1>&2
+      fi
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    # Strip any trailing slash from the destination.
+    dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$destdir" = "X$dest" && destdir=.
+      destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files
+      if test $# -gt 2; then
+       $echo "$modename: \`$dest' is not a directory" 1>&2
+       $echo "$help" 1>&2
+       exit 1
+      fi
+    fi
+    case "$destdir" in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+       case "$file" in
+       *.lo) ;;
+       *)
+         $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+         ;;
+       esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case "$file" in
+      *.a | *.lib)
+       # Do the static libraries later.
+       staticlibs="$staticlibs $file"
+       ;;
+
+      *.la)
+       # Check to see that this really is a libtool archive.
+       if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+       fi
+
+       library_names=
+       old_library=
+       # If there is no directory component, then add one.
+       case "$file" in
+       */* | *\\*) . $file ;;
+       *) . ./$file ;;
+       esac
+
+       # Add the libdir to current_libdirs if it is the destination.
+       if test "X$destdir" = "X$libdir"; then
+         case "$current_libdirs " in
+         *" $libdir "*) ;;
+         *) current_libdirs="$current_libdirs $libdir" ;;
+         esac
+       else
+         # Note the libdir as a future libdir.
+         case "$future_libdirs " in
+         *" $libdir "*) ;;
+         *) future_libdirs="$future_libdirs $libdir" ;;
+         esac
+       fi
+
+       dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/"
+       test "X$dir" = "X$file/" && dir=
+       dir="$dir$objdir"
+
+       # See the names of the shared library.
+       set dummy $library_names
+       if test -n "$2"; then
+         realname="$2"
+         shift
+         shift
+
+         # Install the shared library and build the symlinks.
+         $show "$install_prog $dir/$realname $destdir/$realname"
+         $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $?
+
+         if test $# -gt 0; then
+           # Delete the old symlinks, and create new ones.
+           for linkname
+           do
+             if test "$linkname" != "$realname"; then
+               $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+               $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+             fi
+           done
+         fi
+
+         # Do each command in the postinstall commands.
+         lib="$destdir/$realname"
+         eval cmds=\"$postinstall_cmds\"
+         IFS="${IFS=   }"; save_ifs="$IFS"; IFS='~'
+         for cmd in $cmds; do
+           IFS="$save_ifs"
+           $show "$cmd"
+           $run eval "$cmd" || exit $?
+         done
+         IFS="$save_ifs"
+       fi
+
+       # Install the pseudo-library for information purposes.
+       name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+       instname="$dir/$name"i
+       $show "$install_prog $instname $destdir/$name"
+       $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+       # Maybe install the static library, too.
+       test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+       ;;
+
+      *.lo)
+       # Install (i.e. copy) a libtool object.
+
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+         destfile="$destdir/$destfile"
+       fi
+
+       # Deduce the name of the destination old-style object file.
+       case "$destfile" in
+       *.lo)
+         staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+         ;;
+       *.o | *.obj)
+         staticdest="$destfile"
+         destfile=
+         ;;
+       *)
+         $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+         ;;
+       esac
+
+       # Install the libtool object if requested.
+       if test -n "$destfile"; then
+         $show "$install_prog $file $destfile"
+         $run eval "$install_prog $file $destfile" || exit $?
+       fi
+
+       # Install the old object if enabled.
+       if test "$build_old_libs" = yes; then
+         # Deduce the name of the old-style object file.
+         staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+         $show "$install_prog $staticobj $staticdest"
+         $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+       fi
+       exit 0
+       ;;
+
+      *)
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+         destfile="$destdir/$destfile"
+       fi
+
+       # Do a test to see if this is really a libtool program.
+       if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         link_against_libtool_libs=
+         relink_command=
+
+         # If there is no directory component, then add one.
+         case "$file" in
+         */* | *\\*) . $file ;;
+         *) . ./$file ;;
+         esac
+
+         # Check the variables that should have been set.
+         if test -z "$link_against_libtool_libs"; then
+           $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
+           exit 1
+         fi
+
+         finalize=yes
+         for lib in $link_against_libtool_libs; do
+           # Check to see that each library is installed.
+           libdir=
+           if test -f "$lib"; then
+             # If there is no directory component, then add one.
+             case "$lib" in
+             */* | *\\*) . $lib ;;
+             *) . ./$lib ;;
+             esac
+           fi
+           libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`"
+           if test -n "$libdir" && test ! -f "$libfile"; then
+             $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+             finalize=no
+           fi
+         done
+
+         outputname=
+         if test "$fast_install" = no && test -n "$relink_command"; then
+           if test "$finalize" = yes && test -z "$run"; then
+             tmpdir="/tmp"
+             test -n "$TMPDIR" && tmpdir="$TMPDIR"
+             tmpdir="$tmpdir/libtool-$$"
+             if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
+             else
+               $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+               continue
+             fi
+             outputname="$tmpdir/$file"
+             # Replace the output file specification.
+             relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+             $show "$relink_command"
+             if $run eval "$relink_command"; then :
+             else
+               $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+               ${rm}r "$tmpdir"
+               continue
+             fi
+             file="$outputname"
+           else
+             $echo "$modename: warning: cannot relink \`$file'" 1>&2
+           fi
+         else
+           # Install the binary that we compiled earlier.
+           file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+         fi
+       fi
+
+       $show "$install_prog$stripme $file $destfile"
+       $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+       test -n "$outputname" && ${rm}r "$tmpdir"
+       ;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      $show "$install_prog $file $oldlib"
+      $run eval "$install_prog \$file \$oldlib" || exit $?
+
+      # Do each command in the postinstall commands.
+      eval cmds=\"$old_postinstall_cmds\"
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+       IFS="$save_ifs"
+       $show "$cmd"
+       $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$future_libdirs"; then
+      $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+    fi
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      test -n "$run" && current_libdirs=" -n$current_libdirs"
+      exec $SHELL $0 --finish$current_libdirs
+      exit 1
+    fi
+
+    exit 0
+    ;;
+
+  # libtool finish mode
+  finish)
+    modename="$modename: finish"
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+       libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+       if test -n "$finish_cmds"; then
+         # Do each command in the finish commands.
+         eval cmds=\"$finish_cmds\"
+         IFS="${IFS=   }"; save_ifs="$IFS"; IFS='~'
+         for cmd in $cmds; do
+           IFS="$save_ifs"
+           $show "$cmd"
+           $run eval "$cmd" || admincmds="$admincmds
+       $cmd"
+         done
+         IFS="$save_ifs"
+       fi
+       if test -n "$finish_eval"; then
+         # Do the single finish_eval.
+         eval cmds=\"$finish_eval\"
+         $run eval "$cmds" || admincmds="$admincmds
+       $cmds"
+       fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    test "$show" = : && exit 0
+
+    echo "----------------------------------------------------------------------"
+    echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      echo "   $libdir"
+    done
+    echo
+    echo "If you ever happen to want to link against installed libraries"
+    echo "in a given directory, LIBDIR, you must either use libtool, and"
+    echo "specify the full pathname of the library, or use \`-LLIBDIR'"
+    echo "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      echo "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      echo "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    echo
+    echo "See any operating system documentation about shared libraries for"
+    echo "more information, such as the ld(1) and ld.so(8) manual pages."
+    echo "----------------------------------------------------------------------"
+    exit 0
+    ;;
+
+  # libtool execute mode
+  execute)
+    modename="$modename: execute"
+
+    # The first argument is the command name.
+    cmd="$nonopt"
+    if test -z "$cmd"; then
+      $echo "$modename: you must specify a COMMAND" 1>&2
+      $echo "$help"
+      exit 1
+    fi
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      if test ! -f "$file"; then
+       $echo "$modename: \`$file' is not a file" 1>&2
+       $echo "$help" 1>&2
+       exit 1
+      fi
+
+      dir=
+      case "$file" in
+      *.la)
+       # Check to see that this really is a libtool archive.
+       if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+       else
+         $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+         $echo "$help" 1>&2
+         exit 1
+       fi
+
+       # Read the libtool library.
+       dlname=
+       library_names=
+
+       # If there is no directory component, then add one.
+       case "$file" in
+       */* | *\\*) . $file ;;
+       *) . ./$file ;;
+       esac
+
+       # Skip this library if it cannot be dlopened.
+       if test -z "$dlname"; then
+         # Warn if it was a shared library.
+         test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+         continue
+       fi
+
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+
+       if test -f "$dir/$objdir/$dlname"; then
+         dir="$dir/$objdir"
+       else
+         $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+         exit 1
+       fi
+       ;;
+
+      *.lo)
+       # Just add the directory containing the .lo file.
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+       ;;
+
+      *)
+       $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+       continue
+       ;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+       eval "$shlibpath_var=\"\$dir\""
+      else
+       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case "$file" in
+      -*) ;;
+      *)
+       # Do a test to see if this is really a libtool program.
+       if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         # If there is no directory component, then add one.
+         case "$file" in
+         */* | *\\*) . $file ;;
+         *) . ./$file ;;
+         esac
+
+         # Transform arg to wrapped name.
+         file="$progdir/$program"
+       fi
+       ;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+      args="$args \"$file\""
+    done
+
+    if test -z "$run"; then
+      if test -n "$shlibpath_var"; then
+        # Export the shlibpath_var.
+        eval "export $shlibpath_var"
+      fi
+
+      # Restore saved enviroment variables
+      if test "${save_LC_ALL+set}" = set; then
+       LC_ALL="$save_LC_ALL"; export LC_ALL
+      fi
+      if test "${save_LANG+set}" = set; then
+       LANG="$save_LANG"; export LANG
+      fi
+
+      # Now actually exec the command.
+      eval "exec \$cmd$args"
+
+      $echo "$modename: cannot exec \$cmd$args"
+      exit 1
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+        eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+        $echo "export $shlibpath_var"
+      fi
+      $echo "$cmd$args"
+      exit 0
+    fi
+    ;;
+
+  # libtool uninstall mode
+  uninstall)
+    modename="$modename: uninstall"
+    rm="$nonopt"
+    files=
+
+    for arg
+    do
+      case "$arg" in
+      -*) rm="$rm $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    if test -z "$rm"; then
+      $echo "$modename: you must specify an RM program" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    for file in $files; do
+      dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$dir" = "X$file" && dir=.
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      rmfiles="$file"
+
+      case "$name" in
+      *.la)
+       # Possibly a libtool archive, so verify it.
+       if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+         . $dir/$name
+
+         # Delete the libtool libraries and symlinks.
+         for n in $library_names; do
+           rmfiles="$rmfiles $dir/$n"
+         done
+         test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library"
+
+         $show "$rm $rmfiles"
+         $run $rm $rmfiles
+
+         if test -n "$library_names"; then
+           # Do each command in the postuninstall commands.
+           eval cmds=\"$postuninstall_cmds\"
+           IFS="${IFS=         }"; save_ifs="$IFS"; IFS='~'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             $show "$cmd"
+             $run eval "$cmd"
+           done
+           IFS="$save_ifs"
+         fi
+
+         if test -n "$old_library"; then
+           # Do each command in the old_postuninstall commands.
+           eval cmds=\"$old_postuninstall_cmds\"
+           IFS="${IFS=         }"; save_ifs="$IFS"; IFS='~'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             $show "$cmd"
+             $run eval "$cmd"
+           done
+           IFS="$save_ifs"
+         fi
+
+         # FIXME: should reinstall the best remaining shared library.
+       fi
+       ;;
+
+      *.lo)
+       if test "$build_old_libs" = yes; then
+         oldobj=`$echo "X$name" | $Xsed -e "$lo2o"`
+         rmfiles="$rmfiles $dir/$oldobj"
+       fi
+       $show "$rm $rmfiles"
+       $run $rm $rmfiles
+       ;;
+
+      *)
+       $show "$rm $rmfiles"
+       $run $rm $rmfiles
+       ;;
+      esac
+    done
+    exit 0
+    ;;
+
+  "")
+    $echo "$modename: you must specify a MODE" 1>&2
+    $echo "$generic_help" 1>&2
+    exit 1
+    ;;
+  esac
+
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$generic_help" 1>&2
+  exit 1
+fi # test -z "$show_help"
+
+# We need to display help for each of the modes.
+case "$mode" in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+    --config          show all configuration variables
+    --debug           enable verbose shell tracing
+-n, --dry-run         display commands without modifying any files
+    --features        display basic configuration information and exit
+    --finish          same as \`--mode=finish'
+    --help            display this help message and exit
+    --mode=MODE       use operation mode MODE [default=inferred from MODE-ARGS]
+    --quiet           same as \`--silent'
+    --silent          don't print informational messages
+    --version         print version information
+
+MODE must be one of the following:
+
+      compile         compile a source file into a libtool object
+      execute         automatically set library path, then run a program
+      finish          complete the installation of libtool libraries
+      install         install libraries or executables
+      link            create a library or an executable
+      uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE."
+  exit 0
+  ;;
+
+compile)
+  $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -static           always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+  ;;
+
+execute)
+  $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+  ;;
+
+finish)
+  $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+  ;;
+
+install)
+  $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+  ;;
+
+link)
+  $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                   try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                   try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -static           do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                   specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+  ;;
+
+uninstall)
+  $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+*)
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$help" 1>&2
+  exit 1
+  ;;
+esac
+
+echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/pcre/pcre.c b/pcre/pcre.c
new file mode 100644 (file)
index 0000000..5149f8d
--- /dev/null
@@ -0,0 +1,5151 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10@cam.ac.uk>
+
+           Copyright (c) 1997-2000 University of Cambridge
+
+-----------------------------------------------------------------------------
+Permission is granted to anyone to use this software for any purpose on any
+computer system, and to redistribute it freely, subject to the following
+restrictions:
+
+1. This software 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.
+
+2. The origin of this software must not be misrepresented, either by
+   explicit claim or by omission.
+
+3. Altered versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+4. If PCRE is embedded in any software that is released under the GNU
+   General Purpose Licence (GPL), then the terms of that licence shall
+   supersede any condition above with which it is incompatible.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Define DEBUG to get debugging output on stdout. */
+
+/* #define DEBUG */
+
+/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
+inline, and there are *still* stupid compilers about that don't like indented
+pre-processor statements. I suppose it's only been 10 years... */
+
+#ifdef DEBUG
+#define DPRINTF(p) printf p
+#else
+#define DPRINTF(p) /*nothing*/
+#endif
+
+/* Include the internals header, which itself includes Standard C headers plus
+the external pcre header. */
+
+#include "internal.h"
+
+
+/* Allow compilation as C++ source code, should anybody want to do that. */
+
+#ifdef __cplusplus
+#define class pcre_class
+#endif
+
+
+/* Number of items on the nested bracket stacks at compile time. This should
+not be set greater than 200. */
+
+#define BRASTACK_SIZE 200
+
+
+/* The number of bytes in a literal character string above which we can't add
+any more is different when UTF-8 characters may be encountered. */
+
+#ifdef SUPPORT_UTF8
+#define MAXLIT 250
+#else
+#define MAXLIT 255
+#endif
+
+
+/* Min and max values for the common repeats; for the maxima, 0 => infinity */
+
+static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
+static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
+
+/* Text forms of OP_ values and things, for debugging (not all used) */
+
+#ifdef DEBUG
+static const char *OP_names[] = {
+  "End", "\\A", "\\B", "\\b", "\\D", "\\d",
+  "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z",
+  "Opt", "^", "$", "Any", "chars", "not",
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",
+  "*", "*?", "+", "+?", "?", "??", "{", "{",
+  "class", "Ref", "Recurse",
+  "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not",
+  "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref",
+  "Brazero", "Braminzero", "Bra"
+};
+#endif
+
+/* Table for handling escaped characters in the range '0'-'z'. Positive returns
+are simple data values; negative values are for special things like \d and so
+on. Zero means further processing is needed (for things like \x), or the escape
+is invalid. */
+
+static const short int escapes[] = {
+    0,      0,      0,      0,      0,      0,      0,      0,   /* 0 - 7 */
+    0,      0,    ':',    ';',    '<',    '=',    '>',    '?',   /* 8 - ? */
+  '@', -ESC_A, -ESC_B,      0, -ESC_D,      0,      0,      0,   /* @ - G */
+    0,      0,      0,      0,      0,      0,      0,      0,   /* H - O */
+    0,      0,      0, -ESC_S,      0,      0,      0, -ESC_W,   /* P - W */
+    0,      0, -ESC_Z,    '[',   '\\',    ']',    '^',    '_',   /* X - _ */
+  '`',      7, -ESC_b,      0, -ESC_d,     27,   '\f',      0,   /* ` - g */
+    0,      0,      0,      0,      0,      0,   '\n',      0,   /* h - o */
+    0,      0,   '\r', -ESC_s,   '\t',      0,      0, -ESC_w,   /* p - w */
+    0,      0, -ESC_z                                            /* x - z */
+};
+
+/* Tables of names of POSIX character classes and their lengths. The list is
+terminated by a zero length entry. The first three must be alpha, upper, lower,
+as this is assumed for handling case independence. */
+
+static const char *posix_names[] = {
+  "alpha", "lower", "upper",
+  "alnum", "ascii", "cntrl", "digit", "graph",
+  "print", "punct", "space", "word",  "xdigit" };
+
+static const uschar posix_name_lengths[] = {
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
+
+/* Table of class bit maps for each POSIX class; up to three may be combined
+to form the class. */
+
+static const int posix_class_maps[] = {
+  cbit_lower, cbit_upper, -1,             /* alpha */
+  cbit_lower, -1,         -1,             /* lower */
+  cbit_upper, -1,         -1,             /* upper */
+  cbit_digit, cbit_lower, cbit_upper,     /* alnum */
+  cbit_print, cbit_cntrl, -1,             /* ascii */
+  cbit_cntrl, -1,         -1,             /* cntrl */
+  cbit_digit, -1,         -1,             /* digit */
+  cbit_graph, -1,         -1,             /* graph */
+  cbit_print, -1,         -1,             /* print */
+  cbit_punct, -1,         -1,             /* punct */
+  cbit_space, -1,         -1,             /* space */
+  cbit_word,  -1,         -1,             /* word */
+  cbit_xdigit,-1,         -1              /* xdigit */
+};
+
+
+/* Definition to allow mutual recursion */
+
+static BOOL
+  compile_regex(int, int, int *, uschar **, const uschar **, const char **,
+    BOOL, int, int *, int *, compile_data *);
+
+/* Structure for building a chain of data that actually lives on the
+stack, for holding the values of the subject pointer at the start of each
+subpattern, so as to detect when an empty string has been matched by a
+subpattern - to break infinite loops. */
+
+typedef struct eptrblock {
+  struct eptrblock *prev;
+  const uschar *saved_eptr;
+} eptrblock;
+
+/* Flag bits for the match() function */
+
+#define match_condassert   0x01    /* Called to check a condition assertion */
+#define match_isgroup      0x02    /* Set if start of bracketed group */
+
+
+
+/*************************************************
+*               Global variables                 *
+*************************************************/
+
+/* PCRE is thread-clean and doesn't use any global variables in the normal
+sense. However, it calls memory allocation and free functions via the two
+indirections below, which are can be changed by the caller, but are shared
+between all threads. */
+
+void *(*pcre_malloc)(size_t) = malloc;
+void  (*pcre_free)(void *) = free;
+
+
+
+/*************************************************
+*    Macros and tables for character handling    *
+*************************************************/
+
+/* When UTF-8 encoding is being used, a character is no longer just a single
+byte. The macros for character handling generate simple sequences when used in
+byte-mode, and more complicated ones for UTF-8 characters. */
+
+#ifndef SUPPORT_UTF8
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define BACKCHAR(eptr)
+
+#else   /* SUPPORT_UTF8 */
+
+/* Get the next UTF-8 character, advancing the pointer */
+
+#define GETCHARINC(c, eptr) \
+  c = *eptr++; \
+  if (md->utf8 && (c & 0xc0) == 0xc0) \
+    { \
+    int a = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int s = 6 - a;                  /* Amount to shift next byte */  \
+    c &= utf8_table3[a];            /* Low order bits from first byte */ \
+    while (a-- > 0) \
+      { \
+      c |= (*eptr++ & 0x3f) << s; \
+      s += 6; \
+      } \
+    }
+
+/* Get the next UTF-8 character, not advancing the pointer, setting length */
+
+#define GETCHARLEN(c, eptr, len) \
+  c = *eptr; \
+  len = 1; \
+  if (md->utf8 && (c & 0xc0) == 0xc0) \
+    { \
+    int i; \
+    int a = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int s = 6 - a;                  /* Amount to shift next byte */  \
+    c &= utf8_table3[a];            /* Low order bits from first byte */ \
+    for (i = 1; i <= a; i++) \
+      { \
+      c |= (eptr[i] & 0x3f) << s; \
+      s += 6; \
+      } \
+    len += a; \
+    }
+
+/* If the pointer is not at the start of a character, move it back until
+it is. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--;
+
+#endif
+
+
+
+/*************************************************
+*             Default character tables           *
+*************************************************/
+
+/* A default set of character tables is included in the PCRE binary. Its source
+is built by the maketables auxiliary program, which uses the default C ctypes
+functions, and put in the file chartables.c. These tables are used by PCRE
+whenever the caller of pcre_compile() does not provide an alternate set of
+tables. */
+
+#include "chartables.c"
+
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+*           Tables for UTF-8 support             *
+*************************************************/
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+static int utf8_table2[] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra characters, indexed by the first character
+masked with 0x3f. The highest number for a valid UTF-8 character is in fact
+0x3d. */
+
+static uschar utf8_table4[] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes.
+
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of characters placed in the buffer
+*/
+
+static int
+ord2utf8(int cvalue, uschar *buffer)
+{
+register int i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+  if (cvalue <= utf8_table1[i]) break;
+*buffer++ = utf8_table2[i] | (cvalue & utf8_table3[i]);
+cvalue >>= 6 - i;
+for (j = 0; j < i; j++)
+  {
+  *buffer++ = 0x80 | (cvalue & 0x3f);
+  cvalue >>= 6;
+  }
+return i + 1;
+}
+#endif
+
+
+
+/*************************************************
+*          Return version string                 *
+*************************************************/
+
+#define STRING(a)  # a
+#define XSTRING(s) STRING(s)
+
+const char *
+pcre_version(void)
+{
+return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
+}
+
+
+
+
+/*************************************************
+* (Obsolete) Return info about compiled pattern  *
+*************************************************/
+
+/* This is the original "info" function. It picks potentially useful data out
+of the private structure, but its interface was too rigid. It remains for
+backwards compatibility. The public options are passed back in an int - though
+the re->options field has been expanded to a long int, all the public options
+at the low end of it, and so even on 16-bit systems this will still be OK.
+Therefore, I haven't changed the API for pcre_info().
+
+Arguments:
+  external_re   points to compiled code
+  optptr        where to pass back the options
+  first_char    where to pass back the first character,
+                or -1 if multiline and all branches start ^,
+                or -2 otherwise
+
+Returns:        number of capturing subpatterns
+                or negative values on error
+*/
+
+int
+pcre_info(const pcre *external_re, int *optptr, int *first_char)
+{
+const real_pcre *re = (const real_pcre *)external_re;
+if (re == NULL) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS);
+if (first_char != NULL)
+  *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
+     ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+return re->top_bracket;
+}
+
+
+
+/*************************************************
+*        Return info about compiled pattern      *
+*************************************************/
+
+/* This is a newer "info" function which has an extensible interface so
+that additional items can be added compatibly.
+
+Arguments:
+  external_re      points to compiled code
+  external_study   points to study data, or NULL
+  what             what information is required
+  where            where to put the information
+
+Returns:           0 if data returned, negative on error
+*/
+
+int
+pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what,
+  void *where)
+{
+const real_pcre *re = (const real_pcre *)external_re;
+const real_pcre_extra *study = (const real_pcre_extra *)study_data;
+
+if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+
+switch (what)
+  {
+  case PCRE_INFO_OPTIONS:
+  *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS;
+  break;
+
+  case PCRE_INFO_SIZE:
+  *((size_t *)where) = re->size;
+  break;
+
+  case PCRE_INFO_CAPTURECOUNT:
+  *((int *)where) = re->top_bracket;
+  break;
+
+  case PCRE_INFO_BACKREFMAX:
+  *((int *)where) = re->top_backref;
+  break;
+
+  case PCRE_INFO_FIRSTCHAR:
+  *((int *)where) =
+    ((re->options & PCRE_FIRSTSET) != 0)? re->first_char :
+    ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+  break;
+
+  case PCRE_INFO_FIRSTTABLE:
+  *((const uschar **)where) =
+    (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)?
+      study->start_bits : NULL;
+  break;
+
+  case PCRE_INFO_LASTLITERAL:
+  *((int *)where) =
+    ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1;
+  break;
+
+  default: return PCRE_ERROR_BADOPTION;
+  }
+
+return 0;
+}
+
+
+
+#ifdef DEBUG
+/*************************************************
+*        Debugging function to print chars       *
+*************************************************/
+
+/* Print a sequence of chars in printable format, stopping at the end of the
+subject if the requested.
+
+Arguments:
+  p           points to characters
+  length      number to print
+  is_subject  TRUE if printing from within md->start_subject
+  md          pointer to matching data block, if is_subject is TRUE
+
+Returns:     nothing
+*/
+
+static void
+pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
+{
+int c;
+if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
+while (length-- > 0)
+  if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c);
+}
+#endif
+
+
+
+
+/*************************************************
+*            Handle escapes                      *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \n, or a negative value which
+encodes one of the more complicated things such as \d. When UTF-8 is enabled,
+a positive value greater than 255 may be returned. On entry, ptr is pointing at
+the \. On exit, it is on the final character of the escape sequence.
+
+Arguments:
+  ptrptr     points to the pattern position pointer
+  errorptr   points to the pointer to the error message
+  bracount   number of previous extracting brackets
+  options    the options bits
+  isclass    TRUE if inside a character class
+  cd         pointer to char tables block
+
+Returns:     zero or positive => a data character
+             negative => a special escape sequence
+             on error, errorptr is set
+*/
+
+static int
+check_escape(const uschar **ptrptr, const char **errorptr, int bracount,
+  int options, BOOL isclass, compile_data *cd)
+{
+const uschar *ptr = *ptrptr;
+int c, i;
+
+/* If backslash is at the end of the pattern, it's an error. */
+
+c = *(++ptr);
+if (c == 0) *errorptr = ERR1;
+
+/* Digits or letters may have special meaning; all others are literals. */
+
+else if (c < '0' || c > 'z') {}
+
+/* Do an initial lookup in a table. A non-zero result is something that can be
+returned immediately. Otherwise further processing may be required. */
+
+else if ((i = escapes[c - '0']) != 0) c = i;
+
+/* Escapes that need further processing, or are illegal. */
+
+else
+  {
+  const uschar *oldptr;
+  switch (c)
+    {
+    /* The handling of escape sequences consisting of a string of digits
+    starting with one that is not zero is not straightforward. By experiment,
+    the way Perl works seems to be as follows:
+
+    Outside a character class, the digits are read as a decimal number. If the
+    number is less than 10, or if there are that many previous extracting
+    left brackets, then it is a back reference. Otherwise, up to three octal
+    digits are read to form an escaped byte. Thus \123 is likely to be octal
+    123 (cf \0123, which is octal 012 followed by the literal 3). If the octal
+    value is greater than 377, the least significant 8 bits are taken. Inside a
+    character class, \ followed by a digit is always an octal number. */
+
+    case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+
+    if (!isclass)
+      {
+      oldptr = ptr;
+      c -= '0';
+      while ((cd->ctypes[ptr[1]] & ctype_digit) != 0)
+        c = c * 10 + *(++ptr) - '0';
+      if (c < 10 || c <= bracount)
+        {
+        c = -(ESC_REF + c);
+        break;
+        }
+      ptr = oldptr;      /* Put the pointer back and fall through */
+      }
+
+    /* Handle an octal number following \. If the first digit is 8 or 9, Perl
+    generates a binary zero byte and treats the digit as a following literal.
+    Thus we have to pull back the pointer by one. */
+
+    if ((c = *ptr) >= '8')
+      {
+      ptr--;
+      c = 0;
+      break;
+      }
+
+    /* \0 always starts an octal number, but we may drop through to here with a
+    larger first octal digit. */
+
+    case '0':
+    c -= '0';
+    while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 &&
+      ptr[1] != '8' && ptr[1] != '9')
+        c = c * 8 + *(++ptr) - '0';
+    c &= 255;     /* Take least significant 8 bits */
+    break;
+
+    /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number
+    which can be greater than 0xff, but only if the ddd are hex digits. */
+
+    case 'x':
+#ifdef SUPPORT_UTF8
+    if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
+      {
+      const uschar *pt = ptr + 2;
+      register int count = 0;
+      c = 0;
+      while ((cd->ctypes[*pt] & ctype_xdigit) != 0)
+        {
+        count++;
+        c = c * 16 + cd->lcc[*pt] -
+          (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W');
+        pt++;
+        }
+      if (*pt == '}')
+        {
+        if (c < 0 || count > 8) *errorptr = ERR34;
+        ptr = pt;
+        break;
+        }
+      /* If the sequence of hex digits does not end with '}', then we don't
+      recognize this construct; fall through to the normal \x handling. */
+      }
+#endif
+
+    /* Read just a single hex char */
+
+    c = 0;
+    while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0)
+      {
+      ptr++;
+      c = c * 16 + cd->lcc[*ptr] -
+        (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W');
+      }
+    break;
+
+    /* Other special escapes not starting with a digit are straightforward */
+
+    case 'c':
+    c = *(++ptr);
+    if (c == 0)
+      {
+      *errorptr = ERR2;
+      return 0;
+      }
+
+    /* A letter is upper-cased; then the 0x40 bit is flipped */
+
+    if (c >= 'a' && c <= 'z') c = cd->fcc[c];
+    c ^= 0x40;
+    break;
+
+    /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
+    other alphameric following \ is an error if PCRE_EXTRA was set; otherwise,
+    for Perl compatibility, it is a literal. This code looks a bit odd, but
+    there used to be some cases other than the default, and there may be again
+    in future, so I haven't "optimized" it. */
+
+    default:
+    if ((options & PCRE_EXTRA) != 0) switch(c)
+      {
+      default:
+      *errorptr = ERR3;
+      break;
+      }
+    break;
+    }
+  }
+
+*ptrptr = ptr;
+return c;
+}
+
+
+
+/*************************************************
+*            Check for counted repeat            *
+*************************************************/
+
+/* This function is called when a '{' is encountered in a place where it might
+start a quantifier. It looks ahead to see if it really is a quantifier or not.
+It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
+where the ddds are digits.
+
+Arguments:
+  p         pointer to the first char after '{'
+  cd        pointer to char tables block
+
+Returns:    TRUE or FALSE
+*/
+
+static BOOL
+is_counted_repeat(const uschar *p, compile_data *cd)
+{
+if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
+while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
+if (*p == '}') return TRUE;
+
+if (*p++ != ',') return FALSE;
+if (*p == '}') return TRUE;
+
+if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE;
+while ((cd->ctypes[*p] & ctype_digit) != 0) p++;
+return (*p == '}');
+}
+
+
+
+/*************************************************
+*         Read repeat counts                     *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values. This is called only
+after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
+so the syntax is guaranteed to be correct, but we need to check the values.
+
+Arguments:
+  p          pointer to first char after '{'
+  minp       pointer to int for min
+  maxp       pointer to int for max
+             returned as -1 if no max
+  errorptr   points to pointer to error message
+  cd         pointer to character tables clock
+
+Returns:     pointer to '}' on success;
+             current ptr on error, with errorptr set
+*/
+
+static const uschar *
+read_repeat_counts(const uschar *p, int *minp, int *maxp,
+  const char **errorptr, compile_data *cd)
+{
+int min = 0;
+int max = -1;
+
+while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
+
+if (*p == '}') max = min; else
+  {
+  if (*(++p) != '}')
+    {
+    max = 0;
+    while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
+    if (max < min)
+      {
+      *errorptr = ERR4;
+      return p;
+      }
+    }
+  }
+
+/* Do paranoid checks, then fill in the required variables, and pass back the
+pointer to the terminating '}'. */
+
+if (min > 65535 || max > 65535)
+  *errorptr = ERR5;
+else
+  {
+  *minp = min;
+  *maxp = max;
+  }
+return p;
+}
+
+
+
+/*************************************************
+*        Find the fixed length of a pattern      *
+*************************************************/
+
+/* Scan a pattern and compute the fixed length of subject that will match it,
+if the length is fixed. This is needed for dealing with backward assertions.
+
+Arguments:
+  code     points to the start of the pattern (the bracket)
+  options  the compiling options
+
+Returns:   the fixed length, or -1 if there is no fixed length
+*/
+
+static int
+find_fixedlength(uschar *code, int options)
+{
+int length = -1;
+
+register int branchlength = 0;
+register uschar *cc = code + 3;
+
+/* Scan along the opcodes for this branch. If we get to the end of the
+branch, check the length against that of the other branches. */
+
+for (;;)
+  {
+  int d;
+  register int op = *cc;
+  if (op >= OP_BRA) op = OP_BRA;
+
+  switch (op)
+    {
+    case OP_BRA:
+    case OP_ONCE:
+    case OP_COND:
+    d = find_fixedlength(cc, options);
+    if (d < 0) return -1;
+    branchlength += d;
+    do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
+    cc += 3;
+    break;
+
+    /* Reached end of a branch; if it's a ket it is the end of a nested
+    call. If it's ALT it is an alternation in a nested call. If it is
+    END it's the end of the outer call. All can be handled by the same code. */
+
+    case OP_ALT:
+    case OP_KET:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_END:
+    if (length < 0) length = branchlength;
+      else if (length != branchlength) return -1;
+    if (*cc != OP_ALT) return length;
+    cc += 3;
+    branchlength = 0;
+    break;
+
+    /* Skip over assertive subpatterns */
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT);
+    cc += 3;
+    break;
+
+    /* Skip over things that don't match chars */
+
+    case OP_REVERSE:
+    cc++;
+    /* Fall through */
+
+    case OP_CREF:
+    case OP_OPT:
+    cc++;
+    /* Fall through */
+
+    case OP_SOD:
+    case OP_EOD:
+    case OP_EODN:
+    case OP_CIRC:
+    case OP_DOLL:
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    cc++;
+    break;
+
+    /* Handle char strings. In UTF-8 mode we must count characters, not bytes.
+    This requires a scan of the string, unfortunately. We assume valid UTF-8
+    strings, so all we do is reduce the length by one for byte whose bits are
+    10xxxxxx. */
+
+    case OP_CHARS:
+    branchlength += *(++cc);
+#ifdef SUPPORT_UTF8
+    for (d = 1; d <= *cc; d++)
+      if ((cc[d] & 0xc0) == 0x80) branchlength--;
+#endif
+    cc += *cc + 1;
+    break;
+
+    /* Handle exact repetitions */
+
+    case OP_EXACT:
+    case OP_TYPEEXACT:
+    branchlength += (cc[1] << 8) + cc[2];
+    cc += 4;
+    break;
+
+    /* Handle single-char matchers */
+
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    branchlength++;
+    cc++;
+    break;
+
+
+    /* Check a class for variable quantification */
+
+    case OP_CLASS:
+    cc += (*cc == OP_REF)? 2 : 33;
+
+    switch (*cc)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      return -1;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1;
+      branchlength += (cc[1] << 8) + cc[2];
+      cc += 5;
+      break;
+
+      default:
+      branchlength++;
+      }
+    break;
+
+    /* Anything else is variable length */
+
+    default:
+    return -1;
+    }
+  }
+/* Control never gets here */
+}
+
+
+
+
+/*************************************************
+*           Check for POSIX class syntax         *
+*************************************************/
+
+/* This function is called when the sequence "[:" or "[." or "[=" is
+encountered in a character class. It checks whether this is followed by an
+optional ^ and then a sequence of letters, terminated by a matching ":]" or
+".]" or "=]".
+
+Argument:
+  ptr      pointer to the initial [
+  endptr   where to return the end pointer
+  cd       pointer to compile data
+
+Returns:   TRUE or FALSE
+*/
+
+static BOOL
+check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd)
+{
+int terminator;          /* Don't combine these lines; the Solaris cc */
+terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
+if (*(++ptr) == '^') ptr++;
+while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
+if (*ptr == terminator && ptr[1] == ']')
+  {
+  *endptr = ptr;
+  return TRUE;
+  }
+return FALSE;
+}
+
+
+
+
+/*************************************************
+*          Check POSIX class name                *
+*************************************************/
+
+/* This function is called to check the name given in a POSIX-style class entry
+such as [:alnum:].
+
+Arguments:
+  ptr        points to the first letter
+  len        the length of the name
+
+Returns:     a value representing the name, or -1 if unknown
+*/
+
+static int
+check_posix_name(const uschar *ptr, int len)
+{
+register int yield = 0;
+while (posix_name_lengths[yield] != 0)
+  {
+  if (len == posix_name_lengths[yield] &&
+    strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield;
+  yield++;
+  }
+return -1;
+}
+
+
+
+
+/*************************************************
+*           Compile one branch                   *
+*************************************************/
+
+/* Scan the pattern, compiling it into the code vector.
+
+Arguments:
+  options      the option bits
+  brackets     points to number of brackets used
+  code         points to the pointer to the current code point
+  ptrptr       points to the current pattern pointer
+  errorptr     points to pointer to error message
+  optchanged   set to the value of the last OP_OPT item compiled
+  reqchar      set to the last literal character required, else -1
+  countlits    set to count of mandatory literal characters
+  cd           contains pointers to tables
+
+Returns:       TRUE on success
+               FALSE, with *errorptr set on error
+*/
+
+static BOOL
+compile_branch(int options, int *brackets, uschar **codeptr,
+  const uschar **ptrptr, const char **errorptr, int *optchanged,
+  int *reqchar, int *countlits, compile_data *cd)
+{
+int repeat_type, op_type;
+int repeat_min, repeat_max;
+int bravalue, length;
+int greedy_default, greedy_non_default;
+int prevreqchar;
+int condcount = 0;
+int subcountlits = 0;
+register int c;
+register uschar *code = *codeptr;
+uschar *tempcode;
+const uschar *ptr = *ptrptr;
+const uschar *tempptr;
+uschar *previous = NULL;
+uschar class[32];
+
+/* Set up the default and non-default settings for greediness */
+
+greedy_default = ((options & PCRE_UNGREEDY) != 0);
+greedy_non_default = greedy_default ^ 1;
+
+/* Initialize no required char, and count of literals */
+
+*reqchar = prevreqchar = -1;
+*countlits = 0;
+
+/* Switch on next character until the end of the branch */
+
+for (;; ptr++)
+  {
+  BOOL negate_class;
+  int class_charcount;
+  int class_lastchar;
+  int newoptions;
+  int condref;
+  int subreqchar;
+
+  c = *ptr;
+  if ((options & PCRE_EXTENDED) != 0)
+    {
+    if ((cd->ctypes[c] & ctype_space) != 0) continue;
+    if (c == '#')
+      {
+      /* The space before the ; is to avoid a warning on a silly compiler
+      on the Macintosh. */
+      while ((c = *(++ptr)) != 0 && c != '\n') ;
+      continue;
+      }
+    }
+
+  switch(c)
+    {
+    /* The branch terminates at end of string, |, or ). */
+
+    case 0:
+    case '|':
+    case ')':
+    *codeptr = code;
+    *ptrptr = ptr;
+    return TRUE;
+
+    /* Handle single-character metacharacters */
+
+    case '^':
+    previous = NULL;
+    *code++ = OP_CIRC;
+    break;
+
+    case '$':
+    previous = NULL;
+    *code++ = OP_DOLL;
+    break;
+
+    case '.':
+    previous = code;
+    *code++ = OP_ANY;
+    break;
+
+    /* Character classes. These always build a 32-byte bitmap of the permitted
+    characters, except in the special case where there is only one character.
+    For negated classes, we build the map as usual, then invert it at the end.
+    */
+
+    case '[':
+    previous = code;
+    *code++ = OP_CLASS;
+
+    /* If the first character is '^', set the negation flag and skip it. */
+
+    if ((c = *(++ptr)) == '^')
+      {
+      negate_class = TRUE;
+      c = *(++ptr);
+      }
+    else negate_class = FALSE;
+
+    /* Keep a count of chars so that we can optimize the case of just a single
+    character. */
+
+    class_charcount = 0;
+    class_lastchar = -1;
+
+    /* Initialize the 32-char bit map to all zeros. We have to build the
+    map in a temporary bit of store, in case the class contains only 1
+    character, because in that case the compiled code doesn't use the
+    bit map. */
+
+    memset(class, 0, 32 * sizeof(uschar));
+
+    /* Process characters until ] is reached. By writing this as a "do" it
+    means that an initial ] is taken as a data character. */
+
+    do
+      {
+      if (c == 0)
+        {
+        *errorptr = ERR6;
+        goto FAILED;
+        }
+
+      /* Handle POSIX class names. Perl allows a negation extension of the
+      form [:^name]. A square bracket that doesn't match the syntax is
+      treated as a literal. We also recognize the POSIX constructions
+      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+      5.6 does. */
+
+      if (c == '[' &&
+          (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
+          check_posix_syntax(ptr, &tempptr, cd))
+        {
+        BOOL local_negate = FALSE;
+        int posix_class, i;
+        register const uschar *cbits = cd->cbits;
+
+        if (ptr[1] != ':')
+          {
+          *errorptr = ERR31;
+          goto FAILED;
+          }
+
+        ptr += 2;
+        if (*ptr == '^')
+          {
+          local_negate = TRUE;
+          ptr++;
+          }
+
+        posix_class = check_posix_name(ptr, tempptr - ptr);
+        if (posix_class < 0)
+          {
+          *errorptr = ERR30;
+          goto FAILED;
+          }
+
+        /* If matching is caseless, upper and lower are converted to
+        alpha. This relies on the fact that the class table starts with
+        alpha, lower, upper as the first 3 entries. */
+
+        if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
+          posix_class = 0;
+
+        /* Or into the map we are building up to 3 of the static class
+        tables, or their negations. */
+
+        posix_class *= 3;
+        for (i = 0; i < 3; i++)
+          {
+          int taboffset = posix_class_maps[posix_class + i];
+          if (taboffset < 0) break;
+          if (local_negate)
+            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset];
+          else
+            for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset];
+          }
+
+        ptr = tempptr + 1;
+        class_charcount = 10;  /* Set > 1; assumes more than 1 per class */
+        continue;
+        }
+
+      /* Backslash may introduce a single character, or it may introduce one
+      of the specials, which just set a flag. Escaped items are checked for
+      validity in the pre-compiling pass. The sequence \b is a special case.
+      Inside a class (and only there) it is treated as backspace. Elsewhere
+      it marks a word boundary. Other escapes have preset maps ready to
+      or into the one we are building. We assume they have more than one
+      character in them, so set class_count bigger than one. */
+
+      if (c == '\\')
+        {
+        c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
+        if (-c == ESC_b) c = '\b';
+        else if (c < 0)
+          {
+          register const uschar *cbits = cd->cbits;
+          class_charcount = 10;
+          switch (-c)
+            {
+            case ESC_d:
+            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit];
+            continue;
+
+            case ESC_D:
+            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit];
+            continue;
+
+            case ESC_w:
+            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word];
+            continue;
+
+            case ESC_W:
+            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word];
+            continue;
+
+            case ESC_s:
+            for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space];
+            continue;
+
+            case ESC_S:
+            for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space];
+            continue;
+
+            default:
+            *errorptr = ERR7;
+            goto FAILED;
+            }
+          }
+
+        /* Fall through if single character, but don't at present allow
+        chars > 255 in UTF-8 mode. */
+
+#ifdef SUPPORT_UTF8
+        if (c > 255)
+          {
+          *errorptr = ERR33;
+          goto FAILED;
+          }
+#endif
+        }
+
+      /* A single character may be followed by '-' to form a range. However,
+      Perl does not permit ']' to be the end of the range. A '-' character
+      here is treated as a literal. */
+
+      if (ptr[1] == '-' && ptr[2] != ']')
+        {
+        int d;
+        ptr += 2;
+        d = *ptr;
+
+        if (d == 0)
+          {
+          *errorptr = ERR6;
+          goto FAILED;
+          }
+
+        /* The second part of a range can be a single-character escape, but
+        not any of the other escapes. Perl 5.6 treats a hyphen as a literal
+        in such circumstances. */
+
+        if (d == '\\')
+          {
+          const uschar *oldptr = ptr;
+          d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd);
+
+#ifdef SUPPORT_UTF8
+          if (d > 255)
+            {
+            *errorptr = ERR33;
+            goto FAILED;
+            }
+#endif
+          /* \b is backslash; any other special means the '-' was literal */
+
+          if (d < 0)
+            {
+            if (d == -ESC_b) d = '\b'; else
+              {
+              ptr = oldptr - 2;
+              goto SINGLE_CHARACTER;  /* A few lines below */
+              }
+            }
+          }
+
+        if (d < c)
+          {
+          *errorptr = ERR8;
+          goto FAILED;
+          }
+
+        for (; c <= d; c++)
+          {
+          class[c/8] |= (1 << (c&7));
+          if ((options & PCRE_CASELESS) != 0)
+            {
+            int uc = cd->fcc[c];           /* flip case */
+            class[uc/8] |= (1 << (uc&7));
+            }
+          class_charcount++;                /* in case a one-char range */
+          class_lastchar = c;
+          }
+        continue;   /* Go get the next char in the class */
+        }
+
+      /* Handle a lone single character - we can get here for a normal
+      non-escape char, or after \ that introduces a single character. */
+
+      SINGLE_CHARACTER:
+
+      class [c/8] |= (1 << (c&7));
+      if ((options & PCRE_CASELESS) != 0)
+        {
+        c = cd->fcc[c];   /* flip case */
+        class[c/8] |= (1 << (c&7));
+        }
+      class_charcount++;
+      class_lastchar = c;
+      }
+
+    /* Loop until ']' reached; the check for end of string happens inside the
+    loop. This "while" is the end of the "do" above. */
+
+    while ((c = *(++ptr)) != ']');
+
+    /* If class_charcount is 1 and class_lastchar is not negative, we saw
+    precisely one character. This doesn't need the whole 32-byte bit map.
+    We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if
+    it's negative. */
+
+    if (class_charcount == 1 && class_lastchar >= 0)
+      {
+      if (negate_class)
+        {
+        code[-1] = OP_NOT;
+        }
+      else
+        {
+        code[-1] = OP_CHARS;
+        *code++ = 1;
+        }
+      *code++ = class_lastchar;
+      }
+
+    /* Otherwise, negate the 32-byte map if necessary, and copy it into
+    the code vector. */
+
+    else
+      {
+      if (negate_class)
+        for (c = 0; c < 32; c++) code[c] = ~class[c];
+      else
+        memcpy(code, class, 32);
+      code += 32;
+      }
+    break;
+
+    /* Various kinds of repeat */
+
+    case '{':
+    if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR;
+    ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd);
+    if (*errorptr != NULL) goto FAILED;
+    goto REPEAT;
+
+    case '*':
+    repeat_min = 0;
+    repeat_max = -1;
+    goto REPEAT;
+
+    case '+':
+    repeat_min = 1;
+    repeat_max = -1;
+    goto REPEAT;
+
+    case '?':
+    repeat_min = 0;
+    repeat_max = 1;
+
+    REPEAT:
+    if (previous == NULL)
+      {
+      *errorptr = ERR9;
+      goto FAILED;
+      }
+
+    /* If the next character is '?' this is a minimizing repeat, by default,
+    but if PCRE_UNGREEDY is set, it works the other way round. Advance to the
+    next character. */
+
+    if (ptr[1] == '?')
+      { repeat_type = greedy_non_default; ptr++; }
+    else repeat_type = greedy_default;
+
+    /* If previous was a string of characters, chop off the last one and use it
+    as the subject of the repeat. If there was only one character, we can
+    abolish the previous item altogether. A repeat with a zero minimum wipes
+    out any reqchar setting, backing up to the previous value. We must also
+    adjust the countlits value. */
+
+    if (*previous == OP_CHARS)
+      {
+      int len = previous[1];
+
+      if (repeat_min == 0) *reqchar = prevreqchar;
+      *countlits += repeat_min - 1;
+
+      if (len == 1)
+        {
+        c = previous[2];
+        code = previous;
+        }
+      else
+        {
+        c = previous[len+1];
+        previous[1]--;
+        code--;
+        }
+      op_type = 0;                 /* Use single-char op codes */
+      goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
+      }
+
+    /* If previous was a single negated character ([^a] or similar), we use
+    one of the special opcodes, replacing it. The code is shared with single-
+    character repeats by adding a suitable offset into repeat_type. */
+
+    else if ((int)*previous == OP_NOT)
+      {
+      op_type = OP_NOTSTAR - OP_STAR;  /* Use "not" opcodes */
+      c = previous[1];
+      code = previous;
+      goto OUTPUT_SINGLE_REPEAT;
+      }
+
+    /* If previous was a character type match (\d or similar), abolish it and
+    create a suitable repeat item. The code is shared with single-character
+    repeats by adding a suitable offset into repeat_type. */
+
+    else if ((int)*previous < OP_EODN || *previous == OP_ANY)
+      {
+      op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
+      c = *previous;
+      code = previous;
+
+      OUTPUT_SINGLE_REPEAT:
+
+      /* If the maximum is zero then the minimum must also be zero; Perl allows
+      this case, so we do too - by simply omitting the item altogether. */
+
+      if (repeat_max == 0) goto END_REPEAT;
+
+      /* Combine the op_type with the repeat_type */
+
+      repeat_type += op_type;
+
+      /* A minimum of zero is handled either as the special case * or ?, or as
+      an UPTO, with the maximum given. */
+
+      if (repeat_min == 0)
+        {
+        if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
+          else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+        else
+          {
+          *code++ = OP_UPTO + repeat_type;
+          *code++ = repeat_max >> 8;
+          *code++ = (repeat_max & 255);
+          }
+        }
+
+      /* The case {1,} is handled as the special case + */
+
+      else if (repeat_min == 1 && repeat_max == -1)
+        *code++ = OP_PLUS + repeat_type;
+
+      /* The case {n,n} is just an EXACT, while the general case {n,m} is
+      handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */
+
+      else
+        {
+        if (repeat_min != 1)
+          {
+          *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
+          *code++ = repeat_min >> 8;
+          *code++ = (repeat_min & 255);
+          }
+
+        /* If the mininum is 1 and the previous item was a character string,
+        we either have to put back the item that got cancelled if the string
+        length was 1, or add the character back onto the end of a longer
+        string. For a character type nothing need be done; it will just get
+        put back naturally. Note that the final character is always going to
+        get added below. */
+
+        else if (*previous == OP_CHARS)
+          {
+          if (code == previous) code += 2; else previous[1]++;
+          }
+
+        /*  For a single negated character we also have to put back the
+        item that got cancelled. */
+
+        else if (*previous == OP_NOT) code++;
+
+        /* If the maximum is unlimited, insert an OP_STAR. */
+
+        if (repeat_max < 0)
+          {
+          *code++ = c;
+          *code++ = OP_STAR + repeat_type;
+          }
+
+        /* Else insert an UPTO if the max is greater than the min. */
+
+        else if (repeat_max != repeat_min)
+          {
+          *code++ = c;
+          repeat_max -= repeat_min;
+          *code++ = OP_UPTO + repeat_type;
+          *code++ = repeat_max >> 8;
+          *code++ = (repeat_max & 255);
+          }
+        }
+
+      /* The character or character type itself comes last in all cases. */
+
+      *code++ = c;
+      }
+
+    /* If previous was a character class or a back reference, we put the repeat
+    stuff after it, but just skip the item if the repeat was {0,0}. */
+
+    else if (*previous == OP_CLASS || *previous == OP_REF)
+      {
+      if (repeat_max == 0)
+        {
+        code = previous;
+        goto END_REPEAT;
+        }
+      if (repeat_min == 0 && repeat_max == -1)
+        *code++ = OP_CRSTAR + repeat_type;
+      else if (repeat_min == 1 && repeat_max == -1)
+        *code++ = OP_CRPLUS + repeat_type;
+      else if (repeat_min == 0 && repeat_max == 1)
+        *code++ = OP_CRQUERY + repeat_type;
+      else
+        {
+        *code++ = OP_CRRANGE + repeat_type;
+        *code++ = repeat_min >> 8;
+        *code++ = repeat_min & 255;
+        if (repeat_max == -1) repeat_max = 0;  /* 2-byte encoding for max */
+        *code++ = repeat_max >> 8;
+        *code++ = repeat_max & 255;
+        }
+      }
+
+    /* If previous was a bracket group, we may have to replicate it in certain
+    cases. */
+
+    else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE ||
+             (int)*previous == OP_COND)
+      {
+      register int i;
+      int ketoffset = 0;
+      int len = code - previous;
+      uschar *bralink = NULL;
+
+      /* If the maximum repeat count is unlimited, find the end of the bracket
+      by scanning through from the start, and compute the offset back to it
+      from the current code pointer. There may be an OP_OPT setting following
+      the final KET, so we can't find the end just by going back from the code
+      pointer. */
+
+      if (repeat_max == -1)
+        {
+        register uschar *ket = previous;
+        do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET);
+        ketoffset = code - ket;
+        }
+
+      /* The case of a zero minimum is special because of the need to stick
+      OP_BRAZERO in front of it, and because the group appears once in the
+      data, whereas in other cases it appears the minimum number of times. For
+      this reason, it is simplest to treat this case separately, as otherwise
+      the code gets far too mess. There are several special subcases when the
+      minimum is zero. */
+
+      if (repeat_min == 0)
+        {
+        /* If we set up a required char from the bracket, we must back off
+        to the previous value and reset the countlits value too. */
+
+        if (subcountlits > 0)
+          {
+          *reqchar = prevreqchar;
+          *countlits -= subcountlits;
+          }
+
+        /* If the maximum is also zero, we just omit the group from the output
+        altogether. */
+
+        if (repeat_max == 0)
+          {
+          code = previous;
+          goto END_REPEAT;
+          }
+
+        /* If the maximum is 1 or unlimited, we just have to stick in the
+        BRAZERO and do no more at this point. */
+
+        if (repeat_max <= 1)
+          {
+          memmove(previous+1, previous, len);
+          code++;
+          *previous++ = OP_BRAZERO + repeat_type;
+          }
+
+        /* If the maximum is greater than 1 and limited, we have to replicate
+        in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+        The first one has to be handled carefully because it's the original
+        copy, which has to be moved up. The remainder can be handled by code
+        that is common with the non-zero minimum case below. We just have to
+        adjust the value or repeat_max, since one less copy is required. */
+
+        else
+          {
+          int offset;
+          memmove(previous+4, previous, len);
+          code += 4;
+          *previous++ = OP_BRAZERO + repeat_type;
+          *previous++ = OP_BRA;
+
+          /* We chain together the bracket offset fields that have to be
+          filled in later when the ends of the brackets are reached. */
+
+          offset = (bralink == NULL)? 0 : previous - bralink;
+          bralink = previous;
+          *previous++ = offset >> 8;
+          *previous++ = offset & 255;
+          }
+
+        repeat_max--;
+        }
+
+      /* If the minimum is greater than zero, replicate the group as many
+      times as necessary, and adjust the maximum to the number of subsequent
+      copies that we need. */
+
+      else
+        {
+        for (i = 1; i < repeat_min; i++)
+          {
+          memcpy(code, previous, len);
+          code += len;
+          }
+        if (repeat_max > 0) repeat_max -= repeat_min;
+        }
+
+      /* This code is common to both the zero and non-zero minimum cases. If
+      the maximum is limited, it replicates the group in a nested fashion,
+      remembering the bracket starts on a stack. In the case of a zero minimum,
+      the first one was set up above. In all cases the repeat_max now specifies
+      the number of additional copies needed. */
+
+      if (repeat_max >= 0)
+        {
+        for (i = repeat_max - 1; i >= 0; i--)
+          {
+          *code++ = OP_BRAZERO + repeat_type;
+
+          /* All but the final copy start a new nesting, maintaining the
+          chain of brackets outstanding. */
+
+          if (i != 0)
+            {
+            int offset;
+            *code++ = OP_BRA;
+            offset = (bralink == NULL)? 0 : code - bralink;
+            bralink = code;
+            *code++ = offset >> 8;
+            *code++ = offset & 255;
+            }
+
+          memcpy(code, previous, len);
+          code += len;
+          }
+
+        /* Now chain through the pending brackets, and fill in their length
+        fields (which are holding the chain links pro tem). */
+
+        while (bralink != NULL)
+          {
+          int oldlinkoffset;
+          int offset = code - bralink + 1;
+          uschar *bra = code - offset;
+          oldlinkoffset = (bra[1] << 8) + bra[2];
+          bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+          *code++ = OP_KET;
+          *code++ = bra[1] = offset >> 8;
+          *code++ = bra[2] = (offset & 255);
+          }
+        }
+
+      /* If the maximum is unlimited, set a repeater in the final copy. We
+      can't just offset backwards from the current code point, because we
+      don't know if there's been an options resetting after the ket. The
+      correct offset was computed above. */
+
+      else code[-ketoffset] = OP_KETRMAX + repeat_type;
+      }
+
+    /* Else there's some kind of shambles */
+
+    else
+      {
+      *errorptr = ERR11;
+      goto FAILED;
+      }
+
+    /* In all case we no longer have a previous item. */
+
+    END_REPEAT:
+    previous = NULL;
+    break;
+
+
+    /* Start of nested bracket sub-expression, or comment or lookahead or
+    lookbehind or option setting or condition. First deal with special things
+    that can come after a bracket; all are introduced by ?, and the appearance
+    of any of them means that this is not a referencing group. They were
+    checked for validity in the first pass over the string, so we don't have to
+    check for syntax errors here.  */
+
+    case '(':
+    newoptions = options;
+    condref = -1;
+
+    if (*(++ptr) == '?')
+      {
+      int set, unset;
+      int *optset;
+
+      switch (*(++ptr))
+        {
+        case '#':                 /* Comment; skip to ket */
+        ptr++;
+        while (*ptr != ')') ptr++;
+        continue;
+
+        case ':':                 /* Non-extracting bracket */
+        bravalue = OP_BRA;
+        ptr++;
+        break;
+
+        case '(':
+        bravalue = OP_COND;       /* Conditional group */
+        if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0)
+          {
+          condref = *ptr - '0';
+          while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
+          if (condref == 0)
+            {
+            *errorptr = ERR35;
+            goto FAILED;
+            }
+          ptr++;
+          }
+        else ptr--;
+        break;
+
+        case '=':                 /* Positive lookahead */
+        bravalue = OP_ASSERT;
+        ptr++;
+        break;
+
+        case '!':                 /* Negative lookahead */
+        bravalue = OP_ASSERT_NOT;
+        ptr++;
+        break;
+
+        case '<':                 /* Lookbehinds */
+        switch (*(++ptr))
+          {
+          case '=':               /* Positive lookbehind */
+          bravalue = OP_ASSERTBACK;
+          ptr++;
+          break;
+
+          case '!':               /* Negative lookbehind */
+          bravalue = OP_ASSERTBACK_NOT;
+          ptr++;
+          break;
+
+          default:                /* Syntax error */
+          *errorptr = ERR24;
+          goto FAILED;
+          }
+        break;
+
+        case '>':                 /* One-time brackets */
+        bravalue = OP_ONCE;
+        ptr++;
+        break;
+
+        case 'R':                 /* Pattern recursion */
+        *code++ = OP_RECURSE;
+        ptr++;
+        continue;
+
+        default:                  /* Option setting */
+        set = unset = 0;
+        optset = &set;
+
+        while (*ptr != ')' && *ptr != ':')
+          {
+          switch (*ptr++)
+            {
+            case '-': optset = &unset; break;
+
+            case 'i': *optset |= PCRE_CASELESS; break;
+            case 'm': *optset |= PCRE_MULTILINE; break;
+            case 's': *optset |= PCRE_DOTALL; break;
+            case 'x': *optset |= PCRE_EXTENDED; break;
+            case 'U': *optset |= PCRE_UNGREEDY; break;
+            case 'X': *optset |= PCRE_EXTRA; break;
+
+            default:
+            *errorptr = ERR12;
+            goto FAILED;
+            }
+          }
+
+        /* Set up the changed option bits, but don't change anything yet. */
+
+        newoptions = (options | set) & (~unset);
+
+        /* If the options ended with ')' this is not the start of a nested
+        group with option changes, so the options change at this level. At top
+        level there is nothing else to be done (the options will in fact have
+        been set from the start of compiling as a result of the first pass) but
+        at an inner level we must compile code to change the ims options if
+        necessary, and pass the new setting back so that it can be put at the
+        start of any following branches, and when this group ends, a resetting
+        item can be compiled. */
+
+        if (*ptr == ')')
+          {
+          if ((options & PCRE_INGROUP) != 0 &&
+              (options & PCRE_IMS) != (newoptions & PCRE_IMS))
+            {
+            *code++ = OP_OPT;
+            *code++ = *optchanged = newoptions & PCRE_IMS;
+            }
+          options = newoptions;  /* Change options at this level */
+          previous = NULL;       /* This item can't be repeated */
+          continue;              /* It is complete */
+          }
+
+        /* If the options ended with ':' we are heading into a nested group
+        with possible change of options. Such groups are non-capturing and are
+        not assertions of any kind. All we need to do is skip over the ':';
+        the newoptions value is handled below. */
+
+        bravalue = OP_BRA;
+        ptr++;
+        }
+      }
+
+    /* Else we have a referencing group; adjust the opcode. */
+
+    else
+      {
+      if (++(*brackets) > EXTRACT_MAX)
+        {
+        *errorptr = ERR13;
+        goto FAILED;
+        }
+      bravalue = OP_BRA + *brackets;
+      }
+
+    /* Process nested bracketed re. Assertions may not be repeated, but other
+    kinds can be. We copy code into a non-register variable in order to be able
+    to pass its address because some compilers complain otherwise. Pass in a
+    new setting for the ims options if they have changed. */
+
+    previous = (bravalue >= OP_ONCE)? code : NULL;
+    *code = bravalue;
+    tempcode = code;
+
+    if (!compile_regex(
+         options | PCRE_INGROUP,       /* Set for all nested groups */
+         ((options & PCRE_IMS) != (newoptions & PCRE_IMS))?
+           newoptions & PCRE_IMS : -1, /* Pass ims options if changed */
+         brackets,                     /* Bracket level */
+         &tempcode,                    /* Where to put code (updated) */
+         &ptr,                         /* Input pointer (updated) */
+         errorptr,                     /* Where to put an error message */
+         (bravalue == OP_ASSERTBACK ||
+          bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
+         condref,                      /* Condition reference number */
+         &subreqchar,                  /* For possible last char */
+         &subcountlits,                /* For literal count */
+         cd))                          /* Tables block */
+      goto FAILED;
+
+    /* At the end of compiling, code is still pointing to the start of the
+    group, while tempcode has been updated to point past the end of the group
+    and any option resetting that may follow it. The pattern pointer (ptr)
+    is on the bracket. */
+
+    /* If this is a conditional bracket, check that there are no more than
+    two branches in the group. */
+
+    if (bravalue == OP_COND)
+      {
+      uschar *tc = code;
+      condcount = 0;
+
+      do {
+         condcount++;
+         tc += (tc[1] << 8) | tc[2];
+         }
+      while (*tc != OP_KET);
+
+      if (condcount > 2)
+        {
+        *errorptr = ERR27;
+        goto FAILED;
+        }
+      }
+
+    /* Handle updating of the required character. If the subpattern didn't
+    set one, leave it as it was. Otherwise, update it for normal brackets of
+    all kinds, forward assertions, and conditions with two branches. Don't
+    update the literal count for forward assertions, however. If the bracket
+    is followed by a quantifier with zero repeat, we have to back off. Hence
+    the definition of prevreqchar and subcountlits outside the main loop so
+    that they can be accessed for the back off. */
+
+    if (subreqchar > 0 &&
+         (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT ||
+         (bravalue == OP_COND && condcount == 2)))
+      {
+      prevreqchar = *reqchar;
+      *reqchar = subreqchar;
+      if (bravalue != OP_ASSERT) *countlits += subcountlits;
+      }
+
+    /* Now update the main code pointer to the end of the group. */
+
+    code = tempcode;
+
+    /* Error if hit end of pattern */
+
+    if (*ptr != ')')
+      {
+      *errorptr = ERR14;
+      goto FAILED;
+      }
+    break;
+
+    /* Check \ for being a real metacharacter; if not, fall through and handle
+    it as a data character at the start of a string. Escape items are checked
+    for validity in the pre-compiling pass. */
+
+    case '\\':
+    tempptr = ptr;
+    c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
+
+    /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
+    are arranged to be the negation of the corresponding OP_values. For the
+    back references, the values are ESC_REF plus the reference number. Only
+    back references and those types that consume a character may be repeated.
+    We can test for values between ESC_b and ESC_Z for the latter; this may
+    have to change if any new ones are ever created. */
+
+    if (c < 0)
+      {
+      if (-c >= ESC_REF)
+        {
+        previous = code;
+        *code++ = OP_REF;
+        *code++ = -c - ESC_REF;
+        }
+      else
+        {
+        previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
+        *code++ = -c;
+        }
+      continue;
+      }
+
+    /* Data character: reset and fall through */
+
+    ptr = tempptr;
+    c = '\\';
+
+    /* Handle a run of data characters until a metacharacter is encountered.
+    The first character is guaranteed not to be whitespace or # when the
+    extended flag is set. */
+
+    NORMAL_CHAR:
+    default:
+    previous = code;
+    *code = OP_CHARS;
+    code += 2;
+    length = 0;
+
+    do
+      {
+      if ((options & PCRE_EXTENDED) != 0)
+        {
+        if ((cd->ctypes[c] & ctype_space) != 0) continue;
+        if (c == '#')
+          {
+          /* The space before the ; is to avoid a warning on a silly compiler
+          on the Macintosh. */
+          while ((c = *(++ptr)) != 0 && c != '\n') ;
+          if (c == 0) break;
+          continue;
+          }
+        }
+
+      /* Backslash may introduce a data char or a metacharacter. Escaped items
+      are checked for validity in the pre-compiling pass. Stop the string
+      before a metaitem. */
+
+      if (c == '\\')
+        {
+        tempptr = ptr;
+        c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd);
+        if (c < 0) { ptr = tempptr; break; }
+
+        /* If a character is > 127 in UTF-8 mode, we have to turn it into
+        two or more characters in the UTF-8 encoding. */
+
+#ifdef SUPPORT_UTF8
+        if (c > 127 && (options & PCRE_UTF8) != 0)
+          {
+          uschar buffer[8];
+          int len = ord2utf8(c, buffer);
+          for (c = 0; c < len; c++) *code++ = buffer[c];
+          length += len;
+          continue;
+          }
+#endif
+        }
+
+      /* Ordinary character or single-char escape */
+
+      *code++ = c;
+      length++;
+      }
+
+    /* This "while" is the end of the "do" above. */
+
+    while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0);
+
+    /* Update the last character and the count of literals */
+
+    prevreqchar = (length > 1)? code[-2] : *reqchar;
+    *reqchar = code[-1];
+    *countlits += length;
+
+    /* Compute the length and set it in the data vector, and advance to
+    the next state. */
+
+    previous[1] = length;
+    if (length < MAXLIT) ptr--;
+    break;
+    }
+  }                   /* end of big loop */
+
+/* Control never reaches here by falling through, only by a goto for all the
+error states. Pass back the position in the pattern so that it can be displayed
+to the user for diagnosing the error. */
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
+}
+
+
+
+
+/*************************************************
+*     Compile sequence of alternatives           *
+*************************************************/
+
+/* On entry, ptr is pointing past the bracket character, but on return
+it points to the closing bracket, or vertical bar, or end of string.
+The code variable is pointing at the byte into which the BRA operator has been
+stored. If the ims options are changed at the start (for a (?ims: group) or
+during any branch, we need to insert an OP_OPT item at the start of every
+following branch to ensure they get set correctly at run time, and also pass
+the new options into every subsequent branch compile.
+
+Argument:
+  options     the option bits
+  optchanged  new ims options to set as if (?ims) were at the start, or -1
+               for no change
+  brackets    -> int containing the number of extracting brackets used
+  codeptr     -> the address of the current code pointer
+  ptrptr      -> the address of the current pattern pointer
+  errorptr    -> pointer to error message
+  lookbehind  TRUE if this is a lookbehind assertion
+  condref     >= 0 for OPT_CREF setting at start of conditional group
+  reqchar     -> place to put the last required character, or a negative number
+  countlits   -> place to put the shortest literal count of any branch
+  cd          points to the data block with tables pointers
+
+Returns:      TRUE on success
+*/
+
+static BOOL
+compile_regex(int options, int optchanged, int *brackets, uschar **codeptr,
+  const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int condref,
+  int *reqchar, int *countlits, compile_data *cd)
+{
+const uschar *ptr = *ptrptr;
+uschar *code = *codeptr;
+uschar *last_branch = code;
+uschar *start_bracket = code;
+uschar *reverse_count = NULL;
+int oldoptions = options & PCRE_IMS;
+int branchreqchar, branchcountlits;
+
+*reqchar = -1;
+*countlits = INT_MAX;
+code += 3;
+
+/* At the start of a reference-based conditional group, insert the reference
+number as an OP_CREF item. */
+
+if (condref >= 0)
+  {
+  *code++ = OP_CREF;
+  *code++ = condref;
+  }
+
+/* Loop for each alternative branch */
+
+for (;;)
+  {
+  int length;
+
+  /* Handle change of options */
+
+  if (optchanged >= 0)
+    {
+    *code++ = OP_OPT;
+    *code++ = optchanged;
+    options = (options & ~PCRE_IMS) | optchanged;
+    }
+
+  /* Set up dummy OP_REVERSE if lookbehind assertion */
+
+  if (lookbehind)
+    {
+    *code++ = OP_REVERSE;
+    reverse_count = code;
+    *code++ = 0;
+    *code++ = 0;
+    }
+
+  /* Now compile the branch */
+
+  if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged,
+      &branchreqchar, &branchcountlits, cd))
+    {
+    *ptrptr = ptr;
+    return FALSE;
+    }
+
+  /* Fill in the length of the last branch */
+
+  length = code - last_branch;
+  last_branch[1] = length >> 8;
+  last_branch[2] = length & 255;
+
+  /* Save the last required character if all branches have the same; a current
+  value of -1 means unset, while -2 means "previous branch had no last required
+  char".  */
+
+  if (*reqchar != -2)
+    {
+    if (branchreqchar >= 0)
+      {
+      if (*reqchar == -1) *reqchar = branchreqchar;
+      else if (*reqchar != branchreqchar) *reqchar = -2;
+      }
+    else *reqchar = -2;
+    }
+
+  /* Keep the shortest literal count */
+
+  if (branchcountlits < *countlits) *countlits = branchcountlits;
+  DPRINTF(("literal count = %d min=%d\n", branchcountlits, *countlits));
+
+  /* If lookbehind, check that this branch matches a fixed-length string,
+  and put the length into the OP_REVERSE item. Temporarily mark the end of
+  the branch with OP_END. */
+
+  if (lookbehind)
+    {
+    *code = OP_END;
+    length = find_fixedlength(last_branch, options);
+    DPRINTF(("fixed length = %d\n", length));
+    if (length < 0)
+      {
+      *errorptr = ERR25;
+      *ptrptr = ptr;
+      return FALSE;
+      }
+    reverse_count[0] = (length >> 8);
+    reverse_count[1] = length & 255;
+    }
+
+  /* Reached end of expression, either ')' or end of pattern. Insert a
+  terminating ket and the length of the whole bracketed item, and return,
+  leaving the pointer at the terminating char. If any of the ims options
+  were changed inside the group, compile a resetting op-code following. */
+
+  if (*ptr != '|')
+    {
+    length = code - start_bracket;
+    *code++ = OP_KET;
+    *code++ = length >> 8;
+    *code++ = length & 255;
+    if (optchanged >= 0)
+      {
+      *code++ = OP_OPT;
+      *code++ = oldoptions;
+      }
+    *codeptr = code;
+    *ptrptr = ptr;
+    return TRUE;
+    }
+
+  /* Another branch follows; insert an "or" node and advance the pointer. */
+
+  *code = OP_ALT;
+  last_branch = code;
+  code += 3;
+  ptr++;
+  }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+*      Find first significant op code            *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this. For one application, a change of caseless option is
+important.
+
+Arguments:
+  code       pointer to the start of the group
+  options    pointer to external options
+  optbit     the option bit whose changing is significant, or
+             zero if none are
+  optstop    TRUE to return on option change, otherwise change the options
+               value and continue
+
+Returns:     pointer to the first significant opcode
+*/
+
+static const uschar*
+first_significant_code(const uschar *code, int *options, int optbit,
+  BOOL optstop)
+{
+for (;;)
+  {
+  switch ((int)*code)
+    {
+    case OP_OPT:
+    if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit))
+      {
+      if (optstop) return code;
+      *options = (int)code[1];
+      }
+    code += 2;
+    break;
+
+    case OP_CREF:
+    code += 2;
+    break;
+
+    case OP_WORD_BOUNDARY:
+    case OP_NOT_WORD_BOUNDARY:
+    code++;
+    break;
+
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    do code += (code[1] << 8) + code[2]; while (*code == OP_ALT);
+    code += 3;
+    break;
+
+    default:
+    return code;
+    }
+  }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+*          Check for anchored expression         *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
+all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
+it's anchored. However, if this is a multiline pattern, then only OP_SOD
+counts, since OP_CIRC can match in the middle.
+
+A branch is also implicitly anchored if it starts with .* and DOTALL is set,
+because that will try the rest of the pattern at all possible matching points,
+so there is no point trying them again.
+
+Arguments:
+  code       points to start of expression (the bracket)
+  options    points to the options setting
+
+Returns:     TRUE or FALSE
+*/
+
+static BOOL
+is_anchored(register const uschar *code, int *options)
+{
+do {
+   const uschar *scode = first_significant_code(code + 3, options,
+     PCRE_MULTILINE, FALSE);
+   register int op = *scode;
+   if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+     { if (!is_anchored(scode, options)) return FALSE; }
+   else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) &&
+            (*options & PCRE_DOTALL) != 0)
+     { if (scode[1] != OP_ANY) return FALSE; }
+   else if (op != OP_SOD &&
+           ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC))
+     return FALSE;
+   code += (code[1] << 8) + code[2];
+   }
+while (*code == OP_ALT);
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Check for starting with ^ or .*        *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n).
+
+Argument:  points to start of expression (the bracket)
+Returns:   TRUE or FALSE
+*/
+
+static BOOL
+is_startline(const uschar *code)
+{
+do {
+   const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE);
+   register int op = *scode;
+   if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+     { if (!is_startline(scode)) return FALSE; }
+   else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
+     { if (scode[1] != OP_ANY) return FALSE; }
+   else if (op != OP_CIRC) return FALSE;
+   code += (code[1] << 8) + code[2];
+   }
+while (*code == OP_ALT);
+return TRUE;
+}
+
+
+
+/*************************************************
+*          Check for fixed first char            *
+*************************************************/
+
+/* Try to find out if there is a fixed first character. This is called for
+unanchored expressions, as it speeds up their processing quite considerably.
+Consider each alternative branch. If they all start with the same char, or with
+a bracket all of whose alternatives start with the same char (recurse ad lib),
+then we return that char, otherwise -1.
+
+Arguments:
+  code       points to start of expression (the bracket)
+  options    pointer to the options (used to check casing changes)
+
+Returns:     -1 or the fixed first char
+*/
+
+static int
+find_firstchar(const uschar *code, int *options)
+{
+register int c = -1;
+do {
+   int d;
+   const uschar *scode = first_significant_code(code + 3, options,
+     PCRE_CASELESS, TRUE);
+   register int op = *scode;
+
+   if (op >= OP_BRA) op = OP_BRA;
+
+   switch(op)
+     {
+     default:
+     return -1;
+
+     case OP_BRA:
+     case OP_ASSERT:
+     case OP_ONCE:
+     case OP_COND:
+     if ((d = find_firstchar(scode, options)) < 0) return -1;
+     if (c < 0) c = d; else if (c != d) return -1;
+     break;
+
+     case OP_EXACT:       /* Fall through */
+     scode++;
+
+     case OP_CHARS:       /* Fall through */
+     scode++;
+
+     case OP_PLUS:
+     case OP_MINPLUS:
+     if (c < 0) c = scode[1]; else if (c != scode[1]) return -1;
+     break;
+     }
+
+   code += (code[1] << 8) + code[2];
+   }
+while (*code == OP_ALT);
+return c;
+}
+
+
+
+
+
+/*************************************************
+*        Compile a Regular Expression            *
+*************************************************/
+
+/* This function takes a string and returns a pointer to a block of store
+holding a compiled version of the expression.
+
+Arguments:
+  pattern      the regular expression
+  options      various option bits
+  errorptr     pointer to pointer to error text
+  erroroffset  ptr offset in pattern where error was detected
+  tables       pointer to character tables or NULL
+
+Returns:       pointer to compiled data block, or NULL on error,
+               with errorptr and erroroffset set
+*/
+
+pcre *
+pcre_compile(const char *pattern, int options, const char **errorptr,
+  int *erroroffset, const unsigned char *tables)
+{
+real_pcre *re;
+int length = 3;      /* For initial BRA plus length */
+int runlength;
+int c, reqchar, countlits;
+int bracount = 0;
+int top_backref = 0;
+int branch_extra = 0;
+int branch_newextra;
+unsigned int brastackptr = 0;
+size_t size;
+uschar *code;
+const uschar *ptr;
+compile_data compile_block;
+int brastack[BRASTACK_SIZE];
+uschar bralenstack[BRASTACK_SIZE];
+
+#ifdef DEBUG
+uschar *code_base, *code_end;
+#endif
+
+/* Can't support UTF8 unless PCRE has been compiled to include the code. */
+
+#ifndef SUPPORT_UTF8
+if ((options & PCRE_UTF8) != 0)
+  {
+  *errorptr = ERR32;
+  return NULL;
+  }
+#endif
+
+/* We can't pass back an error message if errorptr is NULL; I guess the best we
+can do is just return NULL. */
+
+if (errorptr == NULL) return NULL;
+*errorptr = NULL;
+
+/* However, we can give a message for this error */
+
+if (erroroffset == NULL)
+  {
+  *errorptr = ERR16;
+  return NULL;
+  }
+*erroroffset = 0;
+
+if ((options & ~PUBLIC_OPTIONS) != 0)
+  {
+  *errorptr = ERR17;
+  return NULL;
+  }
+
+/* Set up pointers to the individual character tables */
+
+if (tables == NULL) tables = pcre_default_tables;
+compile_block.lcc = tables + lcc_offset;
+compile_block.fcc = tables + fcc_offset;
+compile_block.cbits = tables + cbits_offset;
+compile_block.ctypes = tables + ctypes_offset;
+
+/* Reflect pattern for debugging output */
+
+DPRINTF(("------------------------------------------------------------------\n"));
+DPRINTF(("%s\n", pattern));
+
+/* The first thing to do is to make a pass over the pattern to compute the
+amount of store required to hold the compiled code. This does not have to be
+perfect as long as errors are overestimates. At the same time we can detect any
+internal flag settings. Make an attempt to correct for any counted white space
+if an "extended" flag setting appears late in the pattern. We can't be so
+clever for #-comments. */
+
+ptr = (const uschar *)(pattern - 1);
+while ((c = *(++ptr)) != 0)
+  {
+  int min, max;
+  int class_charcount;
+
+  if ((options & PCRE_EXTENDED) != 0)
+    {
+    if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
+    if (c == '#')
+      {
+      /* The space before the ; is to avoid a warning on a silly compiler
+      on the Macintosh. */
+      while ((c = *(++ptr)) != 0 && c != '\n') ;
+      continue;
+      }
+    }
+
+  switch(c)
+    {
+    /* A backslashed item may be an escaped "normal" character or a
+    character type. For a "normal" character, put the pointers and
+    character back so that tests for whitespace etc. in the input
+    are done correctly. */
+
+    case '\\':
+      {
+      const uschar *save_ptr = ptr;
+      c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block);
+      if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+      if (c >= 0)
+        {
+        ptr = save_ptr;
+        c = '\\';
+        goto NORMAL_CHAR;
+        }
+      }
+    length++;
+
+    /* A back reference needs an additional char, plus either one or 5
+    bytes for a repeat. We also need to keep the value of the highest
+    back reference. */
+
+    if (c <= -ESC_REF)
+      {
+      int refnum = -c - ESC_REF;
+      if (refnum > top_backref) top_backref = refnum;
+      length++;   /* For single back reference */
+      if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
+        {
+        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if ((min == 0 && (max == 1 || max == -1)) ||
+          (min == 1 && max == -1))
+            length++;
+        else length += 5;
+        if (ptr[1] == '?') ptr++;
+        }
+      }
+    continue;
+
+    case '^':
+    case '.':
+    case '$':
+    case '*':     /* These repeats won't be after brackets; */
+    case '+':     /* those are handled separately */
+    case '?':
+    length++;
+    continue;
+
+    /* This covers the cases of repeats after a single char, metachar, class,
+    or back reference. */
+
+    case '{':
+    if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR;
+    ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block);
+    if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+    if ((min == 0 && (max == 1 || max == -1)) ||
+      (min == 1 && max == -1))
+        length++;
+    else
+      {
+      length--;   /* Uncount the original char or metachar */
+      if (min == 1) length++; else if (min > 0) length += 4;
+      if (max > 0) length += 4; else length += 2;
+      }
+    if (ptr[1] == '?') ptr++;
+    continue;
+
+    /* An alternation contains an offset to the next branch or ket. If any ims
+    options changed in the previous branch(es), and/or if we are in a
+    lookbehind assertion, extra space will be needed at the start of the
+    branch. This is handled by branch_extra. */
+
+    case '|':
+    length += 3 + branch_extra;
+    continue;
+
+    /* A character class uses 33 characters. Don't worry about character types
+    that aren't allowed in classes - they'll get picked up during the compile.
+    A character class that contains only one character uses 2 or 3 bytes,
+    depending on whether it is negated or not. Notice this where we can. */
+
+    case '[':
+    class_charcount = 0;
+    if (*(++ptr) == '^') ptr++;
+    do
+      {
+      if (*ptr == '\\')
+        {
+        int ch = check_escape(&ptr, errorptr, bracount, options, TRUE,
+          &compile_block);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if (-ch == ESC_b) class_charcount++; else class_charcount = 10;
+        }
+      else class_charcount++;
+      ptr++;
+      }
+    while (*ptr != 0 && *ptr != ']');
+
+    /* Repeats for negated single chars are handled by the general code */
+
+    if (class_charcount == 1) length += 3; else
+      {
+      length += 33;
+
+      /* A repeat needs either 1 or 5 bytes. */
+
+      if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block))
+        {
+        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if ((min == 0 && (max == 1 || max == -1)) ||
+          (min == 1 && max == -1))
+            length++;
+        else length += 5;
+        if (ptr[1] == '?') ptr++;
+        }
+      }
+    continue;
+
+    /* Brackets may be genuine groups or special things */
+
+    case '(':
+    branch_newextra = 0;
+
+    /* Handle special forms of bracket, which all start (? */
+
+    if (ptr[1] == '?')
+      {
+      int set, unset;
+      int *optset;
+
+      switch (c = ptr[2])
+        {
+        /* Skip over comments entirely */
+        case '#':
+        ptr += 3;
+        while (*ptr != 0 && *ptr != ')') ptr++;
+        if (*ptr == 0)
+          {
+          *errorptr = ERR18;
+          goto PCRE_ERROR_RETURN;
+          }
+        continue;
+
+        /* Non-referencing groups and lookaheads just move the pointer on, and
+        then behave like a non-special bracket, except that they don't increment
+        the count of extracting brackets. Ditto for the "once only" bracket,
+        which is in Perl from version 5.005. */
+
+        case ':':
+        case '=':
+        case '!':
+        case '>':
+        ptr += 2;
+        break;
+
+        /* A recursive call to the regex is an extension, to provide the
+        facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */
+
+        case 'R':
+        if (ptr[3] != ')')
+          {
+          *errorptr = ERR29;
+          goto PCRE_ERROR_RETURN;
+          }
+        ptr += 3;
+        length += 1;
+        break;
+
+        /* Lookbehinds are in Perl from version 5.005 */
+
+        case '<':
+        if (ptr[3] == '=' || ptr[3] == '!')
+          {
+          ptr += 3;
+          branch_newextra = 3;
+          length += 3;         /* For the first branch */
+          break;
+          }
+        *errorptr = ERR24;
+        goto PCRE_ERROR_RETURN;
+
+        /* Conditionals are in Perl from version 5.005. The bracket must either
+        be followed by a number (for bracket reference) or by an assertion
+        group. */
+
+        case '(':
+        if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0)
+          {
+          ptr += 4;
+          length += 2;
+          while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++;
+          if (*ptr != ')')
+            {
+            *errorptr = ERR26;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+        else   /* An assertion must follow */
+          {
+          ptr++;   /* Can treat like ':' as far as spacing is concerned */
+          if (ptr[2] != '?' ||
+             (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') )
+            {
+            ptr += 2;    /* To get right offset in message */
+            *errorptr = ERR28;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+        break;
+
+        /* Else loop checking valid options until ) is met. Anything else is an
+        error. If we are without any brackets, i.e. at top level, the settings
+        act as if specified in the options, so massage the options immediately.
+        This is for backward compatibility with Perl 5.004. */
+
+        default:
+        set = unset = 0;
+        optset = &set;
+        ptr += 2;
+
+        for (;; ptr++)
+          {
+          c = *ptr;
+          switch (c)
+            {
+            case 'i':
+            *optset |= PCRE_CASELESS;
+            continue;
+
+            case 'm':
+            *optset |= PCRE_MULTILINE;
+            continue;
+
+            case 's':
+            *optset |= PCRE_DOTALL;
+            continue;
+
+            case 'x':
+            *optset |= PCRE_EXTENDED;
+            continue;
+
+            case 'X':
+            *optset |= PCRE_EXTRA;
+            continue;
+
+            case 'U':
+            *optset |= PCRE_UNGREEDY;
+            continue;
+
+            case '-':
+            optset = &unset;
+            continue;
+
+            /* A termination by ')' indicates an options-setting-only item;
+            this is global at top level; otherwise nothing is done here and
+            it is handled during the compiling process on a per-bracket-group
+            basis. */
+
+            case ')':
+            if (brastackptr == 0)
+              {
+              options = (options | set) & (~unset);
+              set = unset = 0;     /* To save length */
+              }
+            /* Fall through */
+
+            /* A termination by ':' indicates the start of a nested group with
+            the given options set. This is again handled at compile time, but
+            we must allow for compiled space if any of the ims options are
+            set. We also have to allow for resetting space at the end of
+            the group, which is why 4 is added to the length and not just 2.
+            If there are several changes of options within the same group, this
+            will lead to an over-estimate on the length, but this shouldn't
+            matter very much. We also have to allow for resetting options at
+            the start of any alternations, which we do by setting
+            branch_newextra to 2. Finally, we record whether the case-dependent
+            flag ever changes within the regex. This is used by the "required
+            character" code. */
+
+            case ':':
+            if (((set|unset) & PCRE_IMS) != 0)
+              {
+              length += 4;
+              branch_newextra = 2;
+              if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
+              }
+            goto END_OPTIONS;
+
+            /* Unrecognized option character */
+
+            default:
+            *errorptr = ERR12;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+
+        /* If we hit a closing bracket, that's it - this is a freestanding
+        option-setting. We need to ensure that branch_extra is updated if
+        necessary. The only values branch_newextra can have here are 0 or 2.
+        If the value is 2, then branch_extra must either be 2 or 5, depending
+        on whether this is a lookbehind group or not. */
+
+        END_OPTIONS:
+        if (c == ')')
+          {
+          if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3))
+            branch_extra += branch_newextra;
+          continue;
+          }
+
+        /* If options were terminated by ':' control comes here. Fall through
+        to handle the group below. */
+        }
+      }
+
+    /* Extracting brackets must be counted so we can process escapes in a
+    Perlish way. */
+
+    else bracount++;
+
+    /* Non-special forms of bracket. Save length for computing whole length
+    at end if there's a repeat that requires duplication of the group. Also
+    save the current value of branch_extra, and start the new group with
+    the new value. If non-zero, this will either be 2 for a (?imsx: group, or 3
+    for a lookbehind assertion. */
+
+    if (brastackptr >= sizeof(brastack)/sizeof(int))
+      {
+      *errorptr = ERR19;
+      goto PCRE_ERROR_RETURN;
+      }
+
+    bralenstack[brastackptr] = branch_extra;
+    branch_extra = branch_newextra;
+
+    brastack[brastackptr++] = length;
+    length += 3;
+    continue;
+
+    /* Handle ket. Look for subsequent max/min; for certain sets of values we
+    have to replicate this bracket up to that many times. If brastackptr is
+    0 this is an unmatched bracket which will generate an error, but take care
+    not to try to access brastack[-1] when computing the length and restoring
+    the branch_extra value. */
+
+    case ')':
+    length += 3;
+      {
+      int minval = 1;
+      int maxval = 1;
+      int duplength;
+
+      if (brastackptr > 0)
+        {
+        duplength = length - brastack[--brastackptr];
+        branch_extra = bralenstack[brastackptr];
+        }
+      else duplength = 0;
+
+      /* Leave ptr at the final char; for read_repeat_counts this happens
+      automatically; for the others we need an increment. */
+
+      if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block))
+        {
+        ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr,
+          &compile_block);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        }
+      else if (c == '*') { minval = 0; maxval = -1; ptr++; }
+      else if (c == '+') { maxval = -1; ptr++; }
+      else if (c == '?') { minval = 0; ptr++; }
+
+      /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
+      group, and if the maximum is greater than zero, we have to replicate
+      maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
+      bracket set - hence the 7. */
+
+      if (minval == 0)
+        {
+        length++;
+        if (maxval > 0) length += (maxval - 1) * (duplength + 7);
+        }
+
+      /* When the minimum is greater than zero, 1 we have to replicate up to
+      minval-1 times, with no additions required in the copies. Then, if
+      there is a limited maximum we have to replicate up to maxval-1 times
+      allowing for a BRAZERO item before each optional copy and nesting
+      brackets for all but one of the optional copies. */
+
+      else
+        {
+        length += (minval - 1) * duplength;
+        if (maxval > minval)   /* Need this test as maxval=-1 means no limit */
+          length += (maxval - minval) * (duplength + 7) - 6;
+        }
+      }
+    continue;
+
+    /* Non-special character. For a run of such characters the length required
+    is the number of characters + 2, except that the maximum run length is 255.
+    We won't get a skipped space or a non-data escape or the start of a #
+    comment as the first character, so the length can't be zero. */
+
+    NORMAL_CHAR:
+    default:
+    length += 2;
+    runlength = 0;
+    do
+      {
+      if ((options & PCRE_EXTENDED) != 0)
+        {
+        if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
+        if (c == '#')
+          {
+          /* The space before the ; is to avoid a warning on a silly compiler
+          on the Macintosh. */
+          while ((c = *(++ptr)) != 0 && c != '\n') ;
+          continue;
+          }
+        }
+
+      /* Backslash may introduce a data char or a metacharacter; stop the
+      string before the latter. */
+
+      if (c == '\\')
+        {
+        const uschar *saveptr = ptr;
+        c = check_escape(&ptr, errorptr, bracount, options, FALSE,
+          &compile_block);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if (c < 0) { ptr = saveptr; break; }
+
+#ifdef SUPPORT_UTF8
+        if (c > 127 && (options & PCRE_UTF8) != 0)
+          {
+          int i;
+          for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+            if (c <= utf8_table1[i]) break;
+          runlength += i;
+          }
+#endif
+        }
+
+      /* Ordinary character or single-char escape */
+
+      runlength++;
+      }
+
+    /* This "while" is the end of the "do" above. */
+
+    while (runlength < MAXLIT &&
+      (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0);
+
+    ptr--;
+    length += runlength;
+    continue;
+    }
+  }
+
+length += 4;    /* For final KET and END */
+
+if (length > 65539)
+  {
+  *errorptr = ERR20;
+  return NULL;
+  }
+
+/* Compute the size of data block needed and get it, either from malloc or
+externally provided function. We specify "code[0]" in the offsetof() expression
+rather than just "code", because it has been reported that one broken compiler
+fails on "code" because it is also an independent variable. It should make no
+difference to the value of the offsetof(). */
+
+size = length + offsetof(real_pcre, code[0]);
+re = (real_pcre *)(pcre_malloc)(size);
+
+if (re == NULL)
+  {
+  *errorptr = ERR21;
+  return NULL;
+  }
+
+/* Put in the magic number, and save the size, options, and table pointer */
+
+re->magic_number = MAGIC_NUMBER;
+re->size = size;
+re->options = options;
+re->tables = tables;
+
+/* Set up a starting, non-extracting bracket, then compile the expression. On
+error, *errorptr will be set non-NULL, so we don't need to look at the result
+of the function here. */
+
+ptr = (const uschar *)pattern;
+code = re->code;
+*code = OP_BRA;
+bracount = 0;
+(void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, -1,
+  &reqchar, &countlits, &compile_block);
+re->top_bracket = bracount;
+re->top_backref = top_backref;
+
+/* If not reached end of pattern on success, there's an excess bracket. */
+
+if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22;
+
+/* Fill in the terminating state and check for disastrous overflow, but
+if debugging, leave the test till after things are printed out. */
+
+*code++ = OP_END;
+
+#ifndef DEBUG
+if (code - re->code > length) *errorptr = ERR23;
+#endif
+
+/* Give an error if there's back reference to a non-existent capturing
+subpattern. */
+
+if (top_backref > re->top_bracket) *errorptr = ERR15;
+
+/* Failed to compile */
+
+if (*errorptr != NULL)
+  {
+  (pcre_free)(re);
+  PCRE_ERROR_RETURN:
+  *erroroffset = ptr - (const uschar *)pattern;
+  return NULL;
+  }
+
+/* If the anchored option was not passed, set flag if we can determine that the
+pattern is anchored by virtue of ^ characters or \A or anything else (such as
+starting with .* when DOTALL is set).
+
+Otherwise, see if we can determine what the first character has to be, because
+that speeds up unanchored matches no end. If not, see if we can set the
+PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
+start with ^. and also when all branches start with .* for non-DOTALL matches.
+*/
+
+if ((options & PCRE_ANCHORED) == 0)
+  {
+  int temp_options = options;
+  if (is_anchored(re->code, &temp_options))
+    re->options |= PCRE_ANCHORED;
+  else
+    {
+    int ch = find_firstchar(re->code, &temp_options);
+    if (ch >= 0)
+      {
+      re->first_char = ch;
+      re->options |= PCRE_FIRSTSET;
+      }
+    else if (is_startline(re->code))
+      re->options |= PCRE_STARTLINE;
+    }
+  }
+
+/* Save the last required character if there are at least two literal
+characters on all paths, or if there is no first character setting. */
+
+if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0))
+  {
+  re->req_char = reqchar;
+  re->options |= PCRE_REQCHSET;
+  }
+
+/* Print out the compiled data for debugging */
+
+#ifdef DEBUG
+
+printf("Length = %d top_bracket = %d top_backref = %d\n",
+  length, re->top_bracket, re->top_backref);
+
+if (re->options != 0)
+  {
+  printf("%s%s%s%s%s%s%s%s%s\n",
+    ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
+    ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
+    ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
+    ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
+    ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
+    ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
+    ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "",
+    ((re->options & PCRE_EXTRA) != 0)? "extra " : "",
+    ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : "");
+  }
+
+if ((re->options & PCRE_FIRSTSET) != 0)
+  {
+  if (isprint(re->first_char)) printf("First char = %c\n", re->first_char);
+    else printf("First char = \\x%02x\n", re->first_char);
+  }
+
+if ((re->options & PCRE_REQCHSET) != 0)
+  {
+  if (isprint(re->req_char)) printf("Req char = %c\n", re->req_char);
+    else printf("Req char = \\x%02x\n", re->req_char);
+  }
+
+code_end = code;
+code_base = code = re->code;
+
+while (code < code_end)
+  {
+  int charlength;
+
+  printf("%3d ", code - code_base);
+
+  if (*code >= OP_BRA)
+    {
+    printf("%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA);
+    code += 2;
+    }
+
+  else switch(*code)
+    {
+    case OP_OPT:
+    printf(" %.2x %s", code[1], OP_names[*code]);
+    code++;
+    break;
+
+    case OP_COND:
+    printf("%3d Cond", (code[1] << 8) + code[2]);
+    code += 2;
+    break;
+
+    case OP_CREF:
+    printf(" %.2d %s", code[1], OP_names[*code]);
+    code++;
+    break;
+
+    case OP_CHARS:
+    charlength = *(++code);
+    printf("%3d ", charlength);
+    while (charlength-- > 0)
+      if (isprint(c = *(++code))) printf("%c", c); else printf("\\x%02x", c);
+    break;
+
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_ALT:
+    case OP_KET:
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ONCE:
+    printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]);
+    code += 2;
+    break;
+
+    case OP_REVERSE:
+    printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]);
+    code += 2;
+    break;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    if (*code >= OP_TYPESTAR)
+      printf("    %s", OP_names[code[1]]);
+    else if (isprint(c = code[1])) printf("    %c", c);
+      else printf("    \\x%02x", c);
+    printf("%s", OP_names[*code++]);
+    break;
+
+    case OP_EXACT:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    if (isprint(c = code[3])) printf("    %c{", c);
+      else printf("    \\x%02x{", c);
+    if (*code != OP_EXACT) printf("0,");
+    printf("%d}", (code[1] << 8) + code[2]);
+    if (*code == OP_MINUPTO) printf("?");
+    code += 3;
+    break;
+
+    case OP_TYPEEXACT:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    printf("    %s{", OP_names[code[3]]);
+    if (*code != OP_TYPEEXACT) printf(",");
+    printf("%d}", (code[1] << 8) + code[2]);
+    if (*code == OP_TYPEMINUPTO) printf("?");
+    code += 3;
+    break;
+
+    case OP_NOT:
+    if (isprint(c = *(++code))) printf("    [^%c]", c);
+      else printf("    [^\\x%02x]", c);
+    break;
+
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    if (isprint(c = code[1])) printf("    [^%c]", c);
+      else printf("    [^\\x%02x]", c);
+    printf("%s", OP_names[*code++]);
+    break;
+
+    case OP_NOTEXACT:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    if (isprint(c = code[3])) printf("    [^%c]{", c);
+      else printf("    [^\\x%02x]{", c);
+    if (*code != OP_NOTEXACT) printf(",");
+    printf("%d}", (code[1] << 8) + code[2]);
+    if (*code == OP_NOTMINUPTO) printf("?");
+    code += 3;
+    break;
+
+    case OP_REF:
+    printf("    \\%d", *(++code));
+    code ++;
+    goto CLASS_REF_REPEAT;
+
+    case OP_CLASS:
+      {
+      int i, min, max;
+      code++;
+      printf("    [");
+
+      for (i = 0; i < 256; i++)
+        {
+        if ((code[i/8] & (1 << (i&7))) != 0)
+          {
+          int j;
+          for (j = i+1; j < 256; j++)
+            if ((code[j/8] & (1 << (j&7))) == 0) break;
+          if (i == '-' || i == ']') printf("\\");
+          if (isprint(i)) printf("%c", i); else printf("\\x%02x", i);
+          if (--j > i)
+            {
+            printf("-");
+            if (j == '-' || j == ']') printf("\\");
+            if (isprint(j)) printf("%c", j); else printf("\\x%02x", j);
+            }
+          i = j;
+          }
+        }
+      printf("]");
+      code += 32;
+
+      CLASS_REF_REPEAT:
+
+      switch(*code)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        printf("%s", OP_names[*code]);
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        min = (code[1] << 8) + code[2];
+        max = (code[3] << 8) + code[4];
+        if (max == 0) printf("{%d,}", min);
+        else printf("{%d,%d}", min, max);
+        if (*code == OP_CRMINRANGE) printf("?");
+        code += 4;
+        break;
+
+        default:
+        code--;
+        }
+      }
+    break;
+
+    /* Anything else is just a one-node item */
+
+    default:
+    printf("    %s", OP_names[*code]);
+    break;
+    }
+
+  code++;
+  printf("\n");
+  }
+printf("------------------------------------------------------------------\n");
+
+/* This check is done here in the debugging case so that the code that
+was compiled can be seen. */
+
+if (code - re->code > length)
+  {
+  *errorptr = ERR23;
+  (pcre_free)(re);
+  *erroroffset = ptr - (uschar *)pattern;
+  return NULL;
+  }
+#endif
+
+return (pcre *)re;
+}
+
+
+
+/*************************************************
+*          Match a back-reference                *
+*************************************************/
+
+/* If a back reference hasn't been set, the length that is passed is greater
+than the number of characters left in the string, so the match fails.
+
+Arguments:
+  offset      index into the offset vector
+  eptr        points into the subject
+  length      length to be matched
+  md          points to match data block
+  ims         the ims flags
+
+Returns:      TRUE if matched
+*/
+
+static BOOL
+match_ref(int offset, register const uschar *eptr, int length, match_data *md,
+  unsigned long int ims)
+{
+const uschar *p = md->start_subject + md->offset_vector[offset];
+
+#ifdef DEBUG
+if (eptr >= md->end_subject)
+  printf("matching subject <null>");
+else
+  {
+  printf("matching subject ");
+  pchars(eptr, length, TRUE, md);
+  }
+printf(" against backref ");
+pchars(p, length, FALSE, md);
+printf("\n");
+#endif
+
+/* Always fail if not enough characters left */
+
+if (length > md->end_subject - eptr) return FALSE;
+
+/* Separate the caselesss case for speed */
+
+if ((ims & PCRE_CASELESS) != 0)
+  {
+  while (length-- > 0)
+    if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
+  }
+else
+  { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
+
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Match from current position            *
+*************************************************/
+
+/* On entry ecode points to the first opcode, and eptr to the first character
+in the subject string, while eptrb holds the value of eptr at the start of the
+last bracketed group - used for breaking infinite loops matching zero-length
+strings.
+
+Arguments:
+   eptr        pointer in subject
+   ecode       position in code
+   offset_top  current top pointer
+   md          pointer to "static" info for the match
+   ims         current /i, /m, and /s options
+   eptrb       pointer to chain of blocks containing eptr at start of
+                 brackets - for testing for empty matches
+   flags       can contain
+                 match_condassert - this is an assertion condition
+                 match_isgroup - this is the start of a bracketed group
+
+Returns:       TRUE if matched
+*/
+
+static BOOL
+match(register const uschar *eptr, register const uschar *ecode,
+  int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
+  int flags)
+{
+unsigned long int original_ims = ims;   /* Save for resetting on ')' */
+eptrblock newptrb;
+
+/* At the start of a bracketed group, add the current subject pointer to the
+stack of such pointers, to be re-instated at the end of the group when we hit
+the closing ket. When match() is called in other circumstances, we don't add to
+the stack. */
+
+if ((flags & match_isgroup) != 0)
+  {
+  newptrb.prev = eptrb;
+  newptrb.saved_eptr = eptr;
+  eptrb = &newptrb;
+  }
+
+/* Now start processing the operations. */
+
+for (;;)
+  {
+  int op = (int)*ecode;
+  int min, max, ctype;
+  register int i;
+  register int c;
+  BOOL minimize = FALSE;
+
+  /* Opening capturing bracket. If there is space in the offset vector, save
+  the current subject position in the working slot at the top of the vector. We
+  mustn't change the current values of the data slot, because they may be set
+  from a previous iteration of this group, and be referred to by a reference
+  inside the group.
+
+  If the bracket fails to match, we need to restore this value and also the
+  values of the final offsets, in case they were set by a previous iteration of
+  the same bracket.
+
+  If there isn't enough space in the offset vector, treat this as if it were a
+  non-capturing bracket. Don't worry about setting the flag for the error case
+  here; that is handled in the code for KET. */
+
+  if (op > OP_BRA)
+    {
+    int number = op - OP_BRA;
+    int offset = number << 1;
+
+#ifdef DEBUG
+    printf("start bracket %d subject=", number);
+    pchars(eptr, 16, TRUE, md);
+    printf("\n");
+#endif
+
+    if (offset < md->offset_max)
+      {
+      int save_offset1 = md->offset_vector[offset];
+      int save_offset2 = md->offset_vector[offset+1];
+      int save_offset3 = md->offset_vector[md->offset_end - number];
+
+      DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
+      md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
+
+      do
+        {
+        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
+          return TRUE;
+        ecode += (ecode[1] << 8) + ecode[2];
+        }
+      while (*ecode == OP_ALT);
+
+      DPRINTF(("bracket %d failed\n", number));
+
+      md->offset_vector[offset] = save_offset1;
+      md->offset_vector[offset+1] = save_offset2;
+      md->offset_vector[md->offset_end - number] = save_offset3;
+      return FALSE;
+      }
+
+    /* Insufficient room for saving captured contents */
+
+    else op = OP_BRA;
+    }
+
+  /* Other types of node can be handled by a switch */
+
+  switch(op)
+    {
+    case OP_BRA:     /* Non-capturing bracket: optimized */
+    DPRINTF(("start bracket 0\n"));
+    do
+      {
+      if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
+        return TRUE;
+      ecode += (ecode[1] << 8) + ecode[2];
+      }
+    while (*ecode == OP_ALT);
+    DPRINTF(("bracket 0 failed\n"));
+    return FALSE;
+
+    /* Conditional group: compilation checked that there are no more than
+    two branches. If the condition is false, skipping the first branch takes us
+    past the end if there is only one branch, but that's OK because that is
+    exactly what going to the ket would do. */
+
+    case OP_COND:
+    if (ecode[3] == OP_CREF)         /* Condition is extraction test */
+      {
+      int offset = ecode[4] << 1;    /* Doubled reference number */
+      return match(eptr,
+        ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)?
+          5 : 3 + (ecode[1] << 8) + ecode[2]),
+        offset_top, md, ims, eptrb, match_isgroup);
+      }
+
+    /* The condition is an assertion. Call match() to evaluate it - setting
+    the final argument TRUE causes it to stop at the end of an assertion. */
+
+    else
+      {
+      if (match(eptr, ecode+3, offset_top, md, ims, NULL,
+          match_condassert | match_isgroup))
+        {
+        ecode += 3 + (ecode[4] << 8) + ecode[5];
+        while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2];
+        }
+      else ecode += (ecode[1] << 8) + ecode[2];
+      return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup);
+      }
+    /* Control never reaches here */
+
+    /* Skip over conditional reference data if encountered (should not be) */
+
+    case OP_CREF:
+    ecode += 2;
+    break;
+
+    /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched
+    an empty string - recursion will then try other alternatives, if any. */
+
+    case OP_END:
+    if (md->notempty && eptr == md->start_match) return FALSE;
+    md->end_match_ptr = eptr;          /* Record where we ended */
+    md->end_offset_top = offset_top;   /* and how many extracts were taken */
+    return TRUE;
+
+    /* Change option settings */
+
+    case OP_OPT:
+    ims = ecode[1];
+    ecode += 2;
+    DPRINTF(("ims set to %02lx\n", ims));
+    break;
+
+    /* Assertion brackets. Check the alternative branches in turn - the
+    matching won't pass the KET for an assertion. If any one branch matches,
+    the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
+    start of each branch to move the current point backwards, so the code at
+    this level is identical to the lookahead case. */
+
+    case OP_ASSERT:
+    case OP_ASSERTBACK:
+    do
+      {
+      if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break;
+      ecode += (ecode[1] << 8) + ecode[2];
+      }
+    while (*ecode == OP_ALT);
+    if (*ecode == OP_KET) return FALSE;
+
+    /* If checking an assertion for a condition, return TRUE. */
+
+    if ((flags & match_condassert) != 0) return TRUE;
+
+    /* Continue from after the assertion, updating the offsets high water
+    mark, since extracts may have been taken during the assertion. */
+
+    do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
+    ecode += 3;
+    offset_top = md->end_offset_top;
+    continue;
+
+    /* Negative assertion: all branches must fail to match */
+
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK_NOT:
+    do
+      {
+      if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup))
+        return FALSE;
+      ecode += (ecode[1] << 8) + ecode[2];
+      }
+    while (*ecode == OP_ALT);
+
+    if ((flags & match_condassert) != 0) return TRUE;
+
+    ecode += 3;
+    continue;
+
+    /* Move the subject pointer back. This occurs only at the start of
+    each branch of a lookbehind assertion. If we are too close to the start to
+    move back, this match function fails. When working with UTF-8 we move
+    back a number of characters, not bytes. */
+
+    case OP_REVERSE:
+#ifdef SUPPORT_UTF8
+    c = (ecode[1] << 8) + ecode[2];
+    for (i = 0; i < c; i++)
+      {
+      eptr--;
+      BACKCHAR(eptr)
+      }
+#else
+    eptr -= (ecode[1] << 8) + ecode[2];
+#endif
+
+    if (eptr < md->start_subject) return FALSE;
+    ecode += 3;
+    break;
+
+    /* Recursion matches the current regex, nested. If there are any capturing
+    brackets started but not finished, we have to save their starting points
+    and reinstate them after the recursion. However, we don't know how many
+    such there are (offset_top records the completed total) so we just have
+    to save all the potential data. There may be up to 99 such values, which
+    is a bit large to put on the stack, but using malloc for small numbers
+    seems expensive. As a compromise, the stack is used when there are fewer
+    than 16 values to store; otherwise malloc is used. A problem is what to do
+    if the malloc fails ... there is no way of returning to the top level with
+    an error. Save the top 15 values on the stack, and accept that the rest
+    may be wrong. */
+
+    case OP_RECURSE:
+      {
+      BOOL rc;
+      int *save;
+      int stacksave[15];
+
+      c = md->offset_max;
+
+      if (c < 16) save = stacksave; else
+        {
+        save = (int *)(pcre_malloc)((c+1) * sizeof(int));
+        if (save == NULL)
+          {
+          save = stacksave;
+          c = 15;
+          }
+        }
+
+      for (i = 1; i <= c; i++)
+        save[i] = md->offset_vector[md->offset_end - i];
+      rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb,
+        match_isgroup);
+      for (i = 1; i <= c; i++)
+        md->offset_vector[md->offset_end - i] = save[i];
+      if (save != stacksave) (pcre_free)(save);
+      if (!rc) return FALSE;
+
+      /* In case the recursion has set more capturing values, save the final
+      number, then move along the subject till after the recursive match,
+      and advance one byte in the pattern code. */
+
+      offset_top = md->end_offset_top;
+      eptr = md->end_match_ptr;
+      ecode++;
+      }
+    break;
+
+    /* "Once" brackets are like assertion brackets except that after a match,
+    the point in the subject string is not moved back. Thus there can never be
+    a move back into the brackets. Check the alternative branches in turn - the
+    matching won't pass the KET for this kind of subpattern. If any one branch
+    matches, we carry on as at the end of a normal bracket, leaving the subject
+    pointer. */
+
+    case OP_ONCE:
+      {
+      const uschar *prev = ecode;
+      const uschar *saved_eptr = eptr;
+
+      do
+        {
+        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
+          break;
+        ecode += (ecode[1] << 8) + ecode[2];
+        }
+      while (*ecode == OP_ALT);
+
+      /* If hit the end of the group (which could be repeated), fail */
+
+      if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE;
+
+      /* Continue as from after the assertion, updating the offsets high water
+      mark, since extracts may have been taken. */
+
+      do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
+
+      offset_top = md->end_offset_top;
+      eptr = md->end_match_ptr;
+
+      /* For a non-repeating ket, just continue at this level. This also
+      happens for a repeating ket if no characters were matched in the group.
+      This is the forcible breaking of infinite loops as implemented in Perl
+      5.005. If there is an options reset, it will get obeyed in the normal
+      course of events. */
+
+      if (*ecode == OP_KET || eptr == saved_eptr)
+        {
+        ecode += 3;
+        break;
+        }
+
+      /* The repeating kets try the rest of the pattern or restart from the
+      preceding bracket, in the appropriate order. We need to reset any options
+      that changed within the bracket before re-running it, so check the next
+      opcode. */
+
+      if (ecode[3] == OP_OPT)
+        {
+        ims = (ims & ~PCRE_IMS) | ecode[4];
+        DPRINTF(("ims set to %02lx at group repeat\n", ims));
+        }
+
+      if (*ecode == OP_KETRMIN)
+        {
+        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
+            match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
+              return TRUE;
+        }
+      else  /* OP_KETRMAX */
+        {
+        if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
+            match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
+        }
+      }
+    return FALSE;
+
+    /* An alternation is the end of a branch; scan along to find the end of the
+    bracketed group and go to there. */
+
+    case OP_ALT:
+    do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
+    break;
+
+    /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
+    that it may occur zero times. It may repeat infinitely, or not at all -
+    i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
+    repeat limits are compiled as a number of copies, with the optional ones
+    preceded by BRAZERO or BRAMINZERO. */
+
+    case OP_BRAZERO:
+      {
+      const uschar *next = ecode+1;
+      if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup))
+        return TRUE;
+      do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
+      ecode = next + 3;
+      }
+    break;
+
+    case OP_BRAMINZERO:
+      {
+      const uschar *next = ecode+1;
+      do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
+      if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup))
+        return TRUE;
+      ecode++;
+      }
+    break;
+
+    /* End of a group, repeated or non-repeating. If we are at the end of
+    an assertion "group", stop matching and return TRUE, but record the
+    current high water mark for use by positive assertions. Do this also
+    for the "once" (not-backup up) groups. */
+
+    case OP_KET:
+    case OP_KETRMIN:
+    case OP_KETRMAX:
+      {
+      const uschar *prev = ecode - (ecode[1] << 8) - ecode[2];
+      const uschar *saved_eptr = eptrb->saved_eptr;
+
+      eptrb = eptrb->prev;    /* Back up the stack of bracket start pointers */
+
+      if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
+          *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
+          *prev == OP_ONCE)
+        {
+        md->end_match_ptr = eptr;      /* For ONCE */
+        md->end_offset_top = offset_top;
+        return TRUE;
+        }
+
+      /* In all other cases except a conditional group we have to check the
+      group number back at the start and if necessary complete handling an
+      extraction by setting the offsets and bumping the high water mark. */
+
+      if (*prev != OP_COND)
+        {
+        int number = *prev - OP_BRA;
+        int offset = number << 1;
+
+#ifdef DEBUG
+        printf("end bracket %d", number);
+        printf("\n");
+#endif
+
+        if (number > 0)
+          {
+          if (offset >= md->offset_max) md->offset_overflow = TRUE; else
+            {
+            md->offset_vector[offset] =
+              md->offset_vector[md->offset_end - number];
+            md->offset_vector[offset+1] = eptr - md->start_subject;
+            if (offset_top <= offset) offset_top = offset + 2;
+            }
+          }
+        }
+
+      /* Reset the value of the ims flags, in case they got changed during
+      the group. */
+
+      ims = original_ims;
+      DPRINTF(("ims reset to %02lx\n", ims));
+
+      /* For a non-repeating ket, just continue at this level. This also
+      happens for a repeating ket if no characters were matched in the group.
+      This is the forcible breaking of infinite loops as implemented in Perl
+      5.005. If there is an options reset, it will get obeyed in the normal
+      course of events. */
+
+      if (*ecode == OP_KET || eptr == saved_eptr)
+        {
+        ecode += 3;
+        break;
+        }
+
+      /* The repeating kets try the rest of the pattern or restart from the
+      preceding bracket, in the appropriate order. */
+
+      if (*ecode == OP_KETRMIN)
+        {
+        if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
+            match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
+              return TRUE;
+        }
+      else  /* OP_KETRMAX */
+        {
+        if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
+            match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
+        }
+      }
+    return FALSE;
+
+    /* Start of subject unless notbol, or after internal newline if multiline */
+
+    case OP_CIRC:
+    if (md->notbol && eptr == md->start_subject) return FALSE;
+    if ((ims & PCRE_MULTILINE) != 0)
+      {
+      if (eptr != md->start_subject && eptr[-1] != '\n') return FALSE;
+      ecode++;
+      break;
+      }
+    /* ... else fall through */
+
+    /* Start of subject assertion */
+
+    case OP_SOD:
+    if (eptr != md->start_subject) return FALSE;
+    ecode++;
+    break;
+
+    /* Assert before internal newline if multiline, or before a terminating
+    newline unless endonly is set, else end of subject unless noteol is set. */
+
+    case OP_DOLL:
+    if ((ims & PCRE_MULTILINE) != 0)
+      {
+      if (eptr < md->end_subject) { if (*eptr != '\n') return FALSE; }
+        else { if (md->noteol) return FALSE; }
+      ecode++;
+      break;
+      }
+    else
+      {
+      if (md->noteol) return FALSE;
+      if (!md->endonly)
+        {
+        if (eptr < md->end_subject - 1 ||
+           (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE;
+
+        ecode++;
+        break;
+        }
+      }
+    /* ... else fall through */
+
+    /* End of subject assertion (\z) */
+
+    case OP_EOD:
+    if (eptr < md->end_subject) return FALSE;
+    ecode++;
+    break;
+
+    /* End of subject or ending \n assertion (\Z) */
+
+    case OP_EODN:
+    if (eptr < md->end_subject - 1 ||
+       (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE;
+    ecode++;
+    break;
+
+    /* Word boundary assertions */
+
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+      {
+      BOOL prev_is_word = (eptr != md->start_subject) &&
+        ((md->ctypes[eptr[-1]] & ctype_word) != 0);
+      BOOL cur_is_word = (eptr < md->end_subject) &&
+        ((md->ctypes[*eptr] & ctype_word) != 0);
+      if ((*ecode++ == OP_WORD_BOUNDARY)?
+           cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+        return FALSE;
+      }
+    break;
+
+    /* Match a single character type; inline for speed */
+
+    case OP_ANY:
+    if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == '\n')
+      return FALSE;
+    if (eptr++ >= md->end_subject) return FALSE;
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+#endif
+    ecode++;
+    break;
+
+    case OP_NOT_DIGIT:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_digit) != 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    case OP_DIGIT:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_digit) == 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    case OP_NOT_WHITESPACE:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_space) != 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    case OP_WHITESPACE:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_space) == 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    case OP_NOT_WORDCHAR:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_word) != 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    case OP_WORDCHAR:
+    if (eptr >= md->end_subject ||
+       (md->ctypes[*eptr++] & ctype_word) == 0)
+      return FALSE;
+    ecode++;
+    break;
+
+    /* Match a back reference, possibly repeatedly. Look past the end of the
+    item to see if there is repeat information following. The code is similar
+    to that for character classes, but repeated for efficiency. Then obey
+    similar code to character type repeats - written out again for speed.
+    However, if the referenced string is the empty string, always treat
+    it as matched, any number of times (otherwise there could be infinite
+    loops). */
+
+    case OP_REF:
+      {
+      int length;
+      int offset = ecode[1] << 1;                /* Doubled reference number */
+      ecode += 2;                                /* Advance past the item */
+
+      /* If the reference is unset, set the length to be longer than the amount
+      of subject left; this ensures that every attempt at a match fails. We
+      can't just fail here, because of the possibility of quantifiers with zero
+      minima. */
+
+      length = (offset >= offset_top || md->offset_vector[offset] < 0)?
+        md->end_subject - eptr + 1 :
+        md->offset_vector[offset+1] - md->offset_vector[offset];
+
+      /* Set up for repetition, or handle the non-repeated case */
+
+      switch (*ecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        c = *ecode++ - OP_CRSTAR;
+        minimize = (c & 1) != 0;
+        min = rep_min[c];                 /* Pick up values from tables; */
+        max = rep_max[c];                 /* zero for max => infinity */
+        if (max == 0) max = INT_MAX;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        minimize = (*ecode == OP_CRMINRANGE);
+        min = (ecode[1] << 8) + ecode[2];
+        max = (ecode[3] << 8) + ecode[4];
+        if (max == 0) max = INT_MAX;
+        ecode += 5;
+        break;
+
+        default:               /* No repeat follows */
+        if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
+        eptr += length;
+        continue;              /* With the main loop */
+        }
+
+      /* If the length of the reference is zero, just continue with the
+      main loop. */
+
+      if (length == 0) continue;
+
+      /* First, ensure the minimum number of matches are present. We get back
+      the length of the reference string explicitly rather than passing the
+      address of eptr, so that eptr can be a register variable. */
+
+      for (i = 1; i <= min; i++)
+        {
+        if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
+        eptr += length;
+        }
+
+      /* If min = max, continue at the same level without recursion.
+      They are not both allowed to be zero. */
+
+      if (min == max) continue;
+
+      /* If minimizing, keep trying and advancing the pointer */
+
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || !match_ref(offset, eptr, length, md, ims))
+            return FALSE;
+          eptr += length;
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest string and work backwards */
+
+      else
+        {
+        const uschar *pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (!match_ref(offset, eptr, length, md, ims)) break;
+          eptr += length;
+          }
+        while (eptr >= pp)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          eptr -= length;
+          }
+        return FALSE;
+        }
+      }
+    /* Control never gets here */
+
+
+
+    /* Match a character class, possibly repeatedly. Look past the end of the
+    item to see if there is repeat information following. Then obey similar
+    code to character type repeats - written out again for speed. */
+
+    case OP_CLASS:
+      {
+      const uschar *data = ecode + 1;  /* Save for matching */
+      ecode += 33;                     /* Advance past the item */
+
+      switch (*ecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        c = *ecode++ - OP_CRSTAR;
+        minimize = (c & 1) != 0;
+        min = rep_min[c];                 /* Pick up values from tables; */
+        max = rep_max[c];                 /* zero for max => infinity */
+        if (max == 0) max = INT_MAX;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        minimize = (*ecode == OP_CRMINRANGE);
+        min = (ecode[1] << 8) + ecode[2];
+        max = (ecode[3] << 8) + ecode[4];
+        if (max == 0) max = INT_MAX;
+        ecode += 5;
+        break;
+
+        default:               /* No repeat follows */
+        min = max = 1;
+        break;
+        }
+
+      /* First, ensure the minimum number of matches are present. */
+
+      for (i = 1; i <= min; i++)
+        {
+        if (eptr >= md->end_subject) return FALSE;
+        GETCHARINC(c, eptr)         /* Get character; increment eptr */
+
+#ifdef SUPPORT_UTF8
+        /* We do not yet support class members > 255 */
+        if (c > 255) return FALSE;
+#endif
+
+        if ((data[c/8] & (1 << (c&7))) != 0) continue;
+        return FALSE;
+        }
+
+      /* If max == min we can continue with the main loop without the
+      need to recurse. */
+
+      if (min == max) continue;
+
+      /* If minimizing, keep testing the rest of the expression and advancing
+      the pointer while it matches the class. */
+
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || eptr >= md->end_subject) return FALSE;
+          GETCHARINC(c, eptr)       /* Get character; increment eptr */
+
+#ifdef SUPPORT_UTF8
+          /* We do not yet support class members > 255 */
+          if (c > 255) return FALSE;
+#endif
+          if ((data[c/8] & (1 << (c&7))) != 0) continue;
+          return FALSE;
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest possible run, then work backwards. */
+
+      else
+        {
+        const uschar *pp = eptr;
+        int len = 1;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject) break;
+          GETCHARLEN(c, eptr, len)  /* Get character, set length if UTF-8 */
+
+#ifdef SUPPORT_UTF8
+          /* We do not yet support class members > 255 */
+          if (c > 255) break;
+#endif
+          if ((data[c/8] & (1 << (c&7))) == 0) break;
+          eptr += len;
+          }
+
+        while (eptr >= pp)
+          {
+          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+
+#ifdef SUPPORT_UTF8
+          BACKCHAR(eptr)
+#endif
+          }
+        return FALSE;
+        }
+      }
+    /* Control never gets here */
+
+    /* Match a run of characters */
+
+    case OP_CHARS:
+      {
+      register int length = ecode[1];
+      ecode += 2;
+
+#ifdef DEBUG    /* Sigh. Some compilers never learn. */
+      if (eptr >= md->end_subject)
+        printf("matching subject <null> against pattern ");
+      else
+        {
+        printf("matching subject ");
+        pchars(eptr, length, TRUE, md);
+        printf(" against pattern ");
+        }
+      pchars(ecode, length, FALSE, md);
+      printf("\n");
+#endif
+
+      if (length > md->end_subject - eptr) return FALSE;
+      if ((ims & PCRE_CASELESS) != 0)
+        {
+        while (length-- > 0)
+          if (md->lcc[*ecode++] != md->lcc[*eptr++])
+            return FALSE;
+        }
+      else
+        {
+        while (length-- > 0) if (*ecode++ != *eptr++) return FALSE;
+        }
+      }
+    break;
+
+    /* Match a single character repeatedly; different opcodes share code. */
+
+    case OP_EXACT:
+    min = max = (ecode[1] << 8) + ecode[2];
+    ecode += 3;
+    goto REPEATCHAR;
+
+    case OP_UPTO:
+    case OP_MINUPTO:
+    min = 0;
+    max = (ecode[1] << 8) + ecode[2];
+    minimize = *ecode == OP_MINUPTO;
+    ecode += 3;
+    goto REPEATCHAR;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    c = *ecode++ - OP_STAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single-character matches. We can give
+    up quickly if there are fewer than the minimum number of characters left in
+    the subject. */
+
+    REPEATCHAR:
+    if (min > md->end_subject - eptr) return FALSE;
+    c = *ecode++;
+
+    /* The code is duplicated for the caseless and caseful cases, for speed,
+    since matching characters is likely to be quite common. First, ensure the
+    minimum number of matches are present. If min = max, continue at the same
+    level without recursing. Otherwise, if minimizing, keep trying the rest of
+    the expression and advancing one matching character if failing, up to the
+    maximum. Alternatively, if maximizing, find the maximum number of
+    characters and work backwards. */
+
+    DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max,
+      max, eptr));
+
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+      c = md->lcc[c];
+      for (i = 1; i <= min; i++)
+        if (c != md->lcc[*eptr++]) return FALSE;
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || eptr >= md->end_subject ||
+              c != md->lcc[*eptr++])
+            return FALSE;
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        const uschar *pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || c != md->lcc[*eptr]) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+        return FALSE;
+        }
+      /* Control never gets here */
+      }
+
+    /* Caseful comparisons */
+
+    else
+      {
+      for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE;
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE;
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        const uschar *pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || c != *eptr) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+         if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+           return TRUE;
+        return FALSE;
+        }
+      }
+    /* Control never gets here */
+
+    /* Match a negated single character */
+
+    case OP_NOT:
+    if (eptr >= md->end_subject) return FALSE;
+    ecode++;
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+      if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE;
+      }
+    else
+      {
+      if (*ecode++ == *eptr++) return FALSE;
+      }
+    break;
+
+    /* Match a negated single character repeatedly. This is almost a repeat of
+    the code for a repeated single character, but I haven't found a nice way of
+    commoning these up that doesn't require a test of the positive/negative
+    option for each character match. Maybe that wouldn't add very much to the
+    time taken, but character matching *is* what this is all about... */
+
+    case OP_NOTEXACT:
+    min = max = (ecode[1] << 8) + ecode[2];
+    ecode += 3;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    min = 0;
+    max = (ecode[1] << 8) + ecode[2];
+    minimize = *ecode == OP_NOTMINUPTO;
+    ecode += 3;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    c = *ecode++ - OP_NOTSTAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single-character matches. We can give
+    up quickly if there are fewer than the minimum number of characters left in
+    the subject. */
+
+    REPEATNOTCHAR:
+    if (min > md->end_subject - eptr) return FALSE;
+    c = *ecode++;
+
+    /* The code is duplicated for the caseless and caseful cases, for speed,
+    since matching characters is likely to be quite common. First, ensure the
+    minimum number of matches are present. If min = max, continue at the same
+    level without recursing. Otherwise, if minimizing, keep trying the rest of
+    the expression and advancing one matching character if failing, up to the
+    maximum. Alternatively, if maximizing, find the maximum number of
+    characters and work backwards. */
+
+    DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max,
+      max, eptr));
+
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+      c = md->lcc[c];
+      for (i = 1; i <= min; i++)
+        if (c == md->lcc[*eptr++]) return FALSE;
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || eptr >= md->end_subject ||
+              c == md->lcc[*eptr++])
+            return FALSE;
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        const uschar *pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || c == md->lcc[*eptr]) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+          if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+        return FALSE;
+        }
+      /* Control never gets here */
+      }
+
+    /* Caseful comparisons */
+
+    else
+      {
+      for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE;
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (i = min;; i++)
+          {
+          if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
+            return TRUE;
+          if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE;
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        const uschar *pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || c == *eptr) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+         if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+           return TRUE;
+        return FALSE;
+        }
+      }
+    /* Control never gets here */
+
+    /* Match a single character type repeatedly; several different opcodes
+    share code. This is very similar to the code for single characters, but we
+    repeat it in the interests of efficiency. */
+
+    case OP_TYPEEXACT:
+    min = max = (ecode[1] << 8) + ecode[2];
+    minimize = TRUE;
+    ecode += 3;
+    goto REPEATTYPE;
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    min = 0;
+    max = (ecode[1] << 8) + ecode[2];
+    minimize = *ecode == OP_TYPEMINUPTO;
+    ecode += 3;
+    goto REPEATTYPE;
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    c = *ecode++ - OP_TYPESTAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single character type matches */
+
+    REPEATTYPE:
+    ctype = *ecode++;      /* Code for the character type */
+
+    /* First, ensure the minimum number of matches are present. Use inline
+    code for maximizing the speed, and do the type test once at the start
+    (i.e. keep it out of the loop). Also we can test that there are at least
+    the minimum number of bytes before we start, except when doing '.' in
+    UTF8 mode. Leave the test in in all cases; in the special case we have
+    to test after each character. */
+
+    if (min > md->end_subject - eptr) return FALSE;
+    if (min > 0) switch(ctype)
+      {
+      case OP_ANY:
+#ifdef SUPPORT_UTF8
+      if (md->utf8)
+        {
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             (*eptr++ == '\n' && (ims & PCRE_DOTALL) == 0))
+            return FALSE;
+          while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+          }
+        break;
+        }
+#endif
+      /* Non-UTF8 can be faster */
+      if ((ims & PCRE_DOTALL) == 0)
+        { for (i = 1; i <= min; i++) if (*eptr++ == '\n') return FALSE; }
+      else eptr += min;
+      break;
+
+      case OP_NOT_DIGIT:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE;
+      break;
+
+      case OP_DIGIT:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE;
+      break;
+
+      case OP_NOT_WHITESPACE:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE;
+      break;
+
+      case OP_WHITESPACE:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE;
+      break;
+
+      case OP_NOT_WORDCHAR:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_word) != 0)
+          return FALSE;
+      break;
+
+      case OP_WORDCHAR:
+      for (i = 1; i <= min; i++)
+        if ((md->ctypes[*eptr++] & ctype_word) == 0)
+          return FALSE;
+      break;
+      }
+
+    /* If min = max, continue at the same level without recursing */
+
+    if (min == max) continue;
+
+    /* If minimizing, we have to test the rest of the pattern before each
+    subsequent match. */
+
+    if (minimize)
+      {
+      for (i = min;; i++)
+        {
+        if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE;
+        if (i >= max || eptr >= md->end_subject) return FALSE;
+
+        c = *eptr++;
+        switch(ctype)
+          {
+          case OP_ANY:
+          if ((ims & PCRE_DOTALL) == 0 && c == '\n') return FALSE;
+#ifdef SUPPORT_UTF8
+          if (md->utf8)
+            while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+#endif
+          break;
+
+          case OP_NOT_DIGIT:
+          if ((md->ctypes[c] & ctype_digit) != 0) return FALSE;
+          break;
+
+          case OP_DIGIT:
+          if ((md->ctypes[c] & ctype_digit) == 0) return FALSE;
+          break;
+
+          case OP_NOT_WHITESPACE:
+          if ((md->ctypes[c] & ctype_space) != 0) return FALSE;
+          break;
+
+          case OP_WHITESPACE:
+          if  ((md->ctypes[c] & ctype_space) == 0) return FALSE;
+          break;
+
+          case OP_NOT_WORDCHAR:
+          if ((md->ctypes[c] & ctype_word) != 0) return FALSE;
+          break;
+
+          case OP_WORDCHAR:
+          if ((md->ctypes[c] & ctype_word) == 0) return FALSE;
+          break;
+          }
+        }
+      /* Control never gets here */
+      }
+
+    /* If maximizing it is worth using inline code for speed, doing the type
+    test once at the start (i.e. keep it out of the loop). */
+
+    else
+      {
+      const uschar *pp = eptr;
+      switch(ctype)
+        {
+        case OP_ANY:
+
+        /* Special code is required for UTF8, but when the maximum is unlimited
+        we don't need it. */
+
+#ifdef SUPPORT_UTF8
+        if (md->utf8 && max < INT_MAX)
+          {
+          if ((ims & PCRE_DOTALL) == 0)
+            {
+            for (i = min; i < max; i++)
+              {
+              if (eptr >= md->end_subject || *eptr++ == '\n') break;
+              while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+              }
+            }
+          else
+            {
+            for (i = min; i < max; i++)
+              {
+              eptr++;
+              while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+              }
+            }
+          break;
+          }
+#endif
+        /* Non-UTF8 can be faster */
+        if ((ims & PCRE_DOTALL) == 0)
+          {
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || *eptr == '\n') break;
+            eptr++;
+            }
+          }
+        else
+          {
+          c = max - min;
+          if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+          eptr += c;
+          }
+        break;
+
+        case OP_NOT_DIGIT:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
+            break;
+          eptr++;
+          }
+        break;
+
+        case OP_DIGIT:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
+            break;
+          eptr++;
+          }
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
+            break;
+          eptr++;
+          }
+        break;
+
+        case OP_WHITESPACE:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
+            break;
+          eptr++;
+          }
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
+            break;
+          eptr++;
+          }
+        break;
+
+        case OP_WORDCHAR:
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
+            break;
+          eptr++;
+          }
+        break;
+        }
+
+      while (eptr >= pp)
+        {
+        if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
+          return TRUE;
+#ifdef SUPPORT_UTF8
+        if (md->utf8)
+          while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--;
+#endif
+        }
+      return FALSE;
+      }
+    /* Control never gets here */
+
+    /* There's been some horrible disaster. */
+
+    default:
+    DPRINTF(("Unknown opcode %d\n", *ecode));
+    md->errorcode = PCRE_ERROR_UNKNOWN_NODE;
+    return FALSE;
+    }
+
+  /* Do not stick any code in here without much thought; it is assumed
+  that "continue" in the code above comes out to here to repeat the main
+  loop. */
+
+  }             /* End of main loop */
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+*         Execute a Regular Expression           *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+  external_re     points to the compiled expression
+  external_extra  points to "hints" from pcre_study() or is NULL
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  offsets         points to a vector of ints to be filled in with offsets
+  offsetcount     the number of elements in the vector
+
+Returns:          > 0 => success; value is the number of elements filled in
+                  = 0 => success, but offsets is not big enough
+                   -1 => failed to match
+                 < -1 => some kind of unexpected problem
+*/
+
+int
+pcre_exec(const pcre *external_re, const pcre_extra *external_extra,
+  const char *subject, int length, int start_offset, int options, int *offsets,
+  int offsetcount)
+{
+int resetcount, ocount;
+int first_char = -1;
+int req_char = -1;
+int req_char2 = -1;
+unsigned long int ims = 0;
+match_data match_block;
+const uschar *start_bits = NULL;
+const uschar *start_match = (const uschar *)subject + start_offset;
+const uschar *end_subject;
+const uschar *req_char_ptr = start_match - 1;
+const real_pcre *re = (const real_pcre *)external_re;
+const real_pcre_extra *extra = (const real_pcre_extra *)external_extra;
+BOOL using_temporary_offsets = FALSE;
+BOOL anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
+BOOL startline = (re->options & PCRE_STARTLINE) != 0;
+
+if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
+
+if (re == NULL || subject == NULL ||
+   (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
+
+match_block.start_pattern = re->code;
+match_block.start_subject = (const uschar *)subject;
+match_block.end_subject = match_block.start_subject + length;
+end_subject = match_block.end_subject;
+
+match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
+match_block.utf8 = (re->options & PCRE_UTF8) != 0;
+
+match_block.notbol = (options & PCRE_NOTBOL) != 0;
+match_block.noteol = (options & PCRE_NOTEOL) != 0;
+match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
+
+match_block.errorcode = PCRE_ERROR_NOMATCH;     /* Default error */
+
+match_block.lcc = re->tables + lcc_offset;
+match_block.ctypes = re->tables + ctypes_offset;
+
+/* The ims options can vary during the matching as a result of the presence
+of (?ims) items in the pattern. They are kept in a local variable so that
+restoring at the exit of a group is easy. */
+
+ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
+
+/* If the expression has got more back references than the offsets supplied can
+hold, we get a temporary bit of working store to use during the matching.
+Otherwise, we can use the vector supplied, rounding down its size to a multiple
+of 3. */
+
+ocount = offsetcount - (offsetcount % 3);
+
+if (re->top_backref > 0 && re->top_backref >= ocount/3)
+  {
+  ocount = re->top_backref * 3 + 3;
+  match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
+  if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
+  using_temporary_offsets = TRUE;
+  DPRINTF(("Got memory to hold back references\n"));
+  }
+else match_block.offset_vector = offsets;
+
+match_block.offset_end = ocount;
+match_block.offset_max = (2*ocount)/3;
+match_block.offset_overflow = FALSE;
+
+/* Compute the minimum number of offsets that we need to reset each time. Doing
+this makes a huge difference to execution time when there aren't many brackets
+in the pattern. */
+
+resetcount = 2 + re->top_bracket * 2;
+if (resetcount > offsetcount) resetcount = ocount;
+
+/* Reset the working variable associated with each extraction. These should
+never be used unless previously set, but they get saved and restored, and so we
+initialize them to avoid reading uninitialized locations. */
+
+if (match_block.offset_vector != NULL)
+  {
+  register int *iptr = match_block.offset_vector + ocount;
+  register int *iend = iptr - resetcount/2 + 1;
+  while (--iptr >= iend) *iptr = -1;
+  }
+
+/* Set up the first character to match, if available. The first_char value is
+never set for an anchored regular expression, but the anchoring may be forced
+at run time, so we have to test for anchoring. The first char may be unset for
+an unanchored pattern, of course. If there's no first char and the pattern was
+studied, there may be a bitmap of possible first characters. */
+
+if (!anchored)
+  {
+  if ((re->options & PCRE_FIRSTSET) != 0)
+    {
+    first_char = re->first_char;
+    if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char];
+    }
+  else
+    if (!startline && extra != NULL &&
+      (extra->options & PCRE_STUDY_MAPPED) != 0)
+        start_bits = extra->start_bits;
+  }
+
+/* For anchored or unanchored matches, there may be a "last known required
+character" set. If the PCRE_CASELESS is set, implying that the match starts
+caselessly, or if there are any changes of this flag within the regex, set up
+both cases of the character. Otherwise set the two values the same, which will
+avoid duplicate testing (which takes significant time). This covers the vast
+majority of cases. It will be suboptimal when the case flag changes in a regex
+and the required character in fact is caseful. */
+
+if ((re->options & PCRE_REQCHSET) != 0)
+  {
+  req_char = re->req_char;
+  req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)?
+    (re->tables + fcc_offset)[req_char] : req_char;
+  }
+
+/* Loop for handling unanchored repeated matching attempts; for anchored regexs
+the loop runs just once. */
+
+do
+  {
+  int rc;
+  register int *iptr = match_block.offset_vector;
+  register int *iend = iptr + resetcount;
+
+  /* Reset the maximum number of extractions we might see. */
+
+  while (iptr < iend) *iptr++ = -1;
+
+  /* Advance to a unique first char if possible */
+
+  if (first_char >= 0)
+    {
+    if ((ims & PCRE_CASELESS) != 0)
+      while (start_match < end_subject &&
+             match_block.lcc[*start_match] != first_char)
+        start_match++;
+    else
+      while (start_match < end_subject && *start_match != first_char)
+        start_match++;
+    }
+
+  /* Or to just after \n for a multiline match if possible */
+
+  else if (startline)
+    {
+    if (start_match > match_block.start_subject + start_offset)
+      {
+      while (start_match < end_subject && start_match[-1] != '\n')
+        start_match++;
+      }
+    }
+
+  /* Or to a non-unique first char after study */
+
+  else if (start_bits != NULL)
+    {
+    while (start_match < end_subject)
+      {
+      register int c = *start_match;
+      if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
+      }
+    }
+
+#ifdef DEBUG  /* Sigh. Some compilers never learn. */
+  printf(">>>> Match against: ");
+  pchars(start_match, end_subject - start_match, TRUE, &match_block);
+  printf("\n");
+#endif
+
+  /* If req_char is set, we know that that character must appear in the subject
+  for the match to succeed. If the first character is set, req_char must be
+  later in the subject; otherwise the test starts at the match point. This
+  optimization can save a huge amount of backtracking in patterns with nested
+  unlimited repeats that aren't going to match. We don't know what the state of
+  case matching may be when this character is hit, so test for it in both its
+  cases if necessary. However, the different cased versions will not be set up
+  unless PCRE_CASELESS was given or the casing state changes within the regex.
+  Writing separate code makes it go faster, as does using an autoincrement and
+  backing off on a match. */
+
+  if (req_char >= 0)
+    {
+    register const uschar *p = start_match + ((first_char >= 0)? 1 : 0);
+
+    /* We don't need to repeat the search if we haven't yet reached the
+    place we found it at last time. */
+
+    if (p > req_char_ptr)
+      {
+      /* Do a single test if no case difference is set up */
+
+      if (req_char == req_char2)
+        {
+        while (p < end_subject)
+          {
+          if (*p++ == req_char) { p--; break; }
+          }
+        }
+
+      /* Otherwise test for either case */
+
+      else
+        {
+        while (p < end_subject)
+          {
+          register int pp = *p++;
+          if (pp == req_char || pp == req_char2) { p--; break; }
+          }
+        }
+
+      /* If we can't find the required character, break the matching loop */
+
+      if (p >= end_subject) break;
+
+      /* If we have found the required character, save the point where we
+      found it, so that we don't search again next time round the loop if
+      the start hasn't passed this character yet. */
+
+      req_char_ptr = p;
+      }
+    }
+
+  /* When a match occurs, substrings will be set for all internal extractions;
+  we just need to set up the whole thing as substring 0 before returning. If
+  there were too many extractions, set the return code to zero. In the case
+  where we had to get some local store to hold offsets for backreferences, copy
+  those back references that we can. In this case there need not be overflow
+  if certain parts of the pattern were not used. */
+
+  match_block.start_match = start_match;
+  if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup))
+    continue;
+
+  /* Copy the offset information from temporary store if necessary */
+
+  if (using_temporary_offsets)
+    {
+    if (offsetcount >= 4)
+      {
+      memcpy(offsets + 2, match_block.offset_vector + 2,
+        (offsetcount - 2) * sizeof(int));
+      DPRINTF(("Copied offsets from temporary memory\n"));
+      }
+    if (match_block.end_offset_top > offsetcount)
+      match_block.offset_overflow = TRUE;
+
+    DPRINTF(("Freeing temporary memory\n"));
+    (pcre_free)(match_block.offset_vector);
+    }
+
+  rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
+
+  if (match_block.offset_end < 2) rc = 0; else
+    {
+    offsets[0] = start_match - match_block.start_subject;
+    offsets[1] = match_block.end_match_ptr - match_block.start_subject;
+    }
+
+  DPRINTF((">>>> returning %d\n", rc));
+  return rc;
+  }
+
+/* This "while" is the end of the "do" above */
+
+while (!anchored &&
+       match_block.errorcode == PCRE_ERROR_NOMATCH &&
+       start_match++ < end_subject);
+
+if (using_temporary_offsets)
+  {
+  DPRINTF(("Freeing temporary memory\n"));
+  (pcre_free)(match_block.offset_vector);
+  }
+
+DPRINTF((">>>> returning %d\n", match_block.errorcode));
+
+return match_block.errorcode;
+}
+
+/* End of pcre.c */
diff --git a/pcre/pcre.h b/pcre/pcre.h
new file mode 100644 (file)
index 0000000..e5a875a
--- /dev/null
@@ -0,0 +1,110 @@
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* Copyright (c) 1997-2000 University of Cambridge */
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The file pcre.h is build by "configure". Do not edit it; instead
+make changes to pcre.in. */
+
+#define PCRE_MAJOR 3
+#define PCRE_MINOR 4
+#define PCRE_DATE  22-Aug-2000
+
+/* Win32 uses DLL by default */
+
+#ifdef _WIN32
+# ifdef STATIC
+#  define PCRE_DL_IMPORT
+# else
+#  define PCRE_DL_IMPORT __declspec(dllimport)
+# endif
+#else
+# define PCRE_DL_IMPORT
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS        0x0001
+#define PCRE_MULTILINE       0x0002
+#define PCRE_DOTALL          0x0004
+#define PCRE_EXTENDED        0x0008
+#define PCRE_ANCHORED        0x0010
+#define PCRE_DOLLAR_ENDONLY  0x0020
+#define PCRE_EXTRA           0x0040
+#define PCRE_NOTBOL          0x0080
+#define PCRE_NOTEOL          0x0100
+#define PCRE_UNGREEDY        0x0200
+#define PCRE_NOTEMPTY        0x0400
+#define PCRE_UTF8            0x0800
+
+/* Exec-time and get-time error codes */
+
+#define PCRE_ERROR_NOMATCH        (-1)
+#define PCRE_ERROR_NULL           (-2)
+#define PCRE_ERROR_BADOPTION      (-3)
+#define PCRE_ERROR_BADMAGIC       (-4)
+#define PCRE_ERROR_UNKNOWN_NODE   (-5)
+#define PCRE_ERROR_NOMEMORY       (-6)
+#define PCRE_ERROR_NOSUBSTRING    (-7)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS         0
+#define PCRE_INFO_SIZE            1
+#define PCRE_INFO_CAPTURECOUNT    2
+#define PCRE_INFO_BACKREFMAX      3
+#define PCRE_INFO_FIRSTCHAR       4
+#define PCRE_INFO_FIRSTTABLE      5
+#define PCRE_INFO_LASTLITERAL     6
+
+/* Types */
+
+typedef void pcre;
+typedef void pcre_extra;
+
+/* Store get and free functions. These can be set to alternative malloc/free
+functions if required. Some magic is required for Win32 DLL; it is null on
+other OS. */
+
+PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t);
+PCRE_DL_IMPORT extern void  (*pcre_free)(void *);
+
+#undef PCRE_DL_IMPORT
+
+/* Functions */
+
+extern pcre *pcre_compile(const char *, int, const char **, int *,
+              const unsigned char *);
+extern int  pcre_copy_substring(const char *, int *, int, int, char *, int);
+extern int  pcre_exec(const pcre *, const pcre_extra *, const char *,
+              int, int, int, int *, int);
+extern void pcre_free_substring(const char *);
+extern void pcre_free_substring_list(const char **);
+extern int  pcre_get_substring(const char *, int *, int, int, const char **);
+extern int  pcre_get_substring_list(const char *, int *, int, const char ***);
+extern int  pcre_info(const pcre *, int *, int *);
+extern int  pcre_fullinfo(const pcre *, const pcre_extra *, int, void *);
+extern unsigned const char *pcre_maketables(void);
+extern pcre_extra *pcre_study(const pcre *, int, const char **);
+extern const char *pcre_version(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */
diff --git a/pcre/pcre.in b/pcre/pcre.in
new file mode 100644 (file)
index 0000000..1dffb02
--- /dev/null
@@ -0,0 +1,110 @@
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* Copyright (c) 1997-2000 University of Cambridge */
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The file pcre.h is build by "configure". Do not edit it; instead
+make changes to pcre.in. */
+
+#define PCRE_MAJOR @PCRE_MAJOR@
+#define PCRE_MINOR @PCRE_MINOR@
+#define PCRE_DATE  @PCRE_DATE@
+
+/* Win32 uses DLL by default */
+
+#ifdef _WIN32
+# ifdef STATIC
+#  define PCRE_DL_IMPORT
+# else
+#  define PCRE_DL_IMPORT __declspec(dllimport)
+# endif
+#else
+# define PCRE_DL_IMPORT
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS        0x0001
+#define PCRE_MULTILINE       0x0002
+#define PCRE_DOTALL          0x0004
+#define PCRE_EXTENDED        0x0008
+#define PCRE_ANCHORED        0x0010
+#define PCRE_DOLLAR_ENDONLY  0x0020
+#define PCRE_EXTRA           0x0040
+#define PCRE_NOTBOL          0x0080
+#define PCRE_NOTEOL          0x0100
+#define PCRE_UNGREEDY        0x0200
+#define PCRE_NOTEMPTY        0x0400
+#define PCRE_UTF8            0x0800
+
+/* Exec-time and get-time error codes */
+
+#define PCRE_ERROR_NOMATCH        (-1)
+#define PCRE_ERROR_NULL           (-2)
+#define PCRE_ERROR_BADOPTION      (-3)
+#define PCRE_ERROR_BADMAGIC       (-4)
+#define PCRE_ERROR_UNKNOWN_NODE   (-5)
+#define PCRE_ERROR_NOMEMORY       (-6)
+#define PCRE_ERROR_NOSUBSTRING    (-7)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS         0
+#define PCRE_INFO_SIZE            1
+#define PCRE_INFO_CAPTURECOUNT    2
+#define PCRE_INFO_BACKREFMAX      3
+#define PCRE_INFO_FIRSTCHAR       4
+#define PCRE_INFO_FIRSTTABLE      5
+#define PCRE_INFO_LASTLITERAL     6
+
+/* Types */
+
+typedef void pcre;
+typedef void pcre_extra;
+
+/* Store get and free functions. These can be set to alternative malloc/free
+functions if required. Some magic is required for Win32 DLL; it is null on
+other OS. */
+
+PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t);
+PCRE_DL_IMPORT extern void  (*pcre_free)(void *);
+
+#undef PCRE_DL_IMPORT
+
+/* Functions */
+
+extern pcre *pcre_compile(const char *, int, const char **, int *,
+              const unsigned char *);
+extern int  pcre_copy_substring(const char *, int *, int, int, char *, int);
+extern int  pcre_exec(const pcre *, const pcre_extra *, const char *,
+              int, int, int, int *, int);
+extern void pcre_free_substring(const char *);
+extern void pcre_free_substring_list(const char **);
+extern int  pcre_get_substring(const char *, int *, int, int, const char **);
+extern int  pcre_get_substring_list(const char *, int *, int, const char ***);
+extern int  pcre_info(const pcre *, int *, int *);
+extern int  pcre_fullinfo(const pcre *, const pcre_extra *, int, void *);
+extern unsigned const char *pcre_maketables(void);
+extern pcre_extra *pcre_study(const pcre *, int, const char **);
+extern const char *pcre_version(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */
diff --git a/pcre/pcreposix.c b/pcre/pcreposix.c
new file mode 100644 (file)
index 0000000..6aeb882
--- /dev/null
@@ -0,0 +1,280 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+This module is a wrapper that provides a POSIX API to the underlying PCRE
+functions.
+
+Written by: Philip Hazel <ph10@cam.ac.uk>
+
+           Copyright (c) 1997-2000 University of Cambridge
+
+-----------------------------------------------------------------------------
+Permission is granted to anyone to use this software for any purpose on any
+computer system, and to redistribute it freely, subject to the following
+restrictions:
+
+1. This software 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.
+
+2. The origin of this software must not be misrepresented, either by
+   explicit claim or by omission.
+
+3. Altered versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+4. If PCRE is embedded in any software that is released under the GNU
+   General Purpose Licence (GPL), then the terms of that licence shall
+   supersede any condition above with which it is incompatible.
+-----------------------------------------------------------------------------
+*/
+
+#include "internal.h"
+#include "pcreposix.h"
+#include "stdlib.h"
+
+
+
+/* Corresponding tables of PCRE error messages and POSIX error codes. */
+
+static const char *estring[] = {
+  ERR1,  ERR2,  ERR3,  ERR4,  ERR5,  ERR6,  ERR7,  ERR8,  ERR9,  ERR10,
+  ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20,
+  ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR29, ERR29, ERR30,
+  ERR31 };
+
+static int eint[] = {
+  REG_EESCAPE, /* "\\ at end of pattern" */
+  REG_EESCAPE, /* "\\c at end of pattern" */
+  REG_EESCAPE, /* "unrecognized character follows \\" */
+  REG_BADBR,   /* "numbers out of order in {} quantifier" */
+  REG_BADBR,   /* "number too big in {} quantifier" */
+  REG_EBRACK,  /* "missing terminating ] for character class" */
+  REG_ECTYPE,  /* "invalid escape sequence in character class" */
+  REG_ERANGE,  /* "range out of order in character class" */
+  REG_BADRPT,  /* "nothing to repeat" */
+  REG_BADRPT,  /* "operand of unlimited repeat could match the empty string" */
+  REG_ASSERT,  /* "internal error: unexpected repeat" */
+  REG_BADPAT,  /* "unrecognized character after (?" */
+  REG_ESIZE,   /* "too many capturing parenthesized sub-patterns" */
+  REG_EPAREN,  /* "missing )" */
+  REG_ESUBREG, /* "back reference to non-existent subpattern" */
+  REG_INVARG,  /* "erroffset passed as NULL" */
+  REG_INVARG,  /* "unknown option bit(s) set" */
+  REG_EPAREN,  /* "missing ) after comment" */
+  REG_ESIZE,   /* "too many sets of parentheses" */
+  REG_ESIZE,   /* "regular expression too large" */
+  REG_ESPACE,  /* "failed to get memory" */
+  REG_EPAREN,  /* "unmatched brackets" */
+  REG_ASSERT,  /* "internal error: code overflow" */
+  REG_BADPAT,  /* "unrecognized character after (?<" */
+  REG_BADPAT,  /* "lookbehind assertion is not fixed length" */
+  REG_BADPAT,  /* "malformed number after (?(" */
+  REG_BADPAT,  /* "conditional group containe more than two branches" */
+  REG_BADPAT,  /* "assertion expected after (?(" */
+  REG_BADPAT,  /* "(?p must be followed by )" */
+  REG_ECTYPE,  /* "unknown POSIX class name" */
+  REG_BADPAT,  /* "POSIX collating elements are not supported" */
+  REG_INVARG,  /* "this version of PCRE is not compiled with PCRE_UTF8 support" */
+  REG_BADPAT,  /* "characters with values > 255 are not yet supported in classes" */
+  REG_BADPAT,  /* "character value in \x{...} sequence is too large" */
+  REG_BADPAT   /* "invalid condition (?(0)" */
+};
+
+/* Table of texts corresponding to POSIX error codes */
+
+static const char *pstring[] = {
+  "",                                /* Dummy for value 0 */
+  "internal error",                  /* REG_ASSERT */
+  "invalid repeat counts in {}",     /* BADBR      */
+  "pattern error",                   /* BADPAT     */
+  "? * + invalid",                   /* BADRPT     */
+  "unbalanced {}",                   /* EBRACE     */
+  "unbalanced []",                   /* EBRACK     */
+  "collation error - not relevant",  /* ECOLLATE   */
+  "bad class",                       /* ECTYPE     */
+  "bad escape sequence",             /* EESCAPE    */
+  "empty expression",                /* EMPTY      */
+  "unbalanced ()",                   /* EPAREN     */
+  "bad range inside []",             /* ERANGE     */
+  "expression too big",              /* ESIZE      */
+  "failed to get memory",            /* ESPACE     */
+  "bad back reference",              /* ESUBREG    */
+  "bad argument",                    /* INVARG     */
+  "match failed"                     /* NOMATCH    */
+};
+
+
+
+
+/*************************************************
+*          Translate PCRE text code to int       *
+*************************************************/
+
+/* PCRE compile-time errors are given as strings defined as macros. We can just
+look them up in a table to turn them into POSIX-style error codes. */
+
+static int
+pcre_posix_error_code(const char *s)
+{
+size_t i;
+for (i = 0; i < sizeof(estring)/sizeof(char *); i++)
+  if (strcmp(s, estring[i]) == 0) return eint[i];
+return REG_ASSERT;
+}
+
+
+
+/*************************************************
+*          Translate error code to string        *
+*************************************************/
+
+size_t
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+const char *message, *addmessage;
+size_t length, addlength;
+
+message = (errcode >= (int)(sizeof(pstring)/sizeof(char *)))?
+  "unknown error code" : pstring[errcode];
+length = strlen(message) + 1;
+
+addmessage = " at offset ";
+addlength = (preg != NULL && (int)preg->re_erroffset != -1)?
+  strlen(addmessage) + 6 : 0;
+
+if (errbuf_size > 0)
+  {
+  if (addlength > 0 && errbuf_size >= length + addlength)
+    sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset);
+  else
+    {
+    strncpy(errbuf, message, errbuf_size - 1);
+    errbuf[errbuf_size-1] = 0;
+    }
+  }
+
+return length + addlength;
+}
+
+
+
+
+/*************************************************
+*           Free store held by a regex           *
+*************************************************/
+
+void
+regfree(regex_t *preg)
+{
+(pcre_free)(preg->re_pcre);
+}
+
+
+
+
+/*************************************************
+*            Compile a regular expression        *
+*************************************************/
+
+/*
+Arguments:
+  preg        points to a structure for recording the compiled expression
+  pattern     the pattern to compile
+  cflags      compilation flags
+
+Returns:      0 on success
+              various non-zero codes on failure
+*/
+
+int
+regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+const char *errorptr;
+int erroffset;
+int options = 0;
+
+if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS;
+if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
+
+preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
+preg->re_erroffset = erroffset;
+
+if (preg->re_pcre == NULL) return pcre_posix_error_code(errorptr);
+
+preg->re_nsub = pcre_info(preg->re_pcre, NULL, NULL);
+return 0;
+}
+
+
+
+
+/*************************************************
+*              Match a regular expression        *
+*************************************************/
+
+/* Unfortunately, PCRE requires 3 ints of working space for each captured
+substring, so we have to get and release working store instead of just using
+the POSIX structures as was done in earlier releases when PCRE needed only 2
+ints. */
+
+int
+regexec(regex_t *preg, const char *string, size_t nmatch,
+  regmatch_t pmatch[], int eflags)
+{
+int rc;
+int options = 0;
+int *ovector = NULL;
+
+if ((eflags & REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
+if ((eflags & REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
+
+preg->re_erroffset = (size_t)(-1);   /* Only has meaning after compile */
+
+if (nmatch > 0)
+  {
+  ovector = (int *)malloc(sizeof(int) * nmatch * 3);
+  if (ovector == NULL) return REG_ESPACE;
+  }
+
+rc = pcre_exec(preg->re_pcre, NULL, string, (int)strlen(string), 0, options,
+  ovector, nmatch * 3);
+
+if (rc == 0) rc = nmatch;    /* All captured slots were filled in */
+
+if (rc >= 0)
+  {
+  size_t i;
+  for (i = 0; i < rc; i++)
+    {
+    pmatch[i].rm_so = ovector[i*2];
+    pmatch[i].rm_eo = ovector[i*2+1];
+    }
+  if (ovector != NULL) free(ovector);
+  for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+  return 0;
+  }
+
+else
+  {
+  if (ovector != NULL) free(ovector);
+  switch(rc)
+    {
+    case PCRE_ERROR_NOMATCH: return REG_NOMATCH;
+    case PCRE_ERROR_NULL: return REG_INVARG;
+    case PCRE_ERROR_BADOPTION: return REG_INVARG;
+    case PCRE_ERROR_BADMAGIC: return REG_INVARG;
+    case PCRE_ERROR_UNKNOWN_NODE: return REG_ASSERT;
+    case PCRE_ERROR_NOMEMORY: return REG_ESPACE;
+    default: return REG_ASSERT;
+    }
+  }
+}
+
+/* End of pcreposix.c */
diff --git a/pcrs.c b/pcrs.c
new file mode 100644 (file)
index 0000000..cd0c94a
--- /dev/null
+++ b/pcrs.c
@@ -0,0 +1,540 @@
+const char pcrs_rcs[] = "$Id: pcrs.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/pcrs.c,v $
+ *
+ * Purpose     :  This is the pre-pre-alpha realease of libpcrs. It is only
+ *                published at this (ugly) stage of development, because it is
+ *                needed for a new feature in JunkBuster.
+ *
+ *                Apart from the code being quite a mess, no inconsistencies,
+ *                memory leaks or functional bugs **should** be present.
+ *
+ *                While you ROTFL at the code, you could just as well mail me
+ *                (andreas@oesterhelt.org) with advice for improvement.
+ *
+ *                pcrs is a supplement to the brilliant pcre library by Philip
+ *                Hazel (ph10@cam.ac.uk) and adds Perl-style substitution. That
+ *                is, it mimics Perl's 's' operator.
+ *
+ *                Currently, there's no documentation besides comments and the
+ *                source itself ;-)
+ *
+ * Copyright   :  Written and copyright by andreas@oesterhelt.org
+ *
+ * Revisions   :
+ *    $Log: pcrs.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include <pcre.h>
+#include <string.h>
+#include "pcrs.h"
+const char pcrs_h_rcs[] = PCRS_H_VERSION;
+
+
+/*********************************************************************
+ *
+ * Function    :  my_strsep
+ *
+ * Description :  Convenience function. It acts like strsep, except that
+ *                it respects quoting of the delimiter character with the
+ *                quote character. (And, of course, quoting the quote char
+ *                with itself.)  Called from `pcrs_make_job'.
+ *
+ * Parameters  :
+ *          1  :  token = current token
+ *          2  :  text = string to tokenize
+ *          3  :  delimiter = single character deliminter
+ *          4  :  quote_char = character to cause quoting
+ *
+ * Returns     :  -1 => failure, else the length of the token found.
+ *                In the latter case, *text is the token's start.
+ *
+ *********************************************************************/
+int my_strsep(char *token, char **text, char delimiter, char quote_char)
+{
+   int i, k=0, limit, quoted = FALSE;
+
+   limit = strlen(*text);
+   if ( 0 == limit )
+   {
+      return -1;
+   }
+
+   token[0] = '\0';
+
+   for (i=0; i < limit; i++)
+   {
+      if (text[0][i] == delimiter && !quoted)
+      {
+         *text += 1;
+         break;
+      }
+      else if (text[0][i] == quote_char && !quoted && i+1 < limit && text[0][i+1] == delimiter)
+      {
+         quoted = TRUE;
+         continue;
+      }
+      token[k++] = text[0][i];
+      quoted = FALSE;
+   }
+   token[k] = '\0';
+   *text += i;
+   return k;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  pcrs_compile_perl_options
+ *
+ * Description :  This function parses a string containing the options to
+ *                Perl's s/// operator. It returns an integer that is the
+ *                pcre equivalent of the symbolic optstring.
+ *                Since pcre doesn't know about Perl's 'g' (global) option,
+ *                but pcrs needs it, the globalflag integer is set if 'g'
+ *                is encountered.
+ *
+ * Parameters  :
+ *          1  :  optstring = string with options in perl syntax
+ *          2  :  globalflag = see description
+ *
+ * Returns     :  option integer suitable for pcre 
+ *
+ *********************************************************************/
+int pcrs_compile_perl_options(char *optstring, int *globalflag)
+{
+   int i, rc = 0;
+   *globalflag = 0;
+   for (i=0; i < strlen(optstring); i++)
+   {
+      switch(optstring[i])
+      {
+         case 'e': break;
+         case 'g': *globalflag = 1; break;
+         case 'i': rc |= PCRE_CASELESS; break;
+         case 'm': rc |= PCRE_MULTILINE; break;
+         case 'o': break;
+         case 's': rc |= PCRE_DOTALL; break;
+         case 'x': rc |= PCRE_EXTENDED; break;
+         default:  break;
+      }
+   }
+   return rc;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  pcrs_compile_replacement
+ *
+ * Description :  This function takes a Perl-style replacement (2nd argument
+ *                to the s/// operator and returns a compiled pcrs_substitute,
+ *                or NULL if memory allocation for the substitute structure
+ *                fails.
+ *
+ * Parameters  :
+ *          1  :  replacement = replacement part of s/// operator
+ *                              in perl syntax
+ *          2  :  errptr = pointer to an integer in which error
+ *                         conditions can be returned.
+ *
+ * Returns     :  pcrs_substitute data structure, or NULL if an
+ *                error is encountered. In that case, *errptr has
+ *                the reason.
+ *
+ *********************************************************************/
+pcrs_substitute *pcrs_compile_replacement(char *replacement, int *errptr)
+{
+   int length, i, k = 0, l = 0, quoted = 0, idx;
+   char *text, *num_ptr, *numbers = "0123456789";
+   pcrs_substitute *r;
+
+   r = (pcrs_substitute *)malloc(sizeof(pcrs_substitute));
+   if (r == NULL) return NULL;
+   memset(r, '\0', sizeof(pcrs_substitute));
+
+   text = strdup(replacement);      /* must be free()d by caller */
+   if (text  == NULL)
+   {
+      *errptr = PCRS_ERR_NOMEM;
+      free(r);
+      return NULL;
+   }
+
+   length = strlen(replacement);
+
+   for (i=0; i < length; i++)
+   {
+      /* Backslash treatment */
+      if (replacement[i] == '\\')
+      {
+         if (quoted)
+         {
+            text[k++] = replacement[i];
+            quoted = 0;
+         }
+         else
+         {
+            quoted = 1;
+         }
+         continue;
+      }
+
+      /* Dollar treatment */
+      if (replacement[i] == '$' && !quoted && i < length - 1)
+      {
+         if (strchr("0123456789&", replacement[i + 1]) == NULL)
+         {
+            text[k++] = replacement[i];
+         }
+         else
+         {
+            r->block_length[l] = k - r->block_offset[l];
+            r->backref[l] = 0;
+            if (replacement[i + 1] != '&')
+            {
+               while ((num_ptr = strchr(numbers, replacement[++i])) != NULL && i < length)
+               {
+                  idx = num_ptr - numbers;
+                  r->backref[l] = r->backref[l] * 10 + idx;
+               }
+               i--;
+            }
+            else
+               i++;
+            if (r->backref[l] < PCRS_MAX_SUBMATCHES)
+               r->backref_count[r->backref[l]] += 1;
+            l++;
+            r->block_offset[l] = k;
+         }
+         continue;
+      }
+
+      /* Plain char treatment */
+      text[k++] = replacement[i];
+      quoted = 0;
+   }
+
+   text[k] = '\0';
+   r->text = text;
+   r->backrefs = l;
+   r->block_length[l] = k - r->block_offset[l];
+   return r;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  pcrs_free_job
+ *
+ * Description :  Frees the memory used by a pcrs_job struct and its
+ *                dependant structures. Returns a pointer to the next
+ *                job, if there was any, or NULL otherwise.
+ *
+ * Parameters  :
+ *          1  :  job = pointer to the pcrs_job structure to be freed
+ *
+ * Returns     : a pointer to the next job, if there was any, or
+ *               NULL otherwise. 
+ *
+ *********************************************************************/
+pcrs_job *pcrs_free_job(pcrs_job *job)
+{
+   pcrs_job *next;
+
+   if (job == NULL)
+   {
+      return NULL;
+   }
+   else
+   {
+      next = job->next;
+      if (job->pattern != NULL) free(job->pattern);
+      if (job->hints != NULL) free(job->hints);
+      if (job->substitute != NULL)
+      {
+         if (job->substitute->text != NULL) free(job->substitute->text);
+         free(job->substitute);
+      }
+      free(job);
+   }
+   return next;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  pcrs_make_job
+ *
+ * Description :  Main entry point. Takes a string with a Perl-style
+ *                s/// command and returns a corresponding pcrs_job,
+ *                or NULL if compiling the job fails at any stage.
+ *                Diagnostics could obviously be improved.
+ *
+ * Parameters  :
+ *          1  :  command = string with perl-style s/// command
+ *          2  :  errptr = pointer to an integer in which error
+ *                         conditions can be returned.
+ *
+ * Returns     :  a corresponding pcrs_job data structure, or NULL
+ *                if an error was encountered. In that case, *errptr
+ *                has the reason.
+ *
+ *********************************************************************/
+pcrs_job *pcrs_make_job(char *command, int *errptr)
+{
+   char *dummy, *token, delimiter;
+   const char *error;
+   int i = 0, globalflag;
+   pcrs_job *newjob;
+
+   /* Get and init memory */
+   if ((newjob = (pcrs_job *)malloc(sizeof(pcrs_job))) == NULL)
+   {
+      *errptr = PCRS_ERR_NOMEM;
+      return NULL;
+   }
+   memset(newjob, '\0', sizeof(pcrs_job));
+
+   /* Command too short? */
+   if (strlen(command) < 4)
+   {
+      *errptr = PCRS_ERR_CMDSYNTAX;
+      pcrs_free_job(newjob);
+      return NULL;
+   }
+
+   /* Split command into tokens and handle them */
+   delimiter = command[1];
+   token = (char *)malloc(strlen(command)); /* current token */
+   dummy = (char *)malloc(strlen(command)); /* must store pattern, since we can't */
+                                            /* use it until the options are known */
+   while (my_strsep(token, &command, delimiter, '\\') >= 0)
+   {
+      switch (i)
+      {
+  /* We don't care about the command and assume 's' */
+         case 0:
+            break;
+
+         /* The pattern */
+         case 1:
+            strcpy(dummy, token);
+            break;
+
+         /* The substitute */
+         case 2:
+            newjob->substitute = pcrs_compile_replacement(token, errptr);
+            if (newjob->substitute == NULL)
+            {
+               pcrs_free_job(newjob);
+               return NULL;
+            }
+            break;
+
+         /* The options */
+         case 3:
+            newjob->options = pcrs_compile_perl_options(token, &globalflag);
+            newjob->globalflag = globalflag;
+            break;
+
+         /* There shouldn't be anything else! */
+         default:
+            *errptr = PCRS_ERR_CMDSYNTAX;
+            pcrs_free_job(newjob);
+            return NULL;
+      }
+      i++;
+   }
+   free(token);
+
+   /* Compile the pattern */
+   newjob->pattern = pcre_compile(dummy, newjob->options, &error, errptr, NULL);
+   if (newjob->pattern == NULL)
+   {
+      pcrs_free_job(newjob);
+      return NULL;
+   }
+   free(dummy);
+
+   /*
+    * Generate hints. This has little overhead, since the
+    * hints will be NULL for a boring pattern anyway.
+    */
+   newjob->hints = pcre_study(newjob->pattern, 0, &error);
+   if (error != NULL)
+   {
+      *errptr = PCRS_ERR_STUDY;
+      pcrs_free_job(newjob);
+      return NULL;
+   }
+
+   return newjob;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  create_pcrs_job
+ *
+ * Description :  Create a job from all its components, if you don't
+ *                have a Perl command to start from. Rather boring.
+ *
+ * Parameters  :
+ *          1  :  pattern = pointer to pcre pattern
+ *          2  :  hints = pointer to pcre hints
+ *          3  :  options = options in pcre format
+ *          4  :  globalflag = flag that indicates if global matching is desired
+ *          5  :  substitute = pointer to pcrs_substitute data structure
+ *          2  :  errptr = pointer to an integer in which error
+ *                         conditions can be returned.
+ *
+ * Returns     :  pcrs_job structure, or NULL if an error was encountered.
+ *                In that case, *errptr has the reason why.
+ *
+ *********************************************************************/
+pcrs_job *create_pcrs_job(pcre *pattern, pcre_extra *hints, int options, int globalflag, pcrs_substitute *substitute, int *errptr)
+{
+   pcrs_job *newjob;
+
+   if ((newjob = (pcrs_job *)malloc(sizeof(pcrs_job))) == NULL)
+   {
+      *errptr = PCRS_ERR_NOMEM;
+      return NULL;
+   }
+   memset(newjob, '\0', sizeof(pcrs_job));
+
+   newjob->pattern = pattern;
+   newjob->hints = hints;
+   newjob->options = options;
+   newjob->globalflag = globalflag;
+   newjob->substitute = substitute;
+
+   return(newjob);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  pcrs_exec_substitution
+ *
+ * Description :  Modify the subject by executing the regular substitution
+ *                defined by the job. Since the result may be longer than
+ *                the subject, its space requirements are precalculated in
+ *                the matching phase and new memory is allocated accordingly.
+ *                It is the caller's responsibility to free the result when
+ *                it's no longer needed.
+ *
+ * Parameters  :
+ *          1  :  job = the pcrs_job to be executed
+ *          2  :  subject = the subject (== original) string
+ *          3  :  subject_length = the subject's length
+ *          4  :  result = char** for returning  the result 
+ *          5  :  result_length = int* for returning the result's length
+ *
+ * Returns     :  the number of substitutions that were made. May be > 1
+ *                if job->globalflag was set
+ *
+ *********************************************************************/
+int pcrs_exec_substitution(pcrs_job *job, char *subject, int subject_length, char **result, int *result_length)
+{
+   int offsets[3 * PCRS_MAX_SUBMATCHES],
+      offset = 0, i=0, k, matches_found, newsize, submatches;
+   pcrs_match matches[PCRS_MAX_MATCHES];
+   char *result_offset;
+
+   newsize=subject_length;
+
+   /* Find.. */
+   while ((submatches = pcre_exec(job->pattern, job->hints, subject, subject_length, offset, 0, offsets, 99)) > 0)
+   {
+      matches[i].submatches = submatches;
+      for (k=0; k < submatches; k++)
+      {
+         matches[i].submatch_offset[k] = offsets[2 * k];
+         matches[i].submatch_length[k] = offsets[2 * k + 1] - offsets[2 * k]; /* Non-found optional submatches have length -1-(-1)==0 */
+         newsize += matches[i].submatch_length[k] * job->substitute->backref_count[k]; /* reserve mem for each submatch as often as it is ref'd */
+      }
+      newsize += strlen(job->substitute->text) - matches[i].submatch_length[0]; /* plus replacement text size minus match text size */
+
+      /* Non-global search or limit reached? */
+      if (++i >= PCRS_MAX_MATCHES || !job->globalflag ) break;
+
+      /* Don't loop on empty matches */
+      if (offsets[1] == offset)
+         if (offset < subject_length)
+            offset++;
+         else
+            break;
+      /* Go find the next one */
+      else
+         offset = offsets[1];
+   }
+   if (submatches < -1) return submatches;   /* Pass pcre error through */
+   matches_found = i;
+
+   /* ..get memory ..*/
+   if ((*result = (char *)malloc(newsize)) == NULL)   /* must be free()d by caller */
+   {
+      return PCRS_ERR_NOMEM;
+   }
+
+   /* ..and replace */
+   offset = 0;
+   result_offset = *result;
+
+   for (i=0; i < matches_found; i++)
+   {
+      memcpy(result_offset, subject + offset, matches[i].submatch_offset[0] - offset); /* copy the chunk preceding the match */
+      result_offset += matches[i].submatch_offset[0] - offset;
+
+      /* For every segment of the substitute.. */
+      for (k=0; k <= job->substitute->backrefs; k++)
+      {
+         /* ...copy its text.. */
+         memcpy(result_offset, job->substitute->text + job->substitute->block_offset[k], job->substitute->block_length[k]);
+         result_offset += job->substitute->block_length[k];
+
+         /* ..plus, if it's not the last chunk (i.e.: There IS a backref).. */
+         if (k != job->substitute->backrefs
+             /* ..and a nonempty match.. */
+             && matches[i].submatch_length[job->substitute->backref[k]] > 0
+             /* ..and in legal range, ... */
+             && job->substitute->backref[k] <= PCRS_MAX_SUBMATCHES)
+         {
+            /* copy the submatch that is ref'd. */
+            memcpy(
+               result_offset,
+               subject + matches[i].submatch_offset[job->substitute->backref[k]],
+               matches[i].submatch_length[job->substitute->backref[k]]
+            );
+            result_offset += matches[i].submatch_length[job->substitute->backref[k]];
+         }
+      }
+      offset =  matches[i].submatch_offset[0] + matches[i].submatch_length[0];
+   }
+
+   /* Copy the rest. */
+   memcpy(result_offset, subject + offset, subject_length - offset);
+
+   *result_length = newsize;
+   return matches_found;
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/pcrs.h b/pcrs.h
new file mode 100644 (file)
index 0000000..ba77c38
--- /dev/null
+++ b/pcrs.h
@@ -0,0 +1,99 @@
+#ifndef _PCRS_H
+#define _PCRS_H
+
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/pcrs.h,v $
+ *
+ * Purpose     :  This is the pre-pre-alpha realease of libpcrs. It is only
+ *                published at this (ugly) stage of development, because it is
+ *                needed for a new feature in JunkBuster.
+ *
+ *                Apart from the code being quite a mess, no inconsistencies,
+ *                memory leaks or functional bugs **should** be present.
+ *
+ *                While you ROTFL at the code, you could just as well mail me
+ *                (oes@paradis.rhein.de) with advice for improvement.
+ *
+ *                pcrs is a supplement to the brilliant pcre library by Philip
+ *                Hazel (ph10@cam.ac.uk) and adds Perl-style substitution. That
+ *                is, it mimics Perl's 's' operator.
+ *
+ *                Currently, there's no documentation besides comments and the
+ *                source itself ;-)
+ *
+ * Copyright   :  Written and copyright 2001 by Sourceforge IJBSWA team.
+ *
+ * Revisions   :
+ *    $Log: pcrs.h,v $
+ *    Revision 1.4  2001/05/11 01:57:02  rodney
+ *    Added new file header standard w/RCS control tags.
+ *
+ *    revision 1.3  2001/05/08 02:38:13  rodney
+ *    Changed C++ "//" style comment to C style comments.
+ *
+ *    revision 1.2  2001/04/30 02:39:24  rodney
+ *    Made this pcrs.h file conditionally included.
+ *
+ *    revision 1.1  2001/04/16 21:10:38  rodney
+ *    Initial checkin
+ *
+ *********************************************************************/
+
+#define PCRS_H_VERSION "$Id: pcrs.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+\f
+
+
+#include <pcre.h>
+
+#define FALSE 0
+#define TRUE 1
+#define PCRS_MAX_MATCHES 300
+#define PCRS_MAX_SUBMATCHES 33
+#define CHARBUFSIZ BUFSIZ * sizeof(char)
+
+#define PCRS_ERR_NOMEM     -10      /* Failed to acquire memory. */
+#define PCRS_ERR_CMDSYNTAX -11      /* Syntax of s///-command */
+#define PCRS_ERR_STUDY     -12      /* pcre error while studying the pattern */
+
+typedef struct S_PCRS_SUBSTITUTE {
+  char *text;
+  int backrefs;
+  int block_offset[PCRS_MAX_SUBMATCHES];
+  int block_length[PCRS_MAX_SUBMATCHES];
+  int backref[PCRS_MAX_SUBMATCHES];
+  int backref_count[PCRS_MAX_SUBMATCHES];
+} pcrs_substitute;
+
+typedef struct S_PCRS_MATCH {
+  /* char *buffer; */
+  int submatches;
+  int submatch_offset[PCRS_MAX_SUBMATCHES];
+  int submatch_length[PCRS_MAX_SUBMATCHES];
+} pcrs_match;
+
+typedef struct S_PCRS_JOB {
+  pcre *pattern;
+  pcre_extra *hints;
+  int options;
+  int globalflag;
+  int successflag;
+  pcrs_substitute *substitute;
+  struct S_PCRS_JOB *next;
+} pcrs_job;
+
+extern int              pcrs_compile_perl_options(char *optstring, int *globalflag);
+extern pcrs_substitute *pcrs_compile_replacement(char *replacement, int *errptr);
+extern pcrs_job        *pcrs_free_job(pcrs_job *job);
+extern pcrs_job        *pcrs_make_job(char *command, int *errptr);
+extern pcrs_job        *create_pcrs_job(pcre *pattern, pcre_extra *hints, int options, int globalflag, pcrs_substitute *substitute, int *errptr);
+extern int              pcrs_exec_substitution(pcrs_job *job, char *subject, int subject_length, char **result, int *result_length);
+
+
+#endif /* ndef _PCRS_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/popup b/popup
new file mode 100644 (file)
index 0000000..07f0c36
--- /dev/null
+++ b/popup
@@ -0,0 +1,44 @@
+#
+# $Id: popup,v 1.1 2001/04/16 21:10:38 rodney Exp $
+#
+#  This is the configuration file for blocking Javascript popup windows,
+# it specifies both hosts to block from, and hosts to allow the popups
+# from.
+#
+#  The format is the hostname to block, or allow.
+#
+#  eg:
+#
+#  www.geocities.com       # block all popups from geocities.
+#
+#  ~www.trusted-host.com   # Allow popups from the trusted host domain.
+#
+#
+#   If a site is not explicitly blocked popups will be allowed, the
+# "allowable" syntax with "~" exists as a marker that you've explicitly
+# allowed something.
+#
+#   Order is not relevant - an allowable entry overrides a blocked entry,
+# e.g.
+#  ~myhost.com    # Allows myhost.com
+#  myhost.com     # _Still_ allowed.
+#
+#  Steve Kemp
+#  ---
+#  http://www.tardis.ed.ac.uk/~skx/junk/   for more details.
+#
+#
+
+
+
+# This is for the test page, at http://www.tardis.ed.ac.uk/~skx/junk/
+www.tardis.ed.ac.uk
+
+#
+# Samples, uncomment to use:
+#
+
+# members.tripod.co.uk
+# www.geocities.com
+# ~windowsupdates.microsoft.com
+# ~updates.microsoft.com
\ No newline at end of file
diff --git a/project.h b/project.h
new file mode 100644 (file)
index 0000000..5f4324a
--- /dev/null
+++ b/project.h
@@ -0,0 +1,447 @@
+#ifndef _PROJECT_H
+#define _PROJECT_H
+#define PROJECT_H_VERSION "$Id: project.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/project.h,v $
+ *
+ * Purpose     :  Defines data structures which are widely used in the
+ *                project.  Does not define any variables or functions
+ *                (though it does declare some macros).
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: project.h,v $
+ *
+ *********************************************************************/
+\f
+
+/* Declare struct FILE for vars and funcs. */
+#include <stdio.h>
+
+/* Need time_t for file_list */
+#include <time.h>
+
+/*
+ * Include appropriate regular expression libraries.
+ *
+ * PCRS           ==> Include pcre
+ * REGEX && PCRE  ==> Include pcre and pcreposix
+ * REGEX && !PCRE ==> Include gnu_regex
+ *
+ * STATIC  ==> Use  #include "pcre.h"  (compiling at same time)
+ * !STATIC ==> Use  #include <pcre.h>  (System library)
+ *
+ */
+#if (defined(REGEX) && defined(PCRE)) || defined(PCRS)
+#  ifdef STATIC
+#    include "pcre.h"
+#  else
+#    include <pcre.h>
+#  endif
+#endif /* (defined(REGEX) && defined(PCRE)) || defined(PCRS) */
+
+#if defined(REGEX) && defined(PCRE)
+#  ifdef STATIC
+#    include "pcreposix.h"
+#  else
+#    include <pcreposix.h>
+#  endif
+#endif /* defined(REGEX) && defined(PCRE) */
+
+#if defined(REGEX) && !defined(PCRE)
+#  include "gnu_regex.h"
+#endif
+
+#ifdef PCRS
+#include "pcrs.h"
+#endif /* def PCRS */
+
+#ifdef AMIGA 
+#include "amiga.h" 
+#endif /* def AMIGA */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FOREVER 1
+
+/* Default IP and port to listen on */
+#define HADDR_DEFAULT   "127.0.0.1"
+#define HADDR_PORT      8000
+
+
+/* Need this for struct gateway */
+struct client_state;
+
+
+struct http_request
+{
+   char *cmd;
+   char *gpc;
+   char *host;
+   int   port;
+   char *path;
+   char *ver;
+   char *hostport; /* "host[:port]" */
+   int   ssl;
+};
+
+
+struct gateway
+{
+   /* generic attributes */
+   char *name;
+   int (*conn)(const struct gateway *, struct http_request *, struct client_state *);
+   int   type;
+
+   /* domain specific attributes */
+   char *gateway_host;
+   int   gateway_port;
+
+   char *forward_host;
+   int   forward_port;
+};
+
+
+struct proxy_args
+{
+   char *header;
+   char *invocation;
+   char *gateways;
+   char *trailer;
+};
+
+
+struct iob
+{
+   char *buf;
+   char *cur;
+   char *eod;
+};
+
+
+struct list
+{
+   char *str;
+   struct list *last;
+   struct list *next;
+};
+
+#define IOB_PEEK(CSP) ((CSP->iob->cur > CSP->iob->eod) ? (CSP->iob->eod - CSP->iob->cur) : 0)
+#define IOB_RESET(CSP) if(CSP->iob->buf) free(CSP->iob->buf); memset(CSP->iob, '\0', sizeof(CSP->iob));
+
+
+/* Constants defining bitmask for csp->accept_types */
+
+#ifdef DETECT_MSIE_IMAGES
+
+/* MSIE detected by user-agent string */
+#define ACCEPT_TYPE_IS_MSIE     0x0001
+
+/*
+ * *If* this is MSIE, it wants an image.  (Or this is a shift-reload, or
+ * it's got an image from this URL before...  yuck!)
+ * Only meaningful if ACCEPT_TYPE_IS_MSIE set 
+ */
+#define ACCEPT_TYPE_MSIE_IMAGE  0x0002
+
+/*
+ * *If* this is MSIE, it wants a HTML document.
+ * Only meaningful if ACCEPT_TYPE_IS_MSIE set
+ */
+#define ACCEPT_TYPE_MSIE_HTML   0x0004
+
+#endif /* def DETECT_MSIE_IMAGES */
+
+
+struct client_state
+{
+   int  send_user_cookie;
+   int  accept_server_cookie;
+   int  cfd;
+   int  sfd;
+
+#ifdef STATISTICS
+   /* 1 if this URL was rejected, 0 otherwise. Allows actual stats inc to 
+    * occur in main thread only for thread-safety. 
+    */
+   int  rejected;
+#endif /* def STATISTICS */
+
+#ifdef FORCE_LOAD
+   int force;
+#endif /* def FORCE_LOAD */
+
+#ifdef TOGGLE
+   /*
+    * by haroon - most of credit to srt19170
+    * We add an "on/off" toggle here that is used to effectively toggle
+    * the Junkbuster off or on
+    */
+   int   toggled_on;
+#endif
+
+   char *ip_addr_str;
+   long  ip_addr_long;
+   char *referrer;
+
+#if defined(DETECT_MSIE_IMAGES)
+   /* Types the client will accept.
+    * Bitmask - see ACCEPT_TYPE_XXX constants.
+    */
+   int accept_types;
+#endif /* defined(DETECT_MSIE_IMAGES) */
+
+   const struct gateway *gw;
+   struct http_request http[1];
+
+   struct iob iob[1];
+
+   struct list headers[1];
+   struct list cookie_list[1];
+#ifdef PCRS
+   int is_text;
+#endif /* def PCRS */
+
+   char   *x_forwarded;
+
+   int active;
+
+   /* files associated with this client */
+   struct file_list *blist;   /* blockfile */
+   struct file_list *clist;   /* cookiefile */
+   struct file_list *flist;   /* forwardfile */
+
+#ifdef ACL_FILES
+   struct file_list *alist;   /* aclfile */
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+   struct file_list *ilist;   /* imagefile */
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+   struct file_list *plist;   /* kill popup file */
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+     struct file_list *rlist;   /* Perl re_filterfile */
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+   struct file_list *tlist;   /* trustfile */
+#endif /* def TRUST_FILES */
+
+   struct client_state *next;
+};
+
+
+struct parsers
+{
+   char *str;
+   char  len;
+   char *(*parser)(const struct parsers *, char *, struct client_state *);
+};
+
+
+struct interceptors
+{
+   char *str;
+   char  len;
+   char *(*interceptor)(struct http_request *http, struct client_state *csp);
+};
+
+
+/* this allows the proxy to permit/block access to any host and/or path */
+
+struct url_spec
+{
+   char  *spec;
+   char  *domain;
+   char  *dbuf;
+   char **dvec;
+   int    dcnt;
+   int    toplevel;
+
+   char *path;
+   int   pathlen;
+   int   port;
+#ifdef REGEX
+   regex_t *preg;
+#endif
+};
+
+
+struct file_list
+{
+   /*
+    * this is a pointer to the data structures associated with the file.
+    * Read-only once the structure has been created.
+    */
+   void *f;
+   
+   /* Normally NULL.  When we are finished with file (i.e. when we have
+    * loaded a new one), set to a pointer to an unloader function.
+    * Unloader will be called by sweep() (called from main loop) when
+    * all clients using this file are done.  This prevents threading 
+    * problems.
+    */
+   void (*unloader)(void *);
+
+   /* Used internally by sweep().  Do not access from elsewhere. */
+   int active;
+
+#ifndef SPLIT_PROXY_ARGS
+   /* String to be displayed as part of show-proxy-args display.
+    * Read-only once the structure has been created.
+    */
+   char *proxy_args;
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   /* Following variables allow us to check if file has been changed.
+    * Read-only once the structure has been created.
+    */
+   time_t lastmodified;
+   char * filename;
+
+   /* Pointer to next entry in the linked list of all "file_list"s.
+    * This linked list is so that sweep() can navigate it.
+    * Since sweep() can remove items from the list, we must be careful
+    * to only access this value from main thread (when we know sweep
+    * won't be running).
+    */
+   struct file_list *next;
+};
+
+
+struct block_spec
+{
+   struct url_spec url[1];
+   int   reject;
+   struct block_spec *next;
+};
+
+
+struct cookie_spec
+{
+   struct url_spec url[1];
+   int   send_user_cookie;
+   int   accept_server_cookie;
+   struct cookie_spec *next;
+};
+
+
+struct forward_spec
+{
+   struct url_spec url[1];
+   int   reject;
+   struct gateway gw[1];
+   struct forward_spec *next;
+};
+
+
+#ifdef PCRS
+struct re_filterfile_spec
+{
+   struct list patterns[1];
+   /* See README.re_filter */
+   pcrs_job *joblist;
+};
+#endif /* def PCRS */
+
+
+#ifdef KILLPOPUPS
+/* Entries on popup blocklist */
+struct popup_blocklist
+{
+   char *host_name;
+   struct popup_blocklist *next;
+};
+
+/* Actual type used in file object */
+struct popup_settings
+{
+   struct popup_blocklist *blocked;
+   struct popup_blocklist *allowed;
+};
+#endif /* def KILLPOPUPS */
+
+#ifdef ACL_FILES
+#define ACL_PERMIT   1  /* accept connection request */
+#define ACL_DENY     2  /* reject connection request */
+
+struct access_control_addr
+{
+   unsigned long addr;
+   unsigned long mask;
+   unsigned long port;
+};
+
+struct access_control_list
+{
+   struct access_control_addr src[1];
+   struct access_control_addr dst[1];
+
+   short action;
+   struct access_control_list *next;
+};
+#endif /* def ACL_FILES */
+
+#define SZ(X)  (sizeof(X) / sizeof(*X))
+
+#define WHITEBG   "<body bgcolor=\"#ffffff\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
+#define BODY      "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
+#define BANNER    "<strong>Internet J<small>UNK<i><font color=\"red\">BUSTER</font></i></small></strong>"
+
+#ifdef FORCE_LOAD
+/*\r
+ * FIXME: Unfortunately, IE lowercases the domain name.  JunkBuster does\r
+ * a case-sensitive compare.  JunkBuster should be modified to do a\r
+ * case-insensitive compatison.  As a temporary workaround, I've lowercased\r
+ * the FORCE_PREFIX.\r
+ *\r
+ * #define FORCE_PREFIX "IJB-FORCE-LOAD-"\r
+ */\r
+#define FORCE_PREFIX "ijb-force-load-"\r
+#endif /* def FORCE_LOAD */
+
+#define HOME_PAGE_URL  "http://ijbswa.sourceforge.net/"
+#define REDIRECT_URL HOME_PAGE_URL "redirect.php?v=" VERSION "&to="
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _PROJECT_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/re_filterfile b/re_filterfile
new file mode 100644 (file)
index 0000000..16c073b
--- /dev/null
@@ -0,0 +1,62 @@
+# Filterfile for the Regular Substitution Module
+#
+# Syntax: One Perl-Style substitution per line.
+# For Details see the perlre, perlop and pcre manpages.
+# Note that you are free to choose the delimter as you
+# see fit.
+#
+
+# Kill OnUnload popups. Yummy.
+# check it out on http://www.zdnet.com/zdsubs/yahoo/tree/yfs.html
+#
+s/(<body .*?)onunload(.*?>)/$1never$2/i
+
+# Kill refresh tags. I like to refresh myself. Manually.
+# check it out on http://www.airport-cgn.de/ and go to the arrivals page.
+#
+s/<meta[^>]*http-equiv[^>]*refresh[^>]*>/<!--no refresh for me-->/i
+s/<meta[^>]*http-equiv="?page-enter"?[^>]*content=[^>]*>/<!--no page enter for me-->/i
+
+# If I allow popups, I want them to be rezizable and have a location and status bar:
+# check it out on http://www.airport-cgn.de/ and go to the arrivals page.
+#
+s/resizable="?(no|0)"?/resizable=1/ig
+s/noresize/yesresize/ig
+s/location="?(no|0)"?/location=1/ig
+s/status="?(no|0)"?/status=1/ig
+s/scrolling="?(no|0|Auto)"?/scrolling=1/ig
+s/menubar="?(no|0)"?/menubar=1/ig
+#s/framespacing="?(no|0)"?//ig
+#s/margin(height|width)=[0-9]*//gi
+
+# Remove frameborder=0 and border=0 from framesets
+s/(<frameset[ -z]+)(frame)?border="?(no|0)"?/$1/ig
+
+# The status bar is for displaying link targets, not pointless buzzwords.
+# Again, check it out on http://www.airport-cgn.de/
+#
+s/status='.*?';*//ig
+
+# Kill *all* popups a la popup.c. (But for *all* sites, so I wouldn't do that.)
+#
+# JavaScript: s/window\.open\(/who_wants_this_to.open(/ig
+# HTML      : s/target="?_blank"?/target_who/g
+
+# Fun stuff:
+#
+s/microsoft(?!.com)/<b>MicroSuck<\/b>/ig
+
+# Crude parental filtering?  (Use along with a suitable blocklist).
+# Shows how to deny access to whole page based on a keyword.
+#
+# (Note: Middlesex, Sussex and Essex are counties in the UK, not rude words)
+# (Note #2: Is 'sex' a rude word?!)
+#
+#s%^.*(?<!middle)(?<!sus)(?<!es)sex.*$%<html><head><title>Blocked</title></head><body><h3>Blocked due to possible adult content. Please see <a href="http://dmoz.org/Kids_and_Teens/">this site</a>.</h3></body></html>%is
+#s+^.*warez.*$+<html><head><title>No Warez</title></head><body><h3>You're not searching for illegal stuff, are you?</h3></body></html>+is
+
+# http://www.farscapezone.com/wwwboard/messages/1451.html
+s/(\w+) was tired/<b>$1 needed more coffee<\/b>/ig
+
+# I'm sure you'll find more uses.
+# Please send your cool additions to junkbuster-users@yahoogroups.com
diff --git a/showargs.c b/showargs.c
new file mode 100644 (file)
index 0000000..0a7cc2c
--- /dev/null
@@ -0,0 +1,467 @@
+const char showargs_rcs[] = "$Id: showargs.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/showargs.c,v $
+ *
+ * Purpose     :  Contains various utility routines needed to 
+ *                generate the show-proxy-args page.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: showargs.c,v $
+ *
+ *********************************************************************/
+\f
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+
+#include "showargs.h"
+#include "jcc.h"
+#include "encode.h"
+#include "parsers.h"
+#include "errlog.h"
+#include "miscutil.h"
+#include "gateway.h"
+
+const char showargs_h_rcs[] = SHOWARGS_H_VERSION;
+
+/*********************************************************************
+ *
+ * Function    :  strsav
+ *
+ * Description :  Reallocate "old" and append text to it.  This makes
+ *                it easier to append to malloc'd strings.
+ *
+ * Parameters  :
+ *          1  :  old = Old text that is to be extended.  Will be
+ *                free()d by this routine.
+ *          2  :  text_to_append = Text to be appended to old.
+ *
+ * Returns     :  Pointer to newly malloc'ed appended string.
+ *                If there is no text to append, return old.  Caller
+ *                must free().
+ *
+ *********************************************************************/
+char *strsav(char *old, const char *text_to_append)
+{
+   int old_len, new_len;
+   char *p;
+
+   if (( text_to_append == NULL) || (*text_to_append == '\0'))
+   {
+      return(old);
+   }
+
+   if (NULL != old)
+   {
+      old_len = strlen(old);
+   }
+   else
+   {
+      old_len = 0;
+   }
+
+   new_len = old_len + strlen(text_to_append) + 1;
+
+   if (old)
+   {
+      if ((p = realloc(old, new_len)) == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR, "realloc(%d) bytes for proxy_args failed!", new_len);
+         exit(1);
+      }
+   }
+   else
+   {
+      if ((p = (char *)malloc(new_len)) == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR, "malloc(%d) bytes for proxy_args failed!", new_len);
+         exit(1);
+      }
+   }
+
+   strcpy(p + old_len, text_to_append);
+   return(p);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  savearg
+ *
+ * Description :  Called from `load_config'.  It saves each non-empty
+ *                and non-comment line from config into a list.  This
+ *                list is used to create the show-proxy-args page.
+ *
+ * Parameters  :
+ *          1  :  c = config setting that was found
+ *          2  :  o = the setting's argument (if any)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void savearg(char *c, char *o)
+{
+   char buf[BUFSIZ];
+
+   *buf = '\0';
+
+   if ( ( NULL != c ) && ( '\0' != *c ) )
+   {
+      if ((c = html_encode(c)))
+      {
+         sprintf(buf, "<a href=\"" REDIRECT_URL "option#%s\">%s</a> ", c, c);
+      }
+      freez(c);
+   }
+   if ( ( NULL != o ) && ( '\0' != *o ) )
+   {
+      if ((o = html_encode(o)))
+      {
+         if (strncmpic(o, "http://", 7) == 0)
+         {
+            strcat(buf, "<a href=\"");
+            strcat(buf, o);
+            strcat(buf, "\">");
+            strcat(buf, o);
+            strcat(buf, "</a>");
+         }
+         else
+         {
+            strcat(buf, o);
+         }
+      }
+      freez(o);
+   }
+
+   strcat(buf, "<br>\n");
+
+   proxy_args->invocation = strsav(proxy_args->invocation, buf);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  init_proxy_args
+ *
+ * Description :  Create the "top" of the show-proxy-args page.
+ *
+ * Parameters  :
+ *          1  :  argc = argument count (same as in main)
+ *          2  :  argv[] = program arguments (same as in main)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void init_proxy_args(int argc, const char *argv[])
+{
+   const struct gateway *g;
+   int i;
+
+   freez(proxy_args->header);
+   freez(proxy_args->invocation);
+   freez(proxy_args->gateways);
+   freez(proxy_args->trailer);
+   
+
+   proxy_args->header = strsav(proxy_args->header,
+      "HTTP/1.0 200 OK\n"
+      "Server: IJ/" VERSION "\n"
+      "Content-type: text/html\n\n"
+
+      "<html>"
+      "<head>"
+      "<title>Internet Junkbuster Proxy Status</title>"
+      "</head>\n"
+      "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
+      "<center>\n"
+      "<h1>" BANNER "\n"
+      "<a href=\"" REDIRECT_URL "faq#show\">Proxy Status</a>\n"
+      "</h1></center>\n"
+      "<h2>You are using the " BANNER " <sup><small><small>TM</small></small></sup></h2>\n"
+      "Version: " VERSION "\n"
+      "<br>Home page: <a href=\"" HOME_PAGE_URL "\">" HOME_PAGE_URL "</a>\n"\r
+      "<p>\n"
+   );
+
+   proxy_args->header = strsav(proxy_args->header,
+      "<h2>The program was invoked as follows</h2>\n");
+
+   for (i=0; i < argc; i++)
+   {
+      proxy_args->header = strsav(proxy_args->header, argv[i]);
+      proxy_args->header = strsav(proxy_args->header, " ");
+   }
+   proxy_args->header = strsav(proxy_args->header, "<br>\n");
+
+
+   proxy_args->invocation = strsav(
+      proxy_args->invocation,
+      "<br>\n"
+      "and the following options were set in the configuration file"
+      "<br><br>\n"
+   );
+
+
+   proxy_args->gateways = strsav(proxy_args->gateways,
+      "<h2>It supports the following gateway protocols:</h2>\n");
+
+   for (g = gateways; g->name; g++)
+   {
+      proxy_args->gateways = strsav(proxy_args->gateways, g->name);
+      proxy_args->gateways = strsav(proxy_args->gateways, " ");
+   }
+   proxy_args->gateways = strsav(proxy_args->gateways, "<br>\n");
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  end_proxy_args
+ *
+ * Description :  Create the "bottom" of the show-proxy-args page.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void end_proxy_args(void)
+{
+   char *b = NULL;
+   char buf[BUFSIZ];
+
+   /* Instead of including *all* dot h's in the project (thus creating a
+    * tremendous amount of dependencies), I will concede to declaring them
+    * as extern's.  This forces the developer to add to this list, but oh well.
+    */
+
+#ifndef SPLIT_PROXY_ARGS
+   if (suppress_blocklists && suppress_message!=NULL)
+   {
+      b = strsav(b, "<h2>File contents</h2>\n");
+      b = strsav(b, suppress_message);
+      b = strsav(b, "\n");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+   b = strsav(b, "<h2>Source versions:</h2>\n");
+   b = strsav(b, "<pre>");
+
+#define SHOW_RCS(__x)            \
+   {                             \
+      extern const char __x[];   \
+      sprintf(buf, "%s\n", __x); \
+      b = strsav(b, buf);        \
+   }
+
+   /* In alphabetical order */
+#ifdef __MINGW32__
+   SHOW_RCS(cygwin_h_rcs)
+#endif
+   SHOW_RCS(encode_h_rcs)
+   SHOW_RCS(encode_rcs)
+   SHOW_RCS(errlog_h_rcs)
+   SHOW_RCS(errlog_rcs)
+   SHOW_RCS(filters_h_rcs)
+   SHOW_RCS(filters_rcs)
+   SHOW_RCS(gateway_h_rcs)
+   SHOW_RCS(gateway_rcs)
+#ifdef GNU_REGEX
+   SHOW_RCS(gnu_regex_h_rcs)
+   SHOW_RCS(gnu_regex_rcs)
+#endif /* def GNU_REGEX */
+   SHOW_RCS(jbsockets_h_rcs)
+   SHOW_RCS(jbsockets_rcs)
+   SHOW_RCS(jcc_h_rcs)
+   SHOW_RCS(jcc_rcs)
+#ifdef KILLPOPUPS
+   SHOW_RCS(killpopup_h_rcs)
+   SHOW_RCS(killpopup_rcs)
+#endif /* def KILLPOPUPS */
+   SHOW_RCS(loadcfg_h_rcs)
+   SHOW_RCS(loadcfg_rcs)
+   SHOW_RCS(loaders_h_rcs)
+   SHOW_RCS(loaders_rcs)
+   SHOW_RCS(miscutil_h_rcs)
+   SHOW_RCS(miscutil_rcs)
+   SHOW_RCS(parsers_h_rcs)
+   SHOW_RCS(parsers_rcs)
+#ifdef PCRS
+   SHOW_RCS(pcrs_rcs)
+   SHOW_RCS(pcrs_h_rcs)
+#endif /* def PCRS */
+   SHOW_RCS(project_h_rcs)
+   SHOW_RCS(showargs_h_rcs)
+   SHOW_RCS(showargs_rcs)
+   SHOW_RCS(ssplit_h_rcs)
+   SHOW_RCS(ssplit_rcs)
+#ifdef _WIN32
+   SHOW_RCS(w32log_h_rcs)
+   SHOW_RCS(w32log_rcs)
+   SHOW_RCS(w32res_h_rcs)
+   SHOW_RCS(w32rulesdlg_h_rcs)
+   SHOW_RCS(w32rulesdlg_rcs)
+   SHOW_RCS(w32taskbar_h_rcs)
+   SHOW_RCS(w32taskbar_rcs)
+   SHOW_RCS(win32_h_rcs)
+   SHOW_RCS(win32_rcs)
+#endif /* def _WIN32 */
+
+#undef SHOW_RCS
+
+   b = strsav(b, "</pre>\n");
+
+   b = strsav(b, "<h2>Conditional defines:</h2>\n<ul>");
+
+#ifdef REGEX
+   b = strsav(b, "  <li><code>#define <b>REGEX</b></code> - Support for regular expressions in the path specs.</li>\n");
+#else /* ifndef REGEX */
+   b = strsav(b, "  <li><code>#undef <b>REGEX</b></code> - No support for regular expressions in the path specs.</li>\n");
+#endif /* ndef REGEX */
+\r
+#ifdef PCRE\r
+   b = strsav(b, "  <li><code>#define <b>PCRE</b></code> - Use PCRE rather than old GNU regex library.</li>\n");\r
+#else /* ifndef PCRE */\r
+   b = strsav(b, "  <li><code>#undef <b>PCRE</b></code> - Use old GNU regex library rather than PCRE.</li>\n");\r
+#endif /* ndef PCRE */\r
+
+#ifdef PCRS
+   b = strsav(b, "  <li><code>#define <b>PCRS</b></code> - Enables arbitrary content modification regexps.</li>\n");
+#else /* ifndef PCRS */
+   b = strsav(b, "  <li><code>#undef <b>PCRS</b></code> - Disables arbitrary content modification regexps.</li>\n");
+#endif /* ndef PCRS */
+\r
+#ifdef TOGGLE\r
+   b = strsav(b, "  <li><code>#define <b>TOGGLE</b></code> - Allow JunkBuster to be \"disabled\" so it is just a normal non-blocking non-anonymizing proxy.</li>\n");\r
+#else /* ifndef TOGGLE */\r
+   b = strsav(b, "  <li><code>#undef <b>TOGGLE</b></code> - Do not allow JunkBuster to be \"disabled\" so it is just a normal non-blocking non-anonymizing proxy.</li>\n");\r
+#endif /* ndef TOGGLE */\r
+\r
+#ifdef FORCE_LOAD\r
+   b = strsav(b, "  <li><code>#define <b>FORCE_LOAD</b></code> - Enables bypassing filtering for a single page using the prefix \"" FORCE_PREFIX "\".</li>\n");\r
+#else /* ifndef FORCE_LOAD */\r
+   b = strsav(b, "  <li><code>#undef <b>FORCE_LOAD</b></code> - Disables bypassing filtering for a single page.</li>\n");\r
+#endif /* ndef FORCE_LOAD */\r
+
+#ifdef DENY_GZIP
+   b = strsav(b, "  <li><code>#define <b>DENY_GZIP</b></code> - Prevents requests from being compressed - required for PCRS.</li>\n");
+#else /* ifndef DENY_GZIP */
+   b = strsav(b, "  <li><code>#undef <b>DENY_GZIP</b></code> - Allows requests to be compressed if the browser and server support it.</li>\n");
+#endif /* ndef DENY_GZIP */
+
+#ifdef STATISTICS
+   b = strsav(b, "  <li><code>#define <b>STATISTICS</b></code> - Enables statistics function.</li>\n");
+#else /* ifndef STATISTICS */
+   b = strsav(b, "  <li><code>#undef <b>STATISTICS</b></code> - Disables statistics function.</li>\n");
+#endif /* ndef STATISTICS */
+
+#ifdef SPLIT_PROXY_ARGS
+   b = strsav(b, "  <li><code>#define <b>SPLIT_PROXY_ARGS</b></code> - Split this page up by placing the configuration files on separate pages.</li>\n");
+#else /* ifndef SPLIT_PROXY_ARGS */
+   b = strsav(b, "  <li><code>#undef <b>SPLIT_PROXY_ARGS</b></code> - This page contains the text of the configuration files, they are not split onto separate pages.</li>\n");
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+#ifdef KILLPOPUPS
+   b = strsav(b, "  <li><code>#define <b>KILLPOPUPS</b></code> - Enables killing JavaScript popups.</li>\n");
+#else /* ifndef KILLPOPUPS */
+   b = strsav(b, "  <li><code>#undef <b>KILLPOPUPS</b></code> - Disables killing JavaScript popups.</li>\n");
+#endif /* ndef KILLPOPUPS */
+
+#ifdef WEBDAV
+   b = strsav(b, "  <li><code>#define <b>WEBDAV</b></code> - Enables support for webDAV - e.g. stops Microsoft Outlook from accessing HotMail e-mail.</li>\n");
+#else /* ifndef WEBDAV */
+   b = strsav(b, "  <li><code>#undef <b>WEBDAV</b></code> - Disables support for webDAV - e.g. so Microsoft Outlook can access HotMail e-mail.</li>\n");
+#endif /* ndef WEBDAV */
+
+#ifdef DETECT_MSIE_IMAGES
+   b = strsav(b, "  <li><code>#define <b>DETECT_MSIE_IMAGES</b></code> - Enables detecting image requests automatically for MSIE.</li>\n");
+#else /* ifndef DETECT_MSIE_IMAGES */
+   b = strsav(b, "  <li><code>#undef <b>DETECT_MSIE_IMAGES</b></code> - Disables detecting image requests automatically for MSIE.</li>\n");
+#endif /* ndef DETECT_MSIE_IMAGES */
+
+#ifdef USE_IMAGE_LIST
+   b = strsav(b, "  <li><code>#define <b>USE_IMAGE_LIST</b></code> - Enables using image list to detect images.</li>\n");
+#else /* ifndef USE_IMAGE_LIST */
+   b = strsav(b, "  <li><code>#undef <b>USE_IMAGE_LIST</b></code> - Disables using image list to detect images.</li>\n");
+#endif /* ndef USE_IMAGE_LIST */
+
+#ifdef ACL_FILES
+   b = strsav(b, "  <li><code>#define <b>ACL_FILES</b></code> - Enables the use of ACL files to control access to the proxy by IP address.</li>\n");
+#else /* ifndef ACL_FILES */
+   b = strsav(b, "  <li><code>#undef <b>ACL_FILES</b></code> - Disables the use of ACL files to control access to the proxy by IP address.</li>\n");
+#endif /* ndef ACL_FILES */
+\r
+#ifdef TRUST_FILES
+   b = strsav(b, "  <li><code>#define <b>TRUST_FILES</b></code> - Enables the use of trust files.</li>\n");
+#else /* ifndef TRUST_FILES */
+   b = strsav(b, "  <li><code>#undef <b>TRUST_FILES</b></code> - Disables the use of trust files.</li>\n");
+#endif /* ndef TRUST_FILES */
+
+#ifdef JAR_FILES\r
+   b = strsav(b, "  <li><code>#define <b>JAR_FILES</b></code> - Enables the use of jar files to capture cookies.</li>\n");\r
+#else /* ifndef JAR_FILES */\r
+   b = strsav(b, "  <li><code>#undef <b>JAR_FILES</b></code> - Disables the use of jar files to capture cookies.</li>\n");\r
+#endif /* ndef JAR_FILES */\r
+
+   b = strsav(b, "</ul>\n<br>\n");
+
+   b = strsav(b,
+      "<small><small><p>\n"
+      "Code and documentation of the " BANNER " Proxy"
+      "<sup><small>TM</small></sup>\n"
+      "<a href=\"http://www.junkbusters.com/ht/en/legal.html#copy\">\n" "Copyright</a>&#169; 1997 Junkbusters Corporation\n"
+      "<a href=\"http://www.junkbusters.com/ht/en/legal.html#marks\"><sup><small>TM</small></sup></a><br>\n"
+      "Copying and distribution permitted under the"
+      "<a href=\"http://www.gnu.org/copyleft/gpl.html\">\n"
+      "<small>GNU</small></a> "
+      "General Public License.\n"
+      "</small>"
+      "<address><kbd>webmaster@junkbusters.com</kbd></address>"
+      "</small>"
+      "</body></html>\n"
+   );
+
+   proxy_args->trailer = b;
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/showargs.h b/showargs.h
new file mode 100644 (file)
index 0000000..82b511c
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _SHOWARGS_H
+#define _SHOWARGS_H
+#define SHOWARGS_H_VERSION "$Id: showargs.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/showargs.h,v $
+ *
+ * Purpose     :  Contains various utility routines needed to 
+ *                generate the show-proxy-args page.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: showargs.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *strsav(char *old, const char *text_to_append);
+extern void savearg(char *c, char *o);
+
+extern void init_proxy_args(int argc, const char *argv[]);
+extern void end_proxy_args(void);
+
+/* Revision control strings from this header and associated .c file */
+extern const char showargs_rcs[];
+extern const char showargs_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _SHOWARGS_H */
diff --git a/ssplit.c b/ssplit.c
new file mode 100644 (file)
index 0000000..81246fd
--- /dev/null
+++ b/ssplit.c
@@ -0,0 +1,235 @@
+const char ssplit_rcs[] = "$Id: ssplit.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/ssplit.c,v $
+ *
+ * Purpose     :  A function to split a string at specified deliminters.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: ssplit.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>\r
+
+#ifdef _WIN32
+#include <malloc.h>
+#endif
+
+#include "ssplit.h"
+#include "miscutil.h"
+
+const char ssplit_h_rcs[] = SSPLIT_H_VERSION;
+
+/* Define this for lots of debugging information to stdout */
+/* #define SSPLIT_VERBOSE */
+
+#ifdef SSPLIT_VERBOSE
+/*********************************************************************
+ *
+ * Function    :  print
+ *
+ * Description :  Debugging routine to spit info on stdout.  Not very
+ *                useful to the non-console based IJB compiles.
+ *
+ * Parameters  :
+ *          1  :  v = an array of strings
+ *          2  :  n = number of strings in `v' to dump to stdout
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void print(char **v, int n)
+{
+   int i;
+   printf("dump %d strings\n", n);
+   for (i=0; i < n; i++)
+   {
+      printf("%d '%s'\n", i, v[i]);
+   }
+
+}
+#endif /* def SSPLIT_VERBOSE */
+
+
+/*********************************************************************
+ *
+ * Function    :  ssplit
+ *
+ * Description :  Split a string using deliminters in `c'.  Results go
+ *                into `v'.
+ *
+ * Parameters  :
+ *          1  :  s = string to split
+ *          2  :  c = array of delimiters
+ *          3  :  v[] = results vector (aka. array)
+ *          4  :  n = number of usable slots in the vector (aka. array size)
+ *          5  :  m = consecutive delimiters means multiple fields?
+ *          6  :  l = ignore leading field separators?
+ *
+ * Returns     :  -1 => failure, else the number of fields put in `v'.
+ *
+ *********************************************************************/
+int ssplit(char *s, char *c, char *v[], int n, int m, int l)
+{
+   char t[256];
+   char **x = NULL;
+   int xsize = 0;
+   unsigned char *p, b;
+   int xi = 0;
+   int vi = 0;
+   int i;
+   int last_was_null;
+
+   if (!s)
+   {
+      return(-1);
+   }
+
+   memset(t, '\0', sizeof(t));
+
+   p = (unsigned char *) c;
+
+   if (!p)
+   {
+      p = (unsigned char *) " \t";  /* default field separators */
+   }
+
+   while (*p)
+   {
+      t[*p++] = 1;   /* separator  */
+   }
+
+   t['\0'] = 2;   /* terminator */
+   t['\n'] = 2;   /* terminator */
+
+   p = (unsigned char *) s;
+
+   if (l)/* are we to skip leading separators ? */
+   {
+      while ((b = t[*p]) != 2)
+      {
+         if (b != 1)
+         {
+            break;
+         }
+         p++;
+      }
+   }
+
+   xsize = 256;
+
+   x = (char **) zalloc((xsize) * sizeof(char *));
+
+   x[xi++] = (char *) p;   /* first pointer is the beginning of string */
+
+   /* first pass:  save pointers to the field separators */
+   while ((b = t[*p]) != 2)
+   {
+      if (b == 1)    /* if the char is a separator ... */
+      {
+         *p++ = '\0';      /* null terminate the substring */
+
+         if (xi == xsize)
+         {
+            /* get another chunk */
+            int new_xsize = xsize + 256;
+            char **new_x = (char **)zalloc((new_xsize) * sizeof(char *));
+
+            for (i=0; i < xsize; i++)
+            {
+               new_x[i] = x[i];
+            }
+
+            free(x);
+            xsize = new_xsize;
+            x     = new_x;
+         }
+         x[xi++] = (char *) p;   /* save pointer to beginning of next string */
+      }
+      else
+      {
+         p++;
+      }
+   }
+   *p = '\0';     /* null terminate the substring */
+
+
+#ifdef SSPLIT_VERBOSE
+   if (DEBUG(HDR))
+   {
+      print(x, xi); /* debugging */
+   }
+#endif /* def SSPLIT_VERBOSE */
+
+
+   /* second pass: copy the relevant pointers to the output vector */
+   last_was_null = 0;
+   for (i=0 ; i < xi; i++)
+   {
+      if (m)
+      {
+         /* there are NO null fields */
+         if (*x[i] == 0)
+         {
+            continue;
+         }
+      }
+      if (vi < n)
+      {
+         v[vi++] = x[i];
+      }
+      else
+      {
+         free(x);
+         return(-1); /* overflow */
+      }
+   }
+   free(x);
+
+#ifdef SSPLIT_VERBOSE
+   if (DEBUG(HDR))
+   {
+      print(v, vi); /* debugging  */
+   }
+#endif /* def SSPLIT_VERBOSE */
+
+   return(vi);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/ssplit.h b/ssplit.h
new file mode 100644 (file)
index 0000000..39bd993
--- /dev/null
+++ b/ssplit.h
@@ -0,0 +1,61 @@
+#ifndef _SSPLIT_H
+#define _SSPLIT_H
+#define SSPLIT_H_VERSION "$Id: ssplit.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/ssplit.h,v $
+ *
+ * Purpose     :  A function to split a string at specified deliminters.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: ssplit.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int ssplit(char *s, char *c, char *v[], int n, int m, int l);
+
+/* Revision control strings from this header and associated .c file */
+extern const char ssplit_rcs[];
+extern const char ssplit_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _SSPLIT_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/trust b/trust
new file mode 100644 (file)
index 0000000..d1a9fe2
--- /dev/null
+++ b/trust
@@ -0,0 +1,27 @@
+#  Illustrative Trustfile for the Internet Junkbuster
+#
+# Copyright 1997-8 Junkbusters Corp.  For distribution, modification and use
+# under the GNU General Public License. These files come with NO WARRANTY.
+# See http://www.junkbusters.com/ht/en/gpl.html or README file for details.
+
+# For this file to have any effect, the line beginning "trustfile" must
+# be commented in, with the name of this file following the word "trustfile"
+
+# Trustfiles are an experimental feature used for building "whitelists"
+# (versus the usual "blacklists" in a blockfile). Most people don't use it.
+# For more detail, see http://www.junkbusters.com/ht/en/ijbman.html#trustfile
+#
+# This is like parsed exactly like a blockfile, except that a '+'
+# in column one is treated like a '~' (i.e. doesn't block) and
+# it adds the spec to the trusted-referer list.
+#
+# Also, the default is to block any URL that is NOT mentioned on this list.
+#
+# While browsing, the domains for URLs that are referred by a trusted referer
+# are added to this list.  Thus this acts as a "white-list" of OK places
+# to browse. Note this means that the file will grow longer with use.
+#
+# Example: to allow only links that came from yahooligans, uncomment this line
+# +yahooligans.com
+# and remove the last line (* alone), which unblock everything:
+*
diff --git a/vc_junkbuster.dsp b/vc_junkbuster.dsp
new file mode 100644 (file)
index 0000000..f9acd6b
--- /dev/null
@@ -0,0 +1,387 @@
+# Microsoft Developer Studio Project File - Name="vc_junkbuster" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 5.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Application" 0x0101\r
+\r
+CFG=vc_junkbuster - Win32 Release\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vc_junkbuster.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "vc_junkbuster.mak" CFG="vc_junkbuster - Win32 Release"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "vc_junkbuster - Win32 Release" (based on "Win32 (x86) Application")\r
+!MESSAGE "vc_junkbuster - Win32 Debug" (based on "Win32 (x86) Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "vc_junkbuster - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "vc_release"\r
+# PROP BASE Intermediate_Dir "vc_release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "vc_release"\r
+# PROP Intermediate_Dir "vc_release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "pcre" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "STATIC" /FR /YX /FD /c\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32\r
+# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib ws2_32.lib comctl32.lib /nologo /subsystem:windows /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "vc_junkbuster - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "vc_debug"\r
+# PROP BASE Intermediate_Dir "vc_debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "vc_debug"\r
+# PROP Intermediate_Dir "vc_debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /O2 /I "pcre" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "STATIC" /YX /FD /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32\r
+# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib ws2_32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "vc_junkbuster - Win32 Release"\r
+# Name "vc_junkbuster - Win32 Debug"\r
+# Begin Group "JunkBuster"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\amiga.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\amiga.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\errlog.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\errlog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\filters.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\filters.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\jcc.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\jcc.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\killpopup.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\killpopup.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\loadcfg.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\loadcfg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\loaders.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\loaders.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\parsers.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\parsers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\project.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\showargs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\showargs.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Win32"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\cygwin.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32log.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32log.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32res.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32rulesdlg.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32rulesdlg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32taskbar.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32taskbar.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\win32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\win32.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resources"\r
+\r
+# PROP Default_Filter "rc,ico,bmp"\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\denyrule.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00001.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00002.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00003.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00004.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00005.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00006.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00007.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\ico00008.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\icon1.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\idle.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\icons\junkbust.ico\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\w32.rc\r
+# End Source File\r
+# End Group\r
+# Begin Group "PCRE"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\chartables.c\r
+\r
+!IF  "$(CFG)" == "vc_junkbuster - Win32 Release"\r
+\r
+!ELSEIF  "$(CFG)" == "vc_junkbuster - Win32 Debug"\r
+\r
+# PROP Exclude_From_Build 1\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\get.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\maketables.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\pcre.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\pcre.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\pcreposix.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\pcreposix.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcre\study.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "PCRS"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\pcrs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pcrs.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Sockets"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\gateway.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\gateway.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\jbsockets.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\jbsockets.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Utilities"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\encode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\encode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\miscutil.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\miscutil.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ssplit.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ssplit.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/vc_junkbuster.dsw b/vc_junkbuster.dsw
new file mode 100644 (file)
index 0000000..a275c02
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "vc_junkbuster"=".\vc_junkbuster.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/w32.aps b/w32.aps
new file mode 100644 (file)
index 0000000..85caaa5
Binary files /dev/null and b/w32.aps differ
diff --git a/w32.rc b/w32.rc
new file mode 100644 (file)
index 0000000..99cdac2
--- /dev/null
+++ b/w32.rc
@@ -0,0 +1,267 @@
+/*********************************************************************\r
+ *\r
+ * File        :  $Source:  $\r
+ *\r
+ * Purpose     :  Windows GUI resource script.\r
+ *\r
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge\r
+ *                IJBSWA team.  http://ijbswa.sourceforge.net\r
+ *\r
+ *                Based on the Internet Junkbuster originally written\r
+ *                by and Copyright (C) 1997 Anonymous Coders and \r
+ *                Junkbusters Corporation.  http://www.junkbusters.com\r
+ *\r
+ *                This program is free software; you can redistribute it \r
+ *                and/or modify it under the terms of the GNU General\r
+ *                Public License as published by the Free Software\r
+ *                Foundation; either version 2 of the License, or (at\r
+ *                your option) any later version.\r
+ *\r
+ *                This program is distributed in the hope that it will\r
+ *                be useful, but WITHOUT ANY WARRANTY; without even the\r
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A\r
+ *                PARTICULAR PURPOSE.  See the GNU General Public\r
+ *                License for more details.\r
+ *\r
+ *                The GNU General Public License should be included with\r
+ *                this file.  If not, you can view it at\r
+ *                http://www.gnu.org/copyleft/gpl.html\r
+ *                or write to the Free Software Foundation, Inc., 59\r
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ *\r
+ * Revisions   :\r
+ *    $Log:$\r
+ *\r
+ *********************************************************************/\r
+\r
+#include <windows.h>\r
+#include "config.h"\r
+#include "w32res.h"\r
+\r
+#ifdef __MINGW32__\r
+#include "cygwin.h"\r
+#endif\r
+\r
+/****************************************************************************\r
+ *  Language-neutral resources\r
+ ****************************************************************************/\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\r
+#ifdef _WIN32\r
+/* LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL */\r
+#pragma code_page(1252)\r
+#endif /* _WIN32 */\r
+\r
+/*\r
+ * Icons\r
+ *\r
+ * Icon with lowest ID value placed first to ensure application icon\r
+ * remains consistent on all systems.\r
+ */\r
+IDI_JUNKBUSTER          ICON    DISCARDABLE     "icons/junkbust.ico"\r
+IDI_JUNKBUSTER1         ICON    DISCARDABLE     "icons/ico00001.ico"\r
+IDI_JUNKBUSTER2         ICON    DISCARDABLE     "icons/ico00002.ico"\r
+IDI_JUNKBUSTER3         ICON    DISCARDABLE     "icons/ico00003.ico"\r
+IDI_JUNKBUSTER4         ICON    DISCARDABLE     "icons/ico00004.ico"\r
+IDI_JUNKBUSTER5         ICON    DISCARDABLE     "icons/ico00005.ico"\r
+IDI_JUNKBUSTER6         ICON    DISCARDABLE     "icons/ico00006.ico"\r
+IDI_JUNKBUSTER7         ICON    DISCARDABLE     "icons/ico00007.ico"\r
+IDI_JUNKBUSTER8         ICON    DISCARDABLE     "icons/ico00008.ico"\r
+IDI_IDLE                ICON    DISCARDABLE     "icons/idle.ico"\r
+\r
+#endif /* Neutral resources */\r
+\r
+\r
+/****************************************************************************\r
+ *  English (U.S.) resources\r
+ ****************************************************************************/\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+/* LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US */\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/*\r
+ * Menus\r
+ */\r
+\r
+IDR_TRAYMENU MENU DISCARDABLE\r
+BEGIN\r
+    POPUP "Popup"\r
+    BEGIN\r
+        MENUITEM "E&xit JunkBuster",   ID_FILE_EXIT\r
+        MENUITEM                       SEPARATOR\r
+        POPUP "&Options"\r
+        BEGIN\r
+            MENUITEM "&Junkbuster...",              ID_TOOLS_EDITJUNKBUSTER\r
+            MENUITEM                                SEPARATOR\r
+            MENUITEM "&Blockers...",                ID_TOOLS_EDITBLOCKERS\r
+            MENUITEM "&Cookies...",                 ID_TOOLS_EDITCOOKIES\r
+            MENUITEM "&Forward...",                 ID_TOOLS_EDITFORWARD\r
+#ifdef ACL_FILES\r
+            MENUITEM "&Access Control Lists...",    ID_TOOLS_EDITACLS\r
+#endif /* def ACL_FILES */\r
+#ifdef USE_IMAGE_LIST\r
+            MENUITEM "&Images...",                  ID_TOOLS_EDITIMAGE\r
+#endif /* def USE_IMAGE_LIST */\r
+#ifdef KILLPOPUPS\r
+            MENUITEM "&Popups...",                  ID_TOOLS_EDITPOPUPS\r
+#endif /* def KILLPOPUPS */\r
+#ifdef PCRS\r
+            MENUITEM "Perl &Regexps...",            ID_TOOLS_EDITPERLRE\r
+#endif /* def PCRS */\r
+#ifdef TRUST_FILES\r
+            MENUITEM "&Trust...",                   ID_TOOLS_EDITTRUST\r
+#endif /* def TRUST_FILES */\r
+        END\r
+        MENUITEM                              SEPARATOR\r
+#ifdef TOGGLE\r
+        MENUITEM "&Enable",                   ID_TOGGLE_IJB, CHECKED\r
+#endif\r
+        MENUITEM "&Reload config",            ID_RELOAD_CONFIG\r
+        MENUITEM "Show &JunkBuster Window",   ID_SHOWWINDOW\r
+    END\r
+END\r
+\r
+IDR_LOGVIEW MENU DISCARDABLE\r
+BEGIN\r
+    POPUP "&File"\r
+    BEGIN\r
+        MENUITEM "E&xit",                       ID_FILE_EXIT\r
+    END\r
+    POPUP "&Edit"\r
+    BEGIN\r
+        MENUITEM "Copy",                        ID_EDIT_COPY\r
+    END\r
+    POPUP "&View"\r
+    BEGIN\r
+        MENUITEM "&Clear Log",                  ID_VIEW_CLEARLOG\r
+        MENUITEM                                SEPARATOR\r
+        MENUITEM "&Log Messages",               ID_VIEW_LOGMESSAGES, CHECKED\r
+        MENUITEM "Message &Highlighting",       ID_VIEW_MESSAGEHIGHLIGHTING, CHECKED\r
+        MENUITEM "Limit &Buffer Size",          ID_VIEW_LIMITBUFFERSIZE, CHECKED\r
+        MENUITEM "&Activity Animation",         ID_VIEW_ACTIVITYANIMATION, CHECKED\r
+    END\r
+    POPUP "&Options"\r
+    BEGIN\r
+#ifdef TOGGLE\r
+        MENUITEM "&Enable",                     ID_TOGGLE_IJB, CHECKED\r
+        MENUITEM "&Reload config",              ID_RELOAD_CONFIG\r
+        MENUITEM                                SEPARATOR\r
+#endif\r
+        MENUITEM "&Junkbuster...",              ID_TOOLS_EDITJUNKBUSTER\r
+        MENUITEM                                SEPARATOR\r
+        MENUITEM "&Blockers...",                ID_TOOLS_EDITBLOCKERS\r
+        MENUITEM "&Cookies...",                 ID_TOOLS_EDITCOOKIES\r
+        MENUITEM "&Forward...",                 ID_TOOLS_EDITFORWARD\r
+#ifdef ACL_FILES\r
+            MENUITEM "&Access Control Lists...",ID_TOOLS_EDITACLS\r
+#endif /* def ACL_FILES */\r
+#ifdef USE_IMAGE_LIST\r
+            MENUITEM "&Images...",              ID_TOOLS_EDITIMAGE\r
+#endif /* def USE_IMAGE_LIST */\r
+#ifdef KILLPOPUPS\r
+            MENUITEM "&Popups...",              ID_TOOLS_EDITPOPUPS\r
+#endif /* def KILLPOPUPS */\r
+#ifdef PCRS\r
+            MENUITEM "Perl &Regexps...",        ID_TOOLS_EDITPERLRE\r
+#endif /* def PCRS */\r
+#ifdef TRUST_FILES\r
+            MENUITEM "&Trust...",               ID_TOOLS_EDITTRUST\r
+#endif /* def TRUST_FILES */\r
+    END\r
+    POPUP "&Help"\r
+    BEGIN\r
+        MENUITEM "Junkbuster &FAQ",             ID_HELP_FAQ\r
+        MENUITEM "Junkbuster &Manual",          ID_HELP_MANUAL\r
+        MENUITEM "GNU &General Public Licence", ID_HELP_GPL\r
+        MENUITEM                                SEPARATOR\r
+        MENUITEM "Junkbuster Status...",        ID_HELP_STATUS\r
+        MENUITEM                                SEPARATOR\r
+        MENUITEM "About Junkbuster...",         ID_HELP_ABOUTJUNKBUSTER\r
+    END\r
+END\r
+\r
+IDR_POPUP_SELECTION MENU DISCARDABLE\r
+BEGIN\r
+    POPUP "Popup"\r
+    BEGIN\r
+        MENUITEM "&Copy",                       ID_EDIT_COPY\r
+    END\r
+END\r
+\r
+\r
+/*\r
+ * Accelerators\r
+ */\r
+\r
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE\r
+BEGIN\r
+    "C",            ID_EDIT_COPY,           VIRTKEY, CONTROL, NOINVERT\r
+END\r
+\r
+/*\r
+ * Icons\r
+ *\r
+ * Icon with lowest ID value placed first to ensure application icon\r
+ * remains consistent on all systems.\r
+ */\r
+IDI_DENYRULE            ICON    DISCARDABLE     "icons/denyrule.ico"\r
+IDI_ALLOWRULE           ICON    DISCARDABLE     "icons/icon1.ico"\r
+\r
+/*\r
+ * Dialog\r
+ */\r
+\r
+IDD_RULES DIALOG DISCARDABLE  0, 0, 239, 225\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "Blockers"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    GROUPBOX        "New Rule",IDC_STATIC,5,5,230,55\r
+    LTEXT           "For:",IDC_STATIC,10,15,13,8\r
+    EDITTEXT        IDC_NEW,10,25,220,12,ES_AUTOHSCROLL\r
+    COMBOBOX        IDC_ACTION,10,40,75,37,CBS_DROPDOWNLIST | CBS_SORT |\r
+                    WS_VSCROLL | WS_TABSTOP\r
+    PUSHBUTTON      "C&reate!",IDC_CREATE,90,40,50,14\r
+    GROUPBOX        "Rules",IDC_STATIC,5,65,230,135\r
+    CONTROL         "List1",IDC_RULES,"SysListView32",LVS_REPORT |\r
+                    LVS_SHOWSELALWAYS | LVS_EDITLABELS | WS_BORDER |\r
+                    WS_TABSTOP,10,75,220,100\r
+    PUSHBUTTON      "Move &Up",IDC_MOVEUP,10,180,50,14,WS_DISABLED\r
+    PUSHBUTTON      "Move &Down",IDC_MOVEDOWN,65,180,50,14,WS_DISABLED\r
+    PUSHBUTTON      "&Delete",IDC_DELETE,120,180,50,14,WS_DISABLED\r
+    PUSHBUTTON      "&Save",IDC_SAVE,130,205,50,14\r
+    PUSHBUTTON      "&Cancel",IDCANCEL,185,205,50,14\r
+END\r
+\r
+\r
+/*\r
+ * DESIGNINFO\r
+ */\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO DISCARDABLE\r
+BEGIN\r
+    IDD_RULES, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 232\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 218\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/*\r
+ * String Table\r
+ */\r
+\r
+STRINGTABLE DISCARDABLE\r
+BEGIN\r
+    IDS_NEW_BLOCKER         "Create rule for ""%s""..."\r
+END\r
+\r
+#endif /* English (U.S.) resources */\r
diff --git a/w32log.c b/w32log.c
new file mode 100644 (file)
index 0000000..975c5e0
--- /dev/null
+++ b/w32log.c
@@ -0,0 +1,1321 @@
+const char w32log_rcs[] = "$Id: w32log.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32log.c,v $
+ *
+ * Purpose     :  Functions for creating and destroying the log window,
+ *                ouputting strings, processing messages and so on.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32log.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <windows.h>
+#include <richedit.h>
+
+#include "project.h"
+#include "w32log.h"
+#include "w32taskbar.h"
+#include "w32rulesdlg.h"
+#include "win32.h"
+#include "w32res.h"
+#include "jcc.h"
+#include "miscutil.h"
+#include "errlog.h"
+
+const char w32res_h_rcs[] = W32RES_H_VERSION;
+
+#ifdef __MINGW32__
+#include "cygwin.h"
+const char cygwin_h_rcs[] = CYGWIN_H_VERSION;
+#endif
+
+const char w32log_h_rcs[] = W32LOG_H_VERSION;
+
+/*
+ * Timers and the various durations
+ */
+#define TIMER_ANIM_ID               1
+#define TIMER_ANIM_TIME             100
+#define TIMER_ANIMSTOP_ID           2
+#define TIMER_ANIMSTOP_TIME         1000
+#define TIMER_CLIPBUFFER_ID         3
+#define TIMER_CLIPBUFFER_TIME       1000
+#define TIMER_CLIPBUFFER_FORCE_ID   4
+#define TIMER_CLIPBUFFER_FORCE_TIME 5000
+
+/*
+ * Styles of text that can be output
+ */
+#define STYLE_NONE      0
+#define STYLE_HIGHLIGHT 1
+#define STYLE_LINK      2
+#define STYLE_HEADER    3
+
+/*
+ * Number of frames of animation in tray activity sequence
+ */
+#define ANIM_FRAMES 8
+
+#define DEFAULT_MAX_BUFFER_LINES    200
+#define DEFAULT_LOG_FONT_NAME       "MS Sans Serif"
+#define DEFAULT_LOG_FONT_SIZE       8
+
+/*
+ * These values affect the way the log window behaves, they should be read
+ * from a file but for the moment, they are hardcoded here. Some options are
+ * configurable through the UI.
+ */
+
+/* Indicates whether task bar shows activity animation */
+BOOL g_bShowActivityAnimation = 1;
+
+/* Indicates if the log window appears on the task bar */
+BOOL g_bShowOnTaskBar = 0;
+
+/* Indicates whether closing the log window really just hides it */
+BOOL g_bCloseHidesWindow = 1;
+
+/* Indicates if messages are logged at all */
+BOOL g_bLogMessages = 1;
+
+/* Indicates whether log messages are highlighted */
+BOOL g_bHighlightMessages = 1;
+
+/* Indicates if buffer is limited in size */
+BOOL g_bLimitBufferSize = 1;
+
+/* Maximum number of lines allowed in buffer when limited */
+int g_nMaxBufferLines = DEFAULT_MAX_BUFFER_LINES;
+
+/* Font to use */
+char g_szFontFaceName[255] = DEFAULT_LOG_FONT_NAME;
+
+/* Size of font to use */
+int g_nFontSize = DEFAULT_LOG_FONT_SIZE;
+
+
+#ifdef REGEX
+/* Regular expression for detected URLs */
+#define RE_URL "http:[^ \n\r]*"
+
+/*
+ * Regular expressions that are used to perform highlight in the log window
+ */
+static struct _Pattern
+{
+   const char *str;
+   int style;
+   regex_t buffer;
+} patterns_to_highlight[] =
+{
+   /* url headers */
+   { RE_URL,                STYLE_LINK },
+/* { "[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[^ \n\r]*", STYLE_LINK }, */
+   /* interesting text to highlight */
+   { "crunch!",           STYLE_HIGHLIGHT },
+   /* http headers */
+   { "referer:",            STYLE_HEADER },
+   { "proxy-connection:",   STYLE_HEADER },
+   { "proxy-agent:",        STYLE_HEADER },
+   { "user-agent:",         STYLE_HEADER },
+   { "host:",               STYLE_HEADER },
+   { "accept:",             STYLE_HEADER },
+   { "accept-encoding:",    STYLE_HEADER },
+   { "accept-language:",    STYLE_HEADER },
+   { "accept-charset:",     STYLE_HEADER },
+   { "accept-ranges:",      STYLE_HEADER },
+   { "date:",               STYLE_HEADER },
+   { "cache-control:",      STYLE_HEADER },
+   { "cache-last-checked:", STYLE_HEADER },
+   { "connection:",         STYLE_HEADER },
+   { "content-type",        STYLE_HEADER },
+   { "content-length",      STYLE_HEADER },
+   { "cookie",              STYLE_HEADER },
+   { "last-modified:",      STYLE_HEADER },
+   { "pragma:",             STYLE_HEADER },
+   { "server:",             STYLE_HEADER },
+   { "etag:",               STYLE_HEADER },
+   { "expires:",            STYLE_HEADER },
+   { "warning:",            STYLE_HEADER },
+   /* this is the terminator statement - do not delete! */
+   { NULL,                  STYLE_NONE }
+};
+#endif /* def REGEX */
+
+
+/*
+ * Public variables
+ */
+HWND g_hwndLogFrame;
+
+/*
+ * Private variables
+ */
+static CRITICAL_SECTION g_criticalsection;
+static HWND g_hwndTray;
+static HWND g_hwndLogBox;
+static WNDPROC g_fnLogBox;
+static HICON g_hiconAnim[ANIM_FRAMES];
+static HICON g_hiconIdle;
+static HICON g_hiconApp;
+static int g_nAnimFrame;
+static BOOL g_bClipPending = FALSE;
+static int g_nRichEditVersion = 0;
+
+/*
+ * Private functions
+ */
+static HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow);
+static HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance);
+static LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static BOOL InitRichEdit(void);
+static void LogClipBuffer(void);
+static void LogCreatePatternMatchingBuffers(void);
+static void LogDestroyPatternMatchingBuffers(void);
+static int LogPutStringNoMatch(const char *pszText, int style);
+
+
+/*********************************************************************
+ *
+ * Function    :  InitLogWindow
+ *
+ * Description :  Initialise the log window.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  Always TRUE (there should be error checking on the resources).
+ *
+ *********************************************************************/
+BOOL InitLogWindow(void)
+{
+   int i;
+
+   /* Load the icons */
+   g_hiconIdle = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IDLE));
+   for (i = 0; i < ANIM_FRAMES; i++)
+   {
+      g_hiconAnim[i] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_JUNKBUSTER1 + i));
+   }
+   g_hiconApp = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_JUNKBUSTER));
+
+   /* Create the user interface */
+   g_hwndLogFrame = CreateLogWindow(g_hInstance, g_nCmdShow);
+   g_hwndTray = CreateTrayWindow(g_hInstance);
+   TrayAddIcon(g_hwndTray, 1, g_hiconApp, "Junkbuster");
+
+   /* Create pattern matching buffers (for highlighting */
+   LogCreatePatternMatchingBuffers();
+
+   /* Create a critical section to protect multi-threaded access to certain things */
+   InitializeCriticalSection(&g_criticalsection);
+
+   return TRUE;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  TermLogWindow
+ *
+ * Description :  Cleanup the logwindow.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void TermLogWindow(void)
+{
+   int i;
+
+   LogDestroyPatternMatchingBuffers();
+
+   TrayDeleteIcon(g_hwndTray, 1);
+   DeleteObject(g_hiconApp);
+   DeleteObject(g_hiconIdle);
+   for (i = 0; i < ANIM_FRAMES; i++)
+   {
+      DeleteObject(g_hiconAnim[i]);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogCreatePatternMatchingBuffers
+ *
+ * Description :  Compile the pattern matching buffers.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void LogCreatePatternMatchingBuffers(void)
+{
+#ifdef REGEX
+   int i;
+   for (i = 0; patterns_to_highlight[i].str != NULL; i++)
+   {
+      regcomp(&patterns_to_highlight[i].buffer, patterns_to_highlight[i].str, REG_ICASE);
+   }
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogDestroyPatternMatchingBuffers
+ *
+ * Description :  Free up the pattern matching buffers.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void LogDestroyPatternMatchingBuffers(void)
+{
+#ifdef REGEX
+   int i;
+   for (i = 0; patterns_to_highlight[i].str != NULL; i++)
+   {
+      regfree(&patterns_to_highlight[i].buffer);
+   }
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogGetURLUnderCursor
+ *
+ * Description :  Returns the URL from under the cursor (remember to free it!).
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  NULL or a pointer to an URL string.
+ *
+ *********************************************************************/
+char *LogGetURLUnderCursor(void)
+{
+   char *szResult = NULL;
+#ifdef REGEX
+   regex_t re;
+   POINT ptCursor;
+   POINTL ptl;
+   DWORD nPos;
+   DWORD nWordStart = 0;
+   DWORD nWordEnd = 0;
+
+   regcomp(&re, RE_URL, REG_ICASE);
+
+   /* Get the position of the cursor over the text window */
+   GetCursorPos(&ptCursor);
+   ScreenToClient(g_hwndLogBox, &ptCursor);
+   ptl.x = ptCursor.x;
+   ptl.y = ptCursor.y;
+
+   /* Search backwards and fowards to obtain the word that is highlighted */
+   nPos = LOWORD(SendMessage(g_hwndLogBox, EM_CHARFROMPOS, 0, (LPARAM) &ptl));
+   nWordStart = SendMessage(g_hwndLogBox, EM_FINDWORDBREAK, WB_LEFT, nPos);
+   nWordEnd = SendMessage(g_hwndLogBox, EM_FINDWORDBREAK, WB_RIGHTBREAK, nPos);
+
+   /* Compare the string to the pattern */
+   if (nWordEnd > nWordStart)
+   {
+      TEXTRANGE range;
+      regmatch_t match;
+
+      range.chrg.cpMin = nWordStart;
+      range.chrg.cpMax = nWordEnd;
+      range.lpstrText = (LPSTR)zalloc(nWordEnd - nWordStart + 1);
+      SendMessage(g_hwndLogBox, EM_GETTEXTRANGE, 0, (LPARAM) &range);
+
+      if (regexec(&re, range.lpstrText, 1, &match, 0) == 0)
+      {
+         szResult = range.lpstrText;
+      }
+      else
+      {
+         free(range.lpstrText);
+      }
+
+      regfree(&re);
+   }
+#endif
+   return szResult;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogPutString
+ *
+ * Description :  Inserts text into the logging window.  This is really
+ *                a REGEXP aware wrapper function to `LogPutStringNoMatch'.
+ *
+ * Parameters  :
+ *          1  :  pszText = pointer to string going to the log window
+ *
+ * Returns     :  1 => success, else the return code from `LogPutStringNoMatch'.
+ *                FIXME: this is backwards to the rest of IJB and to common
+ *                programming practice.  Please use 0 => success instead.
+ *
+ *********************************************************************/
+int LogPutString(const char *pszText)
+{
+#ifdef REGEX
+   int i;
+#endif
+   int result = 0;
+
+   if (pszText == NULL || strlen(pszText) == 0)
+   {
+      return 1;
+   }
+
+   if (!g_bLogMessages)
+   {
+      return 1;
+   }
+
+   /* Critical section stops multiple threads doing nasty interactions that
+    * foul up the highlighting and output.
+    */
+   EnterCriticalSection(&g_criticalsection);
+
+#ifdef REGEX
+   if (g_bHighlightMessages)
+   {
+      regmatch_t match;
+
+      /* First things first, regexp scan for various things that we would like highlighted */
+      for (i = 0; patterns_to_highlight[i].str != NULL; i++)
+      {
+         if (regexec(&patterns_to_highlight[i].buffer, pszText, 1, &match, 0) == 0)
+         {
+            char *pszBefore = NULL;
+            char *pszMatch = NULL;
+            char *pszAfter = NULL;
+            int nMatchSize;
+
+            /* Split the string up into pieces representing the strings, before
+               at and after the matching pattern
+             */
+            if (match.rm_so > 0)
+            {
+               pszBefore = (char *)malloc((match.rm_so + 1) * sizeof(char));
+               memset(pszBefore, 0, (match.rm_so + 1) * sizeof(char));
+               strncpy(pszBefore, pszText, match.rm_so);
+            }
+            if (match.rm_eo < strlen(pszText))
+            {
+               pszAfter = strdup(&pszText[match.rm_eo]);
+            }
+            nMatchSize = match.rm_eo - match.rm_so;
+            pszMatch = (char *)malloc(nMatchSize + 1);
+            strncpy(pszMatch, &pszText[match.rm_so], nMatchSize);
+            pszMatch[nMatchSize] = '\0';
+
+            /* Recursively call LogPutString */
+            if (pszBefore)
+            {
+               LogPutString(pszBefore);
+               free(pszBefore);
+            }
+            if (pszMatch)
+            {
+               LogPutStringNoMatch(pszMatch, patterns_to_highlight[i].style);
+               free(pszMatch);
+            }
+            if (pszAfter)
+            {
+               LogPutString(pszAfter);
+               free(pszAfter);
+            }
+
+            result = 1;
+            goto end;
+         }
+      }
+   }
+#endif
+
+   result = LogPutStringNoMatch(pszText, STYLE_NONE);
+
+#ifdef REGEX
+end:
+#endif
+   LeaveCriticalSection(&g_criticalsection);
+
+   return result;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogPutStringNoMatch
+ *
+ * Description :  Puts a string into the logging window.
+ *
+ * Parameters  :
+ *          1  :  pszText = pointer to string going to the log window
+ *          2  :  style = STYLE_NONE, STYLE_HEADER, STYLE_HIGHLIGHT, or STYLE_LINK
+ *
+ * Returns     :  Always 1 => success.
+ *                FIXME: this is backwards to the rest of IJB and to common
+ *                programming practice.  Please use 0 => success instead.
+ *
+ *********************************************************************/
+int LogPutStringNoMatch(const char *pszText, int style)
+{
+   CHARRANGE range;
+   CHARFORMAT format;
+   int nTextLength;
+
+   assert(g_hwndLogBox);
+   if (g_hwndLogBox == NULL)
+   {
+      return 1;
+   }
+
+   /* TODO preserve existing selection */
+
+   /* Go to the end of the text */
+   nTextLength = GetWindowTextLength(g_hwndLogBox);
+   range.cpMin = nTextLength;
+   range.cpMax = nTextLength;
+   SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range);
+
+   /* Apply a formatting style */
+   memset(&format, 0, sizeof(format));
+   format.cbSize = sizeof(format);
+   format.dwMask = CFM_BOLD | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_ITALIC | CFM_COLOR | CFM_FACE | CFM_SIZE;
+   format.yHeight = (g_nFontSize * 1440) / 72;
+   strcpy(format.szFaceName, g_szFontFaceName);
+   if (style == STYLE_NONE)
+   {
+      /* DO NOTHING */
+      format.dwEffects |= CFE_AUTOCOLOR;
+   }
+   else if (style == STYLE_HEADER)
+   {
+      format.dwEffects |= CFE_AUTOCOLOR | CFE_ITALIC;
+   }
+   else if (style == STYLE_HIGHLIGHT)
+   {
+      format.dwEffects |= CFE_AUTOCOLOR | CFE_BOLD;
+   }
+   else if (style == STYLE_LINK)
+   {
+      format.dwEffects |= CFE_UNDERLINE;
+      format.crTextColor = RGB(0, 0, 255);
+   }
+   SendMessage(g_hwndLogBox, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &format);
+
+   /* Append text to the end */
+   SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) pszText);
+
+   /* TODO Restore the old selection */
+
+   /* Purge buffer */
+   if (strchr(pszText, '\n') != NULL)
+   {
+      SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID, TIMER_CLIPBUFFER_TIME, NULL);
+      if (!g_bClipPending)
+      {
+         /* Set the force clip timer going. This timer ensures clipping is done
+            intermittently even when there is a sustained burst of logging
+         */
+         SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID, TIMER_CLIPBUFFER_FORCE_TIME, NULL);
+      }
+      g_bClipPending = TRUE;
+   }
+
+   return 1;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogShowActivity
+ *
+ * Description :  Start the spinner.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void LogShowActivity(void)
+{
+   /* Start some activity timers */
+   if (g_bShowActivityAnimation)
+   {
+      SetTimer(g_hwndLogFrame, TIMER_ANIM_ID, TIMER_ANIM_TIME, NULL);
+      SetTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID, TIMER_ANIMSTOP_TIME, NULL);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogClipBuffer
+ *
+ * Description :  Prunes old lines from the log.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void LogClipBuffer(void)
+{
+   int nLines = SendMessage(g_hwndLogBox, EM_GETLINECOUNT, 0, 0);
+   if (g_bLimitBufferSize && nLines > g_nMaxBufferLines)
+   {
+      /* Compute the range representing the lines to be deleted */
+      LONG nLastLineToDelete = nLines - g_nMaxBufferLines;
+      LONG nLastChar = SendMessage(g_hwndLogBox, EM_LINEINDEX, nLastLineToDelete, 0);
+      CHARRANGE range;
+      range.cpMin = 0;
+      range.cpMax = nLastChar;
+
+      /* TODO get current selection */
+
+      /* TODO adjust and clip old selection against range to be deleted */
+
+      /* Select range and erase it (turning off autoscroll to prevent
+         nasty scrolling) */
+      SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
+      SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range);
+      SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) "");
+      SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
+
+      /* Restore old selection */
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  CreateHiddenLogOwnerWindow
+ *
+ * Description :  Creates a hidden owner window that stops the log
+ *                window appearing in the task bar.
+ *
+ * Parameters  :
+ *          1  :  hInstance = application's instance handle
+ *
+ * Returns     :  Handle to newly created window.
+ *
+ *********************************************************************/
+HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance)
+{
+   static const char *szWndName = "JunkbusterLogLogOwner";
+   WNDCLASS wc;
+   HWND hwnd;
+
+   wc.style          = 0;
+   wc.lpfnWndProc    = LogOwnerWindowProc;
+   wc.cbClsExtra     = 0;
+   wc.cbWndExtra     = 0;
+   wc.hInstance      = hInstance;
+   wc.hIcon          = 0;
+   wc.hCursor        = 0;
+   wc.hbrBackground  = 0;
+   wc.lpszMenuName   = 0;
+   wc.lpszClassName  = szWndName;
+
+   RegisterClass(&wc);
+
+   hwnd = CreateWindow(szWndName, szWndName,
+      WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+      CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
+
+   return hwnd;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogOwnerWindowProc
+ *
+ * Description :  Dummy procedure that does nothing special.
+ *
+ * Parameters  :
+ *          1  :  hwnd = window handle
+ *          2  :  uMsg = message number
+ *          3  :  wParam = first param for this message
+ *          4  :  lParam = next param for this message
+ *
+ * Returns     :  Same as `DefWindowProc'.
+ *
+ *********************************************************************/
+LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   return DefWindowProc(hwnd, uMsg, wParam, lParam);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  CreateLogWindow
+ *
+ * Description :  Create the logging window.
+ *
+ * Parameters  :
+ *          1  :  hInstance = application's instance handle
+ *          2  :  nCmdShow = window show value (MIN, MAX, NORMAL, etc...)
+ *
+ * Returns     :  Handle to newly created window.
+ *
+ *********************************************************************/
+HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow)
+{
+   static const char *szWndName = "JunkbusterLogWindow";
+   static const char *szWndTitle = "Junkbuster";
+
+   HWND hwnd = NULL;
+   HWND hwndOwner = (g_bShowOnTaskBar) ? NULL : CreateHiddenLogOwnerWindow(hInstance);
+   HWND hwndChild = NULL;
+   RECT rcClient;
+   WNDCLASSEX wc;
+
+   memset(&wc, 0, sizeof(wc));
+   wc.cbSize         = sizeof(wc);
+   wc.style          = CS_DBLCLKS;
+   wc.lpfnWndProc    = LogWindowProc;
+   wc.cbClsExtra     = 0;
+   wc.cbWndExtra     = 0;
+   wc.hInstance      = hInstance;
+   wc.hIcon          = g_hiconApp;
+   wc.hCursor        = 0;
+   wc.hbrBackground  = 0;
+   wc.lpszMenuName   = MAKEINTRESOURCE(IDR_LOGVIEW);
+   wc.lpszClassName  = szWndName;
+   wc.hbrBackground  = GetStockObject(WHITE_BRUSH);
+   RegisterClassEx(&wc);
+
+   hwnd = CreateWindowEx(WS_EX_APPWINDOW, szWndName, szWndTitle,
+      WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+      CW_USEDEFAULT, hwndOwner, NULL, hInstance, NULL);
+
+   /* Now create a child list box */
+   GetClientRect(hwnd, &rcClient);
+
+   /* Create a rich edit control */
+   InitRichEdit();
+   g_hwndLogBox = CreateWindowEx(0, (g_nRichEditVersion == 0x0100) ? "RichEdit" : RICHEDIT_CLASS, "",
+      ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY | ES_NOHIDESEL | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
+      rcClient.left, rcClient.top, rcClient.right, rcClient.bottom,
+      hwnd, NULL, hInstance, NULL);
+/* SendMessage(g_hwndLogBox, EM_SETWORDWRAPMODE, 0, 0); */
+
+   /* Subclass the control to catch certain messages */
+   g_fnLogBox = (WNDPROC) GetWindowLong(g_hwndLogBox, GWL_WNDPROC);
+   SetWindowLong(g_hwndLogBox, GWL_WNDPROC, (LONG) LogRichEditProc);
+
+   /* Minimizing looks stupid when the log window is not on the task bar, so hide instead */
+   if (!g_bShowOnTaskBar &&
+         (nCmdShow == SW_SHOWMINIMIZED ||
+          nCmdShow == SW_MINIMIZE ||
+          nCmdShow == SW_SHOWMINNOACTIVE))
+   {
+      nCmdShow = SW_HIDE;
+   }
+
+   ShowWindow(hwnd, nCmdShow);
+   UpdateWindow(hwnd);
+
+   GetClientRect(g_hwndLogFrame, &rcClient);
+   SetWindowPos(g_hwndLogBox, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_NOZORDER);
+
+   return hwnd;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  InitRichEdit
+ *
+ * Description :  Initialise the rich edit control library.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  TRUE => success, FALSE => failure.
+ *                FIXME: this is backwards to the rest of IJB and to common
+ *                programming practice.  Please use 0 => success instead.
+ *
+ *********************************************************************/
+BOOL InitRichEdit(void)
+{
+   static HINSTANCE hInstRichEdit;
+   if (hInstRichEdit == NULL)
+   {
+      g_nRichEditVersion = 0;
+      hInstRichEdit = LoadLibraryA("RICHED20.DLL");
+      if (hInstRichEdit)
+      {
+         g_nRichEditVersion = _RICHEDIT_VER;
+      }
+      else
+      {
+         hInstRichEdit = LoadLibraryA("RICHED32.DLL");
+         if (hInstRichEdit)
+         {
+            g_nRichEditVersion = 0x0100;
+         }
+      }
+   }
+   return (hInstRichEdit != NULL) ? TRUE : FALSE;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ShowLogWindow
+ *
+ * Description :  Shows or hides the log window.  We will also raise the
+ *                window on a show command in case it is buried.
+ *
+ * Parameters  :
+ *          1  :  bShow = TRUE to show, FALSE to mimize/hide
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void ShowLogWindow(BOOL bShow)
+{
+   if (bShow)
+   {
+      SetForegroundWindow(g_hwndLogFrame);
+      SetWindowPos(g_hwndLogFrame, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
+   }
+   else if (g_bShowOnTaskBar)
+   {
+      ShowWindow(g_hwndLogFrame, SW_MINIMIZE);
+   }
+   else
+   {
+      ShowWindow(g_hwndLogFrame, SW_HIDE);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  EditFile
+ *
+ * Description :  Opens the specified setting file for editing.
+ *
+ * Parameters  :
+ *          1  :  filename = filename from the config (aka junkbstr.txt) file.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void EditFile(const char *filename)
+{
+   if (filename)
+   {
+      ShellExecute(g_hwndLogFrame, "open", filename, NULL, NULL, SW_SHOWNORMAL);
+   }
+
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* Windows message handlers                                                 */
+/*--------------------------------------------------------------------------*/
+
+
+/*********************************************************************
+ *
+ * Function    :  OnLogRButtonUp
+ *
+ * Description :  Handler for WM_RBUTTONUP messages.
+ *
+ * Parameters  :
+ *          1  :  nModifier = wParam from mouse message (unused)
+ *          2  :  x = x coordinate of the mouse event
+ *          3  :  y = y coordinate of the mouse event
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void OnLogRButtonUp(int nModifier, int x, int y)
+{
+   HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_POPUP_SELECTION));
+   if (hMenu != NULL)
+   {
+      HMENU hMenuPopup = GetSubMenu(hMenu, 0);
+      char *szURL;
+
+      /* Check if there is a selection */
+      CHARRANGE range;
+      SendMessage(g_hwndLogBox, EM_EXGETSEL, 0, (LPARAM) &range);
+      if (range.cpMin == range.cpMax)
+      {
+         EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
+      }
+      else
+      {
+         EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
+      }
+
+      /* Check if cursor is over a link */
+      szURL = LogGetURLUnderCursor();
+      if (szURL)
+      {
+         MENUITEMINFO item;
+         TCHAR szMenuItemTemplate[1000];
+         char *szMenuItem;
+
+         memset(&item, 0, sizeof(item));
+         item.cbSize = sizeof(item);
+         item.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
+         item.fType = MFT_STRING;
+         item.fState = MFS_ENABLED;
+         item.wID = ID_NEW_BLOCKER;
+
+         /* Put the item into the menu */
+         memset(szMenuItemTemplate, 0, sizeof(szMenuItemTemplate));
+         LoadString(g_hInstance, IDS_NEW_BLOCKER, szMenuItemTemplate, sizeof(szMenuItemTemplate) / sizeof(szMenuItemTemplate[0]));
+
+         szMenuItem = (char *)malloc(strlen(szMenuItemTemplate) + strlen(szURL) + 1);
+         sprintf(szMenuItem, szMenuItemTemplate, szURL);
+
+         item.dwTypeData = szMenuItem;
+         item.cch = strlen(szMenuItem);
+
+         InsertMenuItem(hMenuPopup, 1, TRUE, &item);
+
+         SetDefaultRule(szURL);
+
+         free(szURL);
+      }
+
+      /* Display the popup */
+      TrackPopupMenu(hMenuPopup, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, x, y, 0, g_hwndLogFrame, NULL);
+      DestroyMenu(hMenu);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnLogCommand
+ *
+ * Description :  Handler for WM_COMMAND messages.
+ *
+ * Parameters  :
+ *          1  :  nCommand = the command portion of the menu selection event
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void OnLogCommand(int nCommand)
+{
+   switch (nCommand)
+   {
+      case ID_SHOWWINDOW:
+         ShowLogWindow(TRUE);
+         break;
+
+      case ID_FILE_EXIT:
+         PostMessage(g_hwndLogFrame, WM_CLOSE, 0, 0);
+         break;
+
+      case ID_EDIT_COPY:
+         SendMessage(g_hwndLogBox, WM_COPY, 0, 0);
+         break;
+
+      case ID_VIEW_CLEARLOG:
+         SendMessage(g_hwndLogBox, WM_SETTEXT, 0, (LPARAM) "");
+         break;
+
+      case ID_VIEW_LOGMESSAGES:
+         g_bLogMessages = !g_bLogMessages;
+         /* SaveLogSettings(); */
+         break;
+
+      case ID_VIEW_MESSAGEHIGHLIGHTING:
+         g_bHighlightMessages = !g_bHighlightMessages;
+         /* SaveLogSettings(); */
+         break;
+
+      case ID_VIEW_LIMITBUFFERSIZE:
+         g_bLimitBufferSize = !g_bLimitBufferSize;
+         /* SaveLogSettings(); */
+         break;
+
+      case ID_VIEW_ACTIVITYANIMATION:
+         g_bShowActivityAnimation = !g_bShowActivityAnimation;
+         /* SaveLogSettings(); */
+         break;
+
+#ifdef TOGGLE
+      /* by haroon - change toggle to its opposite value */
+      case ID_TOGGLE_IJB:
+         g_bToggleIJB = !g_bToggleIJB;
+         if (g_bToggleIJB)
+         {
+            log_error(LOG_LEVEL_INFO, "Now toggled ON.");
+         }
+         else
+         {
+            log_error(LOG_LEVEL_INFO, "Now toggled OFF.");
+         }
+         break;
+#endif
+
+      case ID_RELOAD_CONFIG:
+         configret = 0;
+         load_config( 1 );
+
+         if ( configret )
+         {
+            log_error(LOG_LEVEL_ERROR, "load_config encountered a problem!  You should probably restart IJB.");
+         }
+         else
+         {
+            log_error(LOG_LEVEL_INFO, "Configuration has been reloaded.");
+         }
+         break;
+
+      case ID_TOOLS_EDITJUNKBUSTER:
+         EditFile(configfile);
+         break;
+
+      case ID_TOOLS_EDITBLOCKERS:
+         EditFile(blockfile);
+         break;
+
+      case ID_TOOLS_EDITCOOKIES:
+         EditFile(cookiefile);
+         break;
+
+      case ID_TOOLS_EDITFORWARD:
+         EditFile(forwardfile);
+         break;
+
+#ifdef ACL_FILES
+      case ID_TOOLS_EDITACLS:
+         EditFile(aclfile);
+         break;
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+      case ID_TOOLS_EDITIMAGE:
+         EditFile(imagefile);
+         break;
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef PCRS
+      case ID_TOOLS_EDITPERLRE:
+         EditFile(re_filterfile);
+         break;
+#endif
+
+#ifdef KILLPOPUPS
+      case ID_TOOLS_EDITPOPUPS:
+         EditFile(popupfile);
+         break;
+#endif /* def KILLPOPUPS */
+
+#ifdef TRUST_FILES
+      case ID_TOOLS_EDITTRUST:
+         EditFile(trustfile);
+         break;
+#endif /* def TRUST_FILES */
+
+      case ID_NEW_BLOCKER:
+         ShowRulesDialog(g_hwndLogFrame);
+         break;
+
+      case ID_HELP_GPL:
+         ShellExecute(g_hwndLogFrame, "open", "gpl.html", NULL, NULL, SW_SHOWNORMAL);
+         break;
+
+      case ID_HELP_FAQ:
+         ShellExecute(g_hwndLogFrame, "open", "ijbfaq.html", NULL, NULL, SW_SHOWNORMAL);
+         break;
+
+      case ID_HELP_MANUAL:
+         ShellExecute(g_hwndLogFrame, "open", "ijbman.html", NULL, NULL, SW_SHOWNORMAL);
+         break;
+
+      case ID_HELP_STATUS:
+         ShellExecute(g_hwndLogFrame, "open", "Junkbuster Status.URL", NULL, NULL, SW_SHOWNORMAL);
+         break;
+
+      case ID_HELP_ABOUTJUNKBUSTER:
+         MessageBox(g_hwndLogFrame, win32_blurb, "Junkbuster Information", MB_OK);
+         break;
+
+      default:
+         /* DO NOTHING */
+         break;
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnLogInitMenu
+ *
+ * Description :  Handler for WM_INITMENU messages.  Enable, disable,
+ *                check, and/or uncheck menu options as apropos.
+ *
+ * Parameters  :
+ *          1  :  hmenu = handle to menu to "make current"
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void OnLogInitMenu(HMENU hmenu)
+{
+   /* Only enable editors if there is a file to edit */
+   EnableMenuItem(hmenu, ID_TOOLS_EDITCOOKIES, MF_BYCOMMAND | (cookiefile ? MF_ENABLED : MF_GRAYED));
+   EnableMenuItem(hmenu, ID_TOOLS_EDITBLOCKERS, MF_BYCOMMAND | (blockfile ? MF_ENABLED : MF_GRAYED));
+   EnableMenuItem(hmenu, ID_TOOLS_EDITFORWARD, MF_BYCOMMAND | (forwardfile ? MF_ENABLED : MF_GRAYED));
+#ifdef ACL_FILES
+   EnableMenuItem(hmenu, ID_TOOLS_EDITACLS, MF_BYCOMMAND | (aclfile ? MF_ENABLED : MF_GRAYED));
+#endif /* def ACL_FILES */
+#ifdef USE_IMAGE_LIST
+   EnableMenuItem(hmenu, ID_TOOLS_EDITIMAGE, MF_BYCOMMAND | (imagefile ? MF_ENABLED : MF_GRAYED));
+#endif /* def USE_IMAGE_LIST */
+#ifdef KILLPOPUPS
+   EnableMenuItem(hmenu, ID_TOOLS_EDITPOPUPS, MF_BYCOMMAND | (popupfile ? MF_ENABLED : MF_GRAYED));
+#endif /* def KILLPOPUPS */
+#ifdef PCRS
+   EnableMenuItem(hmenu, ID_TOOLS_EDITPERLRE, MF_BYCOMMAND | (re_filterfile ? MF_ENABLED : MF_GRAYED));
+#endif
+#ifdef TRUST_FILES
+   EnableMenuItem(hmenu, ID_TOOLS_EDITTRUST, MF_BYCOMMAND | (trustfile ? MF_ENABLED : MF_GRAYED));
+#endif /* def TRUST_FILES */
+
+   /* Check/uncheck options */
+   CheckMenuItem(hmenu, ID_VIEW_LOGMESSAGES, MF_BYCOMMAND | (g_bLogMessages ? MF_CHECKED : MF_UNCHECKED));
+   CheckMenuItem(hmenu, ID_VIEW_MESSAGEHIGHLIGHTING, MF_BYCOMMAND | (g_bHighlightMessages ? MF_CHECKED : MF_UNCHECKED));
+   CheckMenuItem(hmenu, ID_VIEW_LIMITBUFFERSIZE, MF_BYCOMMAND | (g_bLimitBufferSize ? MF_CHECKED : MF_UNCHECKED));
+   CheckMenuItem(hmenu, ID_VIEW_ACTIVITYANIMATION, MF_BYCOMMAND | (g_bShowActivityAnimation ? MF_CHECKED : MF_UNCHECKED));
+#ifdef TOGGLE
+   /* by haroon - menu item for Enable toggle on/off */
+   CheckMenuItem(hmenu, ID_TOGGLE_IJB, MF_BYCOMMAND | (g_bToggleIJB ? MF_CHECKED : MF_UNCHECKED));
+#endif
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnLogTimer
+ *
+ * Description :  Handler for WM_TIMER messages.
+ *
+ * Parameters  :
+ *          1  :  nTimer = timer id (animation start/stop or clip buffer)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void OnLogTimer(int nTimer)
+{
+   switch (nTimer)
+   {
+      case TIMER_ANIM_ID:
+         TraySetIcon(g_hwndTray, 1, g_hiconAnim[g_nAnimFrame++ % ANIM_FRAMES]);
+         break;
+
+      case TIMER_ANIMSTOP_ID:
+         g_nAnimFrame = 0;
+         TraySetIcon(g_hwndTray, 1, g_hiconIdle);
+         KillTimer(g_hwndLogFrame, TIMER_ANIM_ID);
+         KillTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID);
+         break;
+
+      case TIMER_CLIPBUFFER_ID:
+      case TIMER_CLIPBUFFER_FORCE_ID:
+         LogClipBuffer();
+         g_bClipPending = FALSE;
+         KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID);
+         KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID);
+         break;
+
+      default:
+         /* DO NOTHING */
+         break;
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogRichEditProc
+ *
+ * Description :  Window subclass routine handles some events for the rich edit control.
+ *
+ * Parameters  :
+ *          1  :  hwnd = window handle of the rich edit control
+ *          2  :  uMsg = message number
+ *          3  :  wParam = first param for this message
+ *          4  :  lParam = next param for this message
+ *
+ * Returns     :  Appropriate M$ window message handler codes.
+ *
+ *********************************************************************/
+LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   switch (uMsg)
+   {
+      case WM_RBUTTONUP:
+      {
+         POINT pt;
+         pt.x = LOWORD(lParam);
+         pt.y = HIWORD(lParam);
+         ClientToScreen(hwnd, &pt);
+         OnLogRButtonUp(wParam, pt.x, pt.y);
+      }
+      return 0;
+   }
+   return CallWindowProc(g_fnLogBox, hwnd, uMsg, wParam, lParam);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  LogWindowProc
+ *
+ * Description :  Windows call back routine handles events on the log window.
+ *
+ * Parameters  :
+ *          1  :  hwnd = handle of the logging window
+ *          2  :  uMsg = message number
+ *          3  :  wParam = first param for this message
+ *          4  :  lParam = next param for this message
+ *
+ * Returns     :  Appropriate M$ window message handler codes.
+ *
+ *********************************************************************/
+LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   switch (uMsg)
+   {
+      case WM_CREATE:
+         return 0;
+
+      case WM_CLOSE:
+         /* This is the end - beautiful friend - the end */
+         DestroyWindow(g_hwndLogBox);
+         DestroyWindow(g_hwndLogFrame);
+         return 0;
+
+      case WM_DESTROY:
+         PostQuitMessage(0);
+         return 0;
+
+      case WM_SHOWWINDOW:
+      case WM_SIZE:
+         /* Resize the logging window to fit the new frame */
+         if (g_hwndLogBox)
+         {
+            RECT rc;
+            GetClientRect(g_hwndLogFrame, &rc);
+            SetWindowPos(g_hwndLogBox, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
+         }
+         return 0;
+
+      case WM_INITMENU:
+         OnLogInitMenu((HMENU) wParam);
+         return 0;
+
+      case WM_TIMER:
+         OnLogTimer(wParam);
+         return 0;
+
+      case WM_COMMAND:
+         OnLogCommand(LOWORD(wParam));
+         return 0;
+
+      case WM_SYSCOMMAND:
+         switch (wParam)
+         {
+            case SC_CLOSE:
+               if (g_bCloseHidesWindow)
+               {
+                  ShowLogWindow(FALSE);
+                  return 0;
+               }
+               break;
+            case SC_MINIMIZE:
+               ShowLogWindow(FALSE);
+               return 0;
+         }
+         break;
+   }
+
+   return DefWindowProc(hwnd, uMsg, wParam, lParam);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32log.h b/w32log.h
new file mode 100644 (file)
index 0000000..85b4375
--- /dev/null
+++ b/w32log.h
@@ -0,0 +1,96 @@
+#ifndef _W32LOG_H
+#define _W32LOG_H
+#define W32LOG_H_VERSION "$Id: w32log.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32log.h,v $
+ *
+ * Purpose     :  Functions for creating and destroying the log window,
+ *                ouputting strings, processing messages and so on.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32log.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern HWND g_hwndLogFrame;
+
+/* Indicates whether task bar shows activity animation */
+extern BOOL g_bShowActivityAnimation;
+
+/* Indicates if the log window appears on the task bar */
+extern BOOL g_bShowOnTaskBar;
+
+/* Indicates whether closing the log window really just hides it */
+extern BOOL g_bCloseHidesWindow;
+
+/* Indicates if messages are logged at all */
+extern BOOL g_bLogMessages;
+
+/* Indicates whether log messages are highlighted */
+extern BOOL g_bHighlightMessages;
+
+/* Indicates if buffer is limited in size */
+extern BOOL g_bLimitBufferSize;
+
+/* Maximum number of lines allowed in buffer when limited */
+extern int g_nMaxBufferLines;
+
+/* Font to use */
+extern char g_szFontFaceName[255];
+
+/* Size of font to use */
+extern int g_nFontSize;
+
+
+extern int LogPutString(const char *pszText);
+extern BOOL InitLogWindow(void);
+extern void TermLogWindow(void);
+extern void ShowLogWindow(BOOL bShow);
+extern void LogShowActivity(void);
+
+/* Revision control strings from this header and associated .c file */
+extern const char w32log_rcs[];
+extern const char w32log_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _W32LOG_H */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32res.h b/w32res.h
new file mode 100644 (file)
index 0000000..7fb57b6
--- /dev/null
+++ b/w32res.h
@@ -0,0 +1,130 @@
+#ifndef _W32RES_H
+#define _W32RES_H
+#define W32RES_H_VERSION "$Id: w32res.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32res.h,v $
+ *
+ * Purpose     :  Identifiers for Windows GUI resources.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32res.h,v $
+ *
+ *********************************************************************/
+
+#define IDS_NEW_BLOCKER                   1
+
+#define ID_NEW_BLOCKER                    100
+#define IDR_TRAYMENU                      101
+#define IDI_IDLE                          102
+#define IDR_LOGVIEW                       103
+#define IDR_ACCELERATOR                   104
+#define IDR_POPUP_SELECTION               105
+#define IDD_RULES                         106
+#define IDI_DENYRULE                      107
+#define IDI_ALLOWRULE                     108
+
+#define IDI_JUNKBUSTER                    200
+#define IDI_JUNKBUSTER1                   201
+#define IDI_JUNKBUSTER2                   202
+#define IDI_JUNKBUSTER3                   203
+#define IDI_JUNKBUSTER4                   204
+#define IDI_JUNKBUSTER5                   205
+#define IDI_JUNKBUSTER6                   206
+#define IDI_JUNKBUSTER7                   207
+#define IDI_JUNKBUSTER8                   208
+
+#define IDC_NEW                           300
+#define IDC_ACTION                        301
+#define IDC_RULES                         302
+#define IDC_CREATE                        303
+#define IDC_MOVEUP                        304
+#define IDC_MOVEDOWN                      305
+#define IDC_DELETE                        306
+#define IDC_SAVE                          307
+
+#define ID_SHOWWINDOW                     4000
+#define ID_HELP_ABOUTJUNKBUSTER           4001
+#define ID_FILE_EXIT                      4002
+#define ID_VIEW_CLEARLOG                  4003
+#define ID_VIEW_LOGMESSAGES               4004
+#define ID_VIEW_MESSAGEHIGHLIGHTING       4005
+#define ID_VIEW_LIMITBUFFERSIZE           4006
+#define ID_VIEW_ACTIVITYANIMATION         4007
+#define ID_HELP_FAQ                       4008
+#define ID_HELP_MANUAL                    4009
+#define ID_HELP_GPL                       4010
+#define ID_HELP_STATUS                    4011
+#ifdef TOGGLE
+#define ID_TOGGLE_IJB                     4012
+#endif
+#define ID_RELOAD_CONFIG                  4013
+
+/* Break these out so they are easier to extend, but keep consecutive */
+#define ID_TOOLS_EDITJUNKBUSTER           5000
+#define ID_TOOLS_EDITBLOCKERS             5001
+#define ID_TOOLS_EDITCOOKIES              5002
+#define ID_TOOLS_EDITFORWARD              5003
+
+#ifdef ACL_FILES
+#define ID_TOOLS_EDITACLS                 5005
+#endif /* def ACL_FILES */
+
+#ifdef USE_IMAGE_LIST
+#define ID_TOOLS_EDITIMAGE                5006
+#endif /* def USE_IMAGE_LIST */
+
+#ifdef KILLPOPUPS
+#define ID_TOOLS_EDITPOPUPS               5007
+#endif /* def KILLPOPUPS */
+
+#ifdef PCRS
+#define ID_TOOLS_EDITPERLRE               5008
+#endif /* def PCRS */
+
+#ifdef TRUST_FILES
+#define ID_TOOLS_EDITTRUST                5004
+#endif /* def TRUST_FILES */
+
+/*
+ * The following symbols are declared in <afxres.h> in VC++.
+ * However, mingw32 doesn't have that header.  Let's 
+ * always declare them here, for consistency.
+ * These are the VC++ values.
+ */
+#define IDC_STATIC      (-1)
+#define ID_EDIT_COPY  30000
+
+
+#endif /* ndef _W32RES_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32rulesdlg.c b/w32rulesdlg.c
new file mode 100644 (file)
index 0000000..845995b
--- /dev/null
@@ -0,0 +1,532 @@
+const char w32rulesdlg_rcs[] = "$Id: w32rulesdlg.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32rulesdlg.c,v $
+ *
+ * Purpose     :  A dialog to allow GUI editing of the rules.
+ *                Unfinished.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32rulesdlg.c,v $
+ *
+ *********************************************************************/
+\f
+#include "config.h"
+
+#include <stdio.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "w32res.h"
+#include "w32rulesdlg.h"
+#include "win32.h"
+
+#ifdef __MINGW32__
+#include "cygwin.h"
+#endif
+
+const char w32rulesdlg_h_rcs[] = W32RULESDLG_H_VERSION;
+
+const int nSmallIconWidth = 16;
+const int nSmallIconHeight = 16;
+
+static BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static HIMAGELIST g_hImageList = NULL;
+static char *g_pszDefaultRule;
+static BOOL g_bDirty = FALSE;
+
+
+
+/*********************************************************************
+ *
+ * Function    :  ShowRulesDialog
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndParent = (what?)
+ *
+ * Returns     :  (Please fill me in!)
+ *
+ *********************************************************************/
+int ShowRulesDialog(HWND hwndParent)
+{
+   DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_RULES), hwndParent, DialogProc);
+   return TRUE;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  SetDefaultRule
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  pszRule = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void SetDefaultRule(const char *pszRule)
+{
+   if (pszRule == NULL)
+   {
+      if (g_pszDefaultRule)
+      {
+         free(g_pszDefaultRule);
+         g_pszDefaultRule = NULL;
+      }
+   }
+   else
+   {
+      g_pszDefaultRule = strdup(pszRule);
+   }
+
+}
+
+
+#define IMAGE_ALLOW 0
+#define IMAGE_DENY  1
+
+/*********************************************************************
+ *
+ * Function    :  InsertRule
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndListView = (what?)
+ *          2  :  pszRule = (what?)
+ *          3  :  bAllow = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void InsertRule(HWND hwndListView, const char *pszRule, BOOL bAllow)
+{
+   LVITEM item;
+   item.mask = LVIF_TEXT | LVIF_IMAGE;
+   item.pszText = (char *)pszRule;
+   item.iItem = ListView_GetItemCount(hwndListView) + 1;
+   item.iSubItem = 0;
+   item.iImage = bAllow ? IMAGE_ALLOW : IMAGE_DENY;
+   ListView_InsertItem(hwndListView, &item);
+   /* TODO add subitem for whether the rule is always or never */
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  SetDirty
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  bDirty = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void SetDirty(BOOL bDirty)
+{
+   g_bDirty = bDirty;
+   /* TODO Change some values */
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnInitDialog
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnInitDialog(HWND hwndDlg)
+{
+   LVCOLUMN aCols[2];
+   HWND hwndListView;
+   RECT rcListView;
+   int cx;
+
+   if (g_hImageList == NULL)
+   {
+      /* Create image list and add icons */
+      HICON hIconDeny = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_DENYRULE), IMAGE_ICON, nSmallIconWidth, nSmallIconHeight, 0);
+      HICON hIconAllow = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_ALLOWRULE), IMAGE_ICON, nSmallIconWidth, nSmallIconHeight, 0);
+      g_hImageList = ImageList_Create(nSmallIconWidth, nSmallIconHeight, ILC_COLOR | ILC_MASK, 0, 10);
+      ImageList_AddIcon(g_hImageList, hIconAllow);
+      ImageList_AddIcon(g_hImageList, hIconDeny);
+   }
+
+   /* Set the default rule value if there is one */
+   if (g_pszDefaultRule)
+   {
+      SetDlgItemText(hwndDlg, IDC_NEW, g_pszDefaultRule);
+      SetDefaultRule(NULL);
+   }
+
+   /* Initialise the list view */
+   hwndListView = GetDlgItem(hwndDlg, IDC_RULES);
+   ListView_SetImageList(hwndListView, g_hImageList, LVSIL_SMALL);
+   GetClientRect(hwndListView, &rcListView);
+   cx = rcListView.right - rcListView.left;
+   aCols[0].mask = LVCF_TEXT | LVCF_WIDTH;
+   aCols[0].pszText = "Rule";
+   aCols[0].cx = (70 * cx) / 100;
+   aCols[1].mask = LVCF_TEXT | LVCF_WIDTH;
+   aCols[1].pszText = "Applies when";
+   aCols[1].cx = cx - aCols[0].cx;
+   ListView_InsertColumn(hwndListView, 0, &aCols[0]);
+   ListView_InsertColumn(hwndListView, 1, &aCols[1]);
+
+   /* Read and add rules to the list */
+   /* TODO */
+   InsertRule(hwndListView, "Test rule 1", TRUE);
+   InsertRule(hwndListView, "Test rule 2", TRUE);
+   InsertRule(hwndListView, "Test rule 3", FALSE);
+   InsertRule(hwndListView, "Test rule 4", FALSE);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  GetFirstSelectedItem
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  (Please fill me in!)
+ *
+ *********************************************************************/
+static int GetFirstSelectedItem(HWND hwndDlg)
+{
+   /* Check for selected items */
+   HWND hwndListView = GetDlgItem(hwndDlg, IDC_RULES);
+   int nItem = -1;
+   do
+   {
+      nItem = ListView_GetNextItem(hwndListView, nItem, LVNI_SELECTED);
+      if (nItem >= 0)
+      {
+         return nItem;
+      }
+   } while (nItem >= 0);
+   return -1;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnRulesItemChanged
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnRulesItemChanged(HWND hwndDlg)
+{
+   int nItem = GetFirstSelectedItem(hwndDlg);
+   HWND hwndListView = GetDlgItem(hwndDlg, IDC_RULES);
+   int nItems = ListView_GetItemCount(hwndListView);
+   BOOL bHaveSelection = (nItem >= 0) ? TRUE : FALSE;
+   BOOL bMoveUp = (bHaveSelection && nItem > 0) ? TRUE : FALSE;
+   BOOL bMoveDown = (bHaveSelection && nItem < nItems - 1) ? TRUE : FALSE;
+
+   /* Enable/disable buttons */
+   EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), bHaveSelection);
+   EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), bMoveUp);
+   EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), bMoveDown);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  MoveRules
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *          2  :  bMoveUp = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void MoveRules(HWND hwndDlg, BOOL bMoveUp)
+{
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnMoveRuleUpClick
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnMoveRuleUpClick(HWND hwndDlg)
+{
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnMoveRuleDownClick
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnMoveRuleDownClick(HWND hwndDlg)
+{
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnCreateRuleClick
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnCreateRuleClick(HWND hwndDlg)
+{
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnDeleteRuleClick
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnDeleteRuleClick(HWND hwndDlg)
+{
+   /* Get selection and remove it */
+   int nItem = GetFirstSelectedItem(hwndDlg);
+   if (nItem >= 0)
+   {
+      LVITEM item;
+      HWND hwndListView = GetDlgItem(hwndDlg, IDC_RULES);
+      item.mask = LVIF_PARAM;
+      item.iItem = nItem;
+      item.iSubItem = 0;
+      ListView_GetItem(hwndListView, &item);
+      /* TODO erase data stored with item */
+      ListView_DeleteItem(hwndListView, nItem);
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnCommand
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *          2  :  nCommand = (what?)
+ *          3  :  nNotifyCode = (what?)
+ *          4  :  hwndItem = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnCommand(HWND hwndDlg, int nCommand, int nNotifyCode, HWND hwndItem)
+{
+   switch (nCommand)
+   {
+      case IDCANCEL:
+      case IDC_SAVE:
+         EndDialog(hwndDlg, IDOK);
+         break;
+      case IDC_CREATE:
+         if (nNotifyCode == BN_CLICKED)
+         {
+            OnCreateRuleClick(hwndDlg);
+         }
+         break;
+      case IDC_DELETE:
+         if (nNotifyCode == BN_CLICKED)
+         {
+            OnDeleteRuleClick(hwndDlg);
+         }
+         break;
+      case IDC_MOVEUP:
+         if (nNotifyCode == BN_CLICKED)
+         {
+            OnMoveRuleUpClick(hwndDlg);
+         }
+         break;
+      case IDC_MOVEDOWN:
+         if (nNotifyCode == BN_CLICKED)
+         {
+            OnMoveRuleDownClick(hwndDlg);
+         }
+         break;
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnNotify
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *          2  :  nIdCtrl = (what?)
+ *          3  :  pnmh = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnNotify(HWND hwndDlg, int nIdCtrl, LPNMHDR pnmh)
+{
+   switch (nIdCtrl)
+   {
+      case IDC_RULES:
+         switch (pnmh->code)
+         {
+            case LVN_ITEMCHANGED:
+               OnRulesItemChanged(hwndDlg);
+               break;
+         }
+         break;
+   }
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  OnDestroy
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void OnDestroy(HWND hwndDlg)
+{
+   /* TODO any destruction cleanup */
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  DialogProc
+ *
+ * Description :  (Please fill me in!)
+ *
+ * Parameters  :
+ *          1  :  hwndDlg = (what?)
+ *          2  :  uMsg = (what?)
+ *          3  :  wParam = (what?)
+ *          4  :  lParam = (what?)
+ *
+ * Returns     :  (Please fill me in!)
+ *
+ *********************************************************************/
+static BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   switch (uMsg)
+   {
+      case WM_INITDIALOG:
+         OnInitDialog(hwndDlg);
+         return TRUE;
+
+      case WM_DESTROY:
+         OnDestroy(hwndDlg);
+         return TRUE;
+
+      case WM_COMMAND:
+         OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND) lParam);
+         break;
+
+      case WM_NOTIFY:
+         OnNotify(hwndDlg, (int) wParam, (LPNMHDR) lParam);
+         break;
+   }
+   return FALSE;
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32rulesdlg.h b/w32rulesdlg.h
new file mode 100644 (file)
index 0000000..991a8bd
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _W32RULESDLG_H
+#define _W32RULESDLG_H
+#define W32RULESDLG_H_VERSION "$Id: w32rulesdlg.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32rulesdlg.h,v $
+ *
+ * Purpose     :  A dialog to allow GUI editing of the rules.
+ *                Unfinished.
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32rulesdlg.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int ShowRulesDialog(HWND hwndParent);
+extern void SetDefaultRule(const char *pszRule);
+
+/* Revision control strings from this header and associated .c file */
+extern const char w32rulesdlg_rcs[];
+extern const char w32rulesdlg_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _W32RULESDLG_H */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32taskbar.c b/w32taskbar.c
new file mode 100644 (file)
index 0000000..62f269d
--- /dev/null
@@ -0,0 +1,262 @@
+const char w32taskbar_rcs[] = "$Id: w32taskbar.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32taskbar.c,v $
+ *
+ * Purpose     :  Functions for creating, setting and destroying the
+ *                workspace tray icon
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32taskbar.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "w32taskbar.h"
+#include "w32res.h"
+#include "w32log.h"
+
+const char w32taskbar_h_rcs[] = W32TASKBAR_H_VERSION;
+
+#define WM_TRAYMSG WM_USER+1
+
+static HMENU g_hmenuTray;
+static HWND g_hwndTrayX;
+
+static LRESULT CALLBACK TrayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+
+/*********************************************************************
+ *
+ * Function    :  CreateTrayWindow
+ *
+ * Description :  Creates and returns the invisible window responsible for processing tray messages.
+ *
+ * Parameters  :
+ *          1  :  hInstance = instance handle of this application
+ *
+ * Returns     :  Handle of the systray window.
+ *
+ *********************************************************************/
+HWND CreateTrayWindow(HINSTANCE hInstance)
+{
+   WNDCLASS wc;
+   static const char *szWndName = "JunkbusterTrayWindow";
+
+   wc.style          = 0;
+   wc.lpfnWndProc    = TrayProc;
+   wc.cbClsExtra     = 0;
+   wc.cbWndExtra     = 0;
+   wc.hInstance      = hInstance;
+   wc.hIcon          = 0;
+   wc.hCursor        = 0;
+   wc.hbrBackground  = 0;
+   wc.lpszMenuName   = 0;
+   wc.lpszClassName  = szWndName;
+
+   RegisterClass(&wc);
+
+   g_hwndTrayX = CreateWindow(szWndName, szWndName,
+      WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+      CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
+
+   ShowWindow(g_hwndTrayX, SW_HIDE);
+   UpdateWindow(g_hwndTrayX);
+
+   g_hmenuTray = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
+
+   return g_hwndTrayX;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  TraySetIcon
+ *
+ * Description :  Sets the tray icon to the specified shape.
+ *
+ * Parameters  :
+ *          1  :  hwnd = handle of the systray window
+ *          2  :  uID = user message number to notify systray window
+ *          3  :  hicon = set the current icon to this handle
+ *
+ * Returns     :  Same value as `Shell_NotifyIcon'.
+ *
+ *********************************************************************/
+BOOL TraySetIcon(HWND hwnd, UINT uID, HICON hicon)
+{
+   NOTIFYICONDATA nid;
+
+   memset(&nid, 0, sizeof(nid));
+
+   nid.cbSize = sizeof(nid);
+   nid.hWnd = hwnd;
+   nid.uID = uID;
+   nid.uFlags = NIF_ICON;
+   nid.uCallbackMessage = 0;
+   nid.hIcon = hicon;
+
+   return( Shell_NotifyIcon(NIM_MODIFY, &nid) );
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  TrayAddIcon
+ *
+ * Description :  Adds a tray icon.
+ *
+ * Parameters  :
+ *          1  :  hwnd = handle of the systray window
+ *          2  :  uID = user message number to notify systray window
+ *          3  :  hicon = handle of icon to add to systray window
+ *          4  :  pszToolTip = tool tip when mouse hovers over systray window
+ *
+ * Returns     :  Same as `Shell_NotifyIcon'.
+ *
+ *********************************************************************/
+BOOL TrayAddIcon(HWND hwnd, UINT uID, HICON hicon, const char *pszToolTip)
+{
+   NOTIFYICONDATA nid;
+
+   memset(&nid, 0, sizeof(nid));
+
+   nid.cbSize = sizeof(nid);
+   nid.hWnd = hwnd;
+   nid.uID = uID;
+   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
+   nid.uCallbackMessage = WM_TRAYMSG;
+   nid.hIcon = hicon;
+
+   if (pszToolTip)
+   {
+      strcpy(nid.szTip, pszToolTip);
+   }
+
+   return( Shell_NotifyIcon(NIM_ADD, &nid) );
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  TrayDeleteIcon
+ *
+ * Description :  Deletes a tray icon.
+ *
+ * Parameters  :
+ *          1  :  hwnd = handle of the systray window
+ *          2  :  uID = user message number to notify systray window
+ *
+ * Returns     :  Same as `Shell_NotifyIcon'.
+ *
+ *********************************************************************/
+BOOL TrayDeleteIcon(HWND hwnd, UINT uID)
+{
+   NOTIFYICONDATA nid;
+
+   memset(&nid, 0, sizeof(nid));
+
+   nid.cbSize = sizeof(nid);
+   nid.hWnd = hwnd;
+   nid.uID = uID;
+
+   return( Shell_NotifyIcon(NIM_DELETE, &nid) );
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  TrayProc
+ *
+ * Description :  Call back procedure processes tray messages.
+ *
+ * Parameters  :
+ *          1  :  hwnd = handle of the systray window
+ *          2  :  msg = message number
+ *          3  :  wParam = first param for this message
+ *          4  :  lParam = next param for this message
+ *
+ * Returns     :  Appropriate M$ window message handler codes.
+ *
+ *********************************************************************/
+LRESULT CALLBACK TrayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+   switch (msg)
+   {
+      case WM_CREATE:
+         return 0;
+
+      case WM_CLOSE:
+         PostQuitMessage(0);
+         return 0;
+
+      case WM_TRAYMSG:
+      {
+         UINT uID = (UINT) wParam;
+         UINT uMouseMsg = (UINT) lParam;
+
+         if (uMouseMsg == WM_RBUTTONDOWN)
+         {
+            POINT pt;
+            HMENU hmenu = GetSubMenu(g_hmenuTray,0);
+            GetCursorPos(&pt);
+            SetForegroundWindow(g_hwndLogFrame);
+            TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, g_hwndLogFrame, NULL);
+            PostMessage(g_hwndLogFrame, WM_NULL, 0, 0 ) ;
+         }
+         else if (uMouseMsg == WM_LBUTTONDBLCLK)
+         {
+            ShowLogWindow(TRUE);
+         }
+      }
+      return 0;
+
+      default:
+         /* DO NOTHING */
+         break;
+   }
+
+   return DefWindowProc(hwnd, msg, wParam, lParam);
+
+}
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/w32taskbar.h b/w32taskbar.h
new file mode 100644 (file)
index 0000000..9ba21fb
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _W32TASKBAR_H
+#define _W32TASKBAR_H
+#define W32TASKBAR_H_VERSION "$Id: w32taskbar.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/w32taskbar.h,v $
+ *
+ * Purpose     :  Functions for creating, setting and destroying the
+ *                workspace tray icon
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: w32taskbar.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern HWND CreateTrayWindow(HINSTANCE hInstance);
+extern BOOL TrayAddIcon(HWND hwnd, UINT uID, HICON hicon, const char *pszToolTip);
+extern BOOL TraySetIcon(HWND hwnd, UINT uID, HICON hicon);
+extern BOOL TrayDeleteIcon(HWND hwnd, UINT uID);
+
+/* Revision control strings from this header and associated .c file */
+extern const char w32taskbar_rcs[];
+extern const char w32taskbar_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _W32TASKBAR_H */
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/win32.c b/win32.c
new file mode 100644 (file)
index 0000000..2252dc1
--- /dev/null
+++ b/win32.c
@@ -0,0 +1,273 @@
+const char win32_rcs[] = "$Id: win32.c,v 1.1 2001/05/13 21:57:07 administrator Exp $";
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/win32.c,v $
+ *
+ * Purpose     :  Win32 User Interface initialization and message loop
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: win32.c,v $
+ *
+ *********************************************************************/
+\f
+
+#include "config.h"
+
+#ifdef _WIN32
+
+#include <stdio.h>
+
+#include "project.h"
+#include "jcc.h"
+
+/* Uncomment this if you want to build Win32 as a console app */
+/* #define _WIN_CONSOLE */
+
+#include <windows.h>
+
+#include <stdarg.h>
+#include <process.h>
+
+#include "win32.h"
+
+const char win32_h_rcs[] = WIN32_H_VERSION;
+
+const char win32_blurb[] =
+"Internet Junkbuster Proxy(TM) Version " VERSION " for Windows is Copyright (C) 1997-8\n"
+"by Junkbusters Corp.  This is free software; it may be used and copied under\n"
+"the GNU General Public License: http://www.gnu.org/copyleft/gpl.html .\n"
+"This program comes with ABSOLUTELY NO WARRANTY OF ANY KIND.\n"
+"\n"
+"For information about how to to configure the proxy and your browser, see\n"
+"        " REDIRECT_URL "win\n"
+"\n"
+"The Internet Junkbuster Proxy(TM) is running and ready to serve!\n"
+"";
+
+#ifdef _WIN_CONSOLE
+
+int hideConsole     = 0;
+
+#else
+
+HINSTANCE g_hInstance;
+int g_nCmdShow;
+
+static void  __cdecl UserInterfaceThread(void *);
+
+#endif
+
+
+/*********************************************************************
+ *
+ * Function    :  WinMain
+ *
+ * Description :  M$ Windows "main" routine:
+ *                parse the `lpCmdLine' param into main's argc and argv variables,
+ *                start the user interface thread (for the systray window), and
+ *                call main (i.e. patch execution into normal IJB startup).
+ *
+ * Parameters  :
+ *          1  :  hInstance = instance handle of this IJB execution
+ *          2  :  hPrevInstance = instance handle of previous IJB execution
+ *          3  :  lpCmdLine = command line string which started IJB
+ *          4  :  nCmdShow = window show value (MIN, MAX, NORMAL, etc...)
+ *
+ * Returns     :  `main' never returns, so WinMain will also never return.
+ *
+ *********************************************************************/
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+   int argc = 0;
+   int i;
+   int res;
+   char **argv = NULL;
+   char *pszArgs = NULL;
+   char *pszLastTok;
+   char szModule[MAX_PATH+1];
+#ifndef _WIN_CONSOLE
+   HANDLE hInitCompleteEvent = NULL;
+#endif
+
+   /* Split command line into arguments */
+   pszArgs = (char *)malloc(strlen(lpCmdLine) + 1);
+   strcpy(pszArgs, lpCmdLine);
+
+   GetModuleFileName(hInstance, szModule, MAX_PATH);
+
+   /* Count number of spaces */
+   argc = 1;
+   if (strlen(pszArgs) > 0)
+   {
+      pszLastTok = pszArgs;
+      do
+      {
+         argc++;
+         pszLastTok = strchr(pszLastTok+1, ' ');
+      } while (pszLastTok);
+   }
+
+   /* Allocate array of strings */
+   argv = (char **)malloc(sizeof(char *) * argc);
+
+   /* step through command line replacing spaces with zeros, initialise array */
+   argv[0] = szModule;
+   i = 1;
+   pszLastTok = pszArgs;
+   do
+   {
+      argv[i] = pszLastTok;
+      pszLastTok = strchr(pszLastTok+1, ' ');
+      if (pszLastTok)
+      {
+         while (*pszLastTok != '\0' && *pszLastTok == ' ')
+         {
+            *pszLastTok = '\0';
+            pszLastTok++;
+         }
+      }
+      i++;
+   } while (pszLastTok && *pszLastTok != '\0');
+
+#ifndef _WIN_CONSOLE
+   /* Create a user-interface thread and wait for it to initialise */
+   hInitCompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+   g_hInstance = hInstance;
+   g_nCmdShow = nCmdShow;
+   _beginthread(UserInterfaceThread, 0, &hInitCompleteEvent);
+   WaitForSingleObject(hInitCompleteEvent, INFINITE);
+   DeleteObject(hInitCompleteEvent);
+#endif
+
+#ifdef __MINGW32__
+   res = _main( argc, argv );
+#else
+   res = main( argc, argv );
+#endif
+
+   /* Cleanup */
+   free(argv);
+   free(pszArgs);
+
+   return res;
+
+}
+
+#endif
+
+/*********************************************************************
+ *
+ * Function    :  InitWin32
+ *
+ * Description :  Initialise windows, setting up the console or windows as appropriate.
+ *
+ * Parameters  :  None
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void InitWin32(void)
+{
+   WORD wVersionRequested;
+   WSADATA wsaData;
+
+#ifdef _WIN_CONSOLE
+   SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
+   if (hideConsole)
+   {
+      FreeConsole();
+   }
+#endif
+   wVersionRequested = MAKEWORD(2, 0);
+   if (WSAStartup(wVersionRequested, &wsaData) != 0)
+   {
+#ifndef _WIN_CONSOLE
+      MessageBox(NULL, "Cannot initialize WinSock library", "Internet JunkBuster Error", 
+         MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
+#endif
+      exit(1);
+   }
+
+}
+
+
+#ifndef _WIN_CONSOLE
+#include <signal.h>
+#include <assert.h>
+
+#include "win32.h"
+#include "w32log.h"
+
+
+/*********************************************************************
+ *
+ * Function    :  UserInterfaceThread
+ *
+ * Description :  User interface thread.  WinMain will wait for us to set
+ *                the hInitCompleteEvent before patching over to `main'.
+ *                This ensures the systray window is active before beginning
+ *                IJB operations.
+ *
+ * Parameters  :
+ *          1  :  pData = pointer to `hInitCompleteEvent'.
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void __cdecl UserInterfaceThread(void *pData)
+{
+   MSG msg;
+   HANDLE hInitCompleteEvent = *((HANDLE *) pData);
+
+   /* Initialise */
+   InitLogWindow();
+   SetEvent(hInitCompleteEvent);
+
+   /* Enter a message processing loop */
+   while (GetMessage(&msg, (HWND) NULL, 0, 0))
+   {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+   }
+
+   /* Cleanup */
+   TermLogWindow();
+
+   /* Time to die... */
+   raise(SIGINT);
+
+}
+
+
+#endif
+
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/win32.h b/win32.h
new file mode 100644 (file)
index 0000000..3011f47
--- /dev/null
+++ b/win32.h
@@ -0,0 +1,71 @@
+#ifndef _WIN32_H
+#define _WIN32_H
+#define WIN32_H_VERSION "$Id: win32.h,v 1.1 2001/05/13 21:57:07 administrator Exp $"
+/*********************************************************************
+ *
+ * File        :  $Source: /home/administrator/cvs/ijb/win32.h,v $
+ *
+ * Purpose     :  Win32 User Interface initialization and message loop
+ *
+ * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
+ *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *
+ *                Written by and Copyright (C) 1999 Adam Lock
+ *                <locka@iol.ie>
+ *
+ *                This program is free software; you can redistribute it 
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, 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.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log: win32.h,v $
+ *
+ *********************************************************************/
+\f
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char win32_blurb[];
+
+extern void InitWin32(void);
+
+#ifdef _WIN_CONSOLE
+extern int hideConsole;
+#endif /*def _WIN_CONSOLE */
+
+extern HINSTANCE g_hInstance;
+extern int g_nCmdShow;
+
+extern int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+
+/* Revision control strings from this header and associated .c file */
+extern const char win32_rcs[];
+extern const char win32_h_rcs[];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef _WIN32_H */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/