From 3e2d39ba87f341e17021a9233c3c4146a7b613e7 Mon Sep 17 00:00:00 2001
From: Dan Egnor <egnor@ofb.net>
Date: Sat, 9 Oct 1999 19:05:39 +0000
Subject: [PATCH] 0.90a

---
 COPYING           |   7 +
 Makefile.am       |  29 ++--
 Makefile.in       |  67 ++++++---
 adns.c            |   3 +-
 configure         | 273 +++++++++++++++++++++++++++++++++-
 configure.in      |  32 +++-
 foreign/HTEvent.h | 246 ++++++++++++++++++++++++++++++
 foreign/README    |  35 ++++-
 foreign/adns.h    |   8 +-
 glib.c            | 100 +++++++++++++
 oop-adns.h        |   2 +-
 oop-glib.h        |  25 ++++
 oop.h             |  14 +-
 select.c          |  16 +-
 sys.c             |  38 +++--
 test-oop.c        | 370 +++++++++++++++++++++++++++++++++++++++++++---
 www.c             | 185 +++++++++++++++++++++++
 17 files changed, 1357 insertions(+), 93 deletions(-)
 create mode 100644 foreign/HTEvent.h
 create mode 100644 glib.c
 create mode 100644 oop-glib.h
 create mode 100644 www.c

diff --git a/COPYING b/COPYING
index 223ede7..18a090c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,3 +1,10 @@
+   Most of liboop is covered under the Lesser GPL (below).
+
+** However, the contents of the "foreign" directory may have their own 
+** license agreements.  See foreign/README for details.
+
+-------------------------------------------------------------------------------
+
 		  GNU LESSER GENERAL PUBLIC LICENSE
 		       Version 2.1, February 1999
 
diff --git a/Makefile.am b/Makefile.am
index 098c87b..0d08d8e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,22 +7,33 @@
 # See the file COPYING for details.
 
 AUTOMAKE_OPTIONS = foreign 1.2
-lib_LTLIBRARIES = liboop.la liboop-adns.la
-noinst_PROGRAMS = test-oop test-adns
+lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la
+INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) -I$(top_srcdir)/foreign
 
-INCLUDES = -I$(srcdir)/foreign
+# versions updated as of 0.4
 
-liboop_la_LDFLAGS = -version-info 1:0:1 # version:revision:age
-liboop_la_SOURCES = sys.c select.c alloc.c
+liboop_la_LDFLAGS = -version-info 2:0:0 # version:revision:age
+liboop_la_SOURCES = sys.c select.c signal.c alloc.c
 
-liboop_adns_la_LDFLAGS = -version-info 0:0:0 # version:revision:age
+liboop_adns_la_LDFLAGS = -version-info 1:0:1
 liboop_adns_la_SOURCES = adns.c
 
-include_HEADERS = oop.h oop-adns.h
+liboop_glib_la_LDFLAGS = -version-info 0:0:0
+liboop_glib_la_SOURCES = glib.c
+
+liboop_www_la_LDFLAGS = -version-info 0:0:0
+liboop_www_la_SOURCES = www.c
+
+include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h
+
+noinst_PROGRAMS = test-oop
 
-LDADD = liboop-adns.la liboop.la -ladns
 test_oop_SOURCES = test-oop.c
-test_adns_SOURCES = test-adns.c
+test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) liboop.la
+
+dist-hook:
+	mkdir $(distdir)/foreign
+	cp -p $(srcdir)/foreign/README $(srcdir)/foreign/*.h $(distdir)/foreign
 
 release: dist
 	gzip -dc $(PACKAGE)-$(VERSION).tar.gz | bzip2 -9 \
diff --git a/Makefile.in b/Makefile.in
index 8f10a9b..b3a858c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -65,9 +65,12 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 host_alias = @host_alias@
 host_triplet = @host@
+ADNS_LIBS = @ADNS_LIBS@
 AS = @AS@
 CC = @CC@
 DLLTOOL = @DLLTOOL@
+GLIB_INCLUDES = @GLIB_INCLUDES@
+GLIB_LIBS = @GLIB_LIBS@
 LD = @LD@
 LIBTOOL = @LIBTOOL@
 LN_S = @LN_S@
@@ -75,27 +78,37 @@ MAKEINFO = @MAKEINFO@
 NM = @NM@
 OBJDUMP = @OBJDUMP@
 PACKAGE = @PACKAGE@
+PROG_GLIB_CONFIG = @PROG_GLIB_CONFIG@
 PROG_LDCONFIG = @PROG_LDCONFIG@
 RANLIB = @RANLIB@
 VERSION = @VERSION@
+WWW_INCLUDES = @WWW_INCLUDES@
+WWW_LIBS = @WWW_LIBS@
 
 AUTOMAKE_OPTIONS = foreign 1.2
-lib_LTLIBRARIES = liboop.la liboop-adns.la
-noinst_PROGRAMS = test-oop test-adns
+lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la
+INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) -I$(top_srcdir)/foreign
 
-INCLUDES = -I$(srcdir)/foreign
+# versions updated as of 0.4
 
-liboop_la_LDFLAGS = -version-info 1:0:1 # version:revision:age
-liboop_la_SOURCES = sys.c select.c alloc.c
+liboop_la_LDFLAGS = -version-info 2:0:0 # version:revision:age
+liboop_la_SOURCES = sys.c select.c signal.c alloc.c
 
-liboop_adns_la_LDFLAGS = -version-info 0:0:0 # version:revision:age
+liboop_adns_la_LDFLAGS = -version-info 1:0:1
 liboop_adns_la_SOURCES = adns.c
 
-include_HEADERS = oop.h oop-adns.h
+liboop_glib_la_LDFLAGS = -version-info 0:0:0
+liboop_glib_la_SOURCES = glib.c
+
+liboop_www_la_LDFLAGS = -version-info 0:0:0
+liboop_www_la_SOURCES = www.c
+
+include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h
+
+noinst_PROGRAMS = test-oop
 
-LDADD = liboop-adns.la liboop.la -ladns
 test_oop_SOURCES = test-oop.c
-test_adns_SOURCES = test-adns.c
+test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) liboop.la
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_CLEAN_FILES = 
@@ -107,19 +120,18 @@ CPPFLAGS = @CPPFLAGS@
 LDFLAGS = @LDFLAGS@
 LIBS = @LIBS@
 liboop_la_LIBADD = 
-liboop_la_OBJECTS =  sys.lo select.lo alloc.lo
+liboop_la_OBJECTS =  sys.lo select.lo signal.lo alloc.lo
 liboop_adns_la_LIBADD = 
 liboop_adns_la_OBJECTS =  adns.lo
+liboop_glib_la_LIBADD = 
+liboop_glib_la_OBJECTS =  glib.lo
+liboop_www_la_LIBADD = 
+liboop_www_la_OBJECTS =  www.lo
 PROGRAMS =  $(noinst_PROGRAMS)
 
 test_oop_OBJECTS =  test-oop.o
-test_oop_LDADD = $(LDADD)
-test_oop_DEPENDENCIES =  liboop-adns.la liboop.la
+test_oop_DEPENDENCIES =  liboop.la
 test_oop_LDFLAGS = 
-test_adns_OBJECTS =  test-adns.o
-test_adns_LDADD = $(LDADD)
-test_adns_DEPENDENCIES =  liboop-adns.la liboop.la
-test_adns_LDFLAGS = 
 CFLAGS = @CFLAGS@
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -136,10 +148,10 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
 TAR = tar
 GZIP_ENV = --best
-DEP_FILES =  .deps/adns.P .deps/alloc.P .deps/select.P .deps/sys.P \
-.deps/test-adns.P .deps/test-oop.P
-SOURCES = $(liboop_la_SOURCES) $(liboop_adns_la_SOURCES) $(test_oop_SOURCES) $(test_adns_SOURCES)
-OBJECTS = $(liboop_la_OBJECTS) $(liboop_adns_la_OBJECTS) $(test_oop_OBJECTS) $(test_adns_OBJECTS)
+DEP_FILES =  .deps/adns.P .deps/alloc.P .deps/glib.P .deps/select.P \
+.deps/signal.P .deps/sys.P .deps/test-oop.P .deps/www.P
+SOURCES = $(liboop_la_SOURCES) $(liboop_adns_la_SOURCES) $(liboop_glib_la_SOURCES) $(liboop_www_la_SOURCES) $(test_oop_SOURCES)
+OBJECTS = $(liboop_la_OBJECTS) $(liboop_adns_la_OBJECTS) $(liboop_glib_la_OBJECTS) $(liboop_www_la_OBJECTS) $(test_oop_OBJECTS)
 
 all: all-redirect
 .SUFFIXES:
@@ -222,6 +234,12 @@ liboop.la: $(liboop_la_OBJECTS) $(liboop_la_DEPENDENCIES)
 liboop-adns.la: $(liboop_adns_la_OBJECTS) $(liboop_adns_la_DEPENDENCIES)
 	$(LINK) -rpath $(libdir) $(liboop_adns_la_LDFLAGS) $(liboop_adns_la_OBJECTS) $(liboop_adns_la_LIBADD) $(LIBS)
 
+liboop-glib.la: $(liboop_glib_la_OBJECTS) $(liboop_glib_la_DEPENDENCIES)
+	$(LINK) -rpath $(libdir) $(liboop_glib_la_LDFLAGS) $(liboop_glib_la_OBJECTS) $(liboop_glib_la_LIBADD) $(LIBS)
+
+liboop-www.la: $(liboop_www_la_OBJECTS) $(liboop_www_la_DEPENDENCIES)
+	$(LINK) -rpath $(libdir) $(liboop_www_la_LDFLAGS) $(liboop_www_la_OBJECTS) $(liboop_www_la_LIBADD) $(LIBS)
+
 mostlyclean-noinstPROGRAMS:
 
 clean-noinstPROGRAMS:
@@ -235,10 +253,6 @@ test-oop: $(test_oop_OBJECTS) $(test_oop_DEPENDENCIES)
 	@rm -f test-oop
 	$(LINK) $(test_oop_LDFLAGS) $(test_oop_OBJECTS) $(test_oop_LDADD) $(LIBS)
 
-test-adns: $(test_adns_OBJECTS) $(test_adns_DEPENDENCIES)
-	@rm -f test-adns
-	$(LINK) $(test_adns_LDFLAGS) $(test_adns_OBJECTS) $(test_adns_LDADD) $(LIBS)
-
 install-includeHEADERS: $(include_HEADERS)
 	@$(NORMAL_INSTALL)
 	$(mkinstalldirs) $(DESTDIR)$(includedir)
@@ -336,6 +350,7 @@ distdir: $(DISTFILES)
 	    || cp -p $$d/$$file $(distdir)/$$file || :; \
 	  fi; \
 	done
+	$(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
 
 DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
 
@@ -454,6 +469,10 @@ mostlyclean-generic distclean-generic clean-generic \
 maintainer-clean-generic clean mostlyclean distclean maintainer-clean
 
 
+dist-hook:
+	mkdir $(distdir)/foreign
+	cp -p $(srcdir)/foreign/README $(srcdir)/foreign/*.h $(distdir)/foreign
+
 release: dist
 	gzip -dc $(PACKAGE)-$(VERSION).tar.gz | bzip2 -9 \
 	> $(PACKAGE)-$(VERSION).tar.bz2
diff --git a/adns.c b/adns.c
index 1dd7ff6..69ec6ae 100644
--- a/adns.c
+++ b/adns.c
@@ -54,6 +54,7 @@ void oop_adns_delete(oop_adapter_adns *a) {
 	assert(0 == a->count && 
 	       "deleting oop_adapter_adns with outstanding queries");
 	a->source->cancel_time(a->source,OOP_TIME_NOW,on_process,a);
+	oop_select_delete(a->select);
 	adns_finish(a->state);
 	oop_free(a);
 }
@@ -81,8 +82,8 @@ oop_adns_query *oop_adns_submit(
 void oop_adns_cancel(oop_adns_query *q) {
 	adns_cancel(q->query);
 	--q->a->count;
-	oop_free(q);
 	set_select(q->a);
+	oop_free(q);
 }
 
 static void set_select(oop_adapter_adns *a) {
diff --git a/configure b/configure
index c95a465..efd8ef5 100755
--- a/configure
+++ b/configure
@@ -701,7 +701,7 @@ fi
 
 PACKAGE=liboop
 
-VERSION=0.2
+VERSION=0.4
 
 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
   { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
@@ -1787,6 +1787,270 @@ fi
     ;;
 esac
 
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1792: 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 1807 "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:1813: \"$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 1824 "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:1830: \"$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 1841 "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:1847: \"$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
+
+for ac_hdr in poll.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1875: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1880 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1885: \"$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*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6
+echo "configure:1913: checking for adns_init in -ladns" >&5
+ac_lib_var=`echo adns'_'adns_init | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ladns  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1921 "configure"
+#include "confdefs.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 adns_init();
+
+int main() {
+adns_init()
+; return 0; }
+EOF
+if { (eval echo configure:1932: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  
+  cat >> confdefs.h <<\EOF
+#define HAVE_ADNS 1
+EOF
+
+  ADNS_LIBS="liboop-adns.la -ladns"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "glib-config", so it can be a program name with args.
+set dummy glib-config; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1962: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_PROG_GLIB_CONFIG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$PROG_GLIB_CONFIG"; then
+  ac_cv_prog_PROG_GLIB_CONFIG="$PROG_GLIB_CONFIG" # 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_PROG_GLIB_CONFIG="glib-config"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+PROG_GLIB_CONFIG="$ac_cv_prog_PROG_GLIB_CONFIG"
+if test -n "$PROG_GLIB_CONFIG"; then
+  echo "$ac_t""$PROG_GLIB_CONFIG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -n "$PROG_GLIB_CONFIG" ; then
+  GLIB_INCLUDES="`glib-config --cflags`"
+  GLIB_LIBS="liboop-glib.la `glib-config --libs`"
+  cat >> confdefs.h <<\EOF
+#define HAVE_GLIB 1
+EOF
+
+fi
+
+# the libwww RPM puts headers here:
+echo $ac_n "checking for HTEvent_setRegisterCallback in -lwwwcore""... $ac_c" 1>&6
+echo "configure:1999: checking for HTEvent_setRegisterCallback in -lwwwcore" >&5
+ac_lib_var=`echo wwwcore'_'HTEvent_setRegisterCallback | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lwwwcore -lwwwutils $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2007 "configure"
+#include "confdefs.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 HTEvent_setRegisterCallback();
+
+int main() {
+HTEvent_setRegisterCallback()
+; return 0; }
+EOF
+if { (eval echo configure:2018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  
+  cat >> confdefs.h <<\EOF
+#define HAVE_WWW 1
+EOF
+
+  # This is just a little unpleasant.
+  WWW_LIBS="liboop-www.la \
+  -lwwwapp -lwwwcache -lwwwcore -lwwwdir -lwwwfile -lwwwftp -lwwwgopher \
+  -lwwwhtml -lwwwhttp -lwwwinit -lwwwmime -lwwwmux -lwwwnews -lwwwstream \
+  -lwwwtelnet -lwwwtrans -lwwwutils -lwwwxml -lwwwzip -lxmlparse -lxmltok -lmd5"
+  WWW_INCLUDES="-I/usr/include/w3c-libwww"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+
+
+
 
 trap '' 1 2 15
 cat > confcache <<\EOF
@@ -1961,6 +2225,13 @@ s%@NM@%$NM%g
 s%@LN_S@%$LN_S%g
 s%@LIBTOOL@%$LIBTOOL%g
 s%@PROG_LDCONFIG@%$PROG_LDCONFIG%g
+s%@CPP@%$CPP%g
+s%@PROG_GLIB_CONFIG@%$PROG_GLIB_CONFIG%g
+s%@GLIB_INCLUDES@%$GLIB_INCLUDES%g
+s%@GLIB_LIBS@%$GLIB_LIBS%g
+s%@ADNS_LIBS@%$ADNS_LIBS%g
+s%@WWW_INCLUDES@%$WWW_INCLUDES%g
+s%@WWW_LIBS@%$WWW_LIBS%g
 
 CEOF
 EOF
diff --git a/configure.in b/configure.in
index a6058e1..6dc3b79 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_INIT(INSTALL)
-AM_INIT_AUTOMAKE(liboop,0.2)
+AM_INIT_AUTOMAKE(liboop,0.4)
 AC_CANONICAL_HOST
 
 dnl Use libtool for shared libraries
@@ -18,5 +18,35 @@ case "$host" in
     ;;
 esac
 
+AC_CHECK_HEADERS(poll.h)
+
+AC_CHECK_LIB(adns,adns_init,[
+  AC_DEFINE(HAVE_ADNS)
+  ADNS_LIBS="liboop-adns.la -ladns"
+])
+
+AC_CHECK_PROG(PROG_GLIB_CONFIG,glib-config,glib-config)
+if test -n "$PROG_GLIB_CONFIG" ; then
+  GLIB_INCLUDES="`glib-config --cflags`"
+  GLIB_LIBS="liboop-glib.la `glib-config --libs`"
+  AC_DEFINE(HAVE_GLIB)
+fi
+
+# the libwww RPM puts headers here:
+AC_CHECK_LIB(wwwcore,HTEvent_setRegisterCallback,[
+  AC_DEFINE(HAVE_WWW)
+  # This is just a little unpleasant.
+  WWW_LIBS="liboop-www.la \
+  -lwwwapp -lwwwcache -lwwwcore -lwwwdir -lwwwfile -lwwwftp -lwwwgopher \
+  -lwwwhtml -lwwwhttp -lwwwinit -lwwwmime -lwwwmux -lwwwnews -lwwwstream \
+  -lwwwtelnet -lwwwtrans -lwwwutils -lwwwxml -lwwwzip -lxmlparse -lxmltok -lmd5"
+  WWW_INCLUDES="-I/usr/include/w3c-libwww"
+],,-lwwwutils)
+
 AC_SUBST(PROG_LDCONFIG)
+AC_SUBST(GLIB_INCLUDES)
+AC_SUBST(GLIB_LIBS)
+AC_SUBST(ADNS_LIBS)
+AC_SUBST(WWW_INCLUDES)
+AC_SUBST(WWW_LIBS)
 AC_OUTPUT(Makefile)
diff --git a/foreign/HTEvent.h b/foreign/HTEvent.h
new file mode 100644
index 0000000..6550276
--- /dev/null
+++ b/foreign/HTEvent.h
@@ -0,0 +1,246 @@
+/*
+
+  					W3C Sample Code Library libwww Event Class
+
+
+!
+  The Event Class
+!
+*/
+
+/*
+**	(c) COPYRIGHT MIT 1995.
+**	Please first read the full copyright statement in the file COPYRIGH.
+*/
+
+/*
+
+The Event Class defines any event manager to be used by libwww for handling
+events. An event is not strictly defined as it is highly platform
+dependent and hence out of scope for the Library. If you are using the libwww
+pseudo threads on Unix then an event is when the&nbsp;select() system
+call returns a notification on&nbsp;a socket descriptor, but it may as well
+be an asynchronous event from the windows manager etc. If your application
+is not using anything but traditional blocking sockets then you do not need
+an event manager at all. In that case, libwww will block on any socket or
+system call until the process can proceed.
+
+The libwww interface to an event manager is very simple as it consists of
+registering a socket descriptor, the location in the
+program, and the current state when an operation (for example
+read) would block. When the event manager at a later point in
+time gets a notification that the socket has become ready, it can then call
+libwww with the state saved from the registration and libwww can continue.
+Second, libwww must be able to unregister a socket when it is not
+anymore in a state where it can block. Only in case the application
+wishes to use non-blocking sockets it should register methods for
+handling the registration process as described below.
+
+Note: The library core does not define any event manager
+- it is considered part of the application. The library comes with a
+default event manager which can be initiated
+using the function HTEventInit() in HTInit
+module
+
+This module is implemented by HTEvent.c, and it is
+a part of the W3C Sample Code Library.
+*/
+
+#ifndef HTEVENT_H
+#define HTEVENT_H
+#include "wwwsys.h"
+#ifdef IN_EVENT
+typedef struct _HTTimer HTTimer;
+#endif
+
+typedef enum _HTPriority {
+    HT_PRIORITY_INV = -1,
+    HT_PRIORITY_OFF = 0,
+    HT_PRIORITY_MIN = 1,
+    HT_PRIORITY_MAX = 20
+} HTPriority; 
+
+#define HTEVENT_INDEX 0x10
+typedef enum {
+#ifdef WWW_WIN_ASYNC
+    HTEvent_READ    = (0x001 | 0 << HTEVENT_INDEX),
+    HTEvent_WRITE   = (0x002 | 1 << HTEVENT_INDEX),
+    HTEvent_OOB     = (0x004 | 2 << HTEVENT_INDEX),
+    HTEvent_ACCEPT  = (0x008 | 3 << HTEVENT_INDEX),
+    HTEvent_CONNECT = (0x010 | 4 << HTEVENT_INDEX),
+    HTEvent_CLOSE   = (0x020 | 5 << HTEVENT_INDEX),
+    HTEvent_TYPES   = 6,	/* winsock has seperate events for all of these */
+#define HTEVENT_TYPES	6 /* use in constructing the fake event below */
+#else /* WWW_WIN_ASYNC */
+    HTEvent_READ    = (0x001 | 0 << HTEVENT_INDEX),
+    HTEvent_ACCEPT  = (0x002 | 0 << HTEVENT_INDEX),
+    HTEvent_CLOSE   = (0x004 | 0 << HTEVENT_INDEX),
+    HTEvent_WRITE   = (0x008 | 1 << HTEVENT_INDEX),
+    HTEvent_CONNECT = (0x010 | 1 << HTEVENT_INDEX),
+    HTEvent_OOB     = (0x020 | 2 << HTEVENT_INDEX),
+    HTEvent_TYPES   = 3,	/* only READ, WRITE, and OOB are real types */
+#define HTEVENT_TYPES	3 /* use in constructing the fake event below */
+#endif /* !WWW_WIN_ASYNC */
+    /*
+    **	fake events - these don't correspond to event manager events, but they
+    **	are usefull for communicating with the protocol modules
+    */
+    HTEvent_TIMEOUT = (0x040 | HTEVENT_TYPES << HTEVENT_INDEX),
+    HTEvent_BEGIN   = (0x000 | HTEVENT_TYPES << HTEVENT_INDEX),
+    HTEvent_END     = (0x080 | HTEVENT_TYPES << HTEVENT_INDEX),
+    HTEvent_FLUSH   = (0x100 | HTEVENT_TYPES << HTEVENT_INDEX),
+    HTEvent_RESET   = (0x200 | HTEVENT_TYPES << HTEVENT_INDEX),
+    HTEvent_ALL     = 0xFFFF
+} HTEventType;
+
+#define HTEvent_BITS(type) (type & 0xFFFF)
+#define HTEvent_INDEX(type) (type >> HTEVENT_INDEX)
+
+#define HT_EVENT_INITIALIZER \
+    {HTEvent_READ, "HTEvent_READ"}, \
+    {HTEvent_ACCEPT, "HTEvent_ACCEPT"}, \
+    {HTEvent_CLOSE, "HTEvent_CLOSE"}, \
+    {HTEvent_WRITE, "HTEvent_WRITE"}, \
+    {HTEvent_CONNECT, "HTEvent_CONNECT"}, \
+    {HTEvent_OOB, "HTEvent_OOB"}, \
+    {HTEvent_TIMEOUT, "HTEvent_TIMEOUT"}, \
+    {HTEvent_BEGIN, "HTEvent_BEGIN"}, \
+    {HTEvent_END, "HTEvent_END"}, \
+    {HTEvent_FLUSH, "HTEvent_FLUSH"}, \
+    {HTEvent_RESET, "HTEvent_RESET"}
+
+extern char * HTEvent_type2str(HTEventType type);
+
+/*
+.
+  Event Handlers
+.
+
+A location is a function that can be registered by the event manager
+and called at a later point in time in order to continue an operation. All
+locations must be of type &nbsp;HTEventCallback as defined here:
+*/
+
+typedef int HTEventCallback (SOCKET, void *, HTEventType);
+typedef struct _HTEvent HTEvent;
+
+/* Avoid circular include for HTReq->HTNet->HTHost: HTEvent blah */
+#include "HTReq.h"
+
+/*
+
+There are many default event handlers provided with the Library. For example,
+all the protocol modules such as the HTTP client module
+are implemented as event handlers. In stead of using blocking sockets, this
+allows a protocol module to register itself when performing an operation
+that would block. When the sockets becomes ready the handler is called with
+th socket in question, the request object, and the socket operation &nbsp;
+.
+  Registering and Unregistering Events
+.
+
+As mentioned above, the only interface libwww requires from an event manager
+is a method to register an event when an operation would block and
+unregister it when the operation has completed The library registers
+and unregisters events by calling the following two functions:
+*/
+
+extern int HTEvent_register	(SOCKET, HTEventType, HTEvent *);
+extern int HTEvent_unregister	(SOCKET, HTEventType);
+
+/*
+
+The register function contains information about which socket we are waiting
+on to get ready and which operation we are waiting for (read, write, etc.),
+the request object containing the current request, the event handler that
+we want to be called when the socket becomes reasy, and finally the priority
+by which we want the thread to be processed by the event manager. Likewise,
+libwww can unregister a operation on a socket which means that libwww is
+no longer waiting for this actiion to become ready.
+.
+  Registering an Event Manager
+.
+
+Libwww core does not contain any event manager as it depends on whether you
+want to use pseudo threads no threads, or real threads. Instead, libwww comes
+with a default implementation that you may register,
+but you may as well implement and register your own. The register and unregister
+functions above actually does nothing than looking for a registered event
+manager and then passes the call on to that. You register your own event
+manager by using the methods below:
+*/
+
+typedef int HTEvent_registerCallback(SOCKET, HTEventType, HTEvent *);
+typedef int HTEvent_unregisterCallback(SOCKET, HTEventType);
+
+extern void HTEvent_setRegisterCallback(HTEvent_registerCallback *);
+extern void HTEvent_setUnregisterCallback(HTEvent_unregisterCallback *);
+
+/*
+(
+  Has Register and Unregister Callbacks been setup?
+)
+
+Replies YES if both an HTEvent_setRegisterCallback and
+HTEvent_setUnregisterCallback have been called with non NULL callbacks.
+*/
+
+extern BOOL HTEvent_isCallbacksRegistered(void);
+
+/*
+.
+  Create and Delete Events
+.
+*/
+
+extern HTEvent * HTEvent_new (HTEventCallback * cbf, void * context,
+			      HTPriority pritority, int timeoutInMillis);
+extern BOOL HTEvent_delete (HTEvent * event);
+
+/*
+(
+  Event Timeouts, Priorities, Callbacks, and Contexts
+)
+
+Normally, these are set when creating the event.
+*/
+
+extern BOOL HTEvent_setParam(HTEvent * event, void * param);
+extern BOOL HTEvent_setPriority(HTEvent * event, HTPriority priority);
+extern BOOL HTEvent_setTimeout(HTEvent * event, int timeoutInMillis);
+extern BOOL HTEvent_setCallback(HTEvent * event, HTEventCallback * cbf);
+
+/*
+.
+  The Raw Event Type
+.
+
+Don't use this directly, use the methods above instead.
+*/
+
+struct _HTEvent {
+    HTPriority		priority;	 /* Priority of this request (event) */
+    int                 millis;              /* Timeout in ms for this event */
+#ifdef IN_EVENT
+    HTTimer *		timer;
+#endif
+    HTEventCallback *	cbf;			   /* Protocol state machine */
+    void *		param;		       /* HTEvent_register parameter */
+    HTRequest *		request;
+};
+
+/*
+
+You can register the event manager provided together with libwww by using
+the HTEventInit() in the HTInit module
+*/
+
+#endif /* HTEVENT_H */
+
+/*
+
+  
+
+  @(#) $Id: HTEvent.h,v 1.1 1999-10-09 19:05:39 egnor Exp $
+
+*/
diff --git a/foreign/README b/foreign/README
index b373428..78a4682 100644
--- a/foreign/README
+++ b/foreign/README
@@ -5,7 +5,7 @@ adapters without requiring the presence of the foreign components in question.
 An adapter will still not function without the code it adapts, of course, but
 at least this way we eliminate pesky build ordering issues.
 
-Many of these are licensed under specific agreements:
+Many of these have specific licensing terms and agreements:
 
 adns.h
 
@@ -21,3 +21,36 @@ adns.h
         and to any files adns.h with similar contents and function I might
         release during the remainder of this calendar year (1999).
 
+HTEvent.h
+HTMemory.h
+HTUtils.h
+
+    These header files are extracted from libwww.
+    Libwww is a general-purpose Web API written in C.
+    <URL:http://www.w3.org/Library/>
+
+    Libwww code is subject to this copyright:
+
+    Copyright � 1995-1998 World Wide Web Consortium, (Massachusetts Institute
+    of Technology, Institut National de Recherche en Informatique et en
+    Automatique, Keio University). All Rights Reserved. This program is
+    distributed under the W3C's Software Intellectual Property License. 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 W3C License http://www.w3.org/Consortium/Legal/ for more details.
+
+    Copyright � 1995 CERN. "This product includes computer software created and
+    made available by CERN. This acknowledgment shall be mentioned in full in
+    any product which includes the CERN computer software included herein or
+    parts thereof." 
+
+glib.h
+
+    This is the public header file for GLIB, a "library of useful routines
+    for C programming" used heavily by the popular GTK+ widget set.
+    <URL:http://www.gtk.org/>
+
+    GLIB is licensed under the GNU Library GPL, version 2.  The copyright
+    is held by Peter Mattis, Spencer Kimball and Josh MacDonald.
diff --git a/foreign/adns.h b/foreign/adns.h
index 550c6f4..bc6d6eb 100644
--- a/foreign/adns.h
+++ b/foreign/adns.h
@@ -19,7 +19,7 @@
  *  along with this program; if not, write to the Free Software Foundation,
  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- *  $Id: adns.h,v 1.1 1999-08-09 07:11:52 egnor Exp $
+ *  $Id: adns.h,v 1.2 1999-10-09 19:05:39 egnor Exp $
  */
 
 #ifndef ADNS_H_INCLUDED
@@ -32,6 +32,9 @@ extern "C" { /* I really dislike this - iwj. */
 
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
 
 /* All struct in_addr anywhere in adns are in NETWORK byte order. */
 
@@ -300,6 +303,9 @@ void adns_cancel(adns_query query);
  * first adns_submit or _transact call using the same adns_state after
  * it became invalid, so you may compare it for equality with other
  * query handles until you next call _query or _transact.
+ *
+ * _submit and _synchronous return ENOSYS if they don't understand the
+ * query type.
  */
 
 void adns_finish(adns_state ads);
diff --git a/glib.c b/glib.c
new file mode 100644
index 0000000..566740a
--- /dev/null
+++ b/glib.c
@@ -0,0 +1,100 @@
+/* glib.c, liboop, copyright 1999 Dan Egnor
+
+   This is free software; you can redistribute it and/or modify it under the
+   terms of the GNU Lesser General Public License, version 2.1 or later.
+   See the file COPYING for details. */
+
+#include "glib.h"
+#include "oop-glib.h"
+#include "oop.h"
+
+#include <assert.h>
+#include <poll.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+static int use_count = 0;
+static oop_source_sys *sys;
+static oop_adapter_select *sel;
+
+static fd_set read_set,write_set;
+static int count;
+static void *ret = NULL;
+
+static void *on_select(
+	oop_adapter_select *s,int num,fd_set *r,fd_set *w,
+	struct timeval now,void *x) 
+{
+	read_set = *r;
+	write_set = *w;
+	count = num;
+	return &use_count;
+}
+
+static gint on_poll(GPollFD *array,guint num,gint timeout) {
+	struct timeval tv;
+	int i;
+
+	FD_ZERO(&read_set);
+	FD_ZERO(&write_set);
+	count = 0;
+	for (i = 0; i < num; ++i) {
+		if (array[i].events & G_IO_IN)
+			FD_SET(array[i].fd,&read_set);
+		if (array[i].events & G_IO_OUT)
+			FD_SET(array[i].fd,&write_set);
+		if (array[i].fd >= count)
+			count = 1 + array[i].fd;
+	}
+
+	tv.tv_sec = timeout / 1000;
+	tv.tv_usec = timeout % 1000;
+
+	oop_select_set(sel,count,&read_set,&write_set,timeout < 0 ? NULL : &tv);
+	ret = oop_sys_run(sys);
+
+	if (&use_count != ret) {
+		/* I really wish I could: g_main_quit(glib_loop); */
+		return -1;
+		/* but they even ignore the error return... sigh. */
+	}
+
+	for (i = 0; i < num; ++i) {
+		if (FD_ISSET(array[i].fd,&read_set))
+			array[i].revents |= G_IO_IN;
+		if (FD_ISSET(array[i].fd,&write_set))
+			array[i].revents |= G_IO_OUT;
+	}
+
+	return count;
+}
+
+static gint real_poll(GPollFD *array,guint num,gint timeout) {
+	assert(sizeof(GPollFD) == sizeof(struct pollfd));
+	return poll((struct pollfd *) array,num,timeout);
+}
+
+oop_source *oop_glib_new() {
+	if (use_count++) return oop_sys_source(sys);
+
+	sys = oop_sys_new();
+	sel = oop_select_new(oop_sys_source(sys),on_select,NULL);
+	g_main_set_poll_func(on_poll);
+	return oop_sys_source(sys);
+}
+
+void *oop_glib_return() {
+	if (&use_count == ret) return NULL;
+	return ret;
+}
+
+void oop_glib_delete() {
+	assert(use_count > 0 && "oop_glib_delete() called too much");
+	if (0 != --use_count) return;
+
+	oop_select_delete(sel);
+	oop_sys_delete(sys);
+	g_main_set_poll_func(real_poll);
+}
diff --git a/oop-adns.h b/oop-adns.h
index e702243..82a7a84 100644
--- a/oop-adns.h
+++ b/oop-adns.h
@@ -8,7 +8,7 @@
 #define OOP_ADNS_H
 
 #ifndef ADNS_H_INCLUDED
-#error You must include "adns.h" before "oop_adns.h"!
+#error You must include "adns.h" before "oop-adns.h"!
 #endif
 
 #include "oop.h"
diff --git a/oop-glib.h b/oop-glib.h
new file mode 100644
index 0000000..95776f7
--- /dev/null
+++ b/oop-glib.h
@@ -0,0 +1,25 @@
+/* oop-glib.h, liboop, copyright 1999 Dan Egnor
+
+   This is free software; you can redistribute it and/or modify it under the
+   terms of the GNU Lesser General Public License, version 2.1 or later.
+   See the file COPYING for details. */
+
+#ifndef OOP_GLIB_H
+#define OOP_GLIB_H
+
+#ifndef __G_LIB_H__
+#error You must include "glib.h" before "oop-glib.h"!
+#endif
+
+#include "oop.h"
+
+/* Create an event source based on the GLib event loop. */
+oop_source *oop_glib_new();
+
+/* Delete the event source so created.  (Uses reference counting.) */
+void oop_glib_delete();
+
+/* Get the value used to terminate the event loop (e.g. OOP_HALT). */
+void *oop_glib_return();
+
+#endif
diff --git a/oop.h b/oop.h
index c046f22..ebc8923 100644
--- a/oop.h
+++ b/oop.h
@@ -26,6 +26,9 @@ typedef enum {
 /* Pass this to on_time to schedule an event immediately */
 static const struct timeval OOP_TIME_NOW = { 0, 0 };
 
+/* Maximum signal number.  (The OS may have a stricter limit!) */
+#define OOP_NUM_SIGNALS 256
+
 /* Callbacks may return one of these */
 #define OOP_CONTINUE NULL
 #define OOP_HALT ((void *) 1) /* (or any non-NULL pointer of your choice) */
@@ -37,7 +40,7 @@ typedef void *oop_call_signal(oop_source *,int sig,void *);
 
 struct oop_source {
 	void (*on_fd)(oop_source *,int fd,oop_event,oop_call_fd *,void *);
-	void (*cancel_fd)(oop_source *,int fd,oop_event,oop_call_fd *,void *);
+	void (*cancel_fd)(oop_source *,int fd,oop_event);
 
 	void (*on_time)(oop_source *,struct timeval,oop_call_time *,void *);
 	void (*cancel_time)(oop_source *,struct timeval,oop_call_time *,void *);
@@ -92,4 +95,13 @@ void oop_select_set(
 
 void oop_select_delete(oop_adapter_select *);
 
+/* ------------------------------------------------------------------------- */
+
+/* Helper for event sources without signal handling. */
+typedef struct oop_adapter_signal oop_adapter_signal;
+
+oop_adapter_signal *oop_signal_new(oop_source *);
+void oop_signal_delete(oop_adapter_signal *);
+oop_source *oop_signal_source(oop_adapter_signal *);
+
 #endif
diff --git a/select.c b/select.c
index ec86aca..9972d65 100644
--- a/select.c
+++ b/select.c
@@ -77,18 +77,18 @@ void oop_select_set(
 			FD_SET(fd,&s->watch.rfd);
 		}
 
-		if (wfd_set && !w_wfd_set) {
-			s->source->cancel_fd(s->source,fd,OOP_READ,on_fd,s);
+		if (!rfd_set && w_rfd_set) {
+			s->source->cancel_fd(s->source,fd,OOP_READ);
 			FD_CLR(fd,&s->watch.rfd);
 		}
 
-		if (!rfd_set && w_rfd_set) {
+		if (wfd_set && !w_wfd_set) {
 			s->source->on_fd(s->source,fd,OOP_WRITE,on_fd,s);
 			FD_SET(fd,&s->watch.wfd);
 		}
 
 		if (!wfd_set && w_wfd_set) {
-			s->source->cancel_fd(s->source,fd,OOP_WRITE,on_fd,s);
+			s->source->cancel_fd(s->source,fd,OOP_WRITE);
 			FD_CLR(fd,&s->watch.wfd);
 		}
 	}
@@ -155,12 +155,10 @@ static void *on_timeout(oop_source *source,struct timeval when,void *data) {
 
 static void *on_collect(oop_source *source,struct timeval when,void *data) {
 	oop_adapter_select *s = (oop_adapter_select *) data;
+	struct select_set set = s->active;
+	int num = s->num_fd_active;
 	struct timeval now;
-	void *r;
-
 	gettimeofday(&now,NULL);
-	r = s->call(s,s->num_fd_active,&s->active.rfd,&s->active.wfd,now,s->data);
 	deactivate(s);
-
-	return r;
+	return s->call(s,num,&set.rfd,&set.wfd,now,s->data);
 }
diff --git a/sys.c b/sys.c
index 14495d4..442b1f3 100644
--- a/sys.c
+++ b/sys.c
@@ -16,7 +16,6 @@
 #include <setjmp.h>
 
 #define MAGIC 0x9643
-#define NUM_SIGNALS 256
 
 struct sys_time {
 	struct sys_time *next;
@@ -54,7 +53,7 @@ struct oop_source_sys {
 	struct sys_time *time_queue,*time_run;
 
 	/* Signal handling */
-	struct sys_signal sig[NUM_SIGNALS];
+	struct sys_signal sig[OOP_NUM_SIGNALS];
 	sigjmp_buf env;
 	int do_jmp,sig_active;
 
@@ -63,7 +62,7 @@ struct oop_source_sys {
 	sys_file *files;
 };
 
-struct oop_source_sys *sys_sig_owner[NUM_SIGNALS];
+struct oop_source_sys *sys_sig_owner[OOP_NUM_SIGNALS];
 
 static oop_source_sys *verify_source(oop_source *source) {
 	oop_source_sys *sys = (oop_source_sys *) source;
@@ -94,11 +93,9 @@ static void sys_on_fd(oop_source *source,int fd,oop_event ev,
 	++sys->num_events;
 }
 
-static void sys_cancel_fd(oop_source *source,int fd,oop_event ev,
-                          oop_call_fd *f,void *v) {
+static void sys_cancel_fd(oop_source *source,int fd,oop_event ev) {
 	oop_source_sys *sys = verify_source(source);
-	if (fd < sys->num_files && NULL != f
-	&&  f == sys->files[fd][ev].f && v == sys->files[fd][ev].v) {
+	if (fd < sys->num_files && NULL != sys->files[fd][ev].f) {
 		sys->files[fd][ev].f = NULL;
 		--sys->num_events;
 	}
@@ -179,7 +176,7 @@ static void sys_on_signal(oop_source *source,int sig,
 	struct sys_signal_handler *handler = oop_malloc(sizeof(*handler));
 	if (NULL == handler) return; /* ugh */
 
-	assert(sig > 0 && sig < NUM_SIGNALS && "invalid signal number");
+	assert(sig > 0 && sig < OOP_NUM_SIGNALS && "invalid signal number");
 
 	handler->f = f;
 	handler->v = v;
@@ -205,25 +202,26 @@ static void sys_on_signal(oop_source *source,int sig,
 static void sys_cancel_signal(oop_source *source,int sig,
                               oop_call_signal *f,void *v) {
 	oop_source_sys *sys = verify_source(source);
-	struct sys_signal_handler *p,**pp = &sys->sig[sig].list;
+	struct sys_signal_handler **pp = &sys->sig[sig].list;
 
-	assert(sig > 0 && sig < NUM_SIGNALS && "invalid signal number");
+	assert(sig > 0 && sig < OOP_NUM_SIGNALS && "invalid signal number");
 
 	while (NULL != *pp && ((*pp)->f != f || (*pp)->v != v))
 		pp = &(*pp)->next;
 
 	if (NULL != *pp) {
-		p = *pp;
-		*pp = p->next;
-		if (sys->sig[sig].ptr == p) sys->sig[sig].ptr = *pp;
-		--sys->num_events;
-		oop_free(p);
+		struct sys_signal_handler *p = *pp;
 
-		if (NULL == sys->sig[sig].list) {
+		if (NULL == p->next && &sys->sig[sig].list == pp) {
 			sigaction(sig,&sys->sig[sig].old,NULL);
 			sys->sig[sig].active = 0;
 			sys_sig_owner[sig] = NULL;
 		}
+
+		*pp = p->next;
+		if (sys->sig[sig].ptr == p) sys->sig[sig].ptr = *pp;
+		--sys->num_events;
+		oop_free(p);
 	}
 }
 
@@ -244,7 +242,7 @@ oop_source_sys *oop_sys_new(void) {
 
 	source->do_jmp = 0;
 	source->sig_active = 0;
-	for (i = 0; i < NUM_SIGNALS; ++i) {
+	for (i = 0; i < OOP_NUM_SIGNALS; ++i) {
 		source->sig[i].list = NULL;
 		source->sig[i].ptr = NULL;
 		source->sig[i].active = 0;
@@ -324,7 +322,7 @@ void *oop_sys_run(oop_source_sys *sys) {
 
 		if (sys->sig_active) {
 			sys->sig_active = 0;
-			for (i = 0; NULL == ret && i < NUM_SIGNALS; ++i) {
+			for (i = 0; NULL == ret && i < OOP_NUM_SIGNALS; ++i) {
 				if (sys->sig[i].active) {
 					sys->sig[i].active = 0;
 					sys->sig[i].ptr = sys->sig[i].list;
@@ -332,8 +330,8 @@ void *oop_sys_run(oop_source_sys *sys) {
 				while (NULL == ret && NULL != sys->sig[i].ptr) {
 					struct sys_signal_handler *h;
 					h = sys->sig[i].ptr;
-					ret = h->f(&sys->oop,i,h->v);
 					sys->sig[i].ptr = h->next;
+					ret = h->f(&sys->oop,i,h->v);
 				}
 			}
 			if (NULL != ret) {
@@ -387,7 +385,7 @@ void oop_sys_delete(oop_source_sys *sys) {
 	&&     NULL == sys->time_run
 	&&     "cannot delete with timeout");
 
-	for (i = 0; i < NUM_SIGNALS; ++i)
+	for (i = 0; i < OOP_NUM_SIGNALS; ++i)
 		assert(NULL == sys->sig[i].list && "cannot delete with signal handler");
 
 	for (i = 0; i < sys->num_files; ++i)
diff --git a/test-oop.c b/test-oop.c
index bd021ae..38edbbc 100644
--- a/test-oop.c
+++ b/test-oop.c
@@ -1,22 +1,63 @@
+/* test-oop.c, liboop, copyright 1999 Dan Egnor
+
+   This is free software; you can redistribute it and/or modify it under the
+   terms of the GNU Lesser General Public License, version 2.1 or later.
+   See the file COPYING for details. */
+
 #include <stdio.h>
+#include <assert.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/time.h>
+#include <arpa/inet.h>
+
 #include "oop.h"
 
+#ifdef HAVE_GLIB
+#include <glib.h>
+#include "oop-glib.h"
+GMainLoop *glib_loop;
+#endif
+
 struct timer {
 	struct timeval tv;
 	int delay;
 };
 
+static oop_source_sys *source_sys;
+static oop_adapter_signal *source_signal;
+
+static void usage(void) {
+	fputs(
+"usage:   test-oop <source> <sink> [<sink> ...]\n"
+"sources: sys      system event source\n"
+"         signal   system event source with signal adapter\n"
+#ifdef HAVE_GLIB
+"         glib     GLib source adapter\n"
+#endif
+"sinks:   timer    some timers\n"
+"         echo     a stdin->stdout copy\n"
+"         signal   some signal handlers\n"
+#ifdef HAVE_ADNS
+"         adns     some asynchronous DNS lookups\n"
+#endif
+#ifdef HAVE_WWW
+"         libwww   some HTTP GET operations\n"
+#endif
+	,stderr);
+	exit(1);
+}
+
+/* -- timer ---------------------------------------------------------------- */
+
 oop_call_time on_timer;
 void *on_timer(oop_source *source,struct timeval tv,void *data) {
 	struct timer *timer = (struct timer *) data;
 	timer->tv = tv;
 	timer->tv.tv_sec += timer->delay;
 	source->on_time(source,timer->tv,on_timer,data);
-	printf("This message should be output once every ");
+	printf("timer: once every ");
 	if (1 == timer->delay) printf("second\n");
 	else printf("%d seconds\n",timer->delay);
 	return OOP_CONTINUE;
@@ -26,7 +67,7 @@ oop_call_signal stop_timer;
 void *stop_timer(oop_source *source,int sig,void *data) {
 	struct timer *timer = (struct timer *) data;
 	source->cancel_time(source,timer->tv,on_timer,timer);
-	source->cancel_signal(source,SIGINT,stop_timer,timer);
+	source->cancel_signal(source,SIGQUIT,stop_timer,timer);
 	return OOP_CONTINUE;
 }
 
@@ -34,42 +75,323 @@ void add_timer(oop_source *source,int interval) {
 	struct timer *timer = malloc(sizeof(*timer));
 	gettimeofday(&timer->tv,NULL);
 	timer->delay = interval;
-	source->on_signal(source,SIGINT,stop_timer,timer);
+	source->on_signal(source,SIGQUIT,stop_timer,timer);
 	on_timer(source,timer->tv,timer);
 }
 
-oop_call_fd on_data;
-void *on_data(oop_source *source,int fd,oop_event event,void *data) {
+/* -- echo ----------------------------------------------------------------- */
+
+static oop_call_fd on_data;
+static void *on_data(oop_source *source,int fd,oop_event event,void *data) {
 	char buf[BUFSIZ];
 	int r = read(fd,buf,sizeof(buf));
 	write(1,buf,r);
 	return OOP_CONTINUE;
 }
 
-oop_call_signal stop_data;
-void *stop_data(oop_source *source,int sig,void *data) {
-	source->cancel_fd(source,0,OOP_READ,on_data,NULL);
-	source->cancel_signal(source,SIGINT,stop_data,NULL);
+static oop_call_signal stop_data;
+static void *stop_data(oop_source *source,int sig,void *data) {
+	source->cancel_fd(source,0,OOP_READ);
+	source->cancel_signal(source,SIGQUIT,stop_data,NULL);
+	return OOP_CONTINUE;
+}
+
+/* -- signal --------------------------------------------------------------- */
+
+static oop_call_signal on_signal;
+static void *on_signal(oop_source *source,int sig,void *data) {
+	switch (sig) {
+	case SIGINT:
+		puts("signal: SIGINT (control-C) caught.  "
+		     "(Use SIGQUIT, control-\\, to terminate.)");
+		break;
+	case SIGQUIT:
+		puts("signal: SIGQUIT (control-\\) caught, terminating.");
+		source->cancel_signal(source,SIGINT,on_signal,NULL);
+		source->cancel_signal(source,SIGQUIT,on_signal,NULL);
+		break;
+	default:
+		assert(0 && "unknown signal?");
+	}
+	return OOP_CONTINUE;
+}
+
+/* -- adns ----------------------------------------------------------------- */
+
+#ifdef HAVE_ADNS
+
+#include "adns.h"
+#include "oop-adns.h"
+
+#define NUM_Q 6
+oop_adns_query *q[NUM_Q];
+oop_adapter_adns *adns;
+
+void *stop_lookup(oop_source *src,int sig,void *data) {
+	int i;
+
+	for (i = 0; i < NUM_Q; ++i)
+		if (NULL != q[i]) {
+			oop_adns_cancel(q[i]);
+			q[i] = NULL;
+		}
+
+	if (NULL != adns) {
+		oop_adns_delete(adns);
+		adns = NULL;
+	}
+
+	src->cancel_signal(src,SIGQUIT,stop_lookup,NULL);
 	return OOP_CONTINUE;
 }
 
-oop_call_signal on_intr;
-void *on_intr(oop_source *source,int sig,void *data) {
-	puts("SIGINT (control-C) received, terminating!");
-	source->cancel_signal(source,SIGINT,on_intr,NULL);
+void *on_lookup(oop_adapter_adns *adns,adns_answer *reply,void *data) {
+	int i;
+	for (i = 0; i < NUM_Q; ++i) if (data == &q[i]) q[i] = NULL;
+
+	printf("adns: %s =>",reply->owner);
+	if (adns_s_ok != reply->status) {
+		printf(" error: %s\n",adns_strerror(reply->status));
+		return OOP_CONTINUE;
+	}
+	if (NULL != reply->cname) printf(" (%s)",reply->cname);
+	assert(adns_r_a == reply->type);
+	for (i = 0; i < reply->nrrs; ++i)
+		printf(" %s",inet_ntoa(reply->rrs.inaddr[i]));
+	printf("\n");
+	free(reply);
+
 	return OOP_CONTINUE;
 }
 
-int main(void) {
-	oop_source_sys *sys = oop_sys_new();
-	oop_source *src = oop_sys_source(sys);
-	add_timer(src,1);
-	add_timer(src,2);
-	add_timer(src,3);
-	src->on_fd(src,0,OOP_READ,on_data,NULL);
-	src->on_signal(src,SIGINT,stop_data,NULL);
-	src->on_signal(src,SIGINT,on_intr,NULL);
-	oop_sys_run(sys);
-	oop_sys_delete(sys);
+static void get_name(int i,const char *name) {
+	q[i] = oop_adns_submit(
+	       adns,name,adns_r_a,adns_qf_owner,
+	       on_lookup,&q[i]);
+}
+
+static void add_adns(oop_source *src) {
+	adns = oop_adns_new(src,0,NULL);
+	get_name(0,"g.mp");
+	get_name(1,"cnn.com");
+	get_name(2,"slashdot.org");
+	get_name(3,"love.ugcs.caltech.edu");
+	get_name(4,"intel.ugcs.caltech.edu");
+	get_name(5,"ofb.net");
+	src->on_signal(src,SIGQUIT,stop_lookup,NULL);
+}
+
+#else
+
+static void add_adns(oop_source *src) {
+	fputs("sorry, adns not available\n",stderr);
+	usage();
+}
+
+#endif
+
+/* -- libwww --------------------------------------------------------------- */
+
+#ifdef HAVE_WWW
+
+/* Yuck: */
+#define HAVE_CONFIG_H
+#undef PACKAGE
+#undef VERSION
+
+#include "oop.h"
+#include "HTEvent.h"
+#include "oop-www.h"
+
+#include "WWWLib.h"
+#include "WWWInit.h"
+
+static int remaining = 0;
+
+static int on_print(const char *fmt,va_list args) {
+	return (vfprintf(stdout,fmt,args));
+}
+
+static int on_trace (const char *fmt,va_list args) {
+	return (vfprintf(stderr,fmt,args));
+}
+
+static int on_complete(HTRequest *req,HTResponse *resp,void *x,int status) {
+	HTChunk *chunk = (HTChunk *) HTRequest_context(req);
+	char *address = HTAnchor_address((HTAnchor *) HTRequest_anchor(req));
+
+	HTPrint("%d: done with %s\n",status,address);
+	HTMemory_free(address);
+	HTRequest_delete(req);
+
+	if (NULL != chunk) HTChunk_delete(chunk);
+
+	if (0 == --remaining) {
+	/* stop ... */
+	}
+
+	return HT_OK;
+}
+
+static void get_uri(const char *uri) {
+	HTRequest *req = HTRequest_new();
+	HTRequest_setOutputFormat(req, WWW_SOURCE);
+	HTRequest_setContext(req,HTLoadToChunk(uri,req));
+	++remaining;
+}
+
+static void *stop_www(oop_source *source,int sig,void *x) {
+	oop_www_cancel();
+	HTProfile_delete();
+	source->cancel_signal(source,sig,stop_www,x);
+	return OOP_CONTINUE;
+}
+
+void add_www(oop_source *source) {
+	puts("libwww: known bug: termination (^\\) may abort due to cached "
+             "connections, sorry.");
+	HTProfile_newNoCacheClient("test-www","1.0");
+	oop_www_register(source);
+
+	HTPrint_setCallback(on_print);
+	HTTrace_setCallback(on_trace);
+
+	HTNet_addAfter(on_complete, NULL, NULL, HT_ALL, HT_FILTER_LAST);
+	HTAlert_setInteractive(NO);
+
+	get_uri("http://ofb.net/~egnor/oop/");
+	get_uri("http://ofb.net/does.not.exist");
+	get_uri("http://slashdot.org/");
+	get_uri("http://www.w3.org/Library/");
+	get_uri("http://does.not.exist/");
+
+	source->on_signal(source,SIGQUIT,stop_www,NULL);
+}
+
+#else
+
+void add_www(oop_source *source) {
+	fputs("sorry, libwww not available\n",stderr);
+	usage();
+}
+
+#endif
+
+/* -- core ----------------------------------------------------------------- */
+
+static void *stop_loop_delayed(oop_source *source,struct timeval tv,void *x) {
+	return OOP_HALT;
+}
+
+static void *stop_loop(oop_source *source,int sig,void *x) {
+	/* give everyone else a chance to shut down. */
+	source->on_time(source,OOP_TIME_NOW,stop_loop_delayed,NULL);
+	source->cancel_signal(source,SIGQUIT,stop_loop,NULL);
+	return OOP_CONTINUE;
+}
+
+static oop_source *create_source(const char *name) {
+	if (!strcmp(name,"sys")) {
+		source_sys = oop_sys_new();
+		return oop_sys_source(source_sys);
+	}
+
+	if (!strcmp(name,"signal")) {
+		source_sys = oop_sys_new();
+		source_signal = oop_signal_new(oop_sys_source(source_sys));
+		return oop_signal_source(source_signal);
+	}
+
+#ifdef HAVE_GLIB
+	if (!strcmp(name,"glib")) {
+		puts("glib: known bug: termination (^\\) won't quit, sorry.");
+		glib_loop = g_main_new(FALSE);
+		return oop_glib_new();
+	}
+#endif
+
+	fprintf(stderr,"unknown source \"%s\"\n",name);
+	usage();
+	return NULL;
+}
+
+static void run_source(const char *name) {
+	if (!strcmp(name,"sys")
+	||  !strcmp(name,"signal"))
+		oop_sys_run(source_sys);
+
+#ifdef HAVE_GLIB
+	if (!strcmp(name,"glib"))
+		g_main_run(glib_loop);
+#endif
+}
+
+static void delete_source(const char *name) {
+	if (!strcmp(name,"sys"))
+		oop_sys_delete(source_sys);
+	if (!strcmp(name,"signal")) {
+		oop_signal_delete(source_signal);
+		oop_sys_delete(source_sys);
+	}
+
+#ifdef HAVE_GLIB
+	if (!strcmp(name,"glib")) {
+		oop_glib_delete();
+		g_main_destroy(glib_loop);
+	}
+#endif
+}
+
+static void add_sink(oop_source *src,const char *name) {
+	if (!strcmp(name,"timer")) {
+		add_timer(src,1);
+		add_timer(src,2);
+		add_timer(src,3);
+		return;
+	}
+
+	if (!strcmp(name,"echo")) {
+		src->on_fd(src,0,OOP_READ,on_data,NULL);
+		src->on_signal(src,SIGQUIT,stop_data,NULL);
+		return;
+	}
+
+	if (!strcmp(name,"signal")) {
+		src->on_signal(src,SIGINT,on_signal,NULL);
+		src->on_signal(src,SIGQUIT,on_signal,NULL);
+		return;
+	}
+
+#ifdef HAVE_ADNS
+	if (!strcmp(name,"adns")) {
+		add_adns(src);
+		return;
+	}
+#endif
+
+#ifdef HAVE_WWW
+	if (!strcmp(name,"libwww")) {
+		add_www(src);
+		return;
+	}
+#endif
+
+	fprintf(stderr,"unknown sink \"%s\"\n",name);
+	usage();
+}
+
+int main(int argc,char *argv[]) {
+	oop_source *source;
+	int i;
+
+	if (argc < 3) usage();
+	puts("test-oop: use ^\\ (SIGQUIT) for clean shutdown");
+	source = create_source(argv[1]);
+	source->on_signal(source,SIGQUIT,stop_loop,NULL);
+	for (i = 2; i < argc; ++i)
+		add_sink(source,argv[i]);
+
+	run_source(argv[1]);
+	delete_source(argv[1]);
 	return 0;
 }
diff --git a/www.c b/www.c
new file mode 100644
index 0000000..3ae6eb7
--- /dev/null
+++ b/www.c
@@ -0,0 +1,185 @@
+/* www.c, liboop, copyright 1999 Dan Egnor
+
+   This is free software; you can redistribute it and/or modify it under the
+   terms of the GNU Lesser General Public License, version 2.1 or later.
+   See the file COPYING for details. */
+
+/* Yecch: the libwww header files need this. */
+#define HAVE_CONFIG_H
+#undef PACKAGE
+#undef VERSION
+
+#include <stdarg.h> /* Needed for our cut-down libwww headers. */
+
+#include "oop.h"
+#include "HTEvent.h"
+#include "HTMemory.h"
+#include "oop-www.h"
+
+#include <assert.h>
+
+struct event {
+	HTEvent *event;
+	struct timeval time;
+};
+
+typedef struct event descriptor[HTEvent_TYPES];
+
+static int num = 0,size = 0;
+static descriptor *array = NULL;
+static oop_source *oop = NULL;
+
+static struct event *get_event(SOCKET sock,HTEventType type) {
+	assert(sock < size && "invalid file descriptor");
+	return &array[sock][HTEvent_INDEX(type)];
+}
+
+static void *on_time(oop_source *s,struct timeval tv,void *x) {
+	struct event *event;
+	SOCKET sock = (int) x;
+	int j;
+
+	for (j = 0; j < HTEvent_TYPES; ++j) {
+		event = &array[sock][j];
+		if (NULL != event->event && 0 <= event->event->millis
+		&&  tv.tv_sec == event->time.tv_sec
+		&&  tv.tv_usec == event->time.tv_usec) 
+			break;
+	}
+
+	assert(j < HTEvent_TYPES);
+	event->event->cbf(sock,event->event->param,HTEvent_TIMEOUT);
+	return OOP_CONTINUE;
+}
+
+static void set_timer(struct event *event) {
+	if (0 <= event->event->millis) {
+		gettimeofday(&event->time,NULL);
+		event->time.tv_sec += event->event->millis / 1000;
+		event->time.tv_usec += event->event->millis % 1000;
+		if (event->time.tv_usec > 1000000) {
+			event->time.tv_usec -= 1000000;
+			++event->time.tv_sec;
+		}
+		oop->on_time(oop,event->time,on_time,event);
+	}
+}
+
+static void *on_fd(oop_source *s,int fd,oop_event type,void *x) {
+	HTEventType www_type;
+	struct event *event;
+
+	switch (type) {
+	case OOP_READ:
+		www_type = HTEvent_READ;
+		break;
+	case OOP_WRITE:
+		www_type = HTEvent_WRITE;
+		break;
+	default:
+		assert(0);
+	}
+
+	event = get_event(fd,www_type);
+	if (0 <= event->event->millis) {
+		oop->cancel_time(oop,event->time,on_time,event);
+		set_timer(event);
+	}
+	event->event->cbf(fd,event->event->param,www_type);
+	return OOP_CONTINUE;
+}
+
+static void dereg(SOCKET sock,HTEventType www_type,oop_event oop_type) {
+	struct event *event = get_event(sock,www_type);
+	assert(sock < size && "invalid file descriptor");
+	if (NULL != event->event) {
+		--num;
+		oop->cancel_fd(oop,sock,oop_type);
+		if (0 <= event->event->millis)
+			oop->cancel_time(oop,event->time,on_time,event);
+		event->event = NULL;
+	}
+}
+
+static int reg(SOCKET sock,HTEventType type,HTEvent *www_event) {
+	oop_event oop_type;
+	struct event *event;
+
+	switch (HTEvent_INDEX(type)) {
+	case HTEvent_INDEX(HTEvent_READ):
+		oop_type = OOP_READ;
+		break;
+	case HTEvent_INDEX(HTEvent_WRITE):
+		oop_type = OOP_WRITE;
+		break;
+	case HTEvent_INDEX(HTEvent_OOB):
+		// XXX: we don't handle this; does anything use it?
+		return HT_ERROR;
+	default:
+		assert(0 && "invalid HTEvent type specified");
+	}
+
+	if (sock >= size) {
+		int newsize = size ? (2*size) : 16;
+		descriptor *newarray = oop_malloc(sizeof(*newarray) * newsize);
+		int i,j;
+
+		if (NULL == newarray) return HT_ERROR;
+
+		memcpy(newarray,array,sizeof(*newarray) * size);
+		for (i = size; i < newsize; ++i)
+		for (j = 0; j < HTEvent_TYPES; ++j) {
+			newarray[i][j].event = NULL;
+		}
+
+		array = newarray;
+		size = newsize;
+	}
+
+	dereg(sock,type,oop_type);
+	event = get_event(sock,type);
+	event->event = www_event;
+	oop->on_fd(oop,sock,oop_type,on_fd,NULL);
+	set_timer(event);
+	++num;
+
+	return HT_OK;
+}
+
+static int unreg(SOCKET sock,HTEventType type) {
+	oop_event oop_type;
+	switch (HTEvent_INDEX(type)) {
+	case HTEvent_INDEX(HTEvent_READ):
+		oop_type = OOP_READ;
+		break;
+	case HTEvent_INDEX(HTEvent_WRITE):
+		oop_type = OOP_WRITE;
+		break;
+	case HTEvent_INDEX(HTEvent_OOB):
+		// XXX: we don't handle this; does anything use it?
+		return HT_ERROR;
+	default:
+		assert(0 && "invalid HTEvent type specified");
+	}
+
+	dereg(sock,type,oop_type);
+	return HT_OK;
+}
+
+void oop_www_register(oop_source *source) {
+	oop = source;
+	HTEvent_setRegisterCallback(reg);
+	HTEvent_setUnregisterCallback(unreg);
+}
+
+void oop_www_cancel() {
+	assert(0 == num && "cannot unregister with pending libwww events");
+	HTEvent_setRegisterCallback(NULL);
+	HTEvent_setUnregisterCallback(NULL);
+	oop = NULL;
+}
+
+void oop_www_memory() {
+	oop_malloc = HTMemory_malloc;
+	oop_free = HTMemory_free;
+}
-- 
GitLab