changeset 43:2842f50feb55 noffle

[svn] * client.c, client.h, common.h, config.c, config.h, content.c, content.h, control.c, control.h, database.c, database.h, dynamicstring.c, dynamicstring.h, fetch.c, fetch.h, fetchlist.c, fetchlist.h, group.c, group.h, itemlist.c, itemlist.h, lock.c, lock.h, log.c, log.h, noffle.c, online.c, online.h, outgoing.c, outgoing.h, over.c, over.h, post.c, post.h, protocol.c, protocol.h, pseudo.c, pseudo.h, request.c, request.h, server.c, server.h, util.c, util.h, wildmat.c, wildmat.h: Moved files to the subdirectory src/ * Makefile.am, acconfig.h, configure.in, docs/Makefile.am, src/Makefile.am, Makefile.in, aclocal.m4, config.h.in, configure, install-sh, missing, mkinstalldirs, stamp-h.in, docs/Makefile.in, src/Makefile.in: Added files. They are used by aclocal, autoheader, autoconf and automake. * src/config.c, src/config.h: Renamed to configfile.c and configfile.h, because configure will generate a config.h file itself. * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c, src/group.c, src/lock.c, src/noffle.c, src/online.c, src/outgoing.c, src/over.c, src/pseudo.c, src/request.c, src/server.c, src/util.c: Changed '#include "config.h"' to '#include "configfile.h"'. * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c, src/group.c, src/lock.c, src/online.c, src/outgoing.c, src/post.c, src/protocol.c, src/request.c, src/server.c: Files now #include <config.h>. Added missing <stdio.h>. This removes the warnings about snprintf() not being declared. * Makefile: Removed. This is now generated by configure.
author uh1763
date Fri, 05 May 2000 22:45:56 +0100
parents 2467ff423c15
children bb6a1bf61279
files ChangeLog Makefile.am Makefile.in acconfig.h aclocal.m4 client.c client.h common.h config.c config.h config.h.in configure configure.in content.c content.h control.c control.h database.c database.h dynamicstring.c dynamicstring.h fetch.c fetch.h fetchlist.c fetchlist.h group.c group.h install-sh itemlist.c itemlist.h lock.c lock.h log.c log.h missing mkinstalldirs noffle.c online.c online.h outgoing.c outgoing.h over.c over.h post.c post.h protocol.c protocol.h pseudo.c pseudo.h request.c request.h server.c server.h src/Makefile.am src/Makefile.in src/client.c src/client.h src/common.h src/configfile.c src/configfile.h src/content.c src/content.h src/control.c src/control.h src/database.c src/database.h src/dynamicstring.c src/dynamicstring.h src/fetch.c src/fetch.h src/fetchlist.c src/fetchlist.h src/group.c src/group.h src/itemlist.c src/itemlist.h src/lock.c src/lock.h src/log.c src/log.h src/noffle.c src/online.c src/online.h src/outgoing.c src/outgoing.h src/over.c src/over.h src/post.c src/post.h src/protocol.c src/protocol.h src/pseudo.c src/pseudo.h src/request.c src/request.h src/server.c src/server.h src/util.c src/util.h src/wildmat.c src/wildmat.h stamp-h.in util.c util.h wildmat.c wildmat.h
diffstat 105 files changed, 13951 insertions(+), 9120 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri May 05 21:26:14 2000 +0100
+++ b/ChangeLog	Fri May 05 22:45:56 2000 +0100
@@ -2,6 +2,40 @@
 NOFFLE ChangeLog
 -------------------------------------------------------------------------------
 
+
+Fri May  5 23:39:52 CEST 2000  Uwe Hermann <uh1763@bingo-ev.de>
+
+ * client.c, client.h, common.h, config.c, config.h, content.c, content.h,
+   control.c, control.h, database.c, database.h, dynamicstring.c,
+   dynamicstring.h, fetch.c, fetch.h, fetchlist.c, fetchlist.h, group.c,
+   group.h, itemlist.c, itemlist.h, lock.c, lock.h, log.c, log.h, noffle.c,
+   online.c, online.h, outgoing.c, outgoing.h, over.c, over.h, post.c, post.h,
+   protocol.c, protocol.h, pseudo.c, pseudo.h, request.c, request.h, server.c,
+   server.h, util.c, util.h, wildmat.c, wildmat.h: Moved files to the
+   subdirectory src/
+
+ * Makefile.am, acconfig.h, configure.in, docs/Makefile.am, src/Makefile.am,
+   Makefile.in, aclocal.m4, config.h.in, configure, install-sh, missing,
+   mkinstalldirs, stamp-h.in, docs/Makefile.in, src/Makefile.in: Added files.
+   They are used by aclocal, autoheader, autoconf and automake.
+
+ * src/config.c, src/config.h: Renamed to configfile.c and configfile.h,
+   because configure will generate a config.h file itself.
+
+ * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c,
+   src/group.c, src/lock.c, src/noffle.c, src/online.c, src/outgoing.c,
+   src/over.c, src/pseudo.c, src/request.c, src/server.c, src/util.c:
+   Changed '#include "config.h"' to '#include "configfile.h"'.
+
+ * src/client.c, src/content.c, src/database.c, src/fetch.c, src/fetchlist.c,
+   src/group.c, src/lock.c, src/online.c, src/outgoing.c, src/post.c,
+   src/protocol.c, src/request.c, src/server.c: Files now #include <config.h>.
+   Added missing <stdio.h>. This removes the warnings about snprintf() not
+   being declared.
+
+ * Makefile: Removed. This is now generated by configure.
+
+
 Fri May  5 22:24:37 CEST 2000  Uwe Hermann <uh1763@bingo-ev.de>
 
  * AUTHORS.html, CHANGELOG.html, COPYING.html, README.html, FAQ.html,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.am	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,54 @@
+# Process this file with automake to produce Makefile.in
+
+SUBDIRS = src docs
+
+EXTRA_DIST = $(PACKAGE).conf.example
+
+install-data-local:
+	$(INSTALL) -m 2755 -o news -g news -d $(SPOOLDIR)
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/data
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/lock
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/requested
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/outgoing
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/overview
+	chown -R news.news $(SPOOLDIR)
+	$(INSTALL) -m 755 -o 0 -g 0 -d $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/AUTHORS $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/COPYING $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/ChangeLog $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/INSTALL $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/NEWS $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/README $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/TODO $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/noffle.conf.example \
+                                  /etc/noffle.conf.example
+	chown news.news /etc/noffle.conf.example
+	chmod 600 /etc/noffle.conf.example
+	@echo
+	@echo "****************************************************************"
+	@echo "You should now copy /etc/noffle.conf.example to /etc/noffle.conf"
+	@echo "and edit that copy."
+	@echo "****************************************************************"
+	@echo
+
+install-exec-local:
+	chown news.news $(bindir)/$(PACKAGE)
+	chmod 4755 $(bindir)/$(PACKAGE)
+
+uninstall-local:
+	rm -f $(DOCDIR)/AUTHORS
+	rm -f $(DOCDIR)/COPYING
+	rm -f $(DOCDIR)/ChangeLog
+	rm -f $(DOCDIR)/INSTALL
+	rm -f $(DOCDIR)/NEWS
+	rm -f $(DOCDIR)/README
+	rm -f $(DOCDIR)/TODO
+	rm -f /etc/noffle.conf.example
+	@echo
+	@echo "****************************************************************"
+	@echo "The NOFFLE spool directory $(SPOOLDIR) and the configfile"
+	@echo "$(CONFIGFILE) have *not* been removed. Please do this"
+	@echo "manually."
+	@echo "****************************************************************"
+	@echo
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.in	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,408 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Process this file with automake to produce Makefile.in
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CONFIGFILE = @CONFIGFILE@
+DOCDIR = @DOCDIR@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+SPOOLDIR = @SPOOLDIR@
+VERSION = @VERSION@
+
+SUBDIRS = src docs
+
+EXTRA_DIST = $(PACKAGE).conf.example
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  README ./stamp-h.in AUTHORS COPYING ChangeLog INSTALL \
+Makefile.am Makefile.in NEWS TODO acconfig.h aclocal.m4 config.h.in \
+configure configure.in install-sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+	cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+	@if test ! -f $@; then \
+		rm -f stamp-h; \
+		$(MAKE) stamp-h; \
+	else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES= CONFIG_HEADERS=config.h \
+	     $(SHELL) ./config.status
+	@echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+	@if test ! -f $@; then \
+		rm -f $(srcdir)/stamp-h.in; \
+		$(MAKE) $(srcdir)/stamp-h.in; \
+	else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+	cd $(top_srcdir) && $(AUTOHEADER)
+	@echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+	-rm -f config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  test "$$subdir" = "." && dot_seen=yes; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	here=`cd $(top_builddir) && pwd`; \
+	top_distdir=`cd $(distdir) && pwd`; \
+	distdir=`cd $(distdir) && pwd`; \
+	cd $(top_srcdir) \
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+	for subdir in $(SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+all-recursive-am: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-exec-local
+install-exec: install-exec-recursive
+
+install-data-am: install-data-local
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am: uninstall-local
+uninstall: uninstall-recursive
+all-am: Makefile config.h
+all-redirect: all-recursive-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-hdr clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-hdr distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+	-rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
+install-exec-local install-exec-am install-exec install-data-local \
+install-data-am install-data install-am install uninstall-local \
+uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+install-data-local:
+	$(INSTALL) -m 2755 -o news -g news -d $(SPOOLDIR)
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/data
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/lock
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/requested
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/outgoing
+	$(INSTALL) -o news -g news -d $(SPOOLDIR)/overview
+	chown -R news.news $(SPOOLDIR)
+	$(INSTALL) -m 755 -o 0 -g 0 -d $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/AUTHORS $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/COPYING $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/ChangeLog $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/INSTALL $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/NEWS $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/README $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/TODO $(DOCDIR)
+	$(INSTALL_DATA) -o 0 -g 0 $(srcdir)/noffle.conf.example \
+                                  /etc/noffle.conf.example
+	chown news.news /etc/noffle.conf.example
+	chmod 600 /etc/noffle.conf.example
+	@echo
+	@echo "****************************************************************"
+	@echo "You should now copy /etc/noffle.conf.example to /etc/noffle.conf"
+	@echo "and edit that copy."
+	@echo "****************************************************************"
+	@echo
+
+install-exec-local:
+	chown news.news $(bindir)/$(PACKAGE)
+	chmod 4755 $(bindir)/$(PACKAGE)
+
+uninstall-local:
+	rm -f $(DOCDIR)/AUTHORS
+	rm -f $(DOCDIR)/COPYING
+	rm -f $(DOCDIR)/ChangeLog
+	rm -f $(DOCDIR)/INSTALL
+	rm -f $(DOCDIR)/NEWS
+	rm -f $(DOCDIR)/README
+	rm -f $(DOCDIR)/TODO
+	rm -f /etc/noffle.conf.example
+	@echo
+	@echo "****************************************************************"
+	@echo "The NOFFLE spool directory $(SPOOLDIR) and the configfile"
+	@echo "$(CONFIGFILE) have *not* been removed. Please do this"
+	@echo "manually."
+	@echo "****************************************************************"
+	@echo
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/acconfig.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,25 @@
+/* For use by autoheader */
+
+#ifndef CONFIG_H
+#define CONFIG_H    /* To stop multiple inclusions. */
+
+/* The NOFFLE config-file */
+#undef CONFIGFILE
+
+/* The default NOFFLE spool-directory */
+#undef SPOOLDIR
+
+/* Enable GNU extensions. */
+#undef _GNU_SOURCE
+
+/* Define to 'unsigned int' if not already defined by the system. */
+#undef socklen_t
+
+
+@TOP@
+/* autoheader generated things inserted here. */
+@BOTTOM@
+
+
+#endif /* CONFIG_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aclocal.m4	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,127 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
--- a/client.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,883 +0,0 @@
-/*
-  client.c
-
-  $Id: client.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include "client.h"
-
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include "config.h"
-#include "content.h"
-#include "dynamicstring.h"
-#include "group.h"
-#include "log.h"
-#include "over.h"
-#include "protocol.h"
-#include "pseudo.h"
-#include "request.h"
-#include "util.h"
-#include "wildmat.h"
-
-/*
-  Some newsgroups names are reserved for server-specific or server
-  pseudo groups. We don't want to fetch them. For example, INN
-  keeps all its control messages in a 'control' hierarchy, and
-  used the "to." heirarchy for dark and mysterious purposes I think
-  are to do with newsfeeds. The recommended restrictions are documented
-  in C.Lindsay, "News Article Format", <draft-ietf-usefor-article-03.txt>.
-*/
-
-struct ForbiddenGroupName
-{
-    const char *pattern;
-    Bool match;
-} forbiddenGroupNames[] =
-{
-    { "*.*", FALSE },			/* Single component */
-    { "control.*", TRUE },		/* control.* groups */
-    { "to.*", TRUE },			/* control.* groups */
-    { "*.all", TRUE },			/* 'all' as a component */
-    { "*.all.*", TRUE },
-    { "all.*", TRUE },
-    { "*.ctl", TRUE },			/* 'ctl' as a component */
-    { "*.ctl.*", TRUE },
-    { "ctl.*", TRUE }
-};
-
-struct
-{
-    FILE* in;     /* Receiving socket from server */
-    FILE* out;    /* Sending socket to server */
-    Str lastCmd;  /* Last command line */
-    Str lastStat; /* Response from server to last command */
-    Str grp;      /* Selected group */
-    int rmtFirst;  /* First article of current group at server */
-    int rmtLast;   /* Last article of current group at server */
-    Bool auth;    /* Authetication already done? */
-    Str serv;     /* Remote server name */
-} client = { NULL, NULL, "", "", "", 1, 0, FALSE, "" };
-
-static void
-logBreakDown( void )
-{
-    Log_err( "Connection to remote server lost "
-             "(article numbers could be inconsistent)" );
-}
-
-static Bool
-getLn( Str line )
-{
-    Bool r;
-
-    r = Prt_getLn( line, client.in );
-    if ( ! r )
-        logBreakDown();
-    return r; 
-}
-
-static Bool
-getTxtLn( Str line, Bool *err )
-{
-    Bool r;
-
-    r = Prt_getTxtLn( line, err, client.in );
-    if ( *err )
-        logBreakDown();
-    return r; 
-}
-
-static void
-putTxtBuf( const char *buf )
-{
-    Prt_putTxtBuf( buf, client.out );
-    fflush( client.out );
-    Log_dbg( "[S FLUSH]" );
-}
-
-static void
-putEndOfTxt( void )
-{
-    Prt_putEndOfTxt( client.out );
-    fflush( client.out );
-    Log_dbg( "[S FLUSH]" );
-}
-
-static Bool
-putCmd( const char *fmt, ... )
-{
-    Bool err;
-    unsigned int n;
-    Str line;
-    va_list ap;
-
-    va_start( ap, fmt );
-    vsnprintf( line, MAXCHAR, fmt, ap );
-    va_end( ap );
-    strcpy( client.lastCmd, line );
-    Log_dbg( "[S] %s", line );
-    n = fprintf( client.out, "%s\r\n", line );
-    fflush( client.out );
-    Log_dbg( "[S FLUSH]" );
-    err = ( n != strlen( line ) + 2 );
-    if ( err )
-        logBreakDown();;
-    return ! err;
-}
-
-static Bool
-putCmdNoFlush( const char *fmt, ... )
-{
-    Bool err;
-    unsigned int n;
-    Str line;
-    va_list ap;
-
-    va_start( ap, fmt );
-    vsnprintf( line, MAXCHAR, fmt, ap );
-    va_end( ap );
-    strcpy( client.lastCmd, line );
-    Log_dbg( "[S] %s", line );
-    n = fprintf( client.out, "%s\r\n", line );
-    err = ( n != strlen( line ) + 2 );
-    if ( err )
-        logBreakDown();;
-    return ! err;
-}
-
-static int getStat( void );
-
-static Bool
-performAuth( void )
-{
-    int stat;
-    Str user, pass;
-    
-    Cfg_authInfo( client.serv, user, pass );
-    if ( strcmp( user, "" ) == 0 )
-    {
-        Log_err( "No username for authentication set" );
-        return FALSE;
-    }    
-    putCmd( "AUTHINFO USER %s", user );
-    stat = getStat();
-    if ( stat == STAT_AUTH_ACCEPTED )
-        return TRUE;
-    else if ( stat != STAT_MORE_AUTH_REQUIRED )
-    {
-        Log_err( "Username rejected. Server stat: %s", client.lastStat );
-        return FALSE;
-    }    
-    if ( strcmp( pass, "" ) == 0 )
-    {
-        Log_err( "No password for authentication set" );
-        return FALSE;
-    }
-    putCmd( "AUTHINFO PASS %s", pass );
-    stat = getStat();
-    if ( stat != STAT_AUTH_ACCEPTED )
-    {
-        Log_err( "Password rejected. Server status: %s", client.lastStat );
-        return FALSE;
-    }    
-    return TRUE;    
-}
-
-static int
-getStat( void )
-{
-    int result;
-    Str lastCmd;
-
-    if ( ! getLn( client.lastStat ) )
-        result = STAT_PROGRAM_FAULT;
-    else if ( sscanf( client.lastStat, "%d", &result ) != 1 )
-    {
-        Log_err( "Invalid server status: %s", client.lastStat );
-        result = STAT_PROGRAM_FAULT;
-    }
-    if ( result == STAT_AUTH_REQUIRED && ! client.auth )
-    {
-        client.auth = TRUE;
-        strcpy( lastCmd, client.lastCmd );
-        if ( performAuth() )
-        {
-            putCmd( lastCmd );
-            return getStat();
-        }
-    }
-    return result;
-}
-
-static void
-connectAlarm( int sig )
-{
-    return;
-}
-
-static sig_t
-installSignalHandler( int sig, sig_t handler )
-{
-    struct sigaction act, oldAct;
-
-    act.sa_handler = handler;
-    sigemptyset( &act.sa_mask );
-    act.sa_flags = 0;
-    if ( sig == SIGALRM )
-        act.sa_flags |= SA_INTERRUPT;
-    else
-        act.sa_flags |= SA_RESTART;
-    if ( sigaction( sig, &act, &oldAct ) < 0 )
-        return SIG_ERR;
-    return oldAct.sa_handler;
-}
-
-static Bool
-connectWithTimeout( int sock, const struct sockaddr *servAddr,
-                    socklen_t addrLen )
-{
-    sig_t oldHandler;
-    int r, to;
-
-    oldHandler = installSignalHandler( SIGALRM, connectAlarm );
-    if ( oldHandler == SIG_ERR )
-    {
-        Log_err( "client.c:connectWithTimeout: signal failed." );
-        return FALSE;
-    }
-    to = Cfg_connectTimeout();
-    if ( alarm( to ) != 0 )
-        Log_err( "client.c:connectWithTimeout: Alarm was already set." );
-    r = connect( sock, servAddr, addrLen );
-    alarm( 0 );
-    installSignalHandler( SIGALRM, oldHandler );
-    return ( r >= 0 );
-}
-
-Bool
-Client_connect( const char *serv )
-{
-    unsigned short int port;
-    int sock, i;
-    unsigned int stat;
-    struct hostent *hp;
-    char *pStart, *pColon;
-    Str host, s;
-    struct sockaddr_in sIn;
-
-    client.auth = FALSE;
-    Utl_cpyStr( s, serv );
-    pStart = Utl_stripWhiteSpace( s );
-    pColon = strstr( pStart, ":" );
-    if ( pColon == NULL )
-    {
-        strcpy( host, pStart );
-        port = 119;
-    }
-    else
-    {
-        *pColon = '\0';
-        strcpy( host, pStart );
-        if ( sscanf( pColon + 1, "%hi", &port ) != 1 )
-        {
-            Log_err( "Syntax error in server name: '%s'", serv );
-            return FALSE;;
-        }
-        if ( port <= 0 || port > 65535 )
-        {
-            Log_err( "Invalid port number %hi. Must be in [1, 65535]", port );
-            return FALSE;;
-        }
-    }
-    memset( (void *)&sIn, 0, sizeof( sIn ) );
-    hp = gethostbyname( host );
-    if ( hp )
-    {
-        for ( i = 0; (hp->h_addr_list)[ i ]; ++i )
-        {
-            sIn.sin_family = hp->h_addrtype;
-            sIn.sin_port = htons( port );
-            sIn.sin_addr = *( (struct in_addr *)hp->h_addr_list[ i ] );
-            sock = socket( AF_INET, SOCK_STREAM, 0 );
-            if ( sock < 0 )
-                break;
-            if ( ! connectWithTimeout( sock, (struct sockaddr *)&sIn,
-                                       sizeof( sIn ) ) )
-            {
-                close( sock );
-                break;
-            }
-            if ( ! ( client.out = fdopen( sock, "w" ) )
-                 || ! ( client.in  = fdopen( dup( sock ), "r" ) ) )
-            {
-		if ( client.out != NULL )
-		    fclose( client.out );
-                close( sock );
-                break;
-            }
-            stat = getStat();
-	    if ( stat == STAT_READY_POST_ALLOW ||
-		 stat == STAT_READY_NO_POST_ALLOW )
-	    {
-		/* INN needs a MODE READER before it will permit POST. */
-		putCmd( "MODE READER" );
-		stat = getStat();
-	    }
-            switch( stat ) {
-            case STAT_READY_POST_ALLOW:
-            case STAT_READY_NO_POST_ALLOW: 
-                Log_inf( "Connected to %s:%d",
-                         inet_ntoa( sIn.sin_addr ), port );
-                Utl_cpyStr( client.serv, serv );
-                return TRUE;
-            default:
-                Log_err( "Bad server stat %d", stat ); 
-            }
-            shutdown( fileno( client.out ), 0 );
-	    fclose( client.in );
-	    fclose( client.out );
-	    close( sock );
-        }
-    }
-    return FALSE;
-}
-
-static Bool
-isForbiddenGroupName( const char *name )
-{
-    int i;
-
-    for ( i = 0;
-	  i < sizeof( forbiddenGroupNames ) /
-	      sizeof( struct ForbiddenGroupName );
-	  i++ )
-    {
-	/* Negate result of Wld_match to ensure it is 1 or 0. */
-	if ( forbiddenGroupNames[i].match !=
-	     ( ! Wld_match( name, forbiddenGroupNames[i].pattern ) ) )
-	    return TRUE;
-    }
-
-    return FALSE;
-}
-
-static void
-processGrps( void )
-{
-    char postAllow;
-    Bool err;
-    int first, last;
-    Str grp, line, file;
-    
-    while ( getTxtLn( line, &err ) && ! err )
-    {
-        if ( sscanf( line, "%s %d %d %c",
-                     grp, &last, &first, &postAllow ) != 4 )
-        {
-            Log_err( "Unknown reply to LIST or NEWGROUPS: %s", line );
-            continue;
-        }
-	if ( isForbiddenGroupName( grp ) )
-	{
-	    Log_inf( "Group %s forbidden", grp );
-	    continue;
-	}
-        if ( ! Grp_exists( grp ) )
-        {
-            Log_inf( "Registering new group '%s'", grp );
-            Grp_create( grp );
-            Grp_setRmtNext( grp, first );
-            Grp_setServ( grp, client.serv );
-	    Grp_setPostAllow( grp, postAllow );
-        }
-        else
-        {
-            if ( Cfg_servIsPreferential( client.serv, Grp_serv( grp ) ) )
-            {
-                Log_inf( "Changing server for '%s': '%s'->'%s'",
-                         grp, Grp_serv( grp ), client.serv );
-                Grp_setServ( grp, client.serv );
-                Grp_setRmtNext( grp, first );
-		Grp_setPostAllow( grp, postAllow );
-            }
-            else
-                Log_dbg( "Group %s is already fetched from %s",
-                           grp, Grp_serv( grp ) );
-            
-        }
-    }
-    if ( ! err )
-    {
-        snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
-        Utl_stamp( file );
-    }
-}
-
-void
-Client_disconnect( void )
-{
-    if ( putCmd( "QUIT" ) )
-        getStat();
-    fclose( client.in );
-    fclose( client.out );
-    client.in = client.out = NULL;
-}
-
-Bool
-Client_getGrps( void )
-{
-    if ( ! putCmd( "LIST ACTIVE" ) )
-        return FALSE;
-    if ( getStat() != STAT_GRPS_FOLLOW )
-    {
-        Log_err( "LIST ACTIVE command failed: %s", client.lastStat );
-        return FALSE;
-    }
-    processGrps();
-    return TRUE;
-}
-
-Bool
-Client_getDsc( void )
-{
-    Bool err;
-    Str name, line, dsc;
-
-    Log_inf( "Querying group descriptions" );
-    if ( ! putCmd( "LIST NEWSGROUPS" ) )
-        return FALSE;
-    if ( getStat() != STAT_GRPS_FOLLOW )
-    {
-        Log_err( "LIST NEWSGROUPS failed: %s", client.lastStat );
-        return FALSE;
-    }
-    while ( getTxtLn( line, &err ) && ! err )
-    {
-        if ( sscanf( line, "%s", name ) != 1 )
-        {
-            Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line );
-            continue;
-        }
-        strcpy( dsc, Utl_restOfLn( line, 1 ) );
-        if ( Grp_exists( name ) )
-        {
-            Log_dbg( "Description of %s: %s", name, dsc );
-            Grp_setDsc( name, dsc );
-        }
-    }
-    return TRUE;
-}
-
-Bool
-Client_getCreationTimes( void )
-{
-    Bool err;
-    Str name, line;
-    time_t t;
-
-    Log_inf( "Querying group creation times" );
-    if ( ! putCmd( "LIST ACTIVE.TIMES" ) )
-        return FALSE;
-    if ( getStat() != STAT_GRPS_FOLLOW )
-    {
-        Log_err( "LIST ACTIVE.TIMES failes: %s", client.lastStat );
-        return FALSE;
-    }
-    while ( getTxtLn( line, &err ) && ! err )
-    {
-        if ( sscanf( line, "%s %ld", name, &t ) != 2 )
-        {
-            Log_err( "Unknown reply to LIST ACTIVE.TIMES: %s", line );
-            continue;
-        }
-        if ( Grp_exists( name ) )
-        {
-            Log_inf( "Creation time of %s: %ld", name, t );
-            Grp_setCreated( name, t );
-        }
-    }
-    return TRUE;
-}
-
-Bool
-Client_getNewgrps( const time_t *lastTime )
-{
-    Str s;
-    const char *p;
-
-    ASSERT( *lastTime > 0 );
-    strftime( s, MAXCHAR, "%Y%m%d %H%M00", gmtime( lastTime ) );
-    /*
-      Do not use century for working with old server software until 2000.
-      According to newest IETF draft, this is still valid after 2000.
-      (directly using %y in fmt string causes a Y2K compiler warning)
-    */
-    p = s + 2;
-    if ( ! putCmd( "NEWGROUPS %s", p ) )
-        return FALSE;
-    if ( getStat() != STAT_NEW_GRP_FOLLOW )
-    {
-        Log_err( "NEWGROUPS command failed: %s", client.lastStat );
-        return FALSE;
-    }
-    processGrps();
-    return TRUE;
-}
-
-static const char *
-readField( Str result, const char *p )
-{
-    size_t len;
-    char *r;
-
-    if ( ! p )
-        return NULL;
-    r = result;
-    *r = '\0';
-    len = 0;
-    while ( *p != '\t' && *p != '\n' )
-    {
-        if ( ! *p )
-            return p;
-        *(r++) = *(p++);
-        ++len;
-        if ( len >= MAXCHAR - 1 )
-        {
-            *r = '\0';
-            Log_err( "Field in overview too long: %s", r );
-            return ++p;
-        }
-    }
-    *r = '\0';
-    return ++p;
-}
-
-static Bool
-parseOvLn( Str line, int *numb, Str subj, Str from,
-           Str date, Str msgId, Str ref, size_t *bytes, size_t *lines )
-{
-    const char *p;
-    Str t;
-    
-    p = readField( t, line );
-    if ( sscanf( t, "%d", numb ) != 1 )
-        return FALSE;
-    p = readField( subj, p );
-    p = readField( from, p );
-    p = readField( date, p );
-    p = readField( msgId, p );
-    p = readField( ref, p );
-    p = readField( t, p );
-    *bytes = 0;
-    *lines = 0;
-    if ( sscanf( t, "%d", bytes ) != 1 )
-        return TRUE;
-    p = readField( t, p );
-    if ( sscanf( t, "%d", lines ) != 1 )
-        return TRUE;
-    return TRUE;
-}
-
-static const char*
-nextXref( const char *pXref, Str grp, int *numb )
-{
-    Str s;
-    const char *pColon, *src;
-    char *dst;
-
-    src = pXref;
-    while ( *src && isspace( *src ) )
-        ++src;
-    dst = s;
-    while ( *src && ! isspace( *src ) )
-        *(dst++) = *(src++);
-    *dst = '\0';
-    if ( strlen( s ) == 0 )
-        return NULL;
-    pColon = strstr( s, ":" );
-    if ( ! pColon || sscanf( pColon + 1, "%d", numb ) != 1 )
-    {
-        Log_err( "Corrupt Xref at position '%s'", pXref );
-        return NULL;
-    }
-    Utl_cpyStrN( grp, s, pColon - s );
-    Log_dbg( "client.c: nextXref: grp '%s' numb %lu", grp, numb );
-    return src;
-}
-
-static Bool
-needsMark( const char *ref )
-{
-    Bool done = FALSE;
-    char *p;
-    Str msgId;
-    int stat, len;
-    time_t lastAccess, nowTime;
-    double limit;
-
-    nowTime = time( NULL );
-    limit = Cfg_threadFollowTime() * 24. * 3600.;
-    while ( ! done )
-    {
-        p = msgId;
-        while ( *ref != '<' )
-            if ( *(ref++) == '\0' )
-                return FALSE;
-        len = 0;
-        while ( *ref != '>' )
-        {
-            if ( *ref == '\0' || ++len >= MAXCHAR - 1 )
-                return FALSE;
-            *(p++) = *(ref++);
-        }
-        *(p++) = '>';
-        *p = '\0';
-        if ( Db_contains( msgId ) )
-        {
-            stat = Db_stat( msgId );
-            lastAccess = Db_lastAccess( msgId );
-            if ( ( stat & DB_INTERESTING )
-                 && difftime( nowTime, lastAccess ) <= limit )
-                return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-static void
-prepareEntry( Over *ov )
-{
-    Str g, t;
-    const char *msgId, *p, *xref;
-    int n;
-
-    msgId = Ov_msgId( ov );
-    if ( Pseudo_isGeneralInfo( msgId ) )
-        Log_dbg( "Skipping general info '%s'", msgId );
-    else if ( Db_contains( msgId ) )
-    {
-        xref = Db_xref( msgId );
-        Log_dbg( "Entry '%s' already in db with Xref '%s'", msgId, xref );
-        p = nextXref( xref, g, &n );
-        if ( p == NULL )
-            Log_err( "Overview with no group in Xref '%s'", msgId );
-        else
-        {
-            /* TODO: This code block seems unnessesary. Can we remove it? */
-            if ( Cfg_servIsPreferential( client.serv, Grp_serv( g ) ) )
-            {
-                Log_dbg( "Changing first server for '%s' from '%s' to '%s'",
-                         msgId, Grp_serv( g ), client.serv );
-                snprintf( t, MAXCHAR, "%s:%d %s",
-                          client.grp, Ov_numb( ov ), xref );
-                Db_setXref( msgId, t );
-            }
-            else
-            {
-                Log_dbg( "Adding '%s' to Xref of '%s'", g, msgId );
-                snprintf( t, MAXCHAR, "%s %s:%d",
-                          xref, client.grp, Ov_numb( ov ) );
-                Db_setXref( msgId, t );
-            }
-        }
-    }
-    else
-    {
-        Log_dbg( "Preparing '%s' in database", msgId );
-        Db_prepareEntry( ov, client.grp, Ov_numb( ov ) );
-    }
-}
-
-Bool
-Client_getOver( int rmtFirst, int rmtLast, FetchMode mode )
-{
-    Bool err;
-    size_t bytes, lines;
-    int rmtNumb, oldLast, cntMarked;
-    Over *ov;
-    Str line, subj, from, date, msgId, ref;
-
-    ASSERT( strcmp( client.grp, "" ) != 0 );
-    if ( ! putCmd( "XOVER %lu-%lu", rmtFirst, rmtLast ) )
-        return FALSE;
-    if ( getStat() != STAT_OVERS_FOLLOW )
-    {
-        Log_err( "XOVER command failed: %s", client.lastStat );
-        return FALSE;
-    }
-    Log_dbg( "Requesting overview for remote %lu-%lu", rmtFirst, rmtLast );
-    oldLast = Cont_last();
-    cntMarked = 0;
-    while ( getTxtLn( line, &err ) && ! err )
-    {
-        if ( ! parseOvLn( line, &rmtNumb, subj, from, date, msgId, ref,
-                          &bytes, &lines ) )
-            Log_err( "Bad overview line: %s", line );
-        else
-        {
-            ov = new_Over( subj, from, date, msgId, ref, bytes, lines );
-            Cont_app( ov );
-            prepareEntry( ov );
-            if ( mode == FULL || ( mode == THREAD && needsMark( ref ) ) )
-            {
-                Req_add( client.serv, msgId );
-                ++cntMarked;
-            }
-        }
-        Grp_setRmtNext( client.grp, rmtNumb + 1 );
-    }
-    if ( oldLast != Cont_last() )
-        Log_inf( "Added %s %lu-%lu", client.grp, oldLast + 1, Cont_last() );
-    Log_inf( "%u articles marked for download in %s", cntMarked, client.grp  );
-    return err;
-}
-
-static void
-retrievingFailed( const char* msgId, const char *reason )
-{
-    int stat;
-
-    Log_err( "Retrieving of %s failed: %s", msgId, reason );
-    stat = Db_stat( msgId );
-    Pseudo_retrievingFailed( msgId, reason );
-    Db_setStat( msgId, stat | DB_RETRIEVING_FAILED );
-}
-
-static Bool
-retrieveAndStoreArt( const char *msgId )
-{
-    Bool err;
-    DynStr *s = NULL;
-    Str line;
-
-    Log_inf( "Retrieving %s", msgId );
-    s = new_DynStr( 5000 );
-    while ( getTxtLn( line, &err ) && ! err )
-        DynStr_appLn( s, line );
-    if ( ! err )
-        Db_storeArt( msgId, DynStr_str( s ) );
-    else
-        retrievingFailed( msgId, "Connection broke down" );
-    del_DynStr( s );
-    return ! err;
-}
-
-void
-Client_retrieveArt( const char *msgId )
-{
-    if ( ! Db_contains( msgId ) )
-    {
-        Log_err( "Article '%s' not prepared in database. Skipping.", msgId );
-        return;
-    }
-    if ( ! ( Db_stat( msgId ) & DB_NOT_DOWNLOADED ) )
-    {
-        Log_inf( "Article '%s' already retrieved. Skipping.", msgId );
-        return;
-    }
-    if ( ! putCmd( "ARTICLE %s", msgId ) )
-        retrievingFailed( msgId, "Connection broke down" );
-    else if ( getStat() != STAT_ART_FOLLOWS )
-        retrievingFailed( msgId, client.lastStat );
-    else
-        retrieveAndStoreArt( msgId );
-}
-
-void
-Client_retrieveArtList( const char *list )
-{
-    Str msgId;
-    DynStr *s;
-    const char *p;
-    
-    Log_inf( "Retrieving article list" );
-    s = new_DynStr( strlen( list ) );
-    p = list;
-    while ( ( p = Utl_getLn( msgId, p ) ) )
-        if ( ! Db_contains( msgId ) )
-            Log_err( "Skipping retrieving of %s (not prepared in database)",
-                     msgId );
-        else if ( ! ( Db_stat( msgId ) & DB_NOT_DOWNLOADED ) )
-            Log_inf( "Skipping %s (already retrieved)", msgId );
-        else if ( ! putCmdNoFlush( "ARTICLE %s", msgId ) )
-        {
-            retrievingFailed( msgId, "Connection broke down" );
-            del_DynStr( s );
-            return;
-        }
-        else
-            DynStr_appLn( s, msgId );
-    fflush( client.out );
-    Log_dbg( "[S FLUSH]" );
-    p = DynStr_str( s );
-    while ( ( p = Utl_getLn( msgId, p ) ) )
-    {
-        if ( getStat() != STAT_ART_FOLLOWS )
-            retrievingFailed( msgId, client.lastStat );
-        else if ( ! retrieveAndStoreArt( msgId ) )
-            break;
-    }
-    del_DynStr( s );
-}
-
-Bool
-Client_changeToGrp( const char* name )
-{
-    unsigned int stat;
-    int estimatedNumb, first, last;
-
-    if ( ! Grp_exists( name ) )
-        return FALSE;
-    if ( ! putCmd( "GROUP %s", name ) )
-        return FALSE;
-    if ( getStat() != STAT_GRP_SELECTED )
-        return FALSE;
-    if ( sscanf( client.lastStat, "%u %d %d %d",
-                 &stat, &estimatedNumb, &first, &last ) != 4 )
-    {
-        Log_err( "Bad server response to GROUP: %s", client.lastStat );
-        return FALSE;
-    }
-    Utl_cpyStr( client.grp, name );
-    client.rmtFirst = first;
-    client.rmtLast = last;
-    return TRUE;
-}
-
-void
-Client_rmtFirstLast( int *first, int *last )
-{
-    *first = client.rmtFirst;
-    *last = client.rmtLast;
-}
-
-Bool
-Client_postArt( const char *msgId, const char *artTxt,
-                    Str errStr )
-{
-    if ( ! putCmd( "POST" ) )
-        return FALSE;
-    if ( getStat() != STAT_SEND_ART )
-    {
-        Log_err( "Posting of %s not allowed: %s", msgId, client.lastStat );
-        strcpy( errStr, client.lastStat );
-        return FALSE;
-    }
-    putTxtBuf( artTxt );
-    putEndOfTxt();
-    if ( getStat() != STAT_POST_OK )
-    {
-        Log_err( "Posting of %s failed: %s", msgId, client.lastStat );
-        strcpy( errStr, client.lastStat );
-        return FALSE;
-    }
-    Log_inf( "Posted %s (Status: %s)", msgId, client.lastStat );
-    return TRUE;
-}
--- a/client.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
-  client.h
-
-  Noffle acting as client to other NNTP-servers
-
-  $Id: client.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef CLIENT_H
-#define CLIENT_H
-
-#include <time.h>
-#include "common.h"
-#include "database.h"
-#include "fetchlist.h"
-
-/* Format of server name: <host>[:<port>] */
-Bool
-Client_connect( const char *serv );
-
-void
-Client_disconnect( void );
-
-Bool
-Client_getGrps( void );
-
-Bool
-Client_getDsc( void );
-
-Bool
-Client_getCreationTimes( void );
-
-Bool
-Client_getNewgrps( const time_t *lastTime );
-
-/*
-  Change to group <name> at server if it is also in current local grouplist.
-  Returns TRUE at success.
-*/
-Bool
-Client_changeToGrp( const Str name );
-
-/*
-  Get overviews <rmtFirst> - <rmtLast> from server and append it
-  to the current content. For articles that are to be fetched due to FULL
-  or THREAD mode, store IDs in request database.
-*/
-Bool
-Client_getOver( int rmtFirst, int rmtLast, FetchMode mode );
-
-/*
-  Retrieve full article text and store it into database.
-*/
-void
-Client_retrieveArt( const char *msgId );
-
-/*
-  Same, but for a list of msgId's (new line after each msgId).
-  All ARTICLE commands are sent and then all answers read.
-*/
-void
-Client_retrieveArtList( const char *list );
-
-/*
-  Store IDs of first and last article of group selected by
-  Client_changeToGroup at remote server. 
-*/
-void
-Client_rmtFirstLast( int *first, int *last );
-
-Bool
-Client_postArt( const char *msgId, const char *artTxt, Str errStr );
-
-#endif
--- a/common.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
-  common.h
-
-  Common declarations.
-
-  $Id: common.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef COMMON_H
-#define COMMON_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define FALSE 0
-#define TRUE !0
-#define MAXCHAR 2048
-
-#ifdef DEBUG
-#include <assert.h>
-#define ASSERT( x ) \
-    if ( ! ( x ) ) \
-        Log_err( "ASSERTION FAILED: %s line %i", __FILE__, __LINE__ ); \
-    assert( x )
-#else
-#define ASSERT( x )
-#endif
-
-typedef int Bool;
-typedef char Str[ MAXCHAR ];
-
-#endif
--- a/config.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,396 +0,0 @@
-/*
-  config.c
-
-  The following macros must be set, when compiling this file:
-    CONFIGFILE
-    SPOOLDIR
-    VERSION
-
-  $Id: config.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include "config.h"
-
-#include <limits.h>
-#include "log.h"
-#include "util.h"
-
-typedef struct
-{
-    Str name;
-    Str user;
-    Str pass;
-}
-ServEntry;
-
-typedef struct
-{
-    Str pattern;
-    int days;
-}
-ExpireEntry;
-
-struct
-{
-    /* Compile time options */
-    const char *spoolDir;
-    const char *version;
-    /* Options from the config file */
-    int maxFetch;
-    int autoUnsubscribeDays;
-    int threadFollowTime;
-    int connectTimeout;
-    Bool autoSubscribe;
-    Bool autoUnsubscribe;
-    Bool removeMsgId;
-    Bool replaceMsgId;
-    Str autoSubscribeMode;
-    Str mailTo;
-    int defaultExpire;
-    int numServ;
-    int maxServ;
-    ServEntry *serv;
-    int servIdx; /* for server enumeration */
-    int numExpire;
-    int maxExpire;
-    ExpireEntry *expire;
-    int expireIdx;
-} config =
-{
-    SPOOLDIR, /* spoolDir */
-    VERSION,  /* version */
-    300,      /* maxFetch */
-    30,       /* autoUnsubscribeDays */
-    7,        /* threadFollowTime */
-    30,       /* connectTimeout */
-    FALSE,    /* autoSubscribe */
-    FALSE,    /* autoUnsubscribe */
-    FALSE,    /* removeMsgId */
-    TRUE,     /* replaceMsgId */
-    "over",   /* autoSubscribeMode */
-    "",       /* mailTo */
-    14,       /* defaultExpire */
-    0,        /* numServ */
-    0,        /* maxServ */
-    NULL,     /* serv */
-    0,	      /* servIdx */
-    0,        /* numExpire */
-    0,        /* maxExpire */
-    NULL,     /* expire */
-    0         /* expireIdx */
-};
-
-const char * Cfg_spoolDir( void ) { return config.spoolDir; }
-const char * Cfg_version( void ) { return config.version; }
-
-int Cfg_maxFetch( void ) { return config.maxFetch; }
-int Cfg_autoUnsubscribeDays( void ) { return config.autoUnsubscribeDays; }
-int Cfg_threadFollowTime( void ) { return config.threadFollowTime; }
-int Cfg_connectTimeout( void ) { return config.connectTimeout; }
-Bool Cfg_autoUnsubscribe( void ) { return config.autoUnsubscribe; }
-Bool Cfg_autoSubscribe( void )  { return config.autoSubscribe; }
-Bool Cfg_removeMsgId( void ) { return config.removeMsgId; }
-Bool Cfg_replaceMsgId( void ) { return config.replaceMsgId; }
-const char * Cfg_autoSubscribeMode( void ) {
-    return config.autoSubscribeMode; }
-const char * Cfg_mailTo( void ) { return config.mailTo; }
-int Cfg_expire( void ) { return config.defaultExpire; }
-
-void
-Cfg_beginServEnum( void )
-{
-    config.servIdx = 0;
-}
-
-Bool
-Cfg_nextServ( Str name )
-{
-    if ( config.servIdx >= config.numServ )
-        return FALSE;
-    strcpy( name, config.serv[ config.servIdx ].name );
-    ++config.servIdx;
-    return TRUE;
-}
-
-static Bool
-searchServ( const char *name, int *idx )
-{
-    int i;
-
-    for ( i = 0; i < config.numServ; ++i )
-        if ( strcmp( name, config.serv[ i ].name ) == 0 )
-        {
-            *idx = i;
-            return TRUE;
-        }
-    return FALSE;
-}
-
-Bool
-Cfg_servListContains( const char *name )
-{
-    int idx;
-
-    return searchServ( name, &idx );
-}
-
-Bool
-Cfg_servIsPreferential( const char *name1, const char *name2 )
-{
-    Bool exists1, exists2;
-    int idx1, idx2;
-
-    exists1 = searchServ( name1, &idx1 );
-    exists2 = searchServ( name2, &idx2 );
-    if ( exists1 && exists2 )
-        return ( idx1 < idx2 );
-    if ( exists1 && ! exists2 )
-        return TRUE;
-    /* ( ! exists1 && exists2 ) || ( ! exists1 && ! exists2 ) */
-    return FALSE;
-}
-
-void
-Cfg_authInfo( const char *name, Str user, Str pass )
-{
-    int idx;
-
-    if ( searchServ( name, &idx ) )
-    {
-        strcpy( user, config.serv[ idx ].user );
-        strcpy( pass, config.serv[ idx ].pass );
-    }
-    else
-    {
-        user[ 0 ] = '\0';
-        pass[ 0 ] = '\0';
-    }
-}
-
-void
-Cfg_beginExpireEnum( void )
-{
-    config.expireIdx = 0;
-}
-
-int
-Cfg_nextExpire( Str pattern )
-{
-    if ( config.expireIdx >= config.numExpire )
-        return -1;
-    strcpy( pattern, config.expire[ config.expireIdx ].pattern );
-    return config.expire[ config.expireIdx++ ].days;
-}
-
-static void
-logSyntaxErr( const char *line )
-{
-    Log_err( "Syntax error in config file: %s", line );
-}
-
-static void
-getBool( Bool *variable, const char *line )
-{
-    Str value, name, lowerLn;
-
-    strcpy( lowerLn, line );
-    Utl_toLower( lowerLn );
-    if ( sscanf( lowerLn, "%s %s", name, value ) != 2 )
-    {
-        logSyntaxErr( line );
-        return;
-    }
-    
-    if ( strcmp( value, "yes" ) == 0 )
-        *variable = TRUE;
-    else if ( strcmp( value, "no" ) == 0 )
-        *variable = FALSE;
-    else
-        Log_err( "Error in config file %s must be yes or no", name );
-}
-
-static void
-getInt( int *variable, int min, int max, const char *line )
-{
-    int value;
-    Str name;
-
-    if ( sscanf( line, "%s %d", name, &value ) != 2 )
-    {
-        logSyntaxErr( line );
-        return;
-    }
-    if ( value < min || value > max )
-    {
-        Log_err( "Range error in config file %s [%d,%d]", name, min, max );
-        return;
-    }
-    *variable = value;
-}
-
-static void
-getStr( char *variable, const char *line )
-{
-    Str dummy;
-
-    if ( sscanf( line, "%s %s", dummy, variable ) != 2 )
-    {
-        logSyntaxErr( line );
-        return;
-    }
-}
-
-static void
-getServ( const char *line )
-{
-    Str dummy;
-    int r, len;
-    ServEntry entry;
-
-    entry.user[ 0 ] = '\0';
-    entry.pass[ 0 ] = '\0';
-    r = sscanf( line, "%s %s %s %s",
-                dummy, entry.name, entry.user, entry.pass );
-    if ( r < 2 )
-    {
-        logSyntaxErr( line );
-        return;
-    }
-    len = strlen( entry.name );
-    /* To make server name more definit, it is made lowercase and
-       port is removed, if it is the default port */
-    if ( len > 4 && strcmp( entry.name + len - 4, ":119" ) == 0 )
-        entry.name[ len - 4 ] = '\0';
-    Utl_toLower( entry.name );
-
-    if ( config.maxServ < config.numServ + 1 )
-    {
-        if ( ! ( config.serv = realloc( config.serv,
-                                        ( config.maxServ + 5 )
-                                        * sizeof( ServEntry ) ) ) )
-        {
-            Log_err( "Could not realloc server list" );
-            exit( EXIT_FAILURE );
-        }
-        config.maxServ += 5;
-    }
-    config.serv[ config.numServ++ ] = entry;
-}
-
-static void
-getExpire( const char *line )
-{
-    Str dummy;
-    ExpireEntry entry;
-    int days;
-
-    /*
-      The line is either "expire <num>" or "expire <pat> <num>".
-      The former updates the overall default.
-     */
-    if ( sscanf( line, "%s %s %d", dummy, entry.pattern, &days ) != 3 )
-    {
-	logSyntaxErr( line );
-	return;
-    }
-    else
-    {
-	if ( days < 0 )
-	{
-	    Log_err( "Expire days error in '%s': must be integer > 0",
-		     line, days );
-	    return;
-	}
-
-	Utl_toLower( entry.pattern );
-	entry.days = days;
-
-	if ( config.maxExpire < config.numExpire + 1 )
-	{
-	    if ( ! ( config.expire = realloc( config.expire,
-					      ( config.maxExpire + 5 )
-					      * sizeof( ExpireEntry ) ) ) )
-	    {
-		Log_err( "Could not realloc exipre list" );
-		exit( EXIT_FAILURE );
-	    }
-	    config.maxExpire += 5;
-	}
-	config.expire[ config.numExpire++ ] = entry;
-    }
-}
-
-void
-Cfg_read( void )
-{
-    char *p;
-    FILE *f;
-    Str file, line, lowerLine, name, s;
-
-    snprintf( file, MAXCHAR, CONFIGFILE );
-    if ( ! ( f = fopen( file, "r" ) ) )
-    {
-        Log_err( "Cannot read %s", file );
-        return;
-    }
-    while ( fgets( line, MAXCHAR, f ) )
-    {
-        p = Utl_stripWhiteSpace( line );
-	Utl_stripComment( p );
-        Utl_cpyStr( lowerLine, p );
-        Utl_toLower( lowerLine );
-        if ( *p == '\0' )
-            continue;
-        if ( sscanf( p, "%s", name ) != 1 )
-            Log_err( "Syntax error in %s: %s", file, line );
-        else if ( strcmp( "max-fetch", name ) == 0 )
-            getInt( &config.maxFetch, 0, INT_MAX, p );
-        else if ( strcmp( "auto-unsubscribe-days", name ) == 0 )
-            getInt( &config.autoUnsubscribe, -1, INT_MAX, p );
-        else if ( strcmp( "thread-follow-time", name ) == 0 )
-            getInt( &config.threadFollowTime, 0, INT_MAX, p );
-        else if ( strcmp( "connect-timeout", name ) == 0 )
-            getInt( &config.connectTimeout, 0, INT_MAX, p );
-        else if ( strcmp( "default-expire", name ) == 0 )
-            getInt( &config.defaultExpire, 0, INT_MAX, p );
-        else if ( strcmp( "auto-subscribe", name ) == 0 )
-            getBool( &config.autoSubscribe, p );
-        else if ( strcmp( "auto-unsubscribe", name ) == 0 )
-            getBool( &config.autoUnsubscribe, p );
-        else if ( strcmp( "remove-messageid", name ) == 0 )
-            getBool( &config.removeMsgId, p );
-        else if ( strcmp( "replace-messageid", name ) == 0 )
-            getBool( &config.replaceMsgId, p );
-        else if ( strcmp( "auto-subscribe-mode", name ) == 0 )
-        {
-            getStr( s, p );
-            Utl_toLower( s );
-            if ( strcmp( s, "full" ) != 0
-                 && strcmp( s, "thread" ) != 0
-                 && strcmp( s, "over" ) != 0
-                 && strcmp( s, "off" ) != 0 )
-            {
-                Log_err( "Syntax error in config file: %s", line );
-                return;
-            }
-            else
-                strcpy( config.autoSubscribeMode, s );
-        }
-        else if ( strcmp( "server", name ) == 0 )
-            /* Server needs line not p,
-               because password may contain uppercase */
-            getServ( line );
-        else if ( strcmp( "mail-to", name ) == 0 )
-            getStr( config.mailTo, p );
-        else if ( strcmp( "expire", name ) == 0 )
-            getExpire( p );
-        else
-            Log_err( "Unknown config option: %s", name );
-    }
-    fclose( f );
-    if ( ! config.numServ )
-    {
-        Log_err( "Config file contains no server" );
-        exit( EXIT_FAILURE );
-    }
-}
--- a/config.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
-  config.h
-
-  Common declarations and handling of the configuration file.
-
-  $Id: config.h 44 2000-05-05 07:23:15Z enz $
-*/
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-#include "common.h"
-
-const char * Cfg_spoolDir( void );
-const char * Cfg_version( void );
-
-int Cfg_maxFetch( void );
-int Cfg_autoUnsubscribeDays( void );
-int Cfg_threadFollowTime( void );
-int Cfg_connectTimeout( void );
-Bool Cfg_autoUnsubscribe( void );
-Bool Cfg_autoSubscribe( void );
-Bool Cfg_removeMsgId( void );
-Bool Cfg_replaceMsgId( void );
-const char * Cfg_autoSubscribeMode( void ); /* Can be: full, thread, over */
-const char * Cfg_mailTo( void );
-
-/* Begin iteration through the server names */
-void Cfg_beginServEnum( void );
-
-/* Save next server name in "name". Return TRUE if name has been was saved.
-   Return FALSE if there are no more server names. */
-Bool Cfg_nextServ( Str name );
-
-Bool Cfg_servListContains( const char *name );
-/* Prefer server earlier in config file. Known servers are always preferential
-   to unknown servers. */
-Bool Cfg_servIsPreferential( const char *name1, const char *name2 );
-void Cfg_authInfo( const char *name, Str user, Str pass );
-
-/* Begin iteration through expire entries. */
-void Cfg_beginExpireEnum( void );
-
-/* Put next expire pattern in "pattern" and return its days count.
-   Return -1 if no more expire patterns. */
-int Cfg_nextExpire( Str pattern );
-
-/* Return default expire days. */
-int Cfg_expire( void );
-
-void Cfg_read( void );
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.h.in	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,176 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+/* For use by autoheader */
+
+#ifndef CONFIG_H
+#define CONFIG_H    /* To stop multiple inclusions. */
+
+/* The NOFFLE config-file */
+#undef CONFIGFILE
+
+/* The default NOFFLE spool-directory */
+#undef SPOOLDIR
+
+/* Enable GNU extensions. */
+#undef _GNU_SOURCE
+
+/* Define to 'unsigned int' if not already defined by the system. */
+#undef socklen_t
+
+
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define if your system has a working fnmatch function.  */
+#undef HAVE_FNMATCH
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* 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
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define if you have the __snprintf function.  */
+#undef HAVE___SNPRINTF
+
+/* Define if you have the __vsnprintf function.  */
+#undef HAVE___VSNPRINTF
+
+/* Define if you have the fdopen function.  */
+#undef HAVE_FDOPEN
+
+/* Define if you have the gethostname function.  */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the mkdir function.  */
+#undef HAVE_MKDIR
+
+/* Define if you have the mktime function.  */
+#undef HAVE_MKTIME
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the snprintf function.  */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the socket function.  */
+#undef HAVE_SOCKET
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the uname function.  */
+#undef HAVE_UNAME
+
+/* Define if you have the vsnprintf function.  */
+#undef HAVE_VSNPRINTF
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <errno.h> header file.  */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <fnmatch.h> header file.  */
+#undef HAVE_FNMATCH_H
+
+/* Define if you have the <gdbm.h> header file.  */
+#undef HAVE_GDBM_H
+
+/* Define if you have the <getopt.h> header file.  */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <netdb.h> header file.  */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <signal.h> header file.  */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/resource.h> header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/socket.h> header file.  */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/utsname.h> header file.  */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define if you have the <syslog.h> header file.  */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <time.h> header file.  */
+#undef HAVE_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the gdbm library (-lgdbm).  */
+#undef HAVE_LIBGDBM
+
+/* Define if you have the nsl library (-lnsl).  */
+#undef HAVE_LIBNSL
+
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
+
+
+#endif /* CONFIG_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configure	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,2902 @@
+#! /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
+
+NOFFLE options:
+  --enable-debug          turn on debugging (default=yes)"
+ac_help="$ac_help
+  --with-docdir=PATH      specify where to put the documentation
+"
+
+# 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=src/noffle.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
+
+
+
+
+
+PACKAGE=noffle
+VERSION=1.0pre6
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:572: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:625: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:682: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=$PACKAGE
+
+VERSION=$VERSION
+
+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; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:728: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:741: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:754: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:767: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:780: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+cat >> confdefs.h <<\EOF
+#define _GNU_SOURCE 1
+EOF
+
+
+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
+
+
+
+
+# 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:813: 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:843: 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:894: 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:926: 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 937 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:942: \"$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:968: 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:973: 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:982: \"$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:1001: 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:1033: 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 1048 "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:1054: \"$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 1065 "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:1071: \"$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 1082 "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:1088: \"$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
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1114: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 1120 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 1138 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1171: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1224: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1254: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1256 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1278: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1300: checking for minix/config.h" >&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 1305 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1310: \"$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
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+
+
+
+# Whenever both -lsocket and -lnsl are needed, it seems to be always the
+# case that gethostbyname requires -lnsl.  So, check -lnsl first, for it
+# to be in LIBS before the setsockopt checks are performed.  *However*,
+# on SINIX-N 5.43, this is false, and gethostent seems to be a better
+# candidate. So, let's use it below instead of gethostbyname, and see.
+
+# [ This is ripped from GNU tar. ]
+
+echo $ac_n "checking for gethostent""... $ac_c" 1>&6
+echo "configure:1359: checking for gethostent" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostent'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1364 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostent(); 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 gethostent();
+
+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_gethostent) || defined (__stub___gethostent)
+choke me
+#else
+gethostent();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1387: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostent=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostent=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostent`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test $ac_cv_func_gethostent = no; then
+  echo $ac_n "checking for gethostent in -lnsl""... $ac_c" 1>&6
+echo "configure:1408: checking for gethostent in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostent | 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="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1416 "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 gethostent();
+
+int main() {
+gethostent()
+; return 0; }
+EOF
+if { (eval echo configure:1427: \"$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
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+echo $ac_n "checking for setsockopt""... $ac_c" 1>&6
+echo "configure:1456: checking for setsockopt" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setsockopt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1461 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setsockopt(); 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 setsockopt();
+
+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_setsockopt) || defined (__stub___setsockopt)
+choke me
+#else
+setsockopt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1484: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setsockopt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setsockopt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setsockopt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test $ac_cv_func_setsockopt = no; then
+  echo $ac_n "checking for setsockopt in -lsocket""... $ac_c" 1>&6
+echo "configure:1505: checking for setsockopt in -lsocket" >&5
+ac_lib_var=`echo socket'_'setsockopt | 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="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1513 "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 setsockopt();
+
+int main() {
+setsockopt()
+; return 0; }
+EOF
+if { (eval echo configure:1524: \"$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
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+echo $ac_n "checking for gdbm_open in -lgdbm""... $ac_c" 1>&6
+echo "configure:1555: checking for gdbm_open in -lgdbm" >&5
+ac_lib_var=`echo gdbm'_'gdbm_open | 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="-lgdbm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1563 "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 gdbm_open();
+
+int main() {
+gdbm_open()
+; return 0; }
+EOF
+if { (eval echo configure:1574: \"$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
+    ac_tr_lib=HAVE_LIB`echo gdbm | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lgdbm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1605: 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 1610 "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:1618: \"$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 1635 "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 1653 "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 1674 "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:1685: \"$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
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1713: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1718 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1726: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$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
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1751: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | 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="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1759 "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 opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1770: \"$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
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1792: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | 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="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1800 "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 opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1811: \"$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
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_hdr in gdbm.h syslog.h sys/resource.h sys/utsname.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1837: 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 1842 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+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
+  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
+
+for ac_hdr in fnmatch.h errno.h getopt.h time.h sys/time.h signal.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1877: 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 1882 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1887: \"$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
+
+for ac_hdr in netdb.h sys/socket.h fcntl.h limits.h unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1917: 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 1922 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1927: \"$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 working const""... $ac_c" 1>&6
+echo "configure:1957: 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 1962 "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:2011: \"$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:2032: 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 2037 "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
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:2065: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2070 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:2079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:2100: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2105 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:2113: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking socklen_t""... $ac_c" 1>&6
+echo "configure:2135: checking socklen_t" >&5
+if eval "test \"`echo '$''{'noffle_cv_type_socklen_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2140 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int main() {
+ socklen_t s; 
+; return 0; }
+EOF
+if { (eval echo configure:2150: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  noffle_cv_type_socklen_t=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  noffle_cv_type_socklen_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$noffle_cv_type_socklen_t" 1>&6
+
+if test "x$noffle_cv_type_socklen_t" = "xno"
+then
+ cat >> confdefs.h <<EOF
+#define socklen_t unsigned int
+EOF
+
+fi
+
+
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2176: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2181 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2198: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&6
+echo "configure:2217: checking for strftime" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2222 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strftime(); 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 strftime();
+
+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_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+echo "configure:2267: checking for strftime in -lintl" >&5
+ac_lib_var=`echo intl'_'strftime | 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="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2275 "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 strftime();
+
+int main() {
+strftime()
+; return 0; }
+EOF
+if { (eval echo configure:2286: \"$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_STRFTIME 1
+EOF
+
+LIBS="-lintl $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for working fnmatch""... $ac_c" 1>&6
+echo "configure:2313: checking for working fnmatch" >&5
+if eval "test \"`echo '$''{'ac_cv_func_fnmatch_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Some versions of Solaris or SCO have a broken fnmatch function.
+# So we run a test program.  If we are cross-compiling, take no chance.
+# Thanks to John Oleynick and Franc,ois Pinard for this test.
+if test "$cross_compiling" = yes; then
+  ac_cv_func_fnmatch_works=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2324 "configure"
+#include "confdefs.h"
+main() { exit (fnmatch ("a*", "abc", 0) != 0); }
+EOF
+if { (eval echo configure:2328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_fnmatch_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_fnmatch_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_fnmatch_works" 1>&6
+if test $ac_cv_func_fnmatch_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_FNMATCH 1
+EOF
+
+fi
+
+for ac_func in fdopen vsnprintf snprintf __vsnprintf __snprintf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2353: 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 2358 "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:2381: \"$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
+
+for ac_func in gethostname mkdir mktime select socket strerror strstr uname
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2408: 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 2413 "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:2436: \"$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-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval="$enable_debug"
+  :
+else
+  enable_debug=yes
+fi
+
+
+if test "x$enable_debug" = "xyes"
+then
+ CFLAGS="$CFLAGS \
+-Wall -O2 -g -pedantic -ansi -W -Wtraditional -Wshadow -Wpointer-arith \
+-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \
+-Waggregate-return -Wstrict-prototypes -Wmissing-prototypes \
+-Wmissing-declarations -Wnested-externs -Winline \
+-D__USE_BSD -D__USE_XOPEN_EXTENDED -D__USE_POSIX -DDEBUG" 
+fi
+
+
+# [ This is adapted from mutt. ]
+# Check whether --with-docdir or --without-docdir was given.
+if test "${with_docdir+set}" = set; then
+  withval="$with_docdir"
+  noffle_cv_docdir=$withval
+else
+   echo $ac_n "checking where to put the documentation""... $ac_c" 1>&6
+echo "configure:2492: checking where to put the documentation" >&5
+if eval "test \"`echo '$''{'noffle_cv_docdir'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test x$prefix = xNONE; then
+    noffle_cv_prefix=$ac_default_prefix
+   else
+    noffle_cv_prefix=$prefix
+   fi
+   noffle_cv_docdir=$noffle_cv_prefix/doc/noffle
+  
+fi
+
+echo "$ac_t""$noffle_cv_docdir" 1>&6
+
+fi
+
+
+
+
+CONFIGFILE="/etc/noffle.conf"
+cat >> confdefs.h <<EOF
+#define CONFIGFILE "$CONFIGFILE"
+EOF
+
+
+
+
+
+SPOOLDIR="/var/spool/$PACKAGE"
+cat >> confdefs.h <<EOF
+#define SPOOLDIR "$SPOOLDIR"
+EOF
+
+
+
+DOCDIR=$noffle_cv_docdir
+
+
+
+
+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
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile src/Makefile docs/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%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@CONFIGFILE@%$CONFIGFILE%g
+s%@SPOOLDIR@%$SPOOLDIR%g
+s%@DOCDIR@%$DOCDIR%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 src/Makefile docs/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
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  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
+s%@INSTALL@%$INSTALL%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
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+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
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configure.in	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,188 @@
+dnl ---------------------------------------------------------------------------
+dnl Process this file with autoconf to produce a configure script.
+dnl ---------------------------------------------------------------------------
+
+AC_INIT(src/noffle.c)
+
+AC_PREREQ(2.13)
+
+PACKAGE=noffle
+VERSION=1.0pre6
+
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE($PACKAGE,$VERSION)
+
+dnl AM_MAINTAINER_MODE
+
+AC_DEFINE(_GNU_SOURCE)
+
+AC_LANG_C
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for programs.
+dnl ---------------------------------------------------------------------------
+
+AC_PROG_CC
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+
+dnl ---------------------------------------------------------------------------
+dnl System checks.
+dnl ---------------------------------------------------------------------------
+
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for libraries.
+dnl ---------------------------------------------------------------------------
+
+# Whenever both -lsocket and -lnsl are needed, it seems to be always the
+# case that gethostbyname requires -lnsl.  So, check -lnsl first, for it
+# to be in LIBS before the setsockopt checks are performed.  *However*,
+# on SINIX-N 5.43, this is false, and gethostent seems to be a better
+# candidate. So, let's use it below instead of gethostbyname, and see.
+
+# [ This is ripped from GNU tar. ]
+
+AC_CHECK_FUNC(gethostent)
+if test $ac_cv_func_gethostent = no; then
+  AC_CHECK_LIB(nsl, gethostent)
+fi
+AC_CHECK_FUNC(setsockopt)
+if test $ac_cv_func_setsockopt = no; then
+  AC_CHECK_LIB(socket, setsockopt)
+fi
+
+
+AC_CHECK_LIB(gdbm, gdbm_open)
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for header files.
+dnl ---------------------------------------------------------------------------
+
+AC_HEADER_STDC
+AC_HEADER_DIRENT
+AC_CHECK_HEADERS(gdbm.h syslog.h sys/resource.h sys/utsname.h)
+AC_CHECK_HEADERS(fnmatch.h errno.h getopt.h time.h sys/time.h signal.h)
+AC_CHECK_HEADERS(netdb.h sys/socket.h fcntl.h limits.h unistd.h)
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl ---------------------------------------------------------------------------
+
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+AC_CACHE_CHECK(socklen_t, noffle_cv_type_socklen_t,
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+], [ socklen_t s; ],
+noffle_cv_type_socklen_t=yes, noffle_cv_type_socklen_t=no)
+)
+
+if test "x$noffle_cv_type_socklen_t" = "xno"
+then
+ AC_DEFINE_UNQUOTED(socklen_t, unsigned int)
+fi
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for library functions.
+dnl ---------------------------------------------------------------------------
+
+AC_TYPE_SIGNAL
+AC_FUNC_STRFTIME
+AC_FUNC_FNMATCH
+AC_CHECK_FUNCS(fdopen vsnprintf snprintf __vsnprintf __snprintf)
+AC_CHECK_FUNCS(gethostname mkdir mktime select socket strerror strstr uname)
+
+
+dnl ---------------------------------------------------------------------------
+dnl Checks for system services.
+dnl ---------------------------------------------------------------------------
+
+
+dnl ---------------------------------------------------------------------------
+dnl Handle user-specified configure options
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(debug, [
+NOFFLE options:
+  --enable-debug          turn on debugging (default=yes)], ,
+enable_debug=yes)
+
+if test "x$enable_debug" = "xyes"
+then
+ CFLAGS="$CFLAGS \
+-Wall -O2 -g -pedantic -ansi -W -Wtraditional -Wshadow -Wpointer-arith \
+-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \
+-Waggregate-return -Wstrict-prototypes -Wmissing-prototypes \
+-Wmissing-declarations -Wnested-externs -Winline \
+-D__USE_BSD -D__USE_XOPEN_EXTENDED -D__USE_POSIX -DDEBUG" 
+fi
+
+
+# [ This is adapted from mutt. ]
+AC_ARG_WITH(docdir,
+[  --with-docdir=PATH      specify where to put the documentation
+], [noffle_cv_docdir=$withval],
+[ AC_CACHE_CHECK(where to put the documentation, noffle_cv_docdir,
+  [if test x$prefix = xNONE; then
+    noffle_cv_prefix=$ac_default_prefix
+   else
+    noffle_cv_prefix=$prefix
+   fi
+   noffle_cv_docdir=$noffle_cv_prefix/doc/noffle
+  ])
+])
+
+
+dnl ---------------------------------------------------------------------------
+dnl Unquoted defines and substituted variables.
+dnl ---------------------------------------------------------------------------
+
+CONFIGFILE="/etc/noffle.conf"
+AC_DEFINE_UNQUOTED(CONFIGFILE,"$CONFIGFILE")
+AC_SUBST(CONFIGFILE)
+
+dnl NOFFLE_EXPAND_DIR(VARNAME, DIR)
+dnl expands occurrences of ${prefix} and ${exec_prefix} in the given DIR,
+dnl and assigns the resulting string to VARNAME
+dnl example: NOFFLE_EXPAND_DIR(LOCALEDIR, "$datadir/locale")
+dnl eg, then: AC_DEFINE_UNQUOTED(LOCALEDIR, "$LOCALEDIR")
+dnl by Alexandre Oliva
+dnl from http://www.cygnus.com/ml/automake/1998-Aug/0040.html
+AC_DEFUN(NOFFLE_EXPAND_DIR, [
+ $1=$2
+ $1=`(
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+  eval echo \""[$]$1"\"
+ )`
+])
+
+SPOOLDIR="/var/spool/$PACKAGE"
+AC_DEFINE_UNQUOTED(SPOOLDIR, "$SPOOLDIR")
+AC_SUBST(SPOOLDIR)
+
+DOCDIR=$noffle_cv_docdir
+AC_SUBST(DOCDIR)
+
+
+dnl ---------------------------------------------------------------------------
+dnl Output files.
+dnl ---------------------------------------------------------------------------
+
+AC_OUTPUT(Makefile src/Makefile docs/Makefile)
+
--- a/content.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/*
-  content.c
-
-  $Id: content.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "common.h"
-#include "config.h"
-#include "group.h"
-#include "log.h"
-#include "over.h"
-#include "pseudo.h"
-#include "util.h"
-
-struct
-{
-    DIR *dir;           /* Directory for browsing through all
-                           groups */
-    int vecFirst;	/* First article number in vector */
-    int first;		/* First live article number */
-    int last;		/* Last article number */
-    unsigned int size;  /* Number of overviews. */
-    unsigned int max;   /* Size of elem. */
-    Over **elem;        /* Ptr to array with ptrs to overviews.
-                           NULL entries for non-existing article numbers
-                           in group. */
-    Str name;
-    Str file;
-} cont = { NULL, 1, 1, 0, 0, 0, NULL, "", "" };
-
-void
-Cont_app( Over *ov )
-{
-    if ( cont.max < cont.size + 1 )
-    {
-        if ( ! ( cont.elem = realloc( cont.elem,
-                                      ( cont.max + 500 )
-                                      * sizeof( cont.elem[ 0 ] ) ) ) )
-        {
-            Log_err( "Could not realloc overview list" );
-            exit( EXIT_FAILURE );
-        }
-        cont.max += 500;
-    }
-    ASSERT( cont.vecFirst > 0 );
-    if ( ov )
-        Ov_setNumb( ov, cont.vecFirst + cont.size );
-    cont.elem[ cont.size++ ] = ov;
-    cont.last = cont.vecFirst + cont.size - 1;
-}
-
-Bool
-Cont_validNumb( int n )
-{
-    return ( n != 0 && n >= cont.first && n <= cont.last
-             && cont.elem[ n - cont.vecFirst ] );
-}
-
-void
-Cont_delete( int n )
-{
-    Over **ov;
-
-    if ( ! Cont_validNumb( n ) )
-        return;
-    ov = &cont.elem[ n - cont.vecFirst ];
-    free( *ov );
-    *ov = NULL;
-}
-
-/* Remove all overviews from content. */
-static void
-clearCont()
-{
-    int i;
-
-    for ( i = 0; i < cont.size; ++i )
-        del_Over( cont.elem[ i ] );
-    cont.size = 0;
-}
-
-static void
-setupEmpty( const char *name )
-{
-    cont.last = Grp_last( name );
-    cont.first = cont.vecFirst = cont.last + 1;
-    ASSERT( cont.first > 0 );
-}
-
-/* Extend content list to size "cnt" and append NULL entries. */
-static void
-extendCont( int cnt )
-{
-    int i, n;
-    
-    if ( cont.size < cnt )
-    {
-        n = cnt - cont.size;
-        for ( i = 0; i < n; ++i )
-            Cont_app( NULL );
-    }
-}
-
-/* Discard all cached overviews, and read in the overviews of a new group
-   from its overviews file. */
-void
-Cont_read( const char *name )
-{
-    FILE *f;
-    Over *ov;
-    int numb;
-    Str line;
-
-    /* Delete old overviews and make room for new ones. */
-    cont.vecFirst = 0;
-    cont.first = 0;
-    cont.last = 0;
-    Utl_cpyStr( cont.name, name );
-    clearCont();
-
-    /* read overviews from overview file and store them in the overviews
-       list */
-    snprintf( cont.file, MAXCHAR, "%s/overview/%s", Cfg_spoolDir(), name ); 
-    f = fopen( cont.file, "r" );
-    if ( ! f )
-    {
-        Log_dbg( "No group overview file: %s", cont.file );
-	setupEmpty( name );
-        return;
-    }
-    Log_dbg( "Reading %s", cont.file );
-    while ( fgets( line, MAXCHAR, f ) )
-    {
-        if ( ! ( ov = Ov_read( line ) ) )
-        {
-            Log_err( "Overview corrupted in %s: %s", name, line );
-            continue;
-        }
-        numb = Ov_numb( ov );
-        if ( numb < cont.first )
-        {
-            Log_err( "Wrong ordering in %s: %s", name, line );
-            continue;
-        }
-        if ( cont.first == 0 )
-            cont.first = cont.vecFirst = numb;
-        cont.last = numb;
-        extendCont( numb - cont.first + 1 );
-        cont.elem[ numb - cont.first ] = ov;
-    }
-    fclose( f );
-
-    if ( cont.first == 0 )
-	setupEmpty( name );		/* Corrupt overview file recovery */
-}
-
-void
-Cont_write( void )
-{
-    Bool anythingWritten;
-    int i;
-    FILE *f;
-    const Over *ov;
-
-
-    /* Move the first article no. to the first active article */
-    while ( ! Cont_validNumb( cont.first ) && cont.first <= cont.last )
-        ++cont.first;
-
-    /* Save the overview */
-    if ( ! ( f = fopen( cont.file, "w" ) ) )
-    {
-        Log_err( "Could not open %s for writing", cont.file );
-        return;
-    }
-    Log_dbg( "Writing %s (%lu)", cont.file, cont.size );
-    anythingWritten = FALSE;
-    for ( i = 0; i < cont.size; ++i )
-    {
-        if ( ( ov = cont.elem[ i ] ) )
-        {
-            if ( ! Pseudo_isGeneralInfo( Ov_msgId( ov ) ) )
-            {
-                if ( ! Ov_write( ov, f ) )
-                {
-                    Log_err( "Writing of overview line failed" );
-                    break;
-                }
-                else
-                    anythingWritten = TRUE;
-            }
-        }
-    }
-    fclose( f );
-
-    /*
-      If empty, remove the overview file and set set first to one
-      beyond last to flag said emptiness.
-     */
-    if ( ! anythingWritten )
-    {
-	unlink( cont.file );
-	cont.first = cont.last + 1;
-    }
-}
-
-const Over *
-Cont_get( int numb )
-{
-    if ( ! Cont_validNumb( numb ) )
-        return NULL;
-    return cont.elem[ numb - cont.vecFirst ];
-}
-
-int
-Cont_first( void ) { return cont.first; }
-
-int
-Cont_last( void ) { return cont.last; }
-
-const char *
-Cont_grp( void ) { return cont.name; }
-
-Bool
-Cont_nextGrp( Str result )
-{
-    struct dirent *d;
-    
-    ASSERT( cont.dir );
-    if ( ! ( d = readdir( cont.dir ) ) )
-    {
-        cont.dir = NULL;
-        return FALSE;
-    }
-    if ( ! d->d_name )
-        return FALSE;
-    Utl_cpyStr( result, d->d_name );
-    result[ MAXCHAR - 1 ] = '\0';
-    return TRUE;
-}
-
-Bool
-Cont_firstGrp( Str result )
-{
-    Str name;
-
-    snprintf( name, MAXCHAR, "%s/overview", Cfg_spoolDir() );
-    if ( ! ( cont.dir = opendir( name ) ) )
-    {
-        Log_err( "Cannot open %s", name );
-        return FALSE;
-    }
-    Cont_nextGrp( result ); /* "."  */
-    Cont_nextGrp( result ); /* ".." */
-    return Cont_nextGrp( result );
-}
--- a/content.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
-  content.h
-
-  Contents of a newsgroup
-  - list of article overviews for selected group.
-
-  The overviews of all articles of a group are stored in an overview file,
-  filename SPOOLDIR/overview/GROUPNAME. One entire overview file is read
-  and cached in memory, at a time.
-
-  $Id: content.h 3 2000-01-04 11:35:42Z enz $ 
-*/
-
-#ifndef CONT_H
-#define CONT_H
-
-#include "over.h"
-
-/*
-  Try to read overviews from overview file for group <grp>.
-  Fill with fake articles, if something goes wrong.
-*/
-void
-Cont_read( const char *grp );
-
-/*
-  Append overview to current list and increment the current
-  group's last article counter. Ownership of the ptr is transfered
-  to content
-*/
-void
-Cont_app( Over *ov );
-
-/* Write content */
-void
-Cont_write( void );
-
-Bool
-Cont_validNumb( int numb );
-
-const Over *
-Cont_get( int numb );
-
-void
-Cont_delete( int numb );
-
-int
-Cont_first( void );
-
-int
-Cont_last( void );
-
-const char *
-Cont_grp( void );
-
-Bool
-Cont_nextGrp( Str result );
-
-Bool
-Cont_firstGrp( Str result );
-
-void
-Cont_expire( void );
-
-#endif
--- a/control.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
-  control.c
-
-  $Id: control.c 32 2000-04-29 14:45:56Z enz $
-*/
-
-#include "control.h"
-#include <stdio.h>
-#include "common.h"
-#include "content.h"
-#include "database.h"
-#include "group.h"
-#include "itemlist.h"
-#include "log.h"
-#include "outgoing.h"
-
-int
-Ctrl_cancel( const char *msgId )
-{
-    ItemList *refs;
-    const char *ref;
-    Str server;
-    Bool seen = FALSE;
-    int res = CANCEL_OK;
-
-    /* See if in outgoing and zap if so. */
-    if ( Out_find( msgId, server ) )
-    {
-	Out_remove( server, msgId );
-	Log_inf( "'%s' cancelled from outgoing queue for '%s'.\n",
-		 msgId, server );
-	seen = TRUE;
-    }
-
-    if ( ! Db_contains( msgId ) )
-    {
-	Log_inf( "Cancel: '%s' not in database.", msgId );
-	return seen ? CANCEL_OK : CANCEL_NO_SUCH_MSG;
-    }
-
-    /*
-      Retrieve the Xrefs, remove from each group and then
-      remove from the database.
-     */
-    refs = new_Itl( Db_xref( msgId ), " " );
-    for( ref = Itl_first( refs ); ref != NULL; ref = Itl_next( refs ) )
-    {
-	Str grp;
-	int no;
-
-	if ( sscanf( ref, "%s:%d", grp, &no ) != 2 )
-	    break;
-	
-	if ( Grp_exists( grp ) )
-	{
-	    Cont_read( grp );
-	    Cont_delete( no );
-	    Cont_write();
-
-	    if ( ! Grp_local( grp ) && ! seen )
-		res = CANCEL_NEEDS_MSG;
-
-	    Log_dbg( "Removed '%s' from group '%s'.", msgId, grp );
-	}
-	else
-	{
-	    Log_inf( "Group '%s' in Xref for '%s' not found.", grp, msgId );
-	}
-    }
-    del_Itl( refs );
-    Db_delete( msgId );
-    Log_inf( "Message '%s' cancelled.", msgId );
-    return res;
-}
--- a/control.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
-  control.h
-
-  Control actions needed by server and command line.
-
-  $Id: control.h 32 2000-04-29 14:45:56Z enz $
-*/
-
-#ifndef CONTROL_H
-#define CONTROL_H
-
-#define	CANCEL_OK		0
-#define	CANCEL_NO_SUCH_MSG	1
-#define	CANCEL_NEEDS_MSG	2
-
-/*
-   Cancel a message. Return CANCEL_OK if completely cancelled,
-   CANCEL_NO_SUCH_MSG if no message with that ID exists, and
-   CANCEL_NEEDS_MSG if a 'cancel' message should be propagated upstream
-   to cancel the message elsewhere.
- */
-int
-Ctrl_cancel( const char *msgId );
-
-#endif
--- a/database.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,679 +0,0 @@
-/*
-  database.c
-
-  $Id: database.c 44 2000-05-05 07:23:15Z enz $
-
-  Uses GNU gdbm library. Using Berkeley db (included in libc6) was
-  cumbersome. It is based on Berkeley db 1.85, which has severe bugs
-  (e.g. it is not recommended to delete or overwrite entries with
-  overflow pages).
-*/
-
-#include "database.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <gdbm.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "config.h"
-#include "itemlist.h"
-#include "log.h"
-#include "protocol.h"
-#include "util.h"
-#include "wildmat.h"
-
-static struct Db
-{
-    GDBM_FILE dbf;
-
-    /* Start string for Xref header line: "Xref: <host>" */
-    Str xrefHost;
-
-    /* Msg Id of presently loaded article, empty if none loaded */
-    Str msgId;
-
-    /* Status of loaded article */
-    int stat; /* Flags */
-    time_t lastAccess;
-
-    /* Overview of loaded article */
-    Str subj; 
-    Str from;
-    Str date;
-    Str ref;
-    Str xref;
-    size_t bytes;
-    size_t lines;
-
-    /* Article text (except for overview header lines) */
-    DynStr *txt;
-
-} db = { NULL, "(unknown)", "", 0, 0, "", "", "", "", "", 0, 0, NULL };
-
-static const char *
-errMsg( void )
-{
-    if ( errno != 0 )
-        return strerror( errno );
-    return gdbm_strerror( gdbm_errno );
-}
-
-Bool
-Db_open( void )
-{
-    Str name, host;
-    int flags;
-
-    ASSERT( db.dbf == NULL );
-    snprintf( name, MAXCHAR, "%s/data/articles.gdbm", Cfg_spoolDir() );
-    flags = GDBM_WRCREAT | GDBM_FAST;
-
-    if ( ! ( db.dbf = gdbm_open( name, 512, flags, 0644, NULL ) ) )
-    {
-        Log_err( "Error opening %s for r/w (%s)", name, errMsg() );
-        return FALSE;
-    }
-    Log_dbg( "%s opened for r/w", name );
-
-    if ( db.txt == NULL )
-        db.txt = new_DynStr( 5000 );
-
-    gethostname( host, MAXCHAR );
-    snprintf( db.xrefHost, MAXCHAR, "Xref: %s", host );
-
-    return TRUE;
-}
-
-void
-Db_close( void )
-{
-    ASSERT( db.dbf );
-    Log_dbg( "Closing database" );
-    gdbm_close( db.dbf );
-    db.dbf = NULL;
-    del_DynStr( db.txt );
-    db.txt = NULL;
-    Utl_cpyStr( db.msgId, "" );
-}
-
-static Bool
-loadArt( const char *msgId )
-{
-    static void *dptr = NULL;
-    
-    datum key, val;
-    Str t = "";
-    const char *p;
-    
-    ASSERT( db.dbf );
-
-    if ( strcmp( msgId, db.msgId ) == 0 )
-        return TRUE;
-
-    key.dptr = (void *)msgId;
-    key.dsize = strlen( msgId ) + 1;
-    if ( dptr != NULL )
-    {
-        free( dptr );
-        dptr = NULL;
-    }
-    val = gdbm_fetch( db.dbf, key );
-    dptr = val.dptr;
-    if ( dptr == NULL )
-    {
-        Log_dbg( "database.c loadArt: gdbm_fetch found no entry" );
-        return FALSE;
-    }
-    
-    Utl_cpyStr( db.msgId, msgId );
-    p = Utl_getLn( t, (char *)dptr );
-    if ( ! p || sscanf( t, "%x", &db.stat ) != 1 )
-    {
-        Log_err( "Entry in database '%s' is corrupt (status)", msgId );
-        return FALSE;
-    }
-    p = Utl_getLn( t, p );
-    if ( ! p || sscanf( t, "%lu", &db.lastAccess ) != 1 )
-    {
-        Log_err( "Entry in database '%s' is corrupt (lastAccess)", msgId );
-        return FALSE;
-    }
-    p = Utl_getLn( db.subj, p );
-    p = Utl_getLn( db.from, p );
-    p = Utl_getLn( db.date, p );
-    p = Utl_getLn( db.ref, p );
-    p = Utl_getLn( db.xref, p );
-    if ( ! p )
-    {
-        Log_err( "Entry in database '%s' is corrupt (overview)", msgId );
-        return FALSE;
-    }
-    p = Utl_getLn( t, p );
-    if ( ! p || sscanf( t, "%u", &db.bytes ) != 1 )
-    {
-        Log_err( "Entry in database '%s' is corrupt (bytes)", msgId );
-        return FALSE;
-    }
-    p = Utl_getLn( t, p );
-    if ( ! p || sscanf( t, "%u", &db.lines ) != 1 )
-    {
-        Log_err( "Entry in database '%s' is corrupt (lines)", msgId );
-        return FALSE;
-    }
-    DynStr_clear( db.txt );
-    DynStr_app( db.txt, p );
-    return TRUE;
-}
-
-static Bool
-saveArt( void )
-{
-    DynStr *s;
-    Str t = "";
-    datum key, val;
-
-    if ( strcmp( db.msgId, "" ) == 0 )
-        return FALSE;
-    s = new_DynStr( 5000 );
-    snprintf( t, MAXCHAR, "%x", db.stat );
-    DynStr_appLn( s, t );
-    snprintf( t, MAXCHAR, "%lu", db.lastAccess );
-    DynStr_appLn( s, t );
-    DynStr_appLn( s, db.subj );
-    DynStr_appLn( s, db.from );
-    DynStr_appLn( s, db.date );
-    DynStr_appLn( s, db.ref );
-    DynStr_appLn( s, db.xref );
-    snprintf( t, MAXCHAR, "%u", db.bytes );
-    DynStr_appLn( s, t );
-    snprintf( t, MAXCHAR, "%u", db.lines );
-    DynStr_appLn( s, t );
-    DynStr_appDynStr( s, db.txt );
-
-    key.dptr = (void *)db.msgId;
-    key.dsize = strlen( db.msgId ) + 1;
-    val.dptr = (void *)DynStr_str( s );
-    val.dsize = DynStr_len( s ) + 1;
-    if ( gdbm_store( db.dbf, key, val, GDBM_REPLACE ) != 0 )
-    {
-        Log_err( "Could not store %s in database (%s)", errMsg() );
-        return FALSE;
-    }
-
-    del_DynStr( s );
-    return TRUE;
-}
-
-Bool
-Db_prepareEntry( const Over *ov, const char *grp, int numb )
-{
-    const char *msgId;
-
-    ASSERT( db.dbf );
-    ASSERT( ov );
-    ASSERT( grp );
-
-    msgId = Ov_msgId( ov );
-    Log_dbg( "Preparing entry %s", msgId );
-    if ( Db_contains( msgId ) )
-        Log_err( "Preparing article twice: %s", msgId );
-
-    db.stat = DB_NOT_DOWNLOADED;
-    db.lastAccess = time( NULL );
-
-    Utl_cpyStr( db.msgId, msgId );
-    Utl_cpyStr( db.subj, Ov_subj( ov ) );
-    Utl_cpyStr( db.from, Ov_from( ov ) );
-    Utl_cpyStr( db.date, Ov_date( ov ) );
-    Utl_cpyStr( db.ref, Ov_ref( ov ) );
-    snprintf( db.xref, MAXCHAR, "%s:%i", grp, numb );
-    db.bytes = Ov_bytes( ov );
-    db.lines = Ov_lines( ov );
-
-    DynStr_clear( db.txt );
-
-    return saveArt();
-}
-
-Bool
-Db_storeArt( const char *msgId, const char *artTxt )
-{
-    Str line, lineEx, field, value;
-    const char *startPos;
-
-    ASSERT( db.dbf );
-
-    Log_dbg( "Store article %s", msgId );
-    if ( ! loadArt( msgId ) )
-    {
-        Log_err( "Cannot find info about '%s' in database", msgId );
-        return FALSE;
-    }
-    if ( ! ( db.stat & DB_NOT_DOWNLOADED ) )
-    {
-        Log_err( "Trying to store already retrieved article '%s'", msgId );
-        return FALSE;
-    }
-    db.stat &= ~DB_NOT_DOWNLOADED;
-    db.stat &= ~DB_RETRIEVING_FAILED;
-    db.lastAccess = time( NULL );
-
-    DynStr_clear( db.txt );
-
-    /* Read header */
-    startPos = artTxt;
-    while ( TRUE )
-    {
-        artTxt = Utl_getHeaderLn( lineEx, artTxt );
-        if ( lineEx[ 0 ] == '\0' )
-        {
-            DynStr_appLn( db.txt, lineEx );
-            break;
-        }
-        /* Remove fields already in overview and handle x-noffle
-           headers correctly in case of cascading NOFFLEs */
-        if ( Prt_getField( field, value, lineEx ) )
-        {
-            if ( strcmp( field, "x-noffle-status" ) == 0 )
-            {
-                if ( strstr( value, "NOT_DOWNLOADED" ) != 0 )
-                    db.stat |= DB_NOT_DOWNLOADED;
-            }
-            else if ( strcmp( field, "message-id" ) != 0
-                      && strcmp( field, "xref" ) != 0
-                      && strcmp( field, "references" ) != 0
-                      && strcmp( field, "subject" ) != 0
-                      && strcmp( field, "from" ) != 0
-                      && strcmp( field, "date" ) != 0
-                      && strcmp( field, "bytes" ) != 0
-                      && strcmp( field, "lines" ) != 0
-                      && strcmp( field, "x-noffle-lastaccess" ) != 0 )
-                DynStr_appLn( db.txt, lineEx );
-        }
-    }
-
-    /* Read body */
-    while ( ( artTxt = Utl_getLn( line, artTxt ) ) )
-        if ( ! ( db.stat & DB_NOT_DOWNLOADED ) )
-            DynStr_appLn( db.txt, line );
-    
-    return saveArt();
-}
-
-void
-Db_setStat( const char *msgId, int stat )
-{
-    if ( loadArt( msgId ) )
-    {
-        db.stat = stat;
-        saveArt();
-    }
-}
-
-void
-Db_updateLastAccess( const char *msgId )
-{
-    if ( loadArt( msgId ) )
-    {
-        db.lastAccess = time( NULL );
-        saveArt();
-    }
-}
-
-void
-Db_setXref( const char *msgId, const char *xref )
-{
-    if ( loadArt( msgId ) )
-    {
-        Utl_cpyStr( db.xref, xref );
-        saveArt();
-    }
-}
-
-/* Search best position for breaking a line */
-static const char *
-searchBreakPos( const char *line, int wantedLength )
-{
-    const char *lastSpace = NULL;
-    Bool lastWasSpace = FALSE;
-    int len = 0;
-
-    while ( *line != '\0' )
-    {
-        if ( isspace( *line ) )
-        {
-            if ( len > wantedLength && lastSpace != NULL )
-                return lastSpace;
-            if ( ! lastWasSpace )
-                lastSpace = line;
-            lastWasSpace = TRUE;
-        }
-        else
-            lastWasSpace = FALSE;
-        ++len;
-        ++line;
-    }
-    if ( len > wantedLength && lastSpace != NULL )
-        return lastSpace;
-    return line;
-}
-
-/* Append header line by breaking long line into multiple lines */
-static void
-appendLongHeader( DynStr *target, const char *field, const char *value )
-{
-    const int wantedLength = 78;
-    const char *breakPos, *old;
-    int len;
-
-    len = strlen( field );
-    DynStr_appN( target, field, len );
-    DynStr_appN( target, " ", 1 );
-    old = value;
-    while ( isspace( *old ) )
-        ++old;
-    breakPos = searchBreakPos( old, wantedLength - len - 1 );
-    DynStr_appN( target, old, breakPos - old );
-    if ( *breakPos == '\0' )
-    {
-        DynStr_appN( target, "\n", 1 );
-        return;
-    }
-    DynStr_appN( target, "\n ", 2 );
-    while ( TRUE )
-    {
-        old = breakPos;
-        while ( isspace( *old ) )
-            ++old;
-        breakPos = searchBreakPos( old, wantedLength - 1 );
-        DynStr_appN( target, old, breakPos - old );
-        if ( *breakPos == '\0' )
-        {
-            DynStr_appN( target, "\n", 1 );
-            return;
-        }
-        DynStr_appN( target, "\n ", 2 );
-    }
-}
-
-const char *
-Db_header( const char *msgId )
-{
-    static DynStr *s = NULL;
-
-    Str date, t;
-    int stat;
-    const char *p;
-
-    if ( s == NULL )
-        s = new_DynStr( 5000 );
-    else
-        DynStr_clear( s );
-    ASSERT( db.dbf );
-    if ( ! loadArt( msgId ) )
-        return NULL;
-    strftime( date, MAXCHAR, "%Y-%m-%d %H:%M:%S",
-              localtime( &db.lastAccess ) );
-    stat = db.stat;
-    snprintf( t, MAXCHAR,
-              "Message-ID: %s\n"
-              "X-NOFFLE-Status:%s%s%s\n"
-              "X-NOFFLE-LastAccess: %s\n",
-              msgId,
-              stat & DB_INTERESTING ? " INTERESTING" : "",
-              stat & DB_NOT_DOWNLOADED ? " NOT_DOWNLOADED" : "",
-              stat & DB_RETRIEVING_FAILED ? " RETRIEVING_FAILED" : "",
-              date );
-    DynStr_app( s, t );
-    appendLongHeader( s, "Subject:", db.subj );
-    appendLongHeader( s, "From:", db.from );
-    appendLongHeader( s, "Date:", db.date );
-    appendLongHeader( s, "References:", db.ref );
-    DynStr_app( s, "Bytes: " );
-    snprintf( t, MAXCHAR, "%u", db.bytes );
-    DynStr_appLn( s, t );
-    DynStr_app( s, "Lines: " );
-    snprintf( t, MAXCHAR, "%u", db.lines );
-    DynStr_appLn( s, t );
-    appendLongHeader( s, db.xrefHost, db.xref );
-    p = strstr( DynStr_str( db.txt ), "\n\n" );
-    if ( ! p )
-        DynStr_appDynStr( s, db.txt );
-    else
-        DynStr_appN( s, DynStr_str( db.txt ), p - DynStr_str( db.txt ) + 1 );
-    return DynStr_str( s );
-}
-
-const char *
-Db_body( const char *msgId )
-{
-    const char *p;
-
-    if ( ! loadArt( msgId ) )
-        return "";
-    p = strstr( DynStr_str( db.txt ), "\n\n" );
-    if ( ! p )
-        return "";
-    return ( p + 2 );
-}
-
-int
-Db_stat( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return 0;
-    return db.stat;
-}
-
-time_t
-Db_lastAccess( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return -1;
-    return db.lastAccess;
-}
-
-const char *
-Db_ref( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return "";
-    return db.ref;
-}
-
-const char *
-Db_xref( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return "";
-    return db.xref;
-}
-
-const char *
-Db_from( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return "";
-    return db.from;
-}
-
-const char *
-Db_date( const char *msgId )
-{
-    if ( ! loadArt( msgId ) )
-        return "";
-    return db.date;
-}
-
-Bool
-Db_contains( const char *msgId )
-{
-    datum key;
-
-    ASSERT( db.dbf );
-    if ( strcmp( msgId, db.msgId ) == 0 )
-        return TRUE;
-    key.dptr = (void*)msgId;
-    key.dsize = strlen( msgId ) + 1;
-    return gdbm_exists( db.dbf, key );
-}
-
-void
-Db_delete( const char *msgId )
-{
-    datum key;
-
-    ASSERT( db.dbf );
-    if ( strcmp( msgId, db.msgId ) == 0 )
-        db.msgId[ 0 ] = '\0';
-    key.dptr = (void*)msgId;
-    key.dsize = strlen( msgId ) + 1;
-    gdbm_delete( db.dbf, key );
-}
-
-static datum cursor = { NULL, 0 };
-
-Bool
-Db_first( const char** msgId )
-{
-    ASSERT( db.dbf );
-    if ( cursor.dptr != NULL )
-    {
-        free( cursor.dptr );
-        cursor.dptr = NULL;
-    }
-    cursor = gdbm_firstkey( db.dbf );
-    *msgId = cursor.dptr;
-    return ( cursor.dptr != NULL );
-}
-
-Bool
-Db_next( const char** msgId )
-{
-    void *oldDptr = cursor.dptr;
-
-    ASSERT( db.dbf );
-    if ( cursor.dptr == NULL )
-        return FALSE;
-    cursor = gdbm_nextkey( db.dbf, cursor );
-    free( oldDptr );
-    *msgId = cursor.dptr;
-    return ( cursor.dptr != NULL );
-}
-
-static int
-calcExpireDays( const char *msgId )
-{
-    const char *xref;
-    ItemList *refs;
-    const char *ref;
-    int res;
-
-    xref = Db_xref( msgId );
-    if ( xref[ 0 ] == '\0' )
-	return -1;
-
-    res = -1;
-    refs = new_Itl( xref, " :" );
-    for ( ref = Itl_first( refs ); ref != NULL; ref = Itl_next( refs ) )
-    {
-	Str pattern;
-	int days;
-	
-	Cfg_beginExpireEnum();
-	while ( ( days = Cfg_nextExpire( pattern ) ) != -1 )
-	    if ( Wld_match( ref, pattern )
-		 && ( ( days > res && res != 0 ) ||
-		      days == 0 ) )
-	    {
-		res = days;
-		Log_dbg ( "Custom expiry %d for %s in group %s",
-			  days, msgId, ref );
-		break;
-	    }
-	
-	Itl_next( refs );	/* Throw away group number */
-    }
-
-    if ( res == -1 )
-	res = Cfg_expire();
-    return res;
-}
-
-Bool
-Db_expire( void )
-{
-    int cntDel, cntLeft, flags, expDays;
-    time_t nowTime, lastAccess;
-    const char *msgId;
-    Str name, tmpName;
-    GDBM_FILE tmpDbf;
-    datum key, val;
-
-    if ( ! Db_open() )
-        return FALSE;
-    snprintf( name, MAXCHAR, "%s/data/articles.gdbm", Cfg_spoolDir() );
-    snprintf( tmpName, MAXCHAR, "%s/data/articles.gdbm.new", Cfg_spoolDir() );
-    flags = GDBM_NEWDB | GDBM_FAST;
-    if ( ! ( tmpDbf = gdbm_open( tmpName, 512, flags, 0644, NULL ) ) )
-    {
-        Log_err( "Error opening %s for read/write (%s)", errMsg() );
-        Db_close();
-        return FALSE;
-    }
-    Log_inf( "Expiring articles" );
-    cntDel = 0;
-    cntLeft = 0;
-    nowTime = time( NULL );
-    if ( Db_first( &msgId ) )
-        do
-        {
-	    expDays = calcExpireDays( msgId );
-            lastAccess = Db_lastAccess( msgId );
-	    if ( expDays == -1 )
-		Log_err( "Internal error: Failed expiry calculation on %s",
-			 msgId );
-	    else if ( lastAccess == -1 )
-                Log_err( "Internal error: Getting lastAccess of %s failed",
-                         msgId );
-            else if ( expDays > 0
-		      && difftime( nowTime, lastAccess ) >
-		          ( (double) expDays * 24 * 3600 ) )
-            {
-#ifdef DEBUG
-		Str last, now;
-
-		Utl_cpyStr( last, ctime( &lastAccess ) );
-		last[ strlen( last ) - 1 ] = '\0';
-		Utl_cpyStr( now, ctime( &nowTime ) );
-		last[ strlen( now ) - 1 ] = '\0';
-                Log_dbg( "Expiring %s: last access %s, time now %s",
-			 msgId, last, now );
-#endif
-                ++cntDel;
-            }
-            else
-            {
-                ++cntLeft;
-                key.dptr = (void *)msgId;
-                key.dsize = strlen( msgId ) + 1;
-
-                val = gdbm_fetch( db.dbf, key );
-                if ( val.dptr != NULL )
-                {
-                    if ( gdbm_store( tmpDbf, key, val, GDBM_INSERT ) != 0 )
-                        Log_err( "Could not store %s in new database (%s)",
-                                 errMsg() );
-                    free( val.dptr );
-                }
-            }
-        }
-        while ( Db_next( &msgId ) );
-    Log_inf( "%lu articles deleted, %lu left", cntDel, cntLeft );
-    gdbm_close( tmpDbf );
-    Db_close();
-    rename( tmpName, name );
-    return TRUE;
-}
--- a/database.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
-  database.h
-
-  Article database.
-
-  $Id: database.h 44 2000-05-05 07:23:15Z enz $
-*/
-
-#ifndef DB_H
-#define DB_H
-
-#include <time.h>
-#include "common.h"
-#include "dynamicstring.h"
-#include "over.h"
-
-/* Article status flags: */
-#define DB_INTERESTING       0x01  /* Was article ever tried to read? */
-#define DB_NOT_DOWNLOADED    0x02  /* Not fully downloaded */
-#define DB_RETRIEVING_FAILED 0x04  /* Retrieving of article failed */
-
-/* Open database for r/w. Locking must be done by the caller! */
-Bool
-Db_open( void );
-
-void
-Db_close( void );
-
-/*
-  Creates an database entry for the article from the overview
-  information. Xref is replaced by grp:numb.
-*/
-Bool
-Db_prepareEntry( const Over *ov, const char *grp, int numb );
-
-/* Store full article. Can only be used after Db_prepareEntry. */
-Bool
-Db_storeArt( const char *msgId, const char *artTxt );
-
-void
-Db_setStat( const char *msgId, int stat );
-
-void
-Db_updateLastAccess( const char *msgId );
-
-/* Xref header line without hostname */
-void
-Db_setXref( const char *msgId, const char *xref );
-
-const char *
-Db_header( const char *msgId );
-
-const char *
-Db_body( const char *msgId );
-
-int
-Db_stat( const char *msgId );
-
-/* Get last modification time of entry. Returns -1, if msgId non-existing. */
-time_t
-Db_lastAccess( const char *msgId );
-
-/* Value of the References header line */
-const char *
-Db_ref( const char *msgId );
-
-/* Value of the From header line */
-const char *
-Db_from( const char *msgId );
-
-/* Value of the Date header line */
-const char *
-Db_date( const char *msgId );
-
-/* Xref header line without hostname */
-const char *
-Db_xref( const char *msgId );
-
-Bool
-Db_contains( const char *msgId );
-
-/* Delete entry from database */
-void
-Db_delete( const char *msgId );
-
-Bool
-Db_first( const char** msgId );
-
-Bool
-Db_next( const char** msgId );
-
-/*
-  Expire all articles that have not been accessed for a number of
-  days determined by their group membership and noffle configuration.
- */
-Bool
-Db_expire( void );
-
-#endif
--- a/dynamicstring.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
-  dynamicstring.c
-
-  $Id: dynamicstring.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include "dynamicstring.h"
-
-#include <sys/types.h>
-#include "log.h"
-
-struct DynStr
-{
-    size_t len; /* Current length (without trailing '\0') */
-    size_t max; /* Max length that fits into buffer (incl. trailing '\0') */
-    char *str;
-};
-
-static void
-reallocStr( DynStr *self, size_t max )
-{
-    if ( max <= self->max )
-        return;
-    if ( ! ( self->str = (char *)realloc( self->str, max ) ) )
-    {
-        Log_err( "Realloc of DynStr failed" );
-        exit( EXIT_FAILURE );
-    } 
-    if ( self->max == 0 ) /* First allocation? */
-        *(self->str) = '\0';
-    self->max = max;
-}
-
-DynStr *
-new_DynStr( size_t reserve )
-{
-    DynStr *s;
-    
-    if ( ! ( s = (DynStr *) malloc( sizeof( DynStr ) ) ) )
-    {
-        Log_err( "Allocation of DynStr failed" );
-        exit( EXIT_FAILURE );
-    }
-    s->len = 0;
-    s->max = 0;
-    s->str = NULL;
-    if ( reserve > 0 )
-        reallocStr( s, reserve + 1 );
-    return s;
-}
-
-void
-del_DynStr( DynStr *self )
-{
-    if ( ! self )
-        return;
-    free( self->str );
-    self->str = NULL;
-    free( self );
-}
-
-size_t
-DynStr_len( const DynStr *self )
-{
-    return self->len;
-}
-
-const char *
-DynStr_str( const DynStr *self )
-{
-    return self->str;
-}
-
-void
-DynStr_app( DynStr *self, const char *s )
-{
-    size_t len;
-
-    len = strlen( s );
-    if ( self->len + len + 1 > self->max )
-        reallocStr( self, self->len * 2 + len + 1 );
-    strcpy( self->str + self->len, s );
-    self->len += len;
-}
-
-void
-DynStr_appDynStr( DynStr *self, const DynStr *s )
-{
-    if ( self->len + s->len + 1 > self->max )
-        reallocStr( self, self->len * 2 + s->len + 1 );
-    memcpy( self->str + self->len, s->str, s->len + 1 );
-    self->len += s->len;
-}
-
-void
-DynStr_appLn( DynStr *self, const char *s )
-{
-    DynStr_app( self, s );
-    DynStr_app( self, "\n" );
-}
-
-void
-DynStr_appN( DynStr *self, const char *s, size_t n )
-{
-    size_t len = self->len;
-
-    if ( len + n + 1 > self->max )
-        reallocStr( self, len * 2 + n + 1 );
-    strncat( self->str + len, s, n );
-    self->len = len + strlen( self->str + len );
-}
-
-void
-DynStr_clear( DynStr *self )
-{
-    self->len = 0;
-    if ( self->max > 0 )
-        *(self->str) = '\0';
-}
-
--- a/dynamicstring.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
-  dynamicstring.h
-
-  String utilities
-
-  $Id: dynamicstring.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef DYNAMICSTRING_H
-#define DYNAMICSTRING_H
-
-#include <sys/types.h>
-
-/* A dynamically growing string */
-struct DynStr;
-typedef struct DynStr DynStr;
-
-/* Create new DynStr with given capacity */
-DynStr *
-new_DynStr( size_t reserve );
-
-/* Delete DynStr */
-void
-del_DynStr( DynStr *self );
-
-/* Return DynStr's length */
-size_t
-DynStr_len( const DynStr *self );
-
-/* Return DynStr's content ptr */
-const char *
-DynStr_str( const DynStr *self );
-
-/* append C-string to DynStr */
-void
-DynStr_app( DynStr *self, const char *s );
-
-/* append a DynStr to DynStr */
-void
-DynStr_appDynStr( DynStr *self, const DynStr *s );
-
-/* Append C-string + newline to DynStr */
-void
-DynStr_appLn( DynStr *self, const char *s );
-
-/* Append a maximum of n characters from C-string s to DynStr self */
-void
-DynStr_appN( DynStr *self, const char *s, size_t n );
-
-/* Truncate content of DynString to zero length */
-void
-DynStr_clear( DynStr *self );
-
-#endif
--- a/fetch.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/*
-  fetch.c
-
-  $Id: fetch.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include "fetch.h"
-#include <errno.h>
-#include <time.h>
-#include <signal.h>
-#include "client.h"
-#include "config.h"
-#include "content.h"
-#include "dynamicstring.h"
-#include "fetchlist.h"
-#include "request.h"
-#include "group.h"
-#include "log.h"
-#include "outgoing.h"
-#include "protocol.h"
-#include "pseudo.h"
-#include "util.h"
-
-struct Fetch
-{
-    Bool ready;
-    Str serv;
-} fetch = { FALSE, "" };
-
-static Bool
-connectToServ( const char *name )
-{
-    Log_inf( "Fetch from '%s'", name );
-    if ( ! Client_connect( name ) )
-    {
-        Log_err( "Could not connect to %s", name );
-        return FALSE;
-    }
-    return TRUE;
-}
-
-void
-Fetch_getNewGrps( void )
-{
-    time_t t;
-    Str file;
-
-    ASSERT( fetch.ready );
-    snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
-    if ( ! Utl_getStamp( &t, file ) )
-    {
-        Log_err( "Cannot read %s. Please run noffle --query groups", file );
-        return;
-    }
-    Log_inf( "Updating groupinfo" );
-    Client_getNewgrps( &t );
-    Utl_stamp( file );
-}
-
-void
-Fetch_getNewArts( const char *name, FetchMode mode )
-{
-    int next, first, last, oldLast;
-
-    if ( ! Client_changeToGrp( name ) )
-    {
-        Log_err( "Could not change to group %s", name );
-        return;
-    }
-    Cont_read( name );
-    Client_rmtFirstLast( &first, &last );
-    next = Grp_rmtNext( name );
-    oldLast = Cont_last();
-    if ( next == last + 1 )
-    {
-        Log_inf( "No new articles in %s", name );
-        Cont_write();
-        Grp_setFirstLast( name, Cont_first(), Cont_last() );
-        return;
-    }
-    if ( first == 0 && last == 0 )
-    {
-        Log_inf( "No articles in %s", name );
-        Cont_write();
-        Grp_setFirstLast( name, Cont_first(), Cont_last() );
-        return;
-    }
-    if ( next > last + 1 )
-    {
-        Log_err( "Article number inconsistent (%s rmt=%lu-%lu, next=%lu)",
-                 name, first, last, next );
-        Pseudo_cntInconsistent( name, first, last, next );
-    }
-    else if ( next < first )
-    {
-        Log_inf( "Missing articles (%s first=%lu next=%lu)",
-                 name, first, next );
-        Pseudo_missArts( name, first, next );
-    }
-    else
-        first = next;
-    if ( last - first > Cfg_maxFetch() )
-    {
-        Log_ntc( "Cutting number of overviews to %lu", Cfg_maxFetch() );
-        first = last - Cfg_maxFetch() + 1;
-    }
-    Log_inf( "Getting remote overviews %lu-%lu for group %s",
-             first, last, name );
-    Client_getOver( first, last, mode );
-    Cont_write();
-    Grp_setFirstLast( name, Cont_first(), Cont_last() );
-}
-
-void
-Fetch_updateGrps( void )
-{
-    FetchMode mode;
-    int i, size;
-    const char* name;
-
-    ASSERT( fetch.ready );
-    Fetchlist_read();
-    size = Fetchlist_size();
-    for ( i = 0; i < size; ++i )
-    {
-        Fetchlist_element( &name, &mode, i );
-        if ( strcmp( Grp_serv( name ), fetch.serv ) == 0 )
-            Fetch_getNewArts( name, mode );
-    }
-}
-
-void
-Fetch_getReq_( void )
-{
-    Str msgId;
-    DynStr *list;
-    const char *p;
-    int count = 0;
-
-    ASSERT( fetch.ready );
-    Log_dbg( "Retrieving articles marked for download" );
-    list = new_DynStr( 10000 );
-    if ( Req_first( fetch.serv, msgId ) )
-        do
-        {
-            DynStr_appLn( list, msgId );
-            if ( ++count % 20 == 0 ) /* Send max. 20 ARTICLE cmds at once */
-            {
-                p = DynStr_str( list );
-                Client_retrieveArtList( p );
-                while ( ( p = Utl_getLn( msgId, p ) ) )
-                    Req_remove( fetch.serv, msgId );
-                DynStr_clear( list );
-            }
-        }
-        while ( Req_next( msgId ) );
-    p = DynStr_str( list );
-    Client_retrieveArtList( p );
-    while ( ( p = Utl_getLn( msgId, p ) ) )
-        Req_remove( fetch.serv, msgId );
-    del_DynStr( list );
-}
-
-void
-Fetch_postArts( void )
-{
-    DynStr *s;
-    Str msgId, cmd, errStr, sender;
-    int ret;
-    const char *txt;
-    FILE *f;
-    sig_t lastHandler;
-
-    s = new_DynStr( 10000 );
-    if ( Out_first( fetch.serv, msgId, s ) )
-    {
-        Log_inf( "Posting articles" );
-        do
-        {
-            txt = DynStr_str( s );
-            Out_remove( fetch.serv, msgId );
-            if ( ! Client_postArt( msgId, txt, errStr ) )
-            {
-                Utl_cpyStr( sender, Cfg_mailTo() );
-                if ( strcmp( sender, "" ) == 0
-                     && ! Prt_searchHeader( txt, "SENDER", sender )
-                     && ! Prt_searchHeader( txt, "X-NOFFLE-X-SENDER",
-                                            sender ) /* see server.c */
-                     && ! Prt_searchHeader( txt, "FROM", sender ) )
-                    Log_err( "Article %s has no From/Sender/X-Sender field",
-                             msgId );
-                else
-                {
-                    Log_ntc( "Return article to '%s' by mail", sender );
-                    snprintf( cmd, MAXCHAR,
-                              "mail -s '[ NOFFLE: Posting failed ]' '%s'",
-                              sender );
-                    lastHandler = signal( SIGPIPE, SIG_IGN );
-                    f = popen( cmd, "w" );
-                    if ( f == NULL )
-                        Log_err( "Invocation of '%s' failed (%s)", cmd,
-                                 strerror( errno ) );
-                    else
-                    {
-                        fprintf( f,
-                                 "\t[ NOFFLE: POSTING OF ARTICLE FAILED ]\n"
-                                 "\n"
-                                 "\t[ The posting of your article failed. ]\n"
-                                 "\t[ Reason of failure at remote server: ]\n"
-                                 "\n"
-                                 "\t[ %s ]\n"
-                                 "\n"
-                                 "\t[ Full article text has been appended. ]\n"
-                                 "\n"
-                                 "%s"
-                                 ".\n",
-                                 errStr, txt );
-                        ret = pclose( f );
-                        if ( ret != EXIT_SUCCESS )
-                            Log_err( "'%s' exit value %d", cmd, ret );
-                        signal( SIGPIPE, lastHandler );
-                    }
-                }
-            }
-        }
-        while ( Out_next( msgId, s ) );
-    }
-    del_DynStr( s );
-}
-
-Bool
-Fetch_init( const char *serv )
-{
-    if ( ! connectToServ( serv ) )
-        return FALSE;
-    Utl_cpyStr( fetch.serv, serv );
-    fetch.ready = TRUE;
-    return TRUE;
-}
-
-void
-Fetch_close()
-{
-    Client_disconnect();
-    fetch.ready = FALSE;
-    Log_inf( "Fetch from '%s' finished", fetch.serv );
-}
--- a/fetch.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
-  fetch.h
-
-  Do the daily business by using client.c
-
-  $Id: fetch.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef FETCH_H
-#define FETCH_H
-
-#include "common.h"
-#include "database.h"
-#include "fetchlist.h"
-
-Bool
-Fetch_init( const char *serv );
-
-void
-Fetch_close( void );
-
-void
-Fetch_getNewGrps( void );
-
-void
-Fetch_updateGrps( void );
-
-void
-Fetch_getReq_( void );
-
-void
-Fetch_postArts( void );
-
-/* Get new articles in group "grp", using fetch mode "mode". */
-void
-Fetch_getNewArts( const char *grp, FetchMode mode );
-
-#endif
--- a/fetchlist.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-/*
-  fetchlist.c
-
-  $Id: fetchlist.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include "fetchlist.h"
-#include "config.h"
-#include "log.h"
-#include "util.h"
-
-struct Elem
-{
-    Str name;
-    FetchMode mode;
-};
-
-static struct Fetchlist
-{
-    struct Elem *elem;
-    int size;
-    int max;
-} fetchlist = { NULL, 0, 0 };
-
-static const char *
-getFile( void )
-{
-    static Str file;
-    snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
-    return file;
-}
-
-static void
-clearList( void )
-{
-    fetchlist.size = 0;
-}
-
-static int
-compareElem( const void *elem1, const void *elem2 )
-{
-    struct Elem* e1 = (struct Elem*)elem1; 
-    struct Elem* e2 = (struct Elem*)elem2;
-    return strcmp( e1->name, e2->name );
-}
-
-static struct Elem *
-searchElem( const char *name )
-{
-    int i;
-    
-    for ( i = 0; i < fetchlist.size; ++i )
-        if ( strcmp( name, fetchlist.elem[ i ].name ) == 0 )
-            return &fetchlist.elem[ i ];
-    return NULL;
-}
-
-static void
-appGrp( const char *name, FetchMode mode )
-{
-    struct Elem elem;
-
-    if ( fetchlist.max < fetchlist.size + 1 )
-    {
-        if ( ! ( fetchlist.elem
-                 = realloc( fetchlist.elem,
-                            ( fetchlist.max + 50 )
-                            * sizeof( fetchlist.elem[ 0 ] ) ) ) )
-        {
-            Log_err( "Could not realloc fetchlist" );
-            exit( EXIT_FAILURE );
-        }
-        fetchlist.max += 50;
-    }
-    strcpy( elem.name, name );
-    elem.mode = mode;
-    fetchlist.elem[ fetchlist.size++ ] = elem;
-}
-
-void
-Fetchlist_read( void )
-{
-    FILE *f;
-    const char *file = getFile();
-    char *p;
-    FetchMode mode = OVER;
-    Bool valid;
-    int ret;
-    Str line, grp, modeStr;
-
-    Log_dbg( "Reading %s", file );
-    clearList();
-    if ( ! ( f = fopen( file, "r" ) ) )
-    {
-        Log_inf( "No file %s", file );
-        return;
-    }
-    while ( fgets( line, MAXCHAR, f ) )
-    {
-        p = Utl_stripWhiteSpace( line );
-        if ( *p == '#' || *p == '\0' )
-            continue;
-        ret = sscanf( p, "%s %s", grp, modeStr );
-        valid = TRUE;
-        if ( ret < 1 || ret > 2 )
-            valid = FALSE;
-        else if ( ret >= 2 )
-        {
-            if ( strcmp( modeStr, "full" ) == 0 )
-                mode = FULL;
-            else if ( strcmp( modeStr, "thread" ) == 0 )
-                mode = THREAD;
-            else if ( strcmp( modeStr, "over" ) == 0 )
-                mode = OVER;
-            else
-                valid = FALSE;
-        }
-        if ( ! valid )
-        {
-            Log_err( "Invalid entry in %s: %s", file, line );
-            continue;
-        }
-        appGrp( grp, mode );
-    }
-    fclose( f );
-}
-
-Bool
-Fetchlist_write( void )
-{
-    int i;
-    FILE *f;
-    const char *file = getFile();
-    const char *modeStr = "";
-
-    qsort( fetchlist.elem, fetchlist.size, sizeof( fetchlist.elem[ 0 ] ),
-           compareElem );
-    if ( ! ( f = fopen( file, "w" ) ) )
-    {
-        Log_err( "Could not open %s for writing", file );
-        return FALSE;
-    }
-    for ( i = 0; i < fetchlist.size; ++i )
-    {
-        switch ( fetchlist.elem[ i ].mode )
-        {
-        case FULL:
-            modeStr = "full"; break;
-        case THREAD:
-            modeStr = "thread"; break;
-        case OVER:
-            modeStr = "over"; break;
-        }
-        fprintf( f, "%s %s\n", fetchlist.elem[ i ].name, modeStr );
-    }
-    fclose( f );
-    return TRUE;
-}
-
-int
-Fetchlist_size( void )
-{
-    return fetchlist.size;
-}
-
-Bool
-Fetchlist_contains( const char *name )
-{
-    return ( searchElem( name ) != NULL );
-}
-
-Bool
-Fetchlist_element( const char **name, FetchMode *mode, int index )
-{
-    if ( index < 0 || index >= fetchlist.size )
-        return FALSE;
-    *name = fetchlist.elem[ index ].name;
-    *mode = fetchlist.elem[ index ].mode;
-    return TRUE;
-}
-
-Bool
-Fetchlist_add( const char *name, FetchMode mode )
-{
-    struct Elem *elem = searchElem( name );
-    if ( elem == NULL )
-    {
-        appGrp( name, mode );
-        return TRUE;
-    }
-    strcpy( elem->name, name );
-    elem->mode = mode;
-    return FALSE;
-}
-
-Bool
-Fetchlist_remove( const char *name )
-{
-    struct Elem *elem = searchElem( name );
-    if ( elem == NULL )
-        return FALSE;
-    *elem = fetchlist.elem[ fetchlist.size - 1 ];
-    --fetchlist.size;
-    return TRUE;
-}
--- a/fetchlist.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
-  fetchlist.h
-
-  List of groups that are to be fetched presently.
-
-  $Id: fetchlist.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef FETCHLIST_H
-#define FETCHLIST_H
-
-#include "common.h"
-
-typedef enum { FULL, THREAD, OVER } FetchMode;
-
-void
-Fetchlist_read( void );
-
-/* Invalidates any indices (list is sorted by name before saving) */
-Bool
-Fetchlist_write( void );
-
-int
-Fetchlist_size( void );
-
-Bool
-Fetchlist_contains( const char *name );
-
-/* Get element number index. */
-Bool
-Fetchlist_element( const char **name, FetchMode *mode, int index );
-
-/* Add entry. Invalidates any indices. Returns TRUE if new entry, FALSE if
-   entry was overwritten. */
-Bool
-Fetchlist_add( const char *name, FetchMode mode );
-
-/* Remove entry. Invalidates any indices. Returns FALSE if not found. */
-Bool
-Fetchlist_remove( const char *name );
-
-#endif
--- a/group.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,370 +0,0 @@
-/*
-  group.c
-
-  The group database resides in groupinfo.gdbm and stores all we know about
-  the groups we know of. One database record is cached in the global struct
-  grp. Group information is transfered between the grp and the database by
-  loadGrp() and saveGrp(). This is done transparently. Access to the groups
-  database is done by group name, by the functions defined in group.h.        
-
-  $Id: group.c 47 2000-05-05 08:32:53Z enz $
-*/
-
-#include "group.h"
-#include <gdbm.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include "config.h"
-#include "log.h"
-#include "util.h"
-
-/* currently only used within grp */
-typedef struct
-{
-    int first;		/* number of first article within group */
-    int last;		/* number of last article within group */
-    int rmtNext;
-    time_t created;
-    time_t lastAccess;
-} Entry;
-
-struct
-{
-    Str name;		/* name of the group */
-    Entry entry;	/* more information about this group */
-    Str serv;		/* server the group resides on */
-    Str dsc;		/* description of the group */
-    char postAllow;	/* Posting status */
-    GDBM_FILE dbf;
-} grp = { "(no grp)", { 0, 0, 0, 0, 0 }, "", "", ' ', NULL };
-
-/*
-  Note: postAllow should really go in Entry. But changing Entry would
-  make backwards group file format capability tricky, so it goes
-  where it is, and we test the length of the retrieved record to
-  determine if it exists.
-
-  Someday if we really change the record format this should be tidied up.
- */
-
-static const char *
-errMsg( void )
-{
-    if ( errno != 0 )
-        return strerror( errno );
-    return gdbm_strerror( gdbm_errno );
-}
-
-Bool
-Grp_open( void )
-{
-    Str name;
-    int flags;
-
-    ASSERT( grp.dbf == NULL );
-    snprintf( name, MAXCHAR, "%s/data/groupinfo.gdbm", Cfg_spoolDir() );
-    flags = GDBM_WRCREAT | GDBM_FAST;
-    if ( ! ( grp.dbf = gdbm_open( name, 512, flags, 0644, NULL ) ) )
-    {
-        Log_err( "Error opening %s for r/w (%s)", errMsg() );
-        return FALSE;
-    }
-    Log_dbg( "%s opened for r/w", name );
-    return TRUE;
-}
-
-void
-Grp_close( void )
-{
-    ASSERT( grp.dbf );
-    Log_dbg( "Closing groupinfo" );
-    gdbm_close( grp.dbf );
-    grp.dbf = NULL;
-    Utl_cpyStr( grp.name, "" );
-}
-
-/* Load group info from gdbm-database into global struct grp */
-static Bool
-loadGrp( const char *name )
-{
-    const char *p;
-    datum key, val;
-
-    ASSERT( grp.dbf );
-    if ( strcmp( grp.name, name ) == 0 )
-         return TRUE;
-    key.dptr = (void *)name;
-    key.dsize = strlen( name ) + 1;
-    val = gdbm_fetch( grp.dbf, key );
-    if ( val.dptr == NULL )
-        return FALSE;
-    grp.entry = *( (Entry *)val.dptr );
-    p = val.dptr + sizeof( grp.entry );
-    Utl_cpyStr( grp.serv, p );
-    p += strlen( p ) + 1;
-    Utl_cpyStr( grp.dsc, p );
-    p += strlen( p) + 1;
-    if ( p - val.dptr < val.dsize )
-	grp.postAllow = p[ 0 ];
-    else
-	grp.postAllow = 'y';
-    Utl_cpyStr( grp.name, name );
-    free( val.dptr );
-    return TRUE;
-}
-
-/* Save group info from global struct grp into gdbm-database */
-static void
-saveGrp( void )
-{
-    size_t lenServ, lenDsc, bufLen;
-    datum key, val;
-    void *buf;
-    char *p;
-
-    ASSERT( grp.dbf );
-    lenServ = strlen( grp.serv );
-    lenDsc = strlen( grp.dsc );
-    bufLen = sizeof( grp.entry ) + lenServ + lenDsc + 2 + sizeof( char );
-    buf = malloc( bufLen );
-    memcpy( buf, (void *)&grp.entry, sizeof( grp.entry ) );
-    p = (char *)buf + sizeof( grp.entry );
-    strcpy( p, grp.serv );
-    p += lenServ + 1;
-    strcpy( p, grp.dsc );
-    p += lenDsc + 1;
-    p[ 0 ] = grp.postAllow;
-    key.dptr = (void *)grp.name;
-    key.dsize = strlen( grp.name ) + 1;
-    val.dptr = buf;
-    val.dsize = bufLen;
-    if ( gdbm_store( grp.dbf, key, val, GDBM_REPLACE ) != 0 )
-        Log_err( "Could not save group %s: %s", errMsg() );
-    free( buf );
-}
-
-Bool
-Grp_exists( const char *name )
-{
-    datum key;
-
-    ASSERT( grp.dbf );
-    key.dptr = (void*)name;
-    key.dsize = strlen( name ) + 1;
-    return gdbm_exists( grp.dbf, key );
-}
-
-Bool
-Grp_local( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return ( strcmp( grp.serv, GRP_LOCAL_SERVER_NAME ) == 0 );
-}
-
-void
-Grp_create( const char *name )
-{
-    Utl_cpyStr( grp.name, name );
-    Utl_cpyStr( grp.serv, "(unknown)" );
-    grp.dsc[ 0 ] = '\0';
-    grp.entry.first = 1;
-    grp.entry.last = 0;
-    grp.entry.rmtNext = 0;
-    grp.entry.created = 0;
-    grp.entry.lastAccess = 0;
-    grp.postAllow = 'y';
-    saveGrp();
-}
-
-void
-Grp_delete( const char *name )
-{
-    datum key;
-
-    ASSERT( grp.dbf );
-    key.dptr = (void*)name;
-    key.dsize = strlen( name ) + 1;
-    gdbm_delete( grp.dbf, key );
-}
-
-const char *
-Grp_dsc( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return NULL;
-    return grp.dsc;
-}
-
-const char *
-Grp_serv( const char *name )
-{
-    static Str serv = "";
-
-    if ( ! loadGrp( name ) )
-        return "[unknown grp]";
-    if ( Cfg_servListContains( grp.serv )
-         || Grp_local( name ) )
-        Utl_cpyStr( serv, grp.serv );
-    else
-        snprintf( serv, MAXCHAR, "[%s]", grp.serv );
-    return serv;
-}
-
-int
-Grp_first( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.entry.first;
-}
-
-int
-Grp_last( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.entry.last;
-}
-
-int
-Grp_lastAccess( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.entry.lastAccess;
-}
-
-int
-Grp_rmtNext( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.entry.rmtNext;
-}
-
-time_t
-Grp_created( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.entry.created;
-}
-
-char
-Grp_postAllow( const char *name )
-{
-    if ( ! loadGrp( name ) )
-        return 0;
-    return grp.postAllow;
-}
-
-
-/* Replace group's description (only if value != ""). */
-void
-Grp_setDsc( const char *name, const char *value )
-{
-    if ( loadGrp( name ) )
-    {
-        Utl_cpyStr( grp.dsc, value );
-        saveGrp();
-    }
-}
-
-void
-Grp_setLocal( const char *name )
-{
-    Grp_setServ( name, GRP_LOCAL_SERVER_NAME );
-}
-
-void
-Grp_setServ( const char *name, const char *value )
-{
-    if ( loadGrp( name ) )
-    {
-        Utl_cpyStr( grp.serv, value );
-        saveGrp();
-    }
-}
-
-void
-Grp_setCreated( const char *name, time_t value )
-{
-    if ( loadGrp( name ) )
-    {
-        grp.entry.created = value;
-        saveGrp();
-    }
-}
-
-void
-Grp_setRmtNext( const char *name, int value )
-{
-    if ( loadGrp( name ) )
-    {
-        grp.entry.rmtNext = value;
-        saveGrp();
-    }
-}
-
-void
-Grp_setLastAccess( const char *name, int value )
-{
-    if ( loadGrp( name ) )
-    {
-        grp.entry.lastAccess = value;
-        saveGrp();
-    }
-}
-
-void
-Grp_setPostAllow( const char *name, char postAllow )
-{
-    if ( loadGrp( name ) )
-    {
-        grp.postAllow = postAllow;
-        saveGrp();
-    }
-}
-
-void
-Grp_setFirstLast( const char *name, int first, int last )
-{
-    if ( loadGrp( name ) )
-    {
-        grp.entry.first = first;
-        grp.entry.last = last;
-        saveGrp();
-    }
-}
-
-static datum cursor = { NULL, 0 };
-
-Bool
-Grp_firstGrp( const char **name )
-{
-    ASSERT( grp.dbf );
-    if ( cursor.dptr != NULL )
-    {
-        free( cursor.dptr );
-        cursor.dptr = NULL;
-    }
-    cursor = gdbm_firstkey( grp.dbf );
-    *name = cursor.dptr;
-    return ( cursor.dptr != NULL );
-}
-
-Bool
-Grp_nextGrp( const char **name )
-{
-    void *oldDptr = cursor.dptr;
-
-    ASSERT( grp.dbf );
-    if ( cursor.dptr == NULL )
-        return FALSE;
-    cursor = gdbm_nextkey( grp.dbf, cursor );
-    free( oldDptr );
-    *name = cursor.dptr;
-    return ( cursor.dptr != NULL );
-}
--- a/group.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
-  group.h
-
-  Groups database
-
-  $Id: group.h 47 2000-05-05 08:32:53Z enz $
-*/
-
-#ifndef GRP_H
-#define GRP_H
-
-#include <time.h>
-#include "common.h"
-
-#define GRP_LOCAL_SERVER_NAME "(local)"
-
-/* open group database */
-Bool
-Grp_open( void );
-
-/* close group database */
-void
-Grp_close( void );
-
-/* does group exist? */
-Bool
-Grp_exists( const char *name );
-
-/* is it a local group? */
-Bool
-Grp_local( const char *name );
-
-/* create new group and save it in database */
-void
-Grp_create( const char *name );
-
-/* delete a group and its articles from the database. */
-void
-Grp_delete( const char *name );
-
-/* Get group description */
-const char *
-Grp_dsc( const char *name );
-
-/* Get server the group resides on */
-const char *
-Grp_serv( const char *name );
-
-/*
-  Get article number of the first article in the group
-  This number is a hint only, it is independent of the
-  real articles in content.c
-*/
-int
-Grp_first( const char *name );
-
-/*
-  Get article number of the last article in the group
-  This number is a hint only, it is independent of the
-  real articles in content.c
-*/
-int
-Grp_last( const char *name );
-
-int
-Grp_lastAccess( const char *name );
-
-int
-Grp_rmtNext( const char *name );
-
-time_t
-Grp_created( const char *name );
-
-char
-Grp_postAllow( const char *name );
-
-/* Replace group's description (only if value != ""). */
-void
-Grp_setDsc( const char *name, const char *value );
-
-void
-Grp_setLocal( const char *name );
-
-void
-Grp_setServ( const char *name, const char *value );
-
-void
-Grp_setCreated( const char *name, time_t value );
-
-void
-Grp_setRmtNext( const char *name, int value );
-
-void
-Grp_setLastAccess( const char *name, int value );
-
-void
-Grp_setFirstLast( const char *name, int first, int last );
-
-void
-Grp_setPostAllow( const char *name, char postAllow );
-
-/* Begin iterating trough the names of all groups. Store name of first
-   group (or NULL if there aren't any) in name. Returns whether there are
-   any groups. */
-Bool
-Grp_firstGrp( const char **name );
-
-/* Continue iterating trough the names of all groups. Store name of next
-   group (or NULL if there aren't any more) in name. Returns TRUE on
-   success, FALSE when there are no more groups. */
-Bool
-Grp_nextGrp( const char **name );
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/install-sh	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
--- a/itemlist.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
-  itemlist.c
-
-  $Id: itemlist.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include "itemlist.h"
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include "common.h"
-#include "log.h"
-
-struct ItemList
-{
-    char *list;
-    char *separators;
-    char *next;
-    size_t count;
-};
-
-/* Make a new item list. */
-ItemList *
-new_Itl( const char *list, const char *separators )
-{
-    ItemList * res;
-    char *p;
-    Bool inItem;
-
-    res = (ItemList *) malloc( sizeof( ItemList ) );
-    if ( res == NULL )
-    {
-	Log_err( "Malloc of ItemList failed." );
-	exit( EXIT_FAILURE );
-    }
-    
-    res->list = (char *) malloc ( strlen(list) + 2 );
-    if ( res->list == NULL )
-    {
-	Log_err( "Malloc of ItemList.list failed." );
-	exit( EXIT_FAILURE );
-    }
-    strcpy( res->list, list );
-
-    if (  ( res->separators = strdup( separators ) ) == NULL )
-    {
-	Log_err( "Malloc of ItemList.separators failed." );
-	exit( EXIT_FAILURE );
-    }
-
-    res->count = 0;
-    res->next = res->list;
-
-    /* Separate items into strings and have final zero-length string. */
-    for( p = res->list, inItem = FALSE; *p != '\0'; p++ )
-    {
-	Bool isSep = ( strchr( separators, p[ 0 ] ) != NULL );
-	
-	if ( inItem )
-	{
-	    if ( isSep )
-	    {
-		p[ 0 ] = '\0';
-		inItem = FALSE;
-		res->count++;
-	    }
-	}
-	else
-	{
-	    if ( ! isSep )
-		inItem = TRUE;
-	}
-    }
-    if ( inItem )
-	res->count++;
-    p[ 1 ] = '\0';
-    return res;
-}
-
-/* Delete an item list. */
-void
-del_Itl( ItemList *self )
-{
-    if ( self == NULL )
-	return;
-    free( self->list );
-    free( self->separators );
-    free( self );
-}
-
-/* Get first item. */
-const char *
-Itl_first( ItemList *self)
-{
-    self->next = self->list;
-    return Itl_next( self );
-}
-
-/* Get next item or NULL. */
-const char *
-Itl_next( ItemList *self )
-{
-    const char *res = self->next;
-
-    if ( res[ 0 ] == '\0' )
-	return NULL;
-
-    while ( strchr( self->separators, res[ 0 ] ) != NULL )
-	res++;
-
-    if ( res[ 0 ] == '\0' && res[ 1 ] == '\0' )
-	return NULL;
-
-    self->next += strlen( res ) + 1;
-    return res;
-}
-
-/* Get count of items in list. */
-size_t
-Itl_count( const ItemList *self )
-{
-    return self->count;
-}
--- a/itemlist.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
-  itemlist.h
-
-  Copy a string wiht a list of separated items (as found in several
-  header lines) and provide a convenient way of accessing the
-  individual items.
-  
-  $Id: itemlist.h 32 2000-04-29 14:45:56Z enz $ */
-
-#ifndef ITEMLIST_H
-#define ITEMLIST_H
-
-#include <sys/types.h>
-
-struct ItemList;
-typedef struct ItemList ItemList;
-
-/* Make a new item list. */
-ItemList *
-new_Itl( const char *list, const char *separators );
-
-/* Delete an item list. */
-void
-del_Itl( ItemList *self );
-
-/* Get first item. */
-const char *
-Itl_first( ItemList *self);
-
-/* Get next item or NULL. */
-const char *
-Itl_next( ItemList *self );
-
-/* Get count of items in list. */
-size_t
-Itl_count( const ItemList *self );
-
-#endif
--- a/lock.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
-  lock.c
-
-  $Id: lock.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include "lock.h"
-#include <errno.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <time.h>
-#include <unistd.h>
-#include "config.h"
-#include "log.h"
-#include "database.h"
-#include "group.h"
-#include "request.h"
-
-struct Lock
-{
-    int lockFd;
-    Str lockFile;
-} lock = { -1, "" };
-
-
-#ifdef DEBUG
-static Bool
-testLock( void )
-{
-    return ( lock.lockFd != -1 );    
-}
-#endif
-
-static Bool
-waitLock( void )
-{
-    int fd;
-    struct flock l;
-
-    ASSERT( ! testLock() );
-    Log_dbg( "Waiting for lock ..." );
-    snprintf( lock.lockFile, MAXCHAR, "%s/lock/global", Cfg_spoolDir() );
-    if ( ( fd = open( lock.lockFile, O_WRONLY | O_CREAT, 0644 ) ) < 0 )
-    {
-        Log_err( "Cannot open %s (%s)", lock.lockFile, strerror( errno ) );
-        return FALSE;
-    }
-    l.l_type = F_WRLCK;
-    l.l_start = 0;
-    l.l_whence = SEEK_SET;
-    l.l_len = 0;
-    if ( fcntl( fd, F_SETLKW, &l ) < 0 )
-    {
-        Log_err( "Cannot lock %s: %s", lock.lockFile, strerror( errno ) );
-        return FALSE;
-    }
-    lock.lockFd = fd;
-    Log_dbg( "Lock successful" );
-    return TRUE;
-}
-
-static void
-releaseLock( void )
-{
-    struct flock l;
-
-    ASSERT( testLock() );    
-    l.l_type = F_UNLCK;
-    l.l_start = 0;
-    l.l_whence = SEEK_SET;
-    l.l_len = 0;
-    if ( fcntl( lock.lockFd, F_SETLK, &l ) < 0 )
-        Log_err( "Cannot release %s: %s", lock.lockFile,
-                 strerror( errno ) );
-    close( lock.lockFd );
-    lock.lockFd = -1;
-    Log_dbg( "Releasing lock" );
-}
-
-
-/* Open all databases and set global lock. */
-Bool
-Lock_openDatabases( void )
-{
-  if ( ! waitLock() )
-    {
-      Log_err( "Could not get write lock" );
-      return FALSE;
-    }
-  if ( ! Db_open() )
-    {
-      Log_err( "Could not open database" );
-      releaseLock();
-      return FALSE;
-    }
-  if ( ! Grp_open() )
-    {
-      Log_err( "Could not open groupinfo" );
-      Db_close();
-      releaseLock();
-      return FALSE;
-    }
-  if ( ! Req_open() )
-    {
-      Log_err( "Could not initialize request database" );
-      Grp_close();
-      Db_close();
-      releaseLock();
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-
-/* Close all databases and release global lock. */
-void
-Lock_closeDatabases( void )
-{
-  Grp_close();
-  Db_close();
-  Req_close();
-  releaseLock();
-}
--- a/lock.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
-  lock.h
-
-  Opening/Closing of the various databases: article overview database,
-  articla database, groups database, outgoing articles database, requests
-  database. Handles global lock.
-
-  $Id: lock.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef LOCK_H
-#define LOCK_H
-
-#include "common.h"
-
-/* Open all databases and set global lock. */
-Bool
-Lock_openDatabases( void );
-
-/* Close all databases and release global lock. */
-void
-Lock_closeDatabases( void );
-
-#endif
--- a/log.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
-  log.c
-
-  $Id: log.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include <syslog.h>
-#include <stdarg.h>
-#include "common.h"
-
-#define MAXLENGTH 240
-
-struct
-{
-    Bool interactive;
-} log = { FALSE };
-
-void
-Log_init( Str name, Bool interactive, int facility )
-{
-    int option = LOG_PID | LOG_CONS;
-
-    log.interactive = interactive;
-    openlog( name, option, facility );
-}
-
-#define DO_LOG( LEVEL )               \
-    va_list ap;                       \
-    Str t;                            \
-                                      \
-    va_start( ap, fmt );              \
-    vsnprintf( t, MAXCHAR, fmt, ap ); \
-    if ( MAXLENGTH < MAXCHAR )        \
-        t[ MAXLENGTH ] = '\0';        \
-    syslog( LEVEL, "%s", t );         \
-    if ( log.interactive )            \
-        fprintf( stderr, "%s\n", t );   \
-    va_end( ap );
-
-void
-Log_inf( const char *fmt, ... )
-{
-    DO_LOG( LOG_INFO );
-}
-
-void
-Log_err( const char *fmt, ... )
-{
-    DO_LOG( LOG_ERR );
-}
-
-/* Ensure the condition "cond" is true; otherwise log an error and return 1 */
-int 
-Log_check(int cond, const char *fmt, ... )
-{
-  if (!cond) {
-    DO_LOG( LOG_ERR );
-    return 1;
-  }
-  return 0;
-}
-
-void
-Log_ntc( const char *fmt, ... )
-{
-    DO_LOG( LOG_NOTICE );
-}
-
-void
-Log_dbg( const char *fmt, ... )
-{
-#ifdef DEBUG
-    DO_LOG( LOG_DEBUG );
-#endif
-}
--- a/log.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
-  log.h
-
-  Print log messages to syslog, stdout/stderr.
-
-  $Id: log.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef LOG_H
-#define LOG_H
-
-#include "common.h"
-
-/*
-  Initialise logging (required before using any log functions).
-  name: program name for syslog
-  interactive: print messages also to stderr/stdout
-  facility: like syslog
-*/
-void
-Log_init( Str name, Bool interactive, int facility );
-
-/* Log level info */
-void
-Log_inf( const char *fmt, ... );
-
-/* Log level error */
-void
-Log_err( const char *fmt, ... );
-
-/* Check for cond being true. Otherwise log an error, and return 1. */
-int 
-Log_check(int cond, const char *fmt, ... );
-
-/* Log level notice */
-void
-Log_ntc( const char *fmt, ... );
-
-/* Log only if DEBUG is defined. */
-void
-Log_dbg( const char *fmt, ... );
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/missing	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 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, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f y.tab.h ]; then
+	echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mkinstalldirs	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs 49 2000-05-05 21:45:56Z uh1763 $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- a/noffle.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,798 +0,0 @@
-/*
-  noffle.c
-
-  Main program. Implements specified actions, but running as server, which
-  is done by Serv_run(), declared in server.h.
-  
-  Locking policy: lock access to databases while noffle is running, but
-  not as server. If noffle runs as server, locking is performed while
-  executing NNTP commands, but temporarily released if no new command is
-  received for some seconds (to allow multiple clients connect at the same
-  time).
-
-  $Id: noffle.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include <ctype.h>
-#include <errno.h>
-#include <getopt.h>
-#include <signal.h>
-#include <sys/resource.h>
-#include <syslog.h>
-#include <unistd.h>
-#include "client.h"
-#include "common.h"
-#include "content.h"
-#include "control.h"
-#include "config.h"
-#include "database.h"
-#include "fetch.h"
-#include "fetchlist.h"
-#include "group.h"
-#include "itemlist.h"
-#include "log.h"
-#include "online.h"
-#include "outgoing.h"
-#include "over.h"
-#include "pseudo.h"
-#include "util.h"
-#include "server.h"
-#include "request.h"
-#include "lock.h"
-
-struct Noffle
-{
-    Bool queryGrps;
-    Bool queryDsc;
-    Bool queryTimes;
-    Bool interactive;
-} noffle = { FALSE, FALSE, FALSE, TRUE };
-
-static void
-doArt( const char *msgId )
-{
-    const char *id;
-
-    if ( strcmp( msgId, "all" ) == 0 )
-    {
-        if ( ! Db_first( &id ) )
-            fprintf( stderr, "Database empty.\n" );
-        else
-            do
-            {
-                printf( "From %s %s\n"
-                        "%s\n"
-                        "%s\n",
-                        Db_from( id ), Db_date( id ),
-                        Db_header( id ),
-                        Db_body( id ) );
-            }
-            while ( Db_next( &id ) );
-    }
-    else
-    {
-        if ( ! Db_contains( msgId ) )
-            fprintf( stderr, "Not in database.\n" );
-        else
-            printf( "%s\n%s", Db_header( msgId ), Db_body( msgId ) );
-    }
-}
-
-static void
-doCancel( const char *msgId )
-{
-    switch( Ctrl_cancel( msgId ) )
-    {
-    case CANCEL_NO_SUCH_MSG:
-	printf( "No such message '%s'.\n", msgId );
-	break;
-
-    case CANCEL_OK:
-	printf( "Message '%s' cancelled.\n", msgId );
-	break;
-
-    case CANCEL_NEEDS_MSG:
-	printf( "Message '%s' cancelled in local database only.\n", msgId );
-	break;
-    }
-}
-
-/* List articles requested from one particular server */
-static void
-listRequested1( const char* serv )
-{
-  Str msgid;
-
-  if ( ! Req_first( serv, msgid ) )
-      return;
-  do
-      printf( "%s %s\n", msgid, serv );
-  while ( Req_next( msgid ) );
-}
-
-/* List requested articles. List for all servers if serv = "all" or serv =
-   NULL. */
-void
-doRequested( const char *arg )
-{
-    Str serv;
-    
-    if ( ! arg || ! strcmp( arg, "all" ) )
-    {
-        Cfg_beginServEnum();   
-        while ( Cfg_nextServ( serv ) )
-            listRequested1( serv );
-    }   
-    else
-        listRequested1( arg );
-}
-
-
-static void
-doDb( void )
-{
-    const char *msgId;
-
-    if ( ! Db_first( &msgId ) )
-        fprintf( stderr, "Database empty.\n" );
-    else
-        do
-            printf( "%s\n", msgId );
-        while ( Db_next( &msgId ) );
-}
-
-static void
-doFetch( void )
-{
-    Str serv;
-
-    Cfg_beginServEnum();
-    while ( Cfg_nextServ( serv ) )
-        if ( Fetch_init( serv ) )
-        {
-            Fetch_postArts();
-
-            Fetch_getNewGrps();
-
-            /* Get overviews of new articles and store IDs of new articles
-               that are to be fetched becase of FULL or THREAD mode in the
-               request database. */
-            Fetch_updateGrps();         
-
-            /* get requested articles */
-            Fetch_getReq_();
-
-            Fetch_close();
-        }
-}
-
-static void
-doQuery( void )
-{
-    Str serv;
-
-    Cfg_beginServEnum();
-    while ( Cfg_nextServ( serv ) )
-        if ( Fetch_init( serv ) )
-        {
-            if ( noffle.queryGrps )
-                Client_getGrps();
-            if ( noffle.queryDsc )
-                Client_getDsc();
-            if ( noffle.queryTimes )
-                Client_getCreationTimes();
-            Fetch_close();
-        }
-}
-
-/* Expire all overviews not in database */
-static void
-expireContents( void )
-{
-    const Over *ov;
-    int i;
-    int cntDel, cntLeft;
-    Str grp;
-    Bool autoUnsubscribe;
-    int autoUnsubscribeDays;
-    time_t now = time( NULL ), maxAge = 0;
-    const char *msgId;
-
-    autoUnsubscribe = Cfg_autoUnsubscribe();
-    autoUnsubscribeDays = Cfg_autoUnsubscribeDays();
-    maxAge = Cfg_autoUnsubscribeDays() * 24 * 3600;
-    if ( ! Cont_firstGrp( grp ) )
-        return;
-    Log_inf( "Expiring overviews not in database" );
-    do
-    {
-        if ( ! Grp_exists( grp ) )
-            Log_err( "Overview file for unknown group %s exists", grp );
-        else
-        {
-            cntDel = cntLeft = 0;
-            Cont_read( grp );
-            for ( i = Cont_first(); i <= Cont_last(); ++i )
-                if ( ( ov = Cont_get( i ) ) )
-                {
-                    msgId = Ov_msgId( ov );
-                    if ( ! Db_contains( msgId ) )
-                    {
-                        Cont_delete( i );
-                        ++cntDel;
-                    }
-                    else
-                        ++cntLeft;
-                }
-            if ( ! Grp_local( grp )
-		 && autoUnsubscribe
-                 && difftime( now, Grp_lastAccess( grp ) ) > maxAge )
-            {
-                Log_ntc( "Auto-unsubscribing from %s after %d "
-                         "days without access",
-                         grp, autoUnsubscribeDays );
-                Pseudo_autoUnsubscribed( grp, autoUnsubscribeDays );
-                Fetchlist_read();
-                Fetchlist_remove( grp );
-                Fetchlist_write();
-            }
-            Cont_write();
-            Grp_setFirstLast( grp, Cont_first(), Cont_last() );
-            Log_inf( "%ld overviews deleted from group %s, %ld left (%ld-%ld)",
-                     cntDel, grp, cntLeft, Grp_first( grp ), Grp_last( grp ) );
-        }
-    }
-    while ( Cont_nextGrp( grp ) );
-}
-
-static void
-doExpire( void )
-{
-    Db_close();
-    Db_expire();
-    if ( ! Db_open() )
-        return;
-    expireContents();
-}
-
-static void
-doCreateLocalGroup( const char * name )
-{
-    Str grp;
-
-    Utl_cpyStr( grp, name );
-    Utl_toLower( grp );
-    name = Utl_stripWhiteSpace( grp );
-    
-    if ( Grp_exists( name ) )
-        fprintf( stderr, "'%s' already exists.\n", name );
-    else
-    {
-        Log_inf( "Creating new local group '%s'", name );
-        Grp_create( name );
-        Grp_setLocal( name );
-	printf( "New local group '%s' created.\n", name );
-    }
-}
-
-static void
-doDeleteLocalGroup( const char * name )
-{
-    Str grp;
-
-    Utl_cpyStr( grp, name );
-    Utl_toLower( grp );
-    name = Utl_stripWhiteSpace( grp );
-    
-    if ( ! Grp_exists( name ) )
-        fprintf( stderr, "'%s' does not exist.\n", name );
-    else
-    {
-	int i;
-	
-        Log_inf( "Deleting group '%s'", name );
-
-	/*
-	  Delete all articles that are only in the group. Check the
-	  article Xref for more than one group.
-	 */
-	Cont_read( name );
-	for ( i = Cont_first(); i <= Cont_last(); i++ )
-	{
-	    const Over *over;
-	    Bool toDelete;
-	    Str msgId;
-
-	    over = Cont_get( i );
-	    toDelete = TRUE;
-	    if ( over != NULL )
-	    {
-		ItemList * xref;
-
-		Utl_cpyStr( msgId, Ov_msgId( over ) );
-		xref = new_Itl( Db_xref( msgId ), " " );
-		if ( Itl_count( xref ) > 1 )
-		    toDelete = FALSE;
-		del_Itl( xref );
-	    }
-	    Cont_delete( i );
-	    if ( toDelete )
-		Db_delete( msgId );
-	}
-	Cont_write();
-	Grp_delete( name );
-	printf( "Group '%s' deleted.\n", name );
-    }
-}
-
-static void
-doList( void )
-{
-    FetchMode mode;
-    int i, size;
-    const char *name, *modeStr = "";
-
-    Fetchlist_read();
-    size = Fetchlist_size();
-    if ( size == 0 )
-        fprintf( stderr, "Fetch list is empty.\n" );
-    else
-        for ( i = 0; i < size; ++i )
-        {
-            Fetchlist_element( &name, &mode, i );
-            switch ( mode )
-            {
-            case FULL:
-                modeStr = "full"; break;
-            case THREAD:
-                modeStr = "thread"; break;
-            case OVER:
-                modeStr = "over"; break;
-            }
-            printf( "%s %s %s\n", name, Grp_serv( name ), modeStr );
-        }
-}
-
-/* A modify command. argc/argv start AFTER '-m'. */
-static Bool
-doModify( const char *cmd, int argc, char **argv )
-{
-    const char *grp;
-
-    if ( argc < 2 )
-    {
-	fprintf( stderr, "Insufficient arguments to -m\n" );
-	return FALSE;
-	
-    }
-    else if ( strcmp( cmd, "desc" ) != 0
-	      && strcmp( cmd, "post" ) != 0 )
-    {
-	fprintf( stderr, "Unknown argument -m %s\n", optarg );
-	return FALSE;
-    }
-    
-    grp = argv[ 0 ];
-    argv++;
-    argc--;
-    
-    if ( strcmp( cmd, "desc" ) == 0 )
-    {
-	Str desc;
-
-	Utl_cpyStr( desc, *( argv++ ) );
-	while ( --argc > 0 )
-	{
-	    Utl_catStr( desc, " " );
-	    Utl_catStr( desc, *( argv++ ) );
-	}
-
-	Grp_setDsc( grp, desc );
-    }
-    else
-    {
-	char c;
-
-	if ( ! Grp_local( grp ) )
-	{
-	    fprintf( stderr, "%s is not a local group\n", grp );
-	    return FALSE;
-	}
-	
-	c = **argv;
-	if ( c == 'y' || c == 'm' || c == 'n' )
-	    Grp_setPostAllow( grp, c );
-	else
-	{
-	    fprintf( stderr, "Access must be 'y', 'n' or 'm'" );
-	    return FALSE;
-	}
-    }
-
-    return TRUE;
-}
-
-static void
-doGrps( void )
-{
-    const char *g;
-    Str dateLastAccess, dateCreated;
-    time_t lastAccess, created;
-
-    if ( Grp_firstGrp( &g ) )
-        do
-        {
-            lastAccess = Grp_lastAccess( g );
-            created = Grp_created( g );
-            ASSERT( lastAccess >= 0 );
-            ASSERT( created >= 0 );
-            strftime( dateLastAccess, MAXCHAR, "%Y-%m-%d %H:%M:%S",
-                      localtime( &lastAccess ) );
-            strftime( dateCreated, MAXCHAR, "%Y-%m-%d %H:%M:%S",
-                      localtime( &created ) );
-            printf( "%s\t%s\t%i\t%i\t%i\t%c\t%s\t%s\t%s\n",
-                    g, Grp_serv( g ), Grp_first( g ), Grp_last( g ),
-                    Grp_rmtNext( g ), Grp_postAllow( g ), dateCreated,
-                    dateLastAccess, Grp_dsc( g ) );
-        }
-        while ( Grp_nextGrp( &g ) );
-}
-
-static Bool
-doSubscribe( const char *name, FetchMode mode )
-{
-    if ( ! Grp_exists( name ) )
-    {
-        fprintf( stderr, "%s is not available at remote servers.\n", name );
-        return FALSE;
-    }
-    Fetchlist_read();
-    if ( Fetchlist_add( name, mode ) )
-        printf( "Adding %s to fetch list in %s mode.\n",
-                name, mode == FULL ? "full" : mode == THREAD ?
-                "thread" : "overview" );
-    else
-        printf( "%s is already in fetch list. Mode is now: %s.\n",
-                name, mode == FULL ? "full" : mode == THREAD ?
-                "thread" : "overview" );
-    if ( ! Fetchlist_write() )
-        fprintf( stderr, "Could not save fetchlist.\n" );
-    return TRUE;
-}
-
-static void
-doUnsubscribe( const char *name )
-{
-    Fetchlist_read();
-    if ( ! Fetchlist_remove( name ) )
-        printf( "%s is not in fetch list.\n", name );
-    else
-        printf( "%s removed from fetch list.\n", name );
-    if ( ! Fetchlist_write() )
-        fprintf( stderr, "Could not save fetchlist.\n" );
-}
-
-static void
-printUsage( void )
-{
-    static const char *msg =
-      "Usage: noffle <option>\n"
-      "Option is one of the following:\n"
-      " -a | --article <msg id>|all      Show article(s) in database\n"
-      " -c | --cancel <msg id>           Remove article from database\n"
-      " -C | --create <grp>              Create a local group\n"
-      " -d | --database                  Show content of article database\n"
-      " -D | --delete <grp>              Delete a group\n"
-      " -e | --expire                    Expire articles\n"
-      " -f | --fetch                     Get newsfeed from server/post articles\n"
-      " -g | --groups                    Show all groups available at server\n"
-      " -h | --help                      Show this text\n"
-      " -l | --list                      List groups on fetch list\n"
-      " -m | --modify desc <grp> <desc>  Modify a group description\n"
-      " -m | --modify post <grp> (y|n)   Modify posting status of a local group\n"
-      " -n | --online                    Switch to online mode\n"
-      " -o | --offline                   Switch to offline mode\n"
-      " -q | --query groups              Get group list from server\n"
-      " -q | --query desc                Get group descriptions from server\n"
-      " -q | --query times               Get group creation times from server\n"
-      " -r | --server                    Run as server on stdin/stdout\n"
-      " -R | --requested                 List articles marked for download\n"
-      " -s | --subscribe-over <grp>      Add group to fetch list (overview)\n"
-      " -S | --subscribe-full <grp>      Add group to fetch list (full)\n"
-      " -t | --subscribe-thread <grp>    Add group to fetch list (thread)\n"
-      " -u | --unsubscribe <grp>         Remove group from fetch list\n"
-      " -v | --version                   Print version\n";
-    fprintf( stderr, "%s", msg );
-}
-
-/*
-  Allow core files: Change core limit and change working directory
-  to spool directory, where news has write permissions.
-*/
-static void
-enableCorefiles()
-{
-    struct rlimit lim;
-
-    if ( getrlimit( RLIMIT_CORE, &lim ) != 0 )
-    {
-        Log_err( "Cannot get system core limit: %s", strerror( errno ) );
-        return;
-    }
-    lim.rlim_cur = lim.rlim_max;
-    if ( setrlimit( RLIMIT_CORE, &lim ) != 0 )
-    {
-        Log_err( "Cannot set system core limit: %s", strerror( errno ) );
-        return;
-    }
-    Log_dbg( "Core limit set to %i", lim.rlim_max );
-    if ( chdir( Cfg_spoolDir() ) != 0 )
-    {
-         Log_err( "Cannot change to directory '%s'", Cfg_spoolDir() );
-         return;
-    }
-    Log_dbg( "Changed to directory '%s'", Cfg_spoolDir() );
-}
-
-static Bool
-initNoffle( Bool interactive )
-{
-    Log_init( "noffle", interactive, LOG_NEWS );
-    Cfg_read();
-    Log_dbg( "NOFFLE version %s", Cfg_version() );
-    noffle.interactive = interactive;
-    if ( interactive )
-      if ( ! Lock_openDatabases() )
-        return FALSE;
-    if ( ! interactive )
-        enableCorefiles();
-    return TRUE;
-}
-
-static void
-closeNoffle( void )
-{
-    if ( noffle.interactive )
-      Lock_closeDatabases();
-}
-
-static void
-bugReport( int sig )
-{
-    Log_err( "Received SIGSEGV. Please submit a bug report" );
-    signal( SIGSEGV, SIG_DFL );
-    raise( sig );
-}
-
-static void
-logSignal( int sig )
-{
-    const char *name;
-    Bool err = TRUE;
-
-    switch ( sig )
-    {
-    case SIGABRT:
-        name = "SIGABRT"; break;
-    case SIGFPE:
-        name = "SIGFPE"; break;
-    case SIGILL:
-        name = "SIGILL"; break;
-    case SIGINT:
-        name = "SIGINT"; break;
-    case SIGTERM:
-        name = "SIGTERM"; break;
-    case SIGPIPE:
-        name = "SIGPIPE"; err = FALSE; break;
-    default:
-        name = "?"; break;
-    }
-    if ( err )
-        Log_err( "Received signal %i (%s). Aborting.", sig, name );
-    else
-        Log_inf( "Received signal %i (%s). Aborting.", sig, name );
-    signal( sig, SIG_DFL );
-    raise( sig );
-}
-
-int main ( int argc, char **argv )
-{
-    int c, result;
-    struct option longOptions[] =
-    {
-        { "article",          required_argument, NULL, 'a' },
-        { "cancel",           required_argument, NULL, 'c' },
-        { "create",           required_argument, NULL, 'C' },
-        { "database",         no_argument,       NULL, 'd' },
-        { "delete",           required_argument, NULL, 'D' },
-        { "expire",           no_argument,       NULL, 'e' },
-        { "fetch",            no_argument,       NULL, 'f' },
-        { "groups",           no_argument,       NULL, 'g' },
-        { "help",             no_argument,       NULL, 'h' },
-        { "list",             no_argument,       NULL, 'l' },
-        { "modify",           required_argument, NULL, 'm' },
-        { "offline",          no_argument,       NULL, 'o' },
-        { "online",           no_argument,       NULL, 'n' },
-        { "query",            required_argument, NULL, 'q' },
-        { "server",           no_argument,       NULL, 'r' },
-        { "requested",        no_argument,       NULL, 'R' },
-        { "subscribe-over",   required_argument, NULL, 's' },
-        { "subscribe-full",   required_argument, NULL, 'S' },
-        { "subscribe-thread", required_argument, NULL, 't' },
-        { "unsubscribe",      required_argument, NULL, 'u' },
-        { "version",          no_argument,       NULL, 'v' },
-        { NULL, 0, NULL, 0 }
-    };
-    
-    signal( SIGSEGV, bugReport );
-    signal( SIGABRT, logSignal );
-    signal( SIGFPE, logSignal );
-    signal( SIGILL, logSignal );
-    signal( SIGINT, logSignal );
-    signal( SIGTERM, logSignal );
-    signal( SIGPIPE, logSignal );
-    c = getopt_long( argc, argv, "a:c:C:dD:efghlm:onq:rRs:S:t:u:v",
-                     longOptions, NULL );
-    if ( ! initNoffle( c != 'r' ) )
-        return EXIT_FAILURE;
-    result = EXIT_SUCCESS;
-    switch ( c )
-    {
-    case 0:
-        /* Options that set a flag. */
-        break;
-    case 'a':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -a needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doArt( optarg );
-        break;
-    case 'c':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -c needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doCancel( optarg );
-        break;
-    case 'C':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -C needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doCreateLocalGroup( optarg );
-        break;
-    case 'd':
-        doDb();
-        break;
-    case 'D':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -D needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doDeleteLocalGroup( optarg );
-        break;
-    case 'e':
-	doExpire();
-	break;
-    case 'f':
-        doFetch();
-        break;
-    case 'g':
-        doGrps();
-        break;
-    case -1:
-    case 'h':
-        printUsage();
-        break;
-    case 'l':
-        doList();
-        break;
-    case 'm':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -m needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-	    if ( ! doModify( optarg, argc - optind, &argv[ optind ] ) )
-		result = EXIT_FAILURE;
-        break;
-    case 'n':
-        if ( Online_true() )
-            fprintf( stderr, "NOFFLE is already online\n" );
-        else
-            Online_set( TRUE );
-        break;
-    case 'o':
-        if ( ! Online_true() )
-            fprintf( stderr, "NOFFLE is already offline\n" );
-        else
-            Online_set( FALSE );
-        break;
-    case 'q':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -q needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-        {
-            if ( strcmp( optarg, "groups" ) == 0 )
-                noffle.queryGrps = TRUE;
-            else if ( strcmp( optarg, "desc" ) == 0 )
-                noffle.queryDsc = TRUE;
-            else if ( strcmp( optarg, "times" ) == 0 )
-                noffle.queryTimes = TRUE;
-            else
-            {
-                fprintf( stderr, "Unknown argument -q %s\n", optarg );
-                result = EXIT_FAILURE;
-            }
-            doQuery();
-        }
-        break;
-    case 'r':
-        Log_inf( "Starting as server" );
-        Serv_run();
-        break;
-    case 'R':
-        doRequested( optarg );
-        break;
-    case 's':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -s needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            result = doSubscribe( optarg, OVER );
-        break;
-    case 'S':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -S needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doSubscribe( optarg, FULL );
-        break;
-    case 't':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -t needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            result = doSubscribe( optarg, THREAD );
-        break;
-    case 'u':
-        if ( ! optarg )
-        {
-            fprintf( stderr, "Option -u needs argument.\n" );
-            result = EXIT_FAILURE;
-        }
-        else
-            doUnsubscribe( optarg );
-        break;
-    case '?':
-        /* Error message already printed by getopt_long */
-        result = EXIT_FAILURE;
-        break;
-    case 'v':
-        printf( "NNTP server NOFFLE, version %s.\n", Cfg_version() );
-        break;
-    default:
-        abort(); /* Never reached */
-    }
-    closeNoffle();
-    return result;
-}
--- a/online.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
-  online.c
-
-  $Id: online.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include <unistd.h>
-#include "common.h"
-#include "config.h"
-#include "log.h"
-
-static void
-fileOnline( Str s )
-{
-    snprintf( s, MAXCHAR, "%s/lock/online", Cfg_spoolDir() );
-}
-
-Bool
-Online_true( void )
-{
-    FILE *f;
-    Str file;
-
-    fileOnline( file );
-    if ( ! ( f = fopen( file, "r" ) ) )
-        return FALSE;
-    fclose( f );
-    return TRUE;
-}
-
-void
-Online_set( Bool value )
-{
-    FILE *f;
-    Str file;
-
-    fileOnline( file );
-    if ( value )
-    {
-        if ( ! ( f = fopen( file, "a" ) ) )
-        {
-            Log_err( "Could not create %s", file );
-            return;
-        }
-        fclose( f );
-        Log_inf( "NOFFLE is now online" );
-    }
-    else
-    {
-        if ( unlink( file ) != 0 )
-        {
-            Log_err( "Cannot remove %s", file );
-            return;
-        }
-        Log_inf( "NOFFLE is now offline" );
-    }
-}
--- a/online.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-/*
-  online.h
-
-  Online/offline status.
-
-  $Id: online.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef ONLINE_H
-#define ONLINE_H
-
-Bool
-Online_true( void );
-
-void
-Online_set( Bool value );
-
-#endif
--- a/outgoing.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
-  outgoing.c
-
-  $Id: outgoing.c 32 2000-04-29 14:45:56Z enz $
-*/
-
-#include "outgoing.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-#include "config.h"
-#include "log.h"
-#include "util.h"
-
-struct Outgoing
-{
-    DIR *dir;
-    Str serv;
-} outgoing = { NULL, "" };
-
-static void
-fileOutgoing( Str file, const char *serv, const char *msgId )
-{
-    snprintf( file, MAXCHAR, "%s/outgoing/%s/%s",
-              Cfg_spoolDir(), serv, msgId );
-}
-
-static void
-createDir( const char *serv )
-{
-    Str dir;
-    int r;
-
-    snprintf( dir, MAXCHAR, "%s/outgoing/%s", Cfg_spoolDir(), serv );
-    r = mkdir( dir, 0755 );
-    if ( r != 0 )
-        Log_dbg( "mkdir: %s", strerror( errno ) );
-}
-
-Bool
-Out_add( const char *serv, const char *msgId, const DynStr *artTxt )
-{
-    Str file;
-    FILE *f;
-
-    fileOutgoing( file, serv, msgId );
-    if ( ! ( f = fopen( file, "w" ) ) )
-    {
-        createDir( serv );
-        if ( ! ( f = fopen( file, "w" ) ) )
-        {
-            Log_err( "Cannot open %s", file );
-            return FALSE;
-        }
-    }
-    fprintf( f, "%s", DynStr_str( artTxt ) );
-    fclose( f );
-    return TRUE;
-}
-
-Bool
-Out_first( const char *serv, Str msgId, DynStr *artTxt )
-{
-    Str file;
-    
-    snprintf( file, MAXCHAR, "%s/outgoing/%s", Cfg_spoolDir(), serv );
-    if ( ! ( outgoing.dir = opendir( file ) ) )
-    {
-        Log_dbg( "Cannot open %s", file );
-        return FALSE;
-    }
-    Utl_cpyStr( outgoing.serv, serv );
-    Out_next( NULL, NULL ); /* "."  */
-    Out_next( NULL, NULL ); /* ".." */
-    return Out_next( msgId, artTxt );
-}
-
-Bool
-Out_next( Str msgId, DynStr *artTxt )
-{
-    struct dirent *d;
-    FILE *f;
-    Str file, line;
-
-    ASSERT( outgoing.dir );
-    if ( ! ( d = readdir( outgoing.dir ) ) )
-    {
-        closedir( outgoing.dir );
-        outgoing.dir = NULL;
-        return FALSE;
-    }
-    if ( artTxt == NULL )
-        return ( d->d_name != NULL );
-    fileOutgoing( file, outgoing.serv, d->d_name );
-    if ( ! ( f = fopen( file, "r" ) ) )
-    {
-        Log_err( "Cannot open %s for read", file );
-        return FALSE;
-    }
-    DynStr_clear( artTxt );
-    while ( fgets( line, MAXCHAR, f ) )
-        DynStr_app( artTxt, line );
-    Utl_cpyStr( msgId, d->d_name );
-    fclose( f );
-    return TRUE;
-}
-
-void
-Out_remove( const char *serv, const char *msgId )
-{
-    Str file;
-
-    fileOutgoing( file, serv, msgId );
-    if ( unlink( file ) != 0 )
-        Log_err( "Cannot remove %s", file );
-}
-
-Bool
-Out_find( const char *msgId, Str server )
-{
-    Str servdir;
-    DIR *d;
-    struct dirent *entry;
-    Bool res;
-    
-    
-    snprintf( servdir, MAXCHAR, "%s/outgoing", Cfg_spoolDir() );
-    if ( ! ( d = opendir( servdir ) ) )
-    {
-        Log_dbg( "Cannot open %s", servdir );
-        return FALSE;
-    }
-
-    readdir( d );	/* '.' */
-    readdir( d );	/* '..' */
-
-    res = FALSE;
-    while ( ! res && ( entry = readdir( d ) ) != NULL )
-    {
-	Str file;
-	struct stat s;
-
-	fileOutgoing( file, entry->d_name, msgId );
-	if ( stat( file, &s ) == 0 )
-	{
-	    res = TRUE;
-	    Utl_cpyStr( server, entry->d_name );
-	}
-    }
-
-    closedir( d );
-    return res;
-}
-
-
-
-
-
--- a/outgoing.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
-  outgoing.h
-
-  Collection of posted articles.
-
-  $Id: outgoing.h 32 2000-04-29 14:45:56Z enz $
-*/
-
-#ifndef OUT_H
-#define OUT_H
-
-#include "common.h"
-#include "dynamicstring.h"
-
-Bool
-Out_add( const char *serv, const char *msgId, const DynStr *artTxt );
-
-/* Start enumeration. Return TRUE on success. */
-Bool
-Out_first( const char *serv, Str msgId, DynStr *artTxt );
-
-/* Continue enumeration. Return TRUE on success. */
-Bool
-Out_next( Str msgId, DynStr *s );
-
-/* Delete article from outgoing collection */
-void
-Out_remove( const char *serv, const char *msgId );
-
-/* Find server for outgoing message. */
-Bool
-Out_find( const char *msgId, Str server );
-
-#endif
--- a/over.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
-  over.c
-
-  $Id: over.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include <errno.h>
-#include <time.h>
-#include "config.h"
-#include "content.h"
-#include "database.h"
-#include "fetchlist.h"
-#include "log.h"
-#include "util.h"
-#include "protocol.h"
-#include "pseudo.h"
-
-struct Over
-{
-    int numb;            /* message number of the overviewed article */
-    char *subj;
-    char *from;
-    char *date;
-    char *msgId;
-    char *ref;
-    size_t bytes;
-    size_t lines;
-    time_t time;
-};
-
-Over *
-new_Over( const char *subj, const char *from,
-          const char *date, const char *msgId, char *ref,
-          size_t bytes, size_t lines )
-{
-    Over *ov;
-
-    if ( ! ( ov = (Over *)malloc( sizeof( Over ) ) ) )
-    {
-        Log_err( "Cannot allocate Over" );
-        exit( EXIT_FAILURE );
-    }
-    ov->numb = 0;
-    Utl_allocAndCpy( &ov->subj, subj );
-    Utl_allocAndCpy( &ov->from, from );
-    Utl_allocAndCpy( &ov->date, date );
-    Utl_allocAndCpy( &ov->msgId, msgId );
-    Utl_allocAndCpy( &ov->ref, ref );
-    ov->bytes = bytes;
-    ov->lines = lines;
-    return ov;
-}
-
-void
-del_Over( Over *self )
-{
-    if ( ! self )
-        return;
-    free( self->subj );
-    self->subj = NULL;
-    free( self->from );
-    self->from = NULL;
-    free( self->date );
-    self->date = NULL;
-    free( self->msgId );
-    self->msgId = NULL;
-    free( self->ref );
-    self->ref = NULL;
-    free( self );
-}
-
-int
-Ov_numb( const Over *self )
-{
-    return self->numb;
-}
-
-const char *
-Ov_subj( const Over *self )
-{
-    return self->subj;
-}
-
-const char *
-Ov_from( const Over *self )
-{
-    return self->from;
-}
-
-const char *
-Ov_date( const Over *self )
-{
-    return self->date;
-}
-
-const char *
-Ov_msgId( const Over *self )
-{
-    return self->msgId;
-}
-
-const char *
-Ov_ref( const Over *self )
-{
-    return self->ref;
-}
-
-size_t
-Ov_bytes( const Over *self )
-{
-    return self->bytes;
-}
-
-size_t
-Ov_lines( const Over *self )
-{
-    return self->lines;
-}
-
-void
-Ov_setNumb( Over *self, int numb )
-{
-    self->numb = numb;
-}
-
-Bool
-Ov_write( const Over *self, FILE *f )
-{
-    return ( fprintf( f, "%i\t%s\t%s\t%s\t%s\t%s\t%d\t%d\n",
-                      self->numb, self->subj,
-                      self->from, self->date, self->msgId,
-                      self->ref, self->bytes,
-                      self->lines ) > 0 );
-}
-
-static const char *
-readField( Str result, const char *p )
-{
-    size_t len;
-    char *r;
-
-    if ( ! p )
-        return NULL;
-    r = result;
-    *r = '\0';
-    len = 0;
-    while ( *p != '\t' && *p != '\n' )
-    {
-        if ( ! *p )
-            return p;
-        *(r++) = *(p++);
-        ++len;
-        if ( len >= MAXCHAR - 1 )
-        {
-            *r = '\0';
-            Log_err( "Field in overview too long: %s", r );
-            return ++p;
-        }
-    }
-    *r = '\0';
-    return ++p;
-}
-
-/* read Over-struct from line */
-Over *
-Ov_read( char *line )
-{
-    size_t bytes, lines;
-    const char *p;
-    Over *result;
-    int numb;
-    Str t, subj, from, date, msgId, ref;
-    
-    p = readField( t, line );
-    if ( sscanf( t, "%i", &numb ) != 1 )
-        return NULL;
-    p = readField( subj, p );
-    p = readField( from, p );
-    p = readField( date, p );
-    p = readField( msgId, p );
-    p = readField( ref, p );
-    p = readField( t, p );
-    if ( sscanf( t, "%d", &bytes ) != 1 )
-        return NULL;
-    p = readField( t, p );
-    if ( sscanf( t, "%d", &lines ) != 1 )
-        return NULL;
-    result = new_Over( subj, from, date, msgId, ref, bytes, lines );
-    Ov_setNumb( result, numb );
-    return result;
-}
--- a/over.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
-  over.h
-
-  Processing of single article overviews. Handling of overview files is in
-  content.c. An article overview contains important article properties,
-  such as date, from, subject.
-
-  $Id: over.h 3 2000-01-04 11:35:42Z enz $ 
-*/
-
-#ifndef OVER_H
-#define OVER_H
-
-#include <time.h>
-#include "common.h"
-
-struct Over;
-typedef struct Over Over;
-
-/*
-  Usual fields from overview databases.
-  Xref without hostname.
-*/
-Over *
-new_Over( const char *subj, const char *from, const char *date,
-          const char *msgId, char *ref, size_t bytes, size_t lines );
-
-
-/* free memory */
-void
-del_Over( Over *self );
-
-/* read Over-struct from line */
-Over *
-Ov_read( char *line );
-
-/* write struct Over to f as a line */
-Bool
-Ov_write( const Over *self, FILE *f );
-
-/* Access particular fields in struct over */
-
-int
-Ov_numb( const Over *self );
-
-const char *
-Ov_subj( const Over *self );
-
-const char *
-Ov_from( const Over *self );
-
-const char *
-Ov_date( const Over *self );
-
-const char *
-Ov_msgId( const Over *self );
-
-const char *
-Ov_ref( const Over *self );
-
-size_t
-Ov_bytes( const Over *self );
-
-size_t
-Ov_lines( const Over *self );
-
-void
-Ov_setNumb( Over *self, int numb );
-
-#endif
--- a/post.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-/*
-  post.c
-
-  $Id: post.c 32 2000-04-29 14:45:56Z enz $
-*/
-
-#include "post.h"
-#include <string.h>
-#include "common.h"
-#include "content.h"
-#include "database.h"
-#include "group.h"
-#include "log.h"
-#include "over.h"
-#include "protocol.h"
-#include "util.h"
-
-struct OverInfo
-{
-    Str subject;
-    Str from;
-    Str date;
-    Str msgId;
-    Str ref;
-    size_t bytes;
-    size_t lines;
-};
-
-struct Article
-{
-    const char * text;
-    Bool posted;
-    struct OverInfo over;
-};
-
-static struct Article article = { NULL, FALSE };
-
-static void
-getOverInfo( struct OverInfo * o )
-{
-    const char *p = article.text;
-    Str line, field, value;
-    
-    o->bytes = strlen( p );
-
-    while( p != NULL )
-    {
-        p = Utl_getHeaderLn( line, p );
-        if ( line[ 0 ] == '\0' )
-	    break;
-
-	/* Look for headers we need to stash. */
-        if ( Prt_getField( field, value, line ) )
-        {
-	    if ( strcmp( field, "subject" ) == 0 )
-		Utl_cpyStr( o->subject, value );
-	    else if ( strcmp ( field, "from" ) == 0 )
-		Utl_cpyStr( o->from, value );
-	    else if ( strcmp ( field, "date" ) == 0 )
-		Utl_cpyStr( o->date, value );
-	    else if ( strcmp ( field, "references" ) == 0 )
-		Utl_cpyStr( o->ref, value );
-	    else if ( strcmp ( field, "message-id" ) == 0 )
-		Utl_cpyStr( o->msgId, value );
-	}
-    }
-
-    /* Move to start of body and count lines. */
-    for ( p++, o->lines = 0; *p != '\0'; p++ )
-	if ( *p == '\n' )
-	    o->lines++;
-}
-
-/* Register an article for posting. */
-Bool
-Post_open( const char * text )
-{
-    if ( article.text != NULL )
-    {
-	Log_err( "Busy article in Post_open." );
-	return FALSE;
-    }
-
-    memset( &article.over, 0, sizeof( article.over ) );
-    article.text = text;
-    getOverInfo( &article.over );
-
-    if ( Db_contains( article.over.msgId ) )
-    {
-	Log_err( "Duplicate article %s.", article.over.msgId );
-	return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-/* Add the article to a group. */
-Bool
-Post_add ( const char * grp )
-{
-    Over * over;
-    const char *msgId;
-    
-    over = new_Over( article.over.subject,
-		     article.over.from,
-		     article.over.date,
-		     article.over.msgId,
-		     article.over.ref,
-		     article.over.bytes,
-		     article.over.lines );
-    
-    msgId = article.over.msgId;
-    
-    Cont_read( grp );
-    Cont_app( over );
-    Log_dbg( "Added message '%s' to group '%s'.", msgId, grp );
-
-    if ( !article.posted )
-    {
-        Log_inf( "Added '%s' to database.", msgId );
-        if ( ! Db_prepareEntry( over, Cont_grp(), Cont_last() )
-	     || ! Db_storeArt ( msgId, article.text ) )
-	    return FALSE;
-	article.posted = TRUE;
-    }
-    else
-    {
-	Str t;
-	const char *xref;
-
-	xref = Db_xref( msgId );
-	Log_dbg( "Adding '%s' to Xref of '%s'", grp, msgId );
-	snprintf( t, MAXCHAR, "%s %s:%i", xref, grp, Ov_numb( over ) );
-	Db_setXref( msgId, t );
-    }
-    
-    Cont_write();
-    Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() );
-    return TRUE;
-}
-   
-/* Done with article - tidy up. */
-void
-Post_close( void )
-{
-    article.text = NULL;
-    article.posted = FALSE;
-}
-
--- a/post.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
-  post.h
-
-  Take a single article received in its entirety without an overview
-  (i.e. received via at the server via a POST), and add it to the database
-  and (possibly multiple) group(s).
-
-  $Id: post.h 32 2000-04-29 14:45:56Z enz $
-*/
-
-#ifndef POST_H
-#define POST_H
-
-#include "common.h"
-
-/* Register an article for posting. */
-Bool
-Post_open( const char * text );
-
-/* Add the article to a group. */
-Bool
-Post_add ( const char * grp );
-   
-/* Done with article - tidy up. */
-void
-Post_close( void );
-
-#endif
--- a/protocol.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,279 +0,0 @@
-/*
-  protocol.c
-
-  $Id: protocol.c 16 2000-04-11 06:50:16Z enz $
-*/
-
-#include <ctype.h> 
-#include <netdb.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include "common.h"
-#include "dynamicstring.h"
-#include "log.h"
-#include "over.h"
-#include "util.h"
-
-Bool
-Prt_getLn( Str line, FILE *f )
-{
-    size_t len;
-
-    /*
-      We also accept lines ending with "\n" instead of "\r\n", some
-      clients wrongly send such lines.
-    */
-    if ( ! fgets( line, MAXCHAR, f ) )
-    {
-        Log_dbg( "Prt_getLine failed" );
-        return FALSE;
-    }
-    len = strlen( line );
-    if ( line[ len - 1 ] == '\n' )
-    {
-        line[ len - 1 ] = '\0';
-        if ( line[ len - 2 ] == '\r' )
-            line[ len - 2 ] = '\0';
-    }
-    Log_dbg( "[R] %s", line );
-    return TRUE;
-}
-
-Bool
-Prt_getTxtLn( Str line, Bool *err, FILE *f )
-{
-    Str buf;
-
-    if ( ! Prt_getLn( buf, f ) )
-    {
-        Log_err( "Cannot get text line" );
-        *err = TRUE;
-        return FALSE;
-    }
-    *err = FALSE;
-    if ( buf[ 0 ] == '.' )
-    {
-        if ( buf[ 1 ] == 0 )
-            return FALSE;
-        else
-            strcpy( line, buf + 1 );
-    }
-    else
-        strcpy( line, buf );
-    return TRUE;
-}
-
-Bool
-Prt_putTxtLn( const char* line, FILE *f )
-{
-    if ( line[ 0 ] == '.' )
-    {
-        Log_dbg( "[S] .%s", line );
-        return ( fprintf( f, ".%s\r\n", line ) == strlen( line ) + 3 );
-    }
-    else
-    {
-        Log_dbg( "[S] %s", line );
-        return ( fprintf( f, "%s\r\n", line ) == strlen( line ) + 2 );
-    }
-}
-
-Bool
-Prt_putEndOfTxt( FILE *f )
-{
-    Log_dbg( "[S] ." );
-    return ( fprintf( f, ".\r\n" ) == 3 );
-}
-
-/*
-  Write text buffer of lines each ending with '\n'.
-  Replace '\n' by "\r\n".
-*/
-Bool
-Prt_putTxtBuf( const char *buf, FILE *f )
-{
-    Str line;
-    const char *pBuf;
-    char *pLn;
-
-    pBuf = buf;
-    pLn = line;
-    while ( *pBuf != '\0' )
-    {
-        if ( *pBuf == '\n' )
-        {
-            *pLn = '\0';
-            if ( ! Prt_putTxtLn( line, f ) )
-                return FALSE;
-            pLn = line;
-            ++pBuf;
-        }
-        else if ( pLn - line >= MAXCHAR - 1 )
-        {
-            /* Put it out raw to prevent String overflow */
-            Log_err( "Writing VERY long line" );
-            *pLn = '\0';
-            if ( fprintf( f, "%s", line ) != strlen( line ) )
-                return FALSE;
-            pLn = line;
-        }   
-        else
-            *(pLn++) = *(pBuf++);
-    }
-    return TRUE;
-}
-
-Bool
-Prt_getField( Str resultField, Str resultValue, const char* line )
-{
-    char *dst;
-    const char *p;
-    Str lineLower, t;
-    
-    Utl_cpyStr( lineLower, line );
-    Utl_toLower( lineLower );
-    p = Utl_stripWhiteSpace( lineLower );
-    dst = resultField;
-    while ( ! isspace( *p ) && *p != ':' && *p != '\0' )
-        *(dst++) = *(p++);
-    *dst = '\0';
-    while ( isspace( *p ) )
-        ++p;    
-    if ( *p == ':' )
-    {
-        ++p;
-        strcpy( t, line + ( p - lineLower ) );
-        p = Utl_stripWhiteSpace( t );
-        strcpy( resultValue, p );
-        return TRUE;
-    }
-    return FALSE;
-}
-
-Bool
-Prt_searchHeader( const char *artTxt, const char *which, Str result )
-{
-    const char *src, *p;
-    char *dst;
-    Str line, whichLower, field;
-    int len;
-    
-    Utl_cpyStr( whichLower, which );
-    Utl_toLower( whichLower );
-    src = artTxt;
-    while ( TRUE )
-    {
-        dst = line;
-        len = 0;
-        while ( *src != '\n' && len < MAXCHAR )
-        {
-            if ( *src == '\0' )
-                return FALSE;
-            *(dst++) = *(src++);
-            ++len;
-        }
-        if ( *src == '\n' )
-            ++src;
-        *dst = '\0';
-        p = Utl_stripWhiteSpace( line );
-        if ( *p == '\0' )
-            break;
-        if ( Prt_getField( field, result, line )
-             && strcmp( field, whichLower ) == 0 )
-            return TRUE;
-    }
-    return FALSE;
-}
-
-static Bool
-getFQDN( Str result )
-{
-    struct hostent *myHostEnt;
-    struct utsname myName;
-    
-    if ( uname( &myName ) >= 0
-         && ( myHostEnt = gethostbyname( myName.nodename ) ) )
-    {
-        Utl_cpyStr( result, myHostEnt->h_name );
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static void
-getDomain( Str domain, const char *from )
-{
-    const char *addTopLevel, *p1, *p2, *p, *domainStart;
-    Str myDomain;
-
-    if ( getFQDN( myDomain ) )
-    {
-        p = strstr( myDomain, "." );
-        if ( p != NULL )
-            domainStart = p + 1;
-        else
-            domainStart = myDomain;
-    }
-    else /* Take domain of From field */
-    {
-        myDomain[ 0 ] = '\0';
-        p1 = strstr( from, "@" );
-        if ( p1 != NULL )
-        {
-            p2 = strstr( p1, ">" );
-            if ( p2 != NULL )
-                Utl_cpyStrN( myDomain, p1 + 1, p2 - p1 - 1 );
-        }
-        if ( myDomain[ 0 ] == '\0' )
-            Utl_cpyStr( myDomain, "unknown" );
-        domainStart = myDomain;
-    }
-    /*
-      If domain contains no dot (and is probably invalid anyway),
-      we add ".local", because some servers insist on domainnames with dot
-      in message ID.
-    */
-    addTopLevel = strstr( domainStart, "." ) == NULL ? ".local" : "";
-    snprintf( domain, MAXCHAR, "%s%s", myDomain, addTopLevel );    
-}
-
-/* See RFC 850, section 2.1.7 */
-Bool
-Prt_isValidMsgId( const char *msgId )
-{
-    Str head, domain;
-    int len, headLen;
-    const char *p;
-
-    len = strlen( msgId );
-    p = strstr( msgId, "@" );
-    if ( msgId[ 0 ] != '<' || msgId[ len - 1 ] != '>' || p == NULL )
-        return FALSE;
-    strcpy( domain, p + 1 );
-    domain[ strlen( domain ) - 1 ] = '\0';
-    headLen = p - msgId - 1;
-    Utl_cpyStrN( head, msgId + 1, headLen );
-    head[ headLen ] = '\0';
-    /*
-      To do: check for special characters in head and domain (non-printable
-      or '@', '<', '>'). Maybe compare domain with a config option 
-      and replace it by the config option, if not equal.
-     */
-    if ( strstr( domain, "." ) == NULL )
-        return FALSE;
-    return TRUE;
-}
-
-void
-Prt_genMsgId( Str msgId, const char *from, const char *suffix )
-{
-    Str domain, date;
-    time_t t;
-
-    getDomain( domain, from );
-    time( &t );
-    strftime( date, MAXCHAR, "%Y%m%d%H%M%S", gmtime( &t ) );
-    srand( time( NULL ) );
-    snprintf( msgId, MAXCHAR, "<%s.%X.%s@%s>", date, rand(), suffix, domain );
-    ASSERT( Prt_isValidMsgId( msgId ) );
-}
--- a/protocol.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
-  protocol.h
-
-  Functions related with the NNTP protocol which are useful for both
-  the server and the client.
-
-  $Id: protocol.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef PRT_H
-#define PRT_H
-
-#include "dynamicstring.h"
-#include "over.h"
-
-#define STAT_HELP_FOLLOWS        100
-#define STAT_DEBUG_FOLLOWS       199
-
-#define STAT_READY_POST_ALLOW    200
-#define STAT_READY_NO_POST_ALLOW 201
-#define STAT_CMD_OK              202
-#define STAT_GOODBYE             205
-#define STAT_GRP_SELECTED        211
-#define STAT_GRPS_FOLLOW         215
-#define STAT_ART_FOLLOWS         220
-#define STAT_HEAD_FOLLOWS        221
-#define STAT_BODY_FOLLOWS        222
-#define STAT_ART_RETRIEVED       223
-#define STAT_OVERS_FOLLOW        224
-#define STAT_NEW_GRP_FOLLOW      231
-#define STAT_POST_OK             240
-#define STAT_AUTH_ACCEPTED       281
-
-#define STAT_SEND_ART            340
-#define STAT_MORE_AUTH_REQUIRED  381
-
-#define STAT_NO_SUCH_GRP         411
-#define STAT_NO_GRP_SELECTED     412
-#define STAT_NO_ART_SELECTED     420
-#define STAT_NO_NEXT_ART         421
-#define STAT_NO_PREV_ART         422
-#define STAT_NO_SUCH_NUMB        423
-#define STAT_NO_SUCH_ID          430
-#define STAT_ART_REJECTED        437
-#define STAT_POST_FAILED         441
-#define STAT_AUTH_REQUIRED       480
-#define STAT_AUTH_REJECTED       482
-
-#define STAT_NO_SUCH_CMD         500
-#define STAT_SYNTAX_ERR          501
-#define STAT_NO_PERMISSION       502
-#define STAT_PROGRAM_FAULT       503
-
-/* 
-   Read next line from f into Str, up to "\n" or "\r\n". Don't save "\n"
-   or "\r\n" in line. Terminate with '\0'. 
-*/
-Bool
-Prt_getLn( Str line, FILE *f );
-
-/*
-  Read a text line from server. Returns TRUE if line != ".", removes
-  leading '.' otherwise.
-*/
-Bool
-Prt_getTxtLn( Str line, Bool *err, FILE *f );
-
-/*
-  Write text line to f. Escape "." at the beginning with another ".".
-  Terminate with "\r\n".
-*/
-Bool
-Prt_putTxtLn( const char* line, FILE *f );
-
-/*
-  Write text buffer of lines each ending with '\n'.
-  Replace '\n' by "\r\n".
-*/
-Bool
-Prt_putTxtBuf( const char *buf, FILE *f );
-
-/* 
-   Write text-ending "."-line to f
-*/
-Bool
-Prt_putEndOfTxt( FILE *f );
-
-/*
-  Splits line in field and value. Field is converted to lower-case. 
-*/
-Bool
-Prt_getField( Str resultField, Str resultValue, const char* line );
-
-/* Search header. Works only with single line headers (ignores continuation
-   lines */
-Bool
-Prt_searchHeader( const char *artTxt, const char* which, Str result );
-
-Bool
-Prt_isValidMsgId( const char *msgId );
-
-void
-Prt_genMsgId( Str msgId, const char *from, const char *suffix );
-
-#endif
--- a/pseudo.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-/*
-  pseudo.c
-  
-  $Id: pseudo.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include "pseudo.h"
-
-#include <time.h>
-#include "common.h"
-#include "config.h"
-#include "content.h"
-#include "database.h"
-#include "group.h"
-#include "log.h"
-#include "protocol.h"
-#include "util.h"
-
-Over *
-genOv( const char *rawSubj, const char *rawBody, const char *suffix )
-{
-    size_t bytes, lines;
-    time_t t;
-    Str subj, date, msgId;
-
-    snprintf( subj, MAXCHAR, "[ %s ]", rawSubj );
-    time( &t );
-    Utl_rfc822Date( t, date );
-    Prt_genMsgId( msgId, "", suffix );
-    bytes = lines = 0;
-    while ( *rawBody )
-    {
-        ++bytes;
-        if ( *rawBody == '\n' )
-            ++lines;
-        ++rawBody;
-    }
-    return new_Over( subj, "news (\"[ NOFFLE ]\")" , date, msgId, "",
-                     bytes, lines );
-}
-
-void
-Pseudo_appGeneralInfo()
-{
-    Cont_app( genOv( "General info", Pseudo_generalInfoBody(),
-                     "NOFFLE-GENERAL-INFO" ) );
-}
-
-Bool
-Pseudo_isGeneralInfo( const char *msgId )
-{
-    return ( strstr( msgId, "NOFFLE-GENERAL-INFO" ) != NULL );
-}
-
-const char *
-Pseudo_generalInfoHead()
-{
-    static Str s;
-
-    Over *ov;
-
-    ov = genOv( "General info", Pseudo_generalInfoBody(),
-                "NOFFLE-GENERAL-INFO" );
-    if ( ov )
-    {
-        snprintf( s, MAXCHAR,
-                  "Message-ID: %s\n"
-                  "Subject: %s\n"
-                  "From: %s\n"
-                  "Date: %s\n"
-                  "Bytes: %u\n"
-                  "Lines: %u\n",
-                  Ov_msgId( ov ),
-                  Ov_subj( ov ),
-                  Ov_from( ov ),
-                  Ov_date( ov ),
-                  Ov_bytes( ov ),
-                  Ov_lines( ov ) );
-        del_Over( ov );
-        return s;
-    }
-    return NULL;
-}
-
-const char *
-Pseudo_generalInfoBody( void )
-{
-    if ( Cfg_autoSubscribe() )
-        return
-            "\n"
-            "\t[ NOFFLE INFO: General information ]\n"
-            "\n"
-            "\t[ This server is running NOFFLE, which is a NNTP server ]\n"
-            "\t[ optimized for low speed dial-up Internet connections. ]\n"
-            "\n"
-            "\t[ By reading this or any other article of this group, ]\n"
-            "\t[ NOFFLE has put it on its fetch list and will retrieve ]\n"
-            "\t[ articles next time it is online. ]\n"
-            "\n"
-            "\t[ If you have more questions about NOFFLE please talk ]\n"
-            "\t[ to your newsmaster or read the manual page for ]\n"
-            "\t[ \"noffle\". ]\n";
-    else
-        return
-            "\n"
-            "\t[ NOFFLE INFO: General information ]\n"
-            "\n"
-            "\t[ This server is running NOFFLE, which is a NNTP server ]\n"
-            "\t[ optimized for low speed dial-up Internet connections. ]\n"
-            "\n"
-            "\t[ This group is presently not on the fetch list. You can ]\n"
-            "\t[ put groups on the fetch list by running the \"noffle\" ]\n"
-            "\t[ command on the computer where this server is running. ]\n"
-            "\n"
-            "\t[ If you have more questions about NOFFLE please talk ]\n"
-            "\t[ to your newsmaster or read the manual page for ]\n"
-            "\t[ \"noffle\". ]\n";
-}
-
-const char *
-Pseudo_markedBody( void )
-{
-    return
-        "\n"
-        "\t[ NOFFLE INFO: Marked for download ]\n"
-        "\n"
-        "\t[ The body of this article has been marked for download. ]\n";
-}
-
-const char *
-Pseudo_alreadyMarkedBody( void )
-{
-    return
-        "\n"
-        "\t[ NOFFLE INFO: Already marked for download ]\n"
-        "\n"
-        "\t[ The body of this article has already been marked ]\n"
-        "\t[ for download. ]\n";
-}
-
-const char *
-Pseudo_markingFailedBody( void )
-{
-    return
-        "\n"
-        "\t[ NOFFLE ERROR: Marking for download failed ]\n"
-        "\n"
-        "\t[ Sorry, I could not mark this article for download. ]\n"
-        "\t[ Either the database is corrupted, or I was unable to ]\n"
-        "\t[ get write access to the request directory. ]\n"
-        "\t[ Please contact your newsmaster to remove this problem. ]\n";
-}
-
-void
-genPseudo( const char *rawSubj, const char* rawBody )
-{
-    Over *ov;
-    DynStr *body = 0, *artTxt = 0;
-
-    body = new_DynStr( 10000 );
-    artTxt = new_DynStr( 10000 );
-    DynStr_app( body, "\n\t[ NOFFLE INFO: " );
-    DynStr_app( body, rawSubj );
-    DynStr_app( body, " ]\n\n" );
-    DynStr_app( body, "\t[ " );
-    while( *rawBody )
-    {
-        if ( *rawBody == '\n' )
-        {
-            DynStr_app( body, " ]\n" );
-            if ( *( rawBody + 1 ) == '\n' )
-            {
-                DynStr_app( body, "\n\t[ " );
-                ++rawBody;
-            }
-            else if ( *( rawBody + 1 ) != '\0' )
-                DynStr_app( body, "\t[ " );
-        }
-        else
-            DynStr_appN( body, rawBody, 1 );
-        ++rawBody;
-    }
-    DynStr_appLn( body, "" );    
-    DynStr_appLn( artTxt,
-                  "Comments: Pseudo article generated by news server NOFFLE" );
-    DynStr_appLn( artTxt, "" );
-    DynStr_appDynStr( artTxt, body );
-    ov = genOv( rawSubj, DynStr_str( body ), "PSEUDO" );
-    if ( body && artTxt && ov )
-    {
-        Cont_app( ov );
-        if ( Db_prepareEntry( ov, Cont_grp(), Cont_last() ) )
-            Db_storeArt( Ov_msgId( ov ), DynStr_str( artTxt ) );
-        Cont_write();
-        Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() );
-    }
-    del_DynStr( body );
-    del_DynStr( artTxt );
-}
-
-void
-Pseudo_retrievingFailed( const char *msgId, const char *reason )
-{
-    DynStr *artTxt = 0;
-
-    if ( ! Db_contains( msgId ) )
-    {
-        Log_err( "Article %s has no entry in database %s", msgId );
-        return;
-    }
-    artTxt = new_DynStr( 10000 );
-    DynStr_appLn( artTxt,
-                  "Comments: Pseudo body generated by news server NOFFLE" );
-    DynStr_appLn( artTxt, "" );
-    DynStr_app( artTxt,
-                "\n"
-                "\t[ NOFFLE ERROR: Retrieving failed ]\n"
-                "\n"
-                "\t[ This article could not be retrieved. Maybe ]\n"
-                "\t[ it has already expired at the remote server ]\n"
-                "\t[ or it has been cancelled by its sender. See ]\n"
-                "\t[ the appended status line of the remote ]\n"
-                "\t[ server for more information. ]\n"
-                "\n"
-                "\t[ This message will disappear the next time ]\n"
-                "\t[ someone tries to read this article, so that ]\n"
-                "\t[ it can be marked for download again. ]\n" );
-    DynStr_app( artTxt, "\n\t[ Remote server status: " );
-    DynStr_app( artTxt, reason );
-    DynStr_app( artTxt, " ]\n" );
-    Db_storeArt( msgId, DynStr_str( artTxt ) );
-    del_DynStr( artTxt );
-}
-
-void
-Pseudo_cntInconsistent( const char *grp, int first, int last, int next )
-{
-    DynStr *info;
-    Str s;
-
-    info = new_DynStr( 10000 );
-    if ( info )
-    {
-        DynStr_app( info,
-                    "This group's article counter is not \n"
-                    "consistent Probably the remote news server\n"
-                    "was changed or has reset its article counter\n"
-                    "for this group. As a consequence there could\n"
-                    "be some articles be duplicated in this group\n" );
-        snprintf( s, MAXCHAR, "Group: %s", grp );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Remote first article number: %i", first );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Remote last article number: %i", last );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Remote next article number: %i", next );
-        DynStr_appLn( info, s );
-        genPseudo( "Article counter inconsistent", DynStr_str( info ) );
-    }
-    del_DynStr( info );
-}
-
-void
-Pseudo_missArts( const char *grp, int first, int next )
-{
-    DynStr *info;
-    Str s;
-
-    info = new_DynStr( 5000 );
-    if ( info )
-    {
-        DynStr_app( info,
-                    "Some articles could not be retrieved from\n"
-                    "the remote server, because it had already\n"
-                    "deleted them.\n"
-                    "If this group is on the fetch list, then\n"
-                    "contact your newsmaster to ensure that\n"
-                    "\"noffle\" is fetching news more frequently.\n" );
-        snprintf( s, MAXCHAR, "Group: %s", grp );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Remote next article number: %i", next );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Remote first article number: %i", first );
-        DynStr_appLn( info, s );
-        genPseudo( "Missing articles", DynStr_str( info ) );
-        del_DynStr( info );
-    }
-}
-
-void
-Pseudo_autoUnsubscribed( const char *grp, int days )
-{
-    DynStr *info;
-    Str s;
-
-    info = new_DynStr( 10000 );
-    if ( info )
-    {
-        DynStr_app( info,
-                    "NOFFLE has automatically unsubscribed this\n"
-                    "group since it has not been accessed for\n"
-                    "some time.\n"
-                    "Re-subscribing is done either automatically\n"
-                    "by NOFFLE (if configured) or by manually\n"
-                    "running the 'noffle --subscribe' command\n" );
-        snprintf( s, MAXCHAR, "Group: %s", grp );
-        DynStr_appLn( info, s );
-        snprintf( s, MAXCHAR, "Days without access: %i", days );
-        DynStr_appLn( info, s );
-        genPseudo( "Auto unsubscribed", DynStr_str( info ) );
-    }
-    del_DynStr( info );
-}
-
-void
-Pseudo_autoSubscribed()
-{
-    DynStr *info;
-
-    info = new_DynStr( 10000 );
-    if ( info )
-    {
-        DynStr_app( info,
-                    "NOFFLE has now automatically subscribed to\n"
-                    "this group. It will fetch articles next time\n"
-                    "it is online.\n" );
-        genPseudo( "Auto subscribed", DynStr_str( info ) );
-    }
-    del_DynStr( info );
-}
--- a/pseudo.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
-  pseudo.h
-
-  Handling of pseudo articles.
-
-  $Id: pseudo.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef PSEUDO_H
-#define PSEUDO_H
-
-#include "over.h"
-
-/*
-  General info is a special pseudo message for groups not on fetchlist.
-  It is never stored in database, but generated every time a content is read.
-  However the group counter is always increased. This ensures that there
-  is always at least 1 article visible (even if the user deletes it) for
-  using the auto-subscribe option.
-*/
-Bool
-Pseudo_isGeneralInfo( const char *msgId );
-
-void
-Pseudo_appGeneralInfo( void );
-
-const char *
-Pseudo_generalInfoHead( void );
-
-const char *
-Pseudo_generalInfoBody( void );
-
-
-const char *
-Pseudo_markedBody( void );
-
-const char *
-Pseudo_alreadyMarkedBody( void );
-
-const char *
-Pseudo_markingFailedBody( void );
-
-void
-Pseudo_retrievingFailed( const char *msgId, const char *reason );
-
-
-/*
-  Other pseudo articles are stored in database and can contain dynamically
-  generated information about the failure.
- */
-
-void
-Pseudo_cntInconsistent( const char *grp, int first, int last, int next );
-
-void
-Pseudo_missArts( const char *grp, int first, int next );
-
-void
-Pseudo_autoUnsubscribed( const char *grp, int days );
-
-void
-Pseudo_autoSubscribed( void );
-
-#endif
--- a/request.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,405 +0,0 @@
-/*
-  request.c
-
-  Collection of articles that are marked for download.
-
-  $Id: request.c 3 2000-01-04 11:35:42Z enz $
-*/
-
-#include "request.h"
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <assert.h>
-#include "config.h"
-#include "log.h"
-#include "util.h"
-
-
-/* This struct keeps record of the message IDs that are to be fetched from
-   one particular host. Several of these are chained together via the
-   "next" pointer, if we have several servers.
-*/
-
-struct Reqserv;
-typedef struct Reqserv Reqserv;
-
-struct Reqserv {
-  char*    serv;                /* Server the messages are to be requested
-                                   from */
-  char**   reql;                /* List of message IDs of requested
-                                   messages. Some entries (that have been
-                                   deleted) may be NULL */
-  int      reql_length;         /* Number of string pointers in reql,
-                                   including NULL entries */
-  int      reql_capacity;       /* maximum number of string pointers reql
-                                   can hold */
-  Bool     dirty;               /* whether the request list needs to be
-                                   rewritten to disk */
-  Reqserv* next;                /* next Reqserv in list */
-  time_t   mtime;               /* last modification time of request file */ 
-};
-
-/* List of servers */
-static Reqserv* reqserv = 0;
-
-/* sanity check */
-static Bool is_open = FALSE;
-
-/* for Req_first/Req_next */
-static char** iterator = 0;
-static char** iterator_end = 0;
-
-
-/* local functions */
-static Reqserv* newReqserv      (const char* serv);
-static Bool     getReqserv      (const char* serv, Reqserv** rsz);
-static void     fileRequest     (Str file, const char *serv);
-static char**   searchMsgId     (const Reqserv * rs, const char *msgId);
-static void     storeMsgId      (Reqserv* rs, const char* msgId);
-static Bool     readRequestfile (const char* serv, Reqserv** rsz);
-static time_t   get_mtime       (const char* serv);
-
-/* read modification time of request file */
-static time_t get_mtime(const char* serv)
-{
-  Str filename;
-  struct stat stat1;
-
-  fileRequest(filename, serv);
-  stat(filename, &stat1);
-  return stat1.st_mtime;
-}
-
-
-/* create new Reqserv and queue it */
-static Reqserv* newReqserv(const char* serv)
-{
-  Reqserv* rs = (Reqserv*) malloc(sizeof(Reqserv));
-  rs->serv = strcpy(malloc(strlen(serv)+1), serv);
-  rs->reql = 0;
-  rs->reql_length = 0;
-  rs->reql_capacity = 0;
-  rs->next = reqserv;
-  rs->dirty = FALSE;
-  rs->mtime = 0;
-  reqserv = rs;
-  return rs;
-}
-
-
-/* get Reqserv for given server, and save it in "rsz". Load from file as
-   necessary. Return TRUE on success. Otherwise log errors and return
-   FALSE. (details in errno)
-*/
-static Bool getReqserv(const char* serv, Reqserv** rsz)
-{
-  Reqserv* rs;
-  for (rs = reqserv; rs; rs = rs->next)
-    if (!strcmp(serv, rs->serv)) {
-      *rsz = rs;
-      return TRUE;
-    }
-  return readRequestfile(serv, rsz);
-}
-
-
-/* Delete Reqserv from cache, if not up-to-date */
-static void
-cleanupReqserv( void )
-{
-  Reqserv *rs, *prev, *next;
-
-  rs = reqserv;
-  prev = NULL;
-  while ( rs != NULL )
-  {      
-      ASSERT( ! rs->dirty );
-      next = rs->next;
-      if ( get_mtime( rs->serv ) != rs->mtime )
-      {
-          if ( prev != NULL )
-              prev->next = next;
-          else
-              reqserv = next;
-          free( rs->serv );
-          rs->serv = NULL;
-          free( rs->reql );
-          rs->reql = NULL;
-          free( rs );
-      }
-      prev = rs;
-      rs = next;
-  }
-}
-
-/* Save name of file storing requests from server "serv" in "file" */
-static void fileRequest( Str file, const char *serv)
-{
-  snprintf( file, MAXCHAR, "%s/requested/%s", Cfg_spoolDir(), serv);
-}
-
-
-/* Search for msgid in Reqserv. Return pointer to list entry. Return 0 if
-   list does not contain msgid. */
-static char** searchMsgId(const Reqserv * rs, const char *msgId )
-{
-  char** rz;
-  ASSERT(rs != 0);
-
-  if (!rs->reql)
-    return 0;
-
-  for (rz = rs->reql; rz < rs->reql + rs->reql_length; rz++)
-    if (*rz && !strcmp(*rz, msgId))
-      return rz;
-
-  return 0;
-}
-
-
-Bool
-Req_contains(const char *serv, const char *msgId)
-{
-  Reqserv* rs;
-  ASSERT( is_open );
-  if (getReqserv(serv, &rs) == FALSE) 
-    return FALSE;
-  return searchMsgId(rs, msgId) ? TRUE : FALSE;
-}
-
-
-static void storeMsgId(Reqserv* rs, const char* msgId)
-{
-  char* msgid;
-
-  if (searchMsgId(rs, msgId))
-    /* already recorded */
-    return;
-
-  msgid = strcpy(malloc(strlen(msgId)+1), msgId);
-
-  if (rs->reql_length >= rs->reql_capacity) {
-    int c1 = rs->reql_capacity*2 + 10;
-    rs->reql = (char**) realloc(rs->reql, c1*sizeof(char*));
-    rs->reql_capacity = c1;
-  }
-
-  *(rs->reql + rs->reql_length++) = msgid;
-  rs->dirty = TRUE;
-}
-
-
-/* Add request for message "msgIg" from server "serv". Return TRUE iff
-   successful. 
-*/
-Bool Req_add(const char *serv, const char *msgId)
-{
-    Reqserv* rs;
-    ASSERT( is_open );
-    Log_dbg( "Marking %s on %s for download", msgId, serv );
-
-    if (getReqserv(serv, &rs) == FALSE) 
-      return FALSE;
-    storeMsgId(rs, msgId);
-    return TRUE;
-}
-
-static Bool
-readLn( Str line, FILE* f )
-{
-    size_t len;
-
-    if ( ! fgets( line, MAXCHAR, f ) )
-        return FALSE;
-    len = strlen( line );
-    if ( line[ len - 1 ] == '\n' )
-        line[ len - 1 ] = '\0';
-    return TRUE;
-}
-
-/* Read request file into new, non-queued Reqserv. Save new Reqserv in
-   "rsz" and return TRUE on success. Returns FALSE on failure, see errno.
-   If the file doesn't exist, an empty Reqserv is returned.
-*/
-static Bool readRequestfile(const char* serv, Reqserv** rsz)
-{
-  Str           filename;
-  Str           line;
-  FILE*         file;
-  Reqserv*      rs;
-
-  fileRequest(filename, serv);
-  Log_dbg("reading request file %s", filename);
-
-  file = fopen(filename, "r");
-  if (!file && (errno == ENOENT)) {
-    *rsz = newReqserv(serv);
-    (*rsz)->mtime = get_mtime(serv);
-    return TRUE;
-  }
-  if (Log_check(file != 0,
-            "could not open %s for reading: %s", 
-            filename, strerror(errno)))
-    return FALSE;
-
-  rs = *rsz = newReqserv(serv);
-
-  while( readLn(line, file) == TRUE) {
-    char* line1 = Utl_stripWhiteSpace(line);
-    if (*line1)
-      storeMsgId(rs, line1);
-  }
-
-  rs->dirty = FALSE;
-
-  if (Log_check(fclose(file) != EOF, 
-            "could not close %s properly: %s\n", 
-            filename, strerror(errno)))
-    return FALSE;
-
-  return TRUE;
-}
-
-
-/* Write out request file for given Reqserv. Return TRUE on success. If an
-   I/O error occurs, it is logged, and FALSE is returned.
-*/
-static Bool writeRequestfile(Reqserv* rs)
-{
-  Str    filename;
-  FILE*  file;
-  char** z;
-
-  fileRequest(filename, rs->serv);
-  Log_dbg("writing request file %s", filename);
-
-  if (Log_check((file = fopen(filename, "w")) != 0,
-            "could not open %s for writing: %s", 
-            filename, strerror(errno)))
-    return FALSE;
-
-  if (rs->reql)
-    for (z = rs->reql; z < rs->reql+rs->reql_length; z++)
-      if (*z) {
-        if (Log_check(   fputs(*z, file) != EOF
-                      && fputs("\n", file) != EOF,
-                  "write error: %s", strerror(errno)))
-          return FALSE;
-      }
-  
-  if (Log_check(fclose(file) != EOF, 
-                "could not close %s properly: %s\n", 
-                filename, strerror(errno)))
-    return FALSE;
-            
-  rs->dirty = FALSE;
-  rs->mtime = get_mtime(rs->serv);
-
-  return TRUE;
-}
-
-
-void
-Req_remove( const char *serv, const char *msgId )
-{
-    Reqserv* rs;
-    char** z;
-    
-    ASSERT( is_open );
-    Log_dbg("Req_remove(\"%s\", \"%s\")", serv, msgId);
-    
-    if (getReqserv(serv, &rs) == FALSE) 
-        return;
-    
-    z = searchMsgId(rs, msgId);
-    if ( ! z )
-        return;
-    
-    free(*z);
-    *z = 0;
-    rs->dirty = TRUE;
-}
-
-
-Bool
-Req_first( const char *serv, Str msgId )
-{
-  Reqserv* rs;
-
-  ASSERT( is_open );
-  ASSERT( !iterator && !iterator_end );
-
-  if (getReqserv(serv, &rs) == FALSE)
-    return FALSE;
-
-  if (!rs->reql) 
-    return FALSE;
-
-  iterator = rs->reql - 1;
-  iterator_end = rs->reql + rs->reql_length;
-
-  return Req_next(msgId);
-}
-
-
-Bool
-Req_next( Str msgId )
-{
-  ASSERT( is_open );
-  ASSERT(iterator && iterator_end);
-
-  if (iterator >= iterator_end)
-      return FALSE;
-  iterator++;
-
-  while (iterator < iterator_end) {
-    if (!*iterator)
-      iterator++;
-    else {
-      Utl_cpyStr(msgId, *iterator);
-      return TRUE;
-    }
-  }
-
-  iterator = iterator_end = 0;
-  return FALSE;
-}
-
-
-/* Get exclusive access to all request files. Maybe we already have had it,
-   and the cache is outdated. So we delete request files, which have
-   changed recently, from cache. These files will be reread on demand.
-*/
-Bool
-Req_open(void)
-{
-  Log_dbg("opening request database");
-  ASSERT(is_open == FALSE);
-  cleanupReqserv();
-  is_open = TRUE;
-  return TRUE;
-}
-
-
-/* Do not occupy the request files any longer. Write any changes to disk.
-   Return TRUE on success, FALSE if an IO error occurs. */
-void Req_close(void) 
-{
-  Bool ret = TRUE;
-  Reqserv* rs;
-  Log_dbg("closing request database, writing changes to disk");
-  ASSERT(is_open == TRUE);
-
-  for (rs = reqserv; rs; rs = rs->next) {
-    if (rs->dirty == TRUE) {
-      if (!writeRequestfile(rs))
-        ret = FALSE;
-    }
-  }
-
-  is_open = FALSE;
-}
--- a/request.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
-  request.h
-
-  Collection of requested articles.
-
-  $Id: request.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef REQ_H
-#define REQ_H
-
-#include "common.h"
-
-/* Is request for message msgId from server serv already recorded? This
-   function has no error detection facility. On error, FALSE is returned.
-   Nevertheless, errors are logged. */
-Bool
-Req_contains( const char *serv, const char *msgId );
-
-/* Add request for message "msgId" from server "serv". Return TRUE if
-   successful. */ 
-Bool
-Req_add( const char *serv, const char *msgId );
-
-/* Remove request for message msgIg from server serv. This function does
-   not return any errors. Nevertheless, they are logged. */
-void
-Req_remove( const char *serv, const char *msgId );
-
-/* Begin iteration through all messages requested from one server. Return
-   TRUE if there are any requests. Save first message ID in msgId. On
-   error, it is logged, and FALSE is returned.
-*/
-Bool
-Req_first( const char *serv, Str msgId );
-
-/* Continue iteration. Return TRUE on success, FALSE when there are no more
-   requests. Save message ID in msgId. On error, it is logged, and FALSE is
-   returned. */
-Bool
-Req_next( Str msgId );
-
-/* Get exclusive access to the request files. Refresh cache as necessary. */
-Bool 
-Req_open(void);
-
-/* Write changes to disk */
-void
-Req_close(void);
-
-#endif
--- a/server.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1539 +0,0 @@
-/*
-  server.c
-
-  $Id: server.c 47 2000-05-05 08:32:53Z enz $
-*/
-
-#include "server.h"
-#include <ctype.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include "client.h"
-#include "common.h"
-#include "config.h"
-#include "content.h"
-#include "control.h"
-#include "database.h"
-#include "dynamicstring.h"
-#include "fetch.h"
-#include "fetchlist.h"
-#include "group.h"
-#include "itemlist.h"
-#include "lock.h"
-#include "log.h"
-#include "online.h"
-#include "outgoing.h"
-#include "post.h"
-#include "protocol.h"
-#include "pseudo.h"
-#include "request.h"
-#include "util.h"
-#include "wildmat.h"
-
-struct
-{
-    Bool running;
-    int artPtr;
-    Str grp; /* selected group, "" if none */
-} serv = { FALSE, 0, "" };
-
-typedef struct Cmd
-{
-    const char *name;
-    const char *syntax;
-    /* Returns false, if quit cmd */
-    Bool (*cmdProc)( char *arg, const struct Cmd *cmd );
-}
-Cmd;
-
-static Bool doArt( char *arg, const Cmd *cmd );
-static Bool doBody( char *arg, const Cmd *cmd );
-static Bool doGrp( char *arg, const Cmd *cmd );
-static Bool doHead( char *arg, const Cmd *cmd );
-static Bool doHelp( char *arg, const Cmd *cmd );
-static Bool doIhave( char *arg, const Cmd *cmd );
-static Bool doLast( char *arg, const Cmd *cmd );
-static Bool doList( char *arg, const Cmd *cmd );
-static Bool doListgrp( char *arg, const Cmd *cmd );
-static Bool doMode( char *arg, const Cmd *cmd );
-static Bool doNewgrps( char *arg, const Cmd *cmd );
-static Bool doNext( char *arg, const Cmd *cmd );
-static Bool doPost( char *arg, const Cmd *cmd );
-static Bool doSlave( char *arg, const Cmd *cmd );
-static Bool doStat( char *arg, const Cmd *cmd );
-static Bool doQuit( char *arg, const Cmd *cmd );
-static Bool doXhdr( char *arg, const Cmd *cmd );
-static Bool doXpat( char *arg, const Cmd *cmd );
-static Bool doXOver( char *arg, const Cmd *cmd );
-static Bool notImplemented( char *arg, const Cmd *cmd );
-static void putStat( unsigned int stat, const char *fmt, ... );
-
-Cmd commands[] =
-{
-    { "article", "ARTICLE [msg-id|n]", &doArt },
-    { "body", "BODY [msg-id|n]", &doBody },
-    { "head", "HEAD [msg-id|n]", &doHead },
-    { "group", "GROUP grp", &doGrp },
-    { "help", "HELP", &doHelp },
-    { "ihave", "IHAVE (ignored)", &doIhave },
-    { "last", "LAST", &doLast },
-    { "list", "LIST [ACTIVE [pat]]|ACTIVE.TIMES [pat]|"
-      "EXTENSIONS|NEWSGROUPS [pat]|OVERVIEW.FMT", &doList },
-    { "listgroup", "LISTGROUP grp", &doListgrp },
-    { "mode", "MODE (ignored)", &doMode },
-    { "newgroups", "NEWGROUPS [xx]yymmdd hhmmss [GMT]", &doNewgrps },
-    { "newnews", "NEWNEWS (not implemented)", &notImplemented },
-    { "next", "NEXT", &doNext },
-    { "post", "POST", &doPost },
-    { "quit", "QUIT", &doQuit },
-    { "slave", "SLAVE (ignored)", &doSlave },
-    { "stat", "STAT [msg-id|n]", &doStat },
-    { "xhdr", "XHDR over-field [m[-[n]]]", &doXhdr },
-    { "xpat", "XPAT over-field m[-[n]] pat", &doXpat },
-    { "xover", "XOVER [m[-[n]]]", &doXOver }
-};
-
-/*
-  Notice interest in reading this group.
-  Automatically subscribe if option set in config file.
-*/
-static void
-noteInterest( void )
-{
-    FetchMode mode;
-
-    Grp_setLastAccess( serv.grp, time( NULL ) );
-    if ( ! Grp_local ( serv.grp ) && Cfg_autoSubscribe() && ! Online_true() )
-    {
-        Fetchlist_read();
-        if ( ! Fetchlist_contains( serv.grp ) )
-        {
-            if ( strcmp( Cfg_autoSubscribeMode(), "full" ) == 0 )
-                mode = FULL;
-            else if ( strcmp( Cfg_autoSubscribeMode(), "thread" ) == 0 )
-                mode = THREAD;
-            else
-                mode = OVER;
-            Fetchlist_add( serv.grp, mode );
-            Fetchlist_write();
-            Pseudo_autoSubscribed();
-        }
-    }
-}
-
-static void
-putStat( unsigned int stat, const char *fmt, ... )
-{
-    Str s, line;
-    va_list ap;
-
-    ASSERT( stat <= 999 );
-    va_start( ap, fmt );
-    vsnprintf( s, MAXCHAR, fmt, ap );
-    va_end( ap );
-    snprintf( line, MAXCHAR, "%u %s", stat, s );
-    Log_dbg( "[S] %s", line );
-    printf( "%s\r\n", line );
-}
-
-static void
-putTxtLn( const char *fmt, ... )
-{
-    Str line;
-    va_list ap;
-
-    va_start( ap, fmt );
-    vsnprintf( line, MAXCHAR, fmt, ap );
-    va_end( ap );
-    Prt_putTxtLn( line, stdout );
-}
-
-static void
-putTxtBuf( const char *buf )
-{
-    if ( buf )
-        Prt_putTxtBuf( buf, stdout );
-}
-
-static void
-putEndOfTxt( void )
-{
-    Prt_putEndOfTxt( stdout );
-}
-
-static void
-putSyntax( const Cmd *cmd )
-{
-    putStat( STAT_SYNTAX_ERR, "Syntax error. Usage: %s", cmd->syntax );
-}
-
-static Bool
-getLn( Str line )
-{
-    return Prt_getLn( line, stdin );
-}
-
-static Bool
-getTxtLn( Str line, Bool *err )
-{
-    return Prt_getTxtLn( line, err, stdin );
-}
-
-static Bool
-notImplemented( char *arg, const Cmd *cmd )
-{
-    putStat( STAT_NO_PERMISSION, "Command not implemented" );
-    return TRUE;
-}
-
-static void
-checkNewArts( const char *grp )
-{
-    if ( ! Online_true()
-         || strcmp( grp, serv.grp ) == 0
-         || Grp_local( grp )
-         || time( NULL ) - Grp_lastAccess( serv.grp ) < 1800 )
-        return;
-    if ( Fetch_init( Grp_serv( grp ) ) )
-    {
-        Fetch_getNewArts( grp, OVER );
-        Fetch_close();
-    }
-}
-
-static void
-postArts()
-{
-    Str serv;
-
-    Cfg_beginServEnum();
-    while ( Cfg_nextServ( serv ) )
-        if ( Fetch_init( serv ) )
-        {
-            Fetch_postArts();
-            Fetch_close();
-        }
-}
-
-static void
-readCont( const char *name )
-{
-    Fetchlist_read();
-    Cont_read( name );
-    if ( ! Grp_local ( name )
-	 && ! Fetchlist_contains( name )
-	 && ! Online_true() )
-    { 
-        Pseudo_appGeneralInfo();
-        Grp_setFirstLast( name, Cont_first(), Cont_last() );
-    }
-}
-
-static void
-changeToGrp( const char *grp )
-{
-    checkNewArts( grp );
-    Utl_cpyStr( serv.grp, grp );
-    readCont( grp );
-    serv.artPtr = Cont_first();
-}
-
-static Bool
-doGrp( char *arg, const Cmd *cmd )
-{
-    int first, last, numb;
-
-    if ( arg[ 0 ] == '\0' )
-        putSyntax( cmd );
-    else if ( ! Grp_exists( arg ) )
-        putStat( STAT_NO_SUCH_GRP, "No such group" );
-    else
-    {
-        changeToGrp( arg );
-        first = Cont_first();
-        last = Cont_last();
-	if ( ( first == 0 && last == 0 )
-	     || first > last )
-            first = last = numb = 0;
-	else
-	    numb = last - first + 1;
-        putStat( STAT_GRP_SELECTED, "%lu %lu %lu %s selected",
-                 numb, first, last, arg );
-    }
-    return TRUE;
-}
-
-static Bool
-testGrpSelected( void )
-{
-    if ( *serv.grp == '\0' )
-    {
-        putStat( STAT_NO_GRP_SELECTED, "No group selected" );
-        return FALSE;
-    }
-    return TRUE;
-}
-
-static void
-findServ( const char *msgId, Str result )
-{
-    const char *p, *pColon, *serv;
-    Str s, grp;
-
-    Utl_cpyStr( result, "(unknown)" );
-    if ( Db_contains( msgId ) )
-    {
-        Utl_cpyStr( s, Db_xref( msgId ) );
-        p = strtok( s, " \t" );
-        if ( p )
-            do
-            {
-                pColon = strstr( p, ":" );
-                if ( pColon )
-                {
-                    Utl_cpyStrN( grp, p, pColon - p );
-                    serv = Grp_serv( grp );
-                    if ( Cfg_servIsPreferential( serv, result ) )
-                        Utl_cpyStr( result, serv );
-                }
-            }
-            while ( ( p = strtok( NULL, " \t" ) ) );
-    }
-}
-
-static Bool
-retrieveArt( const char *msgId )
-{
-    Str serv;
-
-    findServ( msgId, serv );    
-    if ( strcmp( serv, "(unknown)" ) == 0 
-         || strcmp( serv, GRP_LOCAL_SERVER_NAME ) == 0 )
-        return FALSE;        
-    if ( ! Client_connect( serv ) )
-        return FALSE;
-    Client_retrieveArt( msgId );
-    Client_disconnect();
-    return TRUE;
-}
-
-static Bool
-checkNumb( int numb )
-{
-    if ( ! testGrpSelected() )
-        return FALSE;
-    if ( ! Cont_validNumb( numb ) )
-    {
-        putStat( STAT_NO_SUCH_NUMB, "No such article" );
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/*
-  Parse arguments for ARTICLE, BODY, HEAD, STAT commands.
-  Return message-ID and article number (0 if unknown).
-*/
-static Bool
-whichId( const char **msgId, int *numb, char *arg )
-{
-    const Over *ov;
-    int n;
-
-    if ( sscanf( arg, "%d", &n ) == 1 )
-    {
-        if ( ! checkNumb( n ) )
-            return FALSE;
-        serv.artPtr = n;
-        ov = Cont_get( n );
-        *msgId = Ov_msgId( ov );
-        *numb = n;
-    }
-    else if ( strcmp( arg, "" ) == 0 )
-    {
-        if ( ! checkNumb( serv.artPtr ) )
-            return FALSE;
-        ov = Cont_get( serv.artPtr );
-        *msgId = Ov_msgId( ov );
-        *numb =  serv.artPtr;
-    }
-    else
-    {
-        *msgId = arg;
-        *numb = 0;
-    }
-    if ( ! Pseudo_isGeneralInfo( *msgId ) && ! Db_contains( *msgId ) )
-    {
-        putStat( STAT_NO_SUCH_NUMB, "No such article" );
-        return FALSE;
-    }
-    return TRUE;
-}
-
-void
-touchArticle( const char *msgId )
-{
-    int stat = Db_stat( msgId );
-    stat |= DB_INTERESTING;
-    Db_setStat( msgId, stat );
-    Db_updateLastAccess( msgId );
-}
-
-static void
-touchReferences( const char *msgId )
-{
-    Str s;
-    int len;
-    char *p;
-    const char *ref = Db_ref( msgId );
-
-    while ( TRUE )
-    {
-        p = s;
-        while ( *ref != '<' )
-            if ( *(ref++) == '\0' )
-                return;
-        len = 0;
-        while ( *ref != '>' )
-        {
-            if ( *ref == '\0' || ++len >= MAXCHAR - 1 )
-                return;
-            *(p++) = *(ref++);
-        }
-        *(p++) = '>';
-        *p = '\0';
-        if ( Db_contains( s ) )
-            touchArticle( s );
-    }
-}
-
-static void
-doBodyInDb( const char *msgId )
-{
-    int stat;
-    Str serv;
-
-    touchArticle( msgId );
-    touchReferences( msgId );
-    stat = Db_stat( msgId );
-    if ( Online_true() && ( stat & DB_NOT_DOWNLOADED ) )
-    {
-        retrieveArt( msgId );
-        stat = Db_stat( msgId );
-    }
-    if ( stat & DB_RETRIEVING_FAILED )
-    {
-        Db_setStat( msgId, stat & ~DB_RETRIEVING_FAILED );
-        putTxtBuf( Db_body( msgId ) );
-    }
-    else if ( stat & DB_NOT_DOWNLOADED )
-    {
-        findServ( msgId, serv );
-        if ( Req_contains( serv, msgId ) )
-            putTxtBuf( Pseudo_alreadyMarkedBody() );
-        else if ( strcmp( serv, "(unknown)" ) != 0 && 
-		  strcmp( serv, GRP_LOCAL_SERVER_NAME ) != 0 && 
-		  Req_add( serv, msgId ) )
-            putTxtBuf( Pseudo_markedBody() );
-        else
-            putTxtBuf( Pseudo_markingFailedBody() );
-    }
-    else
-        putTxtBuf( Db_body( msgId ) );
-}
-
-static Bool
-doBody( char *arg, const Cmd *cmd )
-{
-    const char *msgId;
-    int numb;
-    
-    if ( ! whichId( &msgId, &numb, arg ) )
-        return TRUE;
-    putStat( STAT_BODY_FOLLOWS, "%ld %s Body", numb, msgId );
-    if ( Pseudo_isGeneralInfo( msgId ) )
-        putTxtBuf( Pseudo_generalInfoBody() );
-    else
-        doBodyInDb( msgId );
-    putEndOfTxt();
-    noteInterest();
-    return TRUE;
-}
-
-static void
-doHeadInDb( const char *msgId )
-{
-    putTxtBuf( Db_header( msgId ) );
-}
-
-static Bool
-doHead( char *arg, const Cmd *cmd )
-{
-    const char *msgId;
-    int numb;
-    
-    if ( ! whichId( &msgId, &numb, arg ) )
-        return TRUE;
-    putStat( STAT_HEAD_FOLLOWS, "%ld %s Head", numb, msgId );
-    if ( Pseudo_isGeneralInfo( msgId ) )
-        putTxtBuf( Pseudo_generalInfoHead() );
-    else
-        doHeadInDb( msgId );
-    putEndOfTxt();
-    return TRUE;
-}
-
-static void
-doArtInDb( const char *msgId )
-{
-    doHeadInDb( msgId );
-    putTxtLn( "" );
-    doBodyInDb( msgId );
-}
-
-static Bool
-doArt( char *arg, const Cmd *cmd )
-{
-    const char *msgId;
-    int numb;
-    
-    if ( ! whichId( &msgId, &numb, arg ) )
-        return TRUE;
-    putStat( STAT_ART_FOLLOWS, "%ld %s Article", numb, msgId );
-    if ( Pseudo_isGeneralInfo( msgId ) )
-    {
-        putTxtBuf( Pseudo_generalInfoHead() );
-        putTxtLn( "" );
-        putTxtBuf( Pseudo_generalInfoBody() );
-    }
-    else
-        doArtInDb( msgId );
-    putEndOfTxt();
-    noteInterest();
-    return TRUE;
-}
-
-static Bool
-doHelp( char *arg, const Cmd *cmd )
-{
-    unsigned int i;
-
-    putStat( STAT_HELP_FOLLOWS, "Help" );
-    putTxtBuf( "\nCommands:\n\n" );
-    for ( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); ++i )
-        putTxtLn( "%s", commands[ i ].syntax );
-    putEndOfTxt();
-    return TRUE;
-}
-
-static Bool
-doIhave( char *arg, const Cmd *cmd )
-{
-    putStat( STAT_ART_REJECTED, "Command not used" );
-    return TRUE;
-}
-
-static Bool
-doLast( char *arg, const Cmd *cmd )
-{
-    int n;
-
-    if ( testGrpSelected() )
-    {
-        n = serv.artPtr;
-        if ( ! Cont_validNumb( n ) )
-            putStat( STAT_NO_ART_SELECTED, "No article selected" );
-        else
-        {
-            while ( ! Cont_validNumb( --n ) && n >= Cont_first() );
-            if ( ! Cont_validNumb( n ) )
-                putStat( STAT_NO_PREV_ART, "No previous article" );
-            else
-            {
-                putStat( STAT_ART_RETRIEVED, "%ld %s selected",
-                         n, Ov_msgId( Cont_get( n ) ) );
-                serv.artPtr = n;
-            }
-        }
-    }
-    return TRUE;
-}
-
-static void
-printGroups( const char *pat, void (*printProc)( Str, const char* ) )
-{
-    Str line;
-    const char *g;
-    FILE *f;
-    sig_t lastHandler;
-    int ret;
-
-    putStat( STAT_GRPS_FOLLOW, "Groups" );
-    fflush( stdout );
-    Log_dbg( "[S FLUSH]" );
-    if ( Grp_exists( pat ) )
-    {
-        (*printProc)( line, pat );
-        if ( ! Prt_putTxtLn( line, stdout ) )
-            Log_err( "Writing to stdout failed." );
-    }                    
-    else
-    {
-        lastHandler = signal( SIGPIPE, SIG_IGN );
-        f = popen( "sort", "w" );
-        if ( f == NULL )
-        {
-            Log_err( "Cannot open pipe to 'sort'" );
-            if ( Grp_firstGrp( &g ) )
-                do
-                    if ( Wld_match( g, pat ) )
-                    {
-                        (*printProc)( line, g );
-                        if ( ! Prt_putTxtLn( line, stdout ) )
-                            Log_err( "Writing to stdout failed." );
-                    }
-                while ( Grp_nextGrp( &g ) );
-        }
-        else
-        {
-            if ( Grp_firstGrp( &g ) )
-                do
-                    if ( Wld_match( g, pat ) )
-                    {
-                        (*printProc)( line, g );
-                        if ( ! Prt_putTxtLn( line, f ) )
-                        {
-                            Log_err( "Writing to 'sort' pipe failed." );
-                            break;
-                        }                    
-                    }
-                while ( Grp_nextGrp( &g ) );
-            ret = pclose( f );
-            if ( ret != EXIT_SUCCESS )
-                Log_err( "sort command returned %d", ret );
-            fflush( stdout );
-            Log_dbg( "[S FLUSH]" );
-            signal( SIGPIPE, lastHandler );
-        }
-    }
-    putEndOfTxt();
-}
-
-static void
-printActiveTimes( Str result, const char *grp )
-{
-    snprintf( result, MAXCHAR, "%s %ld", grp, Grp_created( grp ) );
-}
-
-static void
-doListActiveTimes( const char *pat )
-{
-    printGroups( pat, &printActiveTimes );
-}
-
-static void
-printActive( Str result, const char *grp )
-{
-    snprintf( result, MAXCHAR, "%s %d %d %c",
-              grp, Grp_last( grp ), Grp_first( grp ), Grp_postAllow( grp ) );
-}
-
-static void
-doListActive( const char *pat )
-{
-    printGroups( pat, &printActive );
-}
-
-static void
-printNewsgrp( Str result, const char *grp )
-{
-    snprintf( result, MAXCHAR, "%s %s", grp, Grp_dsc( grp ) );
-}
-
-static void
-doListNewsgrps( const char *pat )
-{
-    printGroups( pat, &printNewsgrp );
-}
-
-static void
-putGrp( const char *name )
-{
-    putTxtLn( "%s %lu %lu y", name, Grp_last( name ), Grp_first( name ) );
-}
-
-static void
-doListOverFmt( void )
-{
-    putStat( STAT_GRPS_FOLLOW, "Overview format" );
-    putTxtBuf( "Subject:\n"
-               "From:\n"
-               "Date:\n"
-               "Message-ID:\n"
-               "References:\n"
-               "Bytes:\n"
-               "Lines:\n" );
-    putEndOfTxt();
-}
-
-static void
-doListExtensions( void )
-{
-    putStat( STAT_CMD_OK, "Extensions" );
-    putTxtBuf( " LISTGROUP\n"
-               " XOVER\n" );
-    putEndOfTxt();    
-}
-
-static Bool
-doList( char *line, const Cmd *cmd )
-{
-    Str s, arg;
-    const char *pat;
-
-    if ( sscanf( line, "%s", s ) != 1 )
-        doListActive( "*" );
-    else
-    {
-        Utl_toLower( s );
-        strcpy( arg, Utl_restOfLn( line, 1 ) );
-        pat = Utl_stripWhiteSpace( arg );
-        if ( pat[ 0 ] == '\0' )
-            pat = "*";
-        if ( strcmp( "active", s ) == 0 )
-            doListActive( pat );
-        else if ( strcmp( "overview.fmt", s ) == 0 )
-            doListOverFmt();
-        else if ( strcmp( "newsgroups", s ) == 0 )
-            doListNewsgrps( pat );
-        else if ( strcmp( "active.times", s ) == 0 )
-            doListActiveTimes( pat );
-        else if ( strcmp( "extensions", s ) == 0 )
-            doListExtensions();
-        else
-            putSyntax( cmd );
-    }
-    return TRUE;
-}
-
-static Bool
-doListgrp( char *arg, const Cmd *cmd )
-{
-    const Over *ov;
-    int first, last, i;
-
-    if ( ! Grp_exists( arg ) )
-        putStat( STAT_NO_SUCH_GRP, "No such group" );
-    else
-    {
-        changeToGrp( arg );
-        first = Cont_first();
-        last = Cont_last();
-        putStat( STAT_GRP_SELECTED, "Article list" );
-        for ( i = first; i <= last; ++i )
-            if ( ( ov = Cont_get( i ) ) )
-                putTxtLn( "%lu", i );
-        putEndOfTxt();
-    }
-    return TRUE;
-}
-
-static Bool
-doMode( char *arg, const Cmd *cmd )
-{
-    putStat( STAT_READY_POST_ALLOW, "Ok" );
-    return TRUE;
-}
-
-static unsigned long
-getTimeInSeconds( unsigned int year, unsigned int mon, unsigned int day,
-                  unsigned int hour, unsigned int min, unsigned int sec )
-{
-    struct tm t = { 0 };
-
-    t.tm_year = year - 1900;
-    t.tm_mon = mon - 1;
-    t.tm_mday = day;
-    t.tm_hour = hour;
-    t.tm_min = min;
-    t.tm_sec = sec;
-    return mktime( &t );
-}
-
-
-static Bool
-doNewgrps( char *arg, const Cmd *cmd )
-{
-    time_t t, now, lastUpdate;
-    unsigned int year, mon, day, hour, min, sec, cent, len;
-    const char *g;
-    Str date, timeofday, file;
-
-    if ( sscanf( arg, "%s %s", date, timeofday ) != 2 ) 
-    {
-        putSyntax( cmd );
-        return TRUE;
-    }
-    len = strlen( date );
-    switch ( len )
-    {
-    case 6:
-        if ( sscanf( date, "%2u%2u%2u", &year, &mon, &day ) != 3 )
-        {
-            putSyntax( cmd );
-            return TRUE;
-        }
-        now = time( NULL );
-        cent = 1900;
-        while ( now > getTimeInSeconds( cent + 100, 1, 1, 0, 0, 0 ) )
-            cent += 100;
-        year += cent;
-        break;
-    case 8:
-        if ( sscanf( date, "%4u%2u%2u", &year, &mon, &day ) != 3 )
-        {
-            putSyntax( cmd );
-            return TRUE;
-        }
-        break;
-    default:
-        putSyntax( cmd );
-        return TRUE;
-    }
-    if ( sscanf( timeofday, "%2u%2u%2u", &hour, &min, &sec ) != 3 )
-    {
-        putSyntax( cmd );
-        return TRUE;
-    }
-    if ( year < 1970 || mon == 0 || mon > 12 || day == 0 || day > 31
-         || hour > 23 || min > 59 || sec > 60 )
-    {
-        putSyntax( cmd );
-        return TRUE;
-    }
-    snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
-    t = getTimeInSeconds( year, mon, day, hour, min, sec );
-    putStat( STAT_NEW_GRP_FOLLOW, "New groups since %s", arg );
-
-    if ( ! Utl_getStamp( &lastUpdate, file ) || t <= lastUpdate )
-    {
-        if ( Grp_firstGrp( &g ) )
-            do
-                if ( Grp_created( g ) > t )
-                    putGrp( g );
-            while ( Grp_nextGrp( &g ) );
-    }
-    putEndOfTxt();
-    return TRUE;
-}
-
-static Bool
-doNext( char *arg, const Cmd *cmd )
-{
-    int n;
-
-    if ( testGrpSelected() )
-    {
-        n = serv.artPtr;
-        if ( ! Cont_validNumb( n ) )
-            putStat( STAT_NO_ART_SELECTED, "No article selected" );
-        else
-        {
-            while ( ! Cont_validNumb( ++n ) && n <= Cont_last() );
-            if ( ! Cont_validNumb( n ) )
-                putStat( STAT_NO_NEXT_ART, "No next article" );
-            else
-            {
-                putStat( STAT_ART_RETRIEVED, "%ld %s selected",
-                         n, Ov_msgId( Cont_get( n ) ) );
-                serv.artPtr = n;
-            }
-        }
-    }
-    return TRUE;
-}
-
-/* Cancel and return TRUE if need to send cancel message on to server. */
-static Bool
-controlCancel( const char *cancelId )
-{
-    return ( Ctrl_cancel( cancelId ) == CANCEL_NEEDS_MSG );
-}
-
-/*
-  It's a control message. Currently we only know about 'cancel'
-  messages; others are passed on for outside groups, and logged
-  as ignored for local groups.
- */
-static Bool
-handleControl( ItemList *control, ItemList *newsgroups,
-	       const char *msgId, const DynStr *art )
-{
-    const char *grp;
-    const char *op;
-    Bool err = FALSE;
-    Bool localDone = FALSE;
-
-    op = Itl_first( control );
-    if ( op == NULL )
-    {
-	Log_err( "Malformed control line." );
-	return TRUE;
-    }
-    else if ( strcasecmp( op, "cancel" ) == 0 )
-    {
-	if ( controlCancel( Itl_next( control ) ) )
-	    localDone = TRUE;
-	else
-	    return err;
-    }
-
-    /* Pass on for outside groups. */
-    for( grp = Itl_first( newsgroups );
-	 grp != NULL;
-	 grp = Itl_next( newsgroups ) )
-    {
-	if ( Grp_exists( grp ) && ! Grp_local( grp ) )
-	{
-	    if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
-	    {
-		Log_err( "Cannot add posted article to outgoing directory" );
-		err = TRUE;
-	    }
-	    break;
-	}
-    }
-
-    if ( localDone )
-	return err;
-
-    /* Log 'can't do' for internal groups. */
-    for( grp = Itl_first( newsgroups );
-	 grp != NULL;
-	 grp = Itl_next( newsgroups ) )
-    {
-	if ( Grp_exists( grp ) && Grp_local( grp ) )
-	    Log_inf( "Ignoring control '%s' for '%s'.", op, grp );
-    }
-
-    return err;
-}
-
-static Bool
-postArticle( ItemList *newsgroups, const char *msgId, const DynStr *art )
-{
-    const char *grp;
-    Bool err;
-    Bool oneLocal;
-
-    err = oneLocal = FALSE;
-
-    /* Run round first doing all local groups. */ 
-    for( grp = Itl_first( newsgroups );
-	 grp != NULL;
-	 grp = Itl_next( newsgroups ) )
-    {
-	if ( Grp_local( grp ) )
-	{
-	    if ( ! oneLocal )
-	    {
-		if ( ! Post_open( DynStr_str( art ) ) )
-		{
-		    err = TRUE;
-		    break;
-		}
-		else
-		    oneLocal = TRUE;
-	    }
-
-	    if ( ! Post_add( grp ) )
-		err = TRUE;
-	}
-    }
-    if ( oneLocal )
-	Post_close();
-
-    /* Now look for a valid external group. */
-    for( grp = Itl_first( newsgroups );
-	 grp != NULL;
-	 grp = Itl_next( newsgroups ) )
-    {
-	if ( Grp_exists( grp ) && ! Grp_local( grp ) )
-	{
-	    if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
-	    {
-		Log_err( "Cannot add posted article to outgoing directory" );
-		err = TRUE;
-	    }
-	    break;
-	}
-    }
-
-    return err;
-}
-
-static Bool
-doPost( char *arg, const Cmd *cmd )
-{
-    Bool err, replyToFound, dateFound, inHeader;
-    DynStr *s;
-    Str line, field, val, msgId, from;
-    const char* p;
-    ItemList * newsgroups, *control;
-
-    /*
-      Get article and make following changes to the header:
-      - add/replace/cut Message-ID depending on config options
-      - add Reply-To with content of From, if missing
-      (some providers overwrite From field)
-      - rename X-Sender header to X-NOFFLE-X-Sender
-      (some providers want to insert their own X-Sender)
-
-      For doing this, it is not necessary to parse multiple-line
-      headers.
-    */
-    putStat( STAT_SEND_ART, "Continue (end with period)" );
-    fflush( stdout );
-    Log_dbg( "[S FLUSH]" );
-    s = new_DynStr( 10000 );
-    msgId[ 0 ] = '\0';
-    from[ 0 ] = '\0';
-    newsgroups = control = NULL;
-    replyToFound = dateFound = FALSE;
-    inHeader = TRUE;
-    while ( getTxtLn( line, &err ) )
-    {
-        if ( inHeader )
-        {
-            p = Utl_stripWhiteSpace( line );
-            if ( *p == '\0' )
-            {
-                inHeader = FALSE;
-                if ( from[ 0 ] == '\0' )
-                    Log_err( "Posted message has no From field" );
-                if ( ! Cfg_removeMsgId() )
-                {
-                    if ( Cfg_replaceMsgId() )
-                    {
-                        Prt_genMsgId( msgId, from, "NOFFLE" );
-                        Log_dbg( "Replacing Message-ID with '%s'", msgId );
-                    }
-                    else if ( msgId[ 0 ] == '\0' )
-                    {
-                        Prt_genMsgId( msgId, from, "NOFFLE" );
-
-                        Log_inf( "Adding missing Message-ID '%s'", msgId );
-                    }
-                    else if ( ! Prt_isValidMsgId( msgId ) )
-                    {
-                        Log_ntc( "Replacing invalid Message-ID with '%s'",
-                                 msgId );
-                        Prt_genMsgId( msgId, from, "NOFFLE" );
-                    }
-                    DynStr_app( s, "Message-ID: " );
-                    DynStr_appLn( s, msgId );
-                }
-                if ( ! replyToFound && from[ 0 ] != '\0' )
-                {
-                    Log_dbg( "Adding Reply-To field to posted message." );
-                    DynStr_app( s, "Reply-To: " );
-                    DynStr_appLn( s, from );
-                }
-		if ( ! dateFound )
-		{
-		    time_t t;
-
-		    time( &t );
-		    Utl_rfc822Date( t, val );
-		    DynStr_app( s, "Date: " );
-		    DynStr_appLn( s, val );
-		}
-                DynStr_appLn( s, p );
-            }
-            else if ( Prt_getField( field, val, p ) )
-            {
-                if ( strcmp( field, "message-id" ) == 0 )
-                    strcpy( msgId, val );
-                else if ( strcmp( field, "from" ) == 0 )
-                {
-                    strcpy( from, val );
-                    DynStr_appLn( s, p );
-                }
-                else if ( strcmp( field, "newsgroups" ) == 0 )
-                {
-		    Utl_toLower( val );
-		    newsgroups = new_Itl ( val, " ," );
-                    DynStr_appLn( s, p );
-                }
-                else if ( strcmp( field, "control" ) == 0 )
-                {
-		    control = new_Itl ( val, " " );
-                    DynStr_appLn( s, p );
-                }
-                else if ( strcmp( field, "reply-to" ) == 0 )
-                {
-                    replyToFound = TRUE;
-                    DynStr_appLn( s, p );
-                }
-                else if ( strcmp( field, "date" ) == 0 )
-                {
-                    dateFound = TRUE;
-                    DynStr_appLn( s, p );
-                }
-                else if ( strcmp( field, "x-sender" ) == 0 )
-                {
-                    DynStr_app( s, "X-NOFFLE-X-Sender: " );
-                    DynStr_appLn( s, val );
-                }
-                else
-                    DynStr_appLn( s, p );
-            }
-            else
-                DynStr_appLn( s, line );
-        }
-        else
-            DynStr_appLn( s, line );
-    }
-    if ( inHeader )
-        Log_err( "Posted message has no body" );
-    if ( ! err )
-    {
-        if ( newsgroups == NULL || Itl_count( newsgroups ) == 0 )
-        {
-            Log_err( "Posted message has no valid Newsgroups header field" );
-            err = TRUE;
-        }
-        else
-	{
-	    const char *grp;
-	    Bool knownGrp = FALSE;
-	    Bool postAllowedGrp = FALSE;
-
-	    /* Check at least one group is known. */
-	    for( grp = Itl_first( newsgroups );
-		 grp != NULL;
-		 grp = Itl_next( newsgroups ) )
-	    {
-		if ( Grp_exists( grp ) )
-		{
-		    knownGrp = TRUE;
-		    switch( Grp_postAllow( grp ) )
-		    {
-		    case 'n':
-			break;
-		    case 'm':
-			/* Can't post to moderated local groups. */
-			postAllowedGrp = ! Grp_local( grp );
-			break;
-		    default:
-			postAllowedGrp = TRUE;
-		    }
-		    if ( postAllowedGrp )
-			break;
-		}
-	    }
-	    
-	    if ( ! knownGrp )
-	    {
-
-		Log_err( "No known group in Newsgroups header field" );
-		err = TRUE;
-	    }
-	    else if ( ! postAllowedGrp )
-	    {
-
-		Log_err( "No group permits posting" );
-		err = TRUE;
-	    }
-	    else
-	    {
-		err = ( control == NULL )
-		    ? postArticle( newsgroups, msgId, s )
-		    : handleControl( control, newsgroups, msgId, s );
-	    }	    
-	}
-    }
-    if ( err )
-        putStat( STAT_POST_FAILED, "Posting failed" );
-    else
-    {
-        putStat( STAT_POST_OK, "Message posted" );
-        if ( Online_true() )
-            postArts();
-    }
-    del_Itl( newsgroups );
-    del_Itl( control );
-    del_DynStr( s );
-    return TRUE;
-}
-
-static void
-parseRange( const char *s, int *first, int *last, int *numb )
-{
-    int r, i;
-    char* p;
-    Str t;
-
-    Utl_cpyStr( t, s );
-    p = Utl_stripWhiteSpace( t );
-    r = sscanf( p, "%d-%d", first, last );
-    if ( r < 1 )
-    {
-        *first = serv.artPtr;
-        *last = serv.artPtr;
-    }
-    else if ( r == 1 )
-    {
-        if ( p[ strlen( p ) - 1 ] == '-' )
-            *last = Cont_last();
-        else
-            *last = *first;
-    }    
-    if ( *first < Cont_first() )
-        *first = Cont_first();
-    if ( *last > Cont_last() )
-        *last = Cont_last();
-    if ( *first > Cont_last() ||  *last < Cont_first() )
-        *last = *first - 1;
-    *numb = 0;
-    for ( i = *first; i <= *last; ++i )
-        if ( Cont_validNumb( i ) )
-            ++(*numb);
-}
-
-static Bool
-doXhdr( char *arg, const Cmd *cmd )
-{
-    int first, last, i, n, numb;
-    enum { SUBJ, FROM, DATE, MSG_ID, REF, BYTES, LINES } what;
-    const char *p;
-    const Over *ov;
-    Str whatStr;
-
-    if ( ! testGrpSelected() )
-        return TRUE;
-    if ( sscanf( arg, "%s", whatStr ) != 1 )
-    {
-        putSyntax( cmd );
-        return TRUE;
-    }
-    Utl_toLower( whatStr );
-    if ( strcmp( whatStr, "subject" ) == 0 )
-        what = SUBJ;
-    else if ( strcmp( whatStr, "from" ) == 0 )
-        what = FROM;
-    else if ( strcmp( whatStr, "date" ) == 0 )
-        what = DATE;
-    else if ( strcmp( whatStr, "message-id" ) == 0 )
-        what = MSG_ID;
-    else if ( strcmp( whatStr, "references" ) == 0 )
-        what = REF;
-    else if ( strcmp( whatStr, "bytes" ) == 0 )
-        what = BYTES;
-    else if ( strcmp( whatStr, "lines" ) == 0 )
-        what = LINES;
-    else
-    {
-        putStat( STAT_HEAD_FOLLOWS, "Unknown header (empty list follows)" );
-        putEndOfTxt();
-        return TRUE;
-    }
-    p = Utl_restOfLn( arg, 1 );
-    parseRange( p, &first, &last, &numb );
-    if ( numb == 0 )
-        putStat( STAT_NO_ART_SELECTED, "No articles selected" );
-    else
-    {
-        putStat( STAT_HEAD_FOLLOWS, "%s header %lu-%lu",
-                 whatStr, first, last ) ;
-        for ( i = first; i <= last; ++i )
-            if ( ( ov = Cont_get( i ) ) )
-            {
-                n = Ov_numb( ov );
-                switch ( what )
-                {
-                case SUBJ:
-                    putTxtLn( "%lu %s", n, Ov_subj( ov ) );
-                    break;
-                case FROM:
-                    putTxtLn( "%lu %s", n, Ov_from( ov ) );
-                    break;
-                case DATE:
-                    putTxtLn( "%lu %s", n, Ov_date( ov ) );
-                    break;
-                case MSG_ID:
-                    putTxtLn( "%lu %s", n, Ov_msgId( ov ) );
-                    break;
-                case REF:
-                    putTxtLn( "%lu %s", n, Ov_ref( ov ) );
-                    break;
-                case BYTES:
-                    putTxtLn( "%lu %d", n, Ov_bytes( ov ) );
-                    break;
-                case LINES:
-                    putTxtLn( "%lu %d", n, Ov_lines( ov ) );
-                    break;
-                default:
-                    ASSERT( FALSE );
-                }
-            }
-        putEndOfTxt();
-    }
-    return TRUE;
-}
-
-static Bool
-doXpat( char *arg, const Cmd *cmd )
-{
-    int first, last, i, n;
-    enum { SUBJ, FROM, DATE, MSG_ID, REF } what;
-    const Over *ov;
-    Str whatStr, pat;
-
-    if ( ! testGrpSelected() )
-        return TRUE;
-    if ( sscanf( arg, "%s %d-%d %s", whatStr, &first, &last, pat ) != 4 )
-    {
-        if ( sscanf( arg, "%s %d- %s", whatStr, &first, pat ) == 3 )
-            last = Cont_last();
-        else if ( sscanf( arg, "%s %d %s", whatStr, &first, pat ) == 3 )
-            last = first;
-        else
-        {
-            putSyntax( cmd );
-            return TRUE;
-        }
-    }
-    Utl_toLower( whatStr );
-    if ( strcmp( whatStr, "subject" ) == 0 )
-        what = SUBJ;
-    else if ( strcmp( whatStr, "from" ) == 0 )
-        what = FROM;
-    else if ( strcmp( whatStr, "date" ) == 0 )
-        what = DATE;
-    else if ( strcmp( whatStr, "message-id" ) == 0 )
-        what = MSG_ID;
-    else if ( strcmp( whatStr, "references" ) == 0 )
-        what = REF;
-    else
-    {
-        putStat( STAT_HEAD_FOLLOWS, "invalid header (empty list follows)" );
-        putEndOfTxt();
-        return TRUE;
-    }
-    putStat( STAT_HEAD_FOLLOWS, "header" ) ;
-    for ( i = first; i <= last; ++i )
-        if ( ( ov = Cont_get( i ) ) )
-        {
-            n = Ov_numb( ov );
-            switch ( what )
-            {
-            case SUBJ:
-                if ( Wld_match( Ov_subj( ov ), pat ) )
-                     putTxtLn( "%lu %s", n, Ov_subj( ov ) );
-                break;
-            case FROM:
-                if ( Wld_match( Ov_from( ov ), pat ) )
-                    putTxtLn( "%lu %s", n, Ov_from( ov ) );
-                break;
-            case DATE:
-                if ( Wld_match( Ov_date( ov ), pat ) )
-                    putTxtLn( "%lu %s", n, Ov_date( ov ) );
-                break;
-            case MSG_ID:
-                if ( Wld_match( Ov_msgId( ov ), pat ) )
-                    putTxtLn( "%lu %s", n, Ov_msgId( ov ) );
-                break;
-            case REF:
-                if ( Wld_match( Ov_ref( ov ), pat ) )
-                    putTxtLn( "%lu %s", n, Ov_ref( ov ) );
-                break;
-            default:
-                ASSERT( FALSE );
-            }
-        }
-    putEndOfTxt();
-    return TRUE;
-}
-
-static Bool
-doSlave( char *arg, const Cmd *cmd )
-{
-    putStat( STAT_CMD_OK, "Ok" );
-    return TRUE;
-}
-
-static Bool
-doStat( char *arg, const Cmd *cmd )
-{
-    const char *msgId;
-    int numb;
-    
-    if ( ! whichId( &msgId, &numb, arg ) )
-        return TRUE;
-    if ( numb > 0 )
-        putStat( STAT_ART_RETRIEVED, "%ld %s selected",
-                 numb, msgId );
-    else
-        putStat( STAT_ART_RETRIEVED, "0 %s selected", msgId );
-    return TRUE;
-}
-
-static Bool
-doQuit( char *arg, const Cmd *cmd )
-{
-    putStat( STAT_GOODBYE, "Goodbye" );
-    return FALSE;
-}
-
-static Bool
-doXOver( char *arg, const Cmd *cmd )
-{
-    int first, last, i, n;
-    const Over *ov;
-
-    if ( ! testGrpSelected() )
-        return TRUE;
-    parseRange( arg, &first, &last, &n );
-    if ( n == 0 )
-        putStat( STAT_NO_ART_SELECTED, "No articles selected" );
-    else
-    {
-        putStat( STAT_OVERS_FOLLOW, "Overview %ld-%ld", first, last );
-        for ( i = first; i <= last; ++i )
-            if ( ( ov = Cont_get( i ) ) )
-                putTxtLn( "%lu\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t",
-                          Ov_numb( ov ), Ov_subj( ov ), Ov_from( ov ),
-                          Ov_date( ov ), Ov_msgId( ov ), Ov_ref( ov ),
-                          Ov_bytes( ov ), Ov_lines( ov ) );
-        putEndOfTxt();
-    }
-    return TRUE;
-}
-
-static void
-putFatal( const char *fmt, ... )
-{
-    va_list ap;
-    Str s;
-
-    va_start( ap, fmt );
-    vsnprintf( s, MAXCHAR, fmt, ap );
-    va_end( ap );
-    Log_err( s );
-    putStat( STAT_PROGRAM_FAULT, "%s", s );
-    fflush( stdout );
-    Log_dbg( "[S FLUSH]" );
-}
-
-/* Parse line, execute command and return FALSE, if it was the quit command. */
-static Bool
-parseAndExecute( Str line )
-{
-    unsigned int i, n;
-    Cmd *c;
-    Str s, arg;
-    Bool ret;
-
-    if ( sscanf( line, "%s", s ) == 1 )
-    {
-        Utl_toLower( s );
-        strcpy( arg, Utl_restOfLn( line, 1 ) );
-        n = sizeof( commands ) / sizeof( commands[ 0 ] );
-        for ( i = 0, c = commands; i < n; ++i, ++c )
-            if ( strcmp( c->name, s ) == 0 )
-            {
-                ret = c->cmdProc( Utl_stripWhiteSpace( arg ), c );
-                fflush( stdout );
-                Log_dbg( "[S FLUSH]" );
-                return ret;
-            }
-    }
-    putStat( STAT_NO_SUCH_CMD, "Command not recognized" );
-    fflush( stdout );
-    Log_dbg( "[S FLUSH]" );
-    return TRUE;
-}
-
-static void
-putWelcome( void )
-{
-    putStat( STAT_READY_POST_ALLOW, "NNTP server NOFFLE %s",
-             Cfg_version() );
-    fflush( stdout );
-    Log_dbg( "[S FLUSH]" );
-}
-
-static Bool
-initServ( void )
-{
-    ASSERT( ! serv.running );
-    if ( ! Lock_openDatabases() )
-      return FALSE;
-    serv.running = TRUE;
-    return TRUE;
-}
-
-static void
-closeServ( void )
-{
-    ASSERT( serv.running );
-    serv.running = FALSE;
-    Lock_closeDatabases();
-}
-
-void
-Serv_run( void )
-{
-    Bool done;
-    int r;
-    Str line;
-    struct timeval timeOut;
-    fd_set readSet;
-
-    putWelcome();
-    done = FALSE;
-    while ( ! done )
-    {
-        FD_ZERO( &readSet );
-        FD_SET( STDIN_FILENO, &readSet );
-        /* Never hold lock more than 5 seconds (empirically good value,
-           avoids to close/open databases, if clients sends several
-           commands, but releases the lock often enough, for allowing
-           multiple persons to read news at the same time) */
-        timeOut.tv_sec = 5;
-        timeOut.tv_usec = 0;
-        r = select( STDIN_FILENO + 1, &readSet, NULL, NULL, &timeOut );
-        if ( r < 0 )
-            done = TRUE;
-        else if ( r == 0 )
-        {
-            if ( serv.running )
-                closeServ();
-        }
-        else /* ( r > 0 ) */
-        {
-            if ( ! serv.running )
-            {
-                if ( ! initServ() )
-                {
-                    putFatal( "Cannot init server" );
-                    done = TRUE;
-                }
-            }
-            if ( ! getLn( line ) )
-            {
-                Log_inf( "Client disconnected. Terminating." );
-                done = TRUE;
-            }
-            else if ( ! parseAndExecute( line ) )
-                done = TRUE;
-        }
-    }
-    if ( serv.running )
-        closeServ();
-}
--- a/server.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*
-  server.h
-
-  Be NNTP server on stdin/stdout.
-
-  $Id: server.h 3 2000-01-04 11:35:42Z enz $
-*/
-
-#ifndef SERV_H
-#define SERV_H
-
-void Serv_run( void );
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Makefile.am	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,36 @@
+# This Makefile.am is used by automake to generate the Makefile.in,
+# which in turn will be used to generate the Makefile.
+
+bin_PROGRAMS = noffle
+
+noffle_SOURCES = \
+client.c client.h \
+common.h \
+configfile.c configfile.h \
+content.c content.h \
+control.c control.h \
+database.c database.h \
+dynamicstring.c dynamicstring.h \
+fetch.c fetch.h \
+fetchlist.c fetchlist.h \
+group.c group.h \
+itemlist.c itemlist.h \
+lock.c lock.h \
+log.c log.h \
+noffle.c \
+online.c online.h \
+outgoing.c outgoing.h \
+over.c over.h \
+post.c post.h \
+protocol.c protocol.h \
+pseudo.c pseudo.h \
+request.c request.h \
+server.c server.h \
+util.c util.h \
+wildmat.c wildmat.h
+
+noffle_LDADD = -lgdbm
+
+tags:
+	etags $(noffle_SOURCES)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Makefile.in	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,326 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This Makefile.am is used by automake to generate the Makefile.in,
+# which in turn will be used to generate the Makefile.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CONFIGFILE = @CONFIGFILE@
+DOCDIR = @DOCDIR@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+SPOOLDIR = @SPOOLDIR@
+VERSION = @VERSION@
+
+bin_PROGRAMS = noffle
+
+noffle_SOURCES =  client.c client.h common.h configfile.c configfile.h content.c content.h control.c control.h database.c database.h dynamicstring.c dynamicstring.h fetch.c fetch.h fetchlist.c fetchlist.h group.c group.h itemlist.c itemlist.h lock.c lock.h log.c log.h noffle.c online.c online.h outgoing.c outgoing.h over.c over.h post.c post.h protocol.c protocol.h pseudo.c pseudo.h request.c request.h server.c server.h util.c util.h wildmat.c wildmat.h
+
+
+noffle_LDADD = -lgdbm
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+noffle_OBJECTS =  client.o configfile.o content.o control.o database.o \
+dynamicstring.o fetch.o fetchlist.o group.o itemlist.o lock.o log.o \
+noffle.o online.o outgoing.o over.o post.o protocol.o pseudo.o \
+request.o server.o util.o wildmat.o
+noffle_DEPENDENCIES = 
+noffle_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES =  .deps/client.P .deps/configfile.P .deps/content.P \
+.deps/control.P .deps/database.P .deps/dynamicstring.P .deps/fetch.P \
+.deps/fetchlist.P .deps/group.P .deps/itemlist.P .deps/lock.P \
+.deps/log.P .deps/noffle.P .deps/online.P .deps/outgoing.P .deps/over.P \
+.deps/post.P .deps/protocol.P .deps/pseudo.P .deps/request.P \
+.deps/server.P .deps/util.P .deps/wildmat.P
+SOURCES = $(noffle_SOURCES)
+OBJECTS = $(noffle_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo "  $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+	     $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	done
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+noffle: $(noffle_OBJECTS) $(noffle_DEPENDENCIES)
+	@rm -f noffle
+	$(LINK) $(noffle_LDFLAGS) $(noffle_OBJECTS) $(noffle_LDADD) $(LIBS)
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+	here=`cd $(top_builddir) && pwd`; \
+	top_distdir=`cd $(top_distdir) && pwd`; \
+	distdir=`cd $(distdir) && pwd`; \
+	cd $(top_srcdir) \
+	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+	-rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+	@echo '$(COMPILE) -c $<'; \
+	$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm .deps/$(*F).pp
+
+%.lo: %.c
+	@echo '$(LTCOMPILE) -c $<'; \
+	$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+	  < .deps/$(*F).pp > .deps/$(*F).P; \
+	tr ' ' '\012' < .deps/$(*F).pp \
+	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+	    >> .deps/$(*F).P; \
+	rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
+		mostlyclean-tags mostlyclean-depend mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-binPROGRAMS clean-compile clean-tags clean-depend \
+		clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-binPROGRAMS distclean-compile distclean-tags \
+		distclean-depend distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-binPROGRAMS \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-depend maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+tags:
+	etags $(noffle_SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/client.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,888 @@
+/*
+  client.c
+
+  $Id: client.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "client.h"
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include "configfile.h"
+#include "content.h"
+#include "dynamicstring.h"
+#include "group.h"
+#include "log.h"
+#include "over.h"
+#include "protocol.h"
+#include "pseudo.h"
+#include "request.h"
+#include "util.h"
+#include "wildmat.h"
+
+/*
+  Some newsgroups names are reserved for server-specific or server
+  pseudo groups. We don't want to fetch them. For example, INN
+  keeps all its control messages in a 'control' hierarchy, and
+  used the "to." heirarchy for dark and mysterious purposes I think
+  are to do with newsfeeds. The recommended restrictions are documented
+  in C.Lindsay, "News Article Format", <draft-ietf-usefor-article-03.txt>.
+*/
+
+struct ForbiddenGroupName
+{
+    const char *pattern;
+    Bool match;
+} forbiddenGroupNames[] =
+{
+    { "*.*", FALSE },			/* Single component */
+    { "control.*", TRUE },		/* control.* groups */
+    { "to.*", TRUE },			/* control.* groups */
+    { "*.all", TRUE },			/* 'all' as a component */
+    { "*.all.*", TRUE },
+    { "all.*", TRUE },
+    { "*.ctl", TRUE },			/* 'ctl' as a component */
+    { "*.ctl.*", TRUE },
+    { "ctl.*", TRUE }
+};
+
+struct
+{
+    FILE* in;     /* Receiving socket from server */
+    FILE* out;    /* Sending socket to server */
+    Str lastCmd;  /* Last command line */
+    Str lastStat; /* Response from server to last command */
+    Str grp;      /* Selected group */
+    int rmtFirst;  /* First article of current group at server */
+    int rmtLast;   /* Last article of current group at server */
+    Bool auth;    /* Authetication already done? */
+    Str serv;     /* Remote server name */
+} client = { NULL, NULL, "", "", "", 1, 0, FALSE, "" };
+
+static void
+logBreakDown( void )
+{
+    Log_err( "Connection to remote server lost "
+             "(article numbers could be inconsistent)" );
+}
+
+static Bool
+getLn( Str line )
+{
+    Bool r;
+
+    r = Prt_getLn( line, client.in );
+    if ( ! r )
+        logBreakDown();
+    return r; 
+}
+
+static Bool
+getTxtLn( Str line, Bool *err )
+{
+    Bool r;
+
+    r = Prt_getTxtLn( line, err, client.in );
+    if ( *err )
+        logBreakDown();
+    return r; 
+}
+
+static void
+putTxtBuf( const char *buf )
+{
+    Prt_putTxtBuf( buf, client.out );
+    fflush( client.out );
+    Log_dbg( "[S FLUSH]" );
+}
+
+static void
+putEndOfTxt( void )
+{
+    Prt_putEndOfTxt( client.out );
+    fflush( client.out );
+    Log_dbg( "[S FLUSH]" );
+}
+
+static Bool
+putCmd( const char *fmt, ... )
+{
+    Bool err;
+    unsigned int n;
+    Str line;
+    va_list ap;
+
+    va_start( ap, fmt );
+    vsnprintf( line, MAXCHAR, fmt, ap );
+    va_end( ap );
+    strcpy( client.lastCmd, line );
+    Log_dbg( "[S] %s", line );
+    n = fprintf( client.out, "%s\r\n", line );
+    fflush( client.out );
+    Log_dbg( "[S FLUSH]" );
+    err = ( n != strlen( line ) + 2 );
+    if ( err )
+        logBreakDown();;
+    return ! err;
+}
+
+static Bool
+putCmdNoFlush( const char *fmt, ... )
+{
+    Bool err;
+    unsigned int n;
+    Str line;
+    va_list ap;
+
+    va_start( ap, fmt );
+    vsnprintf( line, MAXCHAR, fmt, ap );
+    va_end( ap );
+    strcpy( client.lastCmd, line );
+    Log_dbg( "[S] %s", line );
+    n = fprintf( client.out, "%s\r\n", line );
+    err = ( n != strlen( line ) + 2 );
+    if ( err )
+        logBreakDown();;
+    return ! err;
+}
+
+static int getStat( void );
+
+static Bool
+performAuth( void )
+{
+    int stat;
+    Str user, pass;
+    
+    Cfg_authInfo( client.serv, user, pass );
+    if ( strcmp( user, "" ) == 0 )
+    {
+        Log_err( "No username for authentication set" );
+        return FALSE;
+    }    
+    putCmd( "AUTHINFO USER %s", user );
+    stat = getStat();
+    if ( stat == STAT_AUTH_ACCEPTED )
+        return TRUE;
+    else if ( stat != STAT_MORE_AUTH_REQUIRED )
+    {
+        Log_err( "Username rejected. Server stat: %s", client.lastStat );
+        return FALSE;
+    }    
+    if ( strcmp( pass, "" ) == 0 )
+    {
+        Log_err( "No password for authentication set" );
+        return FALSE;
+    }
+    putCmd( "AUTHINFO PASS %s", pass );
+    stat = getStat();
+    if ( stat != STAT_AUTH_ACCEPTED )
+    {
+        Log_err( "Password rejected. Server status: %s", client.lastStat );
+        return FALSE;
+    }    
+    return TRUE;    
+}
+
+static int
+getStat( void )
+{
+    int result;
+    Str lastCmd;
+
+    if ( ! getLn( client.lastStat ) )
+        result = STAT_PROGRAM_FAULT;
+    else if ( sscanf( client.lastStat, "%d", &result ) != 1 )
+    {
+        Log_err( "Invalid server status: %s", client.lastStat );
+        result = STAT_PROGRAM_FAULT;
+    }
+    if ( result == STAT_AUTH_REQUIRED && ! client.auth )
+    {
+        client.auth = TRUE;
+        strcpy( lastCmd, client.lastCmd );
+        if ( performAuth() )
+        {
+            putCmd( lastCmd );
+            return getStat();
+        }
+    }
+    return result;
+}
+
+static void
+connectAlarm( int sig )
+{
+    return;
+}
+
+static sig_t
+installSignalHandler( int sig, sig_t handler )
+{
+    struct sigaction act, oldAct;
+
+    act.sa_handler = handler;
+    sigemptyset( &act.sa_mask );
+    act.sa_flags = 0;
+    if ( sig == SIGALRM )
+        act.sa_flags |= SA_INTERRUPT;
+    else
+        act.sa_flags |= SA_RESTART;
+    if ( sigaction( sig, &act, &oldAct ) < 0 )
+        return SIG_ERR;
+    return oldAct.sa_handler;
+}
+
+static Bool
+connectWithTimeout( int sock, const struct sockaddr *servAddr,
+                    socklen_t addrLen )
+{
+    sig_t oldHandler;
+    int r, to;
+
+    oldHandler = installSignalHandler( SIGALRM, connectAlarm );
+    if ( oldHandler == SIG_ERR )
+    {
+        Log_err( "client.c:connectWithTimeout: signal failed." );
+        return FALSE;
+    }
+    to = Cfg_connectTimeout();
+    if ( alarm( to ) != 0 )
+        Log_err( "client.c:connectWithTimeout: Alarm was already set." );
+    r = connect( sock, servAddr, addrLen );
+    alarm( 0 );
+    installSignalHandler( SIGALRM, oldHandler );
+    return ( r >= 0 );
+}
+
+Bool
+Client_connect( const char *serv )
+{
+    unsigned short int port;
+    int sock, i;
+    unsigned int stat;
+    struct hostent *hp;
+    char *pStart, *pColon;
+    Str host, s;
+    struct sockaddr_in sIn;
+
+    client.auth = FALSE;
+    Utl_cpyStr( s, serv );
+    pStart = Utl_stripWhiteSpace( s );
+    pColon = strstr( pStart, ":" );
+    if ( pColon == NULL )
+    {
+        strcpy( host, pStart );
+        port = 119;
+    }
+    else
+    {
+        *pColon = '\0';
+        strcpy( host, pStart );
+        if ( sscanf( pColon + 1, "%hi", &port ) != 1 )
+        {
+            Log_err( "Syntax error in server name: '%s'", serv );
+            return FALSE;;
+        }
+        if ( port <= 0 || port > 65535 )
+        {
+            Log_err( "Invalid port number %hi. Must be in [1, 65535]", port );
+            return FALSE;;
+        }
+    }
+    memset( (void *)&sIn, 0, sizeof( sIn ) );
+    hp = gethostbyname( host );
+    if ( hp )
+    {
+        for ( i = 0; (hp->h_addr_list)[ i ]; ++i )
+        {
+            sIn.sin_family = hp->h_addrtype;
+            sIn.sin_port = htons( port );
+            sIn.sin_addr = *( (struct in_addr *)hp->h_addr_list[ i ] );
+            sock = socket( AF_INET, SOCK_STREAM, 0 );
+            if ( sock < 0 )
+                break;
+            if ( ! connectWithTimeout( sock, (struct sockaddr *)&sIn,
+                                       sizeof( sIn ) ) )
+            {
+                close( sock );
+                break;
+            }
+            if ( ! ( client.out = fdopen( sock, "w" ) )
+                 || ! ( client.in  = fdopen( dup( sock ), "r" ) ) )
+            {
+		if ( client.out != NULL )
+		    fclose( client.out );
+                close( sock );
+                break;
+            }
+            stat = getStat();
+	    if ( stat == STAT_READY_POST_ALLOW ||
+		 stat == STAT_READY_NO_POST_ALLOW )
+	    {
+		/* INN needs a MODE READER before it will permit POST. */
+		putCmd( "MODE READER" );
+		stat = getStat();
+	    }
+            switch( stat ) {
+            case STAT_READY_POST_ALLOW:
+            case STAT_READY_NO_POST_ALLOW: 
+                Log_inf( "Connected to %s:%d",
+                         inet_ntoa( sIn.sin_addr ), port );
+                Utl_cpyStr( client.serv, serv );
+                return TRUE;
+            default:
+                Log_err( "Bad server stat %d", stat ); 
+            }
+            shutdown( fileno( client.out ), 0 );
+	    fclose( client.in );
+	    fclose( client.out );
+	    close( sock );
+        }
+    }
+    return FALSE;
+}
+
+static Bool
+isForbiddenGroupName( const char *name )
+{
+    int i;
+
+    for ( i = 0;
+	  i < sizeof( forbiddenGroupNames ) /
+	      sizeof( struct ForbiddenGroupName );
+	  i++ )
+    {
+	/* Negate result of Wld_match to ensure it is 1 or 0. */
+	if ( forbiddenGroupNames[i].match !=
+	     ( ! Wld_match( name, forbiddenGroupNames[i].pattern ) ) )
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void
+processGrps( void )
+{
+    char postAllow;
+    Bool err;
+    int first, last;
+    Str grp, line, file;
+    
+    while ( getTxtLn( line, &err ) && ! err )
+    {
+        if ( sscanf( line, "%s %d %d %c",
+                     grp, &last, &first, &postAllow ) != 4 )
+        {
+            Log_err( "Unknown reply to LIST or NEWGROUPS: %s", line );
+            continue;
+        }
+	if ( isForbiddenGroupName( grp ) )
+	{
+	    Log_inf( "Group %s forbidden", grp );
+	    continue;
+	}
+        if ( ! Grp_exists( grp ) )
+        {
+            Log_inf( "Registering new group '%s'", grp );
+            Grp_create( grp );
+            Grp_setRmtNext( grp, first );
+            Grp_setServ( grp, client.serv );
+	    Grp_setPostAllow( grp, postAllow );
+        }
+        else
+        {
+            if ( Cfg_servIsPreferential( client.serv, Grp_serv( grp ) ) )
+            {
+                Log_inf( "Changing server for '%s': '%s'->'%s'",
+                         grp, Grp_serv( grp ), client.serv );
+                Grp_setServ( grp, client.serv );
+                Grp_setRmtNext( grp, first );
+		Grp_setPostAllow( grp, postAllow );
+            }
+            else
+                Log_dbg( "Group %s is already fetched from %s",
+                           grp, Grp_serv( grp ) );
+            
+        }
+    }
+    if ( ! err )
+    {
+        snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
+        Utl_stamp( file );
+    }
+}
+
+void
+Client_disconnect( void )
+{
+    if ( putCmd( "QUIT" ) )
+        getStat();
+    fclose( client.in );
+    fclose( client.out );
+    client.in = client.out = NULL;
+}
+
+Bool
+Client_getGrps( void )
+{
+    if ( ! putCmd( "LIST ACTIVE" ) )
+        return FALSE;
+    if ( getStat() != STAT_GRPS_FOLLOW )
+    {
+        Log_err( "LIST ACTIVE command failed: %s", client.lastStat );
+        return FALSE;
+    }
+    processGrps();
+    return TRUE;
+}
+
+Bool
+Client_getDsc( void )
+{
+    Bool err;
+    Str name, line, dsc;
+
+    Log_inf( "Querying group descriptions" );
+    if ( ! putCmd( "LIST NEWSGROUPS" ) )
+        return FALSE;
+    if ( getStat() != STAT_GRPS_FOLLOW )
+    {
+        Log_err( "LIST NEWSGROUPS failed: %s", client.lastStat );
+        return FALSE;
+    }
+    while ( getTxtLn( line, &err ) && ! err )
+    {
+        if ( sscanf( line, "%s", name ) != 1 )
+        {
+            Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line );
+            continue;
+        }
+        strcpy( dsc, Utl_restOfLn( line, 1 ) );
+        if ( Grp_exists( name ) )
+        {
+            Log_dbg( "Description of %s: %s", name, dsc );
+            Grp_setDsc( name, dsc );
+        }
+    }
+    return TRUE;
+}
+
+Bool
+Client_getCreationTimes( void )
+{
+    Bool err;
+    Str name, line;
+    time_t t;
+
+    Log_inf( "Querying group creation times" );
+    if ( ! putCmd( "LIST ACTIVE.TIMES" ) )
+        return FALSE;
+    if ( getStat() != STAT_GRPS_FOLLOW )
+    {
+        Log_err( "LIST ACTIVE.TIMES failes: %s", client.lastStat );
+        return FALSE;
+    }
+    while ( getTxtLn( line, &err ) && ! err )
+    {
+        if ( sscanf( line, "%s %ld", name, &t ) != 2 )
+        {
+            Log_err( "Unknown reply to LIST ACTIVE.TIMES: %s", line );
+            continue;
+        }
+        if ( Grp_exists( name ) )
+        {
+            Log_inf( "Creation time of %s: %ld", name, t );
+            Grp_setCreated( name, t );
+        }
+    }
+    return TRUE;
+}
+
+Bool
+Client_getNewgrps( const time_t *lastTime )
+{
+    Str s;
+    const char *p;
+
+    ASSERT( *lastTime > 0 );
+    strftime( s, MAXCHAR, "%Y%m%d %H%M00", gmtime( lastTime ) );
+    /*
+      Do not use century for working with old server software until 2000.
+      According to newest IETF draft, this is still valid after 2000.
+      (directly using %y in fmt string causes a Y2K compiler warning)
+    */
+    p = s + 2;
+    if ( ! putCmd( "NEWGROUPS %s", p ) )
+        return FALSE;
+    if ( getStat() != STAT_NEW_GRP_FOLLOW )
+    {
+        Log_err( "NEWGROUPS command failed: %s", client.lastStat );
+        return FALSE;
+    }
+    processGrps();
+    return TRUE;
+}
+
+static const char *
+readField( Str result, const char *p )
+{
+    size_t len;
+    char *r;
+
+    if ( ! p )
+        return NULL;
+    r = result;
+    *r = '\0';
+    len = 0;
+    while ( *p != '\t' && *p != '\n' )
+    {
+        if ( ! *p )
+            return p;
+        *(r++) = *(p++);
+        ++len;
+        if ( len >= MAXCHAR - 1 )
+        {
+            *r = '\0';
+            Log_err( "Field in overview too long: %s", r );
+            return ++p;
+        }
+    }
+    *r = '\0';
+    return ++p;
+}
+
+static Bool
+parseOvLn( Str line, int *numb, Str subj, Str from,
+           Str date, Str msgId, Str ref, size_t *bytes, size_t *lines )
+{
+    const char *p;
+    Str t;
+    
+    p = readField( t, line );
+    if ( sscanf( t, "%d", numb ) != 1 )
+        return FALSE;
+    p = readField( subj, p );
+    p = readField( from, p );
+    p = readField( date, p );
+    p = readField( msgId, p );
+    p = readField( ref, p );
+    p = readField( t, p );
+    *bytes = 0;
+    *lines = 0;
+    if ( sscanf( t, "%d", bytes ) != 1 )
+        return TRUE;
+    p = readField( t, p );
+    if ( sscanf( t, "%d", lines ) != 1 )
+        return TRUE;
+    return TRUE;
+}
+
+static const char*
+nextXref( const char *pXref, Str grp, int *numb )
+{
+    Str s;
+    const char *pColon, *src;
+    char *dst;
+
+    src = pXref;
+    while ( *src && isspace( *src ) )
+        ++src;
+    dst = s;
+    while ( *src && ! isspace( *src ) )
+        *(dst++) = *(src++);
+    *dst = '\0';
+    if ( strlen( s ) == 0 )
+        return NULL;
+    pColon = strstr( s, ":" );
+    if ( ! pColon || sscanf( pColon + 1, "%d", numb ) != 1 )
+    {
+        Log_err( "Corrupt Xref at position '%s'", pXref );
+        return NULL;
+    }
+    Utl_cpyStrN( grp, s, pColon - s );
+    Log_dbg( "client.c: nextXref: grp '%s' numb %lu", grp, numb );
+    return src;
+}
+
+static Bool
+needsMark( const char *ref )
+{
+    Bool done = FALSE;
+    char *p;
+    Str msgId;
+    int stat, len;
+    time_t lastAccess, nowTime;
+    double limit;
+
+    nowTime = time( NULL );
+    limit = Cfg_threadFollowTime() * 24. * 3600.;
+    while ( ! done )
+    {
+        p = msgId;
+        while ( *ref != '<' )
+            if ( *(ref++) == '\0' )
+                return FALSE;
+        len = 0;
+        while ( *ref != '>' )
+        {
+            if ( *ref == '\0' || ++len >= MAXCHAR - 1 )
+                return FALSE;
+            *(p++) = *(ref++);
+        }
+        *(p++) = '>';
+        *p = '\0';
+        if ( Db_contains( msgId ) )
+        {
+            stat = Db_stat( msgId );
+            lastAccess = Db_lastAccess( msgId );
+            if ( ( stat & DB_INTERESTING )
+                 && difftime( nowTime, lastAccess ) <= limit )
+                return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+prepareEntry( Over *ov )
+{
+    Str g, t;
+    const char *msgId, *p, *xref;
+    int n;
+
+    msgId = Ov_msgId( ov );
+    if ( Pseudo_isGeneralInfo( msgId ) )
+        Log_dbg( "Skipping general info '%s'", msgId );
+    else if ( Db_contains( msgId ) )
+    {
+        xref = Db_xref( msgId );
+        Log_dbg( "Entry '%s' already in db with Xref '%s'", msgId, xref );
+        p = nextXref( xref, g, &n );
+        if ( p == NULL )
+            Log_err( "Overview with no group in Xref '%s'", msgId );
+        else
+        {
+            /* TODO: This code block seems unnessesary. Can we remove it? */
+            if ( Cfg_servIsPreferential( client.serv, Grp_serv( g ) ) )
+            {
+                Log_dbg( "Changing first server for '%s' from '%s' to '%s'",
+                         msgId, Grp_serv( g ), client.serv );
+                snprintf( t, MAXCHAR, "%s:%d %s",
+                          client.grp, Ov_numb( ov ), xref );
+                Db_setXref( msgId, t );
+            }
+            else
+            {
+                Log_dbg( "Adding '%s' to Xref of '%s'", g, msgId );
+                snprintf( t, MAXCHAR, "%s %s:%d",
+                          xref, client.grp, Ov_numb( ov ) );
+                Db_setXref( msgId, t );
+            }
+        }
+    }
+    else
+    {
+        Log_dbg( "Preparing '%s' in database", msgId );
+        Db_prepareEntry( ov, client.grp, Ov_numb( ov ) );
+    }
+}
+
+Bool
+Client_getOver( int rmtFirst, int rmtLast, FetchMode mode )
+{
+    Bool err;
+    size_t bytes, lines;
+    int rmtNumb, oldLast, cntMarked;
+    Over *ov;
+    Str line, subj, from, date, msgId, ref;
+
+    ASSERT( strcmp( client.grp, "" ) != 0 );
+    if ( ! putCmd( "XOVER %lu-%lu", rmtFirst, rmtLast ) )
+        return FALSE;
+    if ( getStat() != STAT_OVERS_FOLLOW )
+    {
+        Log_err( "XOVER command failed: %s", client.lastStat );
+        return FALSE;
+    }
+    Log_dbg( "Requesting overview for remote %lu-%lu", rmtFirst, rmtLast );
+    oldLast = Cont_last();
+    cntMarked = 0;
+    while ( getTxtLn( line, &err ) && ! err )
+    {
+        if ( ! parseOvLn( line, &rmtNumb, subj, from, date, msgId, ref,
+                          &bytes, &lines ) )
+            Log_err( "Bad overview line: %s", line );
+        else
+        {
+            ov = new_Over( subj, from, date, msgId, ref, bytes, lines );
+            Cont_app( ov );
+            prepareEntry( ov );
+            if ( mode == FULL || ( mode == THREAD && needsMark( ref ) ) )
+            {
+                Req_add( client.serv, msgId );
+                ++cntMarked;
+            }
+        }
+        Grp_setRmtNext( client.grp, rmtNumb + 1 );
+    }
+    if ( oldLast != Cont_last() )
+        Log_inf( "Added %s %lu-%lu", client.grp, oldLast + 1, Cont_last() );
+    Log_inf( "%u articles marked for download in %s", cntMarked, client.grp  );
+    return err;
+}
+
+static void
+retrievingFailed( const char* msgId, const char *reason )
+{
+    int stat;
+
+    Log_err( "Retrieving of %s failed: %s", msgId, reason );
+    stat = Db_stat( msgId );
+    Pseudo_retrievingFailed( msgId, reason );
+    Db_setStat( msgId, stat | DB_RETRIEVING_FAILED );
+}
+
+static Bool
+retrieveAndStoreArt( const char *msgId )
+{
+    Bool err;
+    DynStr *s = NULL;
+    Str line;
+
+    Log_inf( "Retrieving %s", msgId );
+    s = new_DynStr( 5000 );
+    while ( getTxtLn( line, &err ) && ! err )
+        DynStr_appLn( s, line );
+    if ( ! err )
+        Db_storeArt( msgId, DynStr_str( s ) );
+    else
+        retrievingFailed( msgId, "Connection broke down" );
+    del_DynStr( s );
+    return ! err;
+}
+
+void
+Client_retrieveArt( const char *msgId )
+{
+    if ( ! Db_contains( msgId ) )
+    {
+        Log_err( "Article '%s' not prepared in database. Skipping.", msgId );
+        return;
+    }
+    if ( ! ( Db_stat( msgId ) & DB_NOT_DOWNLOADED ) )
+    {
+        Log_inf( "Article '%s' already retrieved. Skipping.", msgId );
+        return;
+    }
+    if ( ! putCmd( "ARTICLE %s", msgId ) )
+        retrievingFailed( msgId, "Connection broke down" );
+    else if ( getStat() != STAT_ART_FOLLOWS )
+        retrievingFailed( msgId, client.lastStat );
+    else
+        retrieveAndStoreArt( msgId );
+}
+
+void
+Client_retrieveArtList( const char *list )
+{
+    Str msgId;
+    DynStr *s;
+    const char *p;
+    
+    Log_inf( "Retrieving article list" );
+    s = new_DynStr( strlen( list ) );
+    p = list;
+    while ( ( p = Utl_getLn( msgId, p ) ) )
+        if ( ! Db_contains( msgId ) )
+            Log_err( "Skipping retrieving of %s (not prepared in database)",
+                     msgId );
+        else if ( ! ( Db_stat( msgId ) & DB_NOT_DOWNLOADED ) )
+            Log_inf( "Skipping %s (already retrieved)", msgId );
+        else if ( ! putCmdNoFlush( "ARTICLE %s", msgId ) )
+        {
+            retrievingFailed( msgId, "Connection broke down" );
+            del_DynStr( s );
+            return;
+        }
+        else
+            DynStr_appLn( s, msgId );
+    fflush( client.out );
+    Log_dbg( "[S FLUSH]" );
+    p = DynStr_str( s );
+    while ( ( p = Utl_getLn( msgId, p ) ) )
+    {
+        if ( getStat() != STAT_ART_FOLLOWS )
+            retrievingFailed( msgId, client.lastStat );
+        else if ( ! retrieveAndStoreArt( msgId ) )
+            break;
+    }
+    del_DynStr( s );
+}
+
+Bool
+Client_changeToGrp( const char* name )
+{
+    unsigned int stat;
+    int estimatedNumb, first, last;
+
+    if ( ! Grp_exists( name ) )
+        return FALSE;
+    if ( ! putCmd( "GROUP %s", name ) )
+        return FALSE;
+    if ( getStat() != STAT_GRP_SELECTED )
+        return FALSE;
+    if ( sscanf( client.lastStat, "%u %d %d %d",
+                 &stat, &estimatedNumb, &first, &last ) != 4 )
+    {
+        Log_err( "Bad server response to GROUP: %s", client.lastStat );
+        return FALSE;
+    }
+    Utl_cpyStr( client.grp, name );
+    client.rmtFirst = first;
+    client.rmtLast = last;
+    return TRUE;
+}
+
+void
+Client_rmtFirstLast( int *first, int *last )
+{
+    *first = client.rmtFirst;
+    *last = client.rmtLast;
+}
+
+Bool
+Client_postArt( const char *msgId, const char *artTxt,
+                    Str errStr )
+{
+    if ( ! putCmd( "POST" ) )
+        return FALSE;
+    if ( getStat() != STAT_SEND_ART )
+    {
+        Log_err( "Posting of %s not allowed: %s", msgId, client.lastStat );
+        strcpy( errStr, client.lastStat );
+        return FALSE;
+    }
+    putTxtBuf( artTxt );
+    putEndOfTxt();
+    if ( getStat() != STAT_POST_OK )
+    {
+        Log_err( "Posting of %s failed: %s", msgId, client.lastStat );
+        strcpy( errStr, client.lastStat );
+        return FALSE;
+    }
+    Log_inf( "Posted %s (Status: %s)", msgId, client.lastStat );
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/client.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,74 @@
+/*
+  client.h
+
+  Noffle acting as client to other NNTP-servers
+
+  $Id: client.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <time.h>
+#include "common.h"
+#include "database.h"
+#include "fetchlist.h"
+
+/* Format of server name: <host>[:<port>] */
+Bool
+Client_connect( const char *serv );
+
+void
+Client_disconnect( void );
+
+Bool
+Client_getGrps( void );
+
+Bool
+Client_getDsc( void );
+
+Bool
+Client_getCreationTimes( void );
+
+Bool
+Client_getNewgrps( const time_t *lastTime );
+
+/*
+  Change to group <name> at server if it is also in current local grouplist.
+  Returns TRUE at success.
+*/
+Bool
+Client_changeToGrp( const Str name );
+
+/*
+  Get overviews <rmtFirst> - <rmtLast> from server and append it
+  to the current content. For articles that are to be fetched due to FULL
+  or THREAD mode, store IDs in request database.
+*/
+Bool
+Client_getOver( int rmtFirst, int rmtLast, FetchMode mode );
+
+/*
+  Retrieve full article text and store it into database.
+*/
+void
+Client_retrieveArt( const char *msgId );
+
+/*
+  Same, but for a list of msgId's (new line after each msgId).
+  All ARTICLE commands are sent and then all answers read.
+*/
+void
+Client_retrieveArtList( const char *list );
+
+/*
+  Store IDs of first and last article of group selected by
+  Client_changeToGroup at remote server. 
+*/
+void
+Client_rmtFirstLast( int *first, int *last );
+
+Bool
+Client_postArt( const char *msgId, const char *artTxt, Str errStr );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,33 @@
+/*
+  common.h
+
+  Common declarations.
+
+  $Id: common.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FALSE 0
+#define TRUE !0
+#define MAXCHAR 2048
+
+#ifdef DEBUG
+#include <assert.h>
+#define ASSERT( x ) \
+    if ( ! ( x ) ) \
+        Log_err( "ASSERTION FAILED: %s line %i", __FILE__, __LINE__ ); \
+    assert( x )
+#else
+#define ASSERT( x )
+#endif
+
+typedef int Bool;
+typedef char Str[ MAXCHAR ];
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/configfile.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,400 @@
+/*
+  configfile.c
+
+  The following macros must be set, when compiling this file:
+    CONFIGFILE
+    SPOOLDIR
+    VERSION
+
+  $Id: configfile.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "configfile.h"
+
+#include <limits.h>
+#include "log.h"
+#include "util.h"
+
+typedef struct
+{
+    Str name;
+    Str user;
+    Str pass;
+}
+ServEntry;
+
+typedef struct
+{
+    Str pattern;
+    int days;
+}
+ExpireEntry;
+
+struct
+{
+    /* Compile time options */
+    const char *spoolDir;
+    const char *version;
+    /* Options from the config file */
+    int maxFetch;
+    int autoUnsubscribeDays;
+    int threadFollowTime;
+    int connectTimeout;
+    Bool autoSubscribe;
+    Bool autoUnsubscribe;
+    Bool removeMsgId;
+    Bool replaceMsgId;
+    Str autoSubscribeMode;
+    Str mailTo;
+    int defaultExpire;
+    int numServ;
+    int maxServ;
+    ServEntry *serv;
+    int servIdx; /* for server enumeration */
+    int numExpire;
+    int maxExpire;
+    ExpireEntry *expire;
+    int expireIdx;
+} config =
+{
+    SPOOLDIR, /* spoolDir */
+    VERSION,  /* version */
+    300,      /* maxFetch */
+    30,       /* autoUnsubscribeDays */
+    7,        /* threadFollowTime */
+    30,       /* connectTimeout */
+    FALSE,    /* autoSubscribe */
+    FALSE,    /* autoUnsubscribe */
+    FALSE,    /* removeMsgId */
+    TRUE,     /* replaceMsgId */
+    "over",   /* autoSubscribeMode */
+    "",       /* mailTo */
+    14,       /* defaultExpire */
+    0,        /* numServ */
+    0,        /* maxServ */
+    NULL,     /* serv */
+    0,	      /* servIdx */
+    0,        /* numExpire */
+    0,        /* maxExpire */
+    NULL,     /* expire */
+    0         /* expireIdx */
+};
+
+const char * Cfg_spoolDir( void ) { return config.spoolDir; }
+const char * Cfg_version( void ) { return config.version; }
+
+int Cfg_maxFetch( void ) { return config.maxFetch; }
+int Cfg_autoUnsubscribeDays( void ) { return config.autoUnsubscribeDays; }
+int Cfg_threadFollowTime( void ) { return config.threadFollowTime; }
+int Cfg_connectTimeout( void ) { return config.connectTimeout; }
+Bool Cfg_autoUnsubscribe( void ) { return config.autoUnsubscribe; }
+Bool Cfg_autoSubscribe( void )  { return config.autoSubscribe; }
+Bool Cfg_removeMsgId( void ) { return config.removeMsgId; }
+Bool Cfg_replaceMsgId( void ) { return config.replaceMsgId; }
+const char * Cfg_autoSubscribeMode( void ) {
+    return config.autoSubscribeMode; }
+const char * Cfg_mailTo( void ) { return config.mailTo; }
+int Cfg_expire( void ) { return config.defaultExpire; }
+
+void
+Cfg_beginServEnum( void )
+{
+    config.servIdx = 0;
+}
+
+Bool
+Cfg_nextServ( Str name )
+{
+    if ( config.servIdx >= config.numServ )
+        return FALSE;
+    strcpy( name, config.serv[ config.servIdx ].name );
+    ++config.servIdx;
+    return TRUE;
+}
+
+static Bool
+searchServ( const char *name, int *idx )
+{
+    int i;
+
+    for ( i = 0; i < config.numServ; ++i )
+        if ( strcmp( name, config.serv[ i ].name ) == 0 )
+        {
+            *idx = i;
+            return TRUE;
+        }
+    return FALSE;
+}
+
+Bool
+Cfg_servListContains( const char *name )
+{
+    int idx;
+
+    return searchServ( name, &idx );
+}
+
+Bool
+Cfg_servIsPreferential( const char *name1, const char *name2 )
+{
+    Bool exists1, exists2;
+    int idx1, idx2;
+
+    exists1 = searchServ( name1, &idx1 );
+    exists2 = searchServ( name2, &idx2 );
+    if ( exists1 && exists2 )
+        return ( idx1 < idx2 );
+    if ( exists1 && ! exists2 )
+        return TRUE;
+    /* ( ! exists1 && exists2 ) || ( ! exists1 && ! exists2 ) */
+    return FALSE;
+}
+
+void
+Cfg_authInfo( const char *name, Str user, Str pass )
+{
+    int idx;
+
+    if ( searchServ( name, &idx ) )
+    {
+        strcpy( user, config.serv[ idx ].user );
+        strcpy( pass, config.serv[ idx ].pass );
+    }
+    else
+    {
+        user[ 0 ] = '\0';
+        pass[ 0 ] = '\0';
+    }
+}
+
+void
+Cfg_beginExpireEnum( void )
+{
+    config.expireIdx = 0;
+}
+
+int
+Cfg_nextExpire( Str pattern )
+{
+    if ( config.expireIdx >= config.numExpire )
+        return -1;
+    strcpy( pattern, config.expire[ config.expireIdx ].pattern );
+    return config.expire[ config.expireIdx++ ].days;
+}
+
+static void
+logSyntaxErr( const char *line )
+{
+    Log_err( "Syntax error in config file: %s", line );
+}
+
+static void
+getBool( Bool *variable, const char *line )
+{
+    Str value, name, lowerLn;
+
+    strcpy( lowerLn, line );
+    Utl_toLower( lowerLn );
+    if ( sscanf( lowerLn, "%s %s", name, value ) != 2 )
+    {
+        logSyntaxErr( line );
+        return;
+    }
+    
+    if ( strcmp( value, "yes" ) == 0 )
+        *variable = TRUE;
+    else if ( strcmp( value, "no" ) == 0 )
+        *variable = FALSE;
+    else
+        Log_err( "Error in config file %s must be yes or no", name );
+}
+
+static void
+getInt( int *variable, int min, int max, const char *line )
+{
+    int value;
+    Str name;
+
+    if ( sscanf( line, "%s %d", name, &value ) != 2 )
+    {
+        logSyntaxErr( line );
+        return;
+    }
+    if ( value < min || value > max )
+    {
+        Log_err( "Range error in config file %s [%d,%d]", name, min, max );
+        return;
+    }
+    *variable = value;
+}
+
+static void
+getStr( char *variable, const char *line )
+{
+    Str dummy;
+
+    if ( sscanf( line, "%s %s", dummy, variable ) != 2 )
+    {
+        logSyntaxErr( line );
+        return;
+    }
+}
+
+static void
+getServ( const char *line )
+{
+    Str dummy;
+    int r, len;
+    ServEntry entry;
+
+    entry.user[ 0 ] = '\0';
+    entry.pass[ 0 ] = '\0';
+    r = sscanf( line, "%s %s %s %s",
+                dummy, entry.name, entry.user, entry.pass );
+    if ( r < 2 )
+    {
+        logSyntaxErr( line );
+        return;
+    }
+    len = strlen( entry.name );
+    /* To make server name more definit, it is made lowercase and
+       port is removed, if it is the default port */
+    if ( len > 4 && strcmp( entry.name + len - 4, ":119" ) == 0 )
+        entry.name[ len - 4 ] = '\0';
+    Utl_toLower( entry.name );
+
+    if ( config.maxServ < config.numServ + 1 )
+    {
+        if ( ! ( config.serv = realloc( config.serv,
+                                        ( config.maxServ + 5 )
+                                        * sizeof( ServEntry ) ) ) )
+        {
+            Log_err( "Could not realloc server list" );
+            exit( EXIT_FAILURE );
+        }
+        config.maxServ += 5;
+    }
+    config.serv[ config.numServ++ ] = entry;
+}
+
+static void
+getExpire( const char *line )
+{
+    Str dummy;
+    ExpireEntry entry;
+    int days;
+
+    /*
+      The line is either "expire <num>" or "expire <pat> <num>".
+      The former updates the overall default.
+     */
+    if ( sscanf( line, "%s %s %d", dummy, entry.pattern, &days ) != 3 )
+    {
+	logSyntaxErr( line );
+	return;
+    }
+    else
+    {
+	if ( days < 0 )
+	{
+	    Log_err( "Expire days error in '%s': must be integer > 0",
+		     line, days );
+	    return;
+	}
+
+	Utl_toLower( entry.pattern );
+	entry.days = days;
+
+	if ( config.maxExpire < config.numExpire + 1 )
+	{
+	    if ( ! ( config.expire = realloc( config.expire,
+					      ( config.maxExpire + 5 )
+					      * sizeof( ExpireEntry ) ) ) )
+	    {
+		Log_err( "Could not realloc exipre list" );
+		exit( EXIT_FAILURE );
+	    }
+	    config.maxExpire += 5;
+	}
+	config.expire[ config.numExpire++ ] = entry;
+    }
+}
+
+void
+Cfg_read( void )
+{
+    char *p;
+    FILE *f;
+    Str file, line, lowerLine, name, s;
+
+    snprintf( file, MAXCHAR, CONFIGFILE );
+    if ( ! ( f = fopen( file, "r" ) ) )
+    {
+        Log_err( "Cannot read %s", file );
+        return;
+    }
+    while ( fgets( line, MAXCHAR, f ) )
+    {
+        p = Utl_stripWhiteSpace( line );
+	Utl_stripComment( p );
+        Utl_cpyStr( lowerLine, p );
+        Utl_toLower( lowerLine );
+        if ( *p == '\0' )
+            continue;
+        if ( sscanf( p, "%s", name ) != 1 )
+            Log_err( "Syntax error in %s: %s", file, line );
+        else if ( strcmp( "max-fetch", name ) == 0 )
+            getInt( &config.maxFetch, 0, INT_MAX, p );
+        else if ( strcmp( "auto-unsubscribe-days", name ) == 0 )
+            getInt( &config.autoUnsubscribe, -1, INT_MAX, p );
+        else if ( strcmp( "thread-follow-time", name ) == 0 )
+            getInt( &config.threadFollowTime, 0, INT_MAX, p );
+        else if ( strcmp( "connect-timeout", name ) == 0 )
+            getInt( &config.connectTimeout, 0, INT_MAX, p );
+        else if ( strcmp( "default-expire", name ) == 0 )
+            getInt( &config.defaultExpire, 0, INT_MAX, p );
+        else if ( strcmp( "auto-subscribe", name ) == 0 )
+            getBool( &config.autoSubscribe, p );
+        else if ( strcmp( "auto-unsubscribe", name ) == 0 )
+            getBool( &config.autoUnsubscribe, p );
+        else if ( strcmp( "remove-messageid", name ) == 0 )
+            getBool( &config.removeMsgId, p );
+        else if ( strcmp( "replace-messageid", name ) == 0 )
+            getBool( &config.replaceMsgId, p );
+        else if ( strcmp( "auto-subscribe-mode", name ) == 0 )
+        {
+            getStr( s, p );
+            Utl_toLower( s );
+            if ( strcmp( s, "full" ) != 0
+                 && strcmp( s, "thread" ) != 0
+                 && strcmp( s, "over" ) != 0
+                 && strcmp( s, "off" ) != 0 )
+            {
+                Log_err( "Syntax error in config file: %s", line );
+                return;
+            }
+            else
+                strcpy( config.autoSubscribeMode, s );
+        }
+        else if ( strcmp( "server", name ) == 0 )
+            /* Server needs line not p,
+               because password may contain uppercase */
+            getServ( line );
+        else if ( strcmp( "mail-to", name ) == 0 )
+            getStr( config.mailTo, p );
+        else if ( strcmp( "expire", name ) == 0 )
+            getExpire( p );
+        else
+            Log_err( "Unknown config option: %s", name );
+    }
+    fclose( f );
+    if ( ! config.numServ )
+    {
+        Log_err( "Config file contains no server" );
+        exit( EXIT_FAILURE );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/configfile.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,53 @@
+/*
+  configfile.h
+
+  Common declarations and handling of the configuration file.
+
+  $Id: configfile.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
+
+#include "common.h"
+
+const char * Cfg_spoolDir( void );
+const char * Cfg_version( void );
+
+int Cfg_maxFetch( void );
+int Cfg_autoUnsubscribeDays( void );
+int Cfg_threadFollowTime( void );
+int Cfg_connectTimeout( void );
+Bool Cfg_autoUnsubscribe( void );
+Bool Cfg_autoSubscribe( void );
+Bool Cfg_removeMsgId( void );
+Bool Cfg_replaceMsgId( void );
+const char * Cfg_autoSubscribeMode( void ); /* Can be: full, thread, over */
+const char * Cfg_mailTo( void );
+
+/* Begin iteration through the server names */
+void Cfg_beginServEnum( void );
+
+/* Save next server name in "name". Return TRUE if name has been was saved.
+   Return FALSE if there are no more server names. */
+Bool Cfg_nextServ( Str name );
+
+Bool Cfg_servListContains( const char *name );
+/* Prefer server earlier in config file. Known servers are always preferential
+   to unknown servers. */
+Bool Cfg_servIsPreferential( const char *name1, const char *name2 );
+void Cfg_authInfo( const char *name, Str user, Str pass );
+
+/* Begin iteration through expire entries. */
+void Cfg_beginExpireEnum( void );
+
+/* Put next expire pattern in "pattern" and return its days count.
+   Return -1 if no more expire patterns. */
+int Cfg_nextExpire( Str pattern );
+
+/* Return default expire days. */
+int Cfg_expire( void );
+
+void Cfg_read( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/content.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,266 @@
+/*
+  content.c
+
+  $Id: content.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "common.h"
+#include "configfile.h"
+#include "group.h"
+#include "log.h"
+#include "over.h"
+#include "pseudo.h"
+#include "util.h"
+
+struct
+{
+    DIR *dir;           /* Directory for browsing through all
+                           groups */
+    int vecFirst;	/* First article number in vector */
+    int first;		/* First live article number */
+    int last;		/* Last article number */
+    unsigned int size;  /* Number of overviews. */
+    unsigned int max;   /* Size of elem. */
+    Over **elem;        /* Ptr to array with ptrs to overviews.
+                           NULL entries for non-existing article numbers
+                           in group. */
+    Str name;
+    Str file;
+} cont = { NULL, 1, 1, 0, 0, 0, NULL, "", "" };
+
+void
+Cont_app( Over *ov )
+{
+    if ( cont.max < cont.size + 1 )
+    {
+        if ( ! ( cont.elem = realloc( cont.elem,
+                                      ( cont.max + 500 )
+                                      * sizeof( cont.elem[ 0 ] ) ) ) )
+        {
+            Log_err( "Could not realloc overview list" );
+            exit( EXIT_FAILURE );
+        }
+        cont.max += 500;
+    }
+    ASSERT( cont.vecFirst > 0 );
+    if ( ov )
+        Ov_setNumb( ov, cont.vecFirst + cont.size );
+    cont.elem[ cont.size++ ] = ov;
+    cont.last = cont.vecFirst + cont.size - 1;
+}
+
+Bool
+Cont_validNumb( int n )
+{
+    return ( n != 0 && n >= cont.first && n <= cont.last
+             && cont.elem[ n - cont.vecFirst ] );
+}
+
+void
+Cont_delete( int n )
+{
+    Over **ov;
+
+    if ( ! Cont_validNumb( n ) )
+        return;
+    ov = &cont.elem[ n - cont.vecFirst ];
+    free( *ov );
+    *ov = NULL;
+}
+
+/* Remove all overviews from content. */
+static void
+clearCont()
+{
+    int i;
+
+    for ( i = 0; i < cont.size; ++i )
+        del_Over( cont.elem[ i ] );
+    cont.size = 0;
+}
+
+static void
+setupEmpty( const char *name )
+{
+    cont.last = Grp_last( name );
+    cont.first = cont.vecFirst = cont.last + 1;
+    ASSERT( cont.first > 0 );
+}
+
+/* Extend content list to size "cnt" and append NULL entries. */
+static void
+extendCont( int cnt )
+{
+    int i, n;
+    
+    if ( cont.size < cnt )
+    {
+        n = cnt - cont.size;
+        for ( i = 0; i < n; ++i )
+            Cont_app( NULL );
+    }
+}
+
+/* Discard all cached overviews, and read in the overviews of a new group
+   from its overviews file. */
+void
+Cont_read( const char *name )
+{
+    FILE *f;
+    Over *ov;
+    int numb;
+    Str line;
+
+    /* Delete old overviews and make room for new ones. */
+    cont.vecFirst = 0;
+    cont.first = 0;
+    cont.last = 0;
+    Utl_cpyStr( cont.name, name );
+    clearCont();
+
+    /* read overviews from overview file and store them in the overviews
+       list */
+    snprintf( cont.file, MAXCHAR, "%s/overview/%s", Cfg_spoolDir(), name ); 
+    f = fopen( cont.file, "r" );
+    if ( ! f )
+    {
+        Log_dbg( "No group overview file: %s", cont.file );
+	setupEmpty( name );
+        return;
+    }
+    Log_dbg( "Reading %s", cont.file );
+    while ( fgets( line, MAXCHAR, f ) )
+    {
+        if ( ! ( ov = Ov_read( line ) ) )
+        {
+            Log_err( "Overview corrupted in %s: %s", name, line );
+            continue;
+        }
+        numb = Ov_numb( ov );
+        if ( numb < cont.first )
+        {
+            Log_err( "Wrong ordering in %s: %s", name, line );
+            continue;
+        }
+        if ( cont.first == 0 )
+            cont.first = cont.vecFirst = numb;
+        cont.last = numb;
+        extendCont( numb - cont.first + 1 );
+        cont.elem[ numb - cont.first ] = ov;
+    }
+    fclose( f );
+
+    if ( cont.first == 0 )
+	setupEmpty( name );		/* Corrupt overview file recovery */
+}
+
+void
+Cont_write( void )
+{
+    Bool anythingWritten;
+    int i;
+    FILE *f;
+    const Over *ov;
+
+
+    /* Move the first article no. to the first active article */
+    while ( ! Cont_validNumb( cont.first ) && cont.first <= cont.last )
+        ++cont.first;
+
+    /* Save the overview */
+    if ( ! ( f = fopen( cont.file, "w" ) ) )
+    {
+        Log_err( "Could not open %s for writing", cont.file );
+        return;
+    }
+    Log_dbg( "Writing %s (%lu)", cont.file, cont.size );
+    anythingWritten = FALSE;
+    for ( i = 0; i < cont.size; ++i )
+    {
+        if ( ( ov = cont.elem[ i ] ) )
+        {
+            if ( ! Pseudo_isGeneralInfo( Ov_msgId( ov ) ) )
+            {
+                if ( ! Ov_write( ov, f ) )
+                {
+                    Log_err( "Writing of overview line failed" );
+                    break;
+                }
+                else
+                    anythingWritten = TRUE;
+            }
+        }
+    }
+    fclose( f );
+
+    /*
+      If empty, remove the overview file and set set first to one
+      beyond last to flag said emptiness.
+     */
+    if ( ! anythingWritten )
+    {
+	unlink( cont.file );
+	cont.first = cont.last + 1;
+    }
+}
+
+const Over *
+Cont_get( int numb )
+{
+    if ( ! Cont_validNumb( numb ) )
+        return NULL;
+    return cont.elem[ numb - cont.vecFirst ];
+}
+
+int
+Cont_first( void ) { return cont.first; }
+
+int
+Cont_last( void ) { return cont.last; }
+
+const char *
+Cont_grp( void ) { return cont.name; }
+
+Bool
+Cont_nextGrp( Str result )
+{
+    struct dirent *d;
+    
+    ASSERT( cont.dir );
+    if ( ! ( d = readdir( cont.dir ) ) )
+    {
+        cont.dir = NULL;
+        return FALSE;
+    }
+    if ( ! d->d_name )
+        return FALSE;
+    Utl_cpyStr( result, d->d_name );
+    result[ MAXCHAR - 1 ] = '\0';
+    return TRUE;
+}
+
+Bool
+Cont_firstGrp( Str result )
+{
+    Str name;
+
+    snprintf( name, MAXCHAR, "%s/overview", Cfg_spoolDir() );
+    if ( ! ( cont.dir = opendir( name ) ) )
+    {
+        Log_err( "Cannot open %s", name );
+        return FALSE;
+    }
+    Cont_nextGrp( result ); /* "."  */
+    Cont_nextGrp( result ); /* ".." */
+    return Cont_nextGrp( result );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/content.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,65 @@
+/*
+  content.h
+
+  Contents of a newsgroup
+  - list of article overviews for selected group.
+
+  The overviews of all articles of a group are stored in an overview file,
+  filename SPOOLDIR/overview/GROUPNAME. One entire overview file is read
+  and cached in memory, at a time.
+
+  $Id: content.h 49 2000-05-05 21:45:56Z uh1763 $ 
+*/
+
+#ifndef CONT_H
+#define CONT_H
+
+#include "over.h"
+
+/*
+  Try to read overviews from overview file for group <grp>.
+  Fill with fake articles, if something goes wrong.
+*/
+void
+Cont_read( const char *grp );
+
+/*
+  Append overview to current list and increment the current
+  group's last article counter. Ownership of the ptr is transfered
+  to content
+*/
+void
+Cont_app( Over *ov );
+
+/* Write content */
+void
+Cont_write( void );
+
+Bool
+Cont_validNumb( int numb );
+
+const Over *
+Cont_get( int numb );
+
+void
+Cont_delete( int numb );
+
+int
+Cont_first( void );
+
+int
+Cont_last( void );
+
+const char *
+Cont_grp( void );
+
+Bool
+Cont_nextGrp( Str result );
+
+Bool
+Cont_firstGrp( Str result );
+
+void
+Cont_expire( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/control.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,74 @@
+/*
+  control.c
+
+  $Id: control.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include "control.h"
+#include <stdio.h>
+#include "common.h"
+#include "content.h"
+#include "database.h"
+#include "group.h"
+#include "itemlist.h"
+#include "log.h"
+#include "outgoing.h"
+
+int
+Ctrl_cancel( const char *msgId )
+{
+    ItemList *refs;
+    const char *ref;
+    Str server;
+    Bool seen = FALSE;
+    int res = CANCEL_OK;
+
+    /* See if in outgoing and zap if so. */
+    if ( Out_find( msgId, server ) )
+    {
+	Out_remove( server, msgId );
+	Log_inf( "'%s' cancelled from outgoing queue for '%s'.\n",
+		 msgId, server );
+	seen = TRUE;
+    }
+
+    if ( ! Db_contains( msgId ) )
+    {
+	Log_inf( "Cancel: '%s' not in database.", msgId );
+	return seen ? CANCEL_OK : CANCEL_NO_SUCH_MSG;
+    }
+
+    /*
+      Retrieve the Xrefs, remove from each group and then
+      remove from the database.
+     */
+    refs = new_Itl( Db_xref( msgId ), " " );
+    for( ref = Itl_first( refs ); ref != NULL; ref = Itl_next( refs ) )
+    {
+	Str grp;
+	int no;
+
+	if ( sscanf( ref, "%s:%d", grp, &no ) != 2 )
+	    break;
+	
+	if ( Grp_exists( grp ) )
+	{
+	    Cont_read( grp );
+	    Cont_delete( no );
+	    Cont_write();
+
+	    if ( ! Grp_local( grp ) && ! seen )
+		res = CANCEL_NEEDS_MSG;
+
+	    Log_dbg( "Removed '%s' from group '%s'.", msgId, grp );
+	}
+	else
+	{
+	    Log_inf( "Group '%s' in Xref for '%s' not found.", grp, msgId );
+	}
+    }
+    del_Itl( refs );
+    Db_delete( msgId );
+    Log_inf( "Message '%s' cancelled.", msgId );
+    return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/control.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,25 @@
+/*
+  control.h
+
+  Control actions needed by server and command line.
+
+  $Id: control.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#define	CANCEL_OK		0
+#define	CANCEL_NO_SUCH_MSG	1
+#define	CANCEL_NEEDS_MSG	2
+
+/*
+   Cancel a message. Return CANCEL_OK if completely cancelled,
+   CANCEL_NO_SUCH_MSG if no message with that ID exists, and
+   CANCEL_NEEDS_MSG if a 'cancel' message should be propagated upstream
+   to cancel the message elsewhere.
+ */
+int
+Ctrl_cancel( const char *msgId );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/database.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,684 @@
+/*
+  database.c
+
+  $Id: database.c 49 2000-05-05 21:45:56Z uh1763 $
+
+  Uses GNU gdbm library. Using Berkeley db (included in libc6) was
+  cumbersome. It is based on Berkeley db 1.85, which has severe bugs
+  (e.g. it is not recommended to delete or overwrite entries with
+  overflow pages).
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "database.h"
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gdbm.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "configfile.h"
+#include "itemlist.h"
+#include "log.h"
+#include "protocol.h"
+#include "util.h"
+#include "wildmat.h"
+
+static struct Db
+{
+    GDBM_FILE dbf;
+
+    /* Start string for Xref header line: "Xref: <host>" */
+    Str xrefHost;
+
+    /* Msg Id of presently loaded article, empty if none loaded */
+    Str msgId;
+
+    /* Status of loaded article */
+    int stat; /* Flags */
+    time_t lastAccess;
+
+    /* Overview of loaded article */
+    Str subj; 
+    Str from;
+    Str date;
+    Str ref;
+    Str xref;
+    size_t bytes;
+    size_t lines;
+
+    /* Article text (except for overview header lines) */
+    DynStr *txt;
+
+} db = { NULL, "(unknown)", "", 0, 0, "", "", "", "", "", 0, 0, NULL };
+
+static const char *
+errMsg( void )
+{
+    if ( errno != 0 )
+        return strerror( errno );
+    return gdbm_strerror( gdbm_errno );
+}
+
+Bool
+Db_open( void )
+{
+    Str name, host;
+    int flags;
+
+    ASSERT( db.dbf == NULL );
+    snprintf( name, MAXCHAR, "%s/data/articles.gdbm", Cfg_spoolDir() );
+    flags = GDBM_WRCREAT | GDBM_FAST;
+
+    if ( ! ( db.dbf = gdbm_open( name, 512, flags, 0644, NULL ) ) )
+    {
+        Log_err( "Error opening %s for r/w (%s)", name, errMsg() );
+        return FALSE;
+    }
+    Log_dbg( "%s opened for r/w", name );
+
+    if ( db.txt == NULL )
+        db.txt = new_DynStr( 5000 );
+
+    gethostname( host, MAXCHAR );
+    snprintf( db.xrefHost, MAXCHAR, "Xref: %s", host );
+
+    return TRUE;
+}
+
+void
+Db_close( void )
+{
+    ASSERT( db.dbf );
+    Log_dbg( "Closing database" );
+    gdbm_close( db.dbf );
+    db.dbf = NULL;
+    del_DynStr( db.txt );
+    db.txt = NULL;
+    Utl_cpyStr( db.msgId, "" );
+}
+
+static Bool
+loadArt( const char *msgId )
+{
+    static void *dptr = NULL;
+    
+    datum key, val;
+    Str t = "";
+    const char *p;
+    
+    ASSERT( db.dbf );
+
+    if ( strcmp( msgId, db.msgId ) == 0 )
+        return TRUE;
+
+    key.dptr = (void *)msgId;
+    key.dsize = strlen( msgId ) + 1;
+    if ( dptr != NULL )
+    {
+        free( dptr );
+        dptr = NULL;
+    }
+    val = gdbm_fetch( db.dbf, key );
+    dptr = val.dptr;
+    if ( dptr == NULL )
+    {
+        Log_dbg( "database.c loadArt: gdbm_fetch found no entry" );
+        return FALSE;
+    }
+    
+    Utl_cpyStr( db.msgId, msgId );
+    p = Utl_getLn( t, (char *)dptr );
+    if ( ! p || sscanf( t, "%x", &db.stat ) != 1 )
+    {
+        Log_err( "Entry in database '%s' is corrupt (status)", msgId );
+        return FALSE;
+    }
+    p = Utl_getLn( t, p );
+    if ( ! p || sscanf( t, "%lu", &db.lastAccess ) != 1 )
+    {
+        Log_err( "Entry in database '%s' is corrupt (lastAccess)", msgId );
+        return FALSE;
+    }
+    p = Utl_getLn( db.subj, p );
+    p = Utl_getLn( db.from, p );
+    p = Utl_getLn( db.date, p );
+    p = Utl_getLn( db.ref, p );
+    p = Utl_getLn( db.xref, p );
+    if ( ! p )
+    {
+        Log_err( "Entry in database '%s' is corrupt (overview)", msgId );
+        return FALSE;
+    }
+    p = Utl_getLn( t, p );
+    if ( ! p || sscanf( t, "%u", &db.bytes ) != 1 )
+    {
+        Log_err( "Entry in database '%s' is corrupt (bytes)", msgId );
+        return FALSE;
+    }
+    p = Utl_getLn( t, p );
+    if ( ! p || sscanf( t, "%u", &db.lines ) != 1 )
+    {
+        Log_err( "Entry in database '%s' is corrupt (lines)", msgId );
+        return FALSE;
+    }
+    DynStr_clear( db.txt );
+    DynStr_app( db.txt, p );
+    return TRUE;
+}
+
+static Bool
+saveArt( void )
+{
+    DynStr *s;
+    Str t = "";
+    datum key, val;
+
+    if ( strcmp( db.msgId, "" ) == 0 )
+        return FALSE;
+    s = new_DynStr( 5000 );
+    snprintf( t, MAXCHAR, "%x", db.stat );
+    DynStr_appLn( s, t );
+    snprintf( t, MAXCHAR, "%lu", db.lastAccess );
+    DynStr_appLn( s, t );
+    DynStr_appLn( s, db.subj );
+    DynStr_appLn( s, db.from );
+    DynStr_appLn( s, db.date );
+    DynStr_appLn( s, db.ref );
+    DynStr_appLn( s, db.xref );
+    snprintf( t, MAXCHAR, "%u", db.bytes );
+    DynStr_appLn( s, t );
+    snprintf( t, MAXCHAR, "%u", db.lines );
+    DynStr_appLn( s, t );
+    DynStr_appDynStr( s, db.txt );
+
+    key.dptr = (void *)db.msgId;
+    key.dsize = strlen( db.msgId ) + 1;
+    val.dptr = (void *)DynStr_str( s );
+    val.dsize = DynStr_len( s ) + 1;
+    if ( gdbm_store( db.dbf, key, val, GDBM_REPLACE ) != 0 )
+    {
+        Log_err( "Could not store %s in database (%s)", errMsg() );
+        return FALSE;
+    }
+
+    del_DynStr( s );
+    return TRUE;
+}
+
+Bool
+Db_prepareEntry( const Over *ov, const char *grp, int numb )
+{
+    const char *msgId;
+
+    ASSERT( db.dbf );
+    ASSERT( ov );
+    ASSERT( grp );
+
+    msgId = Ov_msgId( ov );
+    Log_dbg( "Preparing entry %s", msgId );
+    if ( Db_contains( msgId ) )
+        Log_err( "Preparing article twice: %s", msgId );
+
+    db.stat = DB_NOT_DOWNLOADED;
+    db.lastAccess = time( NULL );
+
+    Utl_cpyStr( db.msgId, msgId );
+    Utl_cpyStr( db.subj, Ov_subj( ov ) );
+    Utl_cpyStr( db.from, Ov_from( ov ) );
+    Utl_cpyStr( db.date, Ov_date( ov ) );
+    Utl_cpyStr( db.ref, Ov_ref( ov ) );
+    snprintf( db.xref, MAXCHAR, "%s:%i", grp, numb );
+    db.bytes = Ov_bytes( ov );
+    db.lines = Ov_lines( ov );
+
+    DynStr_clear( db.txt );
+
+    return saveArt();
+}
+
+Bool
+Db_storeArt( const char *msgId, const char *artTxt )
+{
+    Str line, lineEx, field, value;
+    const char *startPos;
+
+    ASSERT( db.dbf );
+
+    Log_dbg( "Store article %s", msgId );
+    if ( ! loadArt( msgId ) )
+    {
+        Log_err( "Cannot find info about '%s' in database", msgId );
+        return FALSE;
+    }
+    if ( ! ( db.stat & DB_NOT_DOWNLOADED ) )
+    {
+        Log_err( "Trying to store already retrieved article '%s'", msgId );
+        return FALSE;
+    }
+    db.stat &= ~DB_NOT_DOWNLOADED;
+    db.stat &= ~DB_RETRIEVING_FAILED;
+    db.lastAccess = time( NULL );
+
+    DynStr_clear( db.txt );
+
+    /* Read header */
+    startPos = artTxt;
+    while ( TRUE )
+    {
+        artTxt = Utl_getHeaderLn( lineEx, artTxt );
+        if ( lineEx[ 0 ] == '\0' )
+        {
+            DynStr_appLn( db.txt, lineEx );
+            break;
+        }
+        /* Remove fields already in overview and handle x-noffle
+           headers correctly in case of cascading NOFFLEs */
+        if ( Prt_getField( field, value, lineEx ) )
+        {
+            if ( strcmp( field, "x-noffle-status" ) == 0 )
+            {
+                if ( strstr( value, "NOT_DOWNLOADED" ) != 0 )
+                    db.stat |= DB_NOT_DOWNLOADED;
+            }
+            else if ( strcmp( field, "message-id" ) != 0
+                      && strcmp( field, "xref" ) != 0
+                      && strcmp( field, "references" ) != 0
+                      && strcmp( field, "subject" ) != 0
+                      && strcmp( field, "from" ) != 0
+                      && strcmp( field, "date" ) != 0
+                      && strcmp( field, "bytes" ) != 0
+                      && strcmp( field, "lines" ) != 0
+                      && strcmp( field, "x-noffle-lastaccess" ) != 0 )
+                DynStr_appLn( db.txt, lineEx );
+        }
+    }
+
+    /* Read body */
+    while ( ( artTxt = Utl_getLn( line, artTxt ) ) )
+        if ( ! ( db.stat & DB_NOT_DOWNLOADED ) )
+            DynStr_appLn( db.txt, line );
+    
+    return saveArt();
+}
+
+void
+Db_setStat( const char *msgId, int stat )
+{
+    if ( loadArt( msgId ) )
+    {
+        db.stat = stat;
+        saveArt();
+    }
+}
+
+void
+Db_updateLastAccess( const char *msgId )
+{
+    if ( loadArt( msgId ) )
+    {
+        db.lastAccess = time( NULL );
+        saveArt();
+    }
+}
+
+void
+Db_setXref( const char *msgId, const char *xref )
+{
+    if ( loadArt( msgId ) )
+    {
+        Utl_cpyStr( db.xref, xref );
+        saveArt();
+    }
+}
+
+/* Search best position for breaking a line */
+static const char *
+searchBreakPos( const char *line, int wantedLength )
+{
+    const char *lastSpace = NULL;
+    Bool lastWasSpace = FALSE;
+    int len = 0;
+
+    while ( *line != '\0' )
+    {
+        if ( isspace( *line ) )
+        {
+            if ( len > wantedLength && lastSpace != NULL )
+                return lastSpace;
+            if ( ! lastWasSpace )
+                lastSpace = line;
+            lastWasSpace = TRUE;
+        }
+        else
+            lastWasSpace = FALSE;
+        ++len;
+        ++line;
+    }
+    if ( len > wantedLength && lastSpace != NULL )
+        return lastSpace;
+    return line;
+}
+
+/* Append header line by breaking long line into multiple lines */
+static void
+appendLongHeader( DynStr *target, const char *field, const char *value )
+{
+    const int wantedLength = 78;
+    const char *breakPos, *old;
+    int len;
+
+    len = strlen( field );
+    DynStr_appN( target, field, len );
+    DynStr_appN( target, " ", 1 );
+    old = value;
+    while ( isspace( *old ) )
+        ++old;
+    breakPos = searchBreakPos( old, wantedLength - len - 1 );
+    DynStr_appN( target, old, breakPos - old );
+    if ( *breakPos == '\0' )
+    {
+        DynStr_appN( target, "\n", 1 );
+        return;
+    }
+    DynStr_appN( target, "\n ", 2 );
+    while ( TRUE )
+    {
+        old = breakPos;
+        while ( isspace( *old ) )
+            ++old;
+        breakPos = searchBreakPos( old, wantedLength - 1 );
+        DynStr_appN( target, old, breakPos - old );
+        if ( *breakPos == '\0' )
+        {
+            DynStr_appN( target, "\n", 1 );
+            return;
+        }
+        DynStr_appN( target, "\n ", 2 );
+    }
+}
+
+const char *
+Db_header( const char *msgId )
+{
+    static DynStr *s = NULL;
+
+    Str date, t;
+    int stat;
+    const char *p;
+
+    if ( s == NULL )
+        s = new_DynStr( 5000 );
+    else
+        DynStr_clear( s );
+    ASSERT( db.dbf );
+    if ( ! loadArt( msgId ) )
+        return NULL;
+    strftime( date, MAXCHAR, "%Y-%m-%d %H:%M:%S",
+              localtime( &db.lastAccess ) );
+    stat = db.stat;
+    snprintf( t, MAXCHAR,
+              "Message-ID: %s\n"
+              "X-NOFFLE-Status:%s%s%s\n"
+              "X-NOFFLE-LastAccess: %s\n",
+              msgId,
+              stat & DB_INTERESTING ? " INTERESTING" : "",
+              stat & DB_NOT_DOWNLOADED ? " NOT_DOWNLOADED" : "",
+              stat & DB_RETRIEVING_FAILED ? " RETRIEVING_FAILED" : "",
+              date );
+    DynStr_app( s, t );
+    appendLongHeader( s, "Subject:", db.subj );
+    appendLongHeader( s, "From:", db.from );
+    appendLongHeader( s, "Date:", db.date );
+    appendLongHeader( s, "References:", db.ref );
+    DynStr_app( s, "Bytes: " );
+    snprintf( t, MAXCHAR, "%u", db.bytes );
+    DynStr_appLn( s, t );
+    DynStr_app( s, "Lines: " );
+    snprintf( t, MAXCHAR, "%u", db.lines );
+    DynStr_appLn( s, t );
+    appendLongHeader( s, db.xrefHost, db.xref );
+    p = strstr( DynStr_str( db.txt ), "\n\n" );
+    if ( ! p )
+        DynStr_appDynStr( s, db.txt );
+    else
+        DynStr_appN( s, DynStr_str( db.txt ), p - DynStr_str( db.txt ) + 1 );
+    return DynStr_str( s );
+}
+
+const char *
+Db_body( const char *msgId )
+{
+    const char *p;
+
+    if ( ! loadArt( msgId ) )
+        return "";
+    p = strstr( DynStr_str( db.txt ), "\n\n" );
+    if ( ! p )
+        return "";
+    return ( p + 2 );
+}
+
+int
+Db_stat( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return 0;
+    return db.stat;
+}
+
+time_t
+Db_lastAccess( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return -1;
+    return db.lastAccess;
+}
+
+const char *
+Db_ref( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return "";
+    return db.ref;
+}
+
+const char *
+Db_xref( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return "";
+    return db.xref;
+}
+
+const char *
+Db_from( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return "";
+    return db.from;
+}
+
+const char *
+Db_date( const char *msgId )
+{
+    if ( ! loadArt( msgId ) )
+        return "";
+    return db.date;
+}
+
+Bool
+Db_contains( const char *msgId )
+{
+    datum key;
+
+    ASSERT( db.dbf );
+    if ( strcmp( msgId, db.msgId ) == 0 )
+        return TRUE;
+    key.dptr = (void*)msgId;
+    key.dsize = strlen( msgId ) + 1;
+    return gdbm_exists( db.dbf, key );
+}
+
+void
+Db_delete( const char *msgId )
+{
+    datum key;
+
+    ASSERT( db.dbf );
+    if ( strcmp( msgId, db.msgId ) == 0 )
+        db.msgId[ 0 ] = '\0';
+    key.dptr = (void*)msgId;
+    key.dsize = strlen( msgId ) + 1;
+    gdbm_delete( db.dbf, key );
+}
+
+static datum cursor = { NULL, 0 };
+
+Bool
+Db_first( const char** msgId )
+{
+    ASSERT( db.dbf );
+    if ( cursor.dptr != NULL )
+    {
+        free( cursor.dptr );
+        cursor.dptr = NULL;
+    }
+    cursor = gdbm_firstkey( db.dbf );
+    *msgId = cursor.dptr;
+    return ( cursor.dptr != NULL );
+}
+
+Bool
+Db_next( const char** msgId )
+{
+    void *oldDptr = cursor.dptr;
+
+    ASSERT( db.dbf );
+    if ( cursor.dptr == NULL )
+        return FALSE;
+    cursor = gdbm_nextkey( db.dbf, cursor );
+    free( oldDptr );
+    *msgId = cursor.dptr;
+    return ( cursor.dptr != NULL );
+}
+
+static int
+calcExpireDays( const char *msgId )
+{
+    const char *xref;
+    ItemList *refs;
+    const char *ref;
+    int res;
+
+    xref = Db_xref( msgId );
+    if ( xref[ 0 ] == '\0' )
+	return -1;
+
+    res = -1;
+    refs = new_Itl( xref, " :" );
+    for ( ref = Itl_first( refs ); ref != NULL; ref = Itl_next( refs ) )
+    {
+	Str pattern;
+	int days;
+	
+	Cfg_beginExpireEnum();
+	while ( ( days = Cfg_nextExpire( pattern ) ) != -1 )
+	    if ( Wld_match( ref, pattern )
+		 && ( ( days > res && res != 0 ) ||
+		      days == 0 ) )
+	    {
+		res = days;
+		Log_dbg ( "Custom expiry %d for %s in group %s",
+			  days, msgId, ref );
+		break;
+	    }
+	
+	Itl_next( refs );	/* Throw away group number */
+    }
+
+    if ( res == -1 )
+	res = Cfg_expire();
+    return res;
+}
+
+Bool
+Db_expire( void )
+{
+    int cntDel, cntLeft, flags, expDays;
+    time_t nowTime, lastAccess;
+    const char *msgId;
+    Str name, tmpName;
+    GDBM_FILE tmpDbf;
+    datum key, val;
+
+    if ( ! Db_open() )
+        return FALSE;
+    snprintf( name, MAXCHAR, "%s/data/articles.gdbm", Cfg_spoolDir() );
+    snprintf( tmpName, MAXCHAR, "%s/data/articles.gdbm.new", Cfg_spoolDir() );
+    flags = GDBM_NEWDB | GDBM_FAST;
+    if ( ! ( tmpDbf = gdbm_open( tmpName, 512, flags, 0644, NULL ) ) )
+    {
+        Log_err( "Error opening %s for read/write (%s)", errMsg() );
+        Db_close();
+        return FALSE;
+    }
+    Log_inf( "Expiring articles" );
+    cntDel = 0;
+    cntLeft = 0;
+    nowTime = time( NULL );
+    if ( Db_first( &msgId ) )
+        do
+        {
+	    expDays = calcExpireDays( msgId );
+            lastAccess = Db_lastAccess( msgId );
+	    if ( expDays == -1 )
+		Log_err( "Internal error: Failed expiry calculation on %s",
+			 msgId );
+	    else if ( lastAccess == -1 )
+                Log_err( "Internal error: Getting lastAccess of %s failed",
+                         msgId );
+            else if ( expDays > 0
+		      && difftime( nowTime, lastAccess ) >
+		          ( (double) expDays * 24 * 3600 ) )
+            {
+#ifdef DEBUG
+		Str last, now;
+
+		Utl_cpyStr( last, ctime( &lastAccess ) );
+		last[ strlen( last ) - 1 ] = '\0';
+		Utl_cpyStr( now, ctime( &nowTime ) );
+		last[ strlen( now ) - 1 ] = '\0';
+                Log_dbg( "Expiring %s: last access %s, time now %s",
+			 msgId, last, now );
+#endif
+                ++cntDel;
+            }
+            else
+            {
+                ++cntLeft;
+                key.dptr = (void *)msgId;
+                key.dsize = strlen( msgId ) + 1;
+
+                val = gdbm_fetch( db.dbf, key );
+                if ( val.dptr != NULL )
+                {
+                    if ( gdbm_store( tmpDbf, key, val, GDBM_INSERT ) != 0 )
+                        Log_err( "Could not store %s in new database (%s)",
+                                 errMsg() );
+                    free( val.dptr );
+                }
+            }
+        }
+        while ( Db_next( &msgId ) );
+    Log_inf( "%lu articles deleted, %lu left", cntDel, cntLeft );
+    gdbm_close( tmpDbf );
+    Db_close();
+    rename( tmpName, name );
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/database.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,99 @@
+/*
+  database.h
+
+  Article database.
+
+  $Id: database.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef DB_H
+#define DB_H
+
+#include <time.h>
+#include "common.h"
+#include "dynamicstring.h"
+#include "over.h"
+
+/* Article status flags: */
+#define DB_INTERESTING       0x01  /* Was article ever tried to read? */
+#define DB_NOT_DOWNLOADED    0x02  /* Not fully downloaded */
+#define DB_RETRIEVING_FAILED 0x04  /* Retrieving of article failed */
+
+/* Open database for r/w. Locking must be done by the caller! */
+Bool
+Db_open( void );
+
+void
+Db_close( void );
+
+/*
+  Creates an database entry for the article from the overview
+  information. Xref is replaced by grp:numb.
+*/
+Bool
+Db_prepareEntry( const Over *ov, const char *grp, int numb );
+
+/* Store full article. Can only be used after Db_prepareEntry. */
+Bool
+Db_storeArt( const char *msgId, const char *artTxt );
+
+void
+Db_setStat( const char *msgId, int stat );
+
+void
+Db_updateLastAccess( const char *msgId );
+
+/* Xref header line without hostname */
+void
+Db_setXref( const char *msgId, const char *xref );
+
+const char *
+Db_header( const char *msgId );
+
+const char *
+Db_body( const char *msgId );
+
+int
+Db_stat( const char *msgId );
+
+/* Get last modification time of entry. Returns -1, if msgId non-existing. */
+time_t
+Db_lastAccess( const char *msgId );
+
+/* Value of the References header line */
+const char *
+Db_ref( const char *msgId );
+
+/* Value of the From header line */
+const char *
+Db_from( const char *msgId );
+
+/* Value of the Date header line */
+const char *
+Db_date( const char *msgId );
+
+/* Xref header line without hostname */
+const char *
+Db_xref( const char *msgId );
+
+Bool
+Db_contains( const char *msgId );
+
+/* Delete entry from database */
+void
+Db_delete( const char *msgId );
+
+Bool
+Db_first( const char** msgId );
+
+Bool
+Db_next( const char** msgId );
+
+/*
+  Expire all articles that have not been accessed for a number of
+  days determined by their group membership and noffle configuration.
+ */
+Bool
+Db_expire( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dynamicstring.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,120 @@
+/*
+  dynamicstring.c
+
+  $Id: dynamicstring.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include "dynamicstring.h"
+
+#include <sys/types.h>
+#include "log.h"
+
+struct DynStr
+{
+    size_t len; /* Current length (without trailing '\0') */
+    size_t max; /* Max length that fits into buffer (incl. trailing '\0') */
+    char *str;
+};
+
+static void
+reallocStr( DynStr *self, size_t max )
+{
+    if ( max <= self->max )
+        return;
+    if ( ! ( self->str = (char *)realloc( self->str, max ) ) )
+    {
+        Log_err( "Realloc of DynStr failed" );
+        exit( EXIT_FAILURE );
+    } 
+    if ( self->max == 0 ) /* First allocation? */
+        *(self->str) = '\0';
+    self->max = max;
+}
+
+DynStr *
+new_DynStr( size_t reserve )
+{
+    DynStr *s;
+    
+    if ( ! ( s = (DynStr *) malloc( sizeof( DynStr ) ) ) )
+    {
+        Log_err( "Allocation of DynStr failed" );
+        exit( EXIT_FAILURE );
+    }
+    s->len = 0;
+    s->max = 0;
+    s->str = NULL;
+    if ( reserve > 0 )
+        reallocStr( s, reserve + 1 );
+    return s;
+}
+
+void
+del_DynStr( DynStr *self )
+{
+    if ( ! self )
+        return;
+    free( self->str );
+    self->str = NULL;
+    free( self );
+}
+
+size_t
+DynStr_len( const DynStr *self )
+{
+    return self->len;
+}
+
+const char *
+DynStr_str( const DynStr *self )
+{
+    return self->str;
+}
+
+void
+DynStr_app( DynStr *self, const char *s )
+{
+    size_t len;
+
+    len = strlen( s );
+    if ( self->len + len + 1 > self->max )
+        reallocStr( self, self->len * 2 + len + 1 );
+    strcpy( self->str + self->len, s );
+    self->len += len;
+}
+
+void
+DynStr_appDynStr( DynStr *self, const DynStr *s )
+{
+    if ( self->len + s->len + 1 > self->max )
+        reallocStr( self, self->len * 2 + s->len + 1 );
+    memcpy( self->str + self->len, s->str, s->len + 1 );
+    self->len += s->len;
+}
+
+void
+DynStr_appLn( DynStr *self, const char *s )
+{
+    DynStr_app( self, s );
+    DynStr_app( self, "\n" );
+}
+
+void
+DynStr_appN( DynStr *self, const char *s, size_t n )
+{
+    size_t len = self->len;
+
+    if ( len + n + 1 > self->max )
+        reallocStr( self, len * 2 + n + 1 );
+    strncat( self->str + len, s, n );
+    self->len = len + strlen( self->str + len );
+}
+
+void
+DynStr_clear( DynStr *self )
+{
+    self->len = 0;
+    if ( self->max > 0 )
+        *(self->str) = '\0';
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dynamicstring.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,54 @@
+/*
+  dynamicstring.h
+
+  String utilities
+
+  $Id: dynamicstring.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef DYNAMICSTRING_H
+#define DYNAMICSTRING_H
+
+#include <sys/types.h>
+
+/* A dynamically growing string */
+struct DynStr;
+typedef struct DynStr DynStr;
+
+/* Create new DynStr with given capacity */
+DynStr *
+new_DynStr( size_t reserve );
+
+/* Delete DynStr */
+void
+del_DynStr( DynStr *self );
+
+/* Return DynStr's length */
+size_t
+DynStr_len( const DynStr *self );
+
+/* Return DynStr's content ptr */
+const char *
+DynStr_str( const DynStr *self );
+
+/* append C-string to DynStr */
+void
+DynStr_app( DynStr *self, const char *s );
+
+/* append a DynStr to DynStr */
+void
+DynStr_appDynStr( DynStr *self, const DynStr *s );
+
+/* Append C-string + newline to DynStr */
+void
+DynStr_appLn( DynStr *self, const char *s );
+
+/* Append a maximum of n characters from C-string s to DynStr self */
+void
+DynStr_appN( DynStr *self, const char *s, size_t n );
+
+/* Truncate content of DynString to zero length */
+void
+DynStr_clear( DynStr *self );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fetch.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,252 @@
+/*
+  fetch.c
+
+  $Id: fetch.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "fetch.h"
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include "client.h"
+#include "configfile.h"
+#include "content.h"
+#include "dynamicstring.h"
+#include "fetchlist.h"
+#include "request.h"
+#include "group.h"
+#include "log.h"
+#include "outgoing.h"
+#include "protocol.h"
+#include "pseudo.h"
+#include "util.h"
+
+struct Fetch
+{
+    Bool ready;
+    Str serv;
+} fetch = { FALSE, "" };
+
+static Bool
+connectToServ( const char *name )
+{
+    Log_inf( "Fetch from '%s'", name );
+    if ( ! Client_connect( name ) )
+    {
+        Log_err( "Could not connect to %s", name );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+void
+Fetch_getNewGrps( void )
+{
+    time_t t;
+    Str file;
+
+    ASSERT( fetch.ready );
+    snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
+    if ( ! Utl_getStamp( &t, file ) )
+    {
+        Log_err( "Cannot read %s. Please run noffle --query groups", file );
+        return;
+    }
+    Log_inf( "Updating groupinfo" );
+    Client_getNewgrps( &t );
+    Utl_stamp( file );
+}
+
+void
+Fetch_getNewArts( const char *name, FetchMode mode )
+{
+    int next, first, last, oldLast;
+
+    if ( ! Client_changeToGrp( name ) )
+    {
+        Log_err( "Could not change to group %s", name );
+        return;
+    }
+    Cont_read( name );
+    Client_rmtFirstLast( &first, &last );
+    next = Grp_rmtNext( name );
+    oldLast = Cont_last();
+    if ( next == last + 1 )
+    {
+        Log_inf( "No new articles in %s", name );
+        Cont_write();
+        Grp_setFirstLast( name, Cont_first(), Cont_last() );
+        return;
+    }
+    if ( first == 0 && last == 0 )
+    {
+        Log_inf( "No articles in %s", name );
+        Cont_write();
+        Grp_setFirstLast( name, Cont_first(), Cont_last() );
+        return;
+    }
+    if ( next > last + 1 )
+    {
+        Log_err( "Article number inconsistent (%s rmt=%lu-%lu, next=%lu)",
+                 name, first, last, next );
+        Pseudo_cntInconsistent( name, first, last, next );
+    }
+    else if ( next < first )
+    {
+        Log_inf( "Missing articles (%s first=%lu next=%lu)",
+                 name, first, next );
+        Pseudo_missArts( name, first, next );
+    }
+    else
+        first = next;
+    if ( last - first > Cfg_maxFetch() )
+    {
+        Log_ntc( "Cutting number of overviews to %lu", Cfg_maxFetch() );
+        first = last - Cfg_maxFetch() + 1;
+    }
+    Log_inf( "Getting remote overviews %lu-%lu for group %s",
+             first, last, name );
+    Client_getOver( first, last, mode );
+    Cont_write();
+    Grp_setFirstLast( name, Cont_first(), Cont_last() );
+}
+
+void
+Fetch_updateGrps( void )
+{
+    FetchMode mode;
+    int i, size;
+    const char* name;
+
+    ASSERT( fetch.ready );
+    Fetchlist_read();
+    size = Fetchlist_size();
+    for ( i = 0; i < size; ++i )
+    {
+        Fetchlist_element( &name, &mode, i );
+        if ( strcmp( Grp_serv( name ), fetch.serv ) == 0 )
+            Fetch_getNewArts( name, mode );
+    }
+}
+
+void
+Fetch_getReq_( void )
+{
+    Str msgId;
+    DynStr *list;
+    const char *p;
+    int count = 0;
+
+    ASSERT( fetch.ready );
+    Log_dbg( "Retrieving articles marked for download" );
+    list = new_DynStr( 10000 );
+    if ( Req_first( fetch.serv, msgId ) )
+        do
+        {
+            DynStr_appLn( list, msgId );
+            if ( ++count % 20 == 0 ) /* Send max. 20 ARTICLE cmds at once */
+            {
+                p = DynStr_str( list );
+                Client_retrieveArtList( p );
+                while ( ( p = Utl_getLn( msgId, p ) ) )
+                    Req_remove( fetch.serv, msgId );
+                DynStr_clear( list );
+            }
+        }
+        while ( Req_next( msgId ) );
+    p = DynStr_str( list );
+    Client_retrieveArtList( p );
+    while ( ( p = Utl_getLn( msgId, p ) ) )
+        Req_remove( fetch.serv, msgId );
+    del_DynStr( list );
+}
+
+void
+Fetch_postArts( void )
+{
+    DynStr *s;
+    Str msgId, cmd, errStr, sender;
+    int ret;
+    const char *txt;
+    FILE *f;
+    sig_t lastHandler;
+
+    s = new_DynStr( 10000 );
+    if ( Out_first( fetch.serv, msgId, s ) )
+    {
+        Log_inf( "Posting articles" );
+        do
+        {
+            txt = DynStr_str( s );
+            Out_remove( fetch.serv, msgId );
+            if ( ! Client_postArt( msgId, txt, errStr ) )
+            {
+                Utl_cpyStr( sender, Cfg_mailTo() );
+                if ( strcmp( sender, "" ) == 0
+                     && ! Prt_searchHeader( txt, "SENDER", sender )
+                     && ! Prt_searchHeader( txt, "X-NOFFLE-X-SENDER",
+                                            sender ) /* see server.c */
+                     && ! Prt_searchHeader( txt, "FROM", sender ) )
+                    Log_err( "Article %s has no From/Sender/X-Sender field",
+                             msgId );
+                else
+                {
+                    Log_ntc( "Return article to '%s' by mail", sender );
+                    snprintf( cmd, MAXCHAR,
+                              "mail -s '[ NOFFLE: Posting failed ]' '%s'",
+                              sender );
+                    lastHandler = signal( SIGPIPE, SIG_IGN );
+                    f = popen( cmd, "w" );
+                    if ( f == NULL )
+                        Log_err( "Invocation of '%s' failed (%s)", cmd,
+                                 strerror( errno ) );
+                    else
+                    {
+                        fprintf( f,
+                                 "\t[ NOFFLE: POSTING OF ARTICLE FAILED ]\n"
+                                 "\n"
+                                 "\t[ The posting of your article failed. ]\n"
+                                 "\t[ Reason of failure at remote server: ]\n"
+                                 "\n"
+                                 "\t[ %s ]\n"
+                                 "\n"
+                                 "\t[ Full article text has been appended. ]\n"
+                                 "\n"
+                                 "%s"
+                                 ".\n",
+                                 errStr, txt );
+                        ret = pclose( f );
+                        if ( ret != EXIT_SUCCESS )
+                            Log_err( "'%s' exit value %d", cmd, ret );
+                        signal( SIGPIPE, lastHandler );
+                    }
+                }
+            }
+        }
+        while ( Out_next( msgId, s ) );
+    }
+    del_DynStr( s );
+}
+
+Bool
+Fetch_init( const char *serv )
+{
+    if ( ! connectToServ( serv ) )
+        return FALSE;
+    Utl_cpyStr( fetch.serv, serv );
+    fetch.ready = TRUE;
+    return TRUE;
+}
+
+void
+Fetch_close()
+{
+    Client_disconnect();
+    fetch.ready = FALSE;
+    Log_inf( "Fetch from '%s' finished", fetch.serv );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fetch.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,38 @@
+/*
+  fetch.h
+
+  Do the daily business by using client.c
+
+  $Id: fetch.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef FETCH_H
+#define FETCH_H
+
+#include "common.h"
+#include "database.h"
+#include "fetchlist.h"
+
+Bool
+Fetch_init( const char *serv );
+
+void
+Fetch_close( void );
+
+void
+Fetch_getNewGrps( void );
+
+void
+Fetch_updateGrps( void );
+
+void
+Fetch_getReq_( void );
+
+void
+Fetch_postArts( void );
+
+/* Get new articles in group "grp", using fetch mode "mode". */
+void
+Fetch_getNewArts( const char *grp, FetchMode mode );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fetchlist.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,210 @@
+/*
+  fetchlist.c
+
+  $Id: fetchlist.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "fetchlist.h"
+#include "configfile.h"
+#include "log.h"
+#include "util.h"
+
+struct Elem
+{
+    Str name;
+    FetchMode mode;
+};
+
+static struct Fetchlist
+{
+    struct Elem *elem;
+    int size;
+    int max;
+} fetchlist = { NULL, 0, 0 };
+
+static const char *
+getFile( void )
+{
+    static Str file;
+    snprintf( file, MAXCHAR, "%s/fetchlist", Cfg_spoolDir() );
+    return file;
+}
+
+static void
+clearList( void )
+{
+    fetchlist.size = 0;
+}
+
+static int
+compareElem( const void *elem1, const void *elem2 )
+{
+    struct Elem* e1 = (struct Elem*)elem1; 
+    struct Elem* e2 = (struct Elem*)elem2;
+    return strcmp( e1->name, e2->name );
+}
+
+static struct Elem *
+searchElem( const char *name )
+{
+    int i;
+    
+    for ( i = 0; i < fetchlist.size; ++i )
+        if ( strcmp( name, fetchlist.elem[ i ].name ) == 0 )
+            return &fetchlist.elem[ i ];
+    return NULL;
+}
+
+static void
+appGrp( const char *name, FetchMode mode )
+{
+    struct Elem elem;
+
+    if ( fetchlist.max < fetchlist.size + 1 )
+    {
+        if ( ! ( fetchlist.elem
+                 = realloc( fetchlist.elem,
+                            ( fetchlist.max + 50 )
+                            * sizeof( fetchlist.elem[ 0 ] ) ) ) )
+        {
+            Log_err( "Could not realloc fetchlist" );
+            exit( EXIT_FAILURE );
+        }
+        fetchlist.max += 50;
+    }
+    strcpy( elem.name, name );
+    elem.mode = mode;
+    fetchlist.elem[ fetchlist.size++ ] = elem;
+}
+
+void
+Fetchlist_read( void )
+{
+    FILE *f;
+    const char *file = getFile();
+    char *p;
+    FetchMode mode = OVER;
+    Bool valid;
+    int ret;
+    Str line, grp, modeStr;
+
+    Log_dbg( "Reading %s", file );
+    clearList();
+    if ( ! ( f = fopen( file, "r" ) ) )
+    {
+        Log_inf( "No file %s", file );
+        return;
+    }
+    while ( fgets( line, MAXCHAR, f ) )
+    {
+        p = Utl_stripWhiteSpace( line );
+        if ( *p == '#' || *p == '\0' )
+            continue;
+        ret = sscanf( p, "%s %s", grp, modeStr );
+        valid = TRUE;
+        if ( ret < 1 || ret > 2 )
+            valid = FALSE;
+        else if ( ret >= 2 )
+        {
+            if ( strcmp( modeStr, "full" ) == 0 )
+                mode = FULL;
+            else if ( strcmp( modeStr, "thread" ) == 0 )
+                mode = THREAD;
+            else if ( strcmp( modeStr, "over" ) == 0 )
+                mode = OVER;
+            else
+                valid = FALSE;
+        }
+        if ( ! valid )
+        {
+            Log_err( "Invalid entry in %s: %s", file, line );
+            continue;
+        }
+        appGrp( grp, mode );
+    }
+    fclose( f );
+}
+
+Bool
+Fetchlist_write( void )
+{
+    int i;
+    FILE *f;
+    const char *file = getFile();
+    const char *modeStr = "";
+
+    qsort( fetchlist.elem, fetchlist.size, sizeof( fetchlist.elem[ 0 ] ),
+           compareElem );
+    if ( ! ( f = fopen( file, "w" ) ) )
+    {
+        Log_err( "Could not open %s for writing", file );
+        return FALSE;
+    }
+    for ( i = 0; i < fetchlist.size; ++i )
+    {
+        switch ( fetchlist.elem[ i ].mode )
+        {
+        case FULL:
+            modeStr = "full"; break;
+        case THREAD:
+            modeStr = "thread"; break;
+        case OVER:
+            modeStr = "over"; break;
+        }
+        fprintf( f, "%s %s\n", fetchlist.elem[ i ].name, modeStr );
+    }
+    fclose( f );
+    return TRUE;
+}
+
+int
+Fetchlist_size( void )
+{
+    return fetchlist.size;
+}
+
+Bool
+Fetchlist_contains( const char *name )
+{
+    return ( searchElem( name ) != NULL );
+}
+
+Bool
+Fetchlist_element( const char **name, FetchMode *mode, int index )
+{
+    if ( index < 0 || index >= fetchlist.size )
+        return FALSE;
+    *name = fetchlist.elem[ index ].name;
+    *mode = fetchlist.elem[ index ].mode;
+    return TRUE;
+}
+
+Bool
+Fetchlist_add( const char *name, FetchMode mode )
+{
+    struct Elem *elem = searchElem( name );
+    if ( elem == NULL )
+    {
+        appGrp( name, mode );
+        return TRUE;
+    }
+    strcpy( elem->name, name );
+    elem->mode = mode;
+    return FALSE;
+}
+
+Bool
+Fetchlist_remove( const char *name )
+{
+    struct Elem *elem = searchElem( name );
+    if ( elem == NULL )
+        return FALSE;
+    *elem = fetchlist.elem[ fetchlist.size - 1 ];
+    --fetchlist.size;
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fetchlist.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,42 @@
+/*
+  fetchlist.h
+
+  List of groups that are to be fetched presently.
+
+  $Id: fetchlist.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef FETCHLIST_H
+#define FETCHLIST_H
+
+#include "common.h"
+
+typedef enum { FULL, THREAD, OVER } FetchMode;
+
+void
+Fetchlist_read( void );
+
+/* Invalidates any indices (list is sorted by name before saving) */
+Bool
+Fetchlist_write( void );
+
+int
+Fetchlist_size( void );
+
+Bool
+Fetchlist_contains( const char *name );
+
+/* Get element number index. */
+Bool
+Fetchlist_element( const char **name, FetchMode *mode, int index );
+
+/* Add entry. Invalidates any indices. Returns TRUE if new entry, FALSE if
+   entry was overwritten. */
+Bool
+Fetchlist_add( const char *name, FetchMode mode );
+
+/* Remove entry. Invalidates any indices. Returns FALSE if not found. */
+Bool
+Fetchlist_remove( const char *name );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/group.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,375 @@
+/*
+  group.c
+
+  The group database resides in groupinfo.gdbm and stores all we know about
+  the groups we know of. One database record is cached in the global struct
+  grp. Group information is transfered between the grp and the database by
+  loadGrp() and saveGrp(). This is done transparently. Access to the groups
+  database is done by group name, by the functions defined in group.h.        
+
+  $Id: group.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "group.h"
+#include <gdbm.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "configfile.h"
+#include "log.h"
+#include "util.h"
+
+/* currently only used within grp */
+typedef struct
+{
+    int first;		/* number of first article within group */
+    int last;		/* number of last article within group */
+    int rmtNext;
+    time_t created;
+    time_t lastAccess;
+} Entry;
+
+struct
+{
+    Str name;		/* name of the group */
+    Entry entry;	/* more information about this group */
+    Str serv;		/* server the group resides on */
+    Str dsc;		/* description of the group */
+    char postAllow;	/* Posting status */
+    GDBM_FILE dbf;
+} grp = { "(no grp)", { 0, 0, 0, 0, 0 }, "", "", ' ', NULL };
+
+/*
+  Note: postAllow should really go in Entry. But changing Entry would
+  make backwards group file format capability tricky, so it goes
+  where it is, and we test the length of the retrieved record to
+  determine if it exists.
+
+  Someday if we really change the record format this should be tidied up.
+ */
+
+static const char *
+errMsg( void )
+{
+    if ( errno != 0 )
+        return strerror( errno );
+    return gdbm_strerror( gdbm_errno );
+}
+
+Bool
+Grp_open( void )
+{
+    Str name;
+    int flags;
+
+    ASSERT( grp.dbf == NULL );
+    snprintf( name, MAXCHAR, "%s/data/groupinfo.gdbm", Cfg_spoolDir() );
+    flags = GDBM_WRCREAT | GDBM_FAST;
+    if ( ! ( grp.dbf = gdbm_open( name, 512, flags, 0644, NULL ) ) )
+    {
+        Log_err( "Error opening %s for r/w (%s)", errMsg() );
+        return FALSE;
+    }
+    Log_dbg( "%s opened for r/w", name );
+    return TRUE;
+}
+
+void
+Grp_close( void )
+{
+    ASSERT( grp.dbf );
+    Log_dbg( "Closing groupinfo" );
+    gdbm_close( grp.dbf );
+    grp.dbf = NULL;
+    Utl_cpyStr( grp.name, "" );
+}
+
+/* Load group info from gdbm-database into global struct grp */
+static Bool
+loadGrp( const char *name )
+{
+    const char *p;
+    datum key, val;
+
+    ASSERT( grp.dbf );
+    if ( strcmp( grp.name, name ) == 0 )
+         return TRUE;
+    key.dptr = (void *)name;
+    key.dsize = strlen( name ) + 1;
+    val = gdbm_fetch( grp.dbf, key );
+    if ( val.dptr == NULL )
+        return FALSE;
+    grp.entry = *( (Entry *)val.dptr );
+    p = val.dptr + sizeof( grp.entry );
+    Utl_cpyStr( grp.serv, p );
+    p += strlen( p ) + 1;
+    Utl_cpyStr( grp.dsc, p );
+    p += strlen( p) + 1;
+    if ( p - val.dptr < val.dsize )
+	grp.postAllow = p[ 0 ];
+    else
+	grp.postAllow = 'y';
+    Utl_cpyStr( grp.name, name );
+    free( val.dptr );
+    return TRUE;
+}
+
+/* Save group info from global struct grp into gdbm-database */
+static void
+saveGrp( void )
+{
+    size_t lenServ, lenDsc, bufLen;
+    datum key, val;
+    void *buf;
+    char *p;
+
+    ASSERT( grp.dbf );
+    lenServ = strlen( grp.serv );
+    lenDsc = strlen( grp.dsc );
+    bufLen = sizeof( grp.entry ) + lenServ + lenDsc + 2 + sizeof( char );
+    buf = malloc( bufLen );
+    memcpy( buf, (void *)&grp.entry, sizeof( grp.entry ) );
+    p = (char *)buf + sizeof( grp.entry );
+    strcpy( p, grp.serv );
+    p += lenServ + 1;
+    strcpy( p, grp.dsc );
+    p += lenDsc + 1;
+    p[ 0 ] = grp.postAllow;
+    key.dptr = (void *)grp.name;
+    key.dsize = strlen( grp.name ) + 1;
+    val.dptr = buf;
+    val.dsize = bufLen;
+    if ( gdbm_store( grp.dbf, key, val, GDBM_REPLACE ) != 0 )
+        Log_err( "Could not save group %s: %s", errMsg() );
+    free( buf );
+}
+
+Bool
+Grp_exists( const char *name )
+{
+    datum key;
+
+    ASSERT( grp.dbf );
+    key.dptr = (void*)name;
+    key.dsize = strlen( name ) + 1;
+    return gdbm_exists( grp.dbf, key );
+}
+
+Bool
+Grp_local( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return ( strcmp( grp.serv, GRP_LOCAL_SERVER_NAME ) == 0 );
+}
+
+void
+Grp_create( const char *name )
+{
+    Utl_cpyStr( grp.name, name );
+    Utl_cpyStr( grp.serv, "(unknown)" );
+    grp.dsc[ 0 ] = '\0';
+    grp.entry.first = 1;
+    grp.entry.last = 0;
+    grp.entry.rmtNext = 0;
+    grp.entry.created = 0;
+    grp.entry.lastAccess = 0;
+    grp.postAllow = 'y';
+    saveGrp();
+}
+
+void
+Grp_delete( const char *name )
+{
+    datum key;
+
+    ASSERT( grp.dbf );
+    key.dptr = (void*)name;
+    key.dsize = strlen( name ) + 1;
+    gdbm_delete( grp.dbf, key );
+}
+
+const char *
+Grp_dsc( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return NULL;
+    return grp.dsc;
+}
+
+const char *
+Grp_serv( const char *name )
+{
+    static Str serv = "";
+
+    if ( ! loadGrp( name ) )
+        return "[unknown grp]";
+    if ( Cfg_servListContains( grp.serv )
+         || Grp_local( name ) )
+        Utl_cpyStr( serv, grp.serv );
+    else
+        snprintf( serv, MAXCHAR, "[%s]", grp.serv );
+    return serv;
+}
+
+int
+Grp_first( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.entry.first;
+}
+
+int
+Grp_last( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.entry.last;
+}
+
+int
+Grp_lastAccess( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.entry.lastAccess;
+}
+
+int
+Grp_rmtNext( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.entry.rmtNext;
+}
+
+time_t
+Grp_created( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.entry.created;
+}
+
+char
+Grp_postAllow( const char *name )
+{
+    if ( ! loadGrp( name ) )
+        return 0;
+    return grp.postAllow;
+}
+
+
+/* Replace group's description (only if value != ""). */
+void
+Grp_setDsc( const char *name, const char *value )
+{
+    if ( loadGrp( name ) )
+    {
+        Utl_cpyStr( grp.dsc, value );
+        saveGrp();
+    }
+}
+
+void
+Grp_setLocal( const char *name )
+{
+    Grp_setServ( name, GRP_LOCAL_SERVER_NAME );
+}
+
+void
+Grp_setServ( const char *name, const char *value )
+{
+    if ( loadGrp( name ) )
+    {
+        Utl_cpyStr( grp.serv, value );
+        saveGrp();
+    }
+}
+
+void
+Grp_setCreated( const char *name, time_t value )
+{
+    if ( loadGrp( name ) )
+    {
+        grp.entry.created = value;
+        saveGrp();
+    }
+}
+
+void
+Grp_setRmtNext( const char *name, int value )
+{
+    if ( loadGrp( name ) )
+    {
+        grp.entry.rmtNext = value;
+        saveGrp();
+    }
+}
+
+void
+Grp_setLastAccess( const char *name, int value )
+{
+    if ( loadGrp( name ) )
+    {
+        grp.entry.lastAccess = value;
+        saveGrp();
+    }
+}
+
+void
+Grp_setPostAllow( const char *name, char postAllow )
+{
+    if ( loadGrp( name ) )
+    {
+        grp.postAllow = postAllow;
+        saveGrp();
+    }
+}
+
+void
+Grp_setFirstLast( const char *name, int first, int last )
+{
+    if ( loadGrp( name ) )
+    {
+        grp.entry.first = first;
+        grp.entry.last = last;
+        saveGrp();
+    }
+}
+
+static datum cursor = { NULL, 0 };
+
+Bool
+Grp_firstGrp( const char **name )
+{
+    ASSERT( grp.dbf );
+    if ( cursor.dptr != NULL )
+    {
+        free( cursor.dptr );
+        cursor.dptr = NULL;
+    }
+    cursor = gdbm_firstkey( grp.dbf );
+    *name = cursor.dptr;
+    return ( cursor.dptr != NULL );
+}
+
+Bool
+Grp_nextGrp( const char **name )
+{
+    void *oldDptr = cursor.dptr;
+
+    ASSERT( grp.dbf );
+    if ( cursor.dptr == NULL )
+        return FALSE;
+    cursor = gdbm_nextkey( grp.dbf, cursor );
+    free( oldDptr );
+    *name = cursor.dptr;
+    return ( cursor.dptr != NULL );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/group.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,114 @@
+/*
+  group.h
+
+  Groups database
+
+  $Id: group.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef GRP_H
+#define GRP_H
+
+#include <time.h>
+#include "common.h"
+
+#define GRP_LOCAL_SERVER_NAME "(local)"
+
+/* open group database */
+Bool
+Grp_open( void );
+
+/* close group database */
+void
+Grp_close( void );
+
+/* does group exist? */
+Bool
+Grp_exists( const char *name );
+
+/* is it a local group? */
+Bool
+Grp_local( const char *name );
+
+/* create new group and save it in database */
+void
+Grp_create( const char *name );
+
+/* delete a group and its articles from the database. */
+void
+Grp_delete( const char *name );
+
+/* Get group description */
+const char *
+Grp_dsc( const char *name );
+
+/* Get server the group resides on */
+const char *
+Grp_serv( const char *name );
+
+/*
+  Get article number of the first article in the group
+  This number is a hint only, it is independent of the
+  real articles in content.c
+*/
+int
+Grp_first( const char *name );
+
+/*
+  Get article number of the last article in the group
+  This number is a hint only, it is independent of the
+  real articles in content.c
+*/
+int
+Grp_last( const char *name );
+
+int
+Grp_lastAccess( const char *name );
+
+int
+Grp_rmtNext( const char *name );
+
+time_t
+Grp_created( const char *name );
+
+char
+Grp_postAllow( const char *name );
+
+/* Replace group's description (only if value != ""). */
+void
+Grp_setDsc( const char *name, const char *value );
+
+void
+Grp_setLocal( const char *name );
+
+void
+Grp_setServ( const char *name, const char *value );
+
+void
+Grp_setCreated( const char *name, time_t value );
+
+void
+Grp_setRmtNext( const char *name, int value );
+
+void
+Grp_setLastAccess( const char *name, int value );
+
+void
+Grp_setFirstLast( const char *name, int first, int last );
+
+void
+Grp_setPostAllow( const char *name, char postAllow );
+
+/* Begin iterating trough the names of all groups. Store name of first
+   group (or NULL if there aren't any) in name. Returns whether there are
+   any groups. */
+Bool
+Grp_firstGrp( const char **name );
+
+/* Continue iterating trough the names of all groups. Store name of next
+   group (or NULL if there aren't any more) in name. Returns TRUE on
+   success, FALSE when there are no more groups. */
+Bool
+Grp_nextGrp( const char **name );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/itemlist.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,123 @@
+/*
+  itemlist.c
+
+  $Id: itemlist.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include "itemlist.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "log.h"
+
+struct ItemList
+{
+    char *list;
+    char *separators;
+    char *next;
+    size_t count;
+};
+
+/* Make a new item list. */
+ItemList *
+new_Itl( const char *list, const char *separators )
+{
+    ItemList * res;
+    char *p;
+    Bool inItem;
+
+    res = (ItemList *) malloc( sizeof( ItemList ) );
+    if ( res == NULL )
+    {
+	Log_err( "Malloc of ItemList failed." );
+	exit( EXIT_FAILURE );
+    }
+    
+    res->list = (char *) malloc ( strlen(list) + 2 );
+    if ( res->list == NULL )
+    {
+	Log_err( "Malloc of ItemList.list failed." );
+	exit( EXIT_FAILURE );
+    }
+    strcpy( res->list, list );
+
+    if (  ( res->separators = strdup( separators ) ) == NULL )
+    {
+	Log_err( "Malloc of ItemList.separators failed." );
+	exit( EXIT_FAILURE );
+    }
+
+    res->count = 0;
+    res->next = res->list;
+
+    /* Separate items into strings and have final zero-length string. */
+    for( p = res->list, inItem = FALSE; *p != '\0'; p++ )
+    {
+	Bool isSep = ( strchr( separators, p[ 0 ] ) != NULL );
+	
+	if ( inItem )
+	{
+	    if ( isSep )
+	    {
+		p[ 0 ] = '\0';
+		inItem = FALSE;
+		res->count++;
+	    }
+	}
+	else
+	{
+	    if ( ! isSep )
+		inItem = TRUE;
+	}
+    }
+    if ( inItem )
+	res->count++;
+    p[ 1 ] = '\0';
+    return res;
+}
+
+/* Delete an item list. */
+void
+del_Itl( ItemList *self )
+{
+    if ( self == NULL )
+	return;
+    free( self->list );
+    free( self->separators );
+    free( self );
+}
+
+/* Get first item. */
+const char *
+Itl_first( ItemList *self)
+{
+    self->next = self->list;
+    return Itl_next( self );
+}
+
+/* Get next item or NULL. */
+const char *
+Itl_next( ItemList *self )
+{
+    const char *res = self->next;
+
+    if ( res[ 0 ] == '\0' )
+	return NULL;
+
+    while ( strchr( self->separators, res[ 0 ] ) != NULL )
+	res++;
+
+    if ( res[ 0 ] == '\0' && res[ 1 ] == '\0' )
+	return NULL;
+
+    self->next += strlen( res ) + 1;
+    return res;
+}
+
+/* Get count of items in list. */
+size_t
+Itl_count( const ItemList *self )
+{
+    return self->count;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/itemlist.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,38 @@
+/*
+  itemlist.h
+
+  Copy a string wiht a list of separated items (as found in several
+  header lines) and provide a convenient way of accessing the
+  individual items.
+  
+  $Id: itemlist.h 49 2000-05-05 21:45:56Z uh1763 $ */
+
+#ifndef ITEMLIST_H
+#define ITEMLIST_H
+
+#include <sys/types.h>
+
+struct ItemList;
+typedef struct ItemList ItemList;
+
+/* Make a new item list. */
+ItemList *
+new_Itl( const char *list, const char *separators );
+
+/* Delete an item list. */
+void
+del_Itl( ItemList *self );
+
+/* Get first item. */
+const char *
+Itl_first( ItemList *self);
+
+/* Get next item or NULL. */
+const char *
+Itl_next( ItemList *self );
+
+/* Get count of items in list. */
+size_t
+Itl_count( const ItemList *self );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lock.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,131 @@
+/*
+  lock.c
+
+  $Id: lock.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "lock.h"
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include "configfile.h"
+#include "log.h"
+#include "database.h"
+#include "group.h"
+#include "request.h"
+
+struct Lock
+{
+    int lockFd;
+    Str lockFile;
+} lock = { -1, "" };
+
+
+#ifdef DEBUG
+static Bool
+testLock( void )
+{
+    return ( lock.lockFd != -1 );    
+}
+#endif
+
+static Bool
+waitLock( void )
+{
+    int fd;
+    struct flock l;
+
+    ASSERT( ! testLock() );
+    Log_dbg( "Waiting for lock ..." );
+    snprintf( lock.lockFile, MAXCHAR, "%s/lock/global", Cfg_spoolDir() );
+    if ( ( fd = open( lock.lockFile, O_WRONLY | O_CREAT, 0644 ) ) < 0 )
+    {
+        Log_err( "Cannot open %s (%s)", lock.lockFile, strerror( errno ) );
+        return FALSE;
+    }
+    l.l_type = F_WRLCK;
+    l.l_start = 0;
+    l.l_whence = SEEK_SET;
+    l.l_len = 0;
+    if ( fcntl( fd, F_SETLKW, &l ) < 0 )
+    {
+        Log_err( "Cannot lock %s: %s", lock.lockFile, strerror( errno ) );
+        return FALSE;
+    }
+    lock.lockFd = fd;
+    Log_dbg( "Lock successful" );
+    return TRUE;
+}
+
+static void
+releaseLock( void )
+{
+    struct flock l;
+
+    ASSERT( testLock() );    
+    l.l_type = F_UNLCK;
+    l.l_start = 0;
+    l.l_whence = SEEK_SET;
+    l.l_len = 0;
+    if ( fcntl( lock.lockFd, F_SETLK, &l ) < 0 )
+        Log_err( "Cannot release %s: %s", lock.lockFile,
+                 strerror( errno ) );
+    close( lock.lockFd );
+    lock.lockFd = -1;
+    Log_dbg( "Releasing lock" );
+}
+
+
+/* Open all databases and set global lock. */
+Bool
+Lock_openDatabases( void )
+{
+  if ( ! waitLock() )
+    {
+      Log_err( "Could not get write lock" );
+      return FALSE;
+    }
+  if ( ! Db_open() )
+    {
+      Log_err( "Could not open database" );
+      releaseLock();
+      return FALSE;
+    }
+  if ( ! Grp_open() )
+    {
+      Log_err( "Could not open groupinfo" );
+      Db_close();
+      releaseLock();
+      return FALSE;
+    }
+  if ( ! Req_open() )
+    {
+      Log_err( "Could not initialize request database" );
+      Grp_close();
+      Db_close();
+      releaseLock();
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+
+/* Close all databases and release global lock. */
+void
+Lock_closeDatabases( void )
+{
+  Grp_close();
+  Db_close();
+  Req_close();
+  releaseLock();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lock.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,24 @@
+/*
+  lock.h
+
+  Opening/Closing of the various databases: article overview database,
+  articla database, groups database, outgoing articles database, requests
+  database. Handles global lock.
+
+  $Id: lock.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef LOCK_H
+#define LOCK_H
+
+#include "common.h"
+
+/* Open all databases and set global lock. */
+Bool
+Lock_openDatabases( void );
+
+/* Close all databases and release global lock. */
+void
+Lock_closeDatabases( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/log.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,75 @@
+/*
+  log.c
+
+  $Id: log.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include <syslog.h>
+#include <stdarg.h>
+#include "common.h"
+
+#define MAXLENGTH 240
+
+struct
+{
+    Bool interactive;
+} log = { FALSE };
+
+void
+Log_init( Str name, Bool interactive, int facility )
+{
+    int option = LOG_PID | LOG_CONS;
+
+    log.interactive = interactive;
+    openlog( name, option, facility );
+}
+
+#define DO_LOG( LEVEL )               \
+    va_list ap;                       \
+    Str t;                            \
+                                      \
+    va_start( ap, fmt );              \
+    vsnprintf( t, MAXCHAR, fmt, ap ); \
+    if ( MAXLENGTH < MAXCHAR )        \
+        t[ MAXLENGTH ] = '\0';        \
+    syslog( LEVEL, "%s", t );         \
+    if ( log.interactive )            \
+        fprintf( stderr, "%s\n", t );   \
+    va_end( ap );
+
+void
+Log_inf( const char *fmt, ... )
+{
+    DO_LOG( LOG_INFO );
+}
+
+void
+Log_err( const char *fmt, ... )
+{
+    DO_LOG( LOG_ERR );
+}
+
+/* Ensure the condition "cond" is true; otherwise log an error and return 1 */
+int 
+Log_check(int cond, const char *fmt, ... )
+{
+  if (!cond) {
+    DO_LOG( LOG_ERR );
+    return 1;
+  }
+  return 0;
+}
+
+void
+Log_ntc( const char *fmt, ... )
+{
+    DO_LOG( LOG_NOTICE );
+}
+
+void
+Log_dbg( const char *fmt, ... )
+{
+#ifdef DEBUG
+    DO_LOG( LOG_DEBUG );
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/log.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,43 @@
+/*
+  log.h
+
+  Print log messages to syslog, stdout/stderr.
+
+  $Id: log.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef LOG_H
+#define LOG_H
+
+#include "common.h"
+
+/*
+  Initialise logging (required before using any log functions).
+  name: program name for syslog
+  interactive: print messages also to stderr/stdout
+  facility: like syslog
+*/
+void
+Log_init( Str name, Bool interactive, int facility );
+
+/* Log level info */
+void
+Log_inf( const char *fmt, ... );
+
+/* Log level error */
+void
+Log_err( const char *fmt, ... );
+
+/* Check for cond being true. Otherwise log an error, and return 1. */
+int 
+Log_check(int cond, const char *fmt, ... );
+
+/* Log level notice */
+void
+Log_ntc( const char *fmt, ... );
+
+/* Log only if DEBUG is defined. */
+void
+Log_dbg( const char *fmt, ... );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/noffle.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,798 @@
+/*
+  noffle.c
+
+  Main program. Implements specified actions, but running as server, which
+  is done by Serv_run(), declared in server.h.
+  
+  Locking policy: lock access to databases while noffle is running, but
+  not as server. If noffle runs as server, locking is performed while
+  executing NNTP commands, but temporarily released if no new command is
+  received for some seconds (to allow multiple clients connect at the same
+  time).
+
+  $Id: noffle.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "client.h"
+#include "common.h"
+#include "content.h"
+#include "control.h"
+#include "configfile.h"
+#include "database.h"
+#include "fetch.h"
+#include "fetchlist.h"
+#include "group.h"
+#include "itemlist.h"
+#include "log.h"
+#include "online.h"
+#include "outgoing.h"
+#include "over.h"
+#include "pseudo.h"
+#include "util.h"
+#include "server.h"
+#include "request.h"
+#include "lock.h"
+
+struct Noffle
+{
+    Bool queryGrps;
+    Bool queryDsc;
+    Bool queryTimes;
+    Bool interactive;
+} noffle = { FALSE, FALSE, FALSE, TRUE };
+
+static void
+doArt( const char *msgId )
+{
+    const char *id;
+
+    if ( strcmp( msgId, "all" ) == 0 )
+    {
+        if ( ! Db_first( &id ) )
+            fprintf( stderr, "Database empty.\n" );
+        else
+            do
+            {
+                printf( "From %s %s\n"
+                        "%s\n"
+                        "%s\n",
+                        Db_from( id ), Db_date( id ),
+                        Db_header( id ),
+                        Db_body( id ) );
+            }
+            while ( Db_next( &id ) );
+    }
+    else
+    {
+        if ( ! Db_contains( msgId ) )
+            fprintf( stderr, "Not in database.\n" );
+        else
+            printf( "%s\n%s", Db_header( msgId ), Db_body( msgId ) );
+    }
+}
+
+static void
+doCancel( const char *msgId )
+{
+    switch( Ctrl_cancel( msgId ) )
+    {
+    case CANCEL_NO_SUCH_MSG:
+	printf( "No such message '%s'.\n", msgId );
+	break;
+
+    case CANCEL_OK:
+	printf( "Message '%s' cancelled.\n", msgId );
+	break;
+
+    case CANCEL_NEEDS_MSG:
+	printf( "Message '%s' cancelled in local database only.\n", msgId );
+	break;
+    }
+}
+
+/* List articles requested from one particular server */
+static void
+listRequested1( const char* serv )
+{
+  Str msgid;
+
+  if ( ! Req_first( serv, msgid ) )
+      return;
+  do
+      printf( "%s %s\n", msgid, serv );
+  while ( Req_next( msgid ) );
+}
+
+/* List requested articles. List for all servers if serv = "all" or serv =
+   NULL. */
+void
+doRequested( const char *arg )
+{
+    Str serv;
+    
+    if ( ! arg || ! strcmp( arg, "all" ) )
+    {
+        Cfg_beginServEnum();   
+        while ( Cfg_nextServ( serv ) )
+            listRequested1( serv );
+    }   
+    else
+        listRequested1( arg );
+}
+
+
+static void
+doDb( void )
+{
+    const char *msgId;
+
+    if ( ! Db_first( &msgId ) )
+        fprintf( stderr, "Database empty.\n" );
+    else
+        do
+            printf( "%s\n", msgId );
+        while ( Db_next( &msgId ) );
+}
+
+static void
+doFetch( void )
+{
+    Str serv;
+
+    Cfg_beginServEnum();
+    while ( Cfg_nextServ( serv ) )
+        if ( Fetch_init( serv ) )
+        {
+            Fetch_postArts();
+
+            Fetch_getNewGrps();
+
+            /* Get overviews of new articles and store IDs of new articles
+               that are to be fetched becase of FULL or THREAD mode in the
+               request database. */
+            Fetch_updateGrps();         
+
+            /* get requested articles */
+            Fetch_getReq_();
+
+            Fetch_close();
+        }
+}
+
+static void
+doQuery( void )
+{
+    Str serv;
+
+    Cfg_beginServEnum();
+    while ( Cfg_nextServ( serv ) )
+        if ( Fetch_init( serv ) )
+        {
+            if ( noffle.queryGrps )
+                Client_getGrps();
+            if ( noffle.queryDsc )
+                Client_getDsc();
+            if ( noffle.queryTimes )
+                Client_getCreationTimes();
+            Fetch_close();
+        }
+}
+
+/* Expire all overviews not in database */
+static void
+expireContents( void )
+{
+    const Over *ov;
+    int i;
+    int cntDel, cntLeft;
+    Str grp;
+    Bool autoUnsubscribe;
+    int autoUnsubscribeDays;
+    time_t now = time( NULL ), maxAge = 0;
+    const char *msgId;
+
+    autoUnsubscribe = Cfg_autoUnsubscribe();
+    autoUnsubscribeDays = Cfg_autoUnsubscribeDays();
+    maxAge = Cfg_autoUnsubscribeDays() * 24 * 3600;
+    if ( ! Cont_firstGrp( grp ) )
+        return;
+    Log_inf( "Expiring overviews not in database" );
+    do
+    {
+        if ( ! Grp_exists( grp ) )
+            Log_err( "Overview file for unknown group %s exists", grp );
+        else
+        {
+            cntDel = cntLeft = 0;
+            Cont_read( grp );
+            for ( i = Cont_first(); i <= Cont_last(); ++i )
+                if ( ( ov = Cont_get( i ) ) )
+                {
+                    msgId = Ov_msgId( ov );
+                    if ( ! Db_contains( msgId ) )
+                    {
+                        Cont_delete( i );
+                        ++cntDel;
+                    }
+                    else
+                        ++cntLeft;
+                }
+            if ( ! Grp_local( grp )
+		 && autoUnsubscribe
+                 && difftime( now, Grp_lastAccess( grp ) ) > maxAge )
+            {
+                Log_ntc( "Auto-unsubscribing from %s after %d "
+                         "days without access",
+                         grp, autoUnsubscribeDays );
+                Pseudo_autoUnsubscribed( grp, autoUnsubscribeDays );
+                Fetchlist_read();
+                Fetchlist_remove( grp );
+                Fetchlist_write();
+            }
+            Cont_write();
+            Grp_setFirstLast( grp, Cont_first(), Cont_last() );
+            Log_inf( "%ld overviews deleted from group %s, %ld left (%ld-%ld)",
+                     cntDel, grp, cntLeft, Grp_first( grp ), Grp_last( grp ) );
+        }
+    }
+    while ( Cont_nextGrp( grp ) );
+}
+
+static void
+doExpire( void )
+{
+    Db_close();
+    Db_expire();
+    if ( ! Db_open() )
+        return;
+    expireContents();
+}
+
+static void
+doCreateLocalGroup( const char * name )
+{
+    Str grp;
+
+    Utl_cpyStr( grp, name );
+    Utl_toLower( grp );
+    name = Utl_stripWhiteSpace( grp );
+    
+    if ( Grp_exists( name ) )
+        fprintf( stderr, "'%s' already exists.\n", name );
+    else
+    {
+        Log_inf( "Creating new local group '%s'", name );
+        Grp_create( name );
+        Grp_setLocal( name );
+	printf( "New local group '%s' created.\n", name );
+    }
+}
+
+static void
+doDeleteLocalGroup( const char * name )
+{
+    Str grp;
+
+    Utl_cpyStr( grp, name );
+    Utl_toLower( grp );
+    name = Utl_stripWhiteSpace( grp );
+    
+    if ( ! Grp_exists( name ) )
+        fprintf( stderr, "'%s' does not exist.\n", name );
+    else
+    {
+	int i;
+	
+        Log_inf( "Deleting group '%s'", name );
+
+	/*
+	  Delete all articles that are only in the group. Check the
+	  article Xref for more than one group.
+	 */
+	Cont_read( name );
+	for ( i = Cont_first(); i <= Cont_last(); i++ )
+	{
+	    const Over *over;
+	    Bool toDelete;
+	    Str msgId;
+
+	    over = Cont_get( i );
+	    toDelete = TRUE;
+	    if ( over != NULL )
+	    {
+		ItemList * xref;
+
+		Utl_cpyStr( msgId, Ov_msgId( over ) );
+		xref = new_Itl( Db_xref( msgId ), " " );
+		if ( Itl_count( xref ) > 1 )
+		    toDelete = FALSE;
+		del_Itl( xref );
+	    }
+	    Cont_delete( i );
+	    if ( toDelete )
+		Db_delete( msgId );
+	}
+	Cont_write();
+	Grp_delete( name );
+	printf( "Group '%s' deleted.\n", name );
+    }
+}
+
+static void
+doList( void )
+{
+    FetchMode mode;
+    int i, size;
+    const char *name, *modeStr = "";
+
+    Fetchlist_read();
+    size = Fetchlist_size();
+    if ( size == 0 )
+        fprintf( stderr, "Fetch list is empty.\n" );
+    else
+        for ( i = 0; i < size; ++i )
+        {
+            Fetchlist_element( &name, &mode, i );
+            switch ( mode )
+            {
+            case FULL:
+                modeStr = "full"; break;
+            case THREAD:
+                modeStr = "thread"; break;
+            case OVER:
+                modeStr = "over"; break;
+            }
+            printf( "%s %s %s\n", name, Grp_serv( name ), modeStr );
+        }
+}
+
+/* A modify command. argc/argv start AFTER '-m'. */
+static Bool
+doModify( const char *cmd, int argc, char **argv )
+{
+    const char *grp;
+
+    if ( argc < 2 )
+    {
+	fprintf( stderr, "Insufficient arguments to -m\n" );
+	return FALSE;
+	
+    }
+    else if ( strcmp( cmd, "desc" ) != 0
+	      && strcmp( cmd, "post" ) != 0 )
+    {
+	fprintf( stderr, "Unknown argument -m %s\n", optarg );
+	return FALSE;
+    }
+    
+    grp = argv[ 0 ];
+    argv++;
+    argc--;
+    
+    if ( strcmp( cmd, "desc" ) == 0 )
+    {
+	Str desc;
+
+	Utl_cpyStr( desc, *( argv++ ) );
+	while ( --argc > 0 )
+	{
+	    Utl_catStr( desc, " " );
+	    Utl_catStr( desc, *( argv++ ) );
+	}
+
+	Grp_setDsc( grp, desc );
+    }
+    else
+    {
+	char c;
+
+	if ( ! Grp_local( grp ) )
+	{
+	    fprintf( stderr, "%s is not a local group\n", grp );
+	    return FALSE;
+	}
+	
+	c = **argv;
+	if ( c == 'y' || c == 'm' || c == 'n' )
+	    Grp_setPostAllow( grp, c );
+	else
+	{
+	    fprintf( stderr, "Access must be 'y', 'n' or 'm'" );
+	    return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+static void
+doGrps( void )
+{
+    const char *g;
+    Str dateLastAccess, dateCreated;
+    time_t lastAccess, created;
+
+    if ( Grp_firstGrp( &g ) )
+        do
+        {
+            lastAccess = Grp_lastAccess( g );
+            created = Grp_created( g );
+            ASSERT( lastAccess >= 0 );
+            ASSERT( created >= 0 );
+            strftime( dateLastAccess, MAXCHAR, "%Y-%m-%d %H:%M:%S",
+                      localtime( &lastAccess ) );
+            strftime( dateCreated, MAXCHAR, "%Y-%m-%d %H:%M:%S",
+                      localtime( &created ) );
+            printf( "%s\t%s\t%i\t%i\t%i\t%c\t%s\t%s\t%s\n",
+                    g, Grp_serv( g ), Grp_first( g ), Grp_last( g ),
+                    Grp_rmtNext( g ), Grp_postAllow( g ), dateCreated,
+                    dateLastAccess, Grp_dsc( g ) );
+        }
+        while ( Grp_nextGrp( &g ) );
+}
+
+static Bool
+doSubscribe( const char *name, FetchMode mode )
+{
+    if ( ! Grp_exists( name ) )
+    {
+        fprintf( stderr, "%s is not available at remote servers.\n", name );
+        return FALSE;
+    }
+    Fetchlist_read();
+    if ( Fetchlist_add( name, mode ) )
+        printf( "Adding %s to fetch list in %s mode.\n",
+                name, mode == FULL ? "full" : mode == THREAD ?
+                "thread" : "overview" );
+    else
+        printf( "%s is already in fetch list. Mode is now: %s.\n",
+                name, mode == FULL ? "full" : mode == THREAD ?
+                "thread" : "overview" );
+    if ( ! Fetchlist_write() )
+        fprintf( stderr, "Could not save fetchlist.\n" );
+    return TRUE;
+}
+
+static void
+doUnsubscribe( const char *name )
+{
+    Fetchlist_read();
+    if ( ! Fetchlist_remove( name ) )
+        printf( "%s is not in fetch list.\n", name );
+    else
+        printf( "%s removed from fetch list.\n", name );
+    if ( ! Fetchlist_write() )
+        fprintf( stderr, "Could not save fetchlist.\n" );
+}
+
+static void
+printUsage( void )
+{
+    static const char *msg =
+      "Usage: noffle <option>\n"
+      "Option is one of the following:\n"
+      " -a | --article <msg id>|all      Show article(s) in database\n"
+      " -c | --cancel <msg id>           Remove article from database\n"
+      " -C | --create <grp>              Create a local group\n"
+      " -d | --database                  Show content of article database\n"
+      " -D | --delete <grp>              Delete a group\n"
+      " -e | --expire                    Expire articles\n"
+      " -f | --fetch                     Get newsfeed from server/post articles\n"
+      " -g | --groups                    Show all groups available at server\n"
+      " -h | --help                      Show this text\n"
+      " -l | --list                      List groups on fetch list\n"
+      " -m | --modify desc <grp> <desc>  Modify a group description\n"
+      " -m | --modify post <grp> (y|n)   Modify posting status of a local group\n"
+      " -n | --online                    Switch to online mode\n"
+      " -o | --offline                   Switch to offline mode\n"
+      " -q | --query groups              Get group list from server\n"
+      " -q | --query desc                Get group descriptions from server\n"
+      " -q | --query times               Get group creation times from server\n"
+      " -r | --server                    Run as server on stdin/stdout\n"
+      " -R | --requested                 List articles marked for download\n"
+      " -s | --subscribe-over <grp>      Add group to fetch list (overview)\n"
+      " -S | --subscribe-full <grp>      Add group to fetch list (full)\n"
+      " -t | --subscribe-thread <grp>    Add group to fetch list (thread)\n"
+      " -u | --unsubscribe <grp>         Remove group from fetch list\n"
+      " -v | --version                   Print version\n";
+    fprintf( stderr, "%s", msg );
+}
+
+/*
+  Allow core files: Change core limit and change working directory
+  to spool directory, where news has write permissions.
+*/
+static void
+enableCorefiles()
+{
+    struct rlimit lim;
+
+    if ( getrlimit( RLIMIT_CORE, &lim ) != 0 )
+    {
+        Log_err( "Cannot get system core limit: %s", strerror( errno ) );
+        return;
+    }
+    lim.rlim_cur = lim.rlim_max;
+    if ( setrlimit( RLIMIT_CORE, &lim ) != 0 )
+    {
+        Log_err( "Cannot set system core limit: %s", strerror( errno ) );
+        return;
+    }
+    Log_dbg( "Core limit set to %i", lim.rlim_max );
+    if ( chdir( Cfg_spoolDir() ) != 0 )
+    {
+         Log_err( "Cannot change to directory '%s'", Cfg_spoolDir() );
+         return;
+    }
+    Log_dbg( "Changed to directory '%s'", Cfg_spoolDir() );
+}
+
+static Bool
+initNoffle( Bool interactive )
+{
+    Log_init( "noffle", interactive, LOG_NEWS );
+    Cfg_read();
+    Log_dbg( "NOFFLE version %s", Cfg_version() );
+    noffle.interactive = interactive;
+    if ( interactive )
+      if ( ! Lock_openDatabases() )
+        return FALSE;
+    if ( ! interactive )
+        enableCorefiles();
+    return TRUE;
+}
+
+static void
+closeNoffle( void )
+{
+    if ( noffle.interactive )
+      Lock_closeDatabases();
+}
+
+static void
+bugReport( int sig )
+{
+    Log_err( "Received SIGSEGV. Please submit a bug report" );
+    signal( SIGSEGV, SIG_DFL );
+    raise( sig );
+}
+
+static void
+logSignal( int sig )
+{
+    const char *name;
+    Bool err = TRUE;
+
+    switch ( sig )
+    {
+    case SIGABRT:
+        name = "SIGABRT"; break;
+    case SIGFPE:
+        name = "SIGFPE"; break;
+    case SIGILL:
+        name = "SIGILL"; break;
+    case SIGINT:
+        name = "SIGINT"; break;
+    case SIGTERM:
+        name = "SIGTERM"; break;
+    case SIGPIPE:
+        name = "SIGPIPE"; err = FALSE; break;
+    default:
+        name = "?"; break;
+    }
+    if ( err )
+        Log_err( "Received signal %i (%s). Aborting.", sig, name );
+    else
+        Log_inf( "Received signal %i (%s). Aborting.", sig, name );
+    signal( sig, SIG_DFL );
+    raise( sig );
+}
+
+int main ( int argc, char **argv )
+{
+    int c, result;
+    struct option longOptions[] =
+    {
+        { "article",          required_argument, NULL, 'a' },
+        { "cancel",           required_argument, NULL, 'c' },
+        { "create",           required_argument, NULL, 'C' },
+        { "database",         no_argument,       NULL, 'd' },
+        { "delete",           required_argument, NULL, 'D' },
+        { "expire",           no_argument,       NULL, 'e' },
+        { "fetch",            no_argument,       NULL, 'f' },
+        { "groups",           no_argument,       NULL, 'g' },
+        { "help",             no_argument,       NULL, 'h' },
+        { "list",             no_argument,       NULL, 'l' },
+        { "modify",           required_argument, NULL, 'm' },
+        { "offline",          no_argument,       NULL, 'o' },
+        { "online",           no_argument,       NULL, 'n' },
+        { "query",            required_argument, NULL, 'q' },
+        { "server",           no_argument,       NULL, 'r' },
+        { "requested",        no_argument,       NULL, 'R' },
+        { "subscribe-over",   required_argument, NULL, 's' },
+        { "subscribe-full",   required_argument, NULL, 'S' },
+        { "subscribe-thread", required_argument, NULL, 't' },
+        { "unsubscribe",      required_argument, NULL, 'u' },
+        { "version",          no_argument,       NULL, 'v' },
+        { NULL, 0, NULL, 0 }
+    };
+    
+    signal( SIGSEGV, bugReport );
+    signal( SIGABRT, logSignal );
+    signal( SIGFPE, logSignal );
+    signal( SIGILL, logSignal );
+    signal( SIGINT, logSignal );
+    signal( SIGTERM, logSignal );
+    signal( SIGPIPE, logSignal );
+    c = getopt_long( argc, argv, "a:c:C:dD:efghlm:onq:rRs:S:t:u:v",
+                     longOptions, NULL );
+    if ( ! initNoffle( c != 'r' ) )
+        return EXIT_FAILURE;
+    result = EXIT_SUCCESS;
+    switch ( c )
+    {
+    case 0:
+        /* Options that set a flag. */
+        break;
+    case 'a':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -a needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doArt( optarg );
+        break;
+    case 'c':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -c needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doCancel( optarg );
+        break;
+    case 'C':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -C needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doCreateLocalGroup( optarg );
+        break;
+    case 'd':
+        doDb();
+        break;
+    case 'D':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -D needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doDeleteLocalGroup( optarg );
+        break;
+    case 'e':
+	doExpire();
+	break;
+    case 'f':
+        doFetch();
+        break;
+    case 'g':
+        doGrps();
+        break;
+    case -1:
+    case 'h':
+        printUsage();
+        break;
+    case 'l':
+        doList();
+        break;
+    case 'm':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -m needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+	    if ( ! doModify( optarg, argc - optind, &argv[ optind ] ) )
+		result = EXIT_FAILURE;
+        break;
+    case 'n':
+        if ( Online_true() )
+            fprintf( stderr, "NOFFLE is already online\n" );
+        else
+            Online_set( TRUE );
+        break;
+    case 'o':
+        if ( ! Online_true() )
+            fprintf( stderr, "NOFFLE is already offline\n" );
+        else
+            Online_set( FALSE );
+        break;
+    case 'q':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -q needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+        {
+            if ( strcmp( optarg, "groups" ) == 0 )
+                noffle.queryGrps = TRUE;
+            else if ( strcmp( optarg, "desc" ) == 0 )
+                noffle.queryDsc = TRUE;
+            else if ( strcmp( optarg, "times" ) == 0 )
+                noffle.queryTimes = TRUE;
+            else
+            {
+                fprintf( stderr, "Unknown argument -q %s\n", optarg );
+                result = EXIT_FAILURE;
+            }
+            doQuery();
+        }
+        break;
+    case 'r':
+        Log_inf( "Starting as server" );
+        Serv_run();
+        break;
+    case 'R':
+        doRequested( optarg );
+        break;
+    case 's':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -s needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            result = doSubscribe( optarg, OVER );
+        break;
+    case 'S':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -S needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doSubscribe( optarg, FULL );
+        break;
+    case 't':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -t needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            result = doSubscribe( optarg, THREAD );
+        break;
+    case 'u':
+        if ( ! optarg )
+        {
+            fprintf( stderr, "Option -u needs argument.\n" );
+            result = EXIT_FAILURE;
+        }
+        else
+            doUnsubscribe( optarg );
+        break;
+    case '?':
+        /* Error message already printed by getopt_long */
+        result = EXIT_FAILURE;
+        break;
+    case 'v':
+        printf( "NNTP server NOFFLE, version %s.\n", Cfg_version() );
+        break;
+    default:
+        abort(); /* Never reached */
+    }
+    closeNoffle();
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/online.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,62 @@
+/*
+  online.c
+
+  $Id: online.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include "common.h"
+#include "configfile.h"
+#include "log.h"
+
+static void
+fileOnline( Str s )
+{
+    snprintf( s, MAXCHAR, "%s/lock/online", Cfg_spoolDir() );
+}
+
+Bool
+Online_true( void )
+{
+    FILE *f;
+    Str file;
+
+    fileOnline( file );
+    if ( ! ( f = fopen( file, "r" ) ) )
+        return FALSE;
+    fclose( f );
+    return TRUE;
+}
+
+void
+Online_set( Bool value )
+{
+    FILE *f;
+    Str file;
+
+    fileOnline( file );
+    if ( value )
+    {
+        if ( ! ( f = fopen( file, "a" ) ) )
+        {
+            Log_err( "Could not create %s", file );
+            return;
+        }
+        fclose( f );
+        Log_inf( "NOFFLE is now online" );
+    }
+    else
+    {
+        if ( unlink( file ) != 0 )
+        {
+            Log_err( "Cannot remove %s", file );
+            return;
+        }
+        Log_inf( "NOFFLE is now offline" );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/online.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,18 @@
+/*
+  online.h
+
+  Online/offline status.
+
+  $Id: online.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef ONLINE_H
+#define ONLINE_H
+
+Bool
+Online_true( void );
+
+void
+Online_set( Bool value );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/outgoing.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,168 @@
+/*
+  outgoing.c
+
+  $Id: outgoing.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "outgoing.h"
+
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include "configfile.h"
+#include "log.h"
+#include "util.h"
+
+struct Outgoing
+{
+    DIR *dir;
+    Str serv;
+} outgoing = { NULL, "" };
+
+static void
+fileOutgoing( Str file, const char *serv, const char *msgId )
+{
+    snprintf( file, MAXCHAR, "%s/outgoing/%s/%s",
+              Cfg_spoolDir(), serv, msgId );
+}
+
+static void
+createDir( const char *serv )
+{
+    Str dir;
+    int r;
+
+    snprintf( dir, MAXCHAR, "%s/outgoing/%s", Cfg_spoolDir(), serv );
+    r = mkdir( dir, 0755 );
+    if ( r != 0 )
+        Log_dbg( "mkdir: %s", strerror( errno ) );
+}
+
+Bool
+Out_add( const char *serv, const char *msgId, const DynStr *artTxt )
+{
+    Str file;
+    FILE *f;
+
+    fileOutgoing( file, serv, msgId );
+    if ( ! ( f = fopen( file, "w" ) ) )
+    {
+        createDir( serv );
+        if ( ! ( f = fopen( file, "w" ) ) )
+        {
+            Log_err( "Cannot open %s", file );
+            return FALSE;
+        }
+    }
+    fprintf( f, "%s", DynStr_str( artTxt ) );
+    fclose( f );
+    return TRUE;
+}
+
+Bool
+Out_first( const char *serv, Str msgId, DynStr *artTxt )
+{
+    Str file;
+    
+    snprintf( file, MAXCHAR, "%s/outgoing/%s", Cfg_spoolDir(), serv );
+    if ( ! ( outgoing.dir = opendir( file ) ) )
+    {
+        Log_dbg( "Cannot open %s", file );
+        return FALSE;
+    }
+    Utl_cpyStr( outgoing.serv, serv );
+    Out_next( NULL, NULL ); /* "."  */
+    Out_next( NULL, NULL ); /* ".." */
+    return Out_next( msgId, artTxt );
+}
+
+Bool
+Out_next( Str msgId, DynStr *artTxt )
+{
+    struct dirent *d;
+    FILE *f;
+    Str file, line;
+
+    ASSERT( outgoing.dir );
+    if ( ! ( d = readdir( outgoing.dir ) ) )
+    {
+        closedir( outgoing.dir );
+        outgoing.dir = NULL;
+        return FALSE;
+    }
+    if ( artTxt == NULL )
+        return ( d->d_name != NULL );
+    fileOutgoing( file, outgoing.serv, d->d_name );
+    if ( ! ( f = fopen( file, "r" ) ) )
+    {
+        Log_err( "Cannot open %s for read", file );
+        return FALSE;
+    }
+    DynStr_clear( artTxt );
+    while ( fgets( line, MAXCHAR, f ) )
+        DynStr_app( artTxt, line );
+    Utl_cpyStr( msgId, d->d_name );
+    fclose( f );
+    return TRUE;
+}
+
+void
+Out_remove( const char *serv, const char *msgId )
+{
+    Str file;
+
+    fileOutgoing( file, serv, msgId );
+    if ( unlink( file ) != 0 )
+        Log_err( "Cannot remove %s", file );
+}
+
+Bool
+Out_find( const char *msgId, Str server )
+{
+    Str servdir;
+    DIR *d;
+    struct dirent *entry;
+    Bool res;
+    
+    
+    snprintf( servdir, MAXCHAR, "%s/outgoing", Cfg_spoolDir() );
+    if ( ! ( d = opendir( servdir ) ) )
+    {
+        Log_dbg( "Cannot open %s", servdir );
+        return FALSE;
+    }
+
+    readdir( d );	/* '.' */
+    readdir( d );	/* '..' */
+
+    res = FALSE;
+    while ( ! res && ( entry = readdir( d ) ) != NULL )
+    {
+	Str file;
+	struct stat s;
+
+	fileOutgoing( file, entry->d_name, msgId );
+	if ( stat( file, &s ) == 0 )
+	{
+	    res = TRUE;
+	    Utl_cpyStr( server, entry->d_name );
+	}
+    }
+
+    closedir( d );
+    return res;
+}
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/outgoing.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,34 @@
+/*
+  outgoing.h
+
+  Collection of posted articles.
+
+  $Id: outgoing.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef OUT_H
+#define OUT_H
+
+#include "common.h"
+#include "dynamicstring.h"
+
+Bool
+Out_add( const char *serv, const char *msgId, const DynStr *artTxt );
+
+/* Start enumeration. Return TRUE on success. */
+Bool
+Out_first( const char *serv, Str msgId, DynStr *artTxt );
+
+/* Continue enumeration. Return TRUE on success. */
+Bool
+Out_next( Str msgId, DynStr *s );
+
+/* Delete article from outgoing collection */
+void
+Out_remove( const char *serv, const char *msgId );
+
+/* Find server for outgoing message. */
+Bool
+Out_find( const char *msgId, Str server );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/over.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,191 @@
+/*
+  over.c
+
+  $Id: over.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include <errno.h>
+#include <time.h>
+#include "configfile.h"
+#include "content.h"
+#include "database.h"
+#include "fetchlist.h"
+#include "log.h"
+#include "util.h"
+#include "protocol.h"
+#include "pseudo.h"
+
+struct Over
+{
+    int numb;            /* message number of the overviewed article */
+    char *subj;
+    char *from;
+    char *date;
+    char *msgId;
+    char *ref;
+    size_t bytes;
+    size_t lines;
+    time_t time;
+};
+
+Over *
+new_Over( const char *subj, const char *from,
+          const char *date, const char *msgId, char *ref,
+          size_t bytes, size_t lines )
+{
+    Over *ov;
+
+    if ( ! ( ov = (Over *)malloc( sizeof( Over ) ) ) )
+    {
+        Log_err( "Cannot allocate Over" );
+        exit( EXIT_FAILURE );
+    }
+    ov->numb = 0;
+    Utl_allocAndCpy( &ov->subj, subj );
+    Utl_allocAndCpy( &ov->from, from );
+    Utl_allocAndCpy( &ov->date, date );
+    Utl_allocAndCpy( &ov->msgId, msgId );
+    Utl_allocAndCpy( &ov->ref, ref );
+    ov->bytes = bytes;
+    ov->lines = lines;
+    return ov;
+}
+
+void
+del_Over( Over *self )
+{
+    if ( ! self )
+        return;
+    free( self->subj );
+    self->subj = NULL;
+    free( self->from );
+    self->from = NULL;
+    free( self->date );
+    self->date = NULL;
+    free( self->msgId );
+    self->msgId = NULL;
+    free( self->ref );
+    self->ref = NULL;
+    free( self );
+}
+
+int
+Ov_numb( const Over *self )
+{
+    return self->numb;
+}
+
+const char *
+Ov_subj( const Over *self )
+{
+    return self->subj;
+}
+
+const char *
+Ov_from( const Over *self )
+{
+    return self->from;
+}
+
+const char *
+Ov_date( const Over *self )
+{
+    return self->date;
+}
+
+const char *
+Ov_msgId( const Over *self )
+{
+    return self->msgId;
+}
+
+const char *
+Ov_ref( const Over *self )
+{
+    return self->ref;
+}
+
+size_t
+Ov_bytes( const Over *self )
+{
+    return self->bytes;
+}
+
+size_t
+Ov_lines( const Over *self )
+{
+    return self->lines;
+}
+
+void
+Ov_setNumb( Over *self, int numb )
+{
+    self->numb = numb;
+}
+
+Bool
+Ov_write( const Over *self, FILE *f )
+{
+    return ( fprintf( f, "%i\t%s\t%s\t%s\t%s\t%s\t%d\t%d\n",
+                      self->numb, self->subj,
+                      self->from, self->date, self->msgId,
+                      self->ref, self->bytes,
+                      self->lines ) > 0 );
+}
+
+static const char *
+readField( Str result, const char *p )
+{
+    size_t len;
+    char *r;
+
+    if ( ! p )
+        return NULL;
+    r = result;
+    *r = '\0';
+    len = 0;
+    while ( *p != '\t' && *p != '\n' )
+    {
+        if ( ! *p )
+            return p;
+        *(r++) = *(p++);
+        ++len;
+        if ( len >= MAXCHAR - 1 )
+        {
+            *r = '\0';
+            Log_err( "Field in overview too long: %s", r );
+            return ++p;
+        }
+    }
+    *r = '\0';
+    return ++p;
+}
+
+/* read Over-struct from line */
+Over *
+Ov_read( char *line )
+{
+    size_t bytes, lines;
+    const char *p;
+    Over *result;
+    int numb;
+    Str t, subj, from, date, msgId, ref;
+    
+    p = readField( t, line );
+    if ( sscanf( t, "%i", &numb ) != 1 )
+        return NULL;
+    p = readField( subj, p );
+    p = readField( from, p );
+    p = readField( date, p );
+    p = readField( msgId, p );
+    p = readField( ref, p );
+    p = readField( t, p );
+    if ( sscanf( t, "%d", &bytes ) != 1 )
+        return NULL;
+    p = readField( t, p );
+    if ( sscanf( t, "%d", &lines ) != 1 )
+        return NULL;
+    result = new_Over( subj, from, date, msgId, ref, bytes, lines );
+    Ov_setNumb( result, numb );
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/over.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,70 @@
+/*
+  over.h
+
+  Processing of single article overviews. Handling of overview files is in
+  content.c. An article overview contains important article properties,
+  such as date, from, subject.
+
+  $Id: over.h 49 2000-05-05 21:45:56Z uh1763 $ 
+*/
+
+#ifndef OVER_H
+#define OVER_H
+
+#include <time.h>
+#include "common.h"
+
+struct Over;
+typedef struct Over Over;
+
+/*
+  Usual fields from overview databases.
+  Xref without hostname.
+*/
+Over *
+new_Over( const char *subj, const char *from, const char *date,
+          const char *msgId, char *ref, size_t bytes, size_t lines );
+
+
+/* free memory */
+void
+del_Over( Over *self );
+
+/* read Over-struct from line */
+Over *
+Ov_read( char *line );
+
+/* write struct Over to f as a line */
+Bool
+Ov_write( const Over *self, FILE *f );
+
+/* Access particular fields in struct over */
+
+int
+Ov_numb( const Over *self );
+
+const char *
+Ov_subj( const Over *self );
+
+const char *
+Ov_from( const Over *self );
+
+const char *
+Ov_date( const Over *self );
+
+const char *
+Ov_msgId( const Over *self );
+
+const char *
+Ov_ref( const Over *self );
+
+size_t
+Ov_bytes( const Over *self );
+
+size_t
+Ov_lines( const Over *self );
+
+void
+Ov_setNumb( Over *self, int numb );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/post.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,155 @@
+/*
+  post.c
+
+  $Id: post.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "post.h"
+#include <string.h>
+#include "common.h"
+#include "content.h"
+#include "database.h"
+#include "group.h"
+#include "log.h"
+#include "over.h"
+#include "protocol.h"
+#include "util.h"
+
+struct OverInfo
+{
+    Str subject;
+    Str from;
+    Str date;
+    Str msgId;
+    Str ref;
+    size_t bytes;
+    size_t lines;
+};
+
+struct Article
+{
+    const char * text;
+    Bool posted;
+    struct OverInfo over;
+};
+
+static struct Article article = { NULL, FALSE };
+
+static void
+getOverInfo( struct OverInfo * o )
+{
+    const char *p = article.text;
+    Str line, field, value;
+    
+    o->bytes = strlen( p );
+
+    while( p != NULL )
+    {
+        p = Utl_getHeaderLn( line, p );
+        if ( line[ 0 ] == '\0' )
+	    break;
+
+	/* Look for headers we need to stash. */
+        if ( Prt_getField( field, value, line ) )
+        {
+	    if ( strcmp( field, "subject" ) == 0 )
+		Utl_cpyStr( o->subject, value );
+	    else if ( strcmp ( field, "from" ) == 0 )
+		Utl_cpyStr( o->from, value );
+	    else if ( strcmp ( field, "date" ) == 0 )
+		Utl_cpyStr( o->date, value );
+	    else if ( strcmp ( field, "references" ) == 0 )
+		Utl_cpyStr( o->ref, value );
+	    else if ( strcmp ( field, "message-id" ) == 0 )
+		Utl_cpyStr( o->msgId, value );
+	}
+    }
+
+    /* Move to start of body and count lines. */
+    for ( p++, o->lines = 0; *p != '\0'; p++ )
+	if ( *p == '\n' )
+	    o->lines++;
+}
+
+/* Register an article for posting. */
+Bool
+Post_open( const char * text )
+{
+    if ( article.text != NULL )
+    {
+	Log_err( "Busy article in Post_open." );
+	return FALSE;
+    }
+
+    memset( &article.over, 0, sizeof( article.over ) );
+    article.text = text;
+    getOverInfo( &article.over );
+
+    if ( Db_contains( article.over.msgId ) )
+    {
+	Log_err( "Duplicate article %s.", article.over.msgId );
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+/* Add the article to a group. */
+Bool
+Post_add ( const char * grp )
+{
+    Over * over;
+    const char *msgId;
+    
+    over = new_Over( article.over.subject,
+		     article.over.from,
+		     article.over.date,
+		     article.over.msgId,
+		     article.over.ref,
+		     article.over.bytes,
+		     article.over.lines );
+    
+    msgId = article.over.msgId;
+    
+    Cont_read( grp );
+    Cont_app( over );
+    Log_dbg( "Added message '%s' to group '%s'.", msgId, grp );
+
+    if ( !article.posted )
+    {
+        Log_inf( "Added '%s' to database.", msgId );
+        if ( ! Db_prepareEntry( over, Cont_grp(), Cont_last() )
+	     || ! Db_storeArt ( msgId, article.text ) )
+	    return FALSE;
+	article.posted = TRUE;
+    }
+    else
+    {
+	Str t;
+	const char *xref;
+
+	xref = Db_xref( msgId );
+	Log_dbg( "Adding '%s' to Xref of '%s'", grp, msgId );
+	snprintf( t, MAXCHAR, "%s %s:%i", xref, grp, Ov_numb( over ) );
+	Db_setXref( msgId, t );
+    }
+    
+    Cont_write();
+    Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() );
+    return TRUE;
+}
+   
+/* Done with article - tidy up. */
+void
+Post_close( void )
+{
+    article.text = NULL;
+    article.posted = FALSE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/post.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,28 @@
+/*
+  post.h
+
+  Take a single article received in its entirety without an overview
+  (i.e. received via at the server via a POST), and add it to the database
+  and (possibly multiple) group(s).
+
+  $Id: post.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef POST_H
+#define POST_H
+
+#include "common.h"
+
+/* Register an article for posting. */
+Bool
+Post_open( const char * text );
+
+/* Add the article to a group. */
+Bool
+Post_add ( const char * grp );
+   
+/* Done with article - tidy up. */
+void
+Post_close( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocol.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,284 @@
+/*
+  protocol.c
+
+  $Id: protocol.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h> 
+#include <ctype.h> 
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include "common.h"
+#include "dynamicstring.h"
+#include "log.h"
+#include "over.h"
+#include "util.h"
+
+Bool
+Prt_getLn( Str line, FILE *f )
+{
+    size_t len;
+
+    /*
+      We also accept lines ending with "\n" instead of "\r\n", some
+      clients wrongly send such lines.
+    */
+    if ( ! fgets( line, MAXCHAR, f ) )
+    {
+        Log_dbg( "Prt_getLine failed" );
+        return FALSE;
+    }
+    len = strlen( line );
+    if ( line[ len - 1 ] == '\n' )
+    {
+        line[ len - 1 ] = '\0';
+        if ( line[ len - 2 ] == '\r' )
+            line[ len - 2 ] = '\0';
+    }
+    Log_dbg( "[R] %s", line );
+    return TRUE;
+}
+
+Bool
+Prt_getTxtLn( Str line, Bool *err, FILE *f )
+{
+    Str buf;
+
+    if ( ! Prt_getLn( buf, f ) )
+    {
+        Log_err( "Cannot get text line" );
+        *err = TRUE;
+        return FALSE;
+    }
+    *err = FALSE;
+    if ( buf[ 0 ] == '.' )
+    {
+        if ( buf[ 1 ] == 0 )
+            return FALSE;
+        else
+            strcpy( line, buf + 1 );
+    }
+    else
+        strcpy( line, buf );
+    return TRUE;
+}
+
+Bool
+Prt_putTxtLn( const char* line, FILE *f )
+{
+    if ( line[ 0 ] == '.' )
+    {
+        Log_dbg( "[S] .%s", line );
+        return ( fprintf( f, ".%s\r\n", line ) == strlen( line ) + 3 );
+    }
+    else
+    {
+        Log_dbg( "[S] %s", line );
+        return ( fprintf( f, "%s\r\n", line ) == strlen( line ) + 2 );
+    }
+}
+
+Bool
+Prt_putEndOfTxt( FILE *f )
+{
+    Log_dbg( "[S] ." );
+    return ( fprintf( f, ".\r\n" ) == 3 );
+}
+
+/*
+  Write text buffer of lines each ending with '\n'.
+  Replace '\n' by "\r\n".
+*/
+Bool
+Prt_putTxtBuf( const char *buf, FILE *f )
+{
+    Str line;
+    const char *pBuf;
+    char *pLn;
+
+    pBuf = buf;
+    pLn = line;
+    while ( *pBuf != '\0' )
+    {
+        if ( *pBuf == '\n' )
+        {
+            *pLn = '\0';
+            if ( ! Prt_putTxtLn( line, f ) )
+                return FALSE;
+            pLn = line;
+            ++pBuf;
+        }
+        else if ( pLn - line >= MAXCHAR - 1 )
+        {
+            /* Put it out raw to prevent String overflow */
+            Log_err( "Writing VERY long line" );
+            *pLn = '\0';
+            if ( fprintf( f, "%s", line ) != strlen( line ) )
+                return FALSE;
+            pLn = line;
+        }   
+        else
+            *(pLn++) = *(pBuf++);
+    }
+    return TRUE;
+}
+
+Bool
+Prt_getField( Str resultField, Str resultValue, const char* line )
+{
+    char *dst;
+    const char *p;
+    Str lineLower, t;
+    
+    Utl_cpyStr( lineLower, line );
+    Utl_toLower( lineLower );
+    p = Utl_stripWhiteSpace( lineLower );
+    dst = resultField;
+    while ( ! isspace( *p ) && *p != ':' && *p != '\0' )
+        *(dst++) = *(p++);
+    *dst = '\0';
+    while ( isspace( *p ) )
+        ++p;    
+    if ( *p == ':' )
+    {
+        ++p;
+        strcpy( t, line + ( p - lineLower ) );
+        p = Utl_stripWhiteSpace( t );
+        strcpy( resultValue, p );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+Bool
+Prt_searchHeader( const char *artTxt, const char *which, Str result )
+{
+    const char *src, *p;
+    char *dst;
+    Str line, whichLower, field;
+    int len;
+    
+    Utl_cpyStr( whichLower, which );
+    Utl_toLower( whichLower );
+    src = artTxt;
+    while ( TRUE )
+    {
+        dst = line;
+        len = 0;
+        while ( *src != '\n' && len < MAXCHAR )
+        {
+            if ( *src == '\0' )
+                return FALSE;
+            *(dst++) = *(src++);
+            ++len;
+        }
+        if ( *src == '\n' )
+            ++src;
+        *dst = '\0';
+        p = Utl_stripWhiteSpace( line );
+        if ( *p == '\0' )
+            break;
+        if ( Prt_getField( field, result, line )
+             && strcmp( field, whichLower ) == 0 )
+            return TRUE;
+    }
+    return FALSE;
+}
+
+static Bool
+getFQDN( Str result )
+{
+    struct hostent *myHostEnt;
+    struct utsname myName;
+    
+    if ( uname( &myName ) >= 0
+         && ( myHostEnt = gethostbyname( myName.nodename ) ) )
+    {
+        Utl_cpyStr( result, myHostEnt->h_name );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void
+getDomain( Str domain, const char *from )
+{
+    const char *addTopLevel, *p1, *p2, *p, *domainStart;
+    Str myDomain;
+
+    if ( getFQDN( myDomain ) )
+    {
+        p = strstr( myDomain, "." );
+        if ( p != NULL )
+            domainStart = p + 1;
+        else
+            domainStart = myDomain;
+    }
+    else /* Take domain of From field */
+    {
+        myDomain[ 0 ] = '\0';
+        p1 = strstr( from, "@" );
+        if ( p1 != NULL )
+        {
+            p2 = strstr( p1, ">" );
+            if ( p2 != NULL )
+                Utl_cpyStrN( myDomain, p1 + 1, p2 - p1 - 1 );
+        }
+        if ( myDomain[ 0 ] == '\0' )
+            Utl_cpyStr( myDomain, "unknown" );
+        domainStart = myDomain;
+    }
+    /*
+      If domain contains no dot (and is probably invalid anyway),
+      we add ".local", because some servers insist on domainnames with dot
+      in message ID.
+    */
+    addTopLevel = strstr( domainStart, "." ) == NULL ? ".local" : "";
+    snprintf( domain, MAXCHAR, "%s%s", myDomain, addTopLevel );    
+}
+
+/* See RFC 850, section 2.1.7 */
+Bool
+Prt_isValidMsgId( const char *msgId )
+{
+    Str head, domain;
+    int len, headLen;
+    const char *p;
+
+    len = strlen( msgId );
+    p = strstr( msgId, "@" );
+    if ( msgId[ 0 ] != '<' || msgId[ len - 1 ] != '>' || p == NULL )
+        return FALSE;
+    strcpy( domain, p + 1 );
+    domain[ strlen( domain ) - 1 ] = '\0';
+    headLen = p - msgId - 1;
+    Utl_cpyStrN( head, msgId + 1, headLen );
+    head[ headLen ] = '\0';
+    /*
+      To do: check for special characters in head and domain (non-printable
+      or '@', '<', '>'). Maybe compare domain with a config option 
+      and replace it by the config option, if not equal.
+     */
+    if ( strstr( domain, "." ) == NULL )
+        return FALSE;
+    return TRUE;
+}
+
+void
+Prt_genMsgId( Str msgId, const char *from, const char *suffix )
+{
+    Str domain, date;
+    time_t t;
+
+    getDomain( domain, from );
+    time( &t );
+    strftime( date, MAXCHAR, "%Y%m%d%H%M%S", gmtime( &t ) );
+    srand( time( NULL ) );
+    snprintf( msgId, MAXCHAR, "<%s.%X.%s@%s>", date, rand(), suffix, domain );
+    ASSERT( Prt_isValidMsgId( msgId ) );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocol.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,105 @@
+/*
+  protocol.h
+
+  Functions related with the NNTP protocol which are useful for both
+  the server and the client.
+
+  $Id: protocol.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef PRT_H
+#define PRT_H
+
+#include "dynamicstring.h"
+#include "over.h"
+
+#define STAT_HELP_FOLLOWS        100
+#define STAT_DEBUG_FOLLOWS       199
+
+#define STAT_READY_POST_ALLOW    200
+#define STAT_READY_NO_POST_ALLOW 201
+#define STAT_CMD_OK              202
+#define STAT_GOODBYE             205
+#define STAT_GRP_SELECTED        211
+#define STAT_GRPS_FOLLOW         215
+#define STAT_ART_FOLLOWS         220
+#define STAT_HEAD_FOLLOWS        221
+#define STAT_BODY_FOLLOWS        222
+#define STAT_ART_RETRIEVED       223
+#define STAT_OVERS_FOLLOW        224
+#define STAT_NEW_GRP_FOLLOW      231
+#define STAT_POST_OK             240
+#define STAT_AUTH_ACCEPTED       281
+
+#define STAT_SEND_ART            340
+#define STAT_MORE_AUTH_REQUIRED  381
+
+#define STAT_NO_SUCH_GRP         411
+#define STAT_NO_GRP_SELECTED     412
+#define STAT_NO_ART_SELECTED     420
+#define STAT_NO_NEXT_ART         421
+#define STAT_NO_PREV_ART         422
+#define STAT_NO_SUCH_NUMB        423
+#define STAT_NO_SUCH_ID          430
+#define STAT_ART_REJECTED        437
+#define STAT_POST_FAILED         441
+#define STAT_AUTH_REQUIRED       480
+#define STAT_AUTH_REJECTED       482
+
+#define STAT_NO_SUCH_CMD         500
+#define STAT_SYNTAX_ERR          501
+#define STAT_NO_PERMISSION       502
+#define STAT_PROGRAM_FAULT       503
+
+/* 
+   Read next line from f into Str, up to "\n" or "\r\n". Don't save "\n"
+   or "\r\n" in line. Terminate with '\0'. 
+*/
+Bool
+Prt_getLn( Str line, FILE *f );
+
+/*
+  Read a text line from server. Returns TRUE if line != ".", removes
+  leading '.' otherwise.
+*/
+Bool
+Prt_getTxtLn( Str line, Bool *err, FILE *f );
+
+/*
+  Write text line to f. Escape "." at the beginning with another ".".
+  Terminate with "\r\n".
+*/
+Bool
+Prt_putTxtLn( const char* line, FILE *f );
+
+/*
+  Write text buffer of lines each ending with '\n'.
+  Replace '\n' by "\r\n".
+*/
+Bool
+Prt_putTxtBuf( const char *buf, FILE *f );
+
+/* 
+   Write text-ending "."-line to f
+*/
+Bool
+Prt_putEndOfTxt( FILE *f );
+
+/*
+  Splits line in field and value. Field is converted to lower-case. 
+*/
+Bool
+Prt_getField( Str resultField, Str resultValue, const char* line );
+
+/* Search header. Works only with single line headers (ignores continuation
+   lines */
+Bool
+Prt_searchHeader( const char *artTxt, const char* which, Str result );
+
+Bool
+Prt_isValidMsgId( const char *msgId );
+
+void
+Prt_genMsgId( Str msgId, const char *from, const char *suffix );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pseudo.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,335 @@
+/*
+  pseudo.c
+  
+  $Id: pseudo.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pseudo.h"
+
+#include <stdio.h>
+#include <time.h>
+#include "common.h"
+#include "configfile.h"
+#include "content.h"
+#include "database.h"
+#include "group.h"
+#include "log.h"
+#include "protocol.h"
+#include "util.h"
+
+Over *
+genOv( const char *rawSubj, const char *rawBody, const char *suffix )
+{
+    size_t bytes, lines;
+    time_t t;
+    Str subj, date, msgId;
+
+    snprintf( subj, MAXCHAR, "[ %s ]", rawSubj );
+    time( &t );
+    Utl_rfc822Date( t, date );
+    Prt_genMsgId( msgId, "", suffix );
+    bytes = lines = 0;
+    while ( *rawBody )
+    {
+        ++bytes;
+        if ( *rawBody == '\n' )
+            ++lines;
+        ++rawBody;
+    }
+    return new_Over( subj, "news (\"[ NOFFLE ]\")" , date, msgId, "",
+                     bytes, lines );
+}
+
+void
+Pseudo_appGeneralInfo()
+{
+    Cont_app( genOv( "General info", Pseudo_generalInfoBody(),
+                     "NOFFLE-GENERAL-INFO" ) );
+}
+
+Bool
+Pseudo_isGeneralInfo( const char *msgId )
+{
+    return ( strstr( msgId, "NOFFLE-GENERAL-INFO" ) != NULL );
+}
+
+const char *
+Pseudo_generalInfoHead()
+{
+    static Str s;
+
+    Over *ov;
+
+    ov = genOv( "General info", Pseudo_generalInfoBody(),
+                "NOFFLE-GENERAL-INFO" );
+    if ( ov )
+    {
+        snprintf( s, MAXCHAR,
+                  "Message-ID: %s\n"
+                  "Subject: %s\n"
+                  "From: %s\n"
+                  "Date: %s\n"
+                  "Bytes: %u\n"
+                  "Lines: %u\n",
+                  Ov_msgId( ov ),
+                  Ov_subj( ov ),
+                  Ov_from( ov ),
+                  Ov_date( ov ),
+                  Ov_bytes( ov ),
+                  Ov_lines( ov ) );
+        del_Over( ov );
+        return s;
+    }
+    return NULL;
+}
+
+const char *
+Pseudo_generalInfoBody( void )
+{
+    if ( Cfg_autoSubscribe() )
+        return
+            "\n"
+            "\t[ NOFFLE INFO: General information ]\n"
+            "\n"
+            "\t[ This server is running NOFFLE, which is a NNTP server ]\n"
+            "\t[ optimized for low speed dial-up Internet connections. ]\n"
+            "\n"
+            "\t[ By reading this or any other article of this group, ]\n"
+            "\t[ NOFFLE has put it on its fetch list and will retrieve ]\n"
+            "\t[ articles next time it is online. ]\n"
+            "\n"
+            "\t[ If you have more questions about NOFFLE please talk ]\n"
+            "\t[ to your newsmaster or read the manual page for ]\n"
+            "\t[ \"noffle\". ]\n";
+    else
+        return
+            "\n"
+            "\t[ NOFFLE INFO: General information ]\n"
+            "\n"
+            "\t[ This server is running NOFFLE, which is a NNTP server ]\n"
+            "\t[ optimized for low speed dial-up Internet connections. ]\n"
+            "\n"
+            "\t[ This group is presently not on the fetch list. You can ]\n"
+            "\t[ put groups on the fetch list by running the \"noffle\" ]\n"
+            "\t[ command on the computer where this server is running. ]\n"
+            "\n"
+            "\t[ If you have more questions about NOFFLE please talk ]\n"
+            "\t[ to your newsmaster or read the manual page for ]\n"
+            "\t[ \"noffle\". ]\n";
+}
+
+const char *
+Pseudo_markedBody( void )
+{
+    return
+        "\n"
+        "\t[ NOFFLE INFO: Marked for download ]\n"
+        "\n"
+        "\t[ The body of this article has been marked for download. ]\n";
+}
+
+const char *
+Pseudo_alreadyMarkedBody( void )
+{
+    return
+        "\n"
+        "\t[ NOFFLE INFO: Already marked for download ]\n"
+        "\n"
+        "\t[ The body of this article has already been marked ]\n"
+        "\t[ for download. ]\n";
+}
+
+const char *
+Pseudo_markingFailedBody( void )
+{
+    return
+        "\n"
+        "\t[ NOFFLE ERROR: Marking for download failed ]\n"
+        "\n"
+        "\t[ Sorry, I could not mark this article for download. ]\n"
+        "\t[ Either the database is corrupted, or I was unable to ]\n"
+        "\t[ get write access to the request directory. ]\n"
+        "\t[ Please contact your newsmaster to remove this problem. ]\n";
+}
+
+void
+genPseudo( const char *rawSubj, const char* rawBody )
+{
+    Over *ov;
+    DynStr *body = 0, *artTxt = 0;
+
+    body = new_DynStr( 10000 );
+    artTxt = new_DynStr( 10000 );
+    DynStr_app( body, "\n\t[ NOFFLE INFO: " );
+    DynStr_app( body, rawSubj );
+    DynStr_app( body, " ]\n\n" );
+    DynStr_app( body, "\t[ " );
+    while( *rawBody )
+    {
+        if ( *rawBody == '\n' )
+        {
+            DynStr_app( body, " ]\n" );
+            if ( *( rawBody + 1 ) == '\n' )
+            {
+                DynStr_app( body, "\n\t[ " );
+                ++rawBody;
+            }
+            else if ( *( rawBody + 1 ) != '\0' )
+                DynStr_app( body, "\t[ " );
+        }
+        else
+            DynStr_appN( body, rawBody, 1 );
+        ++rawBody;
+    }
+    DynStr_appLn( body, "" );    
+    DynStr_appLn( artTxt,
+                  "Comments: Pseudo article generated by news server NOFFLE" );
+    DynStr_appLn( artTxt, "" );
+    DynStr_appDynStr( artTxt, body );
+    ov = genOv( rawSubj, DynStr_str( body ), "PSEUDO" );
+    if ( body && artTxt && ov )
+    {
+        Cont_app( ov );
+        if ( Db_prepareEntry( ov, Cont_grp(), Cont_last() ) )
+            Db_storeArt( Ov_msgId( ov ), DynStr_str( artTxt ) );
+        Cont_write();
+        Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() );
+    }
+    del_DynStr( body );
+    del_DynStr( artTxt );
+}
+
+void
+Pseudo_retrievingFailed( const char *msgId, const char *reason )
+{
+    DynStr *artTxt = 0;
+
+    if ( ! Db_contains( msgId ) )
+    {
+        Log_err( "Article %s has no entry in database %s", msgId );
+        return;
+    }
+    artTxt = new_DynStr( 10000 );
+    DynStr_appLn( artTxt,
+                  "Comments: Pseudo body generated by news server NOFFLE" );
+    DynStr_appLn( artTxt, "" );
+    DynStr_app( artTxt,
+                "\n"
+                "\t[ NOFFLE ERROR: Retrieving failed ]\n"
+                "\n"
+                "\t[ This article could not be retrieved. Maybe ]\n"
+                "\t[ it has already expired at the remote server ]\n"
+                "\t[ or it has been cancelled by its sender. See ]\n"
+                "\t[ the appended status line of the remote ]\n"
+                "\t[ server for more information. ]\n"
+                "\n"
+                "\t[ This message will disappear the next time ]\n"
+                "\t[ someone tries to read this article, so that ]\n"
+                "\t[ it can be marked for download again. ]\n" );
+    DynStr_app( artTxt, "\n\t[ Remote server status: " );
+    DynStr_app( artTxt, reason );
+    DynStr_app( artTxt, " ]\n" );
+    Db_storeArt( msgId, DynStr_str( artTxt ) );
+    del_DynStr( artTxt );
+}
+
+void
+Pseudo_cntInconsistent( const char *grp, int first, int last, int next )
+{
+    DynStr *info;
+    Str s;
+
+    info = new_DynStr( 10000 );
+    if ( info )
+    {
+        DynStr_app( info,
+                    "This group's article counter is not \n"
+                    "consistent Probably the remote news server\n"
+                    "was changed or has reset its article counter\n"
+                    "for this group. As a consequence there could\n"
+                    "be some articles be duplicated in this group\n" );
+        snprintf( s, MAXCHAR, "Group: %s", grp );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Remote first article number: %i", first );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Remote last article number: %i", last );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Remote next article number: %i", next );
+        DynStr_appLn( info, s );
+        genPseudo( "Article counter inconsistent", DynStr_str( info ) );
+    }
+    del_DynStr( info );
+}
+
+void
+Pseudo_missArts( const char *grp, int first, int next )
+{
+    DynStr *info;
+    Str s;
+
+    info = new_DynStr( 5000 );
+    if ( info )
+    {
+        DynStr_app( info,
+                    "Some articles could not be retrieved from\n"
+                    "the remote server, because it had already\n"
+                    "deleted them.\n"
+                    "If this group is on the fetch list, then\n"
+                    "contact your newsmaster to ensure that\n"
+                    "\"noffle\" is fetching news more frequently.\n" );
+        snprintf( s, MAXCHAR, "Group: %s", grp );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Remote next article number: %i", next );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Remote first article number: %i", first );
+        DynStr_appLn( info, s );
+        genPseudo( "Missing articles", DynStr_str( info ) );
+        del_DynStr( info );
+    }
+}
+
+void
+Pseudo_autoUnsubscribed( const char *grp, int days )
+{
+    DynStr *info;
+    Str s;
+
+    info = new_DynStr( 10000 );
+    if ( info )
+    {
+        DynStr_app( info,
+                    "NOFFLE has automatically unsubscribed this\n"
+                    "group since it has not been accessed for\n"
+                    "some time.\n"
+                    "Re-subscribing is done either automatically\n"
+                    "by NOFFLE (if configured) or by manually\n"
+                    "running the 'noffle --subscribe' command\n" );
+        snprintf( s, MAXCHAR, "Group: %s", grp );
+        DynStr_appLn( info, s );
+        snprintf( s, MAXCHAR, "Days without access: %i", days );
+        DynStr_appLn( info, s );
+        genPseudo( "Auto unsubscribed", DynStr_str( info ) );
+    }
+    del_DynStr( info );
+}
+
+void
+Pseudo_autoSubscribed()
+{
+    DynStr *info;
+
+    info = new_DynStr( 10000 );
+    if ( info )
+    {
+        DynStr_app( info,
+                    "NOFFLE has now automatically subscribed to\n"
+                    "this group. It will fetch articles next time\n"
+                    "it is online.\n" );
+        genPseudo( "Auto subscribed", DynStr_str( info ) );
+    }
+    del_DynStr( info );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pseudo.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,64 @@
+/*
+  pseudo.h
+
+  Handling of pseudo articles.
+
+  $Id: pseudo.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef PSEUDO_H
+#define PSEUDO_H
+
+#include "over.h"
+
+/*
+  General info is a special pseudo message for groups not on fetchlist.
+  It is never stored in database, but generated every time a content is read.
+  However the group counter is always increased. This ensures that there
+  is always at least 1 article visible (even if the user deletes it) for
+  using the auto-subscribe option.
+*/
+Bool
+Pseudo_isGeneralInfo( const char *msgId );
+
+void
+Pseudo_appGeneralInfo( void );
+
+const char *
+Pseudo_generalInfoHead( void );
+
+const char *
+Pseudo_generalInfoBody( void );
+
+
+const char *
+Pseudo_markedBody( void );
+
+const char *
+Pseudo_alreadyMarkedBody( void );
+
+const char *
+Pseudo_markingFailedBody( void );
+
+void
+Pseudo_retrievingFailed( const char *msgId, const char *reason );
+
+
+/*
+  Other pseudo articles are stored in database and can contain dynamically
+  generated information about the failure.
+ */
+
+void
+Pseudo_cntInconsistent( const char *grp, int first, int last, int next );
+
+void
+Pseudo_missArts( const char *grp, int first, int next );
+
+void
+Pseudo_autoUnsubscribed( const char *grp, int days );
+
+void
+Pseudo_autoSubscribed( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/request.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,410 @@
+/*
+  request.c
+
+  Collection of articles that are marked for download.
+
+  $Id: request.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "request.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <assert.h>
+#include "configfile.h"
+#include "log.h"
+#include "util.h"
+
+
+/* This struct keeps record of the message IDs that are to be fetched from
+   one particular host. Several of these are chained together via the
+   "next" pointer, if we have several servers.
+*/
+
+struct Reqserv;
+typedef struct Reqserv Reqserv;
+
+struct Reqserv {
+  char*    serv;                /* Server the messages are to be requested
+                                   from */
+  char**   reql;                /* List of message IDs of requested
+                                   messages. Some entries (that have been
+                                   deleted) may be NULL */
+  int      reql_length;         /* Number of string pointers in reql,
+                                   including NULL entries */
+  int      reql_capacity;       /* maximum number of string pointers reql
+                                   can hold */
+  Bool     dirty;               /* whether the request list needs to be
+                                   rewritten to disk */
+  Reqserv* next;                /* next Reqserv in list */
+  time_t   mtime;               /* last modification time of request file */ 
+};
+
+/* List of servers */
+static Reqserv* reqserv = 0;
+
+/* sanity check */
+static Bool is_open = FALSE;
+
+/* for Req_first/Req_next */
+static char** iterator = 0;
+static char** iterator_end = 0;
+
+
+/* local functions */
+static Reqserv* newReqserv      (const char* serv);
+static Bool     getReqserv      (const char* serv, Reqserv** rsz);
+static void     fileRequest     (Str file, const char *serv);
+static char**   searchMsgId     (const Reqserv * rs, const char *msgId);
+static void     storeMsgId      (Reqserv* rs, const char* msgId);
+static Bool     readRequestfile (const char* serv, Reqserv** rsz);
+static time_t   get_mtime       (const char* serv);
+
+/* read modification time of request file */
+static time_t get_mtime(const char* serv)
+{
+  Str filename;
+  struct stat stat1;
+
+  fileRequest(filename, serv);
+  stat(filename, &stat1);
+  return stat1.st_mtime;
+}
+
+
+/* create new Reqserv and queue it */
+static Reqserv* newReqserv(const char* serv)
+{
+  Reqserv* rs = (Reqserv*) malloc(sizeof(Reqserv));
+  rs->serv = strcpy(malloc(strlen(serv)+1), serv);
+  rs->reql = 0;
+  rs->reql_length = 0;
+  rs->reql_capacity = 0;
+  rs->next = reqserv;
+  rs->dirty = FALSE;
+  rs->mtime = 0;
+  reqserv = rs;
+  return rs;
+}
+
+
+/* get Reqserv for given server, and save it in "rsz". Load from file as
+   necessary. Return TRUE on success. Otherwise log errors and return
+   FALSE. (details in errno)
+*/
+static Bool getReqserv(const char* serv, Reqserv** rsz)
+{
+  Reqserv* rs;
+  for (rs = reqserv; rs; rs = rs->next)
+    if (!strcmp(serv, rs->serv)) {
+      *rsz = rs;
+      return TRUE;
+    }
+  return readRequestfile(serv, rsz);
+}
+
+
+/* Delete Reqserv from cache, if not up-to-date */
+static void
+cleanupReqserv( void )
+{
+  Reqserv *rs, *prev, *next;
+
+  rs = reqserv;
+  prev = NULL;
+  while ( rs != NULL )
+  {      
+      ASSERT( ! rs->dirty );
+      next = rs->next;
+      if ( get_mtime( rs->serv ) != rs->mtime )
+      {
+          if ( prev != NULL )
+              prev->next = next;
+          else
+              reqserv = next;
+          free( rs->serv );
+          rs->serv = NULL;
+          free( rs->reql );
+          rs->reql = NULL;
+          free( rs );
+      }
+      prev = rs;
+      rs = next;
+  }
+}
+
+/* Save name of file storing requests from server "serv" in "file" */
+static void fileRequest( Str file, const char *serv)
+{
+  snprintf( file, MAXCHAR, "%s/requested/%s", Cfg_spoolDir(), serv);
+}
+
+
+/* Search for msgid in Reqserv. Return pointer to list entry. Return 0 if
+   list does not contain msgid. */
+static char** searchMsgId(const Reqserv * rs, const char *msgId )
+{
+  char** rz;
+  ASSERT(rs != 0);
+
+  if (!rs->reql)
+    return 0;
+
+  for (rz = rs->reql; rz < rs->reql + rs->reql_length; rz++)
+    if (*rz && !strcmp(*rz, msgId))
+      return rz;
+
+  return 0;
+}
+
+
+Bool
+Req_contains(const char *serv, const char *msgId)
+{
+  Reqserv* rs;
+  ASSERT( is_open );
+  if (getReqserv(serv, &rs) == FALSE) 
+    return FALSE;
+  return searchMsgId(rs, msgId) ? TRUE : FALSE;
+}
+
+
+static void storeMsgId(Reqserv* rs, const char* msgId)
+{
+  char* msgid;
+
+  if (searchMsgId(rs, msgId))
+    /* already recorded */
+    return;
+
+  msgid = strcpy(malloc(strlen(msgId)+1), msgId);
+
+  if (rs->reql_length >= rs->reql_capacity) {
+    int c1 = rs->reql_capacity*2 + 10;
+    rs->reql = (char**) realloc(rs->reql, c1*sizeof(char*));
+    rs->reql_capacity = c1;
+  }
+
+  *(rs->reql + rs->reql_length++) = msgid;
+  rs->dirty = TRUE;
+}
+
+
+/* Add request for message "msgIg" from server "serv". Return TRUE iff
+   successful. 
+*/
+Bool Req_add(const char *serv, const char *msgId)
+{
+    Reqserv* rs;
+    ASSERT( is_open );
+    Log_dbg( "Marking %s on %s for download", msgId, serv );
+
+    if (getReqserv(serv, &rs) == FALSE) 
+      return FALSE;
+    storeMsgId(rs, msgId);
+    return TRUE;
+}
+
+static Bool
+readLn( Str line, FILE* f )
+{
+    size_t len;
+
+    if ( ! fgets( line, MAXCHAR, f ) )
+        return FALSE;
+    len = strlen( line );
+    if ( line[ len - 1 ] == '\n' )
+        line[ len - 1 ] = '\0';
+    return TRUE;
+}
+
+/* Read request file into new, non-queued Reqserv. Save new Reqserv in
+   "rsz" and return TRUE on success. Returns FALSE on failure, see errno.
+   If the file doesn't exist, an empty Reqserv is returned.
+*/
+static Bool readRequestfile(const char* serv, Reqserv** rsz)
+{
+  Str           filename;
+  Str           line;
+  FILE*         file;
+  Reqserv*      rs;
+
+  fileRequest(filename, serv);
+  Log_dbg("reading request file %s", filename);
+
+  file = fopen(filename, "r");
+  if (!file && (errno == ENOENT)) {
+    *rsz = newReqserv(serv);
+    (*rsz)->mtime = get_mtime(serv);
+    return TRUE;
+  }
+  if (Log_check(file != 0,
+            "could not open %s for reading: %s", 
+            filename, strerror(errno)))
+    return FALSE;
+
+  rs = *rsz = newReqserv(serv);
+
+  while( readLn(line, file) == TRUE) {
+    char* line1 = Utl_stripWhiteSpace(line);
+    if (*line1)
+      storeMsgId(rs, line1);
+  }
+
+  rs->dirty = FALSE;
+
+  if (Log_check(fclose(file) != EOF, 
+            "could not close %s properly: %s\n", 
+            filename, strerror(errno)))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/* Write out request file for given Reqserv. Return TRUE on success. If an
+   I/O error occurs, it is logged, and FALSE is returned.
+*/
+static Bool writeRequestfile(Reqserv* rs)
+{
+  Str    filename;
+  FILE*  file;
+  char** z;
+
+  fileRequest(filename, rs->serv);
+  Log_dbg("writing request file %s", filename);
+
+  if (Log_check((file = fopen(filename, "w")) != 0,
+            "could not open %s for writing: %s", 
+            filename, strerror(errno)))
+    return FALSE;
+
+  if (rs->reql)
+    for (z = rs->reql; z < rs->reql+rs->reql_length; z++)
+      if (*z) {
+        if (Log_check(   fputs(*z, file) != EOF
+                      && fputs("\n", file) != EOF,
+                  "write error: %s", strerror(errno)))
+          return FALSE;
+      }
+  
+  if (Log_check(fclose(file) != EOF, 
+                "could not close %s properly: %s\n", 
+                filename, strerror(errno)))
+    return FALSE;
+            
+  rs->dirty = FALSE;
+  rs->mtime = get_mtime(rs->serv);
+
+  return TRUE;
+}
+
+
+void
+Req_remove( const char *serv, const char *msgId )
+{
+    Reqserv* rs;
+    char** z;
+    
+    ASSERT( is_open );
+    Log_dbg("Req_remove(\"%s\", \"%s\")", serv, msgId);
+    
+    if (getReqserv(serv, &rs) == FALSE) 
+        return;
+    
+    z = searchMsgId(rs, msgId);
+    if ( ! z )
+        return;
+    
+    free(*z);
+    *z = 0;
+    rs->dirty = TRUE;
+}
+
+
+Bool
+Req_first( const char *serv, Str msgId )
+{
+  Reqserv* rs;
+
+  ASSERT( is_open );
+  ASSERT( !iterator && !iterator_end );
+
+  if (getReqserv(serv, &rs) == FALSE)
+    return FALSE;
+
+  if (!rs->reql) 
+    return FALSE;
+
+  iterator = rs->reql - 1;
+  iterator_end = rs->reql + rs->reql_length;
+
+  return Req_next(msgId);
+}
+
+
+Bool
+Req_next( Str msgId )
+{
+  ASSERT( is_open );
+  ASSERT(iterator && iterator_end);
+
+  if (iterator >= iterator_end)
+      return FALSE;
+  iterator++;
+
+  while (iterator < iterator_end) {
+    if (!*iterator)
+      iterator++;
+    else {
+      Utl_cpyStr(msgId, *iterator);
+      return TRUE;
+    }
+  }
+
+  iterator = iterator_end = 0;
+  return FALSE;
+}
+
+
+/* Get exclusive access to all request files. Maybe we already have had it,
+   and the cache is outdated. So we delete request files, which have
+   changed recently, from cache. These files will be reread on demand.
+*/
+Bool
+Req_open(void)
+{
+  Log_dbg("opening request database");
+  ASSERT(is_open == FALSE);
+  cleanupReqserv();
+  is_open = TRUE;
+  return TRUE;
+}
+
+
+/* Do not occupy the request files any longer. Write any changes to disk.
+   Return TRUE on success, FALSE if an IO error occurs. */
+void Req_close(void) 
+{
+  Bool ret = TRUE;
+  Reqserv* rs;
+  Log_dbg("closing request database, writing changes to disk");
+  ASSERT(is_open == TRUE);
+
+  for (rs = reqserv; rs; rs = rs->next) {
+    if (rs->dirty == TRUE) {
+      if (!writeRequestfile(rs))
+        ret = FALSE;
+    }
+  }
+
+  is_open = FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/request.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,51 @@
+/*
+  request.h
+
+  Collection of requested articles.
+
+  $Id: request.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef REQ_H
+#define REQ_H
+
+#include "common.h"
+
+/* Is request for message msgId from server serv already recorded? This
+   function has no error detection facility. On error, FALSE is returned.
+   Nevertheless, errors are logged. */
+Bool
+Req_contains( const char *serv, const char *msgId );
+
+/* Add request for message "msgId" from server "serv". Return TRUE if
+   successful. */ 
+Bool
+Req_add( const char *serv, const char *msgId );
+
+/* Remove request for message msgIg from server serv. This function does
+   not return any errors. Nevertheless, they are logged. */
+void
+Req_remove( const char *serv, const char *msgId );
+
+/* Begin iteration through all messages requested from one server. Return
+   TRUE if there are any requests. Save first message ID in msgId. On
+   error, it is logged, and FALSE is returned.
+*/
+Bool
+Req_first( const char *serv, Str msgId );
+
+/* Continue iteration. Return TRUE on success, FALSE when there are no more
+   requests. Save message ID in msgId. On error, it is logged, and FALSE is
+   returned. */
+Bool
+Req_next( Str msgId );
+
+/* Get exclusive access to the request files. Refresh cache as necessary. */
+Bool 
+Req_open(void);
+
+/* Write changes to disk */
+void
+Req_close(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,1544 @@
+/*
+  server.c
+
+  $Id: server.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "server.h"
+#include <ctype.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include "client.h"
+#include "common.h"
+#include "configfile.h"
+#include "content.h"
+#include "control.h"
+#include "database.h"
+#include "dynamicstring.h"
+#include "fetch.h"
+#include "fetchlist.h"
+#include "group.h"
+#include "itemlist.h"
+#include "lock.h"
+#include "log.h"
+#include "online.h"
+#include "outgoing.h"
+#include "post.h"
+#include "protocol.h"
+#include "pseudo.h"
+#include "request.h"
+#include "util.h"
+#include "wildmat.h"
+
+struct
+{
+    Bool running;
+    int artPtr;
+    Str grp; /* selected group, "" if none */
+} serv = { FALSE, 0, "" };
+
+typedef struct Cmd
+{
+    const char *name;
+    const char *syntax;
+    /* Returns false, if quit cmd */
+    Bool (*cmdProc)( char *arg, const struct Cmd *cmd );
+}
+Cmd;
+
+static Bool doArt( char *arg, const Cmd *cmd );
+static Bool doBody( char *arg, const Cmd *cmd );
+static Bool doGrp( char *arg, const Cmd *cmd );
+static Bool doHead( char *arg, const Cmd *cmd );
+static Bool doHelp( char *arg, const Cmd *cmd );
+static Bool doIhave( char *arg, const Cmd *cmd );
+static Bool doLast( char *arg, const Cmd *cmd );
+static Bool doList( char *arg, const Cmd *cmd );
+static Bool doListgrp( char *arg, const Cmd *cmd );
+static Bool doMode( char *arg, const Cmd *cmd );
+static Bool doNewgrps( char *arg, const Cmd *cmd );
+static Bool doNext( char *arg, const Cmd *cmd );
+static Bool doPost( char *arg, const Cmd *cmd );
+static Bool doSlave( char *arg, const Cmd *cmd );
+static Bool doStat( char *arg, const Cmd *cmd );
+static Bool doQuit( char *arg, const Cmd *cmd );
+static Bool doXhdr( char *arg, const Cmd *cmd );
+static Bool doXpat( char *arg, const Cmd *cmd );
+static Bool doXOver( char *arg, const Cmd *cmd );
+static Bool notImplemented( char *arg, const Cmd *cmd );
+static void putStat( unsigned int stat, const char *fmt, ... );
+
+Cmd commands[] =
+{
+    { "article", "ARTICLE [msg-id|n]", &doArt },
+    { "body", "BODY [msg-id|n]", &doBody },
+    { "head", "HEAD [msg-id|n]", &doHead },
+    { "group", "GROUP grp", &doGrp },
+    { "help", "HELP", &doHelp },
+    { "ihave", "IHAVE (ignored)", &doIhave },
+    { "last", "LAST", &doLast },
+    { "list", "LIST [ACTIVE [pat]]|ACTIVE.TIMES [pat]|"
+      "EXTENSIONS|NEWSGROUPS [pat]|OVERVIEW.FMT", &doList },
+    { "listgroup", "LISTGROUP grp", &doListgrp },
+    { "mode", "MODE (ignored)", &doMode },
+    { "newgroups", "NEWGROUPS [xx]yymmdd hhmmss [GMT]", &doNewgrps },
+    { "newnews", "NEWNEWS (not implemented)", &notImplemented },
+    { "next", "NEXT", &doNext },
+    { "post", "POST", &doPost },
+    { "quit", "QUIT", &doQuit },
+    { "slave", "SLAVE (ignored)", &doSlave },
+    { "stat", "STAT [msg-id|n]", &doStat },
+    { "xhdr", "XHDR over-field [m[-[n]]]", &doXhdr },
+    { "xpat", "XPAT over-field m[-[n]] pat", &doXpat },
+    { "xover", "XOVER [m[-[n]]]", &doXOver }
+};
+
+/*
+  Notice interest in reading this group.
+  Automatically subscribe if option set in config file.
+*/
+static void
+noteInterest( void )
+{
+    FetchMode mode;
+
+    Grp_setLastAccess( serv.grp, time( NULL ) );
+    if ( ! Grp_local ( serv.grp ) && Cfg_autoSubscribe() && ! Online_true() )
+    {
+        Fetchlist_read();
+        if ( ! Fetchlist_contains( serv.grp ) )
+        {
+            if ( strcmp( Cfg_autoSubscribeMode(), "full" ) == 0 )
+                mode = FULL;
+            else if ( strcmp( Cfg_autoSubscribeMode(), "thread" ) == 0 )
+                mode = THREAD;
+            else
+                mode = OVER;
+            Fetchlist_add( serv.grp, mode );
+            Fetchlist_write();
+            Pseudo_autoSubscribed();
+        }
+    }
+}
+
+static void
+putStat( unsigned int stat, const char *fmt, ... )
+{
+    Str s, line;
+    va_list ap;
+
+    ASSERT( stat <= 999 );
+    va_start( ap, fmt );
+    vsnprintf( s, MAXCHAR, fmt, ap );
+    va_end( ap );
+    snprintf( line, MAXCHAR, "%u %s", stat, s );
+    Log_dbg( "[S] %s", line );
+    printf( "%s\r\n", line );
+}
+
+static void
+putTxtLn( const char *fmt, ... )
+{
+    Str line;
+    va_list ap;
+
+    va_start( ap, fmt );
+    vsnprintf( line, MAXCHAR, fmt, ap );
+    va_end( ap );
+    Prt_putTxtLn( line, stdout );
+}
+
+static void
+putTxtBuf( const char *buf )
+{
+    if ( buf )
+        Prt_putTxtBuf( buf, stdout );
+}
+
+static void
+putEndOfTxt( void )
+{
+    Prt_putEndOfTxt( stdout );
+}
+
+static void
+putSyntax( const Cmd *cmd )
+{
+    putStat( STAT_SYNTAX_ERR, "Syntax error. Usage: %s", cmd->syntax );
+}
+
+static Bool
+getLn( Str line )
+{
+    return Prt_getLn( line, stdin );
+}
+
+static Bool
+getTxtLn( Str line, Bool *err )
+{
+    return Prt_getTxtLn( line, err, stdin );
+}
+
+static Bool
+notImplemented( char *arg, const Cmd *cmd )
+{
+    putStat( STAT_NO_PERMISSION, "Command not implemented" );
+    return TRUE;
+}
+
+static void
+checkNewArts( const char *grp )
+{
+    if ( ! Online_true()
+         || strcmp( grp, serv.grp ) == 0
+         || Grp_local( grp )
+         || time( NULL ) - Grp_lastAccess( serv.grp ) < 1800 )
+        return;
+    if ( Fetch_init( Grp_serv( grp ) ) )
+    {
+        Fetch_getNewArts( grp, OVER );
+        Fetch_close();
+    }
+}
+
+static void
+postArts()
+{
+    Str serv;
+
+    Cfg_beginServEnum();
+    while ( Cfg_nextServ( serv ) )
+        if ( Fetch_init( serv ) )
+        {
+            Fetch_postArts();
+            Fetch_close();
+        }
+}
+
+static void
+readCont( const char *name )
+{
+    Fetchlist_read();
+    Cont_read( name );
+    if ( ! Grp_local ( name )
+	 && ! Fetchlist_contains( name )
+	 && ! Online_true() )
+    { 
+        Pseudo_appGeneralInfo();
+        Grp_setFirstLast( name, Cont_first(), Cont_last() );
+    }
+}
+
+static void
+changeToGrp( const char *grp )
+{
+    checkNewArts( grp );
+    Utl_cpyStr( serv.grp, grp );
+    readCont( grp );
+    serv.artPtr = Cont_first();
+}
+
+static Bool
+doGrp( char *arg, const Cmd *cmd )
+{
+    int first, last, numb;
+
+    if ( arg[ 0 ] == '\0' )
+        putSyntax( cmd );
+    else if ( ! Grp_exists( arg ) )
+        putStat( STAT_NO_SUCH_GRP, "No such group" );
+    else
+    {
+        changeToGrp( arg );
+        first = Cont_first();
+        last = Cont_last();
+	if ( ( first == 0 && last == 0 )
+	     || first > last )
+            first = last = numb = 0;
+	else
+	    numb = last - first + 1;
+        putStat( STAT_GRP_SELECTED, "%lu %lu %lu %s selected",
+                 numb, first, last, arg );
+    }
+    return TRUE;
+}
+
+static Bool
+testGrpSelected( void )
+{
+    if ( *serv.grp == '\0' )
+    {
+        putStat( STAT_NO_GRP_SELECTED, "No group selected" );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static void
+findServ( const char *msgId, Str result )
+{
+    const char *p, *pColon, *serv;
+    Str s, grp;
+
+    Utl_cpyStr( result, "(unknown)" );
+    if ( Db_contains( msgId ) )
+    {
+        Utl_cpyStr( s, Db_xref( msgId ) );
+        p = strtok( s, " \t" );
+        if ( p )
+            do
+            {
+                pColon = strstr( p, ":" );
+                if ( pColon )
+                {
+                    Utl_cpyStrN( grp, p, pColon - p );
+                    serv = Grp_serv( grp );
+                    if ( Cfg_servIsPreferential( serv, result ) )
+                        Utl_cpyStr( result, serv );
+                }
+            }
+            while ( ( p = strtok( NULL, " \t" ) ) );
+    }
+}
+
+static Bool
+retrieveArt( const char *msgId )
+{
+    Str serv;
+
+    findServ( msgId, serv );    
+    if ( strcmp( serv, "(unknown)" ) == 0 
+         || strcmp( serv, GRP_LOCAL_SERVER_NAME ) == 0 )
+        return FALSE;        
+    if ( ! Client_connect( serv ) )
+        return FALSE;
+    Client_retrieveArt( msgId );
+    Client_disconnect();
+    return TRUE;
+}
+
+static Bool
+checkNumb( int numb )
+{
+    if ( ! testGrpSelected() )
+        return FALSE;
+    if ( ! Cont_validNumb( numb ) )
+    {
+        putStat( STAT_NO_SUCH_NUMB, "No such article" );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/*
+  Parse arguments for ARTICLE, BODY, HEAD, STAT commands.
+  Return message-ID and article number (0 if unknown).
+*/
+static Bool
+whichId( const char **msgId, int *numb, char *arg )
+{
+    const Over *ov;
+    int n;
+
+    if ( sscanf( arg, "%d", &n ) == 1 )
+    {
+        if ( ! checkNumb( n ) )
+            return FALSE;
+        serv.artPtr = n;
+        ov = Cont_get( n );
+        *msgId = Ov_msgId( ov );
+        *numb = n;
+    }
+    else if ( strcmp( arg, "" ) == 0 )
+    {
+        if ( ! checkNumb( serv.artPtr ) )
+            return FALSE;
+        ov = Cont_get( serv.artPtr );
+        *msgId = Ov_msgId( ov );
+        *numb =  serv.artPtr;
+    }
+    else
+    {
+        *msgId = arg;
+        *numb = 0;
+    }
+    if ( ! Pseudo_isGeneralInfo( *msgId ) && ! Db_contains( *msgId ) )
+    {
+        putStat( STAT_NO_SUCH_NUMB, "No such article" );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+void
+touchArticle( const char *msgId )
+{
+    int stat = Db_stat( msgId );
+    stat |= DB_INTERESTING;
+    Db_setStat( msgId, stat );
+    Db_updateLastAccess( msgId );
+}
+
+static void
+touchReferences( const char *msgId )
+{
+    Str s;
+    int len;
+    char *p;
+    const char *ref = Db_ref( msgId );
+
+    while ( TRUE )
+    {
+        p = s;
+        while ( *ref != '<' )
+            if ( *(ref++) == '\0' )
+                return;
+        len = 0;
+        while ( *ref != '>' )
+        {
+            if ( *ref == '\0' || ++len >= MAXCHAR - 1 )
+                return;
+            *(p++) = *(ref++);
+        }
+        *(p++) = '>';
+        *p = '\0';
+        if ( Db_contains( s ) )
+            touchArticle( s );
+    }
+}
+
+static void
+doBodyInDb( const char *msgId )
+{
+    int stat;
+    Str serv;
+
+    touchArticle( msgId );
+    touchReferences( msgId );
+    stat = Db_stat( msgId );
+    if ( Online_true() && ( stat & DB_NOT_DOWNLOADED ) )
+    {
+        retrieveArt( msgId );
+        stat = Db_stat( msgId );
+    }
+    if ( stat & DB_RETRIEVING_FAILED )
+    {
+        Db_setStat( msgId, stat & ~DB_RETRIEVING_FAILED );
+        putTxtBuf( Db_body( msgId ) );
+    }
+    else if ( stat & DB_NOT_DOWNLOADED )
+    {
+        findServ( msgId, serv );
+        if ( Req_contains( serv, msgId ) )
+            putTxtBuf( Pseudo_alreadyMarkedBody() );
+        else if ( strcmp( serv, "(unknown)" ) != 0 && 
+		  strcmp( serv, GRP_LOCAL_SERVER_NAME ) != 0 && 
+		  Req_add( serv, msgId ) )
+            putTxtBuf( Pseudo_markedBody() );
+        else
+            putTxtBuf( Pseudo_markingFailedBody() );
+    }
+    else
+        putTxtBuf( Db_body( msgId ) );
+}
+
+static Bool
+doBody( char *arg, const Cmd *cmd )
+{
+    const char *msgId;
+    int numb;
+    
+    if ( ! whichId( &msgId, &numb, arg ) )
+        return TRUE;
+    putStat( STAT_BODY_FOLLOWS, "%ld %s Body", numb, msgId );
+    if ( Pseudo_isGeneralInfo( msgId ) )
+        putTxtBuf( Pseudo_generalInfoBody() );
+    else
+        doBodyInDb( msgId );
+    putEndOfTxt();
+    noteInterest();
+    return TRUE;
+}
+
+static void
+doHeadInDb( const char *msgId )
+{
+    putTxtBuf( Db_header( msgId ) );
+}
+
+static Bool
+doHead( char *arg, const Cmd *cmd )
+{
+    const char *msgId;
+    int numb;
+    
+    if ( ! whichId( &msgId, &numb, arg ) )
+        return TRUE;
+    putStat( STAT_HEAD_FOLLOWS, "%ld %s Head", numb, msgId );
+    if ( Pseudo_isGeneralInfo( msgId ) )
+        putTxtBuf( Pseudo_generalInfoHead() );
+    else
+        doHeadInDb( msgId );
+    putEndOfTxt();
+    return TRUE;
+}
+
+static void
+doArtInDb( const char *msgId )
+{
+    doHeadInDb( msgId );
+    putTxtLn( "" );
+    doBodyInDb( msgId );
+}
+
+static Bool
+doArt( char *arg, const Cmd *cmd )
+{
+    const char *msgId;
+    int numb;
+    
+    if ( ! whichId( &msgId, &numb, arg ) )
+        return TRUE;
+    putStat( STAT_ART_FOLLOWS, "%ld %s Article", numb, msgId );
+    if ( Pseudo_isGeneralInfo( msgId ) )
+    {
+        putTxtBuf( Pseudo_generalInfoHead() );
+        putTxtLn( "" );
+        putTxtBuf( Pseudo_generalInfoBody() );
+    }
+    else
+        doArtInDb( msgId );
+    putEndOfTxt();
+    noteInterest();
+    return TRUE;
+}
+
+static Bool
+doHelp( char *arg, const Cmd *cmd )
+{
+    unsigned int i;
+
+    putStat( STAT_HELP_FOLLOWS, "Help" );
+    putTxtBuf( "\nCommands:\n\n" );
+    for ( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); ++i )
+        putTxtLn( "%s", commands[ i ].syntax );
+    putEndOfTxt();
+    return TRUE;
+}
+
+static Bool
+doIhave( char *arg, const Cmd *cmd )
+{
+    putStat( STAT_ART_REJECTED, "Command not used" );
+    return TRUE;
+}
+
+static Bool
+doLast( char *arg, const Cmd *cmd )
+{
+    int n;
+
+    if ( testGrpSelected() )
+    {
+        n = serv.artPtr;
+        if ( ! Cont_validNumb( n ) )
+            putStat( STAT_NO_ART_SELECTED, "No article selected" );
+        else
+        {
+            while ( ! Cont_validNumb( --n ) && n >= Cont_first() );
+            if ( ! Cont_validNumb( n ) )
+                putStat( STAT_NO_PREV_ART, "No previous article" );
+            else
+            {
+                putStat( STAT_ART_RETRIEVED, "%ld %s selected",
+                         n, Ov_msgId( Cont_get( n ) ) );
+                serv.artPtr = n;
+            }
+        }
+    }
+    return TRUE;
+}
+
+static void
+printGroups( const char *pat, void (*printProc)( Str, const char* ) )
+{
+    Str line;
+    const char *g;
+    FILE *f;
+    sig_t lastHandler;
+    int ret;
+
+    putStat( STAT_GRPS_FOLLOW, "Groups" );
+    fflush( stdout );
+    Log_dbg( "[S FLUSH]" );
+    if ( Grp_exists( pat ) )
+    {
+        (*printProc)( line, pat );
+        if ( ! Prt_putTxtLn( line, stdout ) )
+            Log_err( "Writing to stdout failed." );
+    }                    
+    else
+    {
+        lastHandler = signal( SIGPIPE, SIG_IGN );
+        f = popen( "sort", "w" );
+        if ( f == NULL )
+        {
+            Log_err( "Cannot open pipe to 'sort'" );
+            if ( Grp_firstGrp( &g ) )
+                do
+                    if ( Wld_match( g, pat ) )
+                    {
+                        (*printProc)( line, g );
+                        if ( ! Prt_putTxtLn( line, stdout ) )
+                            Log_err( "Writing to stdout failed." );
+                    }
+                while ( Grp_nextGrp( &g ) );
+        }
+        else
+        {
+            if ( Grp_firstGrp( &g ) )
+                do
+                    if ( Wld_match( g, pat ) )
+                    {
+                        (*printProc)( line, g );
+                        if ( ! Prt_putTxtLn( line, f ) )
+                        {
+                            Log_err( "Writing to 'sort' pipe failed." );
+                            break;
+                        }                    
+                    }
+                while ( Grp_nextGrp( &g ) );
+            ret = pclose( f );
+            if ( ret != EXIT_SUCCESS )
+                Log_err( "sort command returned %d", ret );
+            fflush( stdout );
+            Log_dbg( "[S FLUSH]" );
+            signal( SIGPIPE, lastHandler );
+        }
+    }
+    putEndOfTxt();
+}
+
+static void
+printActiveTimes( Str result, const char *grp )
+{
+    snprintf( result, MAXCHAR, "%s %ld", grp, Grp_created( grp ) );
+}
+
+static void
+doListActiveTimes( const char *pat )
+{
+    printGroups( pat, &printActiveTimes );
+}
+
+static void
+printActive( Str result, const char *grp )
+{
+    snprintf( result, MAXCHAR, "%s %d %d %c",
+              grp, Grp_last( grp ), Grp_first( grp ), Grp_postAllow( grp ) );
+}
+
+static void
+doListActive( const char *pat )
+{
+    printGroups( pat, &printActive );
+}
+
+static void
+printNewsgrp( Str result, const char *grp )
+{
+    snprintf( result, MAXCHAR, "%s %s", grp, Grp_dsc( grp ) );
+}
+
+static void
+doListNewsgrps( const char *pat )
+{
+    printGroups( pat, &printNewsgrp );
+}
+
+static void
+putGrp( const char *name )
+{
+    putTxtLn( "%s %lu %lu y", name, Grp_last( name ), Grp_first( name ) );
+}
+
+static void
+doListOverFmt( void )
+{
+    putStat( STAT_GRPS_FOLLOW, "Overview format" );
+    putTxtBuf( "Subject:\n"
+               "From:\n"
+               "Date:\n"
+               "Message-ID:\n"
+               "References:\n"
+               "Bytes:\n"
+               "Lines:\n" );
+    putEndOfTxt();
+}
+
+static void
+doListExtensions( void )
+{
+    putStat( STAT_CMD_OK, "Extensions" );
+    putTxtBuf( " LISTGROUP\n"
+               " XOVER\n" );
+    putEndOfTxt();    
+}
+
+static Bool
+doList( char *line, const Cmd *cmd )
+{
+    Str s, arg;
+    const char *pat;
+
+    if ( sscanf( line, "%s", s ) != 1 )
+        doListActive( "*" );
+    else
+    {
+        Utl_toLower( s );
+        strcpy( arg, Utl_restOfLn( line, 1 ) );
+        pat = Utl_stripWhiteSpace( arg );
+        if ( pat[ 0 ] == '\0' )
+            pat = "*";
+        if ( strcmp( "active", s ) == 0 )
+            doListActive( pat );
+        else if ( strcmp( "overview.fmt", s ) == 0 )
+            doListOverFmt();
+        else if ( strcmp( "newsgroups", s ) == 0 )
+            doListNewsgrps( pat );
+        else if ( strcmp( "active.times", s ) == 0 )
+            doListActiveTimes( pat );
+        else if ( strcmp( "extensions", s ) == 0 )
+            doListExtensions();
+        else
+            putSyntax( cmd );
+    }
+    return TRUE;
+}
+
+static Bool
+doListgrp( char *arg, const Cmd *cmd )
+{
+    const Over *ov;
+    int first, last, i;
+
+    if ( ! Grp_exists( arg ) )
+        putStat( STAT_NO_SUCH_GRP, "No such group" );
+    else
+    {
+        changeToGrp( arg );
+        first = Cont_first();
+        last = Cont_last();
+        putStat( STAT_GRP_SELECTED, "Article list" );
+        for ( i = first; i <= last; ++i )
+            if ( ( ov = Cont_get( i ) ) )
+                putTxtLn( "%lu", i );
+        putEndOfTxt();
+    }
+    return TRUE;
+}
+
+static Bool
+doMode( char *arg, const Cmd *cmd )
+{
+    putStat( STAT_READY_POST_ALLOW, "Ok" );
+    return TRUE;
+}
+
+static unsigned long
+getTimeInSeconds( unsigned int year, unsigned int mon, unsigned int day,
+                  unsigned int hour, unsigned int min, unsigned int sec )
+{
+    struct tm t = { 0 };
+
+    t.tm_year = year - 1900;
+    t.tm_mon = mon - 1;
+    t.tm_mday = day;
+    t.tm_hour = hour;
+    t.tm_min = min;
+    t.tm_sec = sec;
+    return mktime( &t );
+}
+
+
+static Bool
+doNewgrps( char *arg, const Cmd *cmd )
+{
+    time_t t, now, lastUpdate;
+    unsigned int year, mon, day, hour, min, sec, cent, len;
+    const char *g;
+    Str date, timeofday, file;
+
+    if ( sscanf( arg, "%s %s", date, timeofday ) != 2 ) 
+    {
+        putSyntax( cmd );
+        return TRUE;
+    }
+    len = strlen( date );
+    switch ( len )
+    {
+    case 6:
+        if ( sscanf( date, "%2u%2u%2u", &year, &mon, &day ) != 3 )
+        {
+            putSyntax( cmd );
+            return TRUE;
+        }
+        now = time( NULL );
+        cent = 1900;
+        while ( now > getTimeInSeconds( cent + 100, 1, 1, 0, 0, 0 ) )
+            cent += 100;
+        year += cent;
+        break;
+    case 8:
+        if ( sscanf( date, "%4u%2u%2u", &year, &mon, &day ) != 3 )
+        {
+            putSyntax( cmd );
+            return TRUE;
+        }
+        break;
+    default:
+        putSyntax( cmd );
+        return TRUE;
+    }
+    if ( sscanf( timeofday, "%2u%2u%2u", &hour, &min, &sec ) != 3 )
+    {
+        putSyntax( cmd );
+        return TRUE;
+    }
+    if ( year < 1970 || mon == 0 || mon > 12 || day == 0 || day > 31
+         || hour > 23 || min > 59 || sec > 60 )
+    {
+        putSyntax( cmd );
+        return TRUE;
+    }
+    snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() );
+    t = getTimeInSeconds( year, mon, day, hour, min, sec );
+    putStat( STAT_NEW_GRP_FOLLOW, "New groups since %s", arg );
+
+    if ( ! Utl_getStamp( &lastUpdate, file ) || t <= lastUpdate )
+    {
+        if ( Grp_firstGrp( &g ) )
+            do
+                if ( Grp_created( g ) > t )
+                    putGrp( g );
+            while ( Grp_nextGrp( &g ) );
+    }
+    putEndOfTxt();
+    return TRUE;
+}
+
+static Bool
+doNext( char *arg, const Cmd *cmd )
+{
+    int n;
+
+    if ( testGrpSelected() )
+    {
+        n = serv.artPtr;
+        if ( ! Cont_validNumb( n ) )
+            putStat( STAT_NO_ART_SELECTED, "No article selected" );
+        else
+        {
+            while ( ! Cont_validNumb( ++n ) && n <= Cont_last() );
+            if ( ! Cont_validNumb( n ) )
+                putStat( STAT_NO_NEXT_ART, "No next article" );
+            else
+            {
+                putStat( STAT_ART_RETRIEVED, "%ld %s selected",
+                         n, Ov_msgId( Cont_get( n ) ) );
+                serv.artPtr = n;
+            }
+        }
+    }
+    return TRUE;
+}
+
+/* Cancel and return TRUE if need to send cancel message on to server. */
+static Bool
+controlCancel( const char *cancelId )
+{
+    return ( Ctrl_cancel( cancelId ) == CANCEL_NEEDS_MSG );
+}
+
+/*
+  It's a control message. Currently we only know about 'cancel'
+  messages; others are passed on for outside groups, and logged
+  as ignored for local groups.
+ */
+static Bool
+handleControl( ItemList *control, ItemList *newsgroups,
+	       const char *msgId, const DynStr *art )
+{
+    const char *grp;
+    const char *op;
+    Bool err = FALSE;
+    Bool localDone = FALSE;
+
+    op = Itl_first( control );
+    if ( op == NULL )
+    {
+	Log_err( "Malformed control line." );
+	return TRUE;
+    }
+    else if ( strcasecmp( op, "cancel" ) == 0 )
+    {
+	if ( controlCancel( Itl_next( control ) ) )
+	    localDone = TRUE;
+	else
+	    return err;
+    }
+
+    /* Pass on for outside groups. */
+    for( grp = Itl_first( newsgroups );
+	 grp != NULL;
+	 grp = Itl_next( newsgroups ) )
+    {
+	if ( Grp_exists( grp ) && ! Grp_local( grp ) )
+	{
+	    if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
+	    {
+		Log_err( "Cannot add posted article to outgoing directory" );
+		err = TRUE;
+	    }
+	    break;
+	}
+    }
+
+    if ( localDone )
+	return err;
+
+    /* Log 'can't do' for internal groups. */
+    for( grp = Itl_first( newsgroups );
+	 grp != NULL;
+	 grp = Itl_next( newsgroups ) )
+    {
+	if ( Grp_exists( grp ) && Grp_local( grp ) )
+	    Log_inf( "Ignoring control '%s' for '%s'.", op, grp );
+    }
+
+    return err;
+}
+
+static Bool
+postArticle( ItemList *newsgroups, const char *msgId, const DynStr *art )
+{
+    const char *grp;
+    Bool err;
+    Bool oneLocal;
+
+    err = oneLocal = FALSE;
+
+    /* Run round first doing all local groups. */ 
+    for( grp = Itl_first( newsgroups );
+	 grp != NULL;
+	 grp = Itl_next( newsgroups ) )
+    {
+	if ( Grp_local( grp ) )
+	{
+	    if ( ! oneLocal )
+	    {
+		if ( ! Post_open( DynStr_str( art ) ) )
+		{
+		    err = TRUE;
+		    break;
+		}
+		else
+		    oneLocal = TRUE;
+	    }
+
+	    if ( ! Post_add( grp ) )
+		err = TRUE;
+	}
+    }
+    if ( oneLocal )
+	Post_close();
+
+    /* Now look for a valid external group. */
+    for( grp = Itl_first( newsgroups );
+	 grp != NULL;
+	 grp = Itl_next( newsgroups ) )
+    {
+	if ( Grp_exists( grp ) && ! Grp_local( grp ) )
+	{
+	    if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
+	    {
+		Log_err( "Cannot add posted article to outgoing directory" );
+		err = TRUE;
+	    }
+	    break;
+	}
+    }
+
+    return err;
+}
+
+static Bool
+doPost( char *arg, const Cmd *cmd )
+{
+    Bool err, replyToFound, dateFound, inHeader;
+    DynStr *s;
+    Str line, field, val, msgId, from;
+    const char* p;
+    ItemList * newsgroups, *control;
+
+    /*
+      Get article and make following changes to the header:
+      - add/replace/cut Message-ID depending on config options
+      - add Reply-To with content of From, if missing
+      (some providers overwrite From field)
+      - rename X-Sender header to X-NOFFLE-X-Sender
+      (some providers want to insert their own X-Sender)
+
+      For doing this, it is not necessary to parse multiple-line
+      headers.
+    */
+    putStat( STAT_SEND_ART, "Continue (end with period)" );
+    fflush( stdout );
+    Log_dbg( "[S FLUSH]" );
+    s = new_DynStr( 10000 );
+    msgId[ 0 ] = '\0';
+    from[ 0 ] = '\0';
+    newsgroups = control = NULL;
+    replyToFound = dateFound = FALSE;
+    inHeader = TRUE;
+    while ( getTxtLn( line, &err ) )
+    {
+        if ( inHeader )
+        {
+            p = Utl_stripWhiteSpace( line );
+            if ( *p == '\0' )
+            {
+                inHeader = FALSE;
+                if ( from[ 0 ] == '\0' )
+                    Log_err( "Posted message has no From field" );
+                if ( ! Cfg_removeMsgId() )
+                {
+                    if ( Cfg_replaceMsgId() )
+                    {
+                        Prt_genMsgId( msgId, from, "NOFFLE" );
+                        Log_dbg( "Replacing Message-ID with '%s'", msgId );
+                    }
+                    else if ( msgId[ 0 ] == '\0' )
+                    {
+                        Prt_genMsgId( msgId, from, "NOFFLE" );
+
+                        Log_inf( "Adding missing Message-ID '%s'", msgId );
+                    }
+                    else if ( ! Prt_isValidMsgId( msgId ) )
+                    {
+                        Log_ntc( "Replacing invalid Message-ID with '%s'",
+                                 msgId );
+                        Prt_genMsgId( msgId, from, "NOFFLE" );
+                    }
+                    DynStr_app( s, "Message-ID: " );
+                    DynStr_appLn( s, msgId );
+                }
+                if ( ! replyToFound && from[ 0 ] != '\0' )
+                {
+                    Log_dbg( "Adding Reply-To field to posted message." );
+                    DynStr_app( s, "Reply-To: " );
+                    DynStr_appLn( s, from );
+                }
+		if ( ! dateFound )
+		{
+		    time_t t;
+
+		    time( &t );
+		    Utl_rfc822Date( t, val );
+		    DynStr_app( s, "Date: " );
+		    DynStr_appLn( s, val );
+		}
+                DynStr_appLn( s, p );
+            }
+            else if ( Prt_getField( field, val, p ) )
+            {
+                if ( strcmp( field, "message-id" ) == 0 )
+                    strcpy( msgId, val );
+                else if ( strcmp( field, "from" ) == 0 )
+                {
+                    strcpy( from, val );
+                    DynStr_appLn( s, p );
+                }
+                else if ( strcmp( field, "newsgroups" ) == 0 )
+                {
+		    Utl_toLower( val );
+		    newsgroups = new_Itl ( val, " ," );
+                    DynStr_appLn( s, p );
+                }
+                else if ( strcmp( field, "control" ) == 0 )
+                {
+		    control = new_Itl ( val, " " );
+                    DynStr_appLn( s, p );
+                }
+                else if ( strcmp( field, "reply-to" ) == 0 )
+                {
+                    replyToFound = TRUE;
+                    DynStr_appLn( s, p );
+                }
+                else if ( strcmp( field, "date" ) == 0 )
+                {
+                    dateFound = TRUE;
+                    DynStr_appLn( s, p );
+                }
+                else if ( strcmp( field, "x-sender" ) == 0 )
+                {
+                    DynStr_app( s, "X-NOFFLE-X-Sender: " );
+                    DynStr_appLn( s, val );
+                }
+                else
+                    DynStr_appLn( s, p );
+            }
+            else
+                DynStr_appLn( s, line );
+        }
+        else
+            DynStr_appLn( s, line );
+    }
+    if ( inHeader )
+        Log_err( "Posted message has no body" );
+    if ( ! err )
+    {
+        if ( newsgroups == NULL || Itl_count( newsgroups ) == 0 )
+        {
+            Log_err( "Posted message has no valid Newsgroups header field" );
+            err = TRUE;
+        }
+        else
+	{
+	    const char *grp;
+	    Bool knownGrp = FALSE;
+	    Bool postAllowedGrp = FALSE;
+
+	    /* Check at least one group is known. */
+	    for( grp = Itl_first( newsgroups );
+		 grp != NULL;
+		 grp = Itl_next( newsgroups ) )
+	    {
+		if ( Grp_exists( grp ) )
+		{
+		    knownGrp = TRUE;
+		    switch( Grp_postAllow( grp ) )
+		    {
+		    case 'n':
+			break;
+		    case 'm':
+			/* Can't post to moderated local groups. */
+			postAllowedGrp = ! Grp_local( grp );
+			break;
+		    default:
+			postAllowedGrp = TRUE;
+		    }
+		    if ( postAllowedGrp )
+			break;
+		}
+	    }
+	    
+	    if ( ! knownGrp )
+	    {
+
+		Log_err( "No known group in Newsgroups header field" );
+		err = TRUE;
+	    }
+	    else if ( ! postAllowedGrp )
+	    {
+
+		Log_err( "No group permits posting" );
+		err = TRUE;
+	    }
+	    else
+	    {
+		err = ( control == NULL )
+		    ? postArticle( newsgroups, msgId, s )
+		    : handleControl( control, newsgroups, msgId, s );
+	    }	    
+	}
+    }
+    if ( err )
+        putStat( STAT_POST_FAILED, "Posting failed" );
+    else
+    {
+        putStat( STAT_POST_OK, "Message posted" );
+        if ( Online_true() )
+            postArts();
+    }
+    del_Itl( newsgroups );
+    del_Itl( control );
+    del_DynStr( s );
+    return TRUE;
+}
+
+static void
+parseRange( const char *s, int *first, int *last, int *numb )
+{
+    int r, i;
+    char* p;
+    Str t;
+
+    Utl_cpyStr( t, s );
+    p = Utl_stripWhiteSpace( t );
+    r = sscanf( p, "%d-%d", first, last );
+    if ( r < 1 )
+    {
+        *first = serv.artPtr;
+        *last = serv.artPtr;
+    }
+    else if ( r == 1 )
+    {
+        if ( p[ strlen( p ) - 1 ] == '-' )
+            *last = Cont_last();
+        else
+            *last = *first;
+    }    
+    if ( *first < Cont_first() )
+        *first = Cont_first();
+    if ( *last > Cont_last() )
+        *last = Cont_last();
+    if ( *first > Cont_last() ||  *last < Cont_first() )
+        *last = *first - 1;
+    *numb = 0;
+    for ( i = *first; i <= *last; ++i )
+        if ( Cont_validNumb( i ) )
+            ++(*numb);
+}
+
+static Bool
+doXhdr( char *arg, const Cmd *cmd )
+{
+    int first, last, i, n, numb;
+    enum { SUBJ, FROM, DATE, MSG_ID, REF, BYTES, LINES } what;
+    const char *p;
+    const Over *ov;
+    Str whatStr;
+
+    if ( ! testGrpSelected() )
+        return TRUE;
+    if ( sscanf( arg, "%s", whatStr ) != 1 )
+    {
+        putSyntax( cmd );
+        return TRUE;
+    }
+    Utl_toLower( whatStr );
+    if ( strcmp( whatStr, "subject" ) == 0 )
+        what = SUBJ;
+    else if ( strcmp( whatStr, "from" ) == 0 )
+        what = FROM;
+    else if ( strcmp( whatStr, "date" ) == 0 )
+        what = DATE;
+    else if ( strcmp( whatStr, "message-id" ) == 0 )
+        what = MSG_ID;
+    else if ( strcmp( whatStr, "references" ) == 0 )
+        what = REF;
+    else if ( strcmp( whatStr, "bytes" ) == 0 )
+        what = BYTES;
+    else if ( strcmp( whatStr, "lines" ) == 0 )
+        what = LINES;
+    else
+    {
+        putStat( STAT_HEAD_FOLLOWS, "Unknown header (empty list follows)" );
+        putEndOfTxt();
+        return TRUE;
+    }
+    p = Utl_restOfLn( arg, 1 );
+    parseRange( p, &first, &last, &numb );
+    if ( numb == 0 )
+        putStat( STAT_NO_ART_SELECTED, "No articles selected" );
+    else
+    {
+        putStat( STAT_HEAD_FOLLOWS, "%s header %lu-%lu",
+                 whatStr, first, last ) ;
+        for ( i = first; i <= last; ++i )
+            if ( ( ov = Cont_get( i ) ) )
+            {
+                n = Ov_numb( ov );
+                switch ( what )
+                {
+                case SUBJ:
+                    putTxtLn( "%lu %s", n, Ov_subj( ov ) );
+                    break;
+                case FROM:
+                    putTxtLn( "%lu %s", n, Ov_from( ov ) );
+                    break;
+                case DATE:
+                    putTxtLn( "%lu %s", n, Ov_date( ov ) );
+                    break;
+                case MSG_ID:
+                    putTxtLn( "%lu %s", n, Ov_msgId( ov ) );
+                    break;
+                case REF:
+                    putTxtLn( "%lu %s", n, Ov_ref( ov ) );
+                    break;
+                case BYTES:
+                    putTxtLn( "%lu %d", n, Ov_bytes( ov ) );
+                    break;
+                case LINES:
+                    putTxtLn( "%lu %d", n, Ov_lines( ov ) );
+                    break;
+                default:
+                    ASSERT( FALSE );
+                }
+            }
+        putEndOfTxt();
+    }
+    return TRUE;
+}
+
+static Bool
+doXpat( char *arg, const Cmd *cmd )
+{
+    int first, last, i, n;
+    enum { SUBJ, FROM, DATE, MSG_ID, REF } what;
+    const Over *ov;
+    Str whatStr, pat;
+
+    if ( ! testGrpSelected() )
+        return TRUE;
+    if ( sscanf( arg, "%s %d-%d %s", whatStr, &first, &last, pat ) != 4 )
+    {
+        if ( sscanf( arg, "%s %d- %s", whatStr, &first, pat ) == 3 )
+            last = Cont_last();
+        else if ( sscanf( arg, "%s %d %s", whatStr, &first, pat ) == 3 )
+            last = first;
+        else
+        {
+            putSyntax( cmd );
+            return TRUE;
+        }
+    }
+    Utl_toLower( whatStr );
+    if ( strcmp( whatStr, "subject" ) == 0 )
+        what = SUBJ;
+    else if ( strcmp( whatStr, "from" ) == 0 )
+        what = FROM;
+    else if ( strcmp( whatStr, "date" ) == 0 )
+        what = DATE;
+    else if ( strcmp( whatStr, "message-id" ) == 0 )
+        what = MSG_ID;
+    else if ( strcmp( whatStr, "references" ) == 0 )
+        what = REF;
+    else
+    {
+        putStat( STAT_HEAD_FOLLOWS, "invalid header (empty list follows)" );
+        putEndOfTxt();
+        return TRUE;
+    }
+    putStat( STAT_HEAD_FOLLOWS, "header" ) ;
+    for ( i = first; i <= last; ++i )
+        if ( ( ov = Cont_get( i ) ) )
+        {
+            n = Ov_numb( ov );
+            switch ( what )
+            {
+            case SUBJ:
+                if ( Wld_match( Ov_subj( ov ), pat ) )
+                     putTxtLn( "%lu %s", n, Ov_subj( ov ) );
+                break;
+            case FROM:
+                if ( Wld_match( Ov_from( ov ), pat ) )
+                    putTxtLn( "%lu %s", n, Ov_from( ov ) );
+                break;
+            case DATE:
+                if ( Wld_match( Ov_date( ov ), pat ) )
+                    putTxtLn( "%lu %s", n, Ov_date( ov ) );
+                break;
+            case MSG_ID:
+                if ( Wld_match( Ov_msgId( ov ), pat ) )
+                    putTxtLn( "%lu %s", n, Ov_msgId( ov ) );
+                break;
+            case REF:
+                if ( Wld_match( Ov_ref( ov ), pat ) )
+                    putTxtLn( "%lu %s", n, Ov_ref( ov ) );
+                break;
+            default:
+                ASSERT( FALSE );
+            }
+        }
+    putEndOfTxt();
+    return TRUE;
+}
+
+static Bool
+doSlave( char *arg, const Cmd *cmd )
+{
+    putStat( STAT_CMD_OK, "Ok" );
+    return TRUE;
+}
+
+static Bool
+doStat( char *arg, const Cmd *cmd )
+{
+    const char *msgId;
+    int numb;
+    
+    if ( ! whichId( &msgId, &numb, arg ) )
+        return TRUE;
+    if ( numb > 0 )
+        putStat( STAT_ART_RETRIEVED, "%ld %s selected",
+                 numb, msgId );
+    else
+        putStat( STAT_ART_RETRIEVED, "0 %s selected", msgId );
+    return TRUE;
+}
+
+static Bool
+doQuit( char *arg, const Cmd *cmd )
+{
+    putStat( STAT_GOODBYE, "Goodbye" );
+    return FALSE;
+}
+
+static Bool
+doXOver( char *arg, const Cmd *cmd )
+{
+    int first, last, i, n;
+    const Over *ov;
+
+    if ( ! testGrpSelected() )
+        return TRUE;
+    parseRange( arg, &first, &last, &n );
+    if ( n == 0 )
+        putStat( STAT_NO_ART_SELECTED, "No articles selected" );
+    else
+    {
+        putStat( STAT_OVERS_FOLLOW, "Overview %ld-%ld", first, last );
+        for ( i = first; i <= last; ++i )
+            if ( ( ov = Cont_get( i ) ) )
+                putTxtLn( "%lu\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t",
+                          Ov_numb( ov ), Ov_subj( ov ), Ov_from( ov ),
+                          Ov_date( ov ), Ov_msgId( ov ), Ov_ref( ov ),
+                          Ov_bytes( ov ), Ov_lines( ov ) );
+        putEndOfTxt();
+    }
+    return TRUE;
+}
+
+static void
+putFatal( const char *fmt, ... )
+{
+    va_list ap;
+    Str s;
+
+    va_start( ap, fmt );
+    vsnprintf( s, MAXCHAR, fmt, ap );
+    va_end( ap );
+    Log_err( s );
+    putStat( STAT_PROGRAM_FAULT, "%s", s );
+    fflush( stdout );
+    Log_dbg( "[S FLUSH]" );
+}
+
+/* Parse line, execute command and return FALSE, if it was the quit command. */
+static Bool
+parseAndExecute( Str line )
+{
+    unsigned int i, n;
+    Cmd *c;
+    Str s, arg;
+    Bool ret;
+
+    if ( sscanf( line, "%s", s ) == 1 )
+    {
+        Utl_toLower( s );
+        strcpy( arg, Utl_restOfLn( line, 1 ) );
+        n = sizeof( commands ) / sizeof( commands[ 0 ] );
+        for ( i = 0, c = commands; i < n; ++i, ++c )
+            if ( strcmp( c->name, s ) == 0 )
+            {
+                ret = c->cmdProc( Utl_stripWhiteSpace( arg ), c );
+                fflush( stdout );
+                Log_dbg( "[S FLUSH]" );
+                return ret;
+            }
+    }
+    putStat( STAT_NO_SUCH_CMD, "Command not recognized" );
+    fflush( stdout );
+    Log_dbg( "[S FLUSH]" );
+    return TRUE;
+}
+
+static void
+putWelcome( void )
+{
+    putStat( STAT_READY_POST_ALLOW, "NNTP server NOFFLE %s",
+             Cfg_version() );
+    fflush( stdout );
+    Log_dbg( "[S FLUSH]" );
+}
+
+static Bool
+initServ( void )
+{
+    ASSERT( ! serv.running );
+    if ( ! Lock_openDatabases() )
+      return FALSE;
+    serv.running = TRUE;
+    return TRUE;
+}
+
+static void
+closeServ( void )
+{
+    ASSERT( serv.running );
+    serv.running = FALSE;
+    Lock_closeDatabases();
+}
+
+void
+Serv_run( void )
+{
+    Bool done;
+    int r;
+    Str line;
+    struct timeval timeOut;
+    fd_set readSet;
+
+    putWelcome();
+    done = FALSE;
+    while ( ! done )
+    {
+        FD_ZERO( &readSet );
+        FD_SET( STDIN_FILENO, &readSet );
+        /* Never hold lock more than 5 seconds (empirically good value,
+           avoids to close/open databases, if clients sends several
+           commands, but releases the lock often enough, for allowing
+           multiple persons to read news at the same time) */
+        timeOut.tv_sec = 5;
+        timeOut.tv_usec = 0;
+        r = select( STDIN_FILENO + 1, &readSet, NULL, NULL, &timeOut );
+        if ( r < 0 )
+            done = TRUE;
+        else if ( r == 0 )
+        {
+            if ( serv.running )
+                closeServ();
+        }
+        else /* ( r > 0 ) */
+        {
+            if ( ! serv.running )
+            {
+                if ( ! initServ() )
+                {
+                    putFatal( "Cannot init server" );
+                    done = TRUE;
+                }
+            }
+            if ( ! getLn( line ) )
+            {
+                Log_inf( "Client disconnected. Terminating." );
+                done = TRUE;
+            }
+            else if ( ! parseAndExecute( line ) )
+                done = TRUE;
+        }
+    }
+    if ( serv.running )
+        closeServ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,14 @@
+/*
+  server.h
+
+  Be NNTP server on stdin/stdout.
+
+  $Id: server.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef SERV_H
+#define SERV_H
+
+void Serv_run( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/util.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,255 @@
+/*
+  util.c
+
+  $Id: util.c 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#include "util.h"
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include "configfile.h"
+#include "log.h"
+#include "wildmat.h"
+
+static const char *
+nextWhiteSpace( const char *p )
+{
+    while ( *p && ! isspace( *p ) )
+        ++p;
+    return p;
+}
+
+static const char *
+nextNonWhiteSpace( const char *p )
+{
+    while ( *p && isspace( *p ) )
+        ++p;
+    return p;
+}
+
+const char *
+Utl_restOfLn( const char *line, unsigned int token )
+{
+    unsigned int i;
+    const char *p;
+
+    p = line;
+    for ( i = 0; i < token; ++i )
+    {
+        p = nextNonWhiteSpace( p );
+        p = nextWhiteSpace( p );
+    }
+    p = nextNonWhiteSpace( p );
+    return p;
+}
+
+const char *
+Utl_getLn( Str result, const char *pos )
+{
+    int len = 0;
+    const char *p = pos;
+
+    if ( ! p )
+        return NULL;
+    while ( *p != '\n' )
+    {
+        if ( *p == '\0' )
+        {
+            if ( len > 0 )
+                Log_err( "Line not terminated by newline: '%s'", pos );
+            return NULL;
+        }
+        *(result++) = *(p++);
+        ++len;
+        if ( len >= MAXCHAR - 1 )
+        {
+            *result = '\0';
+            Log_err( "Utl_getLn: line too long: %s", result );
+            return ++p;
+        }
+    }
+    *result = '\0';
+    return ++p;
+
+}
+
+const char *
+Utl_ungetLn( const char *str, const char *p )
+{
+    if ( str == p )
+        return FALSE;
+    --p;
+    if ( *p != '\n' )
+    {
+        Log_dbg( "Utl_ungetLn: not at beginning of line" );
+        return NULL;
+    }
+    --p;
+    while ( TRUE )
+    {
+        if ( p == str )
+            return p;
+        if ( *p == '\n' )
+            return p + 1;
+        --p;
+    }
+}
+
+const char *
+Utl_getHeaderLn( Str result, const char *p )
+{
+    const char * res = Utl_getLn( result, p );
+
+    /* Look for followon line if this isn't a blank line. */
+    if ( res != NULL && !isspace( result[ 0 ] ) )
+	while ( res != NULL && res[ 0 ] != '\n' && isspace( res[ 0 ] ) )
+	{
+	    Str nextLine;
+	    const char *here;
+	    char *next;
+
+	    here = res;
+	    res = Utl_getLn( nextLine, res );
+	    next = Utl_stripWhiteSpace( nextLine );
+
+	    if ( next[ 0 ] != '\0' )
+	    {
+		Utl_catStr( result, " " );
+		Utl_catStr( result, next );
+	    }
+	    else
+	    {
+		res = here;
+		break;
+	    }
+	}
+
+    return res;
+}
+
+void
+Utl_toLower( Str line )
+{
+    char *p;
+
+    p = line;
+    while ( *p )
+    {
+        *p = tolower( *p );
+        ++p;
+    }
+}
+
+char *
+Utl_stripWhiteSpace( char *line )
+{
+    char *p;
+
+    while ( isspace( *line ) )
+        ++line;
+    p = line + strlen( line ) - 1;
+    while ( isspace( *p ) )
+    {
+        *p = '\0';
+        --p;
+    }
+    return line;
+}
+
+void
+Utl_stripComment( char *line )
+{
+    for ( ; *line != '\0'; line++ )
+	if ( *line =='#' )
+	{
+	    *line = '\0';
+	    break;
+	}
+}
+
+void
+Utl_cpyStr( Str dst, const char *src )
+{
+    dst[ 0 ] = '\0';
+    strncat( dst, src, MAXCHAR );
+}
+
+void
+Utl_cpyStrN( Str dst, const char *src, size_t n )
+{
+    if ( n > MAXCHAR )
+    	n = MAXCHAR;
+    dst[ 0 ] = '\0';
+    strncat( dst, src, n );
+}
+
+void
+Utl_catStr( Str dst, const char *src )
+{
+    strncat( dst, src, MAXCHAR - strlen( dst ) );
+}
+
+void
+Utl_catStrN( Str dst, const char *src, size_t n )
+{
+    if ( n > MAXCHAR - strlen( dst ) )
+    	n = MAXCHAR - strlen( dst );
+    strncat( dst, src, n );
+}
+
+void
+Utl_stamp( Str file )
+{
+    FILE *f;
+    time_t t;
+
+    time( &t );
+    if ( ! ( f = fopen( file, "w" ) ) )
+    {
+        Log_err( "Could not open %s for writing (%s)",
+                 file, strerror( errno ) );
+        return;
+    }
+    fprintf( f, "%lu\n", t );
+    fclose( f );
+}
+
+Bool
+Utl_getStamp( time_t *result, Str file )
+{
+    FILE *f;
+
+    if ( ! ( f = fopen( file, "r" ) ) )
+        return FALSE;
+    if ( fscanf( f, "%lu", result ) != 1 )
+    {
+        Log_err( "File %s corrupted", file );
+        fclose( f );
+        return FALSE;
+    }
+    fclose( f );
+    return TRUE;
+}
+
+void
+Utl_rfc822Date( time_t t, Str res )
+{
+    strftime( res, MAXCHAR,"%a, %d %b %Y %H:%M:%S %z", localtime( &t ) );
+}
+
+void
+Utl_allocAndCpy( char **dst, const char *src )
+{
+    int len = strlen( src );
+    if ( ! ( *dst = (char *)malloc( len + 1 ) ) )
+    {
+        Log_err( "Cannot allocate string with length %lu", strlen( src ) );
+        exit( EXIT_FAILURE );
+    }
+    memcpy( *dst, src, len + 1 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/util.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,84 @@
+/*
+  util.h
+
+  Miscellaneous helper functions.
+
+  $Id: util.h 49 2000-05-05 21:45:56Z uh1763 $
+*/
+
+#ifndef UTL_H
+#define UTL_H
+
+#include <time.h>
+#include "common.h"
+
+/*
+  Find first non-whitespace character after <token> tokens in string <line>.
+  Return pointer to end of string, if parsing failed.
+*/
+const char *
+Utl_restOfLn( const char *line, unsigned int token );
+
+void
+Utl_toLower( Str line );
+
+/*
+  Read a line from string.
+  Return NULL if pos == NULL or no more line to read
+*/
+const char *
+Utl_getLn( Str result, const char *p );
+
+/*
+  Go back to last line.
+*/
+const char *
+Utl_ungetLn( const char *str, const char *p );
+
+/*
+  Read a header line from string. Reads continuation lines if
+  necessary. Return NULL if pos == NULL or no more line to read
+*/
+const char *
+Utl_getHeaderLn( Str result, const char *p );
+
+/*
+  Strip white spaces from left and right side.
+  Return pointer to new start. This is within line.
+*/
+char *
+Utl_stripWhiteSpace( char *line );
+
+/* Strip comment from a line. Comments start with '#'. */
+void
+Utl_stripComment( char *line );
+
+/* Write timestamp into <file>. */
+void
+Utl_stamp( Str file );
+
+/* Get time stamp from <file> */
+Bool
+Utl_getStamp( time_t *result, Str file );
+
+/* Put RFC822-compliant date string into res. */
+void
+Utl_rfc822Date( time_t t, Str res );
+
+void
+Utl_cpyStr( Str dst, const char *src );
+
+void
+Utl_cpyStrN( Str dst, const char *src, size_t n );
+
+void
+Utl_catStr( Str dst, const char *src );
+
+void
+Utl_catStrN( Str dst, const char *src, size_t n );
+
+/* String allocation and copying. */
+void
+Utl_allocAndCpy( char **dst, const char *src );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wildmat.c	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,206 @@
+/*
+  wildmat.c
+
+  Taken from the INN 2.2 distribution and slightly altered to fit the
+  Noffle environment. Changes are:
+  o Rename wildmat() to Wld_match().
+  o Adjust includes.
+  
+  $Id: wildmat.c 49 2000-05-05 21:45:56Z uh1763 $
+
+  The entire INN distribution is covered by the following copyright
+  notice. As this file originated in the INN distribution is it
+  subject to the conditions of this notice.
+  
+    Copyright 1991 Rich Salz.
+    All rights reserved.
+    $Revision: 49 $
+
+    Redistribution and use in any form are permitted provided that the
+    following restrictions are are met:
+        1.  Source distributions must retain this entire copyright notice
+            and comment.
+        2.  Binary distributions must include the acknowledgement ``This
+            product includes software developed by Rich Salz'' in the
+            documentation or other materials provided with the
+            distribution.  This must not be represented as an endorsement
+            or promotion without specific prior written permission.
+        3.  The origin of this software must not be misrepresented, either
+            by explicit claim or by omission.  Credits must appear in the
+            source and documentation.
+        4.  Altered versions must be plainly marked as such in the source
+            and documentation and must not be misrepresented as being the
+            original software.
+    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*  $Revision: 49 $
+**
+**  Do shell-style pattern matching for ?, \, [], and * characters.
+**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
+**  could cause a segmentation violation.  It is 8bit clean.
+**
+**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+**  Rich $alz is now <rsalz@osf.org>.
+**  April, 1991:  Replaced mutually-recursive calls with in-line code
+**  for the star character.
+**
+**  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
+**  This can greatly speed up failing wildcard patterns.  For example:
+**	pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+**	text 1:	 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
+**	text 2:	 -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
+**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
+**  the ABORT code, it takes 22310 calls to fail.  Ugh.  The following
+**  explanation is from Lars:
+**  The precondition that must be fulfilled is that DoMatch will consume
+**  at least one character in text.  This is true if *p is neither '*' nor
+**  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
+**  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
+**  FALSE, each star-loop has to run to the end of the text; with ABORT
+**  only the last one does.
+**
+**  Once the control of one instance of DoMatch enters the star-loop, that
+**  instance will return either TRUE or ABORT, and any calling instance
+**  will therefore return immediately after (without calling recursively
+**  again).  In effect, only one star-loop is ever active.  It would be
+**  possible to modify the code to maintain this context explicitly,
+**  eliminating all recursive calls at the cost of some complication and
+**  loss of clarity (and the ABORT stuff seems to be unclear enough by
+**  itself).  I think it would be unwise to try to get this into a
+**  released version unless you have a good test data base to try it out
+**  on.
+*/
+#include <stdio.h>
+#include <sys/types.h>
+#include "common.h"
+#include "log.h"
+
+#define	ABORT		(-1)
+
+/* What character marks an inverted character class? */
+#define NEGATE_CLASS		'^'
+    /* Is "*" a common pattern? */
+#define OPTIMIZE_JUST_STAR
+    /* Do tar(1) matching rules, which ignore a trailing slash? */
+#undef MATCH_TAR_PATTERN
+
+
+/*
+**  Match text and p, return TRUE, FALSE, or ABORT.
+*/
+static int DoMatch(const char *text, const char *p)
+{
+    int	                last;
+    int	                matched;
+    int	                reverse;
+
+    for ( ; *p; text++, p++) {
+	if (*text == '\0' && *p != '*')
+	    return ABORT;
+	switch (*p) {
+	case '\\':
+	    /* Literal match with following character. */
+	    p++;
+	    /* FALLTHROUGH */
+	default:
+	    if (*text != *p)
+		return FALSE;
+	    continue;
+	case '?':
+	    /* Match anything. */
+	    continue;
+	case '*':
+	    while (*++p == '*')
+		/* Consecutive stars act just like one. */
+		continue;
+	    if (*p == '\0')
+		/* Trailing star matches everything. */
+		return TRUE;
+	    while (*text)
+		if ((matched = DoMatch(text++, p)) != FALSE)
+		    return matched;
+	    return ABORT;
+	case '[':
+	    reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
+	    if (reverse)
+		/* Inverted character class. */
+		p++;
+	    matched = FALSE;
+	    if (p[1] == ']' || p[1] == '-')
+		if (*++p == *text)
+		    matched = TRUE;
+	    for (last = *p; *++p && *p != ']'; last = *p)
+		/* This next line requires a good C compiler. */
+		if (*p == '-' && p[1] != ']'
+		    ? *text <= *++p && *text >= last : *text == *p)
+		    matched = TRUE;
+	    if (matched == reverse)
+		return FALSE;
+	    continue;
+	}
+    }
+
+#ifdef	MATCH_TAR_PATTERN
+    if (*text == '/')
+	return TRUE;
+#endif	/* MATCH_TAR_ATTERN */
+    return *text == '\0';
+}
+
+
+/*
+**  User-level routine.  Returns TRUE or FALSE.
+*/
+Bool
+Wld_match(const char *text, const char *pattern)
+{
+#ifdef	OPTIMIZE_JUST_STAR
+    if (pattern[0] == '*' && pattern[1] == '\0')
+	return TRUE;
+#endif	/* OPTIMIZE_JUST_STAR */
+    return DoMatch(text, pattern) == TRUE;
+}
+
+
+
+#if	defined(WILDMAT_TEST)
+
+/* Yes, we use gets not fgets.  Sue me. */
+extern char	*gets();
+
+
+int
+main()
+{
+    char	 p[80];
+    char	 text[80];
+
+    printf("Wildmat tester.  Enter pattern, then strings to test.\n");
+    printf("A blank line gets prompts for a new pattern; a blank pattern\n");
+    printf("exits the program.\n");
+
+    for ( ; ; ) {
+	printf("\nEnter pattern:  ");
+	(void)fflush(stdout);
+	if (gets(p) == NULL || p[0] == '\0')
+	    break;
+	for ( ; ; ) {
+	    printf("Enter text:  ");
+	    (void)fflush(stdout);
+	    if (gets(text) == NULL)
+		exit(0);
+	    if (text[0] == '\0')
+		/* Blank line; go back and get a new pattern. */
+		break;
+	    printf("      %s\n", Wld_match(text, p) ? "YES" : "NO");
+	}
+    }
+
+    exit(0);
+    /* NOTREACHED */
+}
+#endif	/* defined(TEST) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wildmat.h	Fri May 05 22:45:56 2000 +0100
@@ -0,0 +1,18 @@
+/*
+  wildmat.h
+
+  Noffle header file for wildmat.
+
+  $Id: wildmat.h 49 2000-05-05 21:45:56Z uh1763 $
+ */
+
+#ifndef WILDMAT_H
+#define WILDMAT_H
+
+/*
+  See if test is matched by pattern p. Return TRUE if so.
+ */
+Bool
+Wld_match(const char *text, const char *pattern);
+
+#endif
--- a/util.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-/*
-  util.c
-
-  $Id: util.c 44 2000-05-05 07:23:15Z enz $
-*/
-
-#include "util.h"
-#include <errno.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <time.h>
-#include <unistd.h>
-#include "config.h"
-#include "log.h"
-#include "wildmat.h"
-
-static const char *
-nextWhiteSpace( const char *p )
-{
-    while ( *p && ! isspace( *p ) )
-        ++p;
-    return p;
-}
-
-static const char *
-nextNonWhiteSpace( const char *p )
-{
-    while ( *p && isspace( *p ) )
-        ++p;
-    return p;
-}
-
-const char *
-Utl_restOfLn( const char *line, unsigned int token )
-{
-    unsigned int i;
-    const char *p;
-
-    p = line;
-    for ( i = 0; i < token; ++i )
-    {
-        p = nextNonWhiteSpace( p );
-        p = nextWhiteSpace( p );
-    }
-    p = nextNonWhiteSpace( p );
-    return p;
-}
-
-const char *
-Utl_getLn( Str result, const char *pos )
-{
-    int len = 0;
-    const char *p = pos;
-
-    if ( ! p )
-        return NULL;
-    while ( *p != '\n' )
-    {
-        if ( *p == '\0' )
-        {
-            if ( len > 0 )
-                Log_err( "Line not terminated by newline: '%s'", pos );
-            return NULL;
-        }
-        *(result++) = *(p++);
-        ++len;
-        if ( len >= MAXCHAR - 1 )
-        {
-            *result = '\0';
-            Log_err( "Utl_getLn: line too long: %s", result );
-            return ++p;
-        }
-    }
-    *result = '\0';
-    return ++p;
-
-}
-
-const char *
-Utl_ungetLn( const char *str, const char *p )
-{
-    if ( str == p )
-        return FALSE;
-    --p;
-    if ( *p != '\n' )
-    {
-        Log_dbg( "Utl_ungetLn: not at beginning of line" );
-        return NULL;
-    }
-    --p;
-    while ( TRUE )
-    {
-        if ( p == str )
-            return p;
-        if ( *p == '\n' )
-            return p + 1;
-        --p;
-    }
-}
-
-const char *
-Utl_getHeaderLn( Str result, const char *p )
-{
-    const char * res = Utl_getLn( result, p );
-
-    /* Look for followon line if this isn't a blank line. */
-    if ( res != NULL && !isspace( result[ 0 ] ) )
-	while ( res != NULL && res[ 0 ] != '\n' && isspace( res[ 0 ] ) )
-	{
-	    Str nextLine;
-	    const char *here;
-	    char *next;
-
-	    here = res;
-	    res = Utl_getLn( nextLine, res );
-	    next = Utl_stripWhiteSpace( nextLine );
-
-	    if ( next[ 0 ] != '\0' )
-	    {
-		Utl_catStr( result, " " );
-		Utl_catStr( result, next );
-	    }
-	    else
-	    {
-		res = here;
-		break;
-	    }
-	}
-
-    return res;
-}
-
-void
-Utl_toLower( Str line )
-{
-    char *p;
-
-    p = line;
-    while ( *p )
-    {
-        *p = tolower( *p );
-        ++p;
-    }
-}
-
-char *
-Utl_stripWhiteSpace( char *line )
-{
-    char *p;
-
-    while ( isspace( *line ) )
-        ++line;
-    p = line + strlen( line ) - 1;
-    while ( isspace( *p ) )
-    {
-        *p = '\0';
-        --p;
-    }
-    return line;
-}
-
-void
-Utl_stripComment( char *line )
-{
-    for ( ; *line != '\0'; line++ )
-	if ( *line =='#' )
-	{
-	    *line = '\0';
-	    break;
-	}
-}
-
-void
-Utl_cpyStr( Str dst, const char *src )
-{
-    dst[ 0 ] = '\0';
-    strncat( dst, src, MAXCHAR );
-}
-
-void
-Utl_cpyStrN( Str dst, const char *src, size_t n )
-{
-    if ( n > MAXCHAR )
-    	n = MAXCHAR;
-    dst[ 0 ] = '\0';
-    strncat( dst, src, n );
-}
-
-void
-Utl_catStr( Str dst, const char *src )
-{
-    strncat( dst, src, MAXCHAR - strlen( dst ) );
-}
-
-void
-Utl_catStrN( Str dst, const char *src, size_t n )
-{
-    if ( n > MAXCHAR - strlen( dst ) )
-    	n = MAXCHAR - strlen( dst );
-    strncat( dst, src, n );
-}
-
-void
-Utl_stamp( Str file )
-{
-    FILE *f;
-    time_t t;
-
-    time( &t );
-    if ( ! ( f = fopen( file, "w" ) ) )
-    {
-        Log_err( "Could not open %s for writing (%s)",
-                 file, strerror( errno ) );
-        return;
-    }
-    fprintf( f, "%lu\n", t );
-    fclose( f );
-}
-
-Bool
-Utl_getStamp( time_t *result, Str file )
-{
-    FILE *f;
-
-    if ( ! ( f = fopen( file, "r" ) ) )
-        return FALSE;
-    if ( fscanf( f, "%lu", result ) != 1 )
-    {
-        Log_err( "File %s corrupted", file );
-        fclose( f );
-        return FALSE;
-    }
-    fclose( f );
-    return TRUE;
-}
-
-void
-Utl_rfc822Date( time_t t, Str res )
-{
-    strftime( res, MAXCHAR,"%a, %d %b %Y %H:%M:%S %z", localtime( &t ) );
-}
-
-void
-Utl_allocAndCpy( char **dst, const char *src )
-{
-    int len = strlen( src );
-    if ( ! ( *dst = (char *)malloc( len + 1 ) ) )
-    {
-        Log_err( "Cannot allocate string with length %lu", strlen( src ) );
-        exit( EXIT_FAILURE );
-    }
-    memcpy( *dst, src, len + 1 );
-}
--- a/util.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
-  util.h
-
-  Miscellaneous helper functions.
-
-  $Id: util.h 44 2000-05-05 07:23:15Z enz $
-*/
-
-#ifndef UTL_H
-#define UTL_H
-
-#include <time.h>
-#include "common.h"
-
-/*
-  Find first non-whitespace character after <token> tokens in string <line>.
-  Return pointer to end of string, if parsing failed.
-*/
-const char *
-Utl_restOfLn( const char *line, unsigned int token );
-
-void
-Utl_toLower( Str line );
-
-/*
-  Read a line from string.
-  Return NULL if pos == NULL or no more line to read
-*/
-const char *
-Utl_getLn( Str result, const char *p );
-
-/*
-  Go back to last line.
-*/
-const char *
-Utl_ungetLn( const char *str, const char *p );
-
-/*
-  Read a header line from string. Reads continuation lines if
-  necessary. Return NULL if pos == NULL or no more line to read
-*/
-const char *
-Utl_getHeaderLn( Str result, const char *p );
-
-/*
-  Strip white spaces from left and right side.
-  Return pointer to new start. This is within line.
-*/
-char *
-Utl_stripWhiteSpace( char *line );
-
-/* Strip comment from a line. Comments start with '#'. */
-void
-Utl_stripComment( char *line );
-
-/* Write timestamp into <file>. */
-void
-Utl_stamp( Str file );
-
-/* Get time stamp from <file> */
-Bool
-Utl_getStamp( time_t *result, Str file );
-
-/* Put RFC822-compliant date string into res. */
-void
-Utl_rfc822Date( time_t t, Str res );
-
-void
-Utl_cpyStr( Str dst, const char *src );
-
-void
-Utl_cpyStrN( Str dst, const char *src, size_t n );
-
-void
-Utl_catStr( Str dst, const char *src );
-
-void
-Utl_catStrN( Str dst, const char *src, size_t n );
-
-/* String allocation and copying. */
-void
-Utl_allocAndCpy( char **dst, const char *src );
-
-#endif
--- a/wildmat.c	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
-  wildmat.c
-
-  Taken from the INN 2.2 distribution and slightly altered to fit the
-  Noffle environment. Changes are:
-  o Rename wildmat() to Wld_match().
-  o Adjust includes.
-  
-  $Id: wildmat.c 44 2000-05-05 07:23:15Z enz $
-
-  The entire INN distribution is covered by the following copyright
-  notice. As this file originated in the INN distribution is it
-  subject to the conditions of this notice.
-  
-    Copyright 1991 Rich Salz.
-    All rights reserved.
-    $Revision: 44 $
-
-    Redistribution and use in any form are permitted provided that the
-    following restrictions are are met:
-        1.  Source distributions must retain this entire copyright notice
-            and comment.
-        2.  Binary distributions must include the acknowledgement ``This
-            product includes software developed by Rich Salz'' in the
-            documentation or other materials provided with the
-            distribution.  This must not be represented as an endorsement
-            or promotion without specific prior written permission.
-        3.  The origin of this software must not be misrepresented, either
-            by explicit claim or by omission.  Credits must appear in the
-            source and documentation.
-        4.  Altered versions must be plainly marked as such in the source
-            and documentation and must not be misrepresented as being the
-            original software.
-    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
-    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-*/
-
-/*  $Revision: 44 $
-**
-**  Do shell-style pattern matching for ?, \, [], and * characters.
-**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
-**  could cause a segmentation violation.  It is 8bit clean.
-**
-**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
-**  Rich $alz is now <rsalz@osf.org>.
-**  April, 1991:  Replaced mutually-recursive calls with in-line code
-**  for the star character.
-**
-**  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
-**  This can greatly speed up failing wildcard patterns.  For example:
-**	pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
-**	text 1:	 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
-**	text 2:	 -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
-**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
-**  the ABORT code, it takes 22310 calls to fail.  Ugh.  The following
-**  explanation is from Lars:
-**  The precondition that must be fulfilled is that DoMatch will consume
-**  at least one character in text.  This is true if *p is neither '*' nor
-**  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
-**  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
-**  FALSE, each star-loop has to run to the end of the text; with ABORT
-**  only the last one does.
-**
-**  Once the control of one instance of DoMatch enters the star-loop, that
-**  instance will return either TRUE or ABORT, and any calling instance
-**  will therefore return immediately after (without calling recursively
-**  again).  In effect, only one star-loop is ever active.  It would be
-**  possible to modify the code to maintain this context explicitly,
-**  eliminating all recursive calls at the cost of some complication and
-**  loss of clarity (and the ABORT stuff seems to be unclear enough by
-**  itself).  I think it would be unwise to try to get this into a
-**  released version unless you have a good test data base to try it out
-**  on.
-*/
-#include <stdio.h>
-#include <sys/types.h>
-#include "common.h"
-#include "log.h"
-
-#define	ABORT		(-1)
-
-/* What character marks an inverted character class? */
-#define NEGATE_CLASS		'^'
-    /* Is "*" a common pattern? */
-#define OPTIMIZE_JUST_STAR
-    /* Do tar(1) matching rules, which ignore a trailing slash? */
-#undef MATCH_TAR_PATTERN
-
-
-/*
-**  Match text and p, return TRUE, FALSE, or ABORT.
-*/
-static int DoMatch(const char *text, const char *p)
-{
-    int	                last;
-    int	                matched;
-    int	                reverse;
-
-    for ( ; *p; text++, p++) {
-	if (*text == '\0' && *p != '*')
-	    return ABORT;
-	switch (*p) {
-	case '\\':
-	    /* Literal match with following character. */
-	    p++;
-	    /* FALLTHROUGH */
-	default:
-	    if (*text != *p)
-		return FALSE;
-	    continue;
-	case '?':
-	    /* Match anything. */
-	    continue;
-	case '*':
-	    while (*++p == '*')
-		/* Consecutive stars act just like one. */
-		continue;
-	    if (*p == '\0')
-		/* Trailing star matches everything. */
-		return TRUE;
-	    while (*text)
-		if ((matched = DoMatch(text++, p)) != FALSE)
-		    return matched;
-	    return ABORT;
-	case '[':
-	    reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
-	    if (reverse)
-		/* Inverted character class. */
-		p++;
-	    matched = FALSE;
-	    if (p[1] == ']' || p[1] == '-')
-		if (*++p == *text)
-		    matched = TRUE;
-	    for (last = *p; *++p && *p != ']'; last = *p)
-		/* This next line requires a good C compiler. */
-		if (*p == '-' && p[1] != ']'
-		    ? *text <= *++p && *text >= last : *text == *p)
-		    matched = TRUE;
-	    if (matched == reverse)
-		return FALSE;
-	    continue;
-	}
-    }
-
-#ifdef	MATCH_TAR_PATTERN
-    if (*text == '/')
-	return TRUE;
-#endif	/* MATCH_TAR_ATTERN */
-    return *text == '\0';
-}
-
-
-/*
-**  User-level routine.  Returns TRUE or FALSE.
-*/
-Bool
-Wld_match(const char *text, const char *pattern)
-{
-#ifdef	OPTIMIZE_JUST_STAR
-    if (pattern[0] == '*' && pattern[1] == '\0')
-	return TRUE;
-#endif	/* OPTIMIZE_JUST_STAR */
-    return DoMatch(text, pattern) == TRUE;
-}
-
-
-
-#if	defined(WILDMAT_TEST)
-
-/* Yes, we use gets not fgets.  Sue me. */
-extern char	*gets();
-
-
-int
-main()
-{
-    char	 p[80];
-    char	 text[80];
-
-    printf("Wildmat tester.  Enter pattern, then strings to test.\n");
-    printf("A blank line gets prompts for a new pattern; a blank pattern\n");
-    printf("exits the program.\n");
-
-    for ( ; ; ) {
-	printf("\nEnter pattern:  ");
-	(void)fflush(stdout);
-	if (gets(p) == NULL || p[0] == '\0')
-	    break;
-	for ( ; ; ) {
-	    printf("Enter text:  ");
-	    (void)fflush(stdout);
-	    if (gets(text) == NULL)
-		exit(0);
-	    if (text[0] == '\0')
-		/* Blank line; go back and get a new pattern. */
-		break;
-	    printf("      %s\n", Wld_match(text, p) ? "YES" : "NO");
-	}
-    }
-
-    exit(0);
-    /* NOTREACHED */
-}
-#endif	/* defined(TEST) */
--- a/wildmat.h	Fri May 05 21:26:14 2000 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-/*
-  wildmat.h
-
-  Noffle header file for wildmat.
-
-  $Id: wildmat.h 44 2000-05-05 07:23:15Z enz $
- */
-
-#ifndef WILDMAT_H
-#define WILDMAT_H
-
-/*
-  See if test is matched by pattern p. Return TRUE if so.
- */
-Bool
-Wld_match(const char *text, const char *pattern);
-
-#endif